Do not treat `match` value patterns as `isinstance` checks
Fixes #20358.
As discovered by @randolf-scholz in #20142, mypy treats value patterns in match statement in a completely wrong way.
From PEP 622:
Literal pattern uses equality with literal on the right hand side, so that in the above example number == 0 and then possibly number == 1, etc will be evaluated.
Existing tests for the feature are invalid: for example,
foo: object
match foo:
case 1:
reveal_type(foo)
must reveal object, and test testMatchValuePatternNarrows asserts the opposite. Here's a runtime example:
>>> class A:
... def __eq__(self,o): return True
...
>>> match A():
... case 1:
... print("eq")
...
eq
I have updated the existing tests accordingly.
The idea is that value patterns are essentially equivalent to if foo == SomeValue checks, not isinstance checks modelled by conditional_types_wit_intersection.
The original implementation was introduced in #10191.
According to mypy_primer, this change doesn't affect type check results on a corpus of open source code. ✅
I'm frankly not sure what part of the core team to ping here - reviewers of the original PR, @JukkaL? @randolf-scholz please also take a look if you have time, IIRC some recent PRs of yours were related to pattern matching?
Primer finds nothing, apparently match isn't that popular in wild...
Primer finds nothing, apparently match isn't that popular in wild...
Well, many popular projects still support 3.9, but match-case requires at least 3.10, so that's not surprising.
One thing that might be worth testing is if it interacts correctly with unions types and union patterns, e.g.
from typing import Literal
def test1(x: Literal[1,2,3]) -> None:
match x:
case 1:
reveal_type(x)
case other:
reveal_type(x)
def test2(x: Literal[1,2,3]) -> None:
match x:
case 1:
reveal_type(x)
case 2:
reveal_type(x)
case 3:
reveal_type(x)
case other:
assert_never(x)
def test3(x: Literal[1,2,3]) -> None:
match x:
case 1 | 3:
reveal_type(x)
case other:
reveal_type(x)
and possibly the same with enum arguments / enum patterns.
I don't want to add any enum tests here, they won't be representative due to #19594 - I'd prefer to add match equivalents to tests there once this PR is merged. Unions are more relevant, thanks!
According to mypy_primer, this change doesn't affect type check results on a corpus of open source code. ✅
According to mypy_primer, this change doesn't affect type check results on a corpus of open source code. ✅
According to mypy_primer, this change doesn't affect type check results on a corpus of open source code. ✅