summary_two-phase-complete-2026-10-16.md 3.5 KB

Session summary — 2026-10-16 (b): two-phase thread complete, Check removed

Branch resolve-check, HEAD a89a1c0, tree clean. Suite 201/201; fixpoint OK (3,555,791 bytes).

Tags added this session: v3-two-phase-m2a, m2b, m2c, m2-summary, v3-two-phase-flip, v3-forward-machinery-deleted, v3-two-phase-m2d-summary, v3-check-removed.

What this session did

  1. Landed milestone 2c — real deferral + re-parse (behind -twophase then flipped on by default). Two bugs found and fixed: the re-parse loop clobbered the unit's astDecl/astStmt, and PopPos restored errors, wiping every diagnostic from repassed bodies. Details in docs/summary_two-phase-m2-2026-10-16.md.
  2. Pinned + fixed the spurious ident expected (a DeferSkip snapshot leak: PushPos without PopPos on the success path, fixed with scanner.DropPos) and flipped deferral on by default (-notwophase restores the old inline parse).
  3. Deleted the forward-reference machinery — the thread's original goal: SymTab.FwdVarRef/FwdVarName/FwdVarResolve (+ tables), Check.NoteForward/FlushForward, the Design forward branch, the dead Check.SelType/LeafName. New semantics: a module-level body may call a procedure declared later (no FORWARD); a nested-local forward is a plain 201 instead of a broken image. (Nested deferral was tried and reverted — it regressed nested-proc codegen.)
  4. Removed Check entirely after proving it vestigial: gutting Resolve left the .ssa byte-identical across all 141 suite files and emitted no diagnostics. Deleted Check.def/Check.mod, its driver calls, the -noresolve option, and the atg import; dropped build.sh's Check. Also removed the unused procNest and the always-true L7 flag twoPhase.

Architecture now

per unit:
  Parse   -> AST + declarations (procedure bodies are skipped and
             re-parsed at unit end, so forward references bind normally)
  Lower   -> walk the AST, emit QBE (unchanged)
  Emit    -> buffered image, EndModule

No separate resolve/check pass: binding is late by construction. compiler/src is M2.atg (grammar+scanner+parser+driver frames), FileIO, AST, SymTab, QbeGen, Lower.

Verification

  • Suite 201/201 (t_fwdproc -> 7, t_bad_nestfwd 201); twophase_same gate compares the default (deferral) against -notwophase for forward-free files; forward tests run to 42.
  • Fixpoint OK with deferral on — the self-hosted compiler self-compiles byte-identically under the deferral.
  • Corpus (612 gm2 testsuite files): 365 OK vs 358 with -notwophase — +7 files, 0 regressions, 0 crashes.
  • .ssa byte-identical to pre-cleanup on spot-checks and the 141-file set.

Next

  1. Generics: multi-formal instantiation link bug (top — a real in-scope defect): GENERIC … M(T,U) + X = M(INTEGER,CHAR) compiles but fails to link (undefined First_4; the .ssa has the call but no body). Repro in docs/summary_generics-2026-10-15.md.
  2. Generics increment 3 (const/proc params, constraints), GENERIC CLASS, instance dedup.
  3. stdlib gaps; robustness (M2 exit codes, weak recovery); the latent size-sensitive V3 miscompile.

Resume

cd .../m2compiler-V3
git checkout resolve-check          # HEAD a89a1c0
cd compiler && ./build.sh && ./run_tests.sh   # 201/201
cd .. && ./bootstrap/fixpoint.sh    # FIXPOINT OK
./M2 -notwophase tests/foo.mod       # legacy inline parse (debug)