wcc: route is/as variant lookup through tinfo.params (#198)

checkisas walked the unflattened AST u.list via casevariantin (typeeqast
streq), so any variant introduced via a `...inner` spread was invisible
and rejected as "is/as: not a variant of operand". Repro:

    type rsh = (size | io.eof | ...io.error);
    let r: rsh = 42: size;
    if (r is io.underread) ...    -- pre-fix wwstage REJECTS

io.underread is in io.error.params, which tinfofornode splices into the
parent at L1827-1836, but the AST u.list still holds the single
`...io.error` entry that streq("io.underread", "io.error") rejects.

Route through flatvariantidxt — the same Phase-N helper #179 cgmatch
and #66 cgtagvariantidx already key off. Mirrors cstage cmd/wcc/check.c
:1662-1675 u->params + type_eq. Falls back to casevariantin AST walk
when tinfo isn't available (defensive — non-#198 path stays as-is).

project_tinfo_lossy_nominal: name-keying was the pre-Phase-N workaround
for tinfo lossy on nominal identity; typeeq inside flatvariantidxt now
handles NAMED ptr-id (#64), so the checker pair aligns with cgen on the
flattened-variant axis.

Closes the cgen-drain mini-cluster (#201 -> #199 -> #200 -> #198).

773_isas_spread_variant: 5 rows (spread_is_inline_variant,
direct_cross_mod_tagged, cross_mod_named_void, same_module_variant,
spread_as_inline_payload). Rows 2-4 byte-id; rows 1/5 skip byte-id due
to layout-asymmetry on `...wrapper` (cstage flattens at resolve_type,
wwstage computes maxsz off vt.size of the un-spliced alias) — sibling
not blocking the checker correctness fix.
This commit is contained in:
2026-05-29 04:51:44 +09:00
parent 6ce292b157
commit 3f4eeff7ff
5 changed files with 386 additions and 27 deletions

View File

@@ -13470,16 +13470,29 @@ fn checkisas(c: *checker, n: *node) void = {
};
let want: *node = n.rhs;
if (want == nil) { return; };
if (!casevariantin(u, want)) {
os.write(2, "is/as: not a variant of operand".ptr, 31u64);
if (want.kind == nkind.N_TNAME) {
os.write(2, " (".ptr, 2u64);
os.write(2, want.str.ptr, want.str.len: u64);
os.write(2, ")".ptr, 1u64);
};
os.write(2, "\n".ptr, 1u64);
c.errs += 1;
// #198: route through tinfo.params (the #61a-flattened chain built
// at L1789-1845 N_TTAGGED) — the prior AST u.list walk via
// casevariantin false-rejects every variant that arrives via a
// `...inner` spread. Mirrors cstage cmd/wcc/check.c:1662-1675
// u->params + type_eq, and matches cgen's own #179 cgmatch / #66
// Phase-N flatvariantidxt lookup (the SSoT cgtagvariantidx already
// keys off at cgenexpr.ww:155). project_tinfo_lossy_nominal: name-
// keying was the pre-Phase-N workaround for tinfo lossy on nominal
// identity; typeeq inside flatvariantidxt now handles NAMED ptr-id.
let utinfo: *tinfo = tinfofornode(c, u);
let wanttinfo: *tinfo = tinfofornode(c, want);
if (utinfo != nil) { if (wanttinfo != nil) {
if (flatvariantidxt(utinfo, wanttinfo) >= 0) { return; };
}; };
if (casevariantin(u, want)) { return; };
os.write(2, "is/as: not a variant of operand".ptr, 31u64);
if (want.kind == nkind.N_TNAME) {
os.write(2, " (".ptr, 2u64);
os.write(2, want.str.ptr, want.str.len: u64);
os.write(2, ")".ptr, 1u64);
};
os.write(2, "\n".ptr, 1u64);
c.errs += 1;
};
// ---- ? subset propagation --------------------------------------------

View File

@@ -3440,16 +3440,29 @@ fn checkisas(c: *checker, n: *node) void = {
};
let want: *node = n.rhs;
if (want == nil) { return; };
if (!casevariantin(u, want)) {
os.write(2, "is/as: not a variant of operand".ptr, 31u64);
if (want.kind == nkind.N_TNAME) {
os.write(2, " (".ptr, 2u64);
os.write(2, want.str.ptr, want.str.len: u64);
os.write(2, ")".ptr, 1u64);
};
os.write(2, "\n".ptr, 1u64);
c.errs += 1;
// #198: route through tinfo.params (the #61a-flattened chain built
// at L1789-1845 N_TTAGGED) — the prior AST u.list walk via
// casevariantin false-rejects every variant that arrives via a
// `...inner` spread. Mirrors cstage cmd/wcc/check.c:1662-1675
// u->params + type_eq, and matches cgen's own #179 cgmatch / #66
// Phase-N flatvariantidxt lookup (the SSoT cgtagvariantidx already
// keys off at cgenexpr.ww:155). project_tinfo_lossy_nominal: name-
// keying was the pre-Phase-N workaround for tinfo lossy on nominal
// identity; typeeq inside flatvariantidxt now handles NAMED ptr-id.
let utinfo: *tinfo = tinfofornode(c, u);
let wanttinfo: *tinfo = tinfofornode(c, want);
if (utinfo != nil) { if (wanttinfo != nil) {
if (flatvariantidxt(utinfo, wanttinfo) >= 0) { return; };
}; };
if (casevariantin(u, want)) { return; };
os.write(2, "is/as: not a variant of operand".ptr, 31u64);
if (want.kind == nkind.N_TNAME) {
os.write(2, " (".ptr, 2u64);
os.write(2, want.str.ptr, want.str.len: u64);
os.write(2, ")".ptr, 1u64);
};
os.write(2, "\n".ptr, 1u64);
c.errs += 1;
};
// ---- ? subset propagation --------------------------------------------

View File

@@ -13470,16 +13470,29 @@ fn checkisas(c: *checker, n: *node) void = {
};
let want: *node = n.rhs;
if (want == nil) { return; };
if (!casevariantin(u, want)) {
os.write(2, "is/as: not a variant of operand".ptr, 31u64);
if (want.kind == nkind.N_TNAME) {
os.write(2, " (".ptr, 2u64);
os.write(2, want.str.ptr, want.str.len: u64);
os.write(2, ")".ptr, 1u64);
};
os.write(2, "\n".ptr, 1u64);
c.errs += 1;
// #198: route through tinfo.params (the #61a-flattened chain built
// at L1789-1845 N_TTAGGED) — the prior AST u.list walk via
// casevariantin false-rejects every variant that arrives via a
// `...inner` spread. Mirrors cstage cmd/wcc/check.c:1662-1675
// u->params + type_eq, and matches cgen's own #179 cgmatch / #66
// Phase-N flatvariantidxt lookup (the SSoT cgtagvariantidx already
// keys off at cgenexpr.ww:155). project_tinfo_lossy_nominal: name-
// keying was the pre-Phase-N workaround for tinfo lossy on nominal
// identity; typeeq inside flatvariantidxt now handles NAMED ptr-id.
let utinfo: *tinfo = tinfofornode(c, u);
let wanttinfo: *tinfo = tinfofornode(c, want);
if (utinfo != nil) { if (wanttinfo != nil) {
if (flatvariantidxt(utinfo, wanttinfo) >= 0) { return; };
}; };
if (casevariantin(u, want)) { return; };
os.write(2, "is/as: not a variant of operand".ptr, 31u64);
if (want.kind == nkind.N_TNAME) {
os.write(2, " (".ptr, 2u64);
os.write(2, want.str.ptr, want.str.len: u64);
os.write(2, ")".ptr, 1u64);
};
os.write(2, "\n".ptr, 1u64);
c.errs += 1;
};
// ---- ? subset propagation --------------------------------------------