| -- Capture Pattern -- | |
| [case testMatchCapturePatternType] | |
| # flags: --strict-equality --warn-unreachable | |
| class A: ... | |
| m: A | |
| match m: | |
| case a: | |
| reveal_type(a) # N: Revealed type is "__main__.A" | |
| -- Literal Pattern -- | |
| [case testMatchLiteralPatternNarrows] | |
| # flags: --strict-equality --warn-unreachable | |
| m: object | |
| match m: | |
| case 1: | |
| reveal_type(m) # N: Revealed type is "Literal[1]" | |
| case 2: | |
| reveal_type(m) # N: Revealed type is "Literal[2]" | |
| case other: | |
| reveal_type(other) # N: Revealed type is "builtins.object" | |
| [case testMatchLiteralPatternNarrows2] | |
| # flags: --strict-equality --warn-unreachable | |
| from typing import Any | |
| m: Any | |
| match m: | |
| case 1: | |
| reveal_type(m) # N: Revealed type is "Any" | |
| case 2: | |
| reveal_type(m) # N: Revealed type is "Any" | |
| case other: | |
| reveal_type(other) # N: Revealed type is "Any" | |
| [case testMatchLiteralPatternBoolIntAlreadyNarrower] | |
| # flags: --strict-equality --warn-unreachable | |
| def foo(m: bool, x: int): | |
| match m: | |
| case 1: | |
| reveal_type(m) # N: Revealed type is "builtins.bool" | |
| match m: | |
| case x: | |
| reveal_type(m) # N: Revealed type is "builtins.bool" | |
| [builtins fixtures/primitives.pyi] | |
| [case testMatchLiteralPatternUnreachable] | |
| # flags: --strict-equality --warn-unreachable | |
| m: int | |
| match m: | |
| case "str": | |
| reveal_type(m) # E: Statement is unreachable | |
| [builtins fixtures/primitives.pyi] | |
| -- Value Pattern -- | |
| [case testMatchValuePatternNarrows] | |
| # flags: --strict-equality --warn-unreachable | |
| 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] | |
| # flags: --strict-equality --warn-unreachable | |
| 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] | |
| # flags: --strict-equality --warn-unreachable | |
| import b | |
| class A: ... | |
| def f(m: A) -> None: | |
| match m: | |
| case b.b: | |
| reveal_type(m) # E: Statement is unreachable | |
| [file b.py] | |
| class B: ... | |
| b: B | |
| [case testMatchValuePatternUnreachable] | |
| # flags: --strict-equality --warn-unreachable | |
| import b | |
| def f(m: int) -> None: | |
| match m: | |
| case b.b: | |
| reveal_type(m) # E: Statement is unreachable | |
| [file b.py] | |
| b: str | |
| [builtins fixtures/primitives.pyi] | |
| -- Sequence Pattern -- | |
| [case testMatchSequencePatternCaptures] | |
| # flags: --strict-equality --warn-unreachable | |
| 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] | |
| # flags: --strict-equality --warn-unreachable | |
| 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] | |
| # flags: --strict-equality --warn-unreachable | |
| 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] | |
| # flags: --strict-equality --warn-unreachable | |
| from typing import Sequence | |
| m: object | |
| match m: | |
| case [1, True]: | |
| reveal_type(m) # N: Revealed type is "typing.Sequence[builtins.int]" | |
| [case testMatchSequencePatternAlreadyNarrowerInner] | |
| # flags: --strict-equality --warn-unreachable | |
| 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] | |
| # flags: --strict-equality --warn-unreachable | |
| 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] | |
| # flags: --strict-equality --warn-unreachable | |
| 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] | |
| # flags: --strict-equality --warn-unreachable | |
| 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] | |
| # flags: --strict-equality --warn-unreachable | |
| 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] | |
| # flags: --strict-equality --warn-unreachable | |
| 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] | |
| # flags: --strict-equality --warn-unreachable | |
| 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) # E: Statement is unreachable | |
| match m10: | |
| case [j]: | |
| reveal_type(j) # E: Statement is unreachable | |
| match m11: | |
| case [k]: | |
| reveal_type(k) # E: Statement is unreachable | |
| [builtins fixtures/primitives.pyi] | |
| [typing fixtures/typing-full.pyi] | |
| [case testMatchSequencePatternCapturesTuple] | |
| # flags: --strict-equality --warn-unreachable | |
| 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] | |
| # flags: --strict-equality --warn-unreachable | |
| from typing import Tuple | |
| m: Tuple[int, str] | |
| match m: | |
| case [a, b, c]: | |
| reveal_type(a) # E: Statement is unreachable | |
| reveal_type(b) | |
| reveal_type(c) | |
| [builtins fixtures/list.pyi] | |
| [case testMatchSequencePatternTupleTooShort] | |
| # flags: --strict-equality --warn-unreachable | |
| from typing import Tuple | |
| m: Tuple[int, str, bool] | |
| match m: | |
| case [a, b]: | |
| reveal_type(a) # E: Statement is unreachable | |
| reveal_type(b) | |
| [builtins fixtures/list.pyi] | |
| [case testMatchSequencePatternTupleNarrows] | |
| # flags: --strict-equality --warn-unreachable | |
| 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] | |
| # flags: --strict-equality --warn-unreachable | |
| 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] | |
| # flags: --strict-equality --warn-unreachable | |
| 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[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] | |
| # flags: --strict-equality --warn-unreachable | |
| 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) # E: Statement is unreachable | |
| reveal_type(b) | |
| reveal_type(c) | |
| [builtins fixtures/list.pyi] | |
| [case testMatchNonMatchingSequencePattern] | |
| # flags: --strict-equality --warn-unreachable | |
| from typing import List | |
| x: List[int] | |
| match x: | |
| case [str()]: | |
| pass | |
| [case testMatchSequencePatternWithTypeObject] | |
| # flags: --strict-equality --warn-unreachable | |
| 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]: | |
| reveal_type(value) # N: Revealed type is "builtins.str" | |
| 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] | |
| # flags: --strict-equality --warn-unreachable | |
| 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] | |
| # flags: --strict-equality --warn-unreachable | |
| 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] | |
| # flags: --strict-equality --warn-unreachable | |
| 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] | |
| # flags: --strict-equality --warn-unreachable | |
| 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] | |
| # flags: --strict-equality --warn-unreachable | |
| 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] | |
| # flags: --strict-equality --warn-unreachable | |
| m: int | |
| n: str | |
| o: bool | |
| match m, n, o: | |
| case [3, "foo"]: | |
| pass # E: Statement is unreachable | |
| case [3, "foo", True, True]: | |
| pass # E: Statement is unreachable | |
| [builtins fixtures/tuple.pyi] | |
| [case testMatchSequencePatternSequencesLengthMismatchNoNarrowingRecursive] | |
| # flags: --strict-equality --warn-unreachable | |
| m: int | |
| n: int | |
| o: int | |
| match m, (n, o): | |
| case [0]: | |
| pass # E: Statement is unreachable | |
| case [0, 1, [2]]: | |
| pass # E: Statement is unreachable | |
| case [0, [1]]: | |
| pass # E: Statement is unreachable | |
| case [0, [1, 2, 3]]: | |
| pass # E: Statement is unreachable | |
| [builtins fixtures/tuple.pyi] | |
| [case testMatchUnpackedTupleSubjectExpressionNoCrash] | |
| # flags: --strict-equality --warn-unreachable | |
| # See: https://github.com/python/mypy/issues/21468 | |
| foo: int = 1 | |
| bar: tuple[int, int] = 1, 2 | |
| match foo, *bar: | |
| case x, y, z: | |
| reveal_type(x) # N: Revealed type is "builtins.int" | |
| reveal_type(y) # N: Revealed type is "builtins.int" | |
| reveal_type(z) # N: Revealed type is "builtins.int" | |
| [builtins fixtures/tuple.pyi] | |
| -- Mapping Pattern -- | |
| [case testMatchMappingPatternCaptures] | |
| # flags: --strict-equality --warn-unreachable | |
| 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] | |
| # flags: --strict-equality --warn-unreachable | |
| # 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] | |
| # flags: --strict-equality --warn-unreachable | |
| 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] | |
| # flags: --strict-equality --warn-unreachable | |
| 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] | |
| # flags: --strict-equality --warn-unreachable | |
| 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] | |
| # flags: --strict-equality --warn-unreachable | |
| # 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) # E: Statement is unreachable | |
| case {b.b: v2}: | |
| reveal_type(v2) # E: Statement is unreachable | |
| [file b.py] | |
| b: int | |
| [typing fixtures/typing-typeddict.pyi] | |
| [case testMatchMappingPatternCaptureRest] | |
| # flags: --strict-equality --warn-unreachable | |
| 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] | |
| # flags: --strict-equality --warn-unreachable | |
| 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] | |
| [case testMatchMappingPatternNarrowing] | |
| # flags: --strict-equality --warn-unreachable | |
| from typing import Mapping, Sequence | |
| def f1(x: dict[str, str] | list[str] | str) -> None: | |
| match x: | |
| case {}: | |
| reveal_type(x) # N: Revealed type is "builtins.dict[builtins.str, builtins.str]" | |
| case [*_]: | |
| reveal_type(x) # N: Revealed type is "builtins.list[builtins.str]" | |
| case _: | |
| reveal_type(x) # N: Revealed type is "builtins.str" | |
| def f1_rest(x: dict[str, str] | list[str] | str) -> None: | |
| match x: | |
| case {**rest}: | |
| reveal_type(x) # N: Revealed type is "builtins.dict[builtins.str, builtins.str]" | |
| case [*_]: | |
| reveal_type(x) # N: Revealed type is "builtins.list[builtins.str]" | |
| case _: | |
| reveal_type(x) # N: Revealed type is "builtins.str" | |
| def f2(x: Mapping[str, str] | Sequence[str] | str) -> None: | |
| match x: | |
| case {}: | |
| reveal_type(x) # N: Revealed type is "typing.Mapping[builtins.str, builtins.str]" | |
| case [*_]: | |
| reveal_type(x) # N: Revealed type is "typing.Sequence[builtins.str]" | |
| case _: | |
| # TODO: this should be str | |
| reveal_type(x) # E: Statement is unreachable | |
| def f2_rest(x: Mapping[str, str] | Sequence[str] | str) -> None: | |
| match x: | |
| case {**rest}: | |
| reveal_type(x) # N: Revealed type is "typing.Mapping[builtins.str, builtins.str]" | |
| case [*_]: | |
| reveal_type(x) # N: Revealed type is "typing.Sequence[builtins.str]" | |
| case _: | |
| # TODO: this should be str | |
| reveal_type(x) # E: Statement is unreachable | |
| [builtins fixtures/primitives.pyi] | |
| [case testMatchMappingPatternNarrowingAny] | |
| # flags: --strict-equality --warn-unreachable | |
| from typing import Any | |
| def f1(x: Any) -> None: | |
| match x: | |
| case {}: | |
| reveal_type(x) # N: Revealed type is "Any" | |
| def f2(x: Any) -> None: | |
| match x: | |
| case {"x": "y"}: | |
| reveal_type(x) # N: Revealed type is "Any" | |
| [builtins fixtures/dict.pyi] | |
| -- Class Pattern -- | |
| [case testMatchClassPatternCapturePositional] | |
| # flags: --strict-equality --warn-unreachable | |
| 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] | |
| # flags: --strict-equality --warn-unreachable | |
| 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] | |
| # flags: --strict-equality --warn-unreachable | |
| 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] | |
| # flags: --strict-equality --warn-unreachable | |
| 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] | |
| # flags: --strict-equality --warn-unreachable | |
| 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] | |
| # flags: --strict-equality --warn-unreachable | |
| 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] | |
| # flags: --strict-equality --warn-unreachable | |
| m: object | |
| match m: | |
| case xyz(y): # E: Name "xyz" is not defined | |
| reveal_type(m) # N: Revealed type is "Any" | |
| reveal_type(y) # N: Revealed type is "Any" | |
| match m: | |
| case xyz(z=x): # E: Name "xyz" is not defined | |
| reveal_type(x) # N: Revealed type is "Any" | |
| case (xyz1() as n) | (xyz2(attr=n)): # E: Name "xyz1" is not defined \ | |
| # E: Name "xyz2" is not defined | |
| reveal_type(n) # N: Revealed type is "Any" | |
| [case testMatchClassPatternCaptureDataclass] | |
| # flags: --strict-equality --warn-unreachable | |
| 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] | |
| # flags: --strict-equality --warn-unreachable | |
| 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 # E: Statement is unreachable | |
| [builtins fixtures/dataclasses.pyi] | |
| [case testMatchClassPatternCaptureDataclassPartialMatchArgs] | |
| # flags: --strict-equality --warn-unreachable | |
| 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 # E: Statement is unreachable | |
| case A(k): | |
| reveal_type(k) # N: Revealed type is "builtins.str" | |
| [builtins fixtures/dataclasses.pyi] | |
| [case testMatchClassPatternCaptureNamedTupleInline] | |
| # flags: --strict-equality --warn-unreachable | |
| 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] | |
| # flags: --strict-equality --warn-unreachable | |
| 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] | |
| # flags: --strict-equality --warn-unreachable | |
| 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] | |
| # flags: --strict-equality --warn-unreachable | |
| 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] | |
| # flags: --strict-equality --warn-unreachable | |
| 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] | |
| # flags: --strict-equality --warn-unreachable | |
| 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] | |
| # flags: --strict-equality --warn-unreachable | |
| 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] | |
| # flags: --strict-equality --warn-unreachable | |
| 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) # E: Statement is unreachable | |
| [case testMatchClassPatternCaptureGenericTypeAlias] | |
| # flags: --strict-equality --warn-unreachable | |
| 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] | |
| # flags: --strict-equality --warn-unreachable | |
| 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] | |
| # flags: --strict-equality --warn-unreachable | |
| 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] | |
| # flags: --strict-equality --warn-unreachable | |
| 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] | |
| # flags: --strict-equality --warn-unreachable | |
| 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] | |
| # flags: --strict-equality --warn-unreachable | |
| from typing import Any | |
| class A: ... | |
| m: object | |
| n: Any | |
| 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" | |
| match n: | |
| # Matching against object should not emit an error for non-existing keys | |
| case object(a=k): | |
| reveal_type(n) # N: Revealed type is "builtins.object" | |
| reveal_type(n.a) # N: Revealed type is "Any" | |
| reveal_type(k) # N: Revealed type is "Any" | |
| [case testMatchClassPatternDuplicateKeyword] | |
| # flags: --strict-equality --warn-unreachable | |
| class A: | |
| a: str | |
| m: object | |
| match m: | |
| case A(a=i, a=j): # E: Duplicate keyword pattern "a" | |
| pass # E: Statement is unreachable | |
| [case testMatchClassPatternDuplicateImplicitKeyword] | |
| # flags: --strict-equality --warn-unreachable | |
| 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 # E: Statement is unreachable | |
| [builtins fixtures/tuple.pyi] | |
| [case testMatchClassPatternTooManyPositionals] | |
| # flags: --strict-equality --warn-unreachable | |
| 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 # E: Statement is unreachable | |
| [builtins fixtures/tuple.pyi] | |
| [case testMatchClassPatternIsNotType] | |
| # flags: --strict-equality --warn-unreachable | |
| from typing import Any | |
| def match_int(m: object, a: int): | |
| match m: | |
| case a(i, j): # E: Expected type in class pattern; found "builtins.int" | |
| reveal_type(i) # E: Statement is unreachable | |
| reveal_type(j) | |
| def match_int_str(m: object, a: int | str): | |
| match m: | |
| case a(i, j): # E: Expected type in class pattern; found "builtins.int" \ | |
| # E: Expected type in class pattern; found "builtins.str" | |
| reveal_type(i) # E: Statement is unreachable | |
| reveal_type(j) | |
| def match_int_any(m: object, a: int | Any): | |
| match m: | |
| case a(i, j): # E: Expected type in class pattern; found "builtins.int" | |
| reveal_type(i) # N: Revealed type is "Any" | |
| reveal_type(j) # N: Revealed type is "Any" | |
| [case testMatchClassPatternAny] | |
| # flags: --strict-equality --warn-unreachable | |
| from typing import Any | |
| Foo: Any | |
| m: object | |
| match m: | |
| case Foo(): | |
| pass | |
| [case testMatchClassPatternCallable] | |
| # flags: --strict-equality --warn-unreachable | |
| from typing import Callable, Any | |
| class FnImpl: | |
| def __call__(self, x: object, /) -> int: ... | |
| def test_any(x: Any) -> None: | |
| match x: | |
| case Callable() as fn: | |
| reveal_type(fn) # N: Revealed type is "def (*Any, **Any) -> Any" | |
| case other: | |
| reveal_type(other) # N: Revealed type is "Any" | |
| def test_object(x: object) -> None: | |
| match x: | |
| case Callable() as fn: | |
| reveal_type(fn) # N: Revealed type is "def (*Any, **Any) -> Any" | |
| case other: | |
| reveal_type(other) # N: Revealed type is "builtins.object" | |
| def test_impl(x: FnImpl) -> None: | |
| match x: | |
| case Callable() as fn: | |
| reveal_type(fn) # N: Revealed type is "__main__.FnImpl" | |
| case other: | |
| reveal_type(other) # E: Statement is unreachable | |
| def test_callable(x: Callable[[object], int]) -> None: | |
| match x: | |
| case Callable() as fn: | |
| reveal_type(fn) # N: Revealed type is "def (builtins.object) -> builtins.int" | |
| case other: | |
| reveal_type(other) # E: Statement is unreachable | |
| [case testMatchClassPatternCallbackProtocol] | |
| # flags: --strict-equality --warn-unreachable | |
| from typing import Any, Callable | |
| from typing_extensions import Protocol, runtime_checkable | |
| @runtime_checkable | |
| class FnProto(Protocol): | |
| def __call__(self, x: int, /) -> object: ... | |
| class FnImpl: | |
| def __call__(self, x: object, /) -> int: ... | |
| def test_any(x: Any) -> None: | |
| match x: | |
| case FnProto() as fn: | |
| reveal_type(fn) # N: Revealed type is "__main__.FnProto" | |
| case other: | |
| reveal_type(other) # N: Revealed type is "Any" | |
| def test_object(x: object) -> None: | |
| match x: | |
| case FnProto() as fn: | |
| reveal_type(fn) # N: Revealed type is "__main__.FnProto" | |
| case other: | |
| reveal_type(other) # N: Revealed type is "builtins.object" | |
| def test_impl(x: FnImpl) -> None: | |
| match x: | |
| case FnProto() as fn: | |
| reveal_type(fn) # N: Revealed type is "__main__.FnImpl" | |
| case other: | |
| reveal_type(other) # E: Statement is unreachable | |
| def test_callable(x: Callable[[object], int]) -> None: | |
| match x: | |
| case FnProto() as fn: | |
| reveal_type(fn) # N: Revealed type is "def (builtins.object) -> builtins.int" | |
| case other: | |
| reveal_type(other) # E: Statement is unreachable | |
| [builtins fixtures/dict.pyi] | |
| [case testMatchClassPatternAnyCallableProtocol] | |
| # flags: --strict-equality --warn-unreachable | |
| from typing import Any, Callable | |
| from typing_extensions import Protocol, runtime_checkable | |
| @runtime_checkable | |
| class AnyCallable(Protocol): | |
| def __call__(self, *args: Any, **kwargs: Any) -> Any: ... | |
| class FnImpl: | |
| def __call__(self, x: object, /) -> int: ... | |
| def test_object(x: object) -> None: | |
| match x: | |
| case AnyCallable() as fn: | |
| reveal_type(fn) # N: Revealed type is "__main__.AnyCallable" | |
| case other: | |
| reveal_type(other) # N: Revealed type is "builtins.object" | |
| def test_impl(x: FnImpl) -> None: | |
| match x: | |
| case AnyCallable() as fn: | |
| reveal_type(fn) # N: Revealed type is "__main__.FnImpl" | |
| case other: | |
| reveal_type(other) # E: Statement is unreachable | |
| def test_callable(x: Callable[[object], int]) -> None: | |
| match x: | |
| case AnyCallable() as fn: | |
| reveal_type(fn) # N: Revealed type is "def (builtins.object) -> builtins.int" | |
| case other: | |
| reveal_type(other) # E: Statement is unreachable | |
| [builtins fixtures/dict.pyi] | |
| [case testMatchClassPatternProtocol] | |
| # flags: --strict-equality --warn-unreachable | |
| from typing import Any | |
| from typing_extensions import Protocol, runtime_checkable | |
| @runtime_checkable | |
| class Proto(Protocol): | |
| def foo(self, x: int, /) -> object: ... | |
| class Impl: | |
| def foo(self, x: object, /) -> int: ... | |
| def test_object(x: object) -> None: | |
| match x: | |
| case Proto() as y: | |
| reveal_type(y) # N: Revealed type is "__main__.Proto" | |
| def test_impl(x: Impl) -> None: | |
| match x: | |
| case Proto() as y: | |
| reveal_type(y) # N: Revealed type is "__main__.Impl" | |
| [builtins fixtures/dict.pyi] | |
| [case testMatchClassPatternNestedGenerics] | |
| # flags: --strict-equality --warn-unreachable | |
| # 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 testMatchClassPatternTypeObject] | |
| # flags: --strict-equality --warn-unreachable | |
| class Example: | |
| __match_args__ = ("value",) | |
| def __init__(self, value: str) -> None: | |
| self.value = value | |
| def f1(subclass: type[Example]) -> None: | |
| match subclass("a"): | |
| case Example(value): | |
| reveal_type(value) # N: Revealed type is "builtins.str" | |
| case anything: | |
| reveal_type(anything) # E: Statement is unreachable | |
| def f2(subclass: type[Example]) -> None: | |
| match Example("a"): | |
| case subclass(value): | |
| reveal_type(value) # N: Revealed type is "builtins.str" | |
| case anything: | |
| reveal_type(anything) # N: Revealed type is "__main__.Example" | |
| def f3(subclass: type[Example]) -> None: | |
| match subclass("a"): | |
| case subclass(value): | |
| reveal_type(value) # N: Revealed type is "builtins.str" | |
| case anything: | |
| reveal_type(anything) # N: Revealed type is "__main__.Example" | |
| class Example2: | |
| __match_args__ = ("value",) | |
| def __init__(self, value: str) -> None: | |
| self.value = value | |
| def f4(T: type[Example | Example2]) -> None: | |
| match T("a"): | |
| case Example(value): | |
| reveal_type(value) # N: Revealed type is "builtins.str" | |
| case anything: | |
| reveal_type(anything) # N: Revealed type is "__main__.Example2" | |
| def f5(T: type[Example | Example2]) -> None: | |
| match Example("a"): | |
| case T(value): | |
| reveal_type(value) # N: Revealed type is "builtins.str" | |
| case anything: | |
| reveal_type(anything) # N: Revealed type is "__main__.Example" | |
| def f6(T: type[Example | Example2]) -> None: | |
| match T("a"): | |
| case T(value): | |
| reveal_type(value) # N: Revealed type is "builtins.str" | |
| case anything: | |
| reveal_type(anything) # N: Revealed type is "__main__.Example | __main__.Example2" | |
| def f7(m: object, t: type[object]) -> None: | |
| match m: | |
| case t(): | |
| reveal_type(m) # N: Revealed type is "builtins.object" | |
| case _: | |
| reveal_type(m) # N: Revealed type is "builtins.object" | |
| [builtins fixtures/tuple.pyi] | |
| [case testMatchClassPatternTypeObjectGeneric] | |
| # flags: --strict-equality --warn-unreachable | |
| from typing import TypeVar | |
| T = TypeVar("T") | |
| def print_test(m: object, typ: type[T]) -> T: | |
| match m: | |
| case typ(): | |
| reveal_type(m) # N: Revealed type is "T`-1" | |
| return m | |
| case str(): | |
| reveal_type(m) # N: Revealed type is "builtins.str" | |
| case _: | |
| reveal_type(m) # N: Revealed type is "builtins.object" | |
| raise | |
| [case testMatchClassPatternTupleAlias] | |
| # flags: --strict-equality --warn-unreachable | |
| from typing import Tuple | |
| tuple_alias = tuple | |
| Tuple_alias = Tuple | |
| def main(m: object): | |
| match m: | |
| case tuple(): | |
| reveal_type(m) # N: Revealed type is "builtins.tuple[Any, ...]" | |
| case _: | |
| reveal_type(m) # N: Revealed type is "builtins.object" | |
| match m: | |
| case tuple_alias(): | |
| reveal_type(m) # N: Revealed type is "builtins.tuple[Any, ...]" | |
| case _: | |
| reveal_type(m) # N: Revealed type is "builtins.object" | |
| match m: | |
| # With real typeshed you'll get an error like this instead: | |
| # Expected type in class pattern; found "typing._SpecialForm" | |
| case Tuple(): # E: Expected type in class pattern; found "builtins.int" | |
| reveal_type(m) # E: Statement is unreachable | |
| case _: | |
| reveal_type(m) # N: Revealed type is "builtins.object" | |
| match m: | |
| # This is a false negative, it will raise at runtime | |
| case Tuple_alias(): | |
| reveal_type(m) # N: Revealed type is "builtins.tuple[Any, ...]" | |
| case _: | |
| reveal_type(m) # N: Revealed type is "builtins.object" | |
| [builtins fixtures/tuple.pyi] | |
| [case testMatchNonFinalMatchArgs] | |
| # flags: --strict-equality --warn-unreachable | |
| 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] | |
| # flags: --strict-equality --warn-unreachable | |
| 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] | |
| # flags: --strict-equality --warn-unreachable | |
| 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 # E: Statement is unreachable | |
| 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] | |
| # flags: --strict-equality --warn-unreachable | |
| 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] | |
| # flags: --strict-equality --warn-unreachable | |
| 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] | |
| # flags: --strict-equality --warn-unreachable | |
| m: object | |
| match m: | |
| case int() as l: | |
| reveal_type(l) # N: Revealed type is "builtins.int" | |
| [case testMatchAsPatternCapturesOr] | |
| # flags: --strict-equality --warn-unreachable | |
| m: object | |
| match m: | |
| case 1 | 2 as n: | |
| reveal_type(n) # N: Revealed type is "Literal[1] | Literal[2]" | |
| [case testMatchAsPatternAlreadyNarrower] | |
| # flags: --strict-equality --warn-unreachable | |
| m: bool | |
| match m: | |
| case int() as l: | |
| reveal_type(l) # N: Revealed type is "builtins.bool" | |
| -- Or Pattern -- | |
| [case testMatchOrPatternNarrows] | |
| # flags: --strict-equality --warn-unreachable | |
| m: object | |
| match m: | |
| case 1 | 2: | |
| reveal_type(m) # N: Revealed type is "Literal[1] | Literal[2]" | |
| [case testMatchOrPatternNarrowsStr] | |
| # flags: --strict-equality --warn-unreachable | |
| m: object | |
| match m: | |
| case "foo" | "bar": | |
| reveal_type(m) # N: Revealed type is "Literal['foo'] | Literal['bar']" | |
| [case testMatchOrPatternNarrowsUnion] | |
| # flags: --strict-equality --warn-unreachable | |
| m: object | |
| match m: | |
| case 1 | "foo": | |
| reveal_type(m) # N: Revealed type is "Literal[1] | Literal['foo']" | |
| [case testMatchOrPatternCapturesMissing] | |
| # flags: --strict-equality --warn-unreachable | |
| 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.int | builtins.list[builtins.int]" | |
| reveal_type(y) # N: Revealed type is "builtins.int" | |
| [builtins fixtures/list.pyi] | |
| [case testMatchOrPatternCapturesJoin] | |
| # flags: --strict-equality --warn-unreachable | |
| m: object | |
| match m: | |
| case list(x) | dict(x): | |
| reveal_type(x) # N: Revealed type is "builtins.list[Any] | builtins.dict[Any, Any]" | |
| [builtins fixtures/dict.pyi] | |
| -- Interactions -- | |
| [case testMatchCapturePatternMultipleCases] | |
| # flags: --strict-equality --warn-unreachable | |
| 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 "builtins.int | builtins.str" | |
| [case testMatchCapturePatternMultipleCaptures] | |
| # flags: --strict-equality --warn-unreachable | |
| 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] | |
| # flags: --strict-equality --warn-unreachable | |
| a: int | |
| m: int | |
| match m: | |
| case a: | |
| reveal_type(a) # N: Revealed type is "builtins.int" | |
| [case testMatchCapturePatternPreexistingNarrows] | |
| # flags: --strict-equality --warn-unreachable | |
| 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 testMatchCapturePatternAfterPreviousCase] | |
| # flags: --strict-equality --warn-unreachable | |
| def f1(x: int | None, y: int): | |
| match x: | |
| case None: | |
| pass | |
| case y: | |
| reveal_type(y) # N: Revealed type is "builtins.int" | |
| def f2(x: int | None, y: int, cond: bool): | |
| match x: | |
| case None if cond: | |
| pass | |
| case y: # E: Incompatible types in capture pattern (pattern captures type "int | None", variable has type "int") | |
| reveal_type(y) # N: Revealed type is "builtins.int" | |
| def f3(x: int | None, y: int): | |
| match x: | |
| case None if True: | |
| pass | |
| case y: | |
| reveal_type(y) # N: Revealed type is "builtins.int" | |
| match x: | |
| case None if False: | |
| pass # E: Statement is unreachable | |
| case y: # E: Incompatible types in capture pattern (pattern captures type "int | None", variable has type "int") | |
| reveal_type(y) # N: Revealed type is "builtins.int" | |
| [case testMatchCapturePatternPreexistingIncompatible] | |
| # flags: --strict-equality --warn-unreachable | |
| 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] | |
| # flags: --strict-equality --warn-unreachable | |
| 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] | |
| # flags: --strict-equality --warn-unreachable | |
| 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 "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] | |
| # flags: --strict-equality --warn-unreachable | |
| 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 "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] | |
| # flags: --strict-equality --warn-unreachable | |
| m: str | |
| def guard() -> bool: ... | |
| match m: | |
| case a if guard(): | |
| reveal_type(a) # N: Revealed type is "builtins.str" | |
| [case testMatchAlwaysTruePatternGuard] | |
| # flags: --strict-equality --warn-unreachable | |
| m: str | |
| match m: | |
| case a if True: | |
| reveal_type(a) # N: Revealed type is "builtins.str" | |
| [case testMatchAlwaysFalsePatternGuard] | |
| # flags: --strict-equality --warn-unreachable | |
| m: str | |
| match m: | |
| case a if False: | |
| reveal_type(a) # E: Statement is unreachable | |
| [case testMatchRedefiningPatternGuard] | |
| # flags: --strict-equality --warn-unreachable | |
| 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] | |
| # flags: --strict-equality --warn-unreachable | |
| m: str | |
| match m: | |
| case a if a := "test": | |
| reveal_type(a) # N: Revealed type is "builtins.str" | |
| [case testMatchNarrowingPatternGuard] | |
| # flags: --strict-equality --warn-unreachable | |
| 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] | |
| # flags: --strict-equality --warn-unreachable | |
| 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] | |
| # flags: --strict-equality --warn-unreachable | |
| m: str | |
| match m: | |
| case a if isinstance(a, int): # E: Subclass of "str" and "int" cannot exist: would have incompatible method signatures | |
| reveal_type(a) # E: Statement is unreachable | |
| [builtins fixtures/isinstancelist.pyi] | |
| [case testMatchSubjectAssignExprWithGuard] | |
| # flags: --strict-equality --warn-unreachable | |
| from typing import Optional | |
| def func() -> Optional[str]: ... | |
| match m := func(): | |
| case _ if not m: | |
| reveal_type(m) # N: Revealed type is "Literal[''] | None" | |
| case _: | |
| reveal_type(m) # N: Revealed type is "builtins.str" | |
| -- Exhaustiveness -- | |
| [case testMatchUnionNegativeNarrowing] | |
| # flags: --strict-equality --warn-unreachable | |
| 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] | |
| # flags: --strict-equality --warn-unreachable | |
| from typing import Union | |
| m: Union[str, bytes, int] | |
| match m: | |
| case str(a) | bytes(a): | |
| reveal_type(a) # N: Revealed type is "builtins.str | builtins.bytes" | |
| reveal_type(m) # N: Revealed type is "builtins.str | builtins.bytes" | |
| case b: | |
| reveal_type(b) # N: Revealed type is "builtins.int" | |
| [case testMatchClassPatternLiteralNegativeNarrowing] | |
| # flags: --strict-equality --warn-unreachable | |
| # See: https://github.com/python/mypy/issues/21780 | |
| from typing import reveal_type, NoReturn | |
| def assert_never(x: NoReturn) -> None: ... | |
| def f(x: int | tuple[int, int] | None) -> float | None: | |
| match x: | |
| case None: | |
| reveal_type(x) # N: Revealed type is "None" | |
| return None | |
| case int(0): | |
| reveal_type(x) # N: Revealed type is "Literal[0]" | |
| return 0.0 | |
| case int(bits): | |
| reveal_type(x) # N: Revealed type is "builtins.int" | |
| return bits / 8.0 | |
| case int(bits), int(seconds): | |
| reveal_type(x) # N: Revealed type is "tuple[builtins.int, builtins.int]" | |
| return bits / 8.0 / seconds | |
| case _: | |
| assert_never(x) # E: Statement is unreachable | |
| [builtins fixtures/ops.pyi] | |
| [case testMatchExhaustiveReturn] | |
| # flags: --strict-equality --warn-unreachable | |
| def foo(value) -> int: | |
| match value: | |
| case "bar": | |
| return 1 | |
| case _: | |
| return 2 | |
| [case testMatchNonExhaustiveReturn] | |
| # flags: --strict-equality --warn-unreachable | |
| def foo(value) -> int: # E: Missing return statement | |
| match value: | |
| case "bar": | |
| return 1 | |
| case 2: | |
| return 2 | |
| [case testMatchMoreExhaustiveReturnCases] | |
| # flags: --strict-equality --warn-unreachable | |
| 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] | |
| # flags: --strict-equality --warn-unreachable | |
| 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] | |
| # flags: --strict-equality --warn-unreachable | |
| 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] | |
| # flags: --strict-equality --warn-unreachable | |
| 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) # E: Statement is unreachable | |
| [typing fixtures/typing-medium.pyi] | |
| [case testMatchSequencePatternNegativeNarrowing] | |
| # flags: --strict-equality --warn-unreachable | |
| 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[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[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], Literal['a'] | Literal['b']]" | |
| case _: | |
| reveal_type(m5) # N: Revealed type is "tuple[Literal[2], 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[Literal[1] | Literal[2], Literal['a'] | Literal['b']]" | |
| [builtins fixtures/tuple.pyi] | |
| [case testMatchSequenceWildcardRefutability] | |
| # flags: --strict-equality --warn-unreachable | |
| def f1(x: int | list[int]): | |
| match x: | |
| case [*foo]: | |
| reveal_type(x) # N: Revealed type is "builtins.list[builtins.int]" | |
| reveal_type(foo) # N: Revealed type is "builtins.list[builtins.int]" | |
| case _: | |
| reveal_type(x) # N: Revealed type is "builtins.int" | |
| def f2(x: object): | |
| match x: | |
| case [*foo]: | |
| reveal_type(x) # N: Revealed type is "typing.Sequence[builtins.object]" | |
| reveal_type(foo) # N: Revealed type is "builtins.list[builtins.object]" | |
| case _: | |
| reveal_type(x) # N: Revealed type is "builtins.object" | |
| def f3(x: int | list[int]): | |
| match x: | |
| case [1, *foo]: | |
| reveal_type(x) # N: Revealed type is "builtins.list[builtins.int]" | |
| reveal_type(foo) # N: Revealed type is "builtins.list[builtins.int]" | |
| case _: | |
| reveal_type(x) # N: Revealed type is "builtins.int | builtins.list[builtins.int]" | |
| [builtins fixtures/tuple.pyi] | |
| [case testMatchSequenceTupleAsPattern] | |
| # flags: --strict-equality --warn-unreachable | |
| def f1(x: tuple[list[int], list[int]]): | |
| match x: | |
| case _, []: | |
| reveal_type(x) # N: Revealed type is "tuple[builtins.list[builtins.int], builtins.list[builtins.int]]" | |
| case [], _: | |
| reveal_type(x) # N: Revealed type is "tuple[builtins.list[builtins.int], builtins.list[builtins.int]]" | |
| case _: | |
| reveal_type(x) # N: Revealed type is "tuple[builtins.list[builtins.int], builtins.list[builtins.int]]" | |
| def f2(x: tuple[list[int], list[int]]): | |
| match x: | |
| case a, b: | |
| reveal_type(x) # N: Revealed type is "tuple[builtins.list[builtins.int], builtins.list[builtins.int]]" | |
| case [], _: | |
| reveal_type(x) # E: Statement is unreachable | |
| [builtins fixtures/tuple.pyi] | |
| [case testMatchSequenceTupleRegression] | |
| # flags: --strict-equality --warn-unreachable | |
| def f1(a: str | None, b: str | None): | |
| # https://github.com/python/mypy/issues/14731 | |
| match (a, b): | |
| case (None, _) | (_, None): | |
| reveal_type(a) # N: Revealed type is "builtins.str | None" | |
| reveal_type(b) # N: Revealed type is "builtins.str | None" | |
| case (a, b): | |
| reveal_type(a) # N: Revealed type is "builtins.str" | |
| reveal_type(b) # N: Revealed type is "builtins.str" | |
| def f2(x: tuple[int | str]): | |
| # https://github.com/python/mypy/issues/14833#issuecomment-1454768900 | |
| match x: | |
| case (int(),): | |
| reveal_type(x) # N: Revealed type is "tuple[builtins.int]" | |
| case (str(),): | |
| reveal_type(x) # N: Revealed type is "tuple[builtins.str]" | |
| case _: | |
| reveal_type(x) # E: Statement is unreachable | |
| def f4(x: tuple[int | str, str]): | |
| # https://github.com/python/mypy/issues/18792 | |
| match x: | |
| case (int(), y): | |
| reveal_type(x) # N: Revealed type is "tuple[builtins.int, builtins.str]" | |
| case (str(), y): | |
| reveal_type(x) # N: Revealed type is "tuple[builtins.str, builtins.str]" | |
| case _: | |
| reveal_type(x) # E: Statement is unreachable | |
| class Add(tuple[int, int]): ... | |
| class Const(int): ... | |
| def f5(e: Add | Const) -> int: | |
| # https://github.com/python/mypy/issues/17139 | |
| reveal_type(e) # N: Revealed type is "tuple[builtins.int, builtins.int, fallback=__main__.Add] | __main__.Const" | |
| match e: | |
| case Add((a, b)): | |
| reveal_type(e) # N: Revealed type is "tuple[builtins.int, builtins.int, fallback=__main__.Add]" | |
| return a + b | |
| case Const(x): | |
| reveal_type(e) # N: Revealed type is "__main__.Const" | |
| return x | |
| reveal_type(e) # E: Statement is unreachable | |
| def f6(d1: list[str], d2: list[str]): | |
| # https://github.com/python/mypy/issues/19995 | |
| match (d1, d2): | |
| case ([sym], _) | (_, [sym]): | |
| reveal_type(sym) # N: Revealed type is "builtins.str" | |
| [builtins fixtures/dict.pyi] | |
| [case testMatchTupleUnions] | |
| # flags: --strict-equality --warn-unreachable | |
| from typing_extensions import Unpack | |
| m1: tuple[int, str] | None | |
| match m1: | |
| case (a1, b1): | |
| reveal_type(a1) # N: Revealed type is "builtins.int" | |
| reveal_type(b1) # N: Revealed type is "builtins.str" | |
| m2: tuple[int, str] | tuple[float, str] | |
| match m2: | |
| case (a2, b2): | |
| reveal_type(a2) # N: Revealed type is "builtins.int | builtins.float" | |
| reveal_type(b2) # N: Revealed type is "builtins.str" | |
| m3: tuple[int] | tuple[float, str] | |
| match m3: | |
| case (a3, b3): | |
| reveal_type(a3) # N: Revealed type is "builtins.float" | |
| reveal_type(b3) # N: Revealed type is "builtins.str" | |
| m4: tuple[int] | list[str] | |
| match m4: | |
| case (a4, b4): | |
| reveal_type(a4) # N: Revealed type is "builtins.str" | |
| reveal_type(b4) # N: Revealed type is "builtins.str" | |
| m5: tuple[int, Unpack[tuple[float, ...]]] | None | |
| match m5: | |
| case (a5, b5): | |
| reveal_type(a5) # N: Revealed type is "builtins.int" | |
| reveal_type(b5) # N: Revealed type is "builtins.float" | |
| m6: tuple[int, Unpack[tuple[float, ...]]] | list[str] | |
| match m6: | |
| case (a6, b6): | |
| reveal_type(a6) # N: Revealed type is "builtins.int | builtins.str" | |
| reveal_type(b6) # N: Revealed type is "builtins.float | builtins.str" | |
| m7: tuple[int, Unpack[tuple[float, ...]]] | tuple[str, str] | |
| match m7: | |
| case (a7, b7, *rest7): | |
| reveal_type(a7) # N: Revealed type is "builtins.int | builtins.str" | |
| reveal_type(b7) # N: Revealed type is "builtins.float | builtins.str" | |
| reveal_type(rest7) # N: Revealed type is "builtins.list[builtins.float]" | |
| # verify that if we are unpacking, it will get the type of the sequence if the tuple is too short | |
| m8: tuple[int, str] | list[float] | |
| match m8: | |
| case (a8, b8, *rest8): | |
| reveal_type(a8) # N: Revealed type is "builtins.int | builtins.float" | |
| reveal_type(b8) # N: Revealed type is "builtins.str | builtins.float" | |
| reveal_type(rest8) # N: Revealed type is "builtins.list[builtins.float]" | |
| m9: tuple[str, str, int] | tuple[str, str] | |
| match m9: | |
| case (a9, *rest9): | |
| reveal_type(a9) # N: Revealed type is "builtins.str" | |
| reveal_type(rest9) # N: Revealed type is "builtins.list[builtins.str | builtins.int] | builtins.list[builtins.str]" | |
| [builtins fixtures/tuple.pyi] | |
| [case testMatchEnumSingleChoice] | |
| # flags: --strict-equality --warn-unreachable | |
| 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 | |
| # Ideally, this should narrow to literal | |
| # However `expr_type = try_expanding_sum_type_to_union(coerce_to_literal(expr_type), None)` | |
| # in checker.py means we expand the type to a LiteralType and then because there is no | |
| # net change we don't end up inserting the LiteralType into the type map | |
| reveal_type(m) # N: Revealed type is "__main__.Medal" | |
| case _: | |
| assert_never(m) # E: Statement is unreachable | |
| reveal_type(always_assigned) # N: Revealed type is "builtins.int" | |
| [builtins fixtures/bool.pyi] | |
| [case testMatchLiteralPatternEnumNegativeNarrowing] | |
| # flags: --strict-equality --warn-unreachable | |
| 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 "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 testMatchLiteralOrValuePattern] | |
| # flags: --strict-equality --warn-unreachable | |
| from typing import Literal | |
| def test1(x: Literal[1,2,3]) -> None: | |
| match x: | |
| case 1: | |
| reveal_type(x) # N: Revealed type is "Literal[1]" | |
| case other: | |
| reveal_type(x) # N: Revealed type is "Literal[2] | Literal[3]" | |
| def test2(x: Literal[1,2,3]) -> None: | |
| match x: | |
| case 1: | |
| reveal_type(x) # N: Revealed type is "Literal[1]" | |
| case 2: | |
| reveal_type(x) # N: Revealed type is "Literal[2]" | |
| case 3: | |
| reveal_type(x) # N: Revealed type is "Literal[3]" | |
| case other: | |
| 1 # E: Statement is unreachable | |
| def test3(x: Literal[1,2,3]) -> None: | |
| match x: | |
| case 1 | 3: | |
| reveal_type(x) # N: Revealed type is "Literal[1] | Literal[3]" | |
| case other: | |
| reveal_type(x) # N: Revealed type is "Literal[2]" | |
| [case testMatchLiteralPatternEnumWithTypedAttribute] | |
| # flags: --strict-equality --warn-unreachable | |
| 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) # E: Statement is unreachable | |
| [builtins fixtures/tuple.pyi] | |
| [case testMatchLiteralPatternFunctionalEnum] | |
| # flags: --strict-equality --warn-unreachable | |
| 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) # E: Statement is unreachable | |
| [builtins fixtures/enum.pyi] | |
| [case testMatchLiteralPatternEnumCustomEquals] | |
| # flags: --strict-equality --warn-unreachable | |
| 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 "__main__.Medal" | |
| case _: | |
| reveal_type(m) # N: Revealed type is "Literal[__main__.Medal.silver] | Literal[__main__.Medal.bronze]" | |
| [builtins fixtures/enum.pyi] | |
| [case testMatchNarrowUsingPatternGuardSpecialCase] | |
| # flags: --strict-equality --warn-unreachable | |
| 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] | |
| # flags: --strict-equality --warn-unreachable | |
| 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] | |
| # flags: --strict-equality --warn-unreachable | |
| 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 "builtins.str | Literal[False]" | |
| [builtins fixtures/tuple.pyi] | |
| [case testMatchNarrowDownUnionUsingClassPattern] | |
| # flags: --strict-equality --warn-unreachable | |
| class Foo: ... | |
| class Bar(Foo): ... | |
| def test_1(bar: Bar) -> None: | |
| match bar: | |
| case Foo() as foo: | |
| reveal_type(foo) # N: Revealed type is "__main__.Bar" | |
| def test_2(bar: Bar | str) -> None: | |
| match bar: | |
| case Foo() as foo: | |
| reveal_type(foo) # N: Revealed type is "__main__.Bar" | |
| [case testMatchAssertFalseToSilenceFalsePositives] | |
| # flags: --strict-equality --warn-unreachable | |
| 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] | |
| # flags: --strict-equality --warn-unreachable | |
| def f(x: int | str) -> int: | |
| match x: | |
| case int() as n: | |
| return n | |
| case str() as s: | |
| return 1 | |
| [case testMatchOrPatternExhaustiveness] | |
| # flags: --strict-equality --warn-unreachable | |
| 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] | |
| # flags: --strict-equality --warn-unreachable | |
| 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 "__main__.<subclass of "__main__.A" and "__main__.B"> | __main__.<subclass of "__main__.A" and "__main__.C">" | |
| [case testMatchWithBreakAndContinue] | |
| # flags: --strict-equality --warn-unreachable | |
| 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 "builtins.int | builtins.str | None" | |
| [case testMatchNarrowDownWithStarred-skip] | |
| # flags: --strict-equality --warn-unreachable | |
| 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] | |
| # flags: --strict-equality --warn-unreachable | |
| 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] | |
| # flags: --strict-equality --warn-unreachable | |
| 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: --strict-equality --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] | |
| # flags: --strict-equality --warn-unreachable | |
| 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] | |
| # flags: --strict-equality --warn-unreachable | |
| 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] | |
| # flags: --strict-equality --warn-unreachable | |
| foo: tuple[int] | None | |
| match foo: | |
| case x,: | |
| reveal_type(x) # N: Revealed type is "builtins.int" | |
| [builtins fixtures/tuple.pyi] | |
| [case testMatchUnionTwoTuples] | |
| # flags: --strict-equality --warn-unreachable | |
| def main(var: tuple[int, int] | tuple[str, str]): | |
| match var: | |
| case (42, a): | |
| reveal_type(a) # N: Revealed type is "builtins.int" | |
| case ("yes", b): | |
| reveal_type(b) # N: Revealed type is "builtins.str" | |
| def main2(var: tuple[int, int] | tuple[str, str] | tuple[str, int]): | |
| match var: | |
| case (42, a): | |
| reveal_type(a) # N: Revealed type is "builtins.int" | |
| case ("yes", b): | |
| reveal_type(b) # N: Revealed type is "builtins.str | builtins.int" | |
| [builtins fixtures/tuple.pyi] | |
| [case testMatchNamedAndKeywordsAreTheSame] | |
| # flags: --strict-equality --warn-unreachable | |
| 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] | |
| # flags: --strict-equality --warn-unreachable | |
| 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 --strict-equality --warn-unreachable | |
| 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 --strict-equality --warn-unreachable | |
| 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 --strict-equality --warn-unreachable | |
| 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] | |
| # flags: --strict-equality --warn-unreachable | |
| 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] | |
| # flags: --strict-equality --warn-unreachable | |
| 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" | |
| reveal_type(x) # N: Revealed type is "__main__.A | None" | |
| match x := returns_a(): | |
| case A(): | |
| reveal_type(x.a) # N: Revealed type is "builtins.int" | |
| reveal_type(x) # N: Revealed type is "__main__.A" | |
| y = returns_a_or_none() | |
| match y: | |
| case A(): | |
| reveal_type(y.a) # N: Revealed type is "builtins.int" | |
| [case testNarrowedVariableInNestedModifiedInMatch] | |
| # flags: --strict-equality --warn-unreachable | |
| 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 "str | None", 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 "str | None", 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 "str | None", 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 "list[str] | None", 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 "str | None", expected "str") | |
| match C(): | |
| case C(a=x): | |
| pass | |
| nested() | |
| [builtins fixtures/tuple.pyi] | |
| [case testMatchSubjectRedefinition] | |
| # flags: --allow-redefinition-old --strict-equality --warn-unreachable | |
| 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] | |
| # flags: --strict-equality --warn-unreachable | |
| # 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: --strict-equality --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 "builtins.int | builtins.bytes" | |
| return 0 | |
| [builtins fixtures/primitives.pyi] | |
| [case testMatchGuardAlwaysTrueAlwaysFalse] | |
| # flags: --warn-unreachable --always-true TRUEFLAG --always-false FALSEFLAG --strict-equality | |
| TRUEFLAG = False | |
| FALSEFLAG = True | |
| def true_flag(e: int) -> None: | |
| match e: | |
| case _ if TRUEFLAG: | |
| pass | |
| case 0: | |
| # No error | |
| 1 + "asdf" | |
| def false_flag(e: int) -> None: | |
| match e: | |
| case _ if FALSEFLAG: | |
| # No error | |
| 1 + "asdf" | |
| [case testMatchSequencePatternVariadicTupleNotTooShort] | |
| # flags: --strict-equality --warn-unreachable | |
| 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) # E: Statement is unreachable | |
| 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[builtins.int | builtins.str]" | |
| reveal_type(c3) # N: Revealed type is "builtins.int" | |
| [builtins fixtures/tuple.pyi] | |
| [case testMatchSequencePatternVariadicTuple] | |
| # flags: --strict-equality --warn-unreachable | |
| from typing_extensions import Unpack | |
| def f1(m: tuple[int, Unpack[tuple[str, ...]], int]) -> None: | |
| match m: | |
| case (a1, b1): | |
| reveal_type(m) # N: Revealed type is "tuple[builtins.int, builtins.int]" | |
| case (a2, b2, c2): | |
| reveal_type(m) # N: Revealed type is "tuple[builtins.int, builtins.str, builtins.int]" | |
| case (a3, b3, c3, d3): | |
| reveal_type(m) # N: Revealed type is "tuple[builtins.int, builtins.str, builtins.str, builtins.int]" | |
| case (a4, *b4, c4): | |
| reveal_type(m) # N: Revealed type is "tuple[builtins.int, Unpack[builtins.tuple[builtins.str, ...]], builtins.int]" | |
| case _: | |
| reveal_type(m) # E: Statement is unreachable | |
| def f2(m: tuple[int] | tuple[str, str] | tuple[int, Unpack[tuple[str, ...]], int]): | |
| match m: | |
| case (x,): | |
| reveal_type(m) # N: Revealed type is "tuple[builtins.int]" | |
| case (x, y): | |
| reveal_type(m) # N: Revealed type is "tuple[builtins.str, builtins.str] | tuple[builtins.int, builtins.int]" | |
| case (x, y, z): | |
| reveal_type(m) # N: Revealed type is "tuple[builtins.int, builtins.str, builtins.int]" | |
| case _: | |
| reveal_type(m) # N: Revealed type is "tuple[builtins.int, Unpack[builtins.tuple[builtins.str, ...]], builtins.int]" | |
| [builtins fixtures/tuple.pyi] | |
| [case testMatchSequencePatternTypeVarTupleNotTooShort] | |
| # flags: --strict-equality --warn-unreachable | |
| 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) # E: Statement is unreachable | |
| 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] | |
| # flags: --strict-equality --warn-unreachable | |
| # 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] | |
| # flags: --strict-equality --warn-unreachable | |
| 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: --strict-equality --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] | |
| # flags: --strict-equality --warn-unreachable | |
| 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: --strict-equality --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: --strict-equality --warn-unreachable | |
| from typing import Literal | |
| def f() -> None: | |
| 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']]]") \ | |
| # E: Non-overlapping equality check (left operand type: "Callable[[], tuple[Literal['test']]]", right operand type: "Literal['test']") | |
| reveal_type(x) # E: Statement is unreachable | |
| case foo: | |
| foo | |
| [builtins fixtures/dict.pyi] | |
| [case testMatchRebindsInnerFunctionName] | |
| # flags: --strict-equality --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 "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 "int | str", variable has type "Callable[[], str]") | |
| pass | |
| [builtins fixtures/dict.pyi] | |
| [case testMatchFunctionCall] | |
| # flags: --strict-equality --warn-unreachable | |
| def fn() -> int | str: ... | |
| match fn(): | |
| case str(s): | |
| reveal_type(s) # N: Revealed type is "builtins.str" | |
| case int(i): | |
| reveal_type(i) # N: Revealed type is "builtins.int" | |
| case other: | |
| other # E: Statement is unreachable | |
| [case testMatchAttribute] | |
| # flags: --strict-equality --warn-unreachable | |
| class A: | |
| foo: int | str | |
| match A().foo: | |
| case str(s): | |
| reveal_type(s) # N: Revealed type is "builtins.str" | |
| case int(i): | |
| reveal_type(i) # N: Revealed type is "builtins.int" | |
| case other: | |
| other # E: Statement is unreachable | |
| [case testMatchLiteral] | |
| # flags: --strict-equality --warn-unreachable | |
| def int_literal() -> None: | |
| match 12: | |
| case 1 as s: | |
| reveal_type(s) # E: Statement is unreachable | |
| case int(i): | |
| reveal_type(i) # N: Revealed type is "Literal[12]?" | |
| case other: | |
| other # E: Statement is unreachable | |
| def str_literal() -> None: | |
| match 'foo': | |
| case 'a' as s: | |
| reveal_type(s) # E: Statement is unreachable | |
| case str(i): | |
| reveal_type(i) # N: Revealed type is "Literal['foo']?" | |
| case other: | |
| other # E: Statement is unreachable | |
| [case testMatchOperations] | |
| # flags: --strict-equality --warn-unreachable | |
| x: int | |
| match -x: | |
| case -1 as s: | |
| reveal_type(s) # N: Revealed type is "Literal[-1]" | |
| case int(s): | |
| reveal_type(s) # N: Revealed type is "builtins.int" | |
| case other: | |
| other # E: Statement is unreachable | |
| match 1 + 2: | |
| case 3 as s: | |
| reveal_type(s) # N: Revealed type is "Literal[3]" | |
| case int(s): | |
| reveal_type(s) # N: Revealed type is "builtins.int" | |
| case other: | |
| other # E: Statement is unreachable | |
| match 1 > 2: | |
| case True as s: | |
| reveal_type(s) # N: Revealed type is "Literal[True]" | |
| case False as s: | |
| reveal_type(s) # N: Revealed type is "Literal[False]" | |
| case other: | |
| other # E: Statement is unreachable | |
| [builtins fixtures/ops.pyi] | |
| [case testMatchDictItem] | |
| # flags: --strict-equality --warn-unreachable | |
| m: dict[str, int | str] | |
| k: str | |
| match m[k]: | |
| case str(s): | |
| reveal_type(s) # N: Revealed type is "builtins.str" | |
| case int(i): | |
| reveal_type(i) # N: Revealed type is "builtins.int" | |
| case other: | |
| other # E: Statement is unreachable | |
| [builtins fixtures/dict.pyi] | |
| [case testMatchLiteralValuePathological] | |
| # flags: --strict-equality --warn-unreachable | |
| match 0: | |
| case 0 as i: | |
| reveal_type(i) # N: Revealed type is "Literal[0]?" | |
| case int(i): | |
| i # E: Statement is unreachable | |
| case other: | |
| other # E: Statement is unreachable | |
| [case testMatchNamedTupleSequence] | |
| # flags: --strict-equality --warn-unreachable | |
| 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 testMatchTypeObjectTypeVar] | |
| # flags: --strict-equality --warn-unreachable | |
| from typing import TypeVar | |
| import b | |
| T_Choice = TypeVar("T_Choice", bound=b.One | b.Two) | |
| def switch(choice: type[T_Choice]) -> None: | |
| match choice: | |
| case b.One: | |
| reveal_type(choice) # N: Revealed type is "def () -> b.One" | |
| reveal_type(choice()) # N: Revealed type is "b.One" | |
| case b.Two: | |
| reveal_type(choice) # N: Revealed type is "def () -> b.Two" | |
| reveal_type(choice()) # N: Revealed type is "b.Two" | |
| case _: | |
| reveal_type(choice) # N: Revealed type is "type[T_Choice`-1]" | |
| reveal_type(choice()) # N: Revealed type is "T_Choice`-1" | |
| [file b.py] | |
| class One: ... | |
| class Two: ... | |
| [builtins fixtures/tuple.pyi] | |
| [case testNewRedefineMatchBasics] | |
| # flags: --allow-redefinition --strict-equality --warn-unreachable | |
| 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 "builtins.str | builtins.bytes" | |
| [case testNewRedefineLoopWithMatch] | |
| # flags: --allow-redefinition --strict-equality --warn-unreachable | |
| 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 testExhaustiveMatchNoFlag] | |
| # flags: --strict-equality --warn-unreachable | |
| a: int = 5 | |
| match a: | |
| case 1: | |
| pass | |
| case _: | |
| pass | |
| b: str = "hello" | |
| match b: | |
| case "bye": | |
| pass | |
| case _: | |
| pass | |
| [case testNonExhaustiveMatchNoFlag] | |
| # flags: --strict-equality --warn-unreachable | |
| a: int = 5 | |
| match a: | |
| case 1: | |
| pass | |
| b: str = "hello" | |
| match b: | |
| case "bye": | |
| pass | |
| [case testExhaustiveMatchWithFlag] | |
| # flags: --enable-error-code exhaustive-match --strict-equality --warn-unreachable | |
| a: int = 5 | |
| match a: | |
| case 1: | |
| pass | |
| case _: | |
| pass | |
| b: str = "hello" | |
| match b: | |
| case "bye": | |
| pass | |
| case _: | |
| pass | |
| [case testNonExhaustiveMatchWithFlag] | |
| # flags: --enable-error-code exhaustive-match --strict-equality --warn-unreachable | |
| a: int = 5 | |
| match a: # E: Match statement has unhandled case for values of type "int" \ | |
| # N: If match statement is intended to be non-exhaustive, add `case _: pass` | |
| case 1: | |
| pass | |
| b: str = "hello" | |
| match b: # E: Match statement has unhandled case for values of type "str" \ | |
| # N: If match statement is intended to be non-exhaustive, add `case _: pass` | |
| case "bye": | |
| pass | |
| [case testNonExhaustiveMatchEnumWithFlag] | |
| # flags: --enable-error-code exhaustive-match --strict-equality --warn-unreachable | |
| import enum | |
| class Color(enum.Enum): | |
| RED = 1 | |
| BLUE = 2 | |
| GREEN = 3 | |
| val: Color = Color.RED | |
| match val: # E: Match statement has unhandled case for values of type "Literal[Color.GREEN]" \ | |
| # N: If match statement is intended to be non-exhaustive, add `case _: pass` | |
| case Color.RED: | |
| a = "red" | |
| case Color.BLUE: | |
| a= "blue" | |
| [builtins fixtures/enum.pyi] | |
| [case testExhaustiveMatchEnumWithFlag] | |
| # flags: --enable-error-code exhaustive-match --strict-equality --warn-unreachable | |
| import enum | |
| class Color(enum.Enum): | |
| RED = 1 | |
| BLUE = 2 | |
| val: Color = Color.RED | |
| match val: | |
| case Color.RED: | |
| a = "red" | |
| case Color.BLUE: | |
| a= "blue" | |
| [builtins fixtures/enum.pyi] | |
| [case testNonExhaustiveMatchEnumMultipleMissingMatchesWithFlag] | |
| # flags: --enable-error-code exhaustive-match --strict-equality --warn-unreachable | |
| import enum | |
| class Color(enum.Enum): | |
| RED = 1 | |
| BLUE = 2 | |
| GREEN = 3 | |
| val: Color = Color.RED | |
| match val: # E: Match statement has unhandled case for values of type "Literal[Color.BLUE, Color.GREEN]" \ | |
| # N: If match statement is intended to be non-exhaustive, add `case _: pass` | |
| case Color.RED: | |
| a = "red" | |
| [builtins fixtures/enum.pyi] | |
| [case testExhaustiveMatchEnumFallbackWithFlag] | |
| # flags: --enable-error-code exhaustive-match --strict-equality --warn-unreachable | |
| import enum | |
| class Color(enum.Enum): | |
| RED = 1 | |
| BLUE = 2 | |
| GREEN = 3 | |
| val: Color = Color.RED | |
| match val: | |
| case Color.RED: | |
| a = "red" | |
| case _: | |
| a = "other" | |
| [builtins fixtures/enum.pyi] | |
| # Fork of testMatchNarrowingUnionTypedDictViaIndex to check behaviour with exhaustive match flag | |
| [case testExhaustiveMatchNarrowingUnionTypedDictViaIndex] | |
| # flags: --enable-error-code exhaustive-match --strict-equality --warn-unreachable | |
| 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"]: # E: Match statement has unhandled case for values of type "B" \ | |
| # N: If match statement is intended to be non-exhaustive, add `case _: pass` \ | |
| # E: Match statement has unhandled case for values of type "Literal['b']" | |
| 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" | |
| [typing fixtures/typing-typeddict.pyi] | |
| [case testEnumTypeObjectMember] | |
| # flags: --strict-equality --warn-unreachable | |
| 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) # E: Statement is unreachable | |
| [builtins fixtures/tuple.pyi] | |
| [case testAssignmentToFinalInMatchCaseNotAllowed] | |
| # flags: --strict-equality --warn-unreachable | |
| from typing import Final | |
| FOO: Final[int] = 10 | |
| val: int = 8 | |
| match val: | |
| case FOO: # E: Cannot assign to final name "FOO" | |
| pass | |
| [case testMatchExhaustivenessWithDeferral] | |
| # flags: --enable-error-code exhaustive-match --strict-equality --warn-unreachable | |
| from typing import Literal | |
| import unknown_module # E: Cannot find implementation or library stub for module named "unknown_module" \ | |
| # N: See https://mypy.readthedocs.io/en/stable/running_mypy.html#missing-imports | |
| def foo(e: Literal[0, 1]) -> None: | |
| match e: | |
| case 0: | |
| defer | |
| case 1: | |
| ... | |
| defer = unknown_module.foo | |
| [case testMatchErrorsIncorrectName] | |
| # flags: --strict-equality --warn-unreachable | |
| class A: | |
| pass | |
| match 5: | |
| case A.blah(): # E: "type[A]" has no attribute "blah" | |
| pass | |
| [case testMatchAllowsAnyClassArgsForAny] | |
| # flags: --strict-equality --warn-unreachable | |
| match 5: | |
| case BlahBlah(a, b): # E: Name "BlahBlah" is not defined | |
| reveal_type(a) # N: Revealed type is "Any" | |
| reveal_type(b) # N: Revealed type is "Any" | |
| case BlahBlah(c=c): # E: Name "BlahBlah" is not defined | |
| reveal_type(c) # N: Revealed type is "Any" | |
| [case testMatchAllowsNoneTypeAsClass] | |
| # flags: --strict-equality --warn-unreachable | |
| import types | |
| class V: | |
| X = types.NoneType | |
| def fun(val: str | None): | |
| match val: | |
| case V.X(): | |
| reveal_type(val) # N: Revealed type is "None" | |
| match val: | |
| case types.NoneType(): | |
| reveal_type(val) # N: Revealed type is "None" | |
| [builtins fixtures/tuple.pyi] | |
| [case testMatchMappingRestErrorLocation] | |
| # flags: --strict-equality --warn-unreachable | |
| rest: list[int] | |
| data: list[int] | |
| match data: | |
| case [1, *rest]: | |
| ... | |
| config: dict[str, object] | |
| match config: | |
| case {"a": 1, **rest}: # E: Incompatible types in capture pattern (pattern captures type "dict[str, object]", variable has type "list[int]") | |
| ... | |
| [builtins fixtures/dict.pyi] | |
| [case testMatchTypeNarrowing] | |
| # flags: --strict-equality --warn-unreachable | |
| import builtins | |
| import typing | |
| import types | |
| def type_bare(field_type: type) -> str: | |
| match field_type: | |
| case builtins.int: | |
| reveal_type(field_type) # N: Revealed type is "def () -> builtins.int" | |
| ret = "foo" | |
| case builtins.str: | |
| reveal_type(field_type) # N: Revealed type is "def () -> builtins.str" | |
| ret = "foo" | |
| case builtins.bytes: | |
| reveal_type(field_type) # N: Revealed type is "def () -> builtins.bytes" | |
| ret = "foo" | |
| case builtins.bool: | |
| reveal_type(field_type) # N: Revealed type is "def () -> builtins.bool" | |
| ret = "foo" | |
| case types.NoneType: | |
| reveal_type(field_type) # N: Revealed type is "type[None]" | |
| ret = "foo" | |
| case _: | |
| reveal_type(field_type) # N: Revealed type is "builtins.type" | |
| return "bar" | |
| return ret | |
| def type_any(field_type: type[typing.Any]) -> str: | |
| match field_type: | |
| case builtins.int: | |
| reveal_type(field_type) # N: Revealed type is "type[Any]" | |
| ret = "foo" | |
| case builtins.str: | |
| reveal_type(field_type) # N: Revealed type is "type[Any]" | |
| ret = "foo" | |
| case builtins.bytes: | |
| reveal_type(field_type) # N: Revealed type is "type[Any]" | |
| ret = "foo" | |
| case builtins.bool: | |
| reveal_type(field_type) # N: Revealed type is "type[Any]" | |
| ret = "foo" | |
| case types.NoneType: | |
| reveal_type(field_type) # N: Revealed type is "type[None]" | |
| ret = "foo" | |
| case _: | |
| reveal_type(field_type) # N: Revealed type is "type[Any]" | |
| return "bar" | |
| return ret | |
| def type_object(field_type: type[object]) -> str: | |
| match field_type: | |
| case builtins.int: | |
| reveal_type(field_type) # N: Revealed type is "def () -> builtins.int" | |
| ret = "foo" | |
| case builtins.str: | |
| reveal_type(field_type) # N: Revealed type is "def () -> builtins.str" | |
| ret = "foo" | |
| case builtins.bytes: | |
| reveal_type(field_type) # N: Revealed type is "def () -> builtins.bytes" | |
| ret = "foo" | |
| case builtins.bool: | |
| reveal_type(field_type) # N: Revealed type is "def () -> builtins.bool" | |
| ret = "foo" | |
| case types.NoneType: | |
| reveal_type(field_type) # N: Revealed type is "type[None]" | |
| ret = "foo" | |
| case _: | |
| reveal_type(field_type) # N: Revealed type is "type[builtins.object]" | |
| return "bar" | |
| return ret | |
| [builtins fixtures/dict.pyi] | |
| [case testMatchFinalClass] | |
| # flags: --strict-equality --warn-unreachable | |
| from typing import final, NoReturn | |
| def assert_never(x: NoReturn) -> NoReturn: ... | |
| class Types: | |
| @final | |
| class A: | |
| pass | |
| @final | |
| class B: | |
| pass | |
| def foo(cls: type[Types.A | Types.B]) -> None: | |
| match cls: | |
| case Types.A: | |
| reveal_type(cls) # N: Revealed type is "type[__main__.Types.A]" | |
| case Types.B: | |
| reveal_type(cls) # N: Revealed type is "type[__main__.Types.B]" | |
| case _: | |
| assert_never(cls) | |
| class TypeTypes: | |
| A: type[Types.A] = Types.A | |
| B: type[Types.B] = Types.B | |
| def bar(cls: type[Types.A | Types.B]) -> None: | |
| match cls: | |
| case TypeTypes.A: | |
| reveal_type(cls) # N: Revealed type is "type[__main__.Types.A]" | |
| case TypeTypes.B: | |
| reveal_type(cls) # N: Revealed type is "type[__main__.Types.B]" | |
| case _: | |
| assert_never(cls) | |
| [builtins fixtures/tuple.pyi] | |
| [case testMatchEnumOrdering] | |
| # flags: --strict-equality --warn-unreachable | |
| # Regression test for https://github.com/python/mypy/issues/21187 | |
| import enum | |
| from typing import Literal | |
| class DummyClass: ... | |
| class MyEnum(enum.StrEnum): | |
| RELEVANT = "relevant" | |
| IGNORED = "ignored" | |
| def dummy_class_then_enum(arg: DummyClass | Literal[MyEnum.RELEVANT]): | |
| match arg: | |
| case DummyClass(): | |
| reveal_type(arg) # N: Revealed type is "__main__.DummyClass" | |
| case MyEnum.RELEVANT: | |
| reveal_type(arg) # N: Revealed type is "Literal[__main__.MyEnum.RELEVANT]" | |
| case _: | |
| pass # E: Statement is unreachable | |
| def enum_then_dummy_class(arg: DummyClass | Literal[MyEnum.RELEVANT]): | |
| match arg: | |
| case MyEnum.RELEVANT: | |
| reveal_type(arg) # N: Revealed type is "Literal[__main__.MyEnum.RELEVANT]" | |
| case DummyClass(): | |
| reveal_type(arg) # N: Revealed type is "__main__.DummyClass" | |
| case _: | |
| pass # E: Statement is unreachable | |
| [builtins fixtures/tuple.pyi] |