wcc/ww: module-scope the cgen mangle-hint (#40)
use_hint/usehint were unit-global first-leaf-match: two directory- packages exporting the same fn leaf, each imported by a different module aliasing the same bareword, mis-routed every qualified call to whichever use was collected first. Identically wrong on both stages (byte-id-green #263-class). Key the hint on (owner-module, alias) and prefer cur_mod, mirroring the checker's use_path curmod-preference (55f54fb). 989_m1usehint_run: two same-leaf pick() across a.math/b.math, each module's call routes to its own import (111/222) + cs.s==ww.s.
This commit is contained in:
@@ -1175,33 +1175,36 @@ typedef struct Use Use;
|
||||
struct Use {
|
||||
const char *alias;
|
||||
const char *path;
|
||||
const char *module; /* owning module of the `use` decl (#40) */
|
||||
Use *next;
|
||||
};
|
||||
static Use *use_map;
|
||||
|
||||
/*
|
||||
* Retained divergence (M1 #22): this map is file-global — when two
|
||||
* modules in the same unit bind the same leaf alias to different paths
|
||||
* (sha256's `import crypto.math` vs strconv's `import math`), the first
|
||||
* match wins. The checker's twin (use_path, check.c) is module-scoped
|
||||
* to fix exactly this for qualified-NAME resolution; the cgen mangle
|
||||
* hint is NOT, because it is unreachable with an ambiguous alias: a
|
||||
* cross-module qualified ref resolves only to an EXPORTED symbol, and
|
||||
* exported non-fn decls stay bare (mod_collect skips them, so the hint
|
||||
* is moot) while an exported-fn collision would require two same-leaf
|
||||
* packages to export the same fn name AND a third caller — not present
|
||||
* (the tree links cleanly). Left file-global to stay byte-identical
|
||||
* with wwstage's symmetric usehint (cgen.ww), which is also file-global
|
||||
* (rule 10). Module-scope both stages together if a real collision
|
||||
* surfaces — filed as the M1 cgen-hint twin follow-up.
|
||||
* use_hint — map a `use` alias to its dotted import path for the
|
||||
* qualified-ref mangle hint. NOT file-global: two modules in one unit
|
||||
* may bind the same leaf alias to different paths (#40 — module one's
|
||||
* `import a.math` and module two's `import b.math` both alias `math`).
|
||||
* The import declared in the SAME module as the reference (curmod) is
|
||||
* authoritative; preferring it routes each `math.pick()` to its own
|
||||
* package. Falls back to any matching alias when curmod has no own
|
||||
* import (single-occurrence case). Mirrors the checker's use_path
|
||||
* curmod-preference (check.c, M1 55f54fb). Returns the alias unchanged
|
||||
* when no `use` matches.
|
||||
*/
|
||||
static const char *
|
||||
use_hint(const char *alias)
|
||||
use_hint(const char *curmod, const char *alias)
|
||||
{
|
||||
const char *any = NULL;
|
||||
if (alias == NULL) return alias;
|
||||
for (Use *u = use_map; u; u = u->next)
|
||||
if (strcmp(u->alias, alias) == 0) return u->path;
|
||||
return alias;
|
||||
for (Use *u = use_map; u; u = u->next) {
|
||||
if (strcmp(u->alias, alias) != 0) continue;
|
||||
int same = (u->module == NULL) ? (curmod == NULL)
|
||||
: (curmod != NULL && strcmp(u->module, curmod) == 0);
|
||||
if (same) return u->path;
|
||||
if (any == NULL) any = u->path;
|
||||
}
|
||||
return any ? any : alias;
|
||||
}
|
||||
|
||||
/* Top-level `let` map. Populated alongside mod_map; consulted by the
|
||||
@@ -1428,6 +1431,7 @@ mod_collect(Cg *c, Node *file)
|
||||
Use *u = amalloc(c->a, sizeof *u);
|
||||
u->alias = d->str;
|
||||
u->path = d->usepath;
|
||||
u->module = d->module;
|
||||
u->next = use_map;
|
||||
use_map = u;
|
||||
continue;
|
||||
@@ -4371,7 +4375,7 @@ cgexpr(Cg *c, Node *n, Local *locals)
|
||||
if (lu && lu->kind == TY_FN)
|
||||
ins2(c, A_LEAQ,
|
||||
mafn(c, opnd->str,
|
||||
use_hint(opnd->lhs->str)),
|
||||
use_hint(c->cur_mod, opnd->lhs->str)),
|
||||
areg(D_AX));
|
||||
else
|
||||
/* #229: dotted-module value
|
||||
@@ -4380,7 +4384,7 @@ cgexpr(Cg *c, Node *n, Local *locals)
|
||||
* same-leaf collision. */
|
||||
ins2(c, A_LEAQ,
|
||||
mahint(c, opnd->str,
|
||||
use_hint(opnd->lhs->str)),
|
||||
use_hint(c->cur_mod, opnd->lhs->str)),
|
||||
areg(D_AX));
|
||||
break;
|
||||
}
|
||||
@@ -10232,7 +10236,7 @@ cgexpr(Cg *c, Node *n, Local *locals)
|
||||
* same-leaf exports resolve correctly. */
|
||||
ins1(c, A_CALL,
|
||||
mafn(c, n->lhs->str,
|
||||
use_hint(n->lhs->lhs->str)));
|
||||
use_hint(c->cur_mod, n->lhs->lhs->str)));
|
||||
} else {
|
||||
cgexpr(c, n->lhs, locals); /* AX = fn ptr */
|
||||
ins1(c, A_CALL, areg(D_AX));
|
||||
@@ -11108,7 +11112,7 @@ cgexpr(Cg *c, Node *n, Local *locals)
|
||||
/* `mod.fn` address-of via N_DOT — pass the
|
||||
* module bareword as the disambiguation hint. */
|
||||
ins2(c, A_LEAQ,
|
||||
mafn(c, n->str, use_hint(n->lhs->str)),
|
||||
mafn(c, n->str, use_hint(c->cur_mod, n->lhs->str)),
|
||||
areg(D_AX));
|
||||
break;
|
||||
}
|
||||
@@ -11125,7 +11129,7 @@ cgexpr(Cg *c, Node *n, Local *locals)
|
||||
for (s = sdefs; s; s = s->next) {
|
||||
if (strcmp(s->name, n->str) != 0)
|
||||
continue;
|
||||
if (sdef_mod_match_hint(s, use_hint(n->lhs->str)))
|
||||
if (sdef_mod_match_hint(s, use_hint(c->cur_mod, n->lhs->str)))
|
||||
break;
|
||||
}
|
||||
if (s == NULL) {
|
||||
@@ -11157,11 +11161,11 @@ cgexpr(Cg *c, Node *n, Local *locals)
|
||||
* branch above already uses n->lhs->str via mafn. */
|
||||
if (mqop == A_MOVQ) {
|
||||
ins2(c, A_MOVQ,
|
||||
mahint(c, n->str, use_hint(n->lhs->str)),
|
||||
mahint(c, n->str, use_hint(c->cur_mod, n->lhs->str)),
|
||||
areg(D_AX));
|
||||
} else {
|
||||
ins2(c, A_LEAQ,
|
||||
mahint(c, n->str, use_hint(n->lhs->str)),
|
||||
mahint(c, n->str, use_hint(c->cur_mod, n->lhs->str)),
|
||||
areg(D_CX));
|
||||
ins2(c, mqop, amem(D_CX, 0), areg(D_AX));
|
||||
}
|
||||
@@ -16049,7 +16053,7 @@ node_fnptr_sym(Cg *c, Node *ev)
|
||||
return NULL;
|
||||
Type *du = type_chase_named(opnd->type);
|
||||
if (du == NULL || du->kind != TY_FN) return NULL;
|
||||
return mod_mangle_fn(c, opnd->str, use_hint(opnd->lhs->str));
|
||||
return mod_mangle_fn(c, opnd->str, use_hint(c->cur_mod, opnd->lhs->str));
|
||||
}
|
||||
if (opnd == NULL || opnd->kind != N_IDENT) return NULL;
|
||||
Type *ou = type_chase_named(opnd->type);
|
||||
|
||||
Reference in New Issue
Block a user