test: extend 708 with mlet/forrange/mcase shadow rows (#28)
708 pinned param + clet + self-import-skip after #19 landed; the other 4 sites where check_module_shadow is wired (N_MLET, N_FORRANGE single, N_FORRANGE tuple, N_MCASE) had no dedicated negative-compile row. Worker-19's note that all 6 sites use identical call shape is true today but unpinned by tests; a future asymmetric edit could silently disable enforcement on one site. Adds neg_mlet (let-tuple binder shadows), neg_forrange_single (`for shadowmod of ...`), neg_forrange_tuple (`for (shadowmod, x) of pairs`), neg_mcase (`case let shadowmod:`). Each errors at the binder decl line with the canonical "<kind> '<name>' shadows imported module '<name>'" message. 708's main now runs 8/8 (param, let, mlet, forrange_single, forrange_tuple, mcase, pos_rename, pos_selfimp).
This commit is contained in:
@@ -16,12 +16,15 @@
|
||||
* only for nested-scope binds whose declaring source file imports
|
||||
* the module.
|
||||
*
|
||||
* row | shape | gate
|
||||
* -----------+--------------------------------------+--------------
|
||||
* neg_param | `use shadowmod; fn p(shadowmod: str)`| must fail
|
||||
* neg_let | `use shadowmod; ... let shadowmod` | must fail
|
||||
* pos_rename | rename param away from `shadowmod` | must succeed,
|
||||
* exit = 42
|
||||
* row | shape | gate
|
||||
* ---------------------+--------------------------------------+--------
|
||||
* neg_param | `fn p(shadowmod: str)` | fail
|
||||
* neg_let | `let shadowmod: i32 = 0;` | fail
|
||||
* neg_mlet | `let (shadowmod, x) = pair();` | fail
|
||||
* neg_forrange_single | `for (let shadowmod .. s)` | fail
|
||||
* neg_forrange_tuple | `for (let (shadowmod, x) .. s)` | fail
|
||||
* neg_mcase | `match (r) { case let shadowmod ... }` | fail
|
||||
* pos_rename | rename param away from `shadowmod` | exit=42
|
||||
*
|
||||
* Fixtures live in test/wcc/data/paramshadowmod/. Cstage-only:
|
||||
* wwstage's check.ww runs only inside wwdump_ww (diagnostic), and
|
||||
@@ -150,6 +153,10 @@ main(void)
|
||||
int fail = 0;
|
||||
fail += run_neg(cdrv, fixdir, "param");
|
||||
fail += run_neg(cdrv, fixdir, "let");
|
||||
fail += run_neg(cdrv, fixdir, "mlet");
|
||||
fail += run_neg(cdrv, fixdir, "forrange_single");
|
||||
fail += run_neg(cdrv, fixdir, "forrange_tuple");
|
||||
fail += run_neg(cdrv, fixdir, "mcase");
|
||||
fail += run_pos(cdrv, fixdir);
|
||||
fail += run_pos_selfimp(cdrv, fixdir);
|
||||
|
||||
@@ -158,6 +165,6 @@ main(void)
|
||||
"param_shadow_mod: %d row(s) failed\n", fail);
|
||||
return 1;
|
||||
}
|
||||
printf("param_shadow_mod: 4/4 ok\n");
|
||||
printf("param_shadow_mod: 8/8 ok\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
15
test/wcc/data/paramshadowmod/neg_forrange_single.ww
Normal file
15
test/wcc/data/paramshadowmod/neg_forrange_single.ww
Normal file
@@ -0,0 +1,15 @@
|
||||
// neg_forrange_single — `for (let shadowmod .. s)` single-binding
|
||||
// range loop where the loop variable shadows the imported module.
|
||||
// N_FORRANGE wires check_module_shadow on the single-name branch
|
||||
// (n->str), so the rule fires at the for header.
|
||||
|
||||
use shadowmod;
|
||||
|
||||
export fn main() i32 = {
|
||||
let s: str = "abc";
|
||||
let total: i32 = 0i32;
|
||||
for (let shadowmod .. s) {
|
||||
total += shadowmod: i32;
|
||||
};
|
||||
return total;
|
||||
};
|
||||
22
test/wcc/data/paramshadowmod/neg_forrange_tuple.ww
Normal file
22
test/wcc/data/paramshadowmod/neg_forrange_tuple.ww
Normal file
@@ -0,0 +1,22 @@
|
||||
// neg_forrange_tuple — `for (let (shadowmod, x) .. s)` tuple-
|
||||
// destructure range loop where the first binder shadows the
|
||||
// imported module. N_FORRANGE wires check_module_shadow per-name
|
||||
// on the tuple branch (n->list), so the rule fires at the for
|
||||
// header even though `x` is innocuous.
|
||||
|
||||
use shadowmod;
|
||||
|
||||
export fn main() i32 = {
|
||||
let buf: [2]i64;
|
||||
buf[0] = 1i64;
|
||||
buf[1] = 2i64;
|
||||
let s: [](i64, i64);
|
||||
s.ptr = buf.ptr: *(i64, i64);
|
||||
s.len = 1;
|
||||
s.cap = 1;
|
||||
let total: i64 = 0i64;
|
||||
for (let (shadowmod, x) .. s) {
|
||||
total += shadowmod + x;
|
||||
};
|
||||
return total: i32;
|
||||
};
|
||||
23
test/wcc/data/paramshadowmod/neg_mcase.ww
Normal file
23
test/wcc/data/paramshadowmod/neg_mcase.ww
Normal file
@@ -0,0 +1,23 @@
|
||||
// neg_mcase — `match (r) { case let shadowmod: i64 => ... }` where
|
||||
// the per-arm binder shadows the imported module. N_MCASE wires
|
||||
// check_module_shadow before scope_define on cs->str, so the rule
|
||||
// fires at the case line.
|
||||
|
||||
use shadowmod;
|
||||
|
||||
fn parse(n: i64) (i64 | i32) = {
|
||||
if (n < 0i64) {
|
||||
return 1i32;
|
||||
};
|
||||
return n;
|
||||
};
|
||||
|
||||
export fn main() i32 = {
|
||||
let r: (i64 | i32) = parse(42i64);
|
||||
let out: i64 = 0i64;
|
||||
match (r) {
|
||||
case let shadowmod: i64 => out = shadowmod;
|
||||
case let e: i32 => return e;
|
||||
};
|
||||
return out: i32;
|
||||
};
|
||||
15
test/wcc/data/paramshadowmod/neg_mlet.ww
Normal file
15
test/wcc/data/paramshadowmod/neg_mlet.ww
Normal file
@@ -0,0 +1,15 @@
|
||||
// neg_mlet — Hare tuple destructure `let (shadowmod, x) = pair();`
|
||||
// where the first binder shadows the imported module. N_MLET wires
|
||||
// check_module_shadow per-binder, so the rule fires at the first
|
||||
// name; the second binder `x` is innocuous.
|
||||
|
||||
use shadowmod;
|
||||
|
||||
fn pair() (i64, i64) = {
|
||||
return 1i64, 2i64;
|
||||
};
|
||||
|
||||
export fn main() i32 = {
|
||||
let (shadowmod, x) = pair();
|
||||
return (shadowmod + x): i32;
|
||||
};
|
||||
Reference in New Issue
Block a user