| -- 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 "__main__.A" and "b.B">" | |
| [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] | |
| # Narrowing union-based values via a literal pattern on an indexed/attribute subject | |
| # ------------------------------------------------------------------------------- | |
| # Literal patterns against a union of types can be used to narrow the subject | |
| # itself, not just the expression being matched. Previously, the patterns below | |
| # failed to narrow the `d` variable, leading to errors for missing members; we | |
| # now propagate the type information up to the parent. | |
| [case testMatchNarrowingUnionTypedDictViaIndex] | |
| from typing import Literal, TypedDict | |
| class A(TypedDict): | |
| tag: Literal["a"] | |
| name: str | |
| class B(TypedDict): | |
| tag: Literal["b"] | |
| num: int | |
| d: A | B | |
| match d["tag"]: | |
| case "a": | |
| reveal_type(d) # N: Revealed type is "TypedDict('__main__.A', {'tag': Literal['a'], 'name': builtins.str})" | |
| reveal_type(d["name"]) # N: Revealed type is "builtins.str" | |
| case "b": | |
| reveal_type(d) # N: Revealed type is "TypedDict('__main__.B', {'tag': Literal['b'], 'num': builtins.int})" | |
| reveal_type(d["num"]) # N: Revealed type is "builtins.int" | |
| [typing fixtures/typing-typeddict.pyi] | |
| [case testMatchNarrowingUnionClassViaAttribute] | |
| from typing import Literal | |
| class A: | |
| tag: Literal["a"] | |
| name: str | |
| class B: | |
| tag: Literal["b"] | |
| num: int | |
| d: A | B | |
| match d.tag: | |
| case "a": | |
| reveal_type(d) # N: Revealed type is "__main__.A" | |
| reveal_type(d.name) # N: Revealed type is "builtins.str" | |
| case "b": | |
| reveal_type(d) # N: Revealed type is "__main__.B" | |
| reveal_type(d.num) # N: Revealed type is "builtins.int" | |
| [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] | |
| [case testMatchSequencePatternNarrowSubjectItems] | |
| m: int | |
| n: str | |
| o: bool | |
| match m, n, o: | |
| case [3, "foo", True]: | |
| reveal_type(m) # N: Revealed type is "Literal[3]" | |
| reveal_type(n) # N: Revealed type is "Literal['foo']" | |
| reveal_type(o) # N: Revealed type is "Literal[True]" | |
| case [a, b, c]: | |
| reveal_type(m) # N: Revealed type is "builtins.int" | |
| reveal_type(n) # N: Revealed type is "builtins.str" | |
| reveal_type(o) # N: Revealed type is "builtins.bool" | |
| reveal_type(m) # N: Revealed type is "builtins.int" | |
| reveal_type(n) # N: Revealed type is "builtins.str" | |
| reveal_type(o) # N: Revealed type is "builtins.bool" | |
| [builtins fixtures/tuple.pyi] | |
| [case testMatchSequencePatternNarrowSubjectItemsRecursive] | |
| m: int | |
| n: int | |
| o: int | |
| p: int | |
| q: int | |
| r: int | |
| match m, (n, o), (p, (q, r)): | |
| case [0, [1, 2], [3, [4, 5]]]: | |
| reveal_type(m) # N: Revealed type is "Literal[0]" | |
| reveal_type(n) # N: Revealed type is "Literal[1]" | |
| reveal_type(o) # N: Revealed type is "Literal[2]" | |
| reveal_type(p) # N: Revealed type is "Literal[3]" | |
| reveal_type(q) # N: Revealed type is "Literal[4]" | |
| reveal_type(r) # N: Revealed type is "Literal[5]" | |
| [builtins fixtures/tuple.pyi] | |
| [case testMatchSequencePatternSequencesLengthMismatchNoNarrowing] | |
| m: int | |
| n: str | |
| o: bool | |
| match m, n, o: | |
| case [3, "foo"]: | |
| pass | |
| case [3, "foo", True, True]: | |
| pass | |
| [builtins fixtures/tuple.pyi] | |
| [case testMatchSequencePatternSequencesLengthMismatchNoNarrowingRecursive] | |
| m: int | |
| n: int | |
| o: int | |
| match m, (n, o): | |
| case [0]: | |
| pass | |
| case [0, 1, [2]]: | |
| pass | |
| case [0, [1]]: | |
| pass | |
| case [0, [1, 2, 3]]: | |
| pass | |
| [builtins fixtures/tuple.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 testMatchClassPatternCaptureSelfSubtype] | |
| class A(str): | |
| pass | |
| class B(str): | |
| __match_args__ = ("b",) | |
| b: int | |
| def f1(x: A): | |
| match x: | |
| case A(a): | |
| reveal_type(a) # N: Revealed type is "__main__.A" | |
| def f2(x: B): | |
| match x: | |
| case B(b): | |
| reveal_type(b) # N: Revealed type is "builtins.int" | |
| [builtins fixtures/tuple.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 testMatchSequencePatternCaptureNamedTuple] | |
| from typing import NamedTuple | |
| class N(NamedTuple): | |
| x: int | |
| y: str | |
| a = N(1, "a") | |
| match a: | |
| case [x, y]: | |
| reveal_type(x) # N: Revealed type is "builtins.int" | |
| reveal_type(y) # N: Revealed type is "builtins.str" | |
| [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 testMatchClassPatternCaptureVariadicGeneric] | |
| from typing import Generic, Tuple | |
| from typing_extensions import TypeVarTuple, Unpack | |
| Ts = TypeVarTuple('Ts') | |
| class A(Generic[Unpack[Ts]]): | |
| a: Tuple[Unpack[Ts]] | |
| m: object | |
| match m: | |
| case A(a=i): | |
| reveal_type(m) # N: Revealed type is "__main__.A[Unpack[builtins.tuple[Any, ...]]]" | |
| reveal_type(i) # N: Revealed type is "builtins.tuple[Any, ...]" | |
| [builtins fixtures/tuple.pyi] | |
| [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 "__main__.B" and "__main__.A">" | |
| case A(i, j): | |
| reveal_type(m) # N: Revealed type is "__main__.<subclass of "__main__.B" and "__main__.A">" | |
| [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 testMatchClassPatternAny] | |
| from typing import Any | |
| Foo: Any | |
| m: object | |
| match m: | |
| case Foo(): | |
| pass | |
| [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-full.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" | |
| [case testMatchCapturePatternFromFunctionReturningUnion] | |
| def func1(arg: bool) -> str | int: ... | |
| def func2(arg: bool) -> bytes | int: ... | |
| def main() -> None: | |
| match func1(True): | |
| case str(a): | |
| match func2(True): | |
| case c: | |
| reveal_type(a) # N: Revealed type is "builtins.str" | |
| reveal_type(c) # N: Revealed type is "Union[builtins.bytes, builtins.int]" | |
| reveal_type(a) # N: Revealed type is "builtins.str" | |
| case a: | |
| reveal_type(a) # N: Revealed type is "builtins.int" | |
| [case testMatchCapturePatternFromAsyncFunctionReturningUnion-xfail] | |
| async def func1(arg: bool) -> str | int: ... | |
| async def func2(arg: bool) -> bytes | int: ... | |
| async def main() -> None: | |
| match await func1(True): | |
| case str(a): | |
| match await func2(True): | |
| case c: | |
| reveal_type(a) # N: Revealed type is "builtins.str" | |
| reveal_type(c) # N: Revealed type is "Union[builtins.bytes, builtins.int]" | |
| reveal_type(a) # N: Revealed type is "builtins.str" | |
| case a: | |
| reveal_type(a) # N: Revealed type is "builtins.int" | |
| -- 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 "Literal[1]?" | |
| [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 "__main__.A" and "__main__.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 "Never" | |
| [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 Literal, 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]]" | |
| m4: Tuple[Literal[1], int] | |
| match m4: | |
| case (1, 5): | |
| reveal_type(m4) # N: Revealed type is "Tuple[Literal[1], Literal[5]]" | |
| case (1, 6): | |
| reveal_type(m4) # N: Revealed type is "Tuple[Literal[1], Literal[6]]" | |
| case _: | |
| reveal_type(m4) # N: Revealed type is "Tuple[Literal[1], builtins.int]" | |
| m5: Tuple[Literal[1, 2], Literal["a", "b"]] | |
| match m5: | |
| case (1, str()): | |
| reveal_type(m5) # N: Revealed type is "Tuple[Literal[1], Union[Literal['a'], Literal['b']]]" | |
| case _: | |
| reveal_type(m5) # N: Revealed type is "Tuple[Literal[2], Union[Literal['a'], Literal['b']]]" | |
| m6: Tuple[Literal[1, 2], Literal["a", "b"]] | |
| match m6: | |
| case (1, "a"): | |
| reveal_type(m6) # N: Revealed type is "Tuple[Literal[1], Literal['a']]" | |
| case _: | |
| reveal_type(m6) # N: Revealed type is "Tuple[Union[Literal[1], Literal[2]], Union[Literal['a'], Literal['b']]]" | |
| [builtins fixtures/tuple.pyi] | |
| [case testMatchEnumSingleChoice] | |
| from enum import Enum | |
| from typing import NoReturn | |
| def assert_never(x: NoReturn) -> None: ... | |
| class Medal(Enum): | |
| gold = 1 | |
| def f(m: Medal) -> None: | |
| always_assigned: int | None = None | |
| match m: | |
| case Medal.gold: | |
| always_assigned = 1 | |
| reveal_type(m) # N: Revealed type is "Literal[__main__.Medal.gold]" | |
| case _: | |
| assert_never(m) | |
| reveal_type(always_assigned) # N: Revealed type is "builtins.int" | |
| [builtins fixtures/bool.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: | |
| reveal_type(m) # N: Revealed type is "Literal[__main__.Medal.gold]" | |
| return 0 | |
| case Medal.silver: | |
| reveal_type(m) # N: Revealed type is "Literal[__main__.Medal.silver]" | |
| return 1 | |
| case Medal.bronze: | |
| reveal_type(m) # N: Revealed type is "Literal[__main__.Medal.bronze]" | |
| return 2 | |
| [builtins fixtures/enum.pyi] | |
| [case testMatchLiteralPatternEnumWithTypedAttribute] | |
| from enum import Enum | |
| from typing import NoReturn | |
| def assert_never(x: NoReturn) -> None: ... | |
| class int: | |
| def __new__(cls, value: int): pass | |
| class Medal(int, Enum): | |
| prize: str | |
| def __new__(cls, value: int, prize: str) -> Medal: | |
| enum = int.__new__(cls, value) | |
| enum._value_ = value | |
| enum.prize = prize | |
| return enum | |
| gold = (1, 'cash prize') | |
| silver = (2, 'sponsorship') | |
| bronze = (3, 'nothing') | |
| m: Medal | |
| match m: | |
| case Medal.gold: | |
| reveal_type(m) # N: Revealed type is "Literal[__main__.Medal.gold]" | |
| case Medal.silver: | |
| reveal_type(m) # N: Revealed type is "Literal[__main__.Medal.silver]" | |
| case Medal.bronze: | |
| reveal_type(m) # N: Revealed type is "Literal[__main__.Medal.bronze]" | |
| case _ as unreachable: | |
| assert_never(unreachable) | |
| [builtins fixtures/tuple.pyi] | |
| [case testMatchLiteralPatternFunctionalEnum] | |
| from enum import Enum | |
| from typing import NoReturn | |
| def assert_never(x: NoReturn) -> None: ... | |
| Medal = Enum('Medal', 'gold silver bronze') | |
| m: Medal | |
| match m: | |
| case Medal.gold: | |
| reveal_type(m) # N: Revealed type is "Literal[__main__.Medal.gold]" | |
| case Medal.silver: | |
| reveal_type(m) # N: Revealed type is "Literal[__main__.Medal.silver]" | |
| case Medal.bronze: | |
| reveal_type(m) # N: Revealed type is "Literal[__main__.Medal.bronze]" | |
| case _ as unreachable: | |
| assert_never(unreachable) | |
| [builtins fixtures/enum.pyi] | |
| [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" | |
| [builtins fixtures/enum.pyi] | |
| [case testMatchNarrowUsingPatternGuardSpecialCase] | |
| def f(x: int | str) -> int: | |
| 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]]" | |
| [builtins fixtures/tuple.pyi] | |
| [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 testMatchOrPatternExhaustiveness] | |
| from typing import NoReturn, Literal | |
| def assert_never(x: NoReturn) -> None: ... | |
| Color = Literal["blue", "green", "red"] | |
| c: Color | |
| match c: | |
| case "blue": | |
| reveal_type(c) # N: Revealed type is "Literal['blue']" | |
| case "green" | "notColor": | |
| reveal_type(c) # N: Revealed type is "Literal['green']" | |
| case _: | |
| assert_never(c) # E: Argument 1 to "assert_never" has incompatible type "Literal['red']"; expected "Never" | |
| [typing fixtures/typing-typeddict.pyi] | |
| [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 "__main__.A" and "__main__.B">" | |
| case C() as y: | |
| reveal_type(y) # N: Revealed type is "__main__.<subclass of "__main__.A" and "__main__.C">" | |
| reveal_type(y) # N: Revealed type is "Union[__main__.<subclass of "__main__.A" and "__main__.B">, __main__.<subclass of "__main__.A" and "__main__.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, Final, TypeVar, Union | |
| from dataclasses import dataclass | |
| T = TypeVar("T") | |
| class Regular: | |
| x: str | |
| y: int | |
| __match_args__ = ("x",) | |
| class ReversedOrder: | |
| 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, | |
| ReversedOrder, | |
| GenericRegular[str], | |
| GenericWithFinal[str], | |
| RegularSubtype, | |
| GenericDataclass[str], | |
| ] | |
| # Positional: | |
| match input_arg: | |
| case Regular(a): | |
| reveal_type(a) # N: Revealed type is "builtins.str" | |
| case ReversedOrder(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 ReversedOrder(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] | |
| [case testMatchGuardReachability] | |
| # flags: --warn-unreachable | |
| def f1(e: int) -> int: | |
| match e: | |
| case x if True: | |
| return x | |
| case _: | |
| return 0 # E: Statement is unreachable | |
| e = 0 # E: Statement is unreachable | |
| def f2(e: int) -> int: | |
| match e: | |
| case x if bool(): | |
| return x | |
| case _: | |
| return 0 | |
| e = 0 # E: Statement is unreachable | |
| def f3(e: int | str | bytes) -> int: | |
| match e: | |
| case x if isinstance(x, int): | |
| return x | |
| case [x]: | |
| return 0 # E: Statement is unreachable | |
| case str(x): | |
| return 0 | |
| reveal_type(e) # N: Revealed type is "builtins.bytes" | |
| return 0 | |
| def f4(e: int | str | bytes) -> int: | |
| match e: | |
| case int(x): | |
| pass | |
| case [x]: | |
| return 0 # E: Statement is unreachable | |
| case x if isinstance(x, str): | |
| return 0 | |
| reveal_type(e) # N: Revealed type is "Union[builtins.int, builtins.bytes]" | |
| return 0 | |
| [builtins fixtures/primitives.pyi] | |
| [case testMatchSequencePatternVariadicTupleNotTooShort] | |
| from typing import Tuple | |
| from typing_extensions import Unpack | |
| fm1: Tuple[int, int, Unpack[Tuple[str, ...]], int] | |
| match fm1: | |
| case [fa1, fb1, fc1]: | |
| reveal_type(fa1) # N: Revealed type is "builtins.int" | |
| reveal_type(fb1) # N: Revealed type is "builtins.int" | |
| reveal_type(fc1) # N: Revealed type is "builtins.int" | |
| fm2: Tuple[int, int, Unpack[Tuple[str, ...]], int] | |
| match fm2: | |
| case [fa2, fb2]: | |
| reveal_type(fa2) | |
| reveal_type(fb2) | |
| fm3: Tuple[int, int, Unpack[Tuple[str, ...]], int] | |
| match fm3: | |
| case [fa3, fb3, fc3, fd3, fe3]: | |
| reveal_type(fa3) # N: Revealed type is "builtins.int" | |
| reveal_type(fb3) # N: Revealed type is "builtins.int" | |
| reveal_type(fc3) # N: Revealed type is "builtins.str" | |
| reveal_type(fd3) # N: Revealed type is "builtins.str" | |
| reveal_type(fe3) # N: Revealed type is "builtins.int" | |
| m1: Tuple[int, Unpack[Tuple[str, ...]], int] | |
| match m1: | |
| case [a1, *b1, c1]: | |
| reveal_type(a1) # N: Revealed type is "builtins.int" | |
| reveal_type(b1) # N: Revealed type is "builtins.list[builtins.str]" | |
| reveal_type(c1) # N: Revealed type is "builtins.int" | |
| m2: Tuple[int, Unpack[Tuple[str, ...]], int] | |
| match m2: | |
| case [a2, b2, *c2, d2, e2]: | |
| reveal_type(a2) # N: Revealed type is "builtins.int" | |
| reveal_type(b2) # N: Revealed type is "builtins.str" | |
| reveal_type(c2) # N: Revealed type is "builtins.list[builtins.str]" | |
| reveal_type(d2) # N: Revealed type is "builtins.str" | |
| reveal_type(e2) # N: Revealed type is "builtins.int" | |
| m3: Tuple[int, int, Unpack[Tuple[str, ...]], int, int] | |
| match m3: | |
| case [a3, *b3, c3]: | |
| reveal_type(a3) # N: Revealed type is "builtins.int" | |
| reveal_type(b3) # N: Revealed type is "builtins.list[Union[builtins.int, builtins.str]]" | |
| reveal_type(c3) # N: Revealed type is "builtins.int" | |
| [builtins fixtures/tuple.pyi] | |
| [case testMatchSequencePatternTypeVarTupleNotTooShort] | |
| from typing import Tuple | |
| from typing_extensions import Unpack, TypeVarTuple | |
| Ts = TypeVarTuple("Ts") | |
| def test(xs: Tuple[Unpack[Ts]]) -> None: | |
| fm1: Tuple[int, int, Unpack[Ts], int] | |
| match fm1: | |
| case [fa1, fb1, fc1]: | |
| reveal_type(fa1) # N: Revealed type is "builtins.int" | |
| reveal_type(fb1) # N: Revealed type is "builtins.int" | |
| reveal_type(fc1) # N: Revealed type is "builtins.int" | |
| fm2: Tuple[int, int, Unpack[Ts], int] | |
| match fm2: | |
| case [fa2, fb2]: | |
| reveal_type(fa2) | |
| reveal_type(fb2) | |
| fm3: Tuple[int, int, Unpack[Ts], int] | |
| match fm3: | |
| case [fa3, fb3, fc3, fd3, fe3]: | |
| reveal_type(fa3) # N: Revealed type is "builtins.int" | |
| reveal_type(fb3) # N: Revealed type is "builtins.int" | |
| reveal_type(fc3) # N: Revealed type is "builtins.object" | |
| reveal_type(fd3) # N: Revealed type is "builtins.object" | |
| reveal_type(fe3) # N: Revealed type is "builtins.int" | |
| m1: Tuple[int, Unpack[Ts], int] | |
| match m1: | |
| case [a1, *b1, c1]: | |
| reveal_type(a1) # N: Revealed type is "builtins.int" | |
| reveal_type(b1) # N: Revealed type is "builtins.list[builtins.object]" | |
| reveal_type(c1) # N: Revealed type is "builtins.int" | |
| m2: Tuple[int, Unpack[Ts], int] | |
| match m2: | |
| case [a2, b2, *c2, d2, e2]: | |
| reveal_type(a2) # N: Revealed type is "builtins.int" | |
| reveal_type(b2) # N: Revealed type is "builtins.object" | |
| reveal_type(c2) # N: Revealed type is "builtins.list[builtins.object]" | |
| reveal_type(d2) # N: Revealed type is "builtins.object" | |
| reveal_type(e2) # N: Revealed type is "builtins.int" | |
| m3: Tuple[int, int, Unpack[Ts], int, int] | |
| match m3: | |
| case [a3, *b3, c3]: | |
| reveal_type(a3) # N: Revealed type is "builtins.int" | |
| reveal_type(b3) # N: Revealed type is "builtins.list[builtins.object]" | |
| reveal_type(c3) # N: Revealed type is "builtins.int" | |
| [builtins fixtures/tuple.pyi] | |
| [case testMatchSequencePatternTypeVarBoundNoCrash] | |
| # This was crashing: https://github.com/python/mypy/issues/18089 | |
| from typing import TypeVar, Sequence, Any | |
| T = TypeVar("T", bound=Sequence[Any]) | |
| def f(x: T) -> None: | |
| match x: | |
| case [_]: | |
| pass | |
| [builtins fixtures/tuple.pyi] | |
| [case testMatchSequencePatternTypeVarBoundNarrows] | |
| from typing import TypeVar, Sequence | |
| T = TypeVar("T", bound=Sequence[int | str]) | |
| def accept_seq_int(x: Sequence[int]): ... | |
| def f(x: T) -> None: | |
| match x: | |
| case [1, 2]: | |
| accept_seq_int(x) | |
| case _: | |
| accept_seq_int(x) # E: Argument 1 to "accept_seq_int" has incompatible type "T"; expected "Sequence[int]" | |
| [builtins fixtures/tuple.pyi] | |
| [case testNarrowingTypeVarMatch] | |
| # flags: --warn-unreachable | |
| # https://github.com/python/mypy/issues/18126 | |
| from typing import TypeVar | |
| T = TypeVar("T") | |
| def fn_case(arg: T) -> None: | |
| match arg: | |
| case None: | |
| return None | |
| return None | |
| [builtins fixtures/primitives.pyi] | |
| [case testNoneCheckDoesNotMakeTypeVarOptionalMatch] | |
| from typing import TypeVar | |
| T = TypeVar('T') | |
| def foo(x: T) -> T: | |
| out = None | |
| out = x | |
| match out: | |
| case None: | |
| pass | |
| return out | |
| [builtins fixtures/isinstance.pyi] | |
| [case testMatchSequenceReachableFromAny] | |
| # flags: --warn-unreachable | |
| from typing import Any | |
| def maybe_list(d: Any) -> int: | |
| match d: | |
| case []: | |
| return 0 | |
| case [[_]]: | |
| return 1 | |
| case [_]: | |
| return 1 | |
| case _: | |
| return 2 | |
| def with_guard(d: Any) -> None: | |
| match d: | |
| case [s] if isinstance(s, str): | |
| reveal_type(s) # N: Revealed type is "builtins.str" | |
| match d: | |
| case (s,) if isinstance(s, str): | |
| reveal_type(s) # N: Revealed type is "builtins.str" | |
| def nested_in_dict(d: dict[str, Any]) -> int: | |
| match d: | |
| case {"src": ["src"]}: | |
| return 1 | |
| case _: | |
| return 0 | |
| [builtins fixtures/dict.pyi] | |
| [case testMatchRebindsOuterFunctionName] | |
| # flags: --warn-unreachable | |
| from typing import Literal | |
| def x() -> tuple[Literal["test"]]: ... | |
| match x(): | |
| case (x,) if x == "test": # E: Incompatible types in capture pattern (pattern captures type "Literal['test']", variable has type "Callable[[], Tuple[Literal['test']]]") | |
| reveal_type(x) # N: Revealed type is "def () -> Tuple[Literal['test']]" | |
| case foo: | |
| foo | |
| [builtins fixtures/dict.pyi] | |
| [case testMatchRebindsInnerFunctionName] | |
| # flags: --warn-unreachable | |
| class Some: | |
| value: int | str | |
| __match_args__ = ("value",) | |
| def fn1(x: Some | int | str) -> None: | |
| match x: | |
| case int(): | |
| def value(): | |
| return 1 | |
| reveal_type(value) # N: Revealed type is "def () -> Any" | |
| case str(): | |
| def value(): | |
| return 1 | |
| reveal_type(value) # N: Revealed type is "def () -> Any" | |
| case Some(value): # E: Incompatible types in capture pattern (pattern captures type "Union[int, str]", variable has type "Callable[[], Any]") | |
| pass | |
| def fn2(x: Some | int | str) -> None: | |
| match x: | |
| case int(): | |
| def value() -> str: | |
| return "" | |
| reveal_type(value) # N: Revealed type is "def () -> builtins.str" | |
| case str(): | |
| def value() -> int: # E: All conditional function variants must have identical signatures \ | |
| # N: Original: \ | |
| # N: def value() -> str \ | |
| # N: Redefinition: \ | |
| # N: def value() -> int | |
| return 1 | |
| reveal_type(value) # N: Revealed type is "def () -> builtins.str" | |
| case Some(value): # E: Incompatible types in capture pattern (pattern captures type "Union[int, str]", variable has type "Callable[[], str]") | |
| pass | |
| [builtins fixtures/dict.pyi] | |
| [case testMatchNamedTupleSequence] | |
| from typing import Any, NamedTuple | |
| class T(NamedTuple): | |
| t: list[Any] | |
| class K(NamedTuple): | |
| k: int | |
| def f(t: T) -> None: | |
| match t: | |
| case T([K() as k]): | |
| reveal_type(k) # N: Revealed type is "Tuple[builtins.int, fallback=__main__.K]" | |
| [builtins fixtures/tuple.pyi] | |
| [case testNewRedefineMatchBasics] | |
| # flags: --allow-redefinition-new --local-partial-types | |
| def f1(x: int | str | list[bytes]) -> None: | |
| match x: | |
| case int(): | |
| reveal_type(x) # N: Revealed type is "builtins.int" | |
| case str(y): | |
| reveal_type(y) # N: Revealed type is "builtins.str" | |
| case [y]: | |
| reveal_type(y) # N: Revealed type is "builtins.bytes" | |
| reveal_type(y) # N: Revealed type is "Union[builtins.str, builtins.bytes]" | |
| [case testNewRedefineLoopWithMatch] | |
| # flags: --allow-redefinition-new --local-partial-types | |
| def f1() -> None: | |
| while True: | |
| x = object() | |
| match x: | |
| case str(y): | |
| pass | |
| case int(): | |
| pass | |
| if int(): | |
| continue | |
| def f2() -> None: | |
| for x in [""]: | |
| match str(): | |
| case "a": | |
| y = "" | |
| case "b": | |
| y = 1 | |
| return | |
| reveal_type(y) # N: Revealed type is "builtins.str" | |
| [builtins fixtures/list.pyi] | |
| [case testEnumTypeObjectMember] | |
| import enum | |
| from typing import NoReturn | |
| def assert_never(x: NoReturn) -> None: ... | |
| class ValueType(enum.Enum): | |
| INT = int | |
| STR = str | |
| value_type: ValueType = ValueType.INT | |
| match value_type: | |
| case ValueType.INT: | |
| pass | |
| case ValueType.STR: | |
| pass | |
| case _: | |
| assert_never(value_type) | |
| [builtins fixtures/tuple.pyi] |