wcc/check: #133 const-expr scalar module-global — fold+stamp let-init like def, emit DATA (both stages)

A module-global let with a const-expr init (let s = 7*6) emitted NO DATA word: cstage LINK-FAILed (undefined main.s, loud), wwstage was SILENT (no DATA, MOVSXD on stale AX, exit 152). The DEF pass-2 arm already const-folds + stamps its rhs to N_INTLIT (the #88 eval_def_const/stamp_intlit machinery); the LET pass-2 arm omitted it. Mirror it: after the assignability check, fold the rhs and stamp N_INTLIT when the plain-literal fold missed AND the const-fold succeeded. The existing DATA-emit downstream then fires (DATAW 42 + load). Both stages, byte-identical. Closes the inferred const-expr global and the typed b-ii case (let s:i64=7*6, link-fail both stages) with one stamp.

Gated on genuine int-const success (the eval return value, not the out-param): str/struct/slice/call/runtime-operand rhs short-circuit before the stamp and are left untouched — never zeroed. Non-const rhs stays on its current loud route; div-by-zero stays loud. Latent in selfhost (no const-expr module globals → 990-997 byte-id unchanged).

Pin: 947 rows C1 inferred 7*6, C2 typed b-ii, C3 def-ref K*7, C4 unary-over-binop, C5 div-by-zero loud-guard; cs==ww byte-id.
This commit is contained in:
2026-06-07 22:57:06 +09:00
parent 2138e28f65
commit d0a1e2a221
5 changed files with 155 additions and 6 deletions

View File

@@ -15443,6 +15443,24 @@ export fn checkfile(c: *checker, file: *node) void = {
// were missed). Needed for the array accept-if-fits
// range-check to fire on module-level `let A:[N]u8=[..]`.
checkletassign(c, d);
// #133: const-fold a const-EXPR rhs (N_BIN /
// unary-over-N_BIN / def-ref) to a literal so cgen's
// literal-only emitletdataw lays the DATA row +
// defaultinferredlets recognises it, mirroring the
// N_DEF arm above. GATED on the plain literal fold
// missing first (existing literal/unary-literal lets
// keep their node, byte-identical) AND the const-fold
// succeeding (a str/struct/slice/call/runtime-operand
// rhs returns false silently and is left untouched).
// Stamp LAST — checkletassign consumes the pre-stamp type.
if (d.rhs != nil) {
let dv: u64 = 0u64;
if (!foldintliteral(d.rhs, &dv)) {
if (evaldefconst(c, d.rhs, &dv, 0)) {
stampintlit(d.rhs, dv);
};
};
};
};
d = d.next;
};