selfhost+test: prefer same-module aliaslookup match (#27)

wwstage UNDER — aliaslookup's leaf-only first-match walk let a
cross-module leaf collision (`type invalid = !i32;` ahead of
`type invalid = !void;` in c.aliases) shadow module M's own
alias. Silent-correct-by-zero-init: the let-decl prologue zeroed
the slot 8B-wide (typeis8byteprimitive's void-aliased path,
post-#22), so MOVSXD on the misresolved !i32 produced the right
value while diverging from cstage's MOVQ — bootstrap byte-id
held until any caller bumped the alias-chain ordering. Mirrors
cstage scope_lookup_prefer (cmd/wcc/check.c:65); module-
qualified pkg.alias path unchanged.

Polarity catalog: wwstage UNDER — aliaslookup missing module-
preferring scope discipline. Convergence wwstage → cstage's
resolver pattern (rule 10; cstage already correct via
scope_lookup_prefer). Two-pass walk: same-module first, then
existing first-match fallback. Sea-of-stars shape preserved.

Surfaced by lib/strings landing: utf8's `type invalid = !void;`
and strconv's `type invalid = !i32;` registered in the same flat
c.aliases under one combined.ww, with strconv's later-registered
entry sitting at the head of the chain. utf8.next/decode's
`return e;` (e: invalid) packed via MOVSXD instead of MOVQ. Four
sites in main.s, contributing to 993/995 byte-id divergence in
the wwstage rebuild path.

Tests:
  - 726_alias_leaf_collision row 1 pins MOVQ post-zero-init on
    both stages and cstage↔wwstage cmp -s byte-id for the
    `(invalid:!void via beta)` shape with `alpha.invalid = !i32`
    seeded ahead in c.aliases. Sentinel-flip-verified: revert →
    wwstage emits MOVSXD post-zero-init + cmp diverges.
  - Row 2 (i32_local_read_keeps_movsxd) gates against future
    symptom-fix attempts: legitimate `let i: i32; return (i:i64);`
    must still emit MOVSXD on both stages (>=2 narrow signed loads
    in the promote fn TEXT). Independent of the aliaslookup fix.

98/98 ok. 995_self_rebuild stays green (ww2==ww3==ww4 byte-id).
This commit is contained in:
2026-05-18 09:03:25 +09:00
parent 987391bd12
commit 85af051cd1
5 changed files with 327 additions and 6 deletions

View File

@@ -73,10 +73,23 @@ fn collectaliases(c: *cgen, file: *node) void = {
};
fn aliaslookup(c: *cgen, name: str) *node = {
// Same-module first, then any. Mirrors cstage's scope_lookup_prefer
// (cmd/wcc/check.c:65); without the prefer pass a bare `invalid`
// in module M with `type invalid = !void;` can collapse onto a
// strconv-style `type invalid = !i32;` registered earlier in
// c.aliases (head-first walk). The leaf-collision then drives a
// narrow MOVSXD load of a slot the let-decl zero-inits 8B-wide
// (task #27 silent-correct-by-zero-init).
let a: *aliasent = c.aliases;
for (a != nil) {
let an: str = a.aname;
if (streq(an, name)) { return a.target; };
if (streq(a.aname, name)) {
if (streq(a.amod, c.curmod)) { return a.target; };
};
a = a.aanext;
};
a = c.aliases;
for (a != nil) {
if (streq(a.aname, name)) { return a.target; };
a = a.aanext;
};
// Module-qualified form: `pkg.alias` → match the leaf name