Files
ww/test/wcc/data/paramshadowmod/selfimp/selfimptest.ww
Hojun-Cho c9bbfcb6a6 cstage+selfhost+test: refuse let/param shadow of imported module (#19)
When `use fmt;` is in scope and a local/param named `fmt` shadows it,
`fmt.X` in the body silently resolved to the str-typed value sym and
emitted `CALL AX` through str.ptr → runtime crash. Surfaced during
#15 (lib/log's printfln family); worked around by renaming the param
`fmt`→`format`.

Per rob + user, option (C): "value names and module names are
disjoint." Refuse the shadow at the decl site. Single rule, no
non-local reasoning, no silent footgun if a future lib/X exports a
new leaf.

cstage: src_imports walks file->list for N_USE entries (skipping
self-imports where u->module == u->str — same-module fixtures like
lib/fmt/fmttest.ww carry these); check_module_shadow runs before
each SK_PARAM / SK_VAR scope_define (param, clet, mlet, forrange
single + tuple, mcase). Wwstage mirror in check.ww; wwdump-only
diagnostic today, full enforcement waits on #11 checkfile pass.

Bootstrap byte-id holds — no codegen change. One source patch in
selfhost/cmd/w6a/main.ww renames an outer `let asm: asm_;` to `s` to
sidestep task #27 (cstage localoff scope-blind dedup); unrelated to
#19 but the new rule's first run flagged it as a self-shadow.

Test 708 (param_shadow_mod): 4 rows — neg_param (param shadow errs
at fn decl line), neg_let (let shadow errs at let decl), pos_rename
(rename compiles + runs), pos_selfimp (in-module use is skipped).
4 wired sites without dedicated rows deferred to task #28.

Follow-up: lib/log can revert format→fmt now that the silent
crash is impossible.
2026-05-16 08:39:35 +09:00

20 lines
627 B
Plaintext

// pos_selfimp/selfimptest.ww — same-module self-import case. This
// file's MODULE tag is "selfimp" (parent dir basename), and it
// carries `use selfimp;` — exactly the lib/fmt/fmttest.ww shape that
// originally surfaced check_module_shadow's over-trigger on
// `fn bsprintf(... fmt: str, ...)`.
//
// src_imports' self-import skip (u->module == u->str) drops these
// entries from the import scan, so the param `selfimp: str` here
// must NOT be flagged as shadowing — build + run, exit = 7.
use selfimp;
fn probe(selfimp: str) i32 = {
return selfimp.len;
};
export fn main() i32 = {
return probe("regress");
};