Branch resolve-check. Suite 231/231; fixpoint OK
(3,841,894 bytes); corpus 396/612 compile-OK, 0 crashes.
Tags: v3-set-constants, v3-const-builtin-fold, v3-const-conv-fold,
v3-array-index-fwd, v3-proc-addr, v3-proc-val.
Landed the two features recorded in docs/analysis_gaps.md §9 by the
previous corpus sweep — set constants (static masks) and builtin
calls in CONST initialisers — then went further on CONST
initialisers, forward type references, and procedure values. Corpus
382 → 396 (+14 files, 0 crashes).
CONST Digits = CharSet{"0".."9"}; (* char range *)
Signs = CharSet{'+', '-'};
NumCh = Signs + Digits; (* union of two set constants *)
Warm = CS{Red, Blue}; (* enum base *)
New suite tests: t_setconst (run), t_bad_setconst (reject),
t_constbuiltin (run).
A set literal is emitted as a runtime temp (NewSetTemp/SetZero/
SetBit), so a set CONST had no static value; accepting the
declaration produced a 230 rather than a miscompile (see the previous
sweep's finding). Sets are also addresses of memory words, so the
constant must be a real data symbol.
The fix computes the bit mask at parse time — where the element
values are known and validated — and has Lower re-emit it as a pooled
static descriptor:
Lower.SetConstMaskOf (exported) folds a set expression to
(mask, words, lo): set literals (NkSetLit/NkBraceLit), char /
integer / named-CONST elements, a..b ranges, and +/-/*//
over two foldable set operands (union / difference / intersection /
symdiff), plus + - * DIV MOD on element ordinals.ConstDecl (grammar) calls it for ClSet; on success it records the
mask (Lower.NoteSetMask) and lets the constant be an aggregate; on
failure it stays a clear 230.Lower.LowerDecls looks the mask up by name and calls the new
QbeGen.PoolSet, which registers data $setN = { w mask0, ... } and
returns its address. FlushSets emits the pool in EndModule.Design and Lower's LowerDesign now treat a
ClSet KindConst as an aggregate: its value is the descriptor
address (so c1 := Digits, c IN Digits work).Bound: masks are folded up to 16 words (512 bits); a wider SET
CONST stays a 230 (MaxCFoldW). The corpus set constants are
≤ 8 words.
CAP/ABS/ODD set the runtime sentinel "@", so a CONST such as
A = CAP(VAL(CHAR, 65)) (testcap2) was a 230. They now fold over
an immediate operand in the grammar (Fact): CAP uppercases a CHAR,
ABS takes the magnitude, ODD yields 0/1. This only feeds the
ConstDecl IsImm check (Lower re-lowers from the AST, so runtime code
is unchanged).
MIN/MAX of a set type already folded via TypeBounds. A
BOOLEAN CONST other than TRUE/FALSE was also rejected at the
designator — the grammar's Design class list was missing ClBool
(Lower already had it); added. Corpus 387 → 389.
VAL between representations used to leave a runtime temp, so
CONST r = VAL(REAL, MAX(INTEGER)) (constcast) and
CONST a = VAL(LONGCARD, MAX(LONGINT)) (maxlongint) were 230. The
grammar now folds an immediate operand for the representation-changing
conversions: INT/LONGINT→REAL (and FLOAT, via NormReal),
INT↔LONGINT (identity on an immediate), and identical-class
LONGINT→LONGINT. Corpus 389 → 391.
TYPE a = ARRAY idx OF T; idx = [-2..2] (and ARRAY sub OF … inside a
record/pointer, record7/complextypes) was a 230: the index alias is
unresolved when the array is built. SymTab now marks forward aliases
(tFwd, set by ForwardType) and defers such arrays with placeholder
bounds (DeferArrayIdx); EndTypeBlock patches their [lo..hi]
(FixupArrayIdxs) once the alias resolves. Generic type formals are not
marked, so they are unaffected. Corpus 391 → 393; suite test
t_arrfwd.
ADR(foo) returned 0 (Lower's ADR handled only vars/params), while
VAL(ADDRESS, foo) gave the code address, so procadr compiled but
failed at run time. Lower's ADR now emits the code address for a
procedure (LowerProcAddr). The grammar's VAL conversion was also
missing procedure-value classes: added PROC↔PROC, PROC↔PTR.
Then Assignable rejected p := foo (a procedure value into a PROC
variable, mapped onto ADDRESS): added PROC↔PTR assignability.
procconv now passes and runs. Corpus 393 → 396; suite tests
t_procaddr, t_procval.
setconst3.mod still fails: its VAR mem: ARRAY [0..CARDINAL(
addressLines)] names a CONST declared after the VAR (a forward
CONST reference), which is a separate gap. Its SET CONST itself now
parses.CONST conversion (subrange4/7)
and as a VAR type before its TYPE block (subrange11);
minmaxreal3 (SYSTEM REAL64); procconv2 (CONVERT);
tinyproc2/tinyproc4 (bare procedure value as a statement); the
imp* qualified-import family (partly a corpus-harness
transitive-.def gap).compiler/src/Lower.{def,mod} (evaluator + PoolSet call + ADR(proc)),
compiler/src/QbeGen.{def,mod} (PoolSet/FlushSets/pool state),
compiler/src/SymTab.{def,mod} (forward array-index deferral;
proc-value assignability),
compiler/src/M2.atg (ConstDecl, Design, CAP/ABS/ODD folds,
VAL conversion folds, array-index defer, proc-value conversions),
compiler/tests/t_setconst.mod, t_bad_setconst.mod,
t_constbuiltin.mod, t_constreal.mod, t_constlong.mod,
t_arrfwd.mod, t_procaddr.mod, t_procval.mod,
compiler/run_tests.sh.
cd .../m2compiler-V3
git checkout resolve-check
cd compiler && ./build.sh && ./run_tests.sh # 231/231
cd .. && TMP="$PWD/.scratch/fixpoint" ./bootstrap/fixpoint.sh
M2FLAGS="" ./.scratch/corpusx.sh # 396 OK, 0 crash