From 0a7b9200a32a6515f7e93cbcaeac103bb7f7a402 Mon Sep 17 00:00:00 2001 From: Marc Mueller <30130371+cdce8p@users.noreply.github.com> Date: Thu, 2 Oct 2025 23:51:59 +0200 Subject: [PATCH] Fix reachability in nested match sequence patterns --- mypy/checkpattern.py | 16 +++++++++++++++- test-data/unit/check-python310.test | 18 +++++++++++++++++- 2 files changed, 32 insertions(+), 2 deletions(-) diff --git a/mypy/checkpattern.py b/mypy/checkpattern.py index f81684d2f44a..9d4c00b6c47b 100644 --- a/mypy/checkpattern.py +++ b/mypy/checkpattern.py @@ -313,7 +313,21 @@ def visit_sequence_pattern(self, o: SequencePattern) -> PatternType: ) ) narrowed_inner_types.append(narrowed_inner_type) - inner_rest_types.append(inner_rest_type) + narrowed_ptype = get_proper_type(narrowed_inner_type) + if ( + is_uninhabited(inner_rest_type) + and isinstance(narrowed_ptype, Instance) + and ( + narrowed_ptype.type.fullname == "builtins.dict" + or narrowed_ptype.type.fullname == "builtins.list" + ) + ): + # Can't narrow rest type to uninhabited + # if narrowed_type is dict or list. + # Those can be matched by Mapping or Sequence patterns. + inner_rest_types.append(narrowed_inner_type) + else: + inner_rest_types.append(inner_rest_type) if all(not is_uninhabited(typ) for typ in narrowed_inner_types): new_type = TupleType(narrowed_inner_types, current_type.partial_fallback) else: diff --git a/test-data/unit/check-python310.test b/test-data/unit/check-python310.test index 7d76c09b6151..b08560103dea 100644 --- a/test-data/unit/check-python310.test +++ b/test-data/unit/check-python310.test @@ -1525,6 +1525,7 @@ def f(value: Literal[1] | Literal[2]) -> int: [typing fixtures/typing-medium.pyi] [case testMatchSequencePatternNegativeNarrowing] +# flags: --warn-unreachable from typing import Literal, Union, Sequence, Tuple m1: Sequence[int | str] @@ -1577,7 +1578,22 @@ match m6: case _: reveal_type(m6) # N: Revealed type is "tuple[Union[Literal[1], Literal[2]], Union[Literal['a'], Literal['b']]]" -[builtins fixtures/tuple.pyi] +m7: dict[str, str] + +match (m7, m7): + case ({"a": "1"}, _): + reveal_type(m7) # N: Revealed type is "builtins.dict[builtins.str, builtins.str]" + case (_, {"a": "2"}): + reveal_type(m7) # N: Revealed type is "builtins.dict[builtins.str, builtins.str]" + +m8: list[int] + +match (m8, m8): + case ([1], _): + reveal_type(m8) # N: Revealed type is "builtins.list[builtins.int]" + case (_, [2]): + reveal_type(m8) # N: Revealed type is "builtins.list[builtins.int]" +[builtins fixtures/dict.pyi] [case testMatchEnumSingleChoice] from enum import Enum