blob: c07a90b49e63a94c9264bd423133a4f4625f50d1 [file] [log] [blame] [edit]
-- Capture Pattern --
[case testMatchCapturePatternType]
class A: ...
m: A
match m:
case a:
reveal_type(a) # N: Revealed type is "__main__.A"
-- Literal Pattern --
[case testMatchLiteralPatternNarrows]
m: object
match m:
case 1:
reveal_type(m) # N: Revealed type is "Literal[1]"
[case testMatchLiteralPatternAlreadyNarrower-skip]
m: bool
match m:
case 1:
reveal_type(m) # This should probably be unreachable, but isn't detected as such.
[builtins fixtures/primitives.pyi]
[case testMatchLiteralPatternUnreachable]
# primitives are needed because otherwise mypy doesn't see that int and str are incompatible
m: int
match m:
case "str":
reveal_type(m)
[builtins fixtures/primitives.pyi]
-- Value Pattern --
[case testMatchValuePatternNarrows]
import b
m: object
match m:
case b.b:
reveal_type(m) # N: Revealed type is "builtins.int"
[file b.py]
b: int
[case testMatchValuePatternAlreadyNarrower]
import b
m: bool
match m:
case b.b:
reveal_type(m) # N: Revealed type is "builtins.bool"
[file b.py]
b: int
[case testMatchValuePatternIntersect]
import b
class A: ...
m: A
match m:
case b.b:
reveal_type(m) # N: Revealed type is "__main__.<subclass of "A" and "B">1"
[file b.py]
class B: ...
b: B
[case testMatchValuePatternUnreachable]
# primitives are needed because otherwise mypy doesn't see that int and str are incompatible
import b
m: int
match m:
case b.b:
reveal_type(m)
[file b.py]
b: str
[builtins fixtures/primitives.pyi]
-- Sequence Pattern --
[case testMatchSequencePatternCaptures]
from typing import List
m: List[int]
match m:
case [a]:
reveal_type(a) # N: Revealed type is "builtins.int"
[builtins fixtures/list.pyi]
[case testMatchSequencePatternCapturesStarred]
from typing import Sequence
m: Sequence[int]
match m:
case [a, *b]:
reveal_type(a) # N: Revealed type is "builtins.int"
reveal_type(b) # N: Revealed type is "builtins.list[builtins.int]"
[builtins fixtures/list.pyi]
[case testMatchSequencePatternNarrowsInner]
from typing import Sequence
m: Sequence[object]
match m:
case [1, True]:
reveal_type(m) # N: Revealed type is "typing.Sequence[builtins.int]"
[case testMatchSequencePatternNarrowsOuter]
from typing import Sequence
m: object
match m:
case [1, True]:
reveal_type(m) # N: Revealed type is "typing.Sequence[builtins.int]"
[case testMatchSequencePatternAlreadyNarrowerInner]
from typing import Sequence
m: Sequence[bool]
match m:
case [1, True]:
reveal_type(m) # N: Revealed type is "typing.Sequence[builtins.bool]"
[case testMatchSequencePatternAlreadyNarrowerOuter]
from typing import Sequence
m: Sequence[object]
match m:
case [1, True]:
reveal_type(m) # N: Revealed type is "typing.Sequence[builtins.int]"
[case testMatchSequencePatternAlreadyNarrowerBoth]
from typing import Sequence
m: Sequence[bool]
match m:
case [1, True]:
reveal_type(m) # N: Revealed type is "typing.Sequence[builtins.bool]"
[case testMatchNestedSequencePatternNarrowsInner]
from typing import Sequence
m: Sequence[Sequence[object]]
match m:
case [[1], [True]]:
reveal_type(m) # N: Revealed type is "typing.Sequence[typing.Sequence[builtins.int]]"
[case testMatchNestedSequencePatternNarrowsOuter]
from typing import Sequence
m: object
match m:
case [[1], [True]]:
reveal_type(m) # N: Revealed type is "typing.Sequence[typing.Sequence[builtins.int]]"
[case testMatchSequencePatternDoesntNarrowInvariant]
from typing import List
m: List[object]
match m:
case [1]:
reveal_type(m) # N: Revealed type is "builtins.list[builtins.object]"
[builtins fixtures/list.pyi]
[case testMatchSequencePatternMatches]
import array, collections
from typing import Sequence, Iterable
m1: object
m2: Sequence[int]
m3: array.array[int]
m4: collections.deque[int]
m5: list[int]
m6: memoryview
m7: range
m8: tuple[int]
m9: str
m10: bytes
m11: bytearray
match m1:
case [a]:
reveal_type(a) # N: Revealed type is "builtins.object"
match m2:
case [b]:
reveal_type(b) # N: Revealed type is "builtins.int"
match m3:
case [c]:
reveal_type(c) # N: Revealed type is "builtins.int"
match m4:
case [d]:
reveal_type(d) # N: Revealed type is "builtins.int"
match m5:
case [e]:
reveal_type(e) # N: Revealed type is "builtins.int"
match m6:
case [f]:
reveal_type(f) # N: Revealed type is "builtins.int"
match m7:
case [g]:
reveal_type(g) # N: Revealed type is "builtins.int"
match m8:
case [h]:
reveal_type(h) # N: Revealed type is "builtins.int"
match m9:
case [i]:
reveal_type(i)
match m10:
case [j]:
reveal_type(j)
match m11:
case [k]:
reveal_type(k)
[builtins fixtures/primitives.pyi]
[typing fixtures/typing-full.pyi]
[case testMatchSequencePatternCapturesTuple]
from typing import Tuple
m: Tuple[int, str, bool]
match m:
case [a, b, c]:
reveal_type(a) # N: Revealed type is "builtins.int"
reveal_type(b) # N: Revealed type is "builtins.str"
reveal_type(c) # N: Revealed type is "builtins.bool"
reveal_type(m) # N: Revealed type is "Tuple[builtins.int, builtins.str, builtins.bool]"
[builtins fixtures/list.pyi]
[case testMatchSequencePatternTupleTooLong]
from typing import Tuple
m: Tuple[int, str]
match m:
case [a, b, c]:
reveal_type(a)
reveal_type(b)
reveal_type(c)
[builtins fixtures/list.pyi]
[case testMatchSequencePatternTupleTooShort]
from typing import Tuple
m: Tuple[int, str, bool]
match m:
case [a, b]:
reveal_type(a)
reveal_type(b)
[builtins fixtures/list.pyi]
[case testMatchSequencePatternTupleNarrows]
from typing import Tuple
m: Tuple[object, object]
match m:
case [1, "str"]:
reveal_type(m) # N: Revealed type is "Tuple[Literal[1], Literal['str']]"
[builtins fixtures/list.pyi]
[case testMatchSequencePatternTupleStarred]
from typing import Tuple
m: Tuple[int, str, bool]
match m:
case [a, *b, c]:
reveal_type(a) # N: Revealed type is "builtins.int"
reveal_type(b) # N: Revealed type is "builtins.list[builtins.str]"
reveal_type(c) # N: Revealed type is "builtins.bool"
reveal_type(m) # N: Revealed type is "Tuple[builtins.int, builtins.str, builtins.bool]"
[builtins fixtures/list.pyi]
[case testMatchSequencePatternTupleStarredUnion]
from typing import Tuple
m: Tuple[int, str, float, bool]
match m:
case [a, *b, c]:
reveal_type(a) # N: Revealed type is "builtins.int"
reveal_type(b) # N: Revealed type is "builtins.list[Union[builtins.str, builtins.float]]"
reveal_type(c) # N: Revealed type is "builtins.bool"
reveal_type(m) # N: Revealed type is "Tuple[builtins.int, builtins.str, builtins.float, builtins.bool]"
[builtins fixtures/list.pyi]
[case testMatchSequencePatternTupleStarredTooShort]
from typing import Tuple
m: Tuple[int]
reveal_type(m) # N: Revealed type is "Tuple[builtins.int]"
match m:
case [a, *b, c]:
reveal_type(a)
reveal_type(b)
reveal_type(c)
[builtins fixtures/list.pyi]
[case testMatchNonMatchingSequencePattern]
from typing import List
x: List[int]
match x:
case [str()]:
pass
[case testMatchSequencePatternWithInvalidClassPattern]
class Example:
__match_args__ = ("value",)
def __init__(self, value: str) -> None:
self.value = value
SubClass: type[Example]
match [SubClass("a"), SubClass("b")]:
case [SubClass(value), *rest]: # E: Expected type in class pattern; found "Type[__main__.Example]"
reveal_type(value) # E: Cannot determine type of "value" \
# N: Revealed type is "Any"
reveal_type(rest) # N: Revealed type is "builtins.list[__main__.Example]"
[builtins fixtures/tuple.pyi]
[case testMatchSequenceUnion-skip]
from typing import List, Union
m: Union[List[List[str]], str]
match m:
case [list(['str'])]:
reveal_type(m) # N: Revealed type is "builtins.list[builtins.list[builtins.str]]"
[builtins fixtures/list.pyi]
-- Mapping Pattern --
[case testMatchMappingPatternCaptures]
from typing import Dict
import b
m: Dict[str, int]
match m:
case {"key": v}:
reveal_type(v) # N: Revealed type is "builtins.int"
case {b.b: v2}:
reveal_type(v2) # N: Revealed type is "builtins.int"
[file b.py]
b: str
[builtins fixtures/dict.pyi]
[case testMatchMappingPatternCapturesWrongKeyType]
# This is not actually unreachable, as a subclass of dict could accept keys with different types
from typing import Dict
import b
m: Dict[str, int]
match m:
case {1: v}:
reveal_type(v) # N: Revealed type is "builtins.int"
case {b.b: v2}:
reveal_type(v2) # N: Revealed type is "builtins.int"
[file b.py]
b: int
[builtins fixtures/dict.pyi]
[case testMatchMappingPatternCapturesTypedDict]
from typing import TypedDict
class A(TypedDict):
a: str
b: int
m: A
match m:
case {"a": v}:
reveal_type(v) # N: Revealed type is "builtins.str"
case {"b": v2}:
reveal_type(v2) # N: Revealed type is "builtins.int"
case {"a": v3, "b": v4}:
reveal_type(v3) # N: Revealed type is "builtins.str"
reveal_type(v4) # N: Revealed type is "builtins.int"
case {"o": v5}:
reveal_type(v5) # N: Revealed type is "builtins.object"
[typing fixtures/typing-typeddict.pyi]
[case testMatchMappingPatternCapturesTypedDictWithLiteral]
from typing import TypedDict
import b
class A(TypedDict):
a: str
b: int
m: A
match m:
case {b.a: v}:
reveal_type(v) # N: Revealed type is "builtins.str"
case {b.b: v2}:
reveal_type(v2) # N: Revealed type is "builtins.int"
case {b.a: v3, b.b: v4}:
reveal_type(v3) # N: Revealed type is "builtins.str"
reveal_type(v4) # N: Revealed type is "builtins.int"
case {b.o: v5}:
reveal_type(v5) # N: Revealed type is "builtins.object"
[file b.py]
from typing import Final, Literal
a: Final = "a"
b: Literal["b"] = "b"
o: Final[str] = "o"
[typing fixtures/typing-typeddict.pyi]
[case testMatchMappingPatternCapturesTypedDictWithNonLiteral]
from typing import TypedDict
import b
class A(TypedDict):
a: str
b: int
m: A
match m:
case {b.a: v}:
reveal_type(v) # N: Revealed type is "builtins.object"
[file b.py]
from typing import Final, Literal
a: str
[typing fixtures/typing-typeddict.pyi]
[case testMatchMappingPatternCapturesTypedDictUnreachable]
# TypedDict keys are always str, so this is actually unreachable
from typing import TypedDict
import b
class A(TypedDict):
a: str
b: int
m: A
match m:
case {1: v}:
reveal_type(v)
case {b.b: v2}:
reveal_type(v2)
[file b.py]
b: int
[typing fixtures/typing-typeddict.pyi]
[case testMatchMappingPatternCaptureRest]
m: object
match m:
case {'k': 1, **r}:
reveal_type(r) # N: Revealed type is "builtins.dict[builtins.object, builtins.object]"
[builtins fixtures/dict.pyi]
[case testMatchMappingPatternCaptureRestFromMapping]
from typing import Mapping
m: Mapping[str, int]
match m:
case {'k': 1, **r}:
reveal_type(r) # N: Revealed type is "builtins.dict[builtins.str, builtins.int]"
[builtins fixtures/dict.pyi]
-- Mapping patterns currently do not narrow --
-- Class Pattern --
[case testMatchClassPatternCapturePositional]
from typing import Final
class A:
__match_args__: Final = ("a", "b")
a: str
b: int
m: A
match m:
case A(i, j):
reveal_type(i) # N: Revealed type is "builtins.str"
reveal_type(j) # N: Revealed type is "builtins.int"
[builtins fixtures/tuple.pyi]
[case testMatchClassPatternMemberClassCapturePositional]
import b
m: b.A
match m:
case b.A(i, j):
reveal_type(i) # N: Revealed type is "builtins.str"
reveal_type(j) # N: Revealed type is "builtins.int"
[file b.py]
from typing import Final
class A:
__match_args__: Final = ("a", "b")
a: str
b: int
[builtins fixtures/tuple.pyi]
[case testMatchClassPatternCaptureKeyword]
class A:
a: str
b: int
m: A
match m:
case A(a=i, b=j):
reveal_type(i) # N: Revealed type is "builtins.str"
reveal_type(j) # N: Revealed type is "builtins.int"
[case testMatchClassPatternCaptureSelf]
m: object
match m:
case bool(a):
reveal_type(a) # N: Revealed type is "builtins.bool"
case bytearray(b):
reveal_type(b) # N: Revealed type is "builtins.bytearray"
case bytes(c):
reveal_type(c) # N: Revealed type is "builtins.bytes"
case dict(d):
reveal_type(d) # N: Revealed type is "builtins.dict[Any, Any]"
case float(e):
reveal_type(e) # N: Revealed type is "builtins.float"
case frozenset(f):
reveal_type(f) # N: Revealed type is "builtins.frozenset[Any]"
case int(g):
reveal_type(g) # N: Revealed type is "builtins.int"
case list(h):
reveal_type(h) # N: Revealed type is "builtins.list[Any]"
case set(i):
reveal_type(i) # N: Revealed type is "builtins.set[Any]"
case str(j):
reveal_type(j) # N: Revealed type is "builtins.str"
case tuple(k):
reveal_type(k) # N: Revealed type is "builtins.tuple[Any, ...]"
[builtins fixtures/primitives.pyi]
[case testMatchClassPatternNarrowSelfCapture]
m: object
match m:
case bool():
reveal_type(m) # N: Revealed type is "builtins.bool"
case bytearray():
reveal_type(m) # N: Revealed type is "builtins.bytearray"
case bytes():
reveal_type(m) # N: Revealed type is "builtins.bytes"
case dict():
reveal_type(m) # N: Revealed type is "builtins.dict[Any, Any]"
case float():
reveal_type(m) # N: Revealed type is "builtins.float"
case frozenset():
reveal_type(m) # N: Revealed type is "builtins.frozenset[Any]"
case int():
reveal_type(m) # N: Revealed type is "builtins.int"
case list():
reveal_type(m) # N: Revealed type is "builtins.list[Any]"
case set():
reveal_type(m) # N: Revealed type is "builtins.set[Any]"
case str():
reveal_type(m) # N: Revealed type is "builtins.str"
case tuple():
reveal_type(m) # N: Revealed type is "builtins.tuple[Any, ...]"
[builtins fixtures/primitives.pyi]
[case testMatchInvalidClassPattern]
m: object
match m:
case xyz(y): # E: Name "xyz" is not defined
reveal_type(m) # N: Revealed type is "Any"
reveal_type(y) # E: Cannot determine type of "y" \
# N: Revealed type is "Any"
match m:
case xyz(z=x): # E: Name "xyz" is not defined
reveal_type(x) # E: Cannot determine type of "x" \
# N: Revealed type is "Any"
[case testMatchClassPatternCaptureDataclass]
from dataclasses import dataclass
@dataclass
class A:
a: str
b: int
m: A
match m:
case A(i, j):
reveal_type(i) # N: Revealed type is "builtins.str"
reveal_type(j) # N: Revealed type is "builtins.int"
[builtins fixtures/dataclasses.pyi]
[case testMatchClassPatternCaptureDataclassNoMatchArgs]
from dataclasses import dataclass
@dataclass(match_args=False)
class A:
a: str
b: int
m: A
match m:
case A(i, j): # E: Class "__main__.A" doesn't define "__match_args__"
pass
[builtins fixtures/dataclasses.pyi]
[case testMatchClassPatternCaptureDataclassPartialMatchArgs]
from dataclasses import dataclass, field
@dataclass
class A:
a: str
b: int = field(init=False)
m: A
match m:
case A(i, j): # E: Too many positional patterns for class pattern
pass
case A(k):
reveal_type(k) # N: Revealed type is "builtins.str"
[builtins fixtures/dataclasses.pyi]
[case testMatchClassPatternCaptureNamedTupleInline]
from collections import namedtuple
A = namedtuple("A", ["a", "b"])
m: A
match m:
case A(i, j):
reveal_type(i) # N: Revealed type is "Any"
reveal_type(j) # N: Revealed type is "Any"
[builtins fixtures/list.pyi]
[case testMatchClassPatternCaptureNamedTupleInlineTyped]
from typing import NamedTuple
A = NamedTuple("A", [("a", str), ("b", int)])
m: A
match m:
case A(i, j):
reveal_type(i) # N: Revealed type is "builtins.str"
reveal_type(j) # N: Revealed type is "builtins.int"
[builtins fixtures/list.pyi]
[case testMatchClassPatternCaptureNamedTupleClass]
from typing import NamedTuple
class A(NamedTuple):
a: str
b: int
m: A
match m:
case A(i, j):
reveal_type(i) # N: Revealed type is "builtins.str"
reveal_type(j) # N: Revealed type is "builtins.int"
[builtins fixtures/tuple.pyi]
[case testMatchClassPatternCaptureGeneric]
from typing import Generic, TypeVar
T = TypeVar('T')
class A(Generic[T]):
a: T
m: object
match m:
case A(a=i):
reveal_type(m) # N: Revealed type is "__main__.A[Any]"
reveal_type(i) # N: Revealed type is "Any"
[case testMatchClassPatternCaptureGenericAlreadyKnown]
from typing import Generic, TypeVar
T = TypeVar('T')
class A(Generic[T]):
a: T
m: A[int]
match m:
case A(a=i):
reveal_type(m) # N: Revealed type is "__main__.A[builtins.int]"
reveal_type(i) # N: Revealed type is "builtins.int"
[case testMatchClassPatternCaptureFilledGenericTypeAlias]
from typing import Generic, TypeVar
T = TypeVar('T')
class A(Generic[T]):
a: T
B = A[int]
m: object
match m:
case B(a=i): # E: Class pattern class must not be a type alias with type parameters
reveal_type(i)
[case testMatchClassPatternCaptureGenericTypeAlias]
from typing import Generic, TypeVar
T = TypeVar('T')
class A(Generic[T]):
a: T
B = A
m: object
match m:
case B(a=i):
pass
[case testMatchClassPatternNarrows]
from typing import Final
class A:
__match_args__: Final = ("a", "b")
a: str
b: int
m: object
match m:
case A():
reveal_type(m) # N: Revealed type is "__main__.A"
case A(i, j):
reveal_type(m) # N: Revealed type is "__main__.A"
[builtins fixtures/tuple.pyi]
[case testMatchClassPatternNarrowsUnion]
from typing import Final, Union
class A:
__match_args__: Final = ("a", "b")
a: str
b: int
class B:
__match_args__: Final = ("a", "b")
a: int
b: str
m: Union[A, B]
match m:
case A():
reveal_type(m) # N: Revealed type is "__main__.A"
match m:
case A(i, j):
reveal_type(m) # N: Revealed type is "__main__.A"
reveal_type(i) # N: Revealed type is "builtins.str"
reveal_type(j) # N: Revealed type is "builtins.int"
match m:
case B():
reveal_type(m) # N: Revealed type is "__main__.B"
match m:
case B(k, l):
reveal_type(m) # N: Revealed type is "__main__.B"
reveal_type(k) # N: Revealed type is "builtins.int"
reveal_type(l) # N: Revealed type is "builtins.str"
[builtins fixtures/tuple.pyi]
[case testMatchClassPatternAlreadyNarrower]
from typing import Final
class A:
__match_args__: Final = ("a", "b")
a: str
b: int
class B(A): ...
m: B
match m:
case A():
reveal_type(m) # N: Revealed type is "__main__.B"
match m:
case A(i, j):
reveal_type(m) # N: Revealed type is "__main__.B"
[builtins fixtures/tuple.pyi]
[case testMatchClassPatternIntersection]
from typing import Final
class A:
__match_args__: Final = ("a", "b")
a: str
b: int
class B: ...
m: B
match m:
case A():
reveal_type(m) # N: Revealed type is "__main__.<subclass of "B" and "A">2"
case A(i, j):
reveal_type(m) # N: Revealed type is "__main__.<subclass of "B" and "A">3"
[builtins fixtures/tuple.pyi]
[case testMatchClassPatternNonexistentKeyword]
class A: ...
m: object
match m:
case A(a=j): # E: Class "__main__.A" has no attribute "a"
reveal_type(m) # N: Revealed type is "__main__.A"
reveal_type(j) # N: Revealed type is "Any"
[case testMatchClassPatternDuplicateKeyword]
class A:
a: str
m: object
match m:
case A(a=i, a=j): # E: Duplicate keyword pattern "a"
pass
[case testMatchClassPatternDuplicateImplicitKeyword]
from typing import Final
class A:
__match_args__: Final = ("a",)
a: str
m: object
match m:
case A(i, a=j): # E: Keyword "a" already matches a positional pattern
pass
[builtins fixtures/tuple.pyi]
[case testMatchClassPatternTooManyPositionals]
from typing import Final
class A:
__match_args__: Final = ("a", "b")
a: str
b: int
m: object
match m:
case A(i, j, k): # E: Too many positional patterns for class pattern
pass
[builtins fixtures/tuple.pyi]
[case testMatchClassPatternIsNotType]
a = 1
m: object
match m:
case a(i, j): # E: Expected type in class pattern; found "builtins.int"
reveal_type(i)
reveal_type(j)
[case testMatchClassPatternNestedGenerics]
# From cpython test_patma.py
x = [[{0: 0}]]
match x:
case list([({-0-0j: int(real=0+0j, imag=0-0j) | (1) as z},)]):
y = 0
reveal_type(x) # N: Revealed type is "builtins.list[builtins.list[builtins.dict[builtins.int, builtins.int]]]"
reveal_type(y) # N: Revealed type is "builtins.int"
reveal_type(z) # N: Revealed type is "builtins.int"
[builtins fixtures/dict.pyi]
[case testMatchNonFinalMatchArgs]
class A:
__match_args__ = ("a", "b")
a: str
b: int
m: object
match m:
case A(i, j):
reveal_type(i) # N: Revealed type is "builtins.str"
reveal_type(j) # N: Revealed type is "builtins.int"
[builtins fixtures/tuple.pyi]
[case testMatchAnyTupleMatchArgs]
from typing import Tuple, Any
class A:
__match_args__: Tuple[Any, ...]
a: str
b: int
m: object
match m:
case A(i, j, k):
reveal_type(i) # N: Revealed type is "Any"
reveal_type(j) # N: Revealed type is "Any"
reveal_type(k) # N: Revealed type is "Any"
[builtins fixtures/tuple.pyi]
[case testMatchNonLiteralMatchArgs]
from typing import Final
b: str = "b"
class A:
__match_args__: Final = ("a", b) # N: __match_args__ must be a tuple containing string literals for checking of match statements to work
a: str
b: int
m: object
match m:
case A(i, j, k): # E: Too many positional patterns for class pattern
pass
case A(i, j):
reveal_type(i) # N: Revealed type is "builtins.str"
reveal_type(j) # N: Revealed type is "Any"
[builtins fixtures/tuple.pyi]
[case testMatchExternalMatchArgs]
from typing import Final, Literal
args: Final = ("a", "b")
class A:
__match_args__: Final = args
a: str
b: int
arg: Final = "a"
arg2: Literal["b"] = "b"
class B:
__match_args__: Final = (arg, arg2)
a: str
b: int
[builtins fixtures/tuple.pyi]
[typing fixtures/typing-medium.pyi]
-- As Pattern --
[case testMatchAsPattern]
m: int
match m:
case x as l:
reveal_type(x) # N: Revealed type is "builtins.int"
reveal_type(l) # N: Revealed type is "builtins.int"
[case testMatchAsPatternNarrows]
m: object
match m:
case int() as l:
reveal_type(l) # N: Revealed type is "builtins.int"
[case testMatchAsPatternCapturesOr]
m: object
match m:
case 1 | 2 as n:
reveal_type(n) # N: Revealed type is "Union[Literal[1], Literal[2]]"
[case testMatchAsPatternAlreadyNarrower]
m: bool
match m:
case int() as l:
reveal_type(l) # N: Revealed type is "builtins.bool"
-- Or Pattern --
[case testMatchOrPatternNarrows]
m: object
match m:
case 1 | 2:
reveal_type(m) # N: Revealed type is "Union[Literal[1], Literal[2]]"
[case testMatchOrPatternNarrowsStr]
m: object
match m:
case "foo" | "bar":
reveal_type(m) # N: Revealed type is "Union[Literal['foo'], Literal['bar']]"
[case testMatchOrPatternNarrowsUnion]
m: object
match m:
case 1 | "foo":
reveal_type(m) # N: Revealed type is "Union[Literal[1], Literal['foo']]"
[case testMatchOrPatterCapturesMissing]
from typing import List
m: List[int]
match m:
case [x, y] | list(x): # E: Alternative patterns bind different names
reveal_type(x) # N: Revealed type is "builtins.object"
reveal_type(y) # N: Revealed type is "builtins.int"
[builtins fixtures/list.pyi]
[case testMatchOrPatternCapturesJoin]
m: object
match m:
case list(x) | dict(x):
reveal_type(x) # N: Revealed type is "typing.Iterable[Any]"
[builtins fixtures/dict.pyi]
-- Interactions --
[case testMatchCapturePatternMultipleCases]
m: object
match m:
case int(x):
reveal_type(x) # N: Revealed type is "builtins.int"
case str(x):
reveal_type(x) # N: Revealed type is "builtins.str"
reveal_type(x) # N: Revealed type is "Union[builtins.int, builtins.str]"
[case testMatchCapturePatternMultipleCaptures]
from typing import Iterable
m: Iterable[int]
match m:
case [x, x]: # E: Multiple assignments to name "x" in pattern
reveal_type(x) # N: Revealed type is "builtins.int"
[builtins fixtures/list.pyi]
[case testMatchCapturePatternPreexistingSame]
a: int
m: int
match m:
case a:
reveal_type(a) # N: Revealed type is "builtins.int"
[case testMatchCapturePatternPreexistingNarrows]
a: int
m: bool
match m:
case a:
reveal_type(a) # N: Revealed type is "builtins.bool"
reveal_type(a) # N: Revealed type is "builtins.bool"
a = 3
reveal_type(a) # N: Revealed type is "builtins.int"
[case testMatchCapturePatternPreexistingIncompatible]
a: str
m: int
match m:
case a: # E: Incompatible types in capture pattern (pattern captures type "int", variable has type "str")
reveal_type(a) # N: Revealed type is "builtins.str"
reveal_type(a) # N: Revealed type is "builtins.str"
[case testMatchCapturePatternPreexistingIncompatibleLater]
a: str
m: object
match m:
case str(a):
reveal_type(a) # N: Revealed type is "builtins.str"
case int(a): # E: Incompatible types in capture pattern (pattern captures type "int", variable has type "str")
reveal_type(a) # N: Revealed type is "builtins.str"
reveal_type(a) # N: Revealed type is "builtins.str"
-- Guards --
[case testMatchSimplePatternGuard]
m: str
def guard() -> bool: ...
match m:
case a if guard():
reveal_type(a) # N: Revealed type is "builtins.str"
[case testMatchAlwaysTruePatternGuard]
m: str
match m:
case a if True:
reveal_type(a) # N: Revealed type is "builtins.str"
[case testMatchAlwaysFalsePatternGuard]
m: str
match m:
case a if False:
reveal_type(a)
[case testMatchRedefiningPatternGuard]
m: str
match m:
case a if a := 1: # E: Incompatible types in assignment (expression has type "int", variable has type "str")
reveal_type(a) # N: Revealed type is "<nothing>"
[case testMatchAssigningPatternGuard]
m: str
match m:
case a if a := "test":
reveal_type(a) # N: Revealed type is "builtins.str"
[case testMatchNarrowingPatternGuard]
m: object
match m:
case a if isinstance(a, str):
reveal_type(a) # N: Revealed type is "builtins.str"
[builtins fixtures/isinstancelist.pyi]
[case testMatchIncompatiblePatternGuard]
class A: ...
class B: ...
m: A
match m:
case a if isinstance(a, B):
reveal_type(a) # N: Revealed type is "__main__.<subclass of "A" and "B">"
[builtins fixtures/isinstancelist.pyi]
[case testMatchUnreachablePatternGuard]
m: str
match m:
case a if isinstance(a, int):
reveal_type(a)
[builtins fixtures/isinstancelist.pyi]
-- Exhaustiveness --
[case testMatchUnionNegativeNarrowing]
from typing import Union
m: Union[str, int]
match m:
case str(a):
reveal_type(a) # N: Revealed type is "builtins.str"
reveal_type(m) # N: Revealed type is "builtins.str"
case b:
reveal_type(b) # N: Revealed type is "builtins.int"
reveal_type(m) # N: Revealed type is "builtins.int"
[case testMatchOrPatternNegativeNarrowing]
from typing import Union
m: Union[str, bytes, int]
match m:
case str(a) | bytes(a):
reveal_type(a) # N: Revealed type is "builtins.object"
reveal_type(m) # N: Revealed type is "Union[builtins.str, builtins.bytes]"
case b:
reveal_type(b) # N: Revealed type is "builtins.int"
[case testMatchExhaustiveReturn]
def foo(value) -> int:
match value:
case "bar":
return 1
case _:
return 2
[case testMatchNonExhaustiveReturn]
def foo(value) -> int: # E: Missing return statement
match value:
case "bar":
return 1
case 2:
return 2
[case testMatchMoreExhaustiveReturnCases]
def g(value: int | None) -> int:
match value:
case int():
return 0
case None:
return 1
def b(value: bool) -> int:
match value:
case True:
return 2
case False:
return 3
[case testMatchMiscNonExhaustiveReturn]
class C:
a: int | str
def f1(value: int | str | None) -> int: # E: Missing return statement
match value:
case int():
return 0
case None:
return 1
def f2(c: C) -> int: # E: Missing return statement
match c:
case C(a=int()):
return 0
case C(a=str()):
return 1
def f3(x: list[str]) -> int: # E: Missing return statement
match x:
case [a]:
return 0
case [a, b]:
return 1
def f4(x: dict[str, int]) -> int: # E: Missing return statement
match x:
case {'x': a}:
return 0
def f5(x: bool) -> int: # E: Missing return statement
match x:
case True:
return 0
[builtins fixtures/dict.pyi]
[case testMatchNonExhaustiveError]
from typing import NoReturn
def assert_never(x: NoReturn) -> None: ...
def f(value: int) -> int: # E: Missing return statement
match value:
case 1:
return 0
case 2:
return 1
case o:
assert_never(o) # E: Argument 1 to "assert_never" has incompatible type "int"; expected "NoReturn"
[case testMatchExhaustiveNoError]
from typing import NoReturn, Union, Literal
def assert_never(x: NoReturn) -> None: ...
def f(value: Literal[1] | Literal[2]) -> int:
match value:
case 1:
return 0
case 2:
return 1
case o:
assert_never(o)
[typing fixtures/typing-medium.pyi]
[case testMatchSequencePatternNegativeNarrowing]
from typing import Union, Sequence, Tuple
m1: Sequence[int | str]
match m1:
case [int()]:
reveal_type(m1) # N: Revealed type is "typing.Sequence[builtins.int]"
case r:
reveal_type(m1) # N: Revealed type is "typing.Sequence[Union[builtins.int, builtins.str]]"
m2: Tuple[int | str]
match m2:
case (int(),):
reveal_type(m2) # N: Revealed type is "Tuple[builtins.int]"
case r2:
reveal_type(m2) # N: Revealed type is "Tuple[builtins.str]"
m3: Tuple[Union[int, str]]
match m3:
case (1,):
reveal_type(m3) # N: Revealed type is "Tuple[Literal[1]]"
case r2:
reveal_type(m3) # N: Revealed type is "Tuple[Union[builtins.int, builtins.str]]"
[builtins fixtures/tuple.pyi]
[case testMatchLiteralPatternEnumNegativeNarrowing]
from enum import Enum
class Medal(Enum):
gold = 1
silver = 2
bronze = 3
def f(m: Medal) -> int:
match m:
case Medal.gold:
reveal_type(m) # N: Revealed type is "Literal[__main__.Medal.gold]"
return 0
case _:
reveal_type(m) # N: Revealed type is "Union[Literal[__main__.Medal.silver], Literal[__main__.Medal.bronze]]"
return 1
def g(m: Medal) -> int:
match m:
case Medal.gold:
return 0
case Medal.silver:
return 1
case Medal.bronze:
return 2
[case testMatchLiteralPatternEnumCustomEquals-skip]
from enum import Enum
class Medal(Enum):
gold = 1
silver = 2
bronze = 3
def __eq__(self, other) -> bool: ...
m: Medal
match m:
case Medal.gold:
reveal_type(m) # N: Revealed type is "Literal[__main__.Medal.gold]"
case _:
reveal_type(m) # N: Revealed type is "__main__.Medal"
[case testMatchNarrowUsingPatternGuardSpecialCase]
def f(x: int | str) -> int: # E: Missing return statement
match x:
case x if isinstance(x, str):
return 0
case int():
return 1
[builtins fixtures/isinstance.pyi]
[case testMatchNarrowDownUnionPartially]
def f(x: int | str) -> None:
match x:
case int():
return
reveal_type(x) # N: Revealed type is "builtins.str"
def g(x: int | str | None) -> None:
match x:
case int() | None:
return
reveal_type(x) # N: Revealed type is "builtins.str"
def h(x: int | str | None) -> None:
match x:
case int() | str():
return
reveal_type(x) # N: Revealed type is "None"
[case testMatchNarrowDownUsingLiteralMatch]
from enum import Enum
class Medal(Enum):
gold = 1
silver = 2
def b1(x: bool) -> None:
match x:
case True:
return
reveal_type(x) # N: Revealed type is "Literal[False]"
def b2(x: bool) -> None:
match x:
case False:
return
reveal_type(x) # N: Revealed type is "Literal[True]"
def e1(x: Medal) -> None:
match x:
case Medal.gold:
return
reveal_type(x) # N: Revealed type is "Literal[__main__.Medal.silver]"
def e2(x: Medal) -> None:
match x:
case Medal.silver:
return
reveal_type(x) # N: Revealed type is "Literal[__main__.Medal.gold]"
def i(x: int) -> None:
match x:
case 1:
return
reveal_type(x) # N: Revealed type is "builtins.int"
def s(x: str) -> None:
match x:
case 'x':
return
reveal_type(x) # N: Revealed type is "builtins.str"
def union(x: str | bool) -> None:
match x:
case True:
return
reveal_type(x) # N: Revealed type is "Union[builtins.str, Literal[False]]"
[case testMatchAssertFalseToSilenceFalsePositives]
class C:
a: int | str
def f(c: C) -> int:
match c:
case C(a=int()):
return 0
case C(a=str()):
return 1
case _:
assert False
def g(c: C) -> int:
match c:
case C(a=int()):
return 0
case C(a=str()):
return 1
assert False
[case testMatchAsPatternExhaustiveness]
def f(x: int | str) -> int:
match x:
case int() as n:
return n
case str() as s:
return 1
[case testMatchAsPatternIntersection-skip]
class A: pass
class B: pass
class C: pass
def f(x: A) -> None:
match x:
case B() as y:
reveal_type(y) # N: Revealed type is "__main__.<subclass of "A" and "B">"
case C() as y:
reveal_type(y) # N: Revealed type is "__main__.<subclass of "A" and "C">"
reveal_type(y) # N: Revealed type is "Union[__main__.<subclass of "A" and "B">, __main__.<subclass of "A" and "C">]"
[case testMatchWithBreakAndContinue]
def f(x: int | str | None) -> None:
i = int()
while i:
match x:
case int():
continue
case str():
break
reveal_type(x) # N: Revealed type is "None"
reveal_type(x) # N: Revealed type is "Union[builtins.int, builtins.str, None]"
[case testMatchNarrowDownWithStarred-skip]
from typing import List
def f(x: List[int] | int) -> None:
match x:
case [*y]:
reveal_type(y) # N: Revealed type is "builtins.list[builtins.int]"
return
reveal_type(x) # N: Revealed type is "builtins.int"
[builtins fixtures/list.pyi]
-- Misc
[case testMatchAndWithStatementScope]
from m import A, B
with A() as x:
pass
with B() as x: \
# E: Incompatible types in assignment (expression has type "B", variable has type "A")
pass
with A() as y:
pass
with B() as y: \
# E: Incompatible types in assignment (expression has type "B", variable has type "A")
pass
with A() as z:
pass
with B() as z: \
# E: Incompatible types in assignment (expression has type "B", variable has type "A")
pass
with A() as zz:
pass
with B() as zz: \
# E: Incompatible types in assignment (expression has type "B", variable has type "A")
pass
match x:
case str(y) as z:
zz = y
[file m.pyi]
from typing import Any
class A:
def __enter__(self) -> A: ...
def __exit__(self, x, y, z) -> None: ...
class B:
def __enter__(self) -> B: ...
def __exit__(self, x, y, z) -> None: ...
[case testOverrideMatchArgs]
class AST:
__match_args__ = ()
class stmt(AST): ...
class AnnAssign(stmt):
__match_args__ = ('target', 'annotation', 'value', 'simple')
target: str
annotation: int
value: str
simple: int
reveal_type(AST.__match_args__) # N: Revealed type is "Tuple[]"
reveal_type(stmt.__match_args__) # N: Revealed type is "Tuple[]"
reveal_type(AnnAssign.__match_args__) # N: Revealed type is "Tuple[Literal['target']?, Literal['annotation']?, Literal['value']?, Literal['simple']?]"
AnnAssign.__match_args__ = ('a', 'b', 'c', 'd') # E: Cannot assign to "__match_args__"
__match_args__ = 0
def f(x: AST) -> None:
match x:
case AST():
reveal_type(x) # N: Revealed type is "__main__.AST"
match x:
case stmt():
reveal_type(x) # N: Revealed type is "__main__.stmt"
match x:
case AnnAssign(a, b, c, d):
reveal_type(a) # N: Revealed type is "builtins.str"
reveal_type(b) # N: Revealed type is "builtins.int"
reveal_type(c) # N: Revealed type is "builtins.str"
[builtins fixtures/tuple.pyi]
[case testMatchReachableDottedNames]
# flags: --warn-unreachable
class Consts:
BLANK = ""
SPECIAL = "asdf"
def test_func(test_str: str) -> str:
match test_str:
case Consts.BLANK:
return "blank"
case Consts.SPECIAL:
return "special"
case _:
return "other"
[case testNoneTypeWarning]
from types import NoneType
def foo(x: NoneType): # E: NoneType should not be used as a type, please use None instead
reveal_type(x) # N: Revealed type is "None"
[builtins fixtures/tuple.pyi]
[case testMatchTupleInstanceUnionNoCrash]
from typing import Union
def func(e: Union[str, tuple[str]]) -> None:
match e:
case (a,) if isinstance(a, str):
reveal_type(a) # N: Revealed type is "builtins.str"
[builtins fixtures/tuple.pyi]
[case testMatchTupleOptionalNoCrash]
foo: tuple[int] | None
match foo:
case x,:
reveal_type(x) # N: Revealed type is "builtins.int"
[builtins fixtures/tuple.pyi]
[case testMatchUnionTwoTuplesNoCrash]
var: tuple[int, int] | tuple[str, str]
# TODO: we can infer better here.
match var:
case (42, a):
reveal_type(a) # N: Revealed type is "Union[builtins.int, builtins.str]"
case ("yes", b):
reveal_type(b) # N: Revealed type is "Union[builtins.int, builtins.str]"
[builtins fixtures/tuple.pyi]
[case testMatchNamedAndKeywordsAreTheSame]
from typing import Generic, TypeVar, Union
from typing_extensions import Final
from dataclasses import dataclass
T = TypeVar("T")
class Regular:
x: str
y: int
__match_args__ = ("x",)
class ReveresedOrder:
x: int
y: str
__match_args__ = ("y",)
class GenericRegular(Generic[T]):
x: T
__match_args__ = ("x",)
class GenericWithFinal(Generic[T]):
x: T
__match_args__: Final = ("x",)
class RegularSubtype(GenericRegular[str]): ...
@dataclass
class GenericDataclass(Generic[T]):
x: T
input_arg: Union[
Regular,
ReveresedOrder,
GenericRegular[str],
GenericWithFinal[str],
RegularSubtype,
GenericDataclass[str],
]
# Positional:
match input_arg:
case Regular(a):
reveal_type(a) # N: Revealed type is "builtins.str"
case ReveresedOrder(a):
reveal_type(a) # N: Revealed type is "builtins.str"
case GenericWithFinal(a):
reveal_type(a) # N: Revealed type is "builtins.str"
case RegularSubtype(a):
reveal_type(a) # N: Revealed type is "builtins.str"
case GenericRegular(a):
reveal_type(a) # N: Revealed type is "builtins.str"
case GenericDataclass(a):
reveal_type(a) # N: Revealed type is "builtins.str"
# Keywords:
match input_arg:
case Regular(x=a):
reveal_type(a) # N: Revealed type is "builtins.str"
case ReveresedOrder(x=b): # Order is different
reveal_type(b) # N: Revealed type is "builtins.int"
case GenericWithFinal(x=a):
reveal_type(a) # N: Revealed type is "builtins.str"
case RegularSubtype(x=a):
reveal_type(a) # N: Revealed type is "builtins.str"
case GenericRegular(x=a):
reveal_type(a) # N: Revealed type is "builtins.str"
case GenericDataclass(x=a):
reveal_type(a) # N: Revealed type is "builtins.str"
[builtins fixtures/dataclasses.pyi]
[case testMatchValueConstrainedTypeVar]
from typing import TypeVar, Iterable
S = TypeVar("S", int, str)
def my_func(pairs: Iterable[tuple[S, S]]) -> None:
for pair in pairs:
reveal_type(pair) # N: Revealed type is "Tuple[builtins.int, builtins.int]" \
# N: Revealed type is "Tuple[builtins.str, builtins.str]"
match pair:
case _:
reveal_type(pair) # N: Revealed type is "Tuple[builtins.int, builtins.int]" \
# N: Revealed type is "Tuple[builtins.str, builtins.str]"
[builtins fixtures/tuple.pyi]
[case testPossiblyUndefinedMatch]
# flags: --enable-error-code possibly-undefined
def f0(x: int | str) -> int:
match x:
case int():
y = 1
return y # E: Name "y" may be undefined
def f1(a: object) -> None:
match a:
case [y]: pass
case _:
y = 1
x = 2
z = y
z = x # E: Name "x" may be undefined
def f2(a: object) -> None:
match a:
case [[y] as x]: pass
case {"k1": 1, "k2": x, "k3": y}: pass
case [0, *x]:
y = 2
case _:
y = 1
x = [2]
z = x
z = y
def f3(a: object) -> None:
y = 1
match a:
case [x]:
y = 2
# Note the missing `case _:`
z = x # E: Name "x" may be undefined
z = y
def f4(a: object) -> None:
y = 1
match a:
case [x]:
y = 2
case _:
assert False, "unsupported"
z = x
z = y
def f5(a: object) -> None:
match a:
case tuple(x): pass
case _:
return
y = x
def f6(a: object) -> None:
if int():
y = 1
match a:
case _ if y is not None: # E: Name "y" may be undefined
pass
[builtins fixtures/tuple.pyi]
[case testPossiblyUndefinedMatchUnreachable]
# flags: --enable-error-code possibly-undefined
import typing
def f0(x: int) -> int:
match x:
case 1 if not typing.TYPE_CHECKING:
pass
case 2:
y = 2
case _:
y = 3
return y # No error.
def f1(x: int) -> int:
match x:
case 1 if not typing.TYPE_CHECKING:
pass
case 2:
y = 2
return y # E: Name "y" may be undefined
[typing fixtures/typing-medium.pyi]
[case testUsedBeforeDefMatchWalrus]
# flags: --enable-error-code used-before-def
import typing
def f0(x: int) -> None:
a = y # E: Cannot determine type of "y" # E: Name "y" is used before definition
match y := x:
case 1:
b = y
case 2:
c = y
d = y
[case testTypeAliasWithNewUnionSyntaxAndNoneLeftOperand]
from typing import overload
class C:
@overload
def __init__(self) -> None: pass
@overload
def __init__(self, x: int) -> None: pass
def __init__(self, x=0):
pass
class D: pass
X = None | C
Y = None | D
[builtins fixtures/type.pyi]
[case testMatchStatementWalrus]
class A:
a = 1
def returns_a_or_none() -> A | None:
return A()
def returns_a() -> A:
return A()
def f() -> None:
match x := returns_a_or_none():
case A():
reveal_type(x.a) # N: Revealed type is "builtins.int"
match x := returns_a():
case A():
reveal_type(x.a) # N: Revealed type is "builtins.int"
y = returns_a_or_none()
match y:
case A():
reveal_type(y.a) # N: Revealed type is "builtins.int"
[case testNarrowedVariableInNestedModifiedInMatch]
from typing import Optional
def match_stmt_error1(x: Optional[str]) -> None:
if x is None:
x = "a"
def nested() -> str:
return x # E: Incompatible return value type (got "Optional[str]", expected "str")
match object():
case str(x):
pass
nested()
def foo(x): pass
def match_stmt_ok1(x: Optional[str]) -> None:
if x is None:
x = "a"
def nested() -> str:
return x
match foo(x):
case str(y):
z = x
nested()
def match_stmt_error2(x: Optional[str]) -> None:
if x is None:
x = "a"
def nested() -> str:
return x # E: Incompatible return value type (got "Optional[str]", expected "str")
match [None]:
case [x]:
pass
nested()
def match_stmt_error3(x: Optional[str]) -> None:
if x is None:
x = "a"
def nested() -> str:
return x # E: Incompatible return value type (got "Optional[str]", expected "str")
match {'a': None}:
case {'a': x}:
pass
nested()
def match_stmt_error4(x: Optional[list[str]]) -> None:
if x is None:
x = ["a"]
def nested() -> list[str]:
return x # E: Incompatible return value type (got "Optional[List[str]]", expected "List[str]")
match ["a"]:
case [*x]:
pass
nested()
class C:
a: str
def match_stmt_error5(x: Optional[str]) -> None:
if x is None:
x = "a"
def nested() -> str:
return x # E: Incompatible return value type (got "Optional[str]", expected "str")
match C():
case C(a=x):
pass
nested()
[builtins fixtures/tuple.pyi]
[case testMatchSubjectRedefinition]
# flags: --allow-redefinition
def transform1(a: str) -> int:
...
def transform2(a: int) -> str:
...
def redefinition_good(a: str):
a = transform1(a)
match (a + 1):
case _:
...
def redefinition_bad(a: int):
a = transform2(a)
match (a + 1): # E: Unsupported operand types for + ("str" and "int")
case _:
...
[builtins fixtures/primitives.pyi]
[case testPatternMatchingClassPatternLocation]
# See https://github.com/python/mypy/issues/15496
from some_missing_lib import DataFrame, Series # type: ignore[import]
from typing import TypeVar
T = TypeVar("T", Series, DataFrame)
def f(x: T) -> None:
match x:
case Series() | DataFrame(): # type: ignore[misc]
pass
def f2(x: T) -> None:
match x:
case Series(): # type: ignore[misc]
pass
case DataFrame(): # type: ignore[misc]
pass
[builtins fixtures/primitives.pyi]