wcc: accept NAMED-variant nominal match at tagged→tagged subset (#205)
The tagged→tagged subset arm walked src's leaves against dst's flat variant list, so `let r: (size | eof | wrapper) = e` with e: wrapper REJECTED at cstage's checker — wrapper's leaves (unsupported, underread, nomem) aren't direct variants of dst. Wwstage's permissive tail accepted silently but cgen then miscompiled the tag (#199b layout- extension family, deferred). Mirror the concrete→tagged fix from #199 (α) at type.c:316: when src is a NAMED-tagged wrapper and dst has a direct NAMED-tagged variant equal to src, accept by nominal identity BEFORE the subset loop. Wwstage's isassignable mirrors the structural insertion before the existing `*confident = false; return true;` tail (deferred-tightening per #202). SSoT with `is`/`as` non-recursive variant lookup (#198 family). Cgen's tag-remap for the wrapper-as-whole case still maps src variants to dst tag 0 — the wrapped-slot layout for `dst.tag = variant_idx, dst.payload = src` is #199b future-work. Probe verifies checker-accept + runtime exit-clean only; does NOT inspect the resulting variant tag. Probe 774_tagged_widen_named_variant.c covers 5 rows: bug-repro, nested-wrapper, pure-leaf subset (regression), concrete-unrelated rejection (gate), branched callee. Two sibling cgen/checker bugs surfaced (wwstage cgwidentaggedstorebp ssz<slot_sz pad gap; wwstage isassignable !void-alias collapse) and documented inline at the probe-row comment, kept in #202 family.
This commit is contained in:
@@ -13115,6 +13115,24 @@ fn isassignable(c: *checker, dst: *node, src: *node, confident: *bool) bool = {
|
||||
// return through another fn with the same shape but possibly
|
||||
// a different surface spelling.
|
||||
if (du.kind == nkind.N_TTAGGED && su.kind == nkind.N_TTAGGED) {
|
||||
// #205: NAMED-variant nominal compare BEFORE permissive
|
||||
// fallthrough. Mirror of cstage type.c type_assignable
|
||||
// tagged→tagged arm (#199 α concrete→tagged sibling).
|
||||
// When src is a NAMED-tagged wrapper and dst has a direct
|
||||
// NAMED-tagged variant equal to src, accept by nominal
|
||||
// identity — wrapper's leaves are NOT direct variants of
|
||||
// dst, so a structural subset walk would reject. SSoT
|
||||
// with `is`/`as` variant lookup (#198 family).
|
||||
let v: *node = du.list;
|
||||
for (v != nil) {
|
||||
let vu: *node = resolvealias(c, unwrapbang(v));
|
||||
if (vu != nil) {
|
||||
if (vu.kind == nkind.N_TTAGGED) {
|
||||
if (typeeqast(v, src)) { return true; };
|
||||
};
|
||||
};
|
||||
v = v.next;
|
||||
};
|
||||
*confident = false;
|
||||
return true;
|
||||
};
|
||||
|
||||
@@ -3085,6 +3085,24 @@ fn isassignable(c: *checker, dst: *node, src: *node, confident: *bool) bool = {
|
||||
// return through another fn with the same shape but possibly
|
||||
// a different surface spelling.
|
||||
if (du.kind == nkind.N_TTAGGED && su.kind == nkind.N_TTAGGED) {
|
||||
// #205: NAMED-variant nominal compare BEFORE permissive
|
||||
// fallthrough. Mirror of cstage type.c type_assignable
|
||||
// tagged→tagged arm (#199 α concrete→tagged sibling).
|
||||
// When src is a NAMED-tagged wrapper and dst has a direct
|
||||
// NAMED-tagged variant equal to src, accept by nominal
|
||||
// identity — wrapper's leaves are NOT direct variants of
|
||||
// dst, so a structural subset walk would reject. SSoT
|
||||
// with `is`/`as` variant lookup (#198 family).
|
||||
let v: *node = du.list;
|
||||
for (v != nil) {
|
||||
let vu: *node = resolvealias(c, unwrapbang(v));
|
||||
if (vu != nil) {
|
||||
if (vu.kind == nkind.N_TTAGGED) {
|
||||
if (typeeqast(v, src)) { return true; };
|
||||
};
|
||||
};
|
||||
v = v.next;
|
||||
};
|
||||
*confident = false;
|
||||
return true;
|
||||
};
|
||||
|
||||
@@ -13115,6 +13115,24 @@ fn isassignable(c: *checker, dst: *node, src: *node, confident: *bool) bool = {
|
||||
// return through another fn with the same shape but possibly
|
||||
// a different surface spelling.
|
||||
if (du.kind == nkind.N_TTAGGED && su.kind == nkind.N_TTAGGED) {
|
||||
// #205: NAMED-variant nominal compare BEFORE permissive
|
||||
// fallthrough. Mirror of cstage type.c type_assignable
|
||||
// tagged→tagged arm (#199 α concrete→tagged sibling).
|
||||
// When src is a NAMED-tagged wrapper and dst has a direct
|
||||
// NAMED-tagged variant equal to src, accept by nominal
|
||||
// identity — wrapper's leaves are NOT direct variants of
|
||||
// dst, so a structural subset walk would reject. SSoT
|
||||
// with `is`/`as` variant lookup (#198 family).
|
||||
let v: *node = du.list;
|
||||
for (v != nil) {
|
||||
let vu: *node = resolvealias(c, unwrapbang(v));
|
||||
if (vu != nil) {
|
||||
if (vu.kind == nkind.N_TTAGGED) {
|
||||
if (typeeqast(v, src)) { return true; };
|
||||
};
|
||||
};
|
||||
v = v.next;
|
||||
};
|
||||
*confident = false;
|
||||
return true;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user