selfhost/cmd/wcc/check: populate TY_TAGGED.params (#50 phase 1, A.6.3f-a)
Phase 1 of Rob's two-phase A.6.3f pattern: populate the variant
chain in `tinfofornode`'s TTAGGED arm so phase 2 (#50b) can retire
`nullable_ptr_tag`'s AST-keyed walk in cgenutil onto a tinfo read.
Per b8e5a92 (A.6.3b) commit body: "nullableptrtag stays AST-keyed
for now — tinfofornode doesn't populate TY_TAGGED.params … so the
tinfo equivalent of cstage cgen.c:405 nullable_ptr_tag can't read
params today."
Restructure the TTAGGED arm into a single pre-pass: walk `n.list`,
resolve each variant via tinfofornode, alloc `tparam{name="",
type_=vt, tnext=nil}`, link head/tail, accumulate maxsz + al
inline. Set `r.params = head` after the loop. AST-level nullable
fold runs after, before size assignment — kept AST-keyed (not
ported to cstage's tinfo-level `kind==TY_VOID && !iserror` check)
because wwstage tinfo carries no `iserror` field; that's an honest
data-shape divergence (filed in passing as part of #13's TTAGGED
normalization arc).
Mirrors cstage cmd/wcc/check.c:347-435 — same head/tail append-
list construction, same Tparam reuse across struct-fields /
tuple-fields / fn-params / tagged-variants (sea-of-stars per
rule 12 — one record, four consumers, no per-kind variant of
the param node). Diverges from harec's array+id-sort at
ref/harec/include/types.h:128-132 / ref/harec/src/type_store.c:
431-432; rule 10 anchors wwstage byte-id to cstage, not harec.
Purely additive: ti.params has zero readers on TY_TAGGED today
(typeeq walks params only for TY_FN/TY_TUPLE; cgenutil's
nullableptrtag is still AST-keyed; #50b will consume). Byte-
identity (994/995) unchanged at 133/133 — pre-impl risk audit
by ken-thompson came back zero, confirmed by full make test.
A latent divergence wwstage doesn't cover (never-drop /
...spread / dedup / single-variant collapse — see cstage type
set normalization at check.c:393-432) is pre-existing and out
of #50's scope; tracked as #13. Phase 2 nullableptrtag is a
linear walk for the first TY_PTR variant in a 2-variant
nullable, indifferent to ordering and dedup, so it does not
need #13 closed first.
Net +12 LOC per file across check.ww + two .combined.ww
bundler regens.
This commit is contained in:
@@ -8369,12 +8369,36 @@ fn tinfofornode(c: *checker, n: *node) *tinfo = {
|
||||
// sum-type shapes through NAMED variants).
|
||||
r = newtype(tykind.TY_TAGGED);
|
||||
tinfocachebind(c.tc, n, r);
|
||||
// #50 / A.6.3f phase 1: populate ti.params as a tparam linked
|
||||
// list (head=first source variant) in lock-step with the
|
||||
// size/align accumulator. Mirrors cstage check.c:374-396 —
|
||||
// same Tparam shape ww reuses across struct-fields / tuple-
|
||||
// fields / fn-params / tagged-variants (sea-of-stars per rule
|
||||
// 12). Phase 2 (#50b) retires cgenutil's AST-keyed
|
||||
// nullableptrtag onto the chain.
|
||||
let head: *tparam = nil;
|
||||
let tail: *tparam = nil;
|
||||
let maxsz: u64 = 0u64;
|
||||
let al: u64 = 8u64;
|
||||
let v: *node = n.list;
|
||||
for (v != nil) {
|
||||
let vt: *tinfo = tinfofornode(c, v);
|
||||
let tp: *tparam = alloc(tparam{name="", type_=vt, tnext=nil})!;
|
||||
if (head == nil) { head = tp; } else { tail.tnext = tp; };
|
||||
tail = tp;
|
||||
if (vt != nil) {
|
||||
if (vt.size > maxsz) { maxsz = vt.size; };
|
||||
if (vt.align > al) { al = vt.align; };
|
||||
};
|
||||
v = v.next;
|
||||
};
|
||||
r.params = head;
|
||||
// #61 A.3 nullable fold: `(*T | void)` collapses to a single
|
||||
// 8B pointer slot, null is the void variant. Mirrors
|
||||
// cmd/wcc/check.c:412-426 — bare TNAME("void"), not `!void`,
|
||||
// and not NAMED — so wwstage slotsize fast-path can graduate
|
||||
// TY_TAGGED off the AST-walker fallback. Match before counting
|
||||
// variants so the 8B fold lands in tinfo.size directly.
|
||||
// and not NAMED. AST-kind discrimination retained: wwstage
|
||||
// tinfo carries no `iserror` field, so cstage's tinfo-level
|
||||
// (kind==TY_VOID && !iserror) check doesn't port symmetrically.
|
||||
let a: *node = n.list;
|
||||
if (a != nil) {
|
||||
let b: *node = a.next;
|
||||
@@ -8393,22 +8417,10 @@ fn tinfofornode(c: *checker, n: *node) *tinfo = {
|
||||
r.align = 8u64;
|
||||
r.nullable = 1;
|
||||
r.slotsize = 8u64;
|
||||
tinfocachebind(c.tc, n, r);
|
||||
return r;
|
||||
};
|
||||
};
|
||||
};
|
||||
let maxsz: u64 = 0u64;
|
||||
let al: u64 = 8u64;
|
||||
let v: *node = n.list;
|
||||
for (v != nil) {
|
||||
let vt: *tinfo = tinfofornode(c, v);
|
||||
if (vt != nil) {
|
||||
if (vt.size > maxsz) { maxsz = vt.size; };
|
||||
if (vt.align > al) { al = vt.align; };
|
||||
};
|
||||
v = v.next;
|
||||
};
|
||||
let pad: u64 = (maxsz + 7u64) & ~7u64;
|
||||
r.size = 8u64 + pad;
|
||||
r.align = al;
|
||||
|
||||
@@ -1299,12 +1299,36 @@ fn tinfofornode(c: *checker, n: *node) *tinfo = {
|
||||
// sum-type shapes through NAMED variants).
|
||||
r = newtype(tykind.TY_TAGGED);
|
||||
tinfocachebind(c.tc, n, r);
|
||||
// #50 / A.6.3f phase 1: populate ti.params as a tparam linked
|
||||
// list (head=first source variant) in lock-step with the
|
||||
// size/align accumulator. Mirrors cstage check.c:374-396 —
|
||||
// same Tparam shape ww reuses across struct-fields / tuple-
|
||||
// fields / fn-params / tagged-variants (sea-of-stars per rule
|
||||
// 12). Phase 2 (#50b) retires cgenutil's AST-keyed
|
||||
// nullableptrtag onto the chain.
|
||||
let head: *tparam = nil;
|
||||
let tail: *tparam = nil;
|
||||
let maxsz: u64 = 0u64;
|
||||
let al: u64 = 8u64;
|
||||
let v: *node = n.list;
|
||||
for (v != nil) {
|
||||
let vt: *tinfo = tinfofornode(c, v);
|
||||
let tp: *tparam = alloc(tparam{name="", type_=vt, tnext=nil})!;
|
||||
if (head == nil) { head = tp; } else { tail.tnext = tp; };
|
||||
tail = tp;
|
||||
if (vt != nil) {
|
||||
if (vt.size > maxsz) { maxsz = vt.size; };
|
||||
if (vt.align > al) { al = vt.align; };
|
||||
};
|
||||
v = v.next;
|
||||
};
|
||||
r.params = head;
|
||||
// #61 A.3 nullable fold: `(*T | void)` collapses to a single
|
||||
// 8B pointer slot, null is the void variant. Mirrors
|
||||
// cmd/wcc/check.c:412-426 — bare TNAME("void"), not `!void`,
|
||||
// and not NAMED — so wwstage slotsize fast-path can graduate
|
||||
// TY_TAGGED off the AST-walker fallback. Match before counting
|
||||
// variants so the 8B fold lands in tinfo.size directly.
|
||||
// and not NAMED. AST-kind discrimination retained: wwstage
|
||||
// tinfo carries no `iserror` field, so cstage's tinfo-level
|
||||
// (kind==TY_VOID && !iserror) check doesn't port symmetrically.
|
||||
let a: *node = n.list;
|
||||
if (a != nil) {
|
||||
let b: *node = a.next;
|
||||
@@ -1323,22 +1347,10 @@ fn tinfofornode(c: *checker, n: *node) *tinfo = {
|
||||
r.align = 8u64;
|
||||
r.nullable = 1;
|
||||
r.slotsize = 8u64;
|
||||
tinfocachebind(c.tc, n, r);
|
||||
return r;
|
||||
};
|
||||
};
|
||||
};
|
||||
let maxsz: u64 = 0u64;
|
||||
let al: u64 = 8u64;
|
||||
let v: *node = n.list;
|
||||
for (v != nil) {
|
||||
let vt: *tinfo = tinfofornode(c, v);
|
||||
if (vt != nil) {
|
||||
if (vt.size > maxsz) { maxsz = vt.size; };
|
||||
if (vt.align > al) { al = vt.align; };
|
||||
};
|
||||
v = v.next;
|
||||
};
|
||||
let pad: u64 = (maxsz + 7u64) & ~7u64;
|
||||
r.size = 8u64 + pad;
|
||||
r.align = al;
|
||||
|
||||
@@ -8369,12 +8369,36 @@ fn tinfofornode(c: *checker, n: *node) *tinfo = {
|
||||
// sum-type shapes through NAMED variants).
|
||||
r = newtype(tykind.TY_TAGGED);
|
||||
tinfocachebind(c.tc, n, r);
|
||||
// #50 / A.6.3f phase 1: populate ti.params as a tparam linked
|
||||
// list (head=first source variant) in lock-step with the
|
||||
// size/align accumulator. Mirrors cstage check.c:374-396 —
|
||||
// same Tparam shape ww reuses across struct-fields / tuple-
|
||||
// fields / fn-params / tagged-variants (sea-of-stars per rule
|
||||
// 12). Phase 2 (#50b) retires cgenutil's AST-keyed
|
||||
// nullableptrtag onto the chain.
|
||||
let head: *tparam = nil;
|
||||
let tail: *tparam = nil;
|
||||
let maxsz: u64 = 0u64;
|
||||
let al: u64 = 8u64;
|
||||
let v: *node = n.list;
|
||||
for (v != nil) {
|
||||
let vt: *tinfo = tinfofornode(c, v);
|
||||
let tp: *tparam = alloc(tparam{name="", type_=vt, tnext=nil})!;
|
||||
if (head == nil) { head = tp; } else { tail.tnext = tp; };
|
||||
tail = tp;
|
||||
if (vt != nil) {
|
||||
if (vt.size > maxsz) { maxsz = vt.size; };
|
||||
if (vt.align > al) { al = vt.align; };
|
||||
};
|
||||
v = v.next;
|
||||
};
|
||||
r.params = head;
|
||||
// #61 A.3 nullable fold: `(*T | void)` collapses to a single
|
||||
// 8B pointer slot, null is the void variant. Mirrors
|
||||
// cmd/wcc/check.c:412-426 — bare TNAME("void"), not `!void`,
|
||||
// and not NAMED — so wwstage slotsize fast-path can graduate
|
||||
// TY_TAGGED off the AST-walker fallback. Match before counting
|
||||
// variants so the 8B fold lands in tinfo.size directly.
|
||||
// and not NAMED. AST-kind discrimination retained: wwstage
|
||||
// tinfo carries no `iserror` field, so cstage's tinfo-level
|
||||
// (kind==TY_VOID && !iserror) check doesn't port symmetrically.
|
||||
let a: *node = n.list;
|
||||
if (a != nil) {
|
||||
let b: *node = a.next;
|
||||
@@ -8393,22 +8417,10 @@ fn tinfofornode(c: *checker, n: *node) *tinfo = {
|
||||
r.align = 8u64;
|
||||
r.nullable = 1;
|
||||
r.slotsize = 8u64;
|
||||
tinfocachebind(c.tc, n, r);
|
||||
return r;
|
||||
};
|
||||
};
|
||||
};
|
||||
let maxsz: u64 = 0u64;
|
||||
let al: u64 = 8u64;
|
||||
let v: *node = n.list;
|
||||
for (v != nil) {
|
||||
let vt: *tinfo = tinfofornode(c, v);
|
||||
if (vt != nil) {
|
||||
if (vt.size > maxsz) { maxsz = vt.size; };
|
||||
if (vt.align > al) { al = vt.align; };
|
||||
};
|
||||
v = v.next;
|
||||
};
|
||||
let pad: u64 = (maxsz + 7u64) & ~7u64;
|
||||
r.size = 8u64 + pad;
|
||||
r.align = al;
|
||||
|
||||
Reference in New Issue
Block a user