Skip to content

Matching tuple against union merges field types #19599

@saulshanabrook

Description

@saulshanabrook

Bug Report

Matching a tuple literal against a type which is a tuple literal unioned with another value gives incorrect types for the matched values. They will each be the union of the tuple fields instead of being the correct position

To Reproduce

x: tuple[int, str] | None = (1, "hi")
match x:
    case (a, b):
        reveal_type(a)
        reveal_type(b)

Expected Behavior

main.py:4: note: Revealed type is "builtins.int"
main.py:5: note: Revealed type is "builtins.str"
Success: no issues found in 1 source file

Actual Behavior

main.py:4: note: Revealed type is "builtins.int | builtins.str"
main.py:5: note: Revealed type is "builtins.int | builtins.str"
Success: no issues found in 1 source file

Other Working Examples

If I remove the union, then it works properly:

x: tuple[int, str] = (1, "hi")
match x:
    case (a, b):
        reveal_type(a)
        reveal_type(b)
main.py:4: note: Revealed type is "builtins.int"
main.py:5: note: Revealed type is "builtins.str"
Success: no issues found in 1 source file

Or if I handle the None case first, so the union is narrowed:

x: tuple[int, str] | None = (1, "hi")
match x:
    case None: pass
    case (a, b):
        reveal_type(a)
        reveal_type(b)
main.py:5: note: Revealed type is "builtins.int"
main.py:6: note: Revealed type is "builtins.str"
Success: no issues found in 1 source file

Your Environment

MyPy Playground, tested against master and 1.17.0

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugmypy got something wrongtopic-match-statementPython 3.10's match statementtopic-type-narrowingConditional type narrowing / binder

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions