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

@@ -2910,6 +2910,21 @@ check_file(Checker *c, Node *file)
&& !arrlit_init_fits(c, d->type, d->rhs))
err(c, d->pos, "let %s init not assignable",
d->str);
/* #133: const-fold a const-EXPR rhs (N_BIN /
* unary-over-N_BIN / def-ref) to a literal so
* cgen's literal-only DATA emitter lays the row,
* 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 0 silently and is left untouched).
* Stamp LAST — the assignability check above
* consumes the pre-stamp cexpr type. */
u64 dv;
if (d->rhs && !fold_int_literal(d->rhs, &dv)
&& eval_def_const(c, d->rhs, &dv, 0))
stamp_intlit(c, d->rhs, dv);
} else if (d->type && d->type->kind == TY_ARRAY
&& d->type->alen == 0) {
/* `let x: [_]T;` — no initialiser, length can't be