cgen: resolve chained-DOT fn-ptr field callees
fnptrcalleetfn's N_DOT arm required an N_IDENT base, so a.b.cb(...) fell to the name registry with an empty module hint and emitted CALL cb(SB) (undefined symbol; cstage calls the stamped ptr indirect). dotbasestructinfo resolves the base chain through the struct registry — each link a struct- or *struct-typed field — and the single-dot path routes through the same resolver unchanged. Closes the last open shape of the #59.8 name-keyed callee family. Fixture fnptrfield_chain; corpus pin 1487/2974.
This commit is contained in:
@@ -64,6 +64,53 @@ fn findvariadicparam(ps: *syntax.node, nfixed_out: *i32) *syntax.node = {
|
||||
// lookup missed entirely and the raw N_SPREAD leaked to pushargsrev
|
||||
// as a single $0 word). Cstage mirror: cgcall's callee_params from
|
||||
// the checker-stamped n->lhs->type (cmd/w6c/cgen.c TY_FN cu->params).
|
||||
// dotbasestructinfo — the struct registry entry for a DOT base: a
|
||||
// local ident (struct value or *struct), or a nested field chain
|
||||
// (`a.b.cb(...)` — each link a struct- or *struct-typed field). The
|
||||
// chained form previously fell to the name registry with an empty
|
||||
// module hint (the #59.8 family's last open shape) and emitted
|
||||
// CALL <leaf>(SB).
|
||||
fn dotbasestructinfo(c: *cgen, base: *syntax.node) *structinfo = {
|
||||
if (base == nil) { return nil; };
|
||||
if (base.kind == syntax.nkind.N_IDENT) {
|
||||
let lc: *local = localfindnode(c, base.str);
|
||||
if (lc == nil) { return nil; };
|
||||
let tn: *syntax.node = lc.tnode;
|
||||
if (tn == nil) { return nil; };
|
||||
let sname: str;
|
||||
sname.ptr = nil; sname.len = 0;
|
||||
if (tn.kind == syntax.nkind.N_TNAME) { sname = tn.str; };
|
||||
if (tn.kind == syntax.nkind.N_TPTR) {
|
||||
if (tn.lhs != nil) {
|
||||
if (tn.lhs.kind == syntax.nkind.N_TNAME) {
|
||||
sname = tn.lhs.str;
|
||||
};
|
||||
};
|
||||
};
|
||||
if (sname.len == 0) { return nil; };
|
||||
return structlookup(c, sname);
|
||||
};
|
||||
if (base.kind != syntax.nkind.N_DOT) { return nil; };
|
||||
let outer: *structinfo = dotbasestructinfo(c, base.lhs);
|
||||
if (outer == nil) { return nil; };
|
||||
let fi: *fieldinfo = outer.fields;
|
||||
for (fi != nil) {
|
||||
if (syntax.streq(fi.fname, base.str)) {
|
||||
let ft: *syntax.node = fi.tnode;
|
||||
if (ft == nil) { return nil; };
|
||||
if (ft.kind == syntax.nkind.N_TPTR) {
|
||||
if (ft.lhs != nil) { ft = ft.lhs; };
|
||||
};
|
||||
if (ft.kind == syntax.nkind.N_TNAME) {
|
||||
return structlookup(c, ft.str);
|
||||
};
|
||||
return nil;
|
||||
};
|
||||
fi = fi.finext;
|
||||
};
|
||||
return nil;
|
||||
};
|
||||
|
||||
fn fnptrcalleetfn(c: *cgen, callee: *syntax.node) *syntax.node = {
|
||||
if (callee == nil) { return nil; };
|
||||
if (callee.kind == syntax.nkind.N_IDENT) {
|
||||
@@ -82,25 +129,7 @@ fn fnptrcalleetfn(c: *cgen, callee: *syntax.node) *syntax.node = {
|
||||
return nil;
|
||||
};
|
||||
if (callee.kind != syntax.nkind.N_DOT) { return nil; };
|
||||
let base: *syntax.node = callee.lhs;
|
||||
if (base == nil) { return nil; };
|
||||
if (base.kind != syntax.nkind.N_IDENT) { return nil; };
|
||||
let lc: *local = localfindnode(c, base.str);
|
||||
if (lc == nil) { return nil; };
|
||||
let tn: *syntax.node = lc.tnode;
|
||||
if (tn == nil) { return nil; };
|
||||
let sname: str;
|
||||
sname.ptr = nil; sname.len = 0;
|
||||
if (tn.kind == syntax.nkind.N_TNAME) { sname = tn.str; };
|
||||
if (tn.kind == syntax.nkind.N_TPTR) {
|
||||
if (tn.lhs != nil) {
|
||||
if (tn.lhs.kind == syntax.nkind.N_TNAME) {
|
||||
sname = tn.lhs.str;
|
||||
};
|
||||
};
|
||||
};
|
||||
if (sname.len == 0) { return nil; };
|
||||
let si: *structinfo = structlookup(c, sname);
|
||||
let si: *structinfo = dotbasestructinfo(c, callee.lhs);
|
||||
if (si == nil) { return nil; };
|
||||
let fi: *fieldinfo = si.fields;
|
||||
for (fi != nil) {
|
||||
|
||||
Reference in New Issue
Block a user