Skip to content

Fix exhaustive match on tuples of union types#4939

Open
SeanTAllen wants to merge 1 commit intomainfrom
fix-tuple-union-subtyping
Open

Fix exhaustive match on tuples of union types#4939
SeanTAllen wants to merge 1 commit intomainfrom
fix-tuple-union-subtyping

Conversation

@SeanTAllen
Copy link
Member

The subtype checker didn't recognize that a tuple of unions is a subtype of the equivalent union of tuples. This caused the exhaustiveness checker to reject valid match \exhaustive\ on tuples of union types when concrete types were used instead of don't-care patterns.

The fix expands a tuple of unions into the equivalent union of tuples via cross-product distribution in is_x_sub_union, then checks if every expanded alternative is covered. This addresses the long-standing TODO at line 555 of subtype.c. A cap of 256 alternatives prevents pathological blowup.

Closes #4937

The subtype checker didn't recognize that a tuple of unions is a
subtype of the equivalent union of tuples. For example,
((A | None), (A | None)) was not recognized as a subtype of
(A, (A|None)) | ((A|None), A) | (None, None), even though every
possible value of the tuple is covered by at least one member of
the union.

This caused the exhaustiveness checker to reject valid exhaustive
matches on tuples of union types when concrete types (like None)
were used instead of don't-care patterns.

The fix expands a tuple of unions into the equivalent union of
tuples via cross-product distribution, then checks if every
expanded alternative is covered. A cap of 256 alternatives
prevents pathological blowup.

Closes #4937
@SeanTAllen SeanTAllen added the changelog - fixed Automatically add "Fixed" CHANGELOG entry on merge label Mar 7, 2026
@ponylang-main ponylang-main added the discuss during sync Should be discussed during an upcoming sync label Mar 7, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

changelog - fixed Automatically add "Fixed" CHANGELOG entry on merge discuss during sync Should be discussed during an upcoming sync

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Exhaustiveness checker accepts (_, _) but rejects equivalent concrete types in tuple match

2 participants