wcc/ww: path-qualify exported decls + drop exact-or-bare value mangle (#53)

Under M1 mangling, EXPORTED non-fn decls (let/def/type) skipped path-
qualification and emitted a BARE symbol (`types.I64_MAX` -> `I64_MAX`).
Under separate compilation two packages exporting the same data leaf
would then collide at w6l. Masked in-tree only because no two packages
export the same non-fn leaf.

§7-A (USER-locked, harec's model): path-qualify EVERY exported decl
(fn AND data) at the single mangle choke-point — mod_collect /
collectmods. Retire the `!isfn && d->export` (cstage) and `exported==0`
(wwstage) skips: every decl with a module now mangles `<mod>.<name>`.
The ONLY bare symbols left are @symbol FFI overrides (ffi_resolve at
emit) and the ROOT unit's `main` — both already carved out before the
map insert.

With exported decls in the map the exact-(name,hint)-or-bare value
dance is dead — its sole purpose was the bare-exported case. Delete
mod_lookup_value / mod_mangle_value / mahint (cstage) and
modlookupvalue / emitsymnamehint (wwstage); the value-global sites now
route through the same hint-aware-with-fallback lookup as fns
(mod_mangle_fn/mafn, emitfnname). Net negative LOC in the mangler.

Transparent rename on the live combined path: ref and def move in
lockstep, so cs==ww byte-id holds and the self-host still builds + runs
(fixed-point/995). Byte-id REBASELINE — all 5 ww binaries shift. The
w6c/wwdump combined.ww embed wcc cgen and are regenerated.
This commit is contained in:
2026-06-16 01:48:28 +09:00
parent f77739b1de
commit 0c4a5ecea0
6 changed files with 324 additions and 439 deletions

View File

@@ -1184,7 +1184,7 @@ fn cgident(c: *cgen, n: *node) void = {
let mov: str = "MOVSD";
if (isf32type(c, n)) { mov = "MOVSS"; };
emitline("\tLEAQ\t");
emitsymnamehint(c, nm, c.curmod);
emitfnname(c, nm, c.curmod);
emitline("(SB), CX\n");
emitline("\t");
emitline(mov);
@@ -1192,7 +1192,7 @@ fn cgident(c: *cgen, n: *node) void = {
return;
};
emitline("\tMOVQ\t");
emitsymnamehint(c, nm, c.curmod);
emitfnname(c, nm, c.curmod);
emitline("(SB), AX\n");
return;
};
@@ -1242,7 +1242,7 @@ fn cgident(c: *cgen, n: *node) void = {
// is overwritten by the cap as the last step, after
// ptr/len are already loaded (#1/Phase 3).
emitline("\tLEAQ\t");
emitsymnamehint(c, nm, c.curmod);
emitfnname(c, nm, c.curmod);
emitline("(SB), CX\n");
emitline("\tMOVQ\t(CX), AX\n");
emitline("\tMOVQ\t8(CX), BX\n");
@@ -1275,7 +1275,7 @@ fn cgident(c: *cgen, n: *node) void = {
let mov: str = "MOVSD";
if (is32) { mov = "MOVSS"; };
emitline("\tLEAQ\t");
emitsymnamehint(c, nm, c.curmod);
emitfnname(c, nm, c.curmod);
emitline("(SB), CX\n");
emitline("\t");
emitline(mov);
@@ -1291,11 +1291,11 @@ fn cgident(c: *cgen, n: *node) void = {
let glop: str = localloadop(c, lvtnode);
if (streq(glop, "MOVQ")) {
emitline("\tMOVQ\t");
emitsymnamehint(c, nm, c.curmod);
emitfnname(c, nm, c.curmod);
emitline("(SB), AX\n");
} else {
emitline("\tLEAQ\t");
emitsymnamehint(c, nm, c.curmod);
emitfnname(c, nm, c.curmod);
emitline("(SB), CX\n");
emitline("\t");
emitline(glop);
@@ -2937,7 +2937,7 @@ fn cgmatch(c: *cgen, n: *node) void = {
let gspill: i32 = matchspillsz(c, gtt);
scrutoff = localalloc(c, "@match_spill", gspill, nil);
emitline("\tLEAQ\t");
emitsymnamehint(c, scrut.str, c.curmod);
emitfnname(c, scrut.str, c.curmod);
emitline("(SB), AX\n");
let gk: i32 = 0;
for (gk < gspill) {
@@ -4342,11 +4342,11 @@ fn cgdot(c: *cgen, n: *node) void = {
// threads lhs.str via emitfnname.
if (streq(mqop, "MOVQ")) {
emitline("\tMOVQ\t");
emitsymnamehint(c, fld, usehint(c, lhs.str));
emitfnname(c, fld, usehint(c, lhs.str));
emitline("(SB), AX\n");
} else {
emitline("\tLEAQ\t");
emitsymnamehint(c, fld, usehint(c, lhs.str));
emitfnname(c, fld, usehint(c, lhs.str));
emitline("(SB), CX\n");
emitline("\t");
emitline(mqop);
@@ -5238,7 +5238,7 @@ fn cgun(c: *cgen, n: *node) void = {
// &aa.v takes aa's global, not a
// same-leaf collision.
emitline("\tLEAQ\t");
emitsymnamehint(c, fld, usehint(c, basenm));
emitfnname(c, fld, usehint(c, basenm));
emitline("(SB), AX\n");
return;
};
@@ -5516,7 +5516,7 @@ fn cgstreqpush(c: *cgen, op: *node) void = {
let lc: *local = localfindnode(c, nm);
if (lc == nil && isletvar(c, nm)) {
emitline("\tLEAQ\t");
emitsymnamehint(c, nm, c.curmod);
emitfnname(c, nm, c.curmod);
emitline("(SB), BX\n");
emitline("\tMOVQ\t8(BX), AX\n");
emitline("\tPUSHQ\tAX\n");
@@ -7368,7 +7368,7 @@ fn cgcall(c: *cgen, n: *node) void = {
// mis-resolved.
if (isletvar(c, a.str)) {
emitline("\tLEAQ\t");
emitsymnamehint(c, a.str, c.curmod);
emitfnname(c, a.str, c.curmod);
emitline("(SB), CX\n");
emitline("\tMOVQ\t8(CX), AX\n");
return;