test: migrate 989_letshadow to @test value pin, retire C twin (fold-3)
#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).
This commit is contained in:
@@ -1,69 +0,0 @@
|
||||
// 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;
|
||||
};
|
||||
@@ -1,50 +0,0 @@
|
||||
/*
|
||||
* 989_letshadow_run — #152 regression pin. Compile + run the letshadow
|
||||
* fixture under the C-side `ww run` driver (cstage w6c) and assert exit 0.
|
||||
*
|
||||
* The bug (link-the-let-before-its-init) miscompiled IDENTICALLY on both
|
||||
* stages, so byte-id 990-997 is blind to it; only a runtime value check
|
||||
* catches the regression. Same thin-wrapper shape as 989_path_run.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/wait.h>
|
||||
|
||||
static int
|
||||
runwait(const char *cmd)
|
||||
{
|
||||
int rc = system(cmd);
|
||||
if (rc == -1) return -1;
|
||||
if (WIFEXITED(rc)) return WEXITSTATUS(rc);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
main(void)
|
||||
{
|
||||
const char *bin = getenv("BIN");
|
||||
if (!bin) bin = "out/bin";
|
||||
char absbin[1024];
|
||||
if (bin[0] != '/') {
|
||||
char cwd[1024];
|
||||
if (getcwd(cwd, sizeof cwd) == NULL) return 1;
|
||||
snprintf(absbin, sizeof absbin, "%s/%s", cwd, bin);
|
||||
bin = absbin;
|
||||
}
|
||||
char cwd[1024];
|
||||
if (getcwd(cwd, sizeof cwd) == NULL) return 1;
|
||||
|
||||
const char *src = "test/wcc/989_letshadow.ww";
|
||||
char path[1024], cmd[2048];
|
||||
snprintf(path, sizeof path, "%s/%s", cwd, src);
|
||||
snprintf(cmd, sizeof cmd, "%s/ww run %s", bin, path);
|
||||
int rc = runwait(cmd);
|
||||
if (rc != 0) {
|
||||
fprintf(stderr, "letshadow_run FAIL: %s exited %d "
|
||||
"(row %d miscompiled — #152)\n", src, rc, rc - 10);
|
||||
return 1;
|
||||
}
|
||||
printf("letshadow_run: %s ok\n", src);
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user