Open
Description
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