fix: allow lexical import shadowing
This commit is contained in:
@@ -1,8 +1,6 @@
|
||||
// crossmod — directory package whose probe() takes a param named like the
|
||||
// module `shadowmod` that paramshadowmod (NOT crossmod) imports. The
|
||||
// shadow rule is filtered by the binding's own module (src_imports
|
||||
// cur_mod filter): crossmod carries no `import shadowmod`, so this param
|
||||
// must NOT trip even though a sibling package imports that leaf.
|
||||
// crossmod — directory package whose probe() takes a parameter named like the
|
||||
// module `shadowmod` that a sibling package imports. Since crossmod itself has
|
||||
// no such file-local package-name object, this is an ordinary parameter.
|
||||
|
||||
package crossmod;
|
||||
|
||||
|
||||
@@ -1,15 +1,14 @@
|
||||
// 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.
|
||||
// Legacy neg_forrange_single, now a positive range-binding case. The import
|
||||
// initializes total; the one-byte "A" iteration binds the closer shadowmod
|
||||
// value in the loop body. Builds and runs 42 + 65 = 107.
|
||||
|
||||
package paramshadowmod;
|
||||
package main;
|
||||
|
||||
import shadowmod;
|
||||
|
||||
export fn main() i32 = {
|
||||
let s: str = "abc";
|
||||
let total: i32 = 0i32;
|
||||
fn main() i32 = {
|
||||
let s: str = "A";
|
||||
let total: i32 = shadowmod.say();
|
||||
for (let shadowmod .. s) {
|
||||
total += shadowmod: i32;
|
||||
};
|
||||
|
||||
@@ -1,14 +1,12 @@
|
||||
// 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.
|
||||
// Legacy neg_forrange_tuple, now a positive tuple-range case. The import
|
||||
// initializes total; the loop's first tuple element is the closer shadowmod
|
||||
// binding. Builds and runs 42 + 1 + 2 = 45.
|
||||
|
||||
package paramshadowmod;
|
||||
package main;
|
||||
|
||||
import shadowmod;
|
||||
|
||||
export fn main() i32 = {
|
||||
fn main() i32 = {
|
||||
let buf: [2]i64;
|
||||
buf[0] = 1i64;
|
||||
buf[1] = 2i64;
|
||||
@@ -16,7 +14,7 @@ export fn main() i32 = {
|
||||
s.ptr = buf.ptr: *(i64, i64);
|
||||
s.len = 1;
|
||||
s.cap = 1;
|
||||
let total: i64 = 0i64;
|
||||
let total: i64 = shadowmod.say(): i64;
|
||||
for (let (shadowmod, x) .. s) {
|
||||
total += shadowmod + x;
|
||||
};
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
// neg_let — local `let shadowmod: i32 = ...` shadows the imported
|
||||
// module from inside a fn body. Same rule fires for nested-scope
|
||||
// let binds, not just params.
|
||||
// Legacy neg_let, now a positive declaration-point case. The initializer
|
||||
// resolves shadowmod.say through the file-scope import; after the declaration
|
||||
// shadowmod denotes the closer i32 binding. Builds and runs 42.
|
||||
|
||||
package paramshadowmod;
|
||||
package main;
|
||||
|
||||
import shadowmod;
|
||||
|
||||
export fn main() i32 = {
|
||||
let shadowmod: i32 = 0i32;
|
||||
fn main() i32 = {
|
||||
let shadowmod: i32 = shadowmod.say();
|
||||
return shadowmod;
|
||||
};
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
// 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.
|
||||
// Legacy neg_mcase, now a positive match-arm case. The import supplies the
|
||||
// tagged value before the arm binder exists; inside that arm shadowmod is the
|
||||
// closer i64 binding. Builds and runs 42.
|
||||
|
||||
package paramshadowmod;
|
||||
package main;
|
||||
|
||||
import shadowmod;
|
||||
|
||||
@@ -14,8 +13,8 @@ fn parse(n: i64) (i64 | i32) = {
|
||||
return n;
|
||||
};
|
||||
|
||||
export fn main() i32 = {
|
||||
let r: (i64 | i32) = parse(42i64);
|
||||
fn main() i32 = {
|
||||
let r: (i64 | i32) = parse(shadowmod.say(): i64);
|
||||
let out: i64 = 0i64;
|
||||
match (r) {
|
||||
case let shadowmod: i64 => out = shadowmod;
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
// 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.
|
||||
// Legacy neg_mlet, now a positive tuple-binding case. The selector use before
|
||||
// the destructure belongs to the import; afterward shadowmod is the first
|
||||
// tuple element. Builds and runs 42 + 1 + 2 = 45.
|
||||
|
||||
package paramshadowmod;
|
||||
package main;
|
||||
|
||||
import shadowmod;
|
||||
|
||||
@@ -11,7 +10,8 @@ fn pair() (i64, i64) = {
|
||||
return 1i64, 2i64;
|
||||
};
|
||||
|
||||
export fn main() i32 = {
|
||||
fn main() i32 = {
|
||||
let anchor: i32 = shadowmod.say();
|
||||
let (shadowmod, x) = pair();
|
||||
return (shadowmod + x): i32;
|
||||
return anchor + (shadowmod + x): i32;
|
||||
};
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
// neg_param — fn param `shadowmod: str` shadows the imported module.
|
||||
// Under the "value names and module names are disjoint" rule the
|
||||
// build must fail with a clear diagnostic at the param decl site.
|
||||
// Legacy neg_param, now a positive lexical-scope case. The package selector
|
||||
// in main uses the file-scope import; the parameter named shadowmod is a
|
||||
// closer binding only inside probe. Builds and runs 42 + len("hi") = 44.
|
||||
|
||||
package paramshadowmod;
|
||||
package main;
|
||||
|
||||
import shadowmod;
|
||||
|
||||
@@ -10,6 +10,6 @@ fn probe(shadowmod: str) i32 = {
|
||||
return shadowmod.len;
|
||||
};
|
||||
|
||||
export fn main() i32 = {
|
||||
return probe("hi");
|
||||
fn main() i32 = {
|
||||
return shadowmod.say() + probe("hi");
|
||||
};
|
||||
|
||||
@@ -1,17 +1,14 @@
|
||||
// pos_crossmod — cur_mod-filtering positive. Replaces the abolished
|
||||
// pos_selfimp (self-import is hard-rejected post-#16). This module
|
||||
// (paramshadowmod) imports `shadowmod`, and the bundle also pulls module
|
||||
// `crossmod`, whose probe() has a param named `shadowmod`. crossmod does
|
||||
// NOT import shadowmod, so the shadow rule — filtered by the binding's
|
||||
// own module — must NOT trip crossmod's param, even though a sibling
|
||||
// module in the same bundle imports that leaf. Build + run; exit = 2.
|
||||
// pos_crossmod — file-local import ownership control. This source imports
|
||||
// shadowmod, while crossmod's separate source has a parameter of that name
|
||||
// and no such import. The caller's qualifier cannot leak into the sibling
|
||||
// package's lexical scope. Both stages build and run 2.
|
||||
|
||||
package main;
|
||||
|
||||
import shadowmod;
|
||||
import crossmod;
|
||||
|
||||
export fn main() i32 = {
|
||||
fn main() i32 = {
|
||||
let _ = shadowmod.say();
|
||||
return crossmod.probe("hi");
|
||||
};
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
// pos_rename — positive case. The fn param is renamed away from the
|
||||
// imported module's bareword, so the rule doesn't fire and the body
|
||||
// can call `shadowmod.say()` cleanly. Built + run; exit code = 42.
|
||||
// pos_rename — control with an unrelated parameter name. The file-scope
|
||||
// import remains visible in probe. Both stages build and run 42.
|
||||
|
||||
package main;
|
||||
|
||||
@@ -11,6 +10,6 @@ fn probe(s: str) i32 = {
|
||||
return shadowmod.say();
|
||||
};
|
||||
|
||||
export fn main() i32 = {
|
||||
fn main() i32 = {
|
||||
return probe("hi");
|
||||
};
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// paramshadowmod/shadowmod — a tiny module the negative/positive
|
||||
// fixtures import as `use shadowmod;`. Carries one fn so the leaf
|
||||
// resolves through the module dot path when name resolution succeeds.
|
||||
// paramshadowmod/shadowmod — the sibling package used by the lexical
|
||||
// import-shadowing fixtures. The exported function makes each pre-binding
|
||||
// qualifier occurrence observable at runtime.
|
||||
|
||||
package shadowmod;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user