wcc_ww/check: #47 gap-B tuple-with-tagged case-arm variant-match (align-up)
wwstage's checker rejected a `case let t: ((void|size),(void|size),
size) =>` arm against a (tuple|error) scrutinee ("case: not a variant
of scrutinee"), while cstage accepts and runs it. typeeqast's N_TTUPLE
arm recurses per-element, but a tagged element (void|size) is
N_TTAGGED -> fell to the conservative catch-all `return false`, so the
whole tuple-compare failed. typeeqast is the sole acceptance route
(casevariantpairmatch is N_TNAME-only).
Add an N_TTAGGED arm to typeeqast, sibling of N_TTUPLE, mirroring
cstage type.c:288-300 (type_eq TY_TAGGED): position-by-position
variant compare over the tagged node's .list (direct nodes, not
.lhs-wrapped). cstage's nullable-flag check is deliberately not ported
(resolved-Type property, no ww AST analogue; moot for case-match).
A spread variant (TK_ELLIPSIS) in the .list is loud-rejected rather
than compared: a naive streq would silently accept a `...ab` case that
cstage rejects (a new cs!=ww over-accept the bare arm introduced).
Flattening the spread is deferred (#115); until then it louds, matching
cstage.
ww-only (cstage already accepts); the gap-A cgen store landed in
6a5bb3e. wwstage now accepts the b1c match and runs the full shape
byte-identical to cstage -> #47 (both gaps) closed. The deferred
full-b1c row in 944_tuple_tagged_union_run is promoted to a both-stage
runtime row. Checker change is acceptance-only/additive -> bootstrap
byte-id neutral (990-997 green).
This commit is contained in:
@@ -11174,9 +11174,40 @@ fn typeeqast(a: *node, b: *node) bool = {
|
||||
};
|
||||
return pb == nil;
|
||||
};
|
||||
// Conservative: anything else (struct/tagged/array) fails the
|
||||
// cheap check. Selfhost code doesn't currently rely on equality
|
||||
// at these shapes for the targeted checks.
|
||||
// #47 gap-B: tagged structural equality — mirror of cstage
|
||||
// type.c:288-300 (TY_TAGGED). A tuple member with a TAGGED element
|
||||
// (e.g. ((void|size),(void|size),size)) recurses here from the
|
||||
// N_TTUPLE arm; without it the per-element compare falls to the
|
||||
// catch-all and the whole case-against-tagged-scrutinee is rejected.
|
||||
// Variants are DIRECT .list nodes (casevariantin walks tagged.list
|
||||
// + typeeqast(v,..) directly), NOT N_TPARAM-wrapped like tuple elems.
|
||||
// Divergence: cstage's nullable-flag check (type.c:293) is a resolved-
|
||||
// Type property with no AST analogue; for case-match both sides share
|
||||
// a spelling so it's moot — no phantom AST nullable check.
|
||||
if (k == nkind.N_TTAGGED) {
|
||||
let pa: *node = aa.list;
|
||||
let pb: *node = bb.list;
|
||||
for (pa != nil) {
|
||||
if (pb == nil) { return false; };
|
||||
// #115: a `...inner` spread variant stays unflattened at
|
||||
// this AST layer (casevariantin flattens only at the OUTER
|
||||
// level; cstage flattens in resolve_type before type_eq ever
|
||||
// runs). A position-by-position compare cannot honour it —
|
||||
// the N_TNAME leg is pure streq, so `...ab` would silently
|
||||
// match a plain `ab`, accepting a case cstage rejects.
|
||||
// Conservatively loud-reject any spread until the flatten
|
||||
// lands; b1c's (void|size) has none, so byte-id is untouched.
|
||||
if (pa.op == tkind.TK_ELLIPSIS) { return false; };
|
||||
if (pb.op == tkind.TK_ELLIPSIS) { return false; };
|
||||
if (!typeeqast(pa, pb)) { return false; };
|
||||
pa = pa.next;
|
||||
pb = pb.next;
|
||||
};
|
||||
return pb == nil;
|
||||
};
|
||||
// Conservative: anything else (struct/array) fails the cheap
|
||||
// check. Selfhost code doesn't currently rely on equality at
|
||||
// these shapes for the targeted checks.
|
||||
return false;
|
||||
};
|
||||
|
||||
|
||||
@@ -893,9 +893,40 @@ fn typeeqast(a: *node, b: *node) bool = {
|
||||
};
|
||||
return pb == nil;
|
||||
};
|
||||
// Conservative: anything else (struct/tagged/array) fails the
|
||||
// cheap check. Selfhost code doesn't currently rely on equality
|
||||
// at these shapes for the targeted checks.
|
||||
// #47 gap-B: tagged structural equality — mirror of cstage
|
||||
// type.c:288-300 (TY_TAGGED). A tuple member with a TAGGED element
|
||||
// (e.g. ((void|size),(void|size),size)) recurses here from the
|
||||
// N_TTUPLE arm; without it the per-element compare falls to the
|
||||
// catch-all and the whole case-against-tagged-scrutinee is rejected.
|
||||
// Variants are DIRECT .list nodes (casevariantin walks tagged.list
|
||||
// + typeeqast(v,..) directly), NOT N_TPARAM-wrapped like tuple elems.
|
||||
// Divergence: cstage's nullable-flag check (type.c:293) is a resolved-
|
||||
// Type property with no AST analogue; for case-match both sides share
|
||||
// a spelling so it's moot — no phantom AST nullable check.
|
||||
if (k == nkind.N_TTAGGED) {
|
||||
let pa: *node = aa.list;
|
||||
let pb: *node = bb.list;
|
||||
for (pa != nil) {
|
||||
if (pb == nil) { return false; };
|
||||
// #115: a `...inner` spread variant stays unflattened at
|
||||
// this AST layer (casevariantin flattens only at the OUTER
|
||||
// level; cstage flattens in resolve_type before type_eq ever
|
||||
// runs). A position-by-position compare cannot honour it —
|
||||
// the N_TNAME leg is pure streq, so `...ab` would silently
|
||||
// match a plain `ab`, accepting a case cstage rejects.
|
||||
// Conservatively loud-reject any spread until the flatten
|
||||
// lands; b1c's (void|size) has none, so byte-id is untouched.
|
||||
if (pa.op == tkind.TK_ELLIPSIS) { return false; };
|
||||
if (pb.op == tkind.TK_ELLIPSIS) { return false; };
|
||||
if (!typeeqast(pa, pb)) { return false; };
|
||||
pa = pa.next;
|
||||
pb = pb.next;
|
||||
};
|
||||
return pb == nil;
|
||||
};
|
||||
// Conservative: anything else (struct/array) fails the cheap
|
||||
// check. Selfhost code doesn't currently rely on equality at
|
||||
// these shapes for the targeted checks.
|
||||
return false;
|
||||
};
|
||||
|
||||
|
||||
@@ -11174,9 +11174,40 @@ fn typeeqast(a: *node, b: *node) bool = {
|
||||
};
|
||||
return pb == nil;
|
||||
};
|
||||
// Conservative: anything else (struct/tagged/array) fails the
|
||||
// cheap check. Selfhost code doesn't currently rely on equality
|
||||
// at these shapes for the targeted checks.
|
||||
// #47 gap-B: tagged structural equality — mirror of cstage
|
||||
// type.c:288-300 (TY_TAGGED). A tuple member with a TAGGED element
|
||||
// (e.g. ((void|size),(void|size),size)) recurses here from the
|
||||
// N_TTUPLE arm; without it the per-element compare falls to the
|
||||
// catch-all and the whole case-against-tagged-scrutinee is rejected.
|
||||
// Variants are DIRECT .list nodes (casevariantin walks tagged.list
|
||||
// + typeeqast(v,..) directly), NOT N_TPARAM-wrapped like tuple elems.
|
||||
// Divergence: cstage's nullable-flag check (type.c:293) is a resolved-
|
||||
// Type property with no AST analogue; for case-match both sides share
|
||||
// a spelling so it's moot — no phantom AST nullable check.
|
||||
if (k == nkind.N_TTAGGED) {
|
||||
let pa: *node = aa.list;
|
||||
let pb: *node = bb.list;
|
||||
for (pa != nil) {
|
||||
if (pb == nil) { return false; };
|
||||
// #115: a `...inner` spread variant stays unflattened at
|
||||
// this AST layer (casevariantin flattens only at the OUTER
|
||||
// level; cstage flattens in resolve_type before type_eq ever
|
||||
// runs). A position-by-position compare cannot honour it —
|
||||
// the N_TNAME leg is pure streq, so `...ab` would silently
|
||||
// match a plain `ab`, accepting a case cstage rejects.
|
||||
// Conservatively loud-reject any spread until the flatten
|
||||
// lands; b1c's (void|size) has none, so byte-id is untouched.
|
||||
if (pa.op == tkind.TK_ELLIPSIS) { return false; };
|
||||
if (pb.op == tkind.TK_ELLIPSIS) { return false; };
|
||||
if (!typeeqast(pa, pb)) { return false; };
|
||||
pa = pa.next;
|
||||
pb = pb.next;
|
||||
};
|
||||
return pb == nil;
|
||||
};
|
||||
// Conservative: anything else (struct/array) fails the cheap
|
||||
// check. Selfhost code doesn't currently rely on equality at
|
||||
// these shapes for the targeted checks.
|
||||
return false;
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user