// letshadow — #152 regression pin. A `let` binding must NOT be visible // during its OWN initializer: `let x = f(x)` evaluates f(x) in the OUTER // scope (Hare: harec check.c clet runs cexpr before scope_define). Both // stages once linked the binding into the cgen localfind chain BEFORE // emitting the init, so the init read the fresh UNINIT shadow slot — a // silent miscompile identical on both stages (byte-id GREEN over it), so // this is a RUNTIME assertion. Signalled-then-exit(+10) pinpoints the row. // // Run with `out/bin/ww run test/wcc/989_letshadow.ww`; exit 0 = all pass. package main; import os; let signalled: i32 = 0; fn fail() void = { os.exit(signalled + 10); }; fn id(s: str) str = { return s; }; // Row 1 — PARAM self-shadow (ken's headline, the c3-posix shape): // `let p = id(p)` must read the PARAM p, not the uninit shadow. // "hello" → len(5)*100 + 'h'(104) = 604 (pre-fix: 0, the zero slot). fn paramshadow(p: str) i32 = { let p = id(p); return (p.len: i32) * 100 + (p[0]: i32); }; // Row 2 — LET shadows an OUTER-scope LET in its OWN init. ww rejects // same-block redeclaration, so the inner let lives in a nested block; // its init must read the OUTER x (=5) since the inner x isn't linked // yet → 6 (pre-fix: garbage from the fresh uninit shadow slot). fn letinletinit() i32 = { let x: i32 = 5; let r: i32 = 0; { let x: i32 = x + 1; r = x; }; return r; }; // Row 3 — CONTROL (rename, no shadow). Already correct both pre/post; // pins no-regression. "hi" → 2. fn renamecontrol(p: str) i32 = { let p2 = id(p); return p2.len: i32; }; // Row 4 — UNIFORM-arm proof: arrlit self-ref. The inner `let a = [a, a]` // (nested block; ww rejects same-block redeclaration) shadows the outer // a; both elements must read the OUTER a (=3) → 6. Proves the N_ARRLIT // arm defers the link too, not just the value-init arm. fn arrlitselfref() i32 = { let a: i32 = 3; let r: i32 = 0; { let a: [2]i32 = [a, a]; r = a[0] + a[1]; }; return r; }; export fn main() i32 = { signalled = 1; if (paramshadow("hello") != 604) { fail(); }; signalled = 2; if (letinletinit() != 6) { fail(); }; signalled = 3; if (renamecontrol("hi") != 2) { fail(); }; signalled = 4; if (arrlitselfref() != 6) { fail(); }; return 0; };