wcc/ww: tag sep-built dotted-path packages by full path not leaf (#57)

A separately-compiled package's primary body was emitted under a bare
`//ww:module-reset`, so its own `package <leaf>;` clause set curmod to
the leaf (e.g. utf8) while the importer spliced the .wwi under the full
`//ww:module encoding.utf8` — definer mangled `utf8.X`, importer wanted
`encoding.utf8.X`, unresolved. Thread the dotted path through the
directive: `//ww:module-reset <path>` sets curmod to the dotted path
(imported stays 0, so the root `fn main` stays bare per #32), and the
body's package clause is demoted to a leaf==last-component assertion
instead of overwriting curmod. Aligns sep-build to the M1 path-mangle
model; only the SEP emitter changes (the combined build_one arm is
untouched, so all combined byte-id gates hold). Both stages mirrored.

Commit-6 broad-soak prerequisite. Gate 989_sepdotpath_run sep-builds a
2-level dotted package and proves definer==importer qualification +
single-component non-vacuity, cs==ww.
This commit is contained in:
2026-06-16 16:36:03 +09:00
parent 7b36f961a9
commit 747475174a
12 changed files with 639 additions and 58 deletions

View File

@@ -1373,17 +1373,22 @@ parsefile(Parser *p)
advance(p);
const char *name = expectident(p);
expect(p, TK_SEMI);
if (p->pathmod != NULL) {
if (p->pathmod != NULL || p->resetmod != 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;
* does NOT overwrite the path-derived module.
* #57 extends this to the sep primary-reset path
* (resetmod): the dotted reset path is the
* authoritative identity, the clause asserts. */
const char *active =
p->pathmod ? p->pathmod : p->resetmod;
const char *dot = strrchr(active, '.');
const char *last = dot ? dot + 1 : active;
if (strcmp(name, last) != 0) {
errorf(p->cur.pos,
"package %s does not match import path %s",
name, p->pathmod);
name, active);
p->errs++;
}
} else {
@@ -1398,6 +1403,7 @@ parsefile(Parser *p)
if (p->cur.kind == TK_MODPATH) {
p->pathmod = p->cur.text;
p->curmod = p->cur.text;
p->resetmod = NULL;
advance(p);
continue;
}
@@ -1410,9 +1416,23 @@ parsefile(Parser *p)
* directive after a mid-file `package` would strip subsequent
* decls to bare — that usage is deliberate-only. */
if (p->cur.kind == TK_MODRESET) {
/* #57: a path-carrying reset (sep primary body) mangles
* decls on the dotted path so definer == importer, but
* leaves imported==0 (curmod set, pathmod NULL) so -c
* primary-ness and the #32 bare-main rule are intact;
* the body's `package` clause then asserts (resetmod).
* A bare reset is the root/package-less boundary: curmod
* NULL → bare symbols, today's behavior. */
const char *rp = p->cur.text;
advance(p);
p->curmod = NULL;
p->pathmod = NULL;
if (rp != NULL) {
p->curmod = rp;
p->resetmod = rp;
} else {
p->curmod = NULL;
p->resetmod = NULL;
}
continue;
}
Node *attrs = parseattrs(p);