The wwstage cgdot #191 alias-peel loop broke on a name-keyed any-module structlookup, so a receiver whose alias name collides with a struct of the same name in ANOTHER module resolved to the foreign struct and fell through to an undefined `name(SB)` global instead of the field load. The eFinal FLIP renames io's `vstream` -> `stream`, which collides with memio's `stream` struct, so io.read/io.write/io.close's `match (s.reader)` emitted `MOVQ reader(SB), AX` (reader is also a type-alias) -> cs != ww (cstage chases the nominal TY_NAMED.under pointer chain, module-correct). Gate-blind: on master both stages emit the same wrong store so byte-id stays green; the FLIP corpus is the first to put the io-alias/memio-struct collision in one build. Fix (wwstage-only align-down; cstage is the authority and is untouched): make the peel's struct-break MODULE-AWARE — break only on a same-module struct (a genuine struct-value receiver); a same-module alias keeps peeling to its underlying (io.stream -> *vtable -> the pointer field-load arm); a foreign leaf keeps the prior any-module heuristic. New structsamemod / aliassamemod mirror the same-module-first pass already in structlookup / aliaslookup. This is not a naive alias-first reorder (which would reintroduce the mirror collision: a same-module struct plus a foreign same-leaf alias). Peel-only — the direct- struct arm's broader cross-module same-leaf-STRUCT name-keying is filed as #224. #208-family (name-keyed resolution dropping to a wrong global) but in cgen, not the checker; #213 is distinct (cosmetic local-struct-match divergence). test/wcc/784_xmod_alias_struct_collide_run: collision (cross-module alias-vs- struct, same leaf), symmetric (guards the same-module-struct break against a naive reorder), and a no-collision control — branched callee. The discriminating net is cs.s == ww.s (the path is gate-blind and cstage is correct, so byte-id flips when wwstage is fixed); confirmed by source-revert. The FLIP's combined.ww is now cs.s == ww.s byte-identical.
239 KiB
239 KiB