-- 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 "Literal[1]" 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] -- 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__." case A(i, j): reveal_type(m) # N: Revealed type is "__main__." [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 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__." [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 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__." case C() as y: reveal_type(y) # N: Revealed type is "__main__." reveal_type(y) # N: Revealed type is "__main__. | __main__." [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 "b.One | b.Two" [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]