selfhost/cmd/wcc/check: flatten tagged spreads + iserror on tinfo.params (#61a)
A.6.3 #61 prerequisite (additive, no consumer changes). The tagged-variant machinery (taggedvariantindex / flatvariant* / cgwidentagremap / cgmatch) is AST-keyed -- it walks N_TTAGGED.list and spread-flattens `...inner` at read time. To migrate it onto tinfo.params (#61b/c) the chain must first carry the flattened variant set + per-variant error mark, matching cstage's Type.params / Type.iserror. tinfofornode's TTAGGED arm now splices `...inner` tagged spreads into ti.params (dealias one NAMED level, require TY_TAGGED, inline its already- flattened variants in declaration order) -- mirror of cstage check.c:366-389. Each variant gets an iserror flag via varianterr (TBANG / `!`-aliased). size/align stay accounted off the surface member so ti.size is byte-identical to before; the flatten + iserror have zero readers this commit (the lone TY_TAGGED params reader, nullableptrtag, only fires on 2-variant nullable unions with no spreads). iserror rides the shared tparam struct rather than a sidecar: a cstage-mirror divergence from harec, which carries no per-variant flag (models `!T` as a STORAGE_ERROR type node, ref/harec/include/types.h:144, src/types.c:151-159). Faithful port filed as #62. Spread-only flatten (cstage check.c:373 also flattens non-spread anonymous-nested unions) is a known symmetry gap, inert in bootstrap, tracked for #61b. make test 133/133 (quiescent tree, byte-id 990-997 green).
This commit is contained in:
@@ -71,6 +71,15 @@ type tfield = struct {
|
||||
type tparam = struct {
|
||||
name: str,
|
||||
type_: *tinfo,
|
||||
// #61a: per-variant `!T` error mark for TY_TAGGED variants.
|
||||
// cstage-MIRROR divergence: harec carries no per-variant flag —
|
||||
// it models `!T` as a distinct STORAGE_ERROR type node
|
||||
// (ref/harec/include/types.h:144, src/types.c:151-159
|
||||
// type_is_error). wwstage tinfo has no iserror field
|
||||
// (check.ww TTAGGED arm), so the bit rides the shared param
|
||||
// struct instead, matching cstage Type.iserror semantics.
|
||||
// Faithful STORAGE_ERROR-node port filed as #62.
|
||||
iserror: bool,
|
||||
tnext: *tparam,
|
||||
};
|
||||
|
||||
|
||||
@@ -6401,6 +6401,15 @@ type tfield = struct {
|
||||
type tparam = struct {
|
||||
name: str,
|
||||
type_: *tinfo,
|
||||
// #61a: per-variant `!T` error mark for TY_TAGGED variants.
|
||||
// cstage-MIRROR divergence: harec carries no per-variant flag —
|
||||
// it models `!T` as a distinct STORAGE_ERROR type node
|
||||
// (ref/harec/include/types.h:144, src/types.c:151-159
|
||||
// type_is_error). wwstage tinfo has no iserror field
|
||||
// (check.ww TTAGGED arm), so the bit rides the shared param
|
||||
// struct instead, matching cstage Type.iserror semantics.
|
||||
// Faithful STORAGE_ERROR-node port filed as #62.
|
||||
iserror: bool,
|
||||
tnext: *tparam,
|
||||
};
|
||||
|
||||
@@ -8427,12 +8436,19 @@ fn tinfofornode(c: *checker, n: *node) *tinfo = {
|
||||
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.
|
||||
// list (head=first source variant). #61a: flatten `...inner`
|
||||
// tagged spreads into the chain and stamp each variant's
|
||||
// iserror. Mirrors cstage check.c:366-389 — dealias one NAMED
|
||||
// level, require TY_TAGGED, splice its (already-flattened)
|
||||
// variants in declaration order; otherwise append the single
|
||||
// variant. size/align stays accounted off the surface member
|
||||
// (vt), so r.size is byte-identical to pre-#61a: the flatten +
|
||||
// iserror are additive, with no #61a-stage readers (the variant
|
||||
// machinery + cgwidentaggedstore/matchscrutt migrate onto the
|
||||
// chain in #61b/c). Same shared Tparam shape ww reuses across
|
||||
// struct-fields / tuple-fields / fn-params / tagged-variants
|
||||
// (sea-of-stars per rule 12). Phase 2 (#50b) retired cgenutil's
|
||||
// AST-keyed nullableptrtag onto the chain.
|
||||
let head: *tparam = nil;
|
||||
let tail: *tparam = nil;
|
||||
let maxsz: u64 = 0u64;
|
||||
@@ -8440,13 +8456,33 @@ fn tinfofornode(c: *checker, n: *node) *tinfo = {
|
||||
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; };
|
||||
};
|
||||
let isspread: bool = (v.op == tkind.TK_ELLIPSIS);
|
||||
let vu: *tinfo = vt;
|
||||
if (isspread) {
|
||||
if (vu != nil) {
|
||||
if (vu.kind == tykind.TY_NAMED) { vu = vu.under; };
|
||||
};
|
||||
};
|
||||
if (isspread && vu != nil && vu.kind == tykind.TY_TAGGED) {
|
||||
// Spliced variants carry the inner union's
|
||||
// already-stamped iserror; no re-derivation.
|
||||
let src: *tparam = vu.params;
|
||||
for (src != nil) {
|
||||
let tp: *tparam = alloc(tparam{name="", type_=src.type_, iserror=src.iserror, tnext=nil})!;
|
||||
if (head == nil) { head = tp; } else { tail.tnext = tp; };
|
||||
tail = tp;
|
||||
src = src.tnext;
|
||||
};
|
||||
} else {
|
||||
let ve: bool = varianterr(c, v);
|
||||
let tp: *tparam = alloc(tparam{name="", type_=vt, iserror=ve, tnext=nil})!;
|
||||
if (head == nil) { head = tp; } else { tail.tnext = tp; };
|
||||
tail = tp;
|
||||
};
|
||||
v = v.next;
|
||||
};
|
||||
r.params = head;
|
||||
|
||||
@@ -1339,12 +1339,19 @@ fn tinfofornode(c: *checker, n: *node) *tinfo = {
|
||||
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.
|
||||
// list (head=first source variant). #61a: flatten `...inner`
|
||||
// tagged spreads into the chain and stamp each variant's
|
||||
// iserror. Mirrors cstage check.c:366-389 — dealias one NAMED
|
||||
// level, require TY_TAGGED, splice its (already-flattened)
|
||||
// variants in declaration order; otherwise append the single
|
||||
// variant. size/align stays accounted off the surface member
|
||||
// (vt), so r.size is byte-identical to pre-#61a: the flatten +
|
||||
// iserror are additive, with no #61a-stage readers (the variant
|
||||
// machinery + cgwidentaggedstore/matchscrutt migrate onto the
|
||||
// chain in #61b/c). Same shared Tparam shape ww reuses across
|
||||
// struct-fields / tuple-fields / fn-params / tagged-variants
|
||||
// (sea-of-stars per rule 12). Phase 2 (#50b) retired cgenutil's
|
||||
// AST-keyed nullableptrtag onto the chain.
|
||||
let head: *tparam = nil;
|
||||
let tail: *tparam = nil;
|
||||
let maxsz: u64 = 0u64;
|
||||
@@ -1352,13 +1359,33 @@ fn tinfofornode(c: *checker, n: *node) *tinfo = {
|
||||
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; };
|
||||
};
|
||||
let isspread: bool = (v.op == tkind.TK_ELLIPSIS);
|
||||
let vu: *tinfo = vt;
|
||||
if (isspread) {
|
||||
if (vu != nil) {
|
||||
if (vu.kind == tykind.TY_NAMED) { vu = vu.under; };
|
||||
};
|
||||
};
|
||||
if (isspread && vu != nil && vu.kind == tykind.TY_TAGGED) {
|
||||
// Spliced variants carry the inner union's
|
||||
// already-stamped iserror; no re-derivation.
|
||||
let src: *tparam = vu.params;
|
||||
for (src != nil) {
|
||||
let tp: *tparam = alloc(tparam{name="", type_=src.type_, iserror=src.iserror, tnext=nil})!;
|
||||
if (head == nil) { head = tp; } else { tail.tnext = tp; };
|
||||
tail = tp;
|
||||
src = src.tnext;
|
||||
};
|
||||
} else {
|
||||
let ve: bool = varianterr(c, v);
|
||||
let tp: *tparam = alloc(tparam{name="", type_=vt, iserror=ve, tnext=nil})!;
|
||||
if (head == nil) { head = tp; } else { tail.tnext = tp; };
|
||||
tail = tp;
|
||||
};
|
||||
v = v.next;
|
||||
};
|
||||
r.params = head;
|
||||
|
||||
@@ -6401,6 +6401,15 @@ type tfield = struct {
|
||||
type tparam = struct {
|
||||
name: str,
|
||||
type_: *tinfo,
|
||||
// #61a: per-variant `!T` error mark for TY_TAGGED variants.
|
||||
// cstage-MIRROR divergence: harec carries no per-variant flag —
|
||||
// it models `!T` as a distinct STORAGE_ERROR type node
|
||||
// (ref/harec/include/types.h:144, src/types.c:151-159
|
||||
// type_is_error). wwstage tinfo has no iserror field
|
||||
// (check.ww TTAGGED arm), so the bit rides the shared param
|
||||
// struct instead, matching cstage Type.iserror semantics.
|
||||
// Faithful STORAGE_ERROR-node port filed as #62.
|
||||
iserror: bool,
|
||||
tnext: *tparam,
|
||||
};
|
||||
|
||||
@@ -8427,12 +8436,19 @@ fn tinfofornode(c: *checker, n: *node) *tinfo = {
|
||||
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.
|
||||
// list (head=first source variant). #61a: flatten `...inner`
|
||||
// tagged spreads into the chain and stamp each variant's
|
||||
// iserror. Mirrors cstage check.c:366-389 — dealias one NAMED
|
||||
// level, require TY_TAGGED, splice its (already-flattened)
|
||||
// variants in declaration order; otherwise append the single
|
||||
// variant. size/align stays accounted off the surface member
|
||||
// (vt), so r.size is byte-identical to pre-#61a: the flatten +
|
||||
// iserror are additive, with no #61a-stage readers (the variant
|
||||
// machinery + cgwidentaggedstore/matchscrutt migrate onto the
|
||||
// chain in #61b/c). Same shared Tparam shape ww reuses across
|
||||
// struct-fields / tuple-fields / fn-params / tagged-variants
|
||||
// (sea-of-stars per rule 12). Phase 2 (#50b) retired cgenutil's
|
||||
// AST-keyed nullableptrtag onto the chain.
|
||||
let head: *tparam = nil;
|
||||
let tail: *tparam = nil;
|
||||
let maxsz: u64 = 0u64;
|
||||
@@ -8440,13 +8456,33 @@ fn tinfofornode(c: *checker, n: *node) *tinfo = {
|
||||
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; };
|
||||
};
|
||||
let isspread: bool = (v.op == tkind.TK_ELLIPSIS);
|
||||
let vu: *tinfo = vt;
|
||||
if (isspread) {
|
||||
if (vu != nil) {
|
||||
if (vu.kind == tykind.TY_NAMED) { vu = vu.under; };
|
||||
};
|
||||
};
|
||||
if (isspread && vu != nil && vu.kind == tykind.TY_TAGGED) {
|
||||
// Spliced variants carry the inner union's
|
||||
// already-stamped iserror; no re-derivation.
|
||||
let src: *tparam = vu.params;
|
||||
for (src != nil) {
|
||||
let tp: *tparam = alloc(tparam{name="", type_=src.type_, iserror=src.iserror, tnext=nil})!;
|
||||
if (head == nil) { head = tp; } else { tail.tnext = tp; };
|
||||
tail = tp;
|
||||
src = src.tnext;
|
||||
};
|
||||
} else {
|
||||
let ve: bool = varianterr(c, v);
|
||||
let tp: *tparam = alloc(tparam{name="", type_=vt, iserror=ve, tnext=nil})!;
|
||||
if (head == nil) { head = tp; } else { tail.tnext = tp; };
|
||||
tail = tp;
|
||||
};
|
||||
v = v.next;
|
||||
};
|
||||
r.params = head;
|
||||
|
||||
Reference in New Issue
Block a user