selfhost/cmd/wcc/cgenutil: exprprimresolved N_DOT off dotfieldtnode (#59)

exprprimresolved's N_DOT arm derived a struct field's prim width+sign by
walking the field's declared *node (dotfieldtnode + typenodeprimresolved
alias recursion). Read the checker-stamped tinfo instead, mirroring cstage
castsrcprim N_DOT (cmd/w6c/cgen.c:323-344): the base's n.lhs.type_ must
resolve to a struct (peel NAMED->PTR->NAMED, require TY_STRUCT) before the
field counts -- excluding pseudo-fields .len/.cap/.ptr (stamped i32/*T at
check.ww:1987-2004; their base is TY_SLICE/TY_STR/TY_ARRAY, never TY_STRUCT,
so the guard yields sz=0) and tuple positionals, which stay sz=0 to preserve
995 byte-id. The field's width/sign comes from the N_DOT's own n.type_
(check.ww:2012), one NAMED peel then typeisint?size:0. Bool exclusion is
now free via typeisint(bool)=false, dropping the old streq("bool") arm.

Polarity DOWN per rule 10: cstage castsrcprim already reads the stamped
type. typenamed() has zero callers in wwstage (tinfofornode collapses all
alias depth to the body), so no tinfo carries kind TY_NAMED -- the NAMED
peels are dead/inert, output matches cstage.

Removes one dotfieldtnode caller (3->2; remaining cgenutil 1073, 1871).
typenodeprimresolved retained (3 callers: cgenutil 1459/1465, cgenexpr 431).
Part of the dotfield* consumer-migration arc.

make test 133/133 (quiescent tree, byte-id 990-997 green). Coverage:
710_cast_enum_movl rows struct_field_rt + pseudo_field_clamp + bool_to_i8.
This commit is contained in:
2026-05-23 16:10:46 +09:00
parent 8ccda588c6
commit 827a05e548
3 changed files with 72 additions and 6 deletions

View File

@@ -11911,8 +11911,30 @@ export fn exprprimresolved(c: *cgen, n: *node,
return;
};
if (k == nkind.N_DOT) {
typenodeprimresolved(c, dotfieldtnode(c, n),
sz_out, unsigned_out);
// #59: read the checker-stamped tinfo instead of re-deriving the
// field type via dotfieldtnode's structinfo walk. Mirrors cstage
// castsrcprim N_DOT (cmd/w6c/cgen.c:323-344): the base must
// resolve to a struct (or ptr-to-struct) before the field type
// counts. That guard excludes pseudo-fields .len/.cap/.ptr (the
// checker stamps them i32/*T at check.ww:1987-2004) and tuple
// positionals, keeping them at sz=0 — asymmetry there breaks 995
// byte-id (cgen.c:286-290). The field's own width/sign is the
// N_DOT's stamped type_ (check.ww:2012). One TY_NAMED peel, then
// typeisint ? size : 0; bool falls out because typeisint(bool) is
// false — the same exclusion the old streq("bool") arm encoded.
let bu: *tinfo = nil;
if (n.lhs != nil) { bu = n.lhs.type_: *tinfo; };
if (bu != nil && bu.kind == tykind.TY_NAMED) { bu = bu.under; };
if (bu != nil && bu.kind == tykind.TY_PTR) { bu = bu.sub; };
if (bu != nil && bu.kind == tykind.TY_NAMED) { bu = bu.under; };
if (bu != nil && bu.kind == tykind.TY_STRUCT) {
let u: *tinfo = n.type_: *tinfo;
if (u != nil && u.kind == tykind.TY_NAMED) { u = u.under; };
if (typeisint(u)) {
*sz_out = u.size: i32;
*unsigned_out = typeisunsigned(u);
};
};
return;
};
};

View File

@@ -1470,8 +1470,30 @@ export fn exprprimresolved(c: *cgen, n: *node,
return;
};
if (k == nkind.N_DOT) {
typenodeprimresolved(c, dotfieldtnode(c, n),
sz_out, unsigned_out);
// #59: read the checker-stamped tinfo instead of re-deriving the
// field type via dotfieldtnode's structinfo walk. Mirrors cstage
// castsrcprim N_DOT (cmd/w6c/cgen.c:323-344): the base must
// resolve to a struct (or ptr-to-struct) before the field type
// counts. That guard excludes pseudo-fields .len/.cap/.ptr (the
// checker stamps them i32/*T at check.ww:1987-2004) and tuple
// positionals, keeping them at sz=0 — asymmetry there breaks 995
// byte-id (cgen.c:286-290). The field's own width/sign is the
// N_DOT's stamped type_ (check.ww:2012). One TY_NAMED peel, then
// typeisint ? size : 0; bool falls out because typeisint(bool) is
// false — the same exclusion the old streq("bool") arm encoded.
let bu: *tinfo = nil;
if (n.lhs != nil) { bu = n.lhs.type_: *tinfo; };
if (bu != nil && bu.kind == tykind.TY_NAMED) { bu = bu.under; };
if (bu != nil && bu.kind == tykind.TY_PTR) { bu = bu.sub; };
if (bu != nil && bu.kind == tykind.TY_NAMED) { bu = bu.under; };
if (bu != nil && bu.kind == tykind.TY_STRUCT) {
let u: *tinfo = n.type_: *tinfo;
if (u != nil && u.kind == tykind.TY_NAMED) { u = u.under; };
if (typeisint(u)) {
*sz_out = u.size: i32;
*unsigned_out = typeisunsigned(u);
};
};
return;
};
};

View File

@@ -11911,8 +11911,30 @@ export fn exprprimresolved(c: *cgen, n: *node,
return;
};
if (k == nkind.N_DOT) {
typenodeprimresolved(c, dotfieldtnode(c, n),
sz_out, unsigned_out);
// #59: read the checker-stamped tinfo instead of re-deriving the
// field type via dotfieldtnode's structinfo walk. Mirrors cstage
// castsrcprim N_DOT (cmd/w6c/cgen.c:323-344): the base must
// resolve to a struct (or ptr-to-struct) before the field type
// counts. That guard excludes pseudo-fields .len/.cap/.ptr (the
// checker stamps them i32/*T at check.ww:1987-2004) and tuple
// positionals, keeping them at sz=0 — asymmetry there breaks 995
// byte-id (cgen.c:286-290). The field's own width/sign is the
// N_DOT's stamped type_ (check.ww:2012). One TY_NAMED peel, then
// typeisint ? size : 0; bool falls out because typeisint(bool) is
// false — the same exclusion the old streq("bool") arm encoded.
let bu: *tinfo = nil;
if (n.lhs != nil) { bu = n.lhs.type_: *tinfo; };
if (bu != nil && bu.kind == tykind.TY_NAMED) { bu = bu.under; };
if (bu != nil && bu.kind == tykind.TY_PTR) { bu = bu.sub; };
if (bu != nil && bu.kind == tykind.TY_NAMED) { bu = bu.under; };
if (bu != nil && bu.kind == tykind.TY_STRUCT) {
let u: *tinfo = n.type_: *tinfo;
if (u != nil && u.kind == tykind.TY_NAMED) { u = u.under; };
if (typeisint(u)) {
*sz_out = u.size: i32;
*unsigned_out = typeisunsigned(u);
};
};
return;
};
};