ww: separate package identity from declared name

This commit is contained in:
2026-08-14 03:07:58 +09:00
parent 028da6323e
commit 6efe9b70d4
37 changed files with 1678 additions and 886 deletions

View File

@@ -1226,33 +1226,31 @@ struct Use {
const char *alias;
const char *path;
const char *module; /* owning module of the `use` decl (#40) */
int sourceid; /* owning lexical source-file scope */
Use *next;
};
static Use *use_map;
/*
* 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.
* use_hint — map a declared default qualifier to its canonical import path
* for qualified-ref mangling. It is source-file local: separate files may
* bind the same declared name to different paths. Raw non-package compilation
* retains its historical single-occurrence fallback. Returns the qualifier
* unchanged when no `use` matches.
*/
static const char *
use_hint(const char *curmod, const char *alias)
use_hint(Cg *c, 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) continue;
int same = (u->module == NULL) ? (curmod == NULL)
: (curmod != NULL && strcmp(u->module, curmod) == 0);
int same = u->sourceid == c->cur_source
&& ((u->module == NULL) ? (c->cur_mod == NULL)
: (c->cur_mod != NULL
&& strcmp(u->module, c->cur_mod) == 0));
if (same) return u->path;
if (any == NULL) any = u->path;
if (!c->sep_mode && any == NULL) any = u->path;
}
return any ? any : alias;
}
@@ -1484,6 +1482,7 @@ mod_collect(Cg *c, Node *file)
u->alias = d->str;
u->path = d->usepath;
u->module = d->module;
u->sourceid = d->sourceid;
u->next = use_map;
use_map = u;
continue;
@@ -4564,7 +4563,7 @@ cgexpr(Cg *c, Node *n, Local *locals)
if (lu && lu->kind == TY_FN)
ins2(c, A_LEAQ,
mafn(c, opnd->str,
use_hint(c->cur_mod, opnd->lhs->str)),
use_hint(c, opnd->lhs->str)),
areg(D_AX));
else
/* #229: dotted-module value
@@ -4573,7 +4572,7 @@ cgexpr(Cg *c, Node *n, Local *locals)
* same-leaf collision. */
ins2(c, A_LEAQ,
mafn(c, opnd->str,
use_hint(c->cur_mod, opnd->lhs->str)),
use_hint(c, opnd->lhs->str)),
areg(D_AX));
break;
}
@@ -10976,7 +10975,7 @@ cgexpr(Cg *c, Node *n, Local *locals)
* same-leaf exports resolve correctly. */
ins1(c, A_CALL,
mafn(c, n->lhs->str,
use_hint(c->cur_mod, n->lhs->lhs->str)));
use_hint(c, n->lhs->lhs->str)));
} else {
cgexpr(c, n->lhs, locals); /* AX = fn ptr */
ins1(c, A_CALL, areg(D_AX));
@@ -11906,7 +11905,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(c->cur_mod, n->lhs->str)),
mafn(c, n->str, use_hint(c, n->lhs->str)),
areg(D_AX));
break;
}
@@ -11923,7 +11922,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(c->cur_mod, n->lhs->str)))
if (sdef_mod_match_hint(s, use_hint(c, n->lhs->str)))
break;
}
if (s == NULL) {
@@ -11955,11 +11954,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,
mafn(c, n->str, use_hint(c->cur_mod, n->lhs->str)),
mafn(c, n->str, use_hint(c, n->lhs->str)),
areg(D_AX));
} else {
ins2(c, A_LEAQ,
mafn(c, n->str, use_hint(c->cur_mod, n->lhs->str)),
mafn(c, n->str, use_hint(c, n->lhs->str)),
areg(D_CX));
ins2(c, mqop, amem(D_CX, 0), areg(D_AX));
}
@@ -15800,6 +15799,7 @@ cgfn(Cg *c, FILE *out, Node *fn)
c->head = c->tail = NULL;
c->fnname = fn->str;
c->cur_mod = (fn->module && fn->module[0]) ? fn->module : NULL;
c->cur_source = fn->sourceid;
c->labelseq = 0;
cg_stack_arg_cursor = 0;
ndefers = 0;
@@ -16913,7 +16913,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(c->cur_mod, opnd->lhs->str));
return mod_mangle_fn(c, opnd->str, use_hint(c, opnd->lhs->str));
}
if (opnd == NULL || opnd->kind != N_IDENT) return NULL;
Type *ou = type_chase_named(opnd->type);
@@ -17205,8 +17205,12 @@ emit_slice_data(FILE *out, Cg *c, const char *directive, const char *name,
static void
emit_lets(Cg *c, FILE *out, Node *file)
{
const char *save_mod = c->cur_mod;
int save_source = c->cur_source;
for (Node *d = file->list; d; d = d->next) {
if (d->kind != N_LET) continue;
c->cur_mod = (d->module && d->module[0]) ? d->module : NULL;
c->cur_source = d->sourceid;
if (d->str == NULL || d->str[0] == '\0') continue;
/* #22 M3 THE ONE REAL GUARD: a `.wwi` dep value-global is
* initializer-less; emitting a DATAW for it would DUPLICATE the
@@ -17377,6 +17381,8 @@ emit_lets(Cg *c, FILE *out, Node *file)
emit_data_row_zero(out, "DATAW",
mod_mangle_fn(c, d->str, d->module), sz);
}
c->cur_mod = save_mod;
c->cur_source = save_source;
}
/* Emit DATA directives for top-level `def` constants whose value
@@ -17392,8 +17398,12 @@ emit_lets(Cg *c, FILE *out, Node *file)
static void
emit_defs(Cg *c, FILE *out, Node *file)
{
const char *save_mod = c->cur_mod;
int save_source = c->cur_source;
for (Node *d = file->list; d; d = d->next) {
if (d->kind != N_DEF || d->rhs == NULL) continue;
c->cur_mod = (d->module && d->module[0]) ? d->module : NULL;
c->cur_source = d->sourceid;
/* #22 M3: a `.wwi` dep def with DATA storage (int-fold / float /
* struct / array) must NOT re-emit — the dep's own .o owns the
* symbol. Str defs are inline-spliced (sdef_collect), never
@@ -17455,7 +17465,8 @@ emit_defs(Cg *c, FILE *out, Node *file)
"asm.c:362); read-only `def` unsupported (#10, "
"rule 7)");
}
(void)c;
c->cur_mod = save_mod;
c->cur_source = save_source;
}
/* Collect str-typed `def`s so cgexpr N_IDENT can splice them inline.
@@ -17537,8 +17548,10 @@ let_pre_intern(Cg *c, Node *file)
* they did before. let_pre_intern itself only interns, so driving
* cur_mod here has no other effect. */
const char *save_mod = c->cur_mod;
int save_source = c->cur_source;
for (Node *d = file->list; d; d = d->next) {
c->cur_mod = (d->module && d->module[0]) ? d->module : NULL;
c->cur_source = d->sourceid;
/* #22 M3: skip imported deps so the strlit table (and its _S_
* sequence) is a pure function of THIS package's own decls. A
* dep's body initializer would intern here, but its `.wwi`
@@ -17658,6 +17671,7 @@ let_pre_intern(Cg *c, Node *file)
(void)intern_strlit(c, r->str, r->strlen);
}
c->cur_mod = save_mod;
c->cur_source = save_source;
}
void