wwstage: match cross-module union variants by (module, leaf) pair (#13)
wwstage's checker rejected matching an imported union's variants cross-module: casevariantin/casecovers' typeeqast did a raw streq, so a union's bare variant "unsupported" failed to match the dotted case pattern "errors.unsupported" (cstage compares resolved-Type identity, qualifier-agnostic). Add a (module, leaf)-pair fallback after typeeqast: reduce both the case pattern and each variant to (module, leaf) and match on pair equality -- a dotted name keeps its own qualifier, a bare name takes the union's defining module (taggeddefmod, via the aliassym hop chain). This closes BOTH directions: the false-reject of valid cross-module match AND a false-accept of a foreign same-leaf qualifier (case othermod.foo vs errors.error now rejected, matching cstage). Handles the nested errors.error-in-io.error case (the dotted variant keeps mod=errors, not the union's mod=io). typeeqast stays the first check so currently-valid code is byte-id-unchanged; the pair-match fires only on the previously-rejected qualified-vs-bare mix. Wired into casevariantin, casecovers, and the is/as caller. Adds test/wcc/787 (cross-module positive, exhaustiveness, foreign-qualifier reject-guard, dotted-variant body). Unblocks #5's cross-module io.error/errors.error decomposition. rule-10 fix-up; #10-family (wwstage cross-module resolution).
This commit is contained in:
@@ -13389,13 +13389,94 @@ fn isassignable(c: *checker, dst: *node, src: *node, confident: *bool) bool = {
|
||||
// tagged-union type is handled by some case (or a default arm
|
||||
// exists). Multi-pattern `case A | B =>` covers all alts.
|
||||
|
||||
fn casecovers(c: *checker, cs: *node, want: *node) bool = {
|
||||
// qualleaf — rightmost dotted segment of a (possibly module-qualified)
|
||||
// type name; the whole name when unqualified.
|
||||
fn qualleaf(nm: str) str = {
|
||||
let dotidx: i32 = -1;
|
||||
let i: i32 = 0;
|
||||
for (i < nm.len) {
|
||||
if (nm[i] == 46u8) { dotidx = i; };
|
||||
i += 1;
|
||||
};
|
||||
if (dotidx < 0) { return nm; };
|
||||
let leaf: str;
|
||||
leaf.ptr = nm.ptr + ((dotidx + 1): u64);
|
||||
leaf.len = nm.len - dotidx - 1;
|
||||
return leaf;
|
||||
};
|
||||
|
||||
// qualmod — module qualifier of a type name (segment before the
|
||||
// rightmost '.'), or `defmod` when unqualified.
|
||||
fn qualmod(nm: str, defmod: str) str = {
|
||||
let dotidx: i32 = -1;
|
||||
let i: i32 = 0;
|
||||
for (i < nm.len) {
|
||||
if (nm[i] == 46u8) { dotidx = i; };
|
||||
i += 1;
|
||||
};
|
||||
if (dotidx < 0) { return defmod; };
|
||||
let head: str;
|
||||
head.ptr = nm.ptr;
|
||||
head.len = dotidx;
|
||||
return head;
|
||||
};
|
||||
|
||||
// casevariantpairmatch — a case pattern names variant `v` of the tagged
|
||||
// union iff their (module, leaf) PAIRS match. Each name reduces to
|
||||
// (qualmod, qualleaf): a DOTTED name keeps its own qualifier; a BARE
|
||||
// name is attributed `unionmod`, the union's defining module. So a
|
||||
// cross-module `case errors.unsupported` matches the bare `unsupported`
|
||||
// in errors.error's body, while a foreign `othermod.unsupported` is
|
||||
// REJECTED (qualifier differs) and Shape A's dotted `errors.error`
|
||||
// variant of io.error keeps matching `case errors.error` (defmod is
|
||||
// NOT forced onto a dotted variant — drew #13). Approximates harec's
|
||||
// resolved-Type variant identity (cmd/wcc/check.c:1651) at the AST
|
||||
// level via the existing nmod/aliassym machinery (cf. #51/#53); the
|
||||
// precise Type-identity form is #10 (tinfo SSoT). typeeqast handles the
|
||||
// exact-string cases first, so this fires only on the qualified-vs-bare
|
||||
// mix.
|
||||
fn casevariantpairmatch(v: *node, pat: *node, unionmod: str) bool = {
|
||||
let vv: *node = unwrapbang(v);
|
||||
let pp: *node = unwrapbang(pat);
|
||||
if (vv == nil) { return false; };
|
||||
if (pp == nil) { return false; };
|
||||
if (vv.kind != nkind.N_TNAME) { return false; };
|
||||
if (pp.kind != nkind.N_TNAME) { return false; };
|
||||
if (!streq(qualleaf(vv.str), qualleaf(pp.str))) { return false; };
|
||||
return streq(qualmod(vv.str, unionmod), qualmod(pp.str, unionmod));
|
||||
};
|
||||
|
||||
// taggeddefmod — defining module of the typedecl whose body IS the
|
||||
// tagged union (follows alias hops via aliassym, the #51/#53 machinery).
|
||||
// Bare variants in that body are defined here: io.error =
|
||||
// !(errors.error | underread | nomem) (module io) -> "io"; errors.error
|
||||
// -> "errors". Falls back to c.curmod when the chain can't resolve.
|
||||
fn taggeddefmod(c: *checker, st: *node) str = {
|
||||
let defmod: str = c.curmod;
|
||||
let cur: *node = unwrapbang(st);
|
||||
for (cur != nil) {
|
||||
if (cur.kind != nkind.N_TNAME) { return defmod; };
|
||||
let s: *sym = aliassym(c, cur);
|
||||
if (s == nil) { return defmod; };
|
||||
if (s.decl == nil) { return defmod; };
|
||||
if (s.decl.nmod.len > 0) { defmod = s.decl.nmod; };
|
||||
let body: *node = unwrapbang(s.decl.lhs);
|
||||
if (body == nil) { return defmod; };
|
||||
if (body.kind == nkind.N_TTAGGED) { return defmod; };
|
||||
cur = body;
|
||||
};
|
||||
return defmod;
|
||||
};
|
||||
|
||||
fn casecovers(c: *checker, cs: *node, want: *node, unionmod: str) bool = {
|
||||
if (cs.lhs != nil) {
|
||||
if (typeeqast(cs.lhs, want)) { return true; };
|
||||
if (casevariantpairmatch(want, cs.lhs, unionmod)) { return true; };
|
||||
};
|
||||
let alt: *node = cs.list;
|
||||
for (alt != nil) {
|
||||
if (typeeqast(alt, want)) { return true; };
|
||||
if (casevariantpairmatch(want, alt, unionmod)) { return true; };
|
||||
alt = alt.next;
|
||||
};
|
||||
return false;
|
||||
@@ -13417,10 +13498,11 @@ fn errmatchvariant(c: *checker, n: *node, vname: *node) void = {
|
||||
// casevariantin — true iff `pat` (a `case T` pattern, including
|
||||
// each alt of a multi-pattern) names a variant of the tagged
|
||||
// union `tagged`.
|
||||
fn casevariantin(tagged: *node, pat: *node) bool = {
|
||||
fn casevariantin(tagged: *node, pat: *node, unionmod: str) bool = {
|
||||
let v: *node = tagged.list;
|
||||
for (v != nil) {
|
||||
if (typeeqast(v, pat)) { return true; };
|
||||
if (casevariantpairmatch(v, pat, unionmod)) { return true; };
|
||||
v = v.next;
|
||||
};
|
||||
return false;
|
||||
@@ -13446,18 +13528,23 @@ fn checkmatchexhaust(c: *checker, n: *node) void = {
|
||||
let u: *node = resolvealias(c, unwrapbang(st));
|
||||
if (u == nil) { return; };
|
||||
if (u.kind != nkind.N_TTAGGED) { return; };
|
||||
// #13: the union's defining module, so a bare body variant can be
|
||||
// matched against a module-qualified cross-module case pattern (and
|
||||
// a foreign-qualifier pattern correctly rejected). See
|
||||
// casevariantpairmatch.
|
||||
let unionmod: str = taggeddefmod(c, st);
|
||||
// Validity: every `case T` pattern (and multi-pattern alts)
|
||||
// must name a variant of u. Catches typos and dead arms that
|
||||
// the dispatch would never reach.
|
||||
let cs0: *node = n.list;
|
||||
for (cs0 != nil) {
|
||||
if (cs0.lhs != nil) {
|
||||
if (!casevariantin(u, cs0.lhs)) {
|
||||
if (!casevariantin(u, cs0.lhs, unionmod)) {
|
||||
errbadcase(c, cs0.lhs);
|
||||
};
|
||||
let alt: *node = cs0.list;
|
||||
for (alt != nil) {
|
||||
if (!casevariantin(u, alt)) {
|
||||
if (!casevariantin(u, alt, unionmod)) {
|
||||
errbadcase(c, alt);
|
||||
};
|
||||
alt = alt.next;
|
||||
@@ -13477,7 +13564,7 @@ fn checkmatchexhaust(c: *checker, n: *node) void = {
|
||||
let covered: bool = false;
|
||||
let cs2: *node = n.list;
|
||||
for (cs2 != nil) {
|
||||
if (casecovers(c, cs2, v)) {
|
||||
if (casecovers(c, cs2, v, unionmod)) {
|
||||
covered = true;
|
||||
cs2 = nil;
|
||||
} else {
|
||||
@@ -13729,7 +13816,7 @@ fn checkisas(c: *checker, n: *node) void = {
|
||||
if (utinfo != nil) { if (wanttinfo != nil) {
|
||||
if (flatvariantidxt(utinfo, wanttinfo) >= 0) { return; };
|
||||
}; };
|
||||
if (casevariantin(u, want)) { return; };
|
||||
if (casevariantin(u, want, taggeddefmod(c, st))) { return; };
|
||||
os.write(2, "is/as: not a variant of operand".ptr, 31u64);
|
||||
if (want.kind == nkind.N_TNAME) {
|
||||
os.write(2, " (".ptr, 2u64);
|
||||
|
||||
@@ -3288,13 +3288,94 @@ fn isassignable(c: *checker, dst: *node, src: *node, confident: *bool) bool = {
|
||||
// tagged-union type is handled by some case (or a default arm
|
||||
// exists). Multi-pattern `case A | B =>` covers all alts.
|
||||
|
||||
fn casecovers(c: *checker, cs: *node, want: *node) bool = {
|
||||
// qualleaf — rightmost dotted segment of a (possibly module-qualified)
|
||||
// type name; the whole name when unqualified.
|
||||
fn qualleaf(nm: str) str = {
|
||||
let dotidx: i32 = -1;
|
||||
let i: i32 = 0;
|
||||
for (i < nm.len) {
|
||||
if (nm[i] == 46u8) { dotidx = i; };
|
||||
i += 1;
|
||||
};
|
||||
if (dotidx < 0) { return nm; };
|
||||
let leaf: str;
|
||||
leaf.ptr = nm.ptr + ((dotidx + 1): u64);
|
||||
leaf.len = nm.len - dotidx - 1;
|
||||
return leaf;
|
||||
};
|
||||
|
||||
// qualmod — module qualifier of a type name (segment before the
|
||||
// rightmost '.'), or `defmod` when unqualified.
|
||||
fn qualmod(nm: str, defmod: str) str = {
|
||||
let dotidx: i32 = -1;
|
||||
let i: i32 = 0;
|
||||
for (i < nm.len) {
|
||||
if (nm[i] == 46u8) { dotidx = i; };
|
||||
i += 1;
|
||||
};
|
||||
if (dotidx < 0) { return defmod; };
|
||||
let head: str;
|
||||
head.ptr = nm.ptr;
|
||||
head.len = dotidx;
|
||||
return head;
|
||||
};
|
||||
|
||||
// casevariantpairmatch — a case pattern names variant `v` of the tagged
|
||||
// union iff their (module, leaf) PAIRS match. Each name reduces to
|
||||
// (qualmod, qualleaf): a DOTTED name keeps its own qualifier; a BARE
|
||||
// name is attributed `unionmod`, the union's defining module. So a
|
||||
// cross-module `case errors.unsupported` matches the bare `unsupported`
|
||||
// in errors.error's body, while a foreign `othermod.unsupported` is
|
||||
// REJECTED (qualifier differs) and Shape A's dotted `errors.error`
|
||||
// variant of io.error keeps matching `case errors.error` (defmod is
|
||||
// NOT forced onto a dotted variant — drew #13). Approximates harec's
|
||||
// resolved-Type variant identity (cmd/wcc/check.c:1651) at the AST
|
||||
// level via the existing nmod/aliassym machinery (cf. #51/#53); the
|
||||
// precise Type-identity form is #10 (tinfo SSoT). typeeqast handles the
|
||||
// exact-string cases first, so this fires only on the qualified-vs-bare
|
||||
// mix.
|
||||
fn casevariantpairmatch(v: *node, pat: *node, unionmod: str) bool = {
|
||||
let vv: *node = unwrapbang(v);
|
||||
let pp: *node = unwrapbang(pat);
|
||||
if (vv == nil) { return false; };
|
||||
if (pp == nil) { return false; };
|
||||
if (vv.kind != nkind.N_TNAME) { return false; };
|
||||
if (pp.kind != nkind.N_TNAME) { return false; };
|
||||
if (!streq(qualleaf(vv.str), qualleaf(pp.str))) { return false; };
|
||||
return streq(qualmod(vv.str, unionmod), qualmod(pp.str, unionmod));
|
||||
};
|
||||
|
||||
// taggeddefmod — defining module of the typedecl whose body IS the
|
||||
// tagged union (follows alias hops via aliassym, the #51/#53 machinery).
|
||||
// Bare variants in that body are defined here: io.error =
|
||||
// !(errors.error | underread | nomem) (module io) -> "io"; errors.error
|
||||
// -> "errors". Falls back to c.curmod when the chain can't resolve.
|
||||
fn taggeddefmod(c: *checker, st: *node) str = {
|
||||
let defmod: str = c.curmod;
|
||||
let cur: *node = unwrapbang(st);
|
||||
for (cur != nil) {
|
||||
if (cur.kind != nkind.N_TNAME) { return defmod; };
|
||||
let s: *sym = aliassym(c, cur);
|
||||
if (s == nil) { return defmod; };
|
||||
if (s.decl == nil) { return defmod; };
|
||||
if (s.decl.nmod.len > 0) { defmod = s.decl.nmod; };
|
||||
let body: *node = unwrapbang(s.decl.lhs);
|
||||
if (body == nil) { return defmod; };
|
||||
if (body.kind == nkind.N_TTAGGED) { return defmod; };
|
||||
cur = body;
|
||||
};
|
||||
return defmod;
|
||||
};
|
||||
|
||||
fn casecovers(c: *checker, cs: *node, want: *node, unionmod: str) bool = {
|
||||
if (cs.lhs != nil) {
|
||||
if (typeeqast(cs.lhs, want)) { return true; };
|
||||
if (casevariantpairmatch(want, cs.lhs, unionmod)) { return true; };
|
||||
};
|
||||
let alt: *node = cs.list;
|
||||
for (alt != nil) {
|
||||
if (typeeqast(alt, want)) { return true; };
|
||||
if (casevariantpairmatch(want, alt, unionmod)) { return true; };
|
||||
alt = alt.next;
|
||||
};
|
||||
return false;
|
||||
@@ -3316,10 +3397,11 @@ fn errmatchvariant(c: *checker, n: *node, vname: *node) void = {
|
||||
// casevariantin — true iff `pat` (a `case T` pattern, including
|
||||
// each alt of a multi-pattern) names a variant of the tagged
|
||||
// union `tagged`.
|
||||
fn casevariantin(tagged: *node, pat: *node) bool = {
|
||||
fn casevariantin(tagged: *node, pat: *node, unionmod: str) bool = {
|
||||
let v: *node = tagged.list;
|
||||
for (v != nil) {
|
||||
if (typeeqast(v, pat)) { return true; };
|
||||
if (casevariantpairmatch(v, pat, unionmod)) { return true; };
|
||||
v = v.next;
|
||||
};
|
||||
return false;
|
||||
@@ -3345,18 +3427,23 @@ fn checkmatchexhaust(c: *checker, n: *node) void = {
|
||||
let u: *node = resolvealias(c, unwrapbang(st));
|
||||
if (u == nil) { return; };
|
||||
if (u.kind != nkind.N_TTAGGED) { return; };
|
||||
// #13: the union's defining module, so a bare body variant can be
|
||||
// matched against a module-qualified cross-module case pattern (and
|
||||
// a foreign-qualifier pattern correctly rejected). See
|
||||
// casevariantpairmatch.
|
||||
let unionmod: str = taggeddefmod(c, st);
|
||||
// Validity: every `case T` pattern (and multi-pattern alts)
|
||||
// must name a variant of u. Catches typos and dead arms that
|
||||
// the dispatch would never reach.
|
||||
let cs0: *node = n.list;
|
||||
for (cs0 != nil) {
|
||||
if (cs0.lhs != nil) {
|
||||
if (!casevariantin(u, cs0.lhs)) {
|
||||
if (!casevariantin(u, cs0.lhs, unionmod)) {
|
||||
errbadcase(c, cs0.lhs);
|
||||
};
|
||||
let alt: *node = cs0.list;
|
||||
for (alt != nil) {
|
||||
if (!casevariantin(u, alt)) {
|
||||
if (!casevariantin(u, alt, unionmod)) {
|
||||
errbadcase(c, alt);
|
||||
};
|
||||
alt = alt.next;
|
||||
@@ -3376,7 +3463,7 @@ fn checkmatchexhaust(c: *checker, n: *node) void = {
|
||||
let covered: bool = false;
|
||||
let cs2: *node = n.list;
|
||||
for (cs2 != nil) {
|
||||
if (casecovers(c, cs2, v)) {
|
||||
if (casecovers(c, cs2, v, unionmod)) {
|
||||
covered = true;
|
||||
cs2 = nil;
|
||||
} else {
|
||||
@@ -3628,7 +3715,7 @@ fn checkisas(c: *checker, n: *node) void = {
|
||||
if (utinfo != nil) { if (wanttinfo != nil) {
|
||||
if (flatvariantidxt(utinfo, wanttinfo) >= 0) { return; };
|
||||
}; };
|
||||
if (casevariantin(u, want)) { return; };
|
||||
if (casevariantin(u, want, taggeddefmod(c, st))) { return; };
|
||||
os.write(2, "is/as: not a variant of operand".ptr, 31u64);
|
||||
if (want.kind == nkind.N_TNAME) {
|
||||
os.write(2, " (".ptr, 2u64);
|
||||
|
||||
@@ -13389,13 +13389,94 @@ fn isassignable(c: *checker, dst: *node, src: *node, confident: *bool) bool = {
|
||||
// tagged-union type is handled by some case (or a default arm
|
||||
// exists). Multi-pattern `case A | B =>` covers all alts.
|
||||
|
||||
fn casecovers(c: *checker, cs: *node, want: *node) bool = {
|
||||
// qualleaf — rightmost dotted segment of a (possibly module-qualified)
|
||||
// type name; the whole name when unqualified.
|
||||
fn qualleaf(nm: str) str = {
|
||||
let dotidx: i32 = -1;
|
||||
let i: i32 = 0;
|
||||
for (i < nm.len) {
|
||||
if (nm[i] == 46u8) { dotidx = i; };
|
||||
i += 1;
|
||||
};
|
||||
if (dotidx < 0) { return nm; };
|
||||
let leaf: str;
|
||||
leaf.ptr = nm.ptr + ((dotidx + 1): u64);
|
||||
leaf.len = nm.len - dotidx - 1;
|
||||
return leaf;
|
||||
};
|
||||
|
||||
// qualmod — module qualifier of a type name (segment before the
|
||||
// rightmost '.'), or `defmod` when unqualified.
|
||||
fn qualmod(nm: str, defmod: str) str = {
|
||||
let dotidx: i32 = -1;
|
||||
let i: i32 = 0;
|
||||
for (i < nm.len) {
|
||||
if (nm[i] == 46u8) { dotidx = i; };
|
||||
i += 1;
|
||||
};
|
||||
if (dotidx < 0) { return defmod; };
|
||||
let head: str;
|
||||
head.ptr = nm.ptr;
|
||||
head.len = dotidx;
|
||||
return head;
|
||||
};
|
||||
|
||||
// casevariantpairmatch — a case pattern names variant `v` of the tagged
|
||||
// union iff their (module, leaf) PAIRS match. Each name reduces to
|
||||
// (qualmod, qualleaf): a DOTTED name keeps its own qualifier; a BARE
|
||||
// name is attributed `unionmod`, the union's defining module. So a
|
||||
// cross-module `case errors.unsupported` matches the bare `unsupported`
|
||||
// in errors.error's body, while a foreign `othermod.unsupported` is
|
||||
// REJECTED (qualifier differs) and Shape A's dotted `errors.error`
|
||||
// variant of io.error keeps matching `case errors.error` (defmod is
|
||||
// NOT forced onto a dotted variant — drew #13). Approximates harec's
|
||||
// resolved-Type variant identity (cmd/wcc/check.c:1651) at the AST
|
||||
// level via the existing nmod/aliassym machinery (cf. #51/#53); the
|
||||
// precise Type-identity form is #10 (tinfo SSoT). typeeqast handles the
|
||||
// exact-string cases first, so this fires only on the qualified-vs-bare
|
||||
// mix.
|
||||
fn casevariantpairmatch(v: *node, pat: *node, unionmod: str) bool = {
|
||||
let vv: *node = unwrapbang(v);
|
||||
let pp: *node = unwrapbang(pat);
|
||||
if (vv == nil) { return false; };
|
||||
if (pp == nil) { return false; };
|
||||
if (vv.kind != nkind.N_TNAME) { return false; };
|
||||
if (pp.kind != nkind.N_TNAME) { return false; };
|
||||
if (!streq(qualleaf(vv.str), qualleaf(pp.str))) { return false; };
|
||||
return streq(qualmod(vv.str, unionmod), qualmod(pp.str, unionmod));
|
||||
};
|
||||
|
||||
// taggeddefmod — defining module of the typedecl whose body IS the
|
||||
// tagged union (follows alias hops via aliassym, the #51/#53 machinery).
|
||||
// Bare variants in that body are defined here: io.error =
|
||||
// !(errors.error | underread | nomem) (module io) -> "io"; errors.error
|
||||
// -> "errors". Falls back to c.curmod when the chain can't resolve.
|
||||
fn taggeddefmod(c: *checker, st: *node) str = {
|
||||
let defmod: str = c.curmod;
|
||||
let cur: *node = unwrapbang(st);
|
||||
for (cur != nil) {
|
||||
if (cur.kind != nkind.N_TNAME) { return defmod; };
|
||||
let s: *sym = aliassym(c, cur);
|
||||
if (s == nil) { return defmod; };
|
||||
if (s.decl == nil) { return defmod; };
|
||||
if (s.decl.nmod.len > 0) { defmod = s.decl.nmod; };
|
||||
let body: *node = unwrapbang(s.decl.lhs);
|
||||
if (body == nil) { return defmod; };
|
||||
if (body.kind == nkind.N_TTAGGED) { return defmod; };
|
||||
cur = body;
|
||||
};
|
||||
return defmod;
|
||||
};
|
||||
|
||||
fn casecovers(c: *checker, cs: *node, want: *node, unionmod: str) bool = {
|
||||
if (cs.lhs != nil) {
|
||||
if (typeeqast(cs.lhs, want)) { return true; };
|
||||
if (casevariantpairmatch(want, cs.lhs, unionmod)) { return true; };
|
||||
};
|
||||
let alt: *node = cs.list;
|
||||
for (alt != nil) {
|
||||
if (typeeqast(alt, want)) { return true; };
|
||||
if (casevariantpairmatch(want, alt, unionmod)) { return true; };
|
||||
alt = alt.next;
|
||||
};
|
||||
return false;
|
||||
@@ -13417,10 +13498,11 @@ fn errmatchvariant(c: *checker, n: *node, vname: *node) void = {
|
||||
// casevariantin — true iff `pat` (a `case T` pattern, including
|
||||
// each alt of a multi-pattern) names a variant of the tagged
|
||||
// union `tagged`.
|
||||
fn casevariantin(tagged: *node, pat: *node) bool = {
|
||||
fn casevariantin(tagged: *node, pat: *node, unionmod: str) bool = {
|
||||
let v: *node = tagged.list;
|
||||
for (v != nil) {
|
||||
if (typeeqast(v, pat)) { return true; };
|
||||
if (casevariantpairmatch(v, pat, unionmod)) { return true; };
|
||||
v = v.next;
|
||||
};
|
||||
return false;
|
||||
@@ -13446,18 +13528,23 @@ fn checkmatchexhaust(c: *checker, n: *node) void = {
|
||||
let u: *node = resolvealias(c, unwrapbang(st));
|
||||
if (u == nil) { return; };
|
||||
if (u.kind != nkind.N_TTAGGED) { return; };
|
||||
// #13: the union's defining module, so a bare body variant can be
|
||||
// matched against a module-qualified cross-module case pattern (and
|
||||
// a foreign-qualifier pattern correctly rejected). See
|
||||
// casevariantpairmatch.
|
||||
let unionmod: str = taggeddefmod(c, st);
|
||||
// Validity: every `case T` pattern (and multi-pattern alts)
|
||||
// must name a variant of u. Catches typos and dead arms that
|
||||
// the dispatch would never reach.
|
||||
let cs0: *node = n.list;
|
||||
for (cs0 != nil) {
|
||||
if (cs0.lhs != nil) {
|
||||
if (!casevariantin(u, cs0.lhs)) {
|
||||
if (!casevariantin(u, cs0.lhs, unionmod)) {
|
||||
errbadcase(c, cs0.lhs);
|
||||
};
|
||||
let alt: *node = cs0.list;
|
||||
for (alt != nil) {
|
||||
if (!casevariantin(u, alt)) {
|
||||
if (!casevariantin(u, alt, unionmod)) {
|
||||
errbadcase(c, alt);
|
||||
};
|
||||
alt = alt.next;
|
||||
@@ -13477,7 +13564,7 @@ fn checkmatchexhaust(c: *checker, n: *node) void = {
|
||||
let covered: bool = false;
|
||||
let cs2: *node = n.list;
|
||||
for (cs2 != nil) {
|
||||
if (casecovers(c, cs2, v)) {
|
||||
if (casecovers(c, cs2, v, unionmod)) {
|
||||
covered = true;
|
||||
cs2 = nil;
|
||||
} else {
|
||||
@@ -13729,7 +13816,7 @@ fn checkisas(c: *checker, n: *node) void = {
|
||||
if (utinfo != nil) { if (wanttinfo != nil) {
|
||||
if (flatvariantidxt(utinfo, wanttinfo) >= 0) { return; };
|
||||
}; };
|
||||
if (casevariantin(u, want)) { return; };
|
||||
if (casevariantin(u, want, taggeddefmod(c, st))) { return; };
|
||||
os.write(2, "is/as: not a variant of operand".ptr, 31u64);
|
||||
if (want.kind == nkind.N_TNAME) {
|
||||
os.write(2, " (".ptr, 2u64);
|
||||
|
||||
Reference in New Issue
Block a user