summary_generics-inc3-2026-10-16.md 3.3 KB

Session summary — 2026-10-16 (c): generics increment 3

Branch resolve-check, tree clean. Suite 211/211; fixpoint OK (3,702,885 bytes); corpus 372 OK / 0 crash.

Tags: v3-generics-value-params, v3-generics-inc3, v3-generics-proc-params.

What inc3 added

ISO 10514-2 refinement generics now accept value and procedure parameters, plus actual-kind constraints.

1. Value (constant) parameters

GENERIC DEFINITION MODULE Buf (size : CARDINAL);
TYPE T = ARRAY [0..size] OF CHAR;
END Buf.
DEFINITION MODULE Buf10 = Buf(10); END Buf10.

GenericFormal collects its names, then takes : TYPE (type formal) or : TypeIdent (value formal). Actual accepts an integer, charConst, or an identifier. Refinement actuals carry a kind (0 type / 1 value / 2 proc) and a value text (refKind/refVal, instKind/instVal + accessors). A value formal binds to a CONST with the actual value at instantiation; in the abstract template it is a CONST placeholder ("0") — templates are never lowered, so only instances matter. Verified with two instances of different sizes.

2. Actual-kind constraints

At instantiation the actual's kind must match the formal: a type formal needs a type actual, a value formal a value actual, else 233 (g_badbuf).

3. Procedure parameters

GENERIC DEFINITION MODULE Sort
  (Element : TYPE; Compare : PROCEDURE(a, b : Element) : INTEGER);
PROCEDURE Smaller(x, y : Element) : Element;
END Sort.
DEFINITION/IMPLEMENTATION MODULE IntSort = Sort(INTEGER, Cmp.IntCompare);

The formal's type is an inline ProcType; the actual is a qualified procedure name (the refinement parses actuals before any import, so qualification is the only way to reach a proc without one). In the template the formal is a proc-typed callable (the body checks, via an indirect call there); at instantiation it is aliased to the actual:

  • SymTab.AliasProc(formal, mod, actual) — clones the actual's SymNode under the formal's name (keeps uid/mod/sym).
  • Lower.AliasProc(...) — a scope-neutral proc-table entry, because Lower resolves call targets from its own table, not SymTab (the first attempt emitted call $Compare, an unresolved symbol).
  • SymTab.ProcBaseByUid + a uid→base map, so QbeGen.Mangled recovers the base name after the instance scope has been popped.

Refinement forms also accept { Import } now. Verified end-to-end (Smaller(7,3) through IntSort, IntCompare in a separate module, returns 3).

Verification

  • Suite 211/211 (BufProg, g_badbuf, SortProg); forward tests, two-phase gates, and exit-code gates all green.
  • Fixpoint OK (3,702,885 bytes).
  • Corpus unchanged: 372 OK, 0 crash (generics are not in the corpus).

Remaining in the generics thread

  • A richer constraint model (e.g. "T must be ordinal") — next.
  • GENERIC CLASS; instance dedup; nested generics as actuals.

Resume

cd .../m2compiler-V3/compiler
./M2 tests/g_cmp.def tests/g_cmp.mod tests/g_sort.def tests/g_sort.mod \
    tests/g_isort.def tests/g_isort.mod tests/g_sortprog.mod   # SortProg -> 3
./M2 tests/g_buf.def tests/g_buf.mod tests/g_buf10.def \
    tests/g_buf10.mod tests/g_bufprog.mod                      # BufProg -> 42