Skip to content

Type narrowing for tuple worse with match than with the equivalent instanceof check #19082

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
mscheifer opened this issue May 12, 2025 · 1 comment
Labels
bug mypy got something wrong topic-match-statement Python 3.10's match statement topic-type-narrowing Conditional type narrowing / binder

Comments

@mscheifer
Copy link

Bug Report

Type narrowing is worse in a match statement on a tuple than the equivalent isinstance check.

With isinstance, mypy is able to determine that the type of a must be the tuple side of the union even though the check is only against Sequence, and then correctly narrows the type of the second element. With match, mypy is unable to do so and gives a union of the two element types in the tuple.

To Reproduce

repro.py

from collections.abc import Sequence

Type = tuple[float, int] | None


def foo(a: int) -> None:
    pass


def bar_match(a: Type) -> None:
    match a:
        case _, int_a:
            foo(int_a)


def bar_isinstance(a: Type) -> None:
    if isinstance(a, Sequence):
        _, int_a = a
        foo(int_a)

Expected Behavior

No errors

Actual Behavior

$ mypy repro.py 
repro.py:13: error: Argument 1 to "foo" has incompatible type "float | int"; expected "int"  [arg-type]
Found 1 error in 1 file (checked 1 source file)

Note that there is only one error, for the bar_match function, and no error for the bar_isinstance function.

Your Environment

I found this with 1.15 and reproduced it on the current master branch.

  • Mypy version used: 1.15 or 1.16.0+dev.ca609acabdc94ee973a53d62b8dcb7e55c789aec (compiled: no)
  • Mypy command-line flags: None
  • Mypy configuration options from mypy.ini (and other config files): None
  • Python version used: Python 3.12.3

Possibly related issues:
#19081

@mscheifer mscheifer added the bug mypy got something wrong label May 12, 2025
@sterliakov sterliakov added topic-match-statement Python 3.10's match statement topic-type-narrowing Conditional type narrowing / binder labels May 12, 2025
@phoebecd
Copy link

Hi! When you use isinstance(), it clearly narrows the type of int_a to int, and mypy recognizes this—so it doesn't return a warning. In contrast, match/case is more general, and type checkers like mypy are more conservative with pattern matching. As a result, mypy infers that int_a could be either a float or an int, and returns a type error.

Also, when I first ran your code, I didn't get a warning. I had to use mypy --strict repro.py to make the warning appear. Afterwards, I disabled strict mode by just running mypy repro.py, so those optional error checks were not enabled, and I didn’t receive the error again.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug mypy got something wrong topic-match-statement Python 3.10's match statement topic-type-narrowing Conditional type narrowing / binder
Projects
None yet
Development

No branches or pull requests

3 participants