selfhost+test: route convenience-wrapper N_DOT probes via fnretlookupmod (#17)

Structural close of the #4-trio convenience-wrapper audit. Session-6's
#4-trio + #11/#16 graduated individual lookup helpers (fnret/fnparams/
enum/struct/def) to same-module-first via *mod variants. The close
didn't enumerate every cgcall-context callsite — convenience wrappers
that take a *node callee and probe its return shape via bare-leaf
fnretlookup stripped the N_DOT module hint, same wedge shape as #16
(callee_variadic_param, d9b0c90) through a different family of
consumers.

Eight LATENT sites in selfhost/cmd/wcc fixed (each mirrors #34's
nodeisslice two-arm route — N_IDENT uses cmod=c.curmod, N_DOT uses
cmod=callee.lhs.str, terminal call routes through fnretlookupmod):

- cgenstmt.ww  cgreturn forwardtagged probe
- cgenstmt.ww  cgmlet tuple-return shape probe
- cgenexpr.ww  cgdot fn-rvalue probe (mod.fn LEAQ)
- cgenexpr.ww  cgtryprop succisstr probe
- cgenexpr.ww  cgtryunw  succisstr probe
- cgenutil.ww  callsretsize (sret arg-prep)
- cgenutil.ww  inferletcalltype (let x = f()? tnode)
- cgenutil.ww  rhstaggedabicall N_CALL branch

cstage carries no sister bug: cmd/w6c/cgen.c reads every callee
return shape from the typed n->lhs->type per TY_FN sig. Mirror of
#4d/#28/#31/#34/#16 cstage no-sister notes.

753_convwrap_audit: table-driven sentinel exercising cgmlet's tuple-
shape probe. alpha exports foo() (i64, str); beta exports foo()
(i64, i64); main calls beta.foo() — source order puts alpha LAST so
alpha.foo prepends to head of c.fnrets, pre-fix bare walk picks
alpha's str-branch dispatch for beta's call. Post-fix routes to
beta.foo via fnretlookupmod. Asserts MOVQ\\tCX, absent in main.run
TEXT (no str.len store; would fire pre-fix). Remaining 7 sites
covered structurally by shape-mirror — single wedge shape, single
exercise.

make test 127/127; ww2==ww3==ww4 byte-id holds via 995_self_rebuild.
This commit is contained in:
2026-05-19 10:44:16 +09:00
parent 23fccee4a0
commit 006df414aa
7 changed files with 560 additions and 66 deletions

View File

@@ -8777,10 +8777,22 @@ export fn callsretsize(c: *cgen, n: *node) i32 = {
if (callee == nil) { return 0; };
let cn: str;
cn.ptr = nil; cn.len = 0;
if (callee.kind == nkind.N_IDENT) { cn = callee.str; };
if (callee.kind == nkind.N_DOT) { cn = callee.str; };
let cmod: str;
cmod.ptr = nil; cmod.len = 0;
if (callee.kind == nkind.N_IDENT) {
cn = callee.str;
cmod = c.curmod;
};
if (callee.kind == nkind.N_DOT) {
cn = callee.str;
if (callee.lhs != nil) {
if (callee.lhs.kind == nkind.N_IDENT) {
cmod = callee.lhs.str;
};
};
};
if (cn.len == 0) { return 0; };
let rt: *node = fnretlookup(c, cn);
let rt: *node = fnretlookupmod(c, cn, cmod);
return sretretsize(c, rt);
};
@@ -9023,10 +9035,22 @@ fn inferletcalltype(c: *cgen, rhs: *node) *node = {
if (callee == nil) { return nil; };
let cname: str;
cname.ptr = nil; cname.len = 0;
if (callee.kind == nkind.N_IDENT) { cname = callee.str; };
if (callee.kind == nkind.N_DOT) { cname = callee.str; };
let cmod: str;
cmod.ptr = nil; cmod.len = 0;
if (callee.kind == nkind.N_IDENT) {
cname = callee.str;
cmod = c.curmod;
};
if (callee.kind == nkind.N_DOT) {
cname = callee.str;
if (callee.lhs != nil) {
if (callee.lhs.kind == nkind.N_IDENT) {
cmod = callee.lhs.str;
};
};
};
if (cname.len == 0) { return nil; };
let rt: *node = fnretlookup(c, cname);
let rt: *node = fnretlookupmod(c, cname, cmod);
if (rt == nil) { return nil; };
if (unwrap) {
// Strip error variants — success type is the first
@@ -10143,10 +10167,22 @@ fn rhstaggedabicall(c: *cgen, src: *node) bool = {
if (callee != nil) {
let calleename: str;
calleename.ptr = nil; calleename.len = 0;
if (callee.kind == nkind.N_IDENT) { calleename = callee.str; };
if (callee.kind == nkind.N_DOT) { calleename = callee.str; };
let cmod: str;
cmod.ptr = nil; cmod.len = 0;
if (callee.kind == nkind.N_IDENT) {
calleename = callee.str;
cmod = c.curmod;
};
if (callee.kind == nkind.N_DOT) {
calleename = callee.str;
if (callee.lhs != nil) {
if (callee.lhs.kind == nkind.N_IDENT) {
cmod = callee.lhs.str;
};
};
};
if (calleename.len > 0) {
let rt: *node = fnretlookup(c, calleename);
let rt: *node = fnretlookupmod(c, calleename, cmod);
if (rt != nil) {
if (istaggedtype(c, rt)) { return true; };
};
@@ -11245,10 +11281,22 @@ fn cgtryprop(c: *cgen, n: *node) void = {
if (callee != nil) {
let cname: str;
cname.ptr = nil; cname.len = 0;
if (callee.kind == nkind.N_IDENT) { cname = callee.str; };
if (callee.kind == nkind.N_DOT) { cname = callee.str; };
let cmod: str;
cmod.ptr = nil; cmod.len = 0;
if (callee.kind == nkind.N_IDENT) {
cname = callee.str;
cmod = c.curmod;
};
if (callee.kind == nkind.N_DOT) {
cname = callee.str;
if (callee.lhs != nil) {
if (callee.lhs.kind == nkind.N_IDENT) {
cmod = callee.lhs.str;
};
};
};
if (cname.len > 0) {
let rt: *node = fnretlookup(c, cname);
let rt: *node = fnretlookupmod(c, cname, cmod);
if (rt != nil) {
if (rt.kind == nkind.N_TTAGGED) {
let first: *node = rt.list;
@@ -11289,10 +11337,22 @@ fn cgtryunw(c: *cgen, n: *node) void = {
if (callee != nil) {
let cname: str;
cname.ptr = nil; cname.len = 0;
if (callee.kind == nkind.N_IDENT) { cname = callee.str; };
if (callee.kind == nkind.N_DOT) { cname = callee.str; };
let cmod: str;
cmod.ptr = nil; cmod.len = 0;
if (callee.kind == nkind.N_IDENT) {
cname = callee.str;
cmod = c.curmod;
};
if (callee.kind == nkind.N_DOT) {
cname = callee.str;
if (callee.lhs != nil) {
if (callee.lhs.kind == nkind.N_IDENT) {
cmod = callee.lhs.str;
};
};
};
if (cname.len > 0) {
let rt: *node = fnretlookup(c, cname);
let rt: *node = fnretlookupmod(c, cname, cmod);
if (rt != nil) {
if (rt.kind == nkind.N_TTAGGED) {
let first: *node = rt.list;
@@ -12822,7 +12882,10 @@ fn cgdot(c: *cgen, n: *node) void = {
// Without this the MOVQ leaf(SB) fallback below would
// load 8 bytes of fn-prologue code into AX instead of
// the fn address.
let frt: *node = fnretlookup(c, fld);
// lhs.str is the explicit module hint so a same-leaf
// def in another module (head of c.fnrets) can't shadow
// the explicit qualifier (#17 N_DOT-arm omission audit).
let frt: *node = fnretlookupmod(c, fld, lhs.str);
if (frt != nil) {
emitline("\tLEAQ\t");
emitfnname(c, fld, lhs.str);
@@ -16960,10 +17023,22 @@ fn cgreturn(c: *cgen, n: *node) void = {
if (callee != nil) {
let calleename: str;
calleename.ptr = nil; calleename.len = 0;
if (callee.kind == nkind.N_IDENT) { calleename = callee.str; };
if (callee.kind == nkind.N_DOT) { calleename = callee.str; };
let cmod: str;
cmod.ptr = nil; cmod.len = 0;
if (callee.kind == nkind.N_IDENT) {
calleename = callee.str;
cmod = c.curmod;
};
if (callee.kind == nkind.N_DOT) {
calleename = callee.str;
if (callee.lhs != nil) {
if (callee.lhs.kind == nkind.N_IDENT) {
cmod = callee.lhs.str;
};
};
};
if (calleename.len > 0) {
let rt: *node = fnretlookup(c, calleename);
let rt: *node = fnretlookupmod(c, calleename, cmod);
if (istaggedtype(c, rt)) { forwardtagged = true; };
};
};
@@ -17867,10 +17942,22 @@ fn cgmlet(c: *cgen, n: *node) void = {
if (callee != nil) {
let cnm: str;
cnm.ptr = nil; cnm.len = 0;
if (callee.kind == nkind.N_IDENT) { cnm = callee.str; };
if (callee.kind == nkind.N_DOT) { cnm = callee.str; };
let cmod: str;
cmod.ptr = nil; cmod.len = 0;
if (callee.kind == nkind.N_IDENT) {
cnm = callee.str;
cmod = c.curmod;
};
if (callee.kind == nkind.N_DOT) {
cnm = callee.str;
if (callee.lhs != nil) {
if (callee.lhs.kind == nkind.N_IDENT) {
cmod = callee.lhs.str;
};
};
};
if (cnm.len > 0) {
let rt: *node = fnretlookup(c, cnm);
let rt: *node = fnretlookupmod(c, cnm, cmod);
if (rt != nil) {
if (rt.kind == nkind.N_TTUPLE) {
p0t = rt.list;

View File

@@ -156,10 +156,22 @@ fn cgtryprop(c: *cgen, n: *node) void = {
if (callee != nil) {
let cname: str;
cname.ptr = nil; cname.len = 0;
if (callee.kind == nkind.N_IDENT) { cname = callee.str; };
if (callee.kind == nkind.N_DOT) { cname = callee.str; };
let cmod: str;
cmod.ptr = nil; cmod.len = 0;
if (callee.kind == nkind.N_IDENT) {
cname = callee.str;
cmod = c.curmod;
};
if (callee.kind == nkind.N_DOT) {
cname = callee.str;
if (callee.lhs != nil) {
if (callee.lhs.kind == nkind.N_IDENT) {
cmod = callee.lhs.str;
};
};
};
if (cname.len > 0) {
let rt: *node = fnretlookup(c, cname);
let rt: *node = fnretlookupmod(c, cname, cmod);
if (rt != nil) {
if (rt.kind == nkind.N_TTAGGED) {
let first: *node = rt.list;
@@ -200,10 +212,22 @@ fn cgtryunw(c: *cgen, n: *node) void = {
if (callee != nil) {
let cname: str;
cname.ptr = nil; cname.len = 0;
if (callee.kind == nkind.N_IDENT) { cname = callee.str; };
if (callee.kind == nkind.N_DOT) { cname = callee.str; };
let cmod: str;
cmod.ptr = nil; cmod.len = 0;
if (callee.kind == nkind.N_IDENT) {
cname = callee.str;
cmod = c.curmod;
};
if (callee.kind == nkind.N_DOT) {
cname = callee.str;
if (callee.lhs != nil) {
if (callee.lhs.kind == nkind.N_IDENT) {
cmod = callee.lhs.str;
};
};
};
if (cname.len > 0) {
let rt: *node = fnretlookup(c, cname);
let rt: *node = fnretlookupmod(c, cname, cmod);
if (rt != nil) {
if (rt.kind == nkind.N_TTAGGED) {
let first: *node = rt.list;
@@ -1733,7 +1757,10 @@ fn cgdot(c: *cgen, n: *node) void = {
// Without this the MOVQ leaf(SB) fallback below would
// load 8 bytes of fn-prologue code into AX instead of
// the fn address.
let frt: *node = fnretlookup(c, fld);
// lhs.str is the explicit module hint so a same-leaf
// def in another module (head of c.fnrets) can't shadow
// the explicit qualifier (#17 N_DOT-arm omission audit).
let frt: *node = fnretlookupmod(c, fld, lhs.str);
if (frt != nil) {
emitline("\tLEAQ\t");
emitfnname(c, fld, lhs.str);

View File

@@ -169,10 +169,22 @@ fn cgreturn(c: *cgen, n: *node) void = {
if (callee != nil) {
let calleename: str;
calleename.ptr = nil; calleename.len = 0;
if (callee.kind == nkind.N_IDENT) { calleename = callee.str; };
if (callee.kind == nkind.N_DOT) { calleename = callee.str; };
let cmod: str;
cmod.ptr = nil; cmod.len = 0;
if (callee.kind == nkind.N_IDENT) {
calleename = callee.str;
cmod = c.curmod;
};
if (callee.kind == nkind.N_DOT) {
calleename = callee.str;
if (callee.lhs != nil) {
if (callee.lhs.kind == nkind.N_IDENT) {
cmod = callee.lhs.str;
};
};
};
if (calleename.len > 0) {
let rt: *node = fnretlookup(c, calleename);
let rt: *node = fnretlookupmod(c, calleename, cmod);
if (istaggedtype(c, rt)) { forwardtagged = true; };
};
};
@@ -1076,10 +1088,22 @@ fn cgmlet(c: *cgen, n: *node) void = {
if (callee != nil) {
let cnm: str;
cnm.ptr = nil; cnm.len = 0;
if (callee.kind == nkind.N_IDENT) { cnm = callee.str; };
if (callee.kind == nkind.N_DOT) { cnm = callee.str; };
let cmod: str;
cmod.ptr = nil; cmod.len = 0;
if (callee.kind == nkind.N_IDENT) {
cnm = callee.str;
cmod = c.curmod;
};
if (callee.kind == nkind.N_DOT) {
cnm = callee.str;
if (callee.lhs != nil) {
if (callee.lhs.kind == nkind.N_IDENT) {
cmod = callee.lhs.str;
};
};
};
if (cnm.len > 0) {
let rt: *node = fnretlookup(c, cnm);
let rt: *node = fnretlookupmod(c, cnm, cmod);
if (rt != nil) {
if (rt.kind == nkind.N_TTUPLE) {
p0t = rt.list;

View File

@@ -1532,10 +1532,22 @@ export fn callsretsize(c: *cgen, n: *node) i32 = {
if (callee == nil) { return 0; };
let cn: str;
cn.ptr = nil; cn.len = 0;
if (callee.kind == nkind.N_IDENT) { cn = callee.str; };
if (callee.kind == nkind.N_DOT) { cn = callee.str; };
let cmod: str;
cmod.ptr = nil; cmod.len = 0;
if (callee.kind == nkind.N_IDENT) {
cn = callee.str;
cmod = c.curmod;
};
if (callee.kind == nkind.N_DOT) {
cn = callee.str;
if (callee.lhs != nil) {
if (callee.lhs.kind == nkind.N_IDENT) {
cmod = callee.lhs.str;
};
};
};
if (cn.len == 0) { return 0; };
let rt: *node = fnretlookup(c, cn);
let rt: *node = fnretlookupmod(c, cn, cmod);
return sretretsize(c, rt);
};
@@ -1778,10 +1790,22 @@ fn inferletcalltype(c: *cgen, rhs: *node) *node = {
if (callee == nil) { return nil; };
let cname: str;
cname.ptr = nil; cname.len = 0;
if (callee.kind == nkind.N_IDENT) { cname = callee.str; };
if (callee.kind == nkind.N_DOT) { cname = callee.str; };
let cmod: str;
cmod.ptr = nil; cmod.len = 0;
if (callee.kind == nkind.N_IDENT) {
cname = callee.str;
cmod = c.curmod;
};
if (callee.kind == nkind.N_DOT) {
cname = callee.str;
if (callee.lhs != nil) {
if (callee.lhs.kind == nkind.N_IDENT) {
cmod = callee.lhs.str;
};
};
};
if (cname.len == 0) { return nil; };
let rt: *node = fnretlookup(c, cname);
let rt: *node = fnretlookupmod(c, cname, cmod);
if (rt == nil) { return nil; };
if (unwrap) {
// Strip error variants — success type is the first
@@ -2898,10 +2922,22 @@ fn rhstaggedabicall(c: *cgen, src: *node) bool = {
if (callee != nil) {
let calleename: str;
calleename.ptr = nil; calleename.len = 0;
if (callee.kind == nkind.N_IDENT) { calleename = callee.str; };
if (callee.kind == nkind.N_DOT) { calleename = callee.str; };
let cmod: str;
cmod.ptr = nil; cmod.len = 0;
if (callee.kind == nkind.N_IDENT) {
calleename = callee.str;
cmod = c.curmod;
};
if (callee.kind == nkind.N_DOT) {
calleename = callee.str;
if (callee.lhs != nil) {
if (callee.lhs.kind == nkind.N_IDENT) {
cmod = callee.lhs.str;
};
};
};
if (calleename.len > 0) {
let rt: *node = fnretlookup(c, calleename);
let rt: *node = fnretlookupmod(c, calleename, cmod);
if (rt != nil) {
if (istaggedtype(c, rt)) { return true; };
};

View File

@@ -8777,10 +8777,22 @@ export fn callsretsize(c: *cgen, n: *node) i32 = {
if (callee == nil) { return 0; };
let cn: str;
cn.ptr = nil; cn.len = 0;
if (callee.kind == nkind.N_IDENT) { cn = callee.str; };
if (callee.kind == nkind.N_DOT) { cn = callee.str; };
let cmod: str;
cmod.ptr = nil; cmod.len = 0;
if (callee.kind == nkind.N_IDENT) {
cn = callee.str;
cmod = c.curmod;
};
if (callee.kind == nkind.N_DOT) {
cn = callee.str;
if (callee.lhs != nil) {
if (callee.lhs.kind == nkind.N_IDENT) {
cmod = callee.lhs.str;
};
};
};
if (cn.len == 0) { return 0; };
let rt: *node = fnretlookup(c, cn);
let rt: *node = fnretlookupmod(c, cn, cmod);
return sretretsize(c, rt);
};
@@ -9023,10 +9035,22 @@ fn inferletcalltype(c: *cgen, rhs: *node) *node = {
if (callee == nil) { return nil; };
let cname: str;
cname.ptr = nil; cname.len = 0;
if (callee.kind == nkind.N_IDENT) { cname = callee.str; };
if (callee.kind == nkind.N_DOT) { cname = callee.str; };
let cmod: str;
cmod.ptr = nil; cmod.len = 0;
if (callee.kind == nkind.N_IDENT) {
cname = callee.str;
cmod = c.curmod;
};
if (callee.kind == nkind.N_DOT) {
cname = callee.str;
if (callee.lhs != nil) {
if (callee.lhs.kind == nkind.N_IDENT) {
cmod = callee.lhs.str;
};
};
};
if (cname.len == 0) { return nil; };
let rt: *node = fnretlookup(c, cname);
let rt: *node = fnretlookupmod(c, cname, cmod);
if (rt == nil) { return nil; };
if (unwrap) {
// Strip error variants — success type is the first
@@ -10143,10 +10167,22 @@ fn rhstaggedabicall(c: *cgen, src: *node) bool = {
if (callee != nil) {
let calleename: str;
calleename.ptr = nil; calleename.len = 0;
if (callee.kind == nkind.N_IDENT) { calleename = callee.str; };
if (callee.kind == nkind.N_DOT) { calleename = callee.str; };
let cmod: str;
cmod.ptr = nil; cmod.len = 0;
if (callee.kind == nkind.N_IDENT) {
calleename = callee.str;
cmod = c.curmod;
};
if (callee.kind == nkind.N_DOT) {
calleename = callee.str;
if (callee.lhs != nil) {
if (callee.lhs.kind == nkind.N_IDENT) {
cmod = callee.lhs.str;
};
};
};
if (calleename.len > 0) {
let rt: *node = fnretlookup(c, calleename);
let rt: *node = fnretlookupmod(c, calleename, cmod);
if (rt != nil) {
if (istaggedtype(c, rt)) { return true; };
};
@@ -11245,10 +11281,22 @@ fn cgtryprop(c: *cgen, n: *node) void = {
if (callee != nil) {
let cname: str;
cname.ptr = nil; cname.len = 0;
if (callee.kind == nkind.N_IDENT) { cname = callee.str; };
if (callee.kind == nkind.N_DOT) { cname = callee.str; };
let cmod: str;
cmod.ptr = nil; cmod.len = 0;
if (callee.kind == nkind.N_IDENT) {
cname = callee.str;
cmod = c.curmod;
};
if (callee.kind == nkind.N_DOT) {
cname = callee.str;
if (callee.lhs != nil) {
if (callee.lhs.kind == nkind.N_IDENT) {
cmod = callee.lhs.str;
};
};
};
if (cname.len > 0) {
let rt: *node = fnretlookup(c, cname);
let rt: *node = fnretlookupmod(c, cname, cmod);
if (rt != nil) {
if (rt.kind == nkind.N_TTAGGED) {
let first: *node = rt.list;
@@ -11289,10 +11337,22 @@ fn cgtryunw(c: *cgen, n: *node) void = {
if (callee != nil) {
let cname: str;
cname.ptr = nil; cname.len = 0;
if (callee.kind == nkind.N_IDENT) { cname = callee.str; };
if (callee.kind == nkind.N_DOT) { cname = callee.str; };
let cmod: str;
cmod.ptr = nil; cmod.len = 0;
if (callee.kind == nkind.N_IDENT) {
cname = callee.str;
cmod = c.curmod;
};
if (callee.kind == nkind.N_DOT) {
cname = callee.str;
if (callee.lhs != nil) {
if (callee.lhs.kind == nkind.N_IDENT) {
cmod = callee.lhs.str;
};
};
};
if (cname.len > 0) {
let rt: *node = fnretlookup(c, cname);
let rt: *node = fnretlookupmod(c, cname, cmod);
if (rt != nil) {
if (rt.kind == nkind.N_TTAGGED) {
let first: *node = rt.list;
@@ -12822,7 +12882,10 @@ fn cgdot(c: *cgen, n: *node) void = {
// Without this the MOVQ leaf(SB) fallback below would
// load 8 bytes of fn-prologue code into AX instead of
// the fn address.
let frt: *node = fnretlookup(c, fld);
// lhs.str is the explicit module hint so a same-leaf
// def in another module (head of c.fnrets) can't shadow
// the explicit qualifier (#17 N_DOT-arm omission audit).
let frt: *node = fnretlookupmod(c, fld, lhs.str);
if (frt != nil) {
emitline("\tLEAQ\t");
emitfnname(c, fld, lhs.str);
@@ -16960,10 +17023,22 @@ fn cgreturn(c: *cgen, n: *node) void = {
if (callee != nil) {
let calleename: str;
calleename.ptr = nil; calleename.len = 0;
if (callee.kind == nkind.N_IDENT) { calleename = callee.str; };
if (callee.kind == nkind.N_DOT) { calleename = callee.str; };
let cmod: str;
cmod.ptr = nil; cmod.len = 0;
if (callee.kind == nkind.N_IDENT) {
calleename = callee.str;
cmod = c.curmod;
};
if (callee.kind == nkind.N_DOT) {
calleename = callee.str;
if (callee.lhs != nil) {
if (callee.lhs.kind == nkind.N_IDENT) {
cmod = callee.lhs.str;
};
};
};
if (calleename.len > 0) {
let rt: *node = fnretlookup(c, calleename);
let rt: *node = fnretlookupmod(c, calleename, cmod);
if (istaggedtype(c, rt)) { forwardtagged = true; };
};
};
@@ -17867,10 +17942,22 @@ fn cgmlet(c: *cgen, n: *node) void = {
if (callee != nil) {
let cnm: str;
cnm.ptr = nil; cnm.len = 0;
if (callee.kind == nkind.N_IDENT) { cnm = callee.str; };
if (callee.kind == nkind.N_DOT) { cnm = callee.str; };
let cmod: str;
cmod.ptr = nil; cmod.len = 0;
if (callee.kind == nkind.N_IDENT) {
cnm = callee.str;
cmod = c.curmod;
};
if (callee.kind == nkind.N_DOT) {
cnm = callee.str;
if (callee.lhs != nil) {
if (callee.lhs.kind == nkind.N_IDENT) {
cmod = callee.lhs.str;
};
};
};
if (cnm.len > 0) {
let rt: *node = fnretlookup(c, cnm);
let rt: *node = fnretlookupmod(c, cnm, cmod);
if (rt != nil) {
if (rt.kind == nkind.N_TTUPLE) {
p0t = rt.list;