Branch ast-stage-c. This supersedes the "size/complexity-triggered"
conclusion in docs/handoff-l3-option2.md.
t_lower3 byte-matches; suite 184/184 (with lower_ok t_lower3).FIXPOINT OK (stage2.ssa == stage3.ssa,
3,184,888 bytes).SymTab surface; no FORWARD; no SymTab edits.Not size/complexity. It is a deterministic codegen bug:
A record's array field is stored as an inline descriptor (
{ l <len>, data }), but in static array-of-record data the record elements are emitted as a single zero blob (z n*size), so the embedded length word is never initialized (stays 0). Passing such a field as an open-array actual makes the callee read length 0 and trap (call $abort).
Bisect evidence: m2s2 aborts in Lower.CopyN ← NoteProc ←
ProcHeading while parsing Lower.mod. Minimal repro
docs/wip/arrrec-field-openarray.mod (procs[i].name → VAR dst:
ARRAY OF CHAR): gm2-built compilers work, V3-built ones abort (rc 134).
Shrinking MaxSym/MaxProc did not help because the bug is not
size-related.
Option 2's procs : ARRAY OF ProcEnt table hit exactly this pattern
(procs[i].name, procs[i].pname passed to CopyN/CopySpan).
Flatten Lower's procedure table into parallel flat arrays — no
ARRAY OF RECORD at all:
procName (stride 64), procUid, procRes, procDep, procExt,
procNpar, and parTy/parVar/parName (strides MaxPar,
MaxPar*64).NoteProc/NoteParam write via CopySpan into the flat arrays;
FindProc/ProcInfo/ParamInfo read them.Flat top-level arrays are descriptor-backed with a correct length word, so no record field is ever passed as an open array. This matches the handoff's "no arrays of records in Lower" rule (which the earlier design did not actually satisfy).
A correct general fix was implemented and validated on the repro:
QbeGen.ArrBodyItems expands record/class elements per element (reusing
a record-field walk, with ArrData emitting per-element nested
sub-descriptors via a mirrored RecStatics). It fixes the repro
(rc 0) but inflates the compiler image past QbeGen.sessBuf
(4 MiB) — AST.arena is ARRAY [0..65535] OF NodeRec and its data
line grows from ~40 bytes to ~2 MB. The whole image exceeds 4 MiB and is
silently truncated (call at EOF → qbe error).
Options for the follow-up:
z, emitting only l <len> at each array
field (e.g. NodeRec → l 8, z 48 per element, ~590 KB total, which
fits). Needs field-size arithmetic; must match RecItems layout.sessBuf (band-aid; image keeps growing).Also documented: docs/wip/nested-array-field-bug.mod (nested-array
record field) is a related, still-open case.
Removing the pre-existing ASTDUMP in M2.atg's root production makes
the V3-built compiler emit spurious semantic errors in Lower.mod
(AST.NChild: invalid call, etc.) and breaks the fixpoint. So the
debug dump stays for now; it is a symptom of the remaining
"parser-size-sensitive" V3 miscompile and should be revisited separately.