summary_generics-inc2.md 3.6 KB

Session summary — 2026-10-08 (b): generics increment 2

Tag v3-generics-inc2, branch generics-inc2 (off generics-inc1). Suite 190/190; fixpoint OK (3,472,663 bytes).

Increment 2 of ISO 10514-2 generics: a refinement now instantiates the generic by re-parsing its source with the type formals bound to the actuals — the design sketched in docs/analysis_generics.md.

1. What the syntax does now

GENERIC DEFINITION MODULE Ident (T : TYPE);      (* the template *)
PROCEDURE Id(x : T) : T;
END Ident.

DEFINITION MODULE IntId = Ident(INTEGER);        (* a refinement *)
END IntId.

IntId is now a real module: its Id takes/returns INTEGER. A program FROM IntId IMPORT Id; … Id(42) compiles and returns 42.

2. How it works

Increment 1 left: grammar recognition of the four generic module categories, formals entered as unresolved aliases (EnterTypeParam), and refinements recorded (refInst/refGen/refActual).

Increment 2 adds the instantiation pass:

  • Grammar (M2.atg): an instantiation context instActive/instName/instActual[]/instFk, with accessors (InstBegin/InstAddActual/InstEnd/InInst) and unit/refinement queries (UnitNameGet/UnitIsGeneric/UnitIsDefModule, RefineSeen/RefineIsDef/RefineInst/RefineGen/RefineActual*), exported via parser.frm. When instActive, DefUnit/ImplUnit rename the module to instName, GenericFormal binds each formal to the matching actual (EnterTypeParamBound), and the END name is overridden.
  • SymTab: EnterTypeParamBound (a formal alias whose target is the actual) and Reenter (re-enter an already-registered module scope — the refinement registered X before the re-parse).
  • Driver (compiler.frm): records each generic def/impl file (module name → path) when parsed and does not emit the abstract template; on a refinement it re-opens the generic's file, sets the instantiation context, re-parses, and lowers the resulting unit.

3. Self-hosting constraints hit (and fixed)

The self-hosted compiler is stricter than gm2; three fixes were needed:

  • helper procedures must be declared before their callers (CopyNm) — moved the accessor block below it;
  • an array element may not be passed to a VAR ARRAY OF CHAR formal, and an open array may not be assigned to a fixed array — the registry copies element-by-element and looks up by index;
  • gm2 rejects an anonymous fixed-size array as a formal parameter type — named types GName/GPath were introduced.

4. Test

g_ident.def/.mod (the generic Ident(T)), g_intid.def/.mod (IntId = Ident(INTEGER)) and g_prog.mod (Id(42)). run_tests.sh: expect_run_files GenericProg 42 … → PASS.

5. Scope / remaining

  • Multiple formals and multiple actuals are threaded but only a single T is exercised; const/procedure parameters and constraints are increment 3.
  • Instance dedup is not implemented (each refinement re-instantiates).
  • GENERIC CLASS, and generics with a program module, are untouched.
  • The refinement file must appear after the generic's file in the session (the registry is populated as files are parsed), and the generic's def must precede its impl.

Resume

cd .../m2compiler-V3
./bootstrap/fixpoint.sh                       # FIXPOINT OK
cd compiler && ./build.sh && ./run_tests.sh   # 190/190

Files

compiler/src/M2.atg, compiler/src/parser.frm, compiler/src/SymTab.def/.mod, compiler/src/compiler.frm, compiler/tests/g_ident.*, g_intid.*, g_prog.mod, compiler/run_tests.sh, this doc.