wcc: kind-agnostic typeeq dispatch in cgmatch non-nullable arm (#179)

cgmatch's non-nullable variant-tag synthesis gated flatvariantidx on
pat.kind == N_TNAME (with N_TSLICE else-branch for #19's untyped-elem
fallback). N_TPTR / N_TFN / N_TPTR(N_TFN) case-patterns fell through
both, leaving r=-1 → want=0 so every variant past 0 silently
collapsed to tag 0 — runtime-passes only when the value happens to
sit on variant 0 (zero-coincidence miscompile).

Cstage cg_tag_for_variant works on resolved Type and is kind-
agnostic; harec stores `_case->type = ctype` (ref/harec check.c:2527).
#66 Phase-N already flipped match dispatch to typeeq; #179 is the
last site still keyed on AST kind. Memory: project_tinfo_lossy_nominal
+ feedback "Hare = resolved-type-only match dispatch".

Route through flatvariantidxt(scrutt.type_, pat.type_) directly,
guarded by istaggedtype + typeisslice(pattype) for the slice axis.
No new helper — existing flatvariantidxt / flatslicevariantidx wire
up unchanged.

767 probe locks the fix across 5 rows: (1) nullable *fn branched
store (ken's verify gate — proves the nullable arm at line 1484
isn't perturbed); (2) *i32|*i64 storing &i64 — pre-fix wwstage
emitted CMPQ $0 for *i64 arm, post-fix CMPQ $1; (3) *fn(i32)|*fn(i64)
via intermediate local; (4) branched runtime variant choice defeats
const-fold; (5) aliased ptr variants (typeeq through TY_NAMED).
Per row: cs runtime, ww runtime, cs.s == ww.s byte-id.

Sibling filed inline: widening `&fn` INLINE into a fn-ptr-only
tagged union picks tag 0 in wwstage's cgwidentaggedstorebp
(out-of-scope; row 3 dodges via intermediate ident store).
This commit is contained in:
2026-05-28 20:55:42 +09:00
parent 595577f606
commit c07f96fc35
5 changed files with 392 additions and 30 deletions

View File

@@ -19069,16 +19069,22 @@ fn cgmatch(c: *cgen, n: *node) void = {
// rather than the resolved N_TTAGGED node.
if (istaggedtype(c, scrutt)) {
let r: i32 = -1;
if (pat.kind == nkind.N_TNAME) {
r = flatvariantidx(c, scrutt, pat);
} else { if (pat.kind == nkind.N_TSLICE) {
// `case let s: []T =>` — pat.str is empty
// because the variant is a composite, so
// route through the slice-shape helper.
// Without this every (scalar | []T) match
// arm collapses to tag 0 (task #19).
r = flatslicevariantidx(c, scrutt, pat.lhs);
}; };
let pattype: *tinfo = pat.type_: *tinfo;
if (pattype != nil) {
// #179: kind-agnostic dispatch on the resolved
// tinfo. Cstage cg_tag_for_variant works on
// Type, so N_TPTR / N_TFN / N_TPTR(N_TFN) case-
// patterns all reach typeeq; the prior pat.kind
// gate dropped them to r=-1 → tag 0 collapse.
// Slice arm still goes through flatslicevariantidx
// (task #19 untyped-elem fallback when typeeq
// can't match a (scalar | []T) shape).
if (typeisslice(pattype)) {
r = flatslicevariantidx(c, scrutt, pat.lhs);
} else {
r = flatvariantidxt(scrutt.type_: *tinfo, pattype);
};
};
if (r >= 0) { want = r; };
};
};

View File

@@ -1509,16 +1509,22 @@ fn cgmatch(c: *cgen, n: *node) void = {
// rather than the resolved N_TTAGGED node.
if (istaggedtype(c, scrutt)) {
let r: i32 = -1;
if (pat.kind == nkind.N_TNAME) {
r = flatvariantidx(c, scrutt, pat);
} else { if (pat.kind == nkind.N_TSLICE) {
// `case let s: []T =>` — pat.str is empty
// because the variant is a composite, so
// route through the slice-shape helper.
// Without this every (scalar | []T) match
// arm collapses to tag 0 (task #19).
r = flatslicevariantidx(c, scrutt, pat.lhs);
}; };
let pattype: *tinfo = pat.type_: *tinfo;
if (pattype != nil) {
// #179: kind-agnostic dispatch on the resolved
// tinfo. Cstage cg_tag_for_variant works on
// Type, so N_TPTR / N_TFN / N_TPTR(N_TFN) case-
// patterns all reach typeeq; the prior pat.kind
// gate dropped them to r=-1 → tag 0 collapse.
// Slice arm still goes through flatslicevariantidx
// (task #19 untyped-elem fallback when typeeq
// can't match a (scalar | []T) shape).
if (typeisslice(pattype)) {
r = flatslicevariantidx(c, scrutt, pat.lhs);
} else {
r = flatvariantidxt(scrutt.type_: *tinfo, pattype);
};
};
if (r >= 0) { want = r; };
};
};

View File

@@ -19069,16 +19069,22 @@ fn cgmatch(c: *cgen, n: *node) void = {
// rather than the resolved N_TTAGGED node.
if (istaggedtype(c, scrutt)) {
let r: i32 = -1;
if (pat.kind == nkind.N_TNAME) {
r = flatvariantidx(c, scrutt, pat);
} else { if (pat.kind == nkind.N_TSLICE) {
// `case let s: []T =>` — pat.str is empty
// because the variant is a composite, so
// route through the slice-shape helper.
// Without this every (scalar | []T) match
// arm collapses to tag 0 (task #19).
r = flatslicevariantidx(c, scrutt, pat.lhs);
}; };
let pattype: *tinfo = pat.type_: *tinfo;
if (pattype != nil) {
// #179: kind-agnostic dispatch on the resolved
// tinfo. Cstage cg_tag_for_variant works on
// Type, so N_TPTR / N_TFN / N_TPTR(N_TFN) case-
// patterns all reach typeeq; the prior pat.kind
// gate dropped them to r=-1 → tag 0 collapse.
// Slice arm still goes through flatslicevariantidx
// (task #19 untyped-elem fallback when typeeq
// can't match a (scalar | []T) shape).
if (typeisslice(pattype)) {
r = flatslicevariantidx(c, scrutt, pat.lhs);
} else {
r = flatvariantidxt(scrutt.type_: *tinfo, pattype);
};
};
if (r >= 0) { want = r; };
};
};