ww: separate package identity from declared name
This commit is contained in:
@@ -455,7 +455,9 @@ type cgen = struct {
|
||||
// bare-IDENT call mangling — `frob()` from
|
||||
// inside lib/foo binds to `foo.frob` even when
|
||||
// other modules also export `frob`. Set in cgfn
|
||||
// before walking the body.
|
||||
// before walking the body.
|
||||
cursource: i32, // lexical source-file scope of the current decl;
|
||||
// selects its own import bindings.
|
||||
fnret: *syntax.node, // declared return type of current fn (or nil)
|
||||
looptop: i32,
|
||||
loopendbuf: []str, // stack of end labels for break
|
||||
@@ -1420,9 +1422,11 @@ fn letpreintern(c: *cgen, file: *syntax.node) void = {
|
||||
// fn-ptr relocs — see the same value they did before; letpreintern
|
||||
// itself only interns, so driving curmod here has no other effect.
|
||||
let savedmod: str = c.curmod;
|
||||
let savedsource: i32 = c.cursource;
|
||||
let d: *syntax.node = file.list;
|
||||
for (d != nil) {
|
||||
c.curmod = d.nmod;
|
||||
c.cursource = 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` (init
|
||||
@@ -1596,6 +1600,7 @@ fn letpreintern(c: *cgen, file: *syntax.node) void = {
|
||||
d = d.next;
|
||||
};
|
||||
c.curmod = savedmod;
|
||||
c.cursource = savedsource;
|
||||
};
|
||||
|
||||
// emitletdataw — DATAW directive per top-level `let` global.
|
||||
@@ -2890,8 +2895,12 @@ fn emittupledata(c: *cgen, name: str, module: str, tt: *syntax.node, rhs: *synta
|
||||
};
|
||||
|
||||
fn emitletdataw(c: *cgen, file: *syntax.node) void = {
|
||||
let savedmod: str = c.curmod;
|
||||
let savedsource: i32 = c.cursource;
|
||||
let d: *syntax.node = file.list;
|
||||
for (d != nil) {
|
||||
c.curmod = d.nmod;
|
||||
c.cursource = d.sourceid;
|
||||
// #22 M3 THE ONE REAL GUARD: a `.wwi` dep value-global is
|
||||
// initializer-less; emitting a DATAW for it would DUPLICATE the
|
||||
// definition that lives in the dep's own .o → link collision.
|
||||
@@ -3226,6 +3235,8 @@ fn emitletdataw(c: *cgen, file: *syntax.node) void = {
|
||||
};
|
||||
d = d.next;
|
||||
};
|
||||
c.curmod = savedmod;
|
||||
c.cursource = savedsource;
|
||||
};
|
||||
|
||||
// emitdefconstants — DATA directive per top-level fold-to-literal
|
||||
@@ -3235,8 +3246,12 @@ fn emitletdataw(c: *cgen, file: *syntax.node) void = {
|
||||
// N_UN(TK_MINUS, N_INTLIT) — the unary peel is exactly what the
|
||||
// gate is for.
|
||||
fn emitdefconstants(c: *cgen, file: *syntax.node) void = {
|
||||
let savedmod: str = c.curmod;
|
||||
let savedsource: i32 = c.cursource;
|
||||
let d: *syntax.node = file.list;
|
||||
for (d != nil) {
|
||||
c.curmod = d.nmod;
|
||||
c.cursource = 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 (never emitted here), so
|
||||
@@ -3369,6 +3384,8 @@ fn emitdefconstants(c: *cgen, file: *syntax.node) void = {
|
||||
};
|
||||
d = d.next;
|
||||
};
|
||||
c.curmod = savedmod;
|
||||
c.cursource = savedsource;
|
||||
};
|
||||
|
||||
// emitdatasection — DATA directives for every interned strlit.
|
||||
@@ -3760,6 +3777,7 @@ type modent = struct {
|
||||
mname: str, // the bare ident as it appears in source
|
||||
nmod: str, // the originating module (`// MODULE: foo`)
|
||||
omod: str, // owning module of a `use` decl (#40); unused for mods
|
||||
sourceid: i32, // owning lexical source-file scope for N_USE entries
|
||||
mnext: *modent,
|
||||
};
|
||||
|
||||
@@ -3772,7 +3790,7 @@ fn collectmods(c: *cgen, file: *syntax.node) void = {
|
||||
// M1 #22: record alias→path for the qualified-ref hint.
|
||||
if (d.kind == syntax.nkind.N_USE) {
|
||||
if (d.usepath.len > 0) {
|
||||
let um: *modent = alloc(modent{mname=d.str, nmod=d.usepath, omod=d.nmod, mnext=c.uses})!;
|
||||
let um: *modent = alloc(modent{mname=d.str, nmod=d.usepath, omod=d.nmod, sourceid=d.sourceid, mnext=c.uses})!;
|
||||
c.uses = um;
|
||||
};
|
||||
};
|
||||
@@ -3811,7 +3829,7 @@ fn collectmods(c: *cgen, file: *syntax.node) void = {
|
||||
// Explicit entry mode clears sepisdep independently of export
|
||||
// production; every other package's main remains mangled.
|
||||
if (!syntax.streq(d.str, "main") || d.imported != 0 || c.sepisdep != 0) {
|
||||
let m: *modent = alloc(modent{mname=d.str, nmod=d.nmod, omod=d.nmod, mnext=c.mods})!;
|
||||
let m: *modent = alloc(modent{mname=d.str, nmod=d.nmod, omod=d.nmod, sourceid=d.sourceid, mnext=c.mods})!;
|
||||
c.mods = m;
|
||||
};
|
||||
};
|
||||
@@ -3827,19 +3845,19 @@ fn collectmods(c: *cgen, file: *syntax.node) void = {
|
||||
// retained until then (rule-11).
|
||||
if (d.kind == syntax.nkind.N_DEF) {
|
||||
if (d.nmod.len > 0) {
|
||||
let m: *modent = alloc(modent{mname=d.str, nmod=d.nmod, omod=d.nmod, mnext=c.mods})!;
|
||||
let m: *modent = alloc(modent{mname=d.str, nmod=d.nmod, omod=d.nmod, sourceid=d.sourceid, mnext=c.mods})!;
|
||||
c.mods = m;
|
||||
};
|
||||
};
|
||||
if (d.kind == syntax.nkind.N_TYPEDECL) {
|
||||
if (d.nmod.len > 0) {
|
||||
let m: *modent = alloc(modent{mname=d.str, nmod=d.nmod, omod=d.nmod, mnext=c.mods})!;
|
||||
let m: *modent = alloc(modent{mname=d.str, nmod=d.nmod, omod=d.nmod, sourceid=d.sourceid, mnext=c.mods})!;
|
||||
c.mods = m;
|
||||
};
|
||||
};
|
||||
if (d.kind == syntax.nkind.N_LET) {
|
||||
if (d.nmod.len > 0) {
|
||||
let m: *modent = alloc(modent{mname=d.str, nmod=d.nmod, omod=d.nmod, mnext=c.mods})!;
|
||||
let m: *modent = alloc(modent{mname=d.str, nmod=d.nmod, omod=d.nmod, sourceid=d.sourceid, mnext=c.mods})!;
|
||||
c.mods = m;
|
||||
};
|
||||
};
|
||||
@@ -3859,18 +3877,10 @@ fn modlookup(c: *cgen, name: str) str = {
|
||||
return empty;
|
||||
};
|
||||
|
||||
// usehint — M1 #22: map a qualified-ref alias (`utf8`) to its dotted
|
||||
// import path (`encoding.utf8`) so the codegen hint keys the path-keyed
|
||||
// mods map. For single-level packages alias == path (no-op). Returns the
|
||||
// alias unchanged when no matching `use` exists.
|
||||
//
|
||||
// NOT file-global (#40): two modules in one unit may bind the same leaf
|
||||
// alias to different paths (module one's `import a.math` vs module two's
|
||||
// `import b.math`, both alias `math`). The `use` declared in the SAME
|
||||
// module as the reference (c.curmod) is authoritative; preferring it
|
||||
// routes each `math.pick()` to its own package. Falls back to any
|
||||
// matching alias when c.curmod has no own import. Mirrors the checker's
|
||||
// use_path curmod-preference (cstage check.c, M1 55f54fb).
|
||||
// usehint — map a declared default qualifier to its canonical import path so
|
||||
// codegen mangles on package identity. 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.
|
||||
fn usehint(c: *cgen, alias: str) str = {
|
||||
let m: *modent = c.uses;
|
||||
let any: str;
|
||||
@@ -3878,8 +3888,12 @@ fn usehint(c: *cgen, alias: str) str = {
|
||||
any.len = 0;
|
||||
for (m != nil) {
|
||||
if (syntax.streq(m.mname, alias)) {
|
||||
if (syntax.streq(m.omod, c.curmod)) { return m.nmod; };
|
||||
if (any.ptr == nil && any.len == 0) { any = m.nmod; };
|
||||
if (m.sourceid == c.cursource && syntax.streq(m.omod, c.curmod)) {
|
||||
return m.nmod;
|
||||
};
|
||||
if (c.sepmode == 0 && any.ptr == nil && any.len == 0) {
|
||||
any = m.nmod;
|
||||
};
|
||||
};
|
||||
m = m.mnext;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user