Switch symbol mangling from the import leaf clause to the full dotted import path for directory packages; single-file imports keep package-clause mangling (isdir-gate: imported<=>directory-import). The root build unit's fn main stays bare, every other top-level decl mangles, closing #31's duplicate-main hazard by construction (#32). Both stages, byte-identical. Single commit, not split: the bare rename (f244af3) is red on its own because it unmasks cross-module resolution gaps that do not reproduce pre-M1, so the fixes are intrinsic to making the rename correct. Included: wwstage fnret/fnparamslookupmod map import alias->path (#199b cross-module union-variant scrutinee resolved the wrong fn's union); cstage use_path prefers the referencing module's import for an ambiguous leaf alias (sha256 crypto.math vs strconv math). Tests table-driven: 989_m1mangle_run/_sym, 989_m1union_run (gate-visible per-arm exit codes + cs==ww byte-id).
This commit is contained in:
@@ -1253,11 +1253,24 @@ parseuse(Parser *p)
|
||||
Pos pp = p->cur.pos;
|
||||
expect(p, TK_USE);
|
||||
Node *n = newnode(p->a, N_USE, pp);
|
||||
/* M1 #22: accumulate the full dotted import path (n->module) so the
|
||||
* checker can match decl identity on the path, while n->str stays the
|
||||
* leaf alias the user writes (`utf8.x`). */
|
||||
char pathbuf[256];
|
||||
size_t pl = 0;
|
||||
const char *leaf = expectident(p);
|
||||
while (accept(p, TK_DOT))
|
||||
for (size_t i = 0; leaf[i] && pl + 1 < sizeof pathbuf; i++)
|
||||
pathbuf[pl++] = leaf[i];
|
||||
while (accept(p, TK_DOT)) {
|
||||
leaf = expectident(p);
|
||||
if (pl + 1 < sizeof pathbuf) pathbuf[pl++] = '.';
|
||||
for (size_t i = 0; leaf[i] && pl + 1 < sizeof pathbuf; i++)
|
||||
pathbuf[pl++] = leaf[i];
|
||||
}
|
||||
pathbuf[pl] = '\0';
|
||||
n->str = leaf;
|
||||
n->strlen = strlen(leaf);
|
||||
n->usepath = astrndup(p->a, pathbuf, pl);
|
||||
expect(p, TK_SEMI);
|
||||
return n;
|
||||
}
|
||||
@@ -1360,7 +1373,32 @@ parsefile(Parser *p)
|
||||
advance(p);
|
||||
const char *name = expectident(p);
|
||||
expect(p, TK_SEMI);
|
||||
p->curmod = name;
|
||||
if (p->pathmod != NULL) {
|
||||
/* M1 #22: while an import path is active the
|
||||
* in-file `package` clause is an ASSERTION — its
|
||||
* leaf must equal the path's last component; it
|
||||
* does NOT overwrite the path-derived module. */
|
||||
const char *dot = strrchr(p->pathmod, '.');
|
||||
const char *last = dot ? dot + 1 : p->pathmod;
|
||||
if (strcmp(name, last) != 0) {
|
||||
errorf(p->cur.pos,
|
||||
"package %s does not match import path %s",
|
||||
name, p->pathmod);
|
||||
p->errs++;
|
||||
}
|
||||
} else {
|
||||
p->curmod = name;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
/* `//ww:module <path>` — M1 #22 import boundary. The following
|
||||
* file's decls mangle on the full dotted import path, not the
|
||||
* leaf `package` clause, and are flagged imported (gates the
|
||||
* root-only bare-`main` rule, #32). */
|
||||
if (p->cur.kind == TK_MODPATH) {
|
||||
p->pathmod = p->cur.text;
|
||||
p->curmod = p->cur.text;
|
||||
advance(p);
|
||||
continue;
|
||||
}
|
||||
/* `//ww:module-reset` — bundle boundary before a package-less
|
||||
@@ -1374,6 +1412,7 @@ parsefile(Parser *p)
|
||||
if (p->cur.kind == TK_MODRESET) {
|
||||
advance(p);
|
||||
p->curmod = NULL;
|
||||
p->pathmod = NULL;
|
||||
continue;
|
||||
}
|
||||
Node *attrs = parseattrs(p);
|
||||
@@ -1399,7 +1438,10 @@ parsefile(Parser *p)
|
||||
advance(p);
|
||||
continue;
|
||||
}
|
||||
if (d != NULL) d->module = p->curmod;
|
||||
if (d != NULL) {
|
||||
d->module = p->curmod;
|
||||
d->imported = (p->pathmod != NULL);
|
||||
}
|
||||
if (head == NULL) head = d;
|
||||
else tail->next = d;
|
||||
tail = d;
|
||||
|
||||
Reference in New Issue
Block a user