selfhost+cstage+test: graduate alias-chain unwrap to transitive (#22)
Single-peel TY_NAMED.under bottoms out at the inner alias when chain length is 2+, surfaces in two stages with different mechanisms: cstage's gates inline `if (t->kind == TY_NAMED) t = t->under` at every callsite (cgreturn, cglet sizing, cgexpr N_DOT, cgassign N_DOT, cg_sret_retsize) — graduated to a while-loop via new type_chase_named helper across 11 sites. wwstage routes all field-walks through structlookup, which registers only direct struct definitions (not aliases) — missing the alias-recurse fallback. New structlookupchain helper mirrors slotsize's N_TARRAY arm precedent; sretretsize + 4 cgenexpr.ww sites route through it. Splitting would either land cstage without unblocking wwstage's strings.tokenize wrapper shape (rule 10 byte-id regression) or land wwstage without cstage gate parity (breaking 995 self-rebuild). 756 sentinel exercises 4 rows × cstage RC + wwstage RC + byte-id = 12 fixtures; pre-fix rows 2 + 4 (slice-fields single alias, i32 double alias) fail on both RC and byte-id. The ~67 cstage / ~26 wwstage candidate sibling sites are #17-style structural-close follow-up; this commit fixes the immediate strings.tokenize-wrapper blockers.
This commit is contained in:
@@ -1520,6 +1520,39 @@ fn structnaturalsize(si: *structinfo) i32 = {
|
||||
// cg_sret_retsize predicate. Resolves N_TNAME → struct via structlookup
|
||||
// and unwraps one leading N_TBANG so `type box = !big;` still
|
||||
// triggers sret on the underlying big.
|
||||
//
|
||||
// Chain-of-aliases (#22): `type a = struct{...}; type b = a;` registers
|
||||
// `b → a` in c.aliases (target node = N_TNAME "a"), not `b → struct`.
|
||||
// When structlookup(c, "b") misses, fall through to aliaslookup and
|
||||
// recurse on the alias target — mirrors slotsize's N_TNAME arm
|
||||
// (cgenutil.ww:1955) and the cstage while-loop in cg_sret_retsize.
|
||||
|
||||
// structlookupchain — resolve TNAME `tn` to its registered struct,
|
||||
// chasing alias-of-alias (#22). Returns nil if the chain doesn't
|
||||
// bottom out at a struct. Mirrors cstage's transitive
|
||||
// `while (t->kind == TY_NAMED) t = t->under` peel; consumed by
|
||||
// cgdot / cgassign at every "field-walk on a struct-typed local"
|
||||
// site so a transitively-aliased struct name resolves to its
|
||||
// fieldinfo list regardless of chain depth.
|
||||
export fn structlookupchain(c: *cgen, tn: *node) *structinfo = {
|
||||
if (tn == nil) { return nil; };
|
||||
if (tn.kind != nkind.N_TNAME) { return nil; };
|
||||
let si: *structinfo = structlookup(c, tn.str);
|
||||
if (si != nil) { return si; };
|
||||
let cur: *node = tn;
|
||||
for (cur != nil && cur.kind == nkind.N_TNAME && si == nil) {
|
||||
let aliased: *node = aliaslookup(c, cur.str);
|
||||
if (aliased == nil) { cur = nil; }
|
||||
else {
|
||||
if (aliased.kind == nkind.N_TNAME) {
|
||||
si = structlookup(c, aliased.str);
|
||||
cur = aliased;
|
||||
} else { cur = nil; };
|
||||
};
|
||||
};
|
||||
return si;
|
||||
};
|
||||
|
||||
export fn sretretsize(c: *cgen, t: *node) i32 = {
|
||||
if (t == nil) { return 0; };
|
||||
let r: *node = t;
|
||||
@@ -1532,7 +1565,15 @@ export fn sretretsize(c: *cgen, t: *node) i32 = {
|
||||
if (primsize(r.str) > 0) { return 0; };
|
||||
if (streq(r.str, "str")) { return 0; };
|
||||
let si: *structinfo = structlookup(c, r.str);
|
||||
if (si == nil) { return 0; };
|
||||
if (si == nil) {
|
||||
if (c != nil) {
|
||||
let aliased: *node = aliaslookup(c, r.str);
|
||||
if (aliased != nil) {
|
||||
return sretretsize(c, aliased);
|
||||
};
|
||||
};
|
||||
return 0;
|
||||
};
|
||||
let n: i32 = structnaturalsize(si);
|
||||
if (n <= 24) { return 0; };
|
||||
return n;
|
||||
|
||||
Reference in New Issue
Block a user