Description
When using match \exhaustive\ on a tuple of union types, the exhaustiveness checker accepts (_, _) as a final catch-all pattern but rejects (None, None) in the same position — even when None is the only remaining possibility for each tuple element.
Example that works
type A is String
actor Main
new create(env: Env) =>
let x: (A | None) = None
let y: (A | None) = None
match \exhaustive\ (x, y)
| (let a: A, _) => env.out.print("1")
| (_, let a: A) => env.out.print("2")
| (_, _) => env.out.print("3")
end
Example that fails
The only change is (None, None) instead of (_, _):
type A is String
actor Main
new create(env: Env) =>
let x: (A | None) = None
let y: (A | None) = None
match \exhaustive\ (x, y)
| (let a: A, _) => env.out.print("1")
| (_, let a: A) => env.out.print("2")
| (None, None) => env.out.print("3")
end
Error:
main.pony:9:5: match marked \exhaustive\ is not exhaustive
match \exhaustive\ (x, y)
^
Expected behavior
Both versions should be accepted. After the first two patterns cover all cases where at least one element is A, the only remaining combination is (None, None). The checker should recognize that (None, None) covers the same remaining space as (_, _) in this context.
Environment
ponyc 0.61.0 on Linux x86_64.
Description
When using
match \exhaustive\on a tuple of union types, the exhaustiveness checker accepts(_, _)as a final catch-all pattern but rejects(None, None)in the same position — even whenNoneis the only remaining possibility for each tuple element.Example that works
Example that fails
The only change is
(None, None)instead of(_, _):Expected behavior
Both versions should be accepted. After the first two patterns cover all cases where at least one element is
A, the only remaining combination is(None, None). The checker should recognize that(None, None)covers the same remaining space as(_, _)in this context.Environment
ponyc 0.61.0 on Linux x86_64.