| -- 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] |