#152 link-the-let-before-its-init miscompile (miscompiled IDENTICALLY on both stages, so byte-id 990-997 was blind; only a runtime value check catches it). Lifted the run fixture into test/lang/letshadow_test.ww (primitive @test value pin; byteid-eligible — symmetric, cs==ww). byteid floor 56->57. Closes the fold-3 #7 umbrella (last C test twin retired).
72 lines
2.1 KiB
Plaintext
72 lines
2.1 KiB
Plaintext
// letshadow_test — #152 regression pin, migrated from test/wcc/989_letshadow_run.c.
|
|
//
|
|
// 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 was GREEN over it), now fixed. PRIMITIVE-only (i32) asserts.
|
|
|
|
package letshadow_test;
|
|
|
|
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;
|
|
};
|
|
|
|
@test fn param_self_shadow() void = {
|
|
assert(paramshadow("hello") == 604i32);
|
|
};
|
|
|
|
@test fn let_in_let_init() void = {
|
|
assert(letinletinit() == 6i32);
|
|
};
|
|
|
|
@test fn rename_control() void = {
|
|
assert(renamecontrol("hi") == 2i32);
|
|
};
|
|
|
|
@test fn arrlit_self_ref() void = {
|
|
assert(arrlitselfref() == 6i32);
|
|
};
|