Skip to content

Commit f394946

Browse files
authored
Fix narrowing for match case with variadic tuples (#21192)
Fixes #21189
1 parent ef28d9c commit f394946

File tree

2 files changed

+38
-2
lines changed

2 files changed

+38
-2
lines changed

mypy/checkpattern.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -378,9 +378,15 @@ def visit_sequence_pattern(self, o: SequencePattern) -> PatternType:
378378
# tuples, so we instead try to narrow the entire type.
379379
# TODO: use more precise narrowing when possible (e.g. for identical shapes).
380380
new_tuple_type = TupleType(new_inner_types, current_type.partial_fallback)
381-
new_type, rest_type = self.chk.conditional_types_with_intersection(
381+
new_type, _ = self.chk.conditional_types_with_intersection(
382382
new_tuple_type, [get_type_range(current_type)], o, default=new_tuple_type
383383
)
384+
if (
385+
star_position is not None
386+
and required_patterns <= len(inner_types) - 1
387+
and all(is_uninhabited(rest) for rest in rest_inner_types)
388+
):
389+
rest_type = UninhabitedType()
384390
else:
385391
new_inner_type = UninhabitedType()
386392
for typ in new_inner_types:
@@ -460,7 +466,7 @@ def expand_starred_pattern_types(
460466
# so we only restore the type of the star item.
461467
res = []
462468
for i, t in enumerate(types):
463-
if i != star_pos:
469+
if i != star_pos or is_uninhabited(t):
464470
res.append(t)
465471
else:
466472
res.append(UnpackType(self.chk.named_generic_type("builtins.tuple", [t])))

test-data/unit/check-python310.test

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3136,6 +3136,36 @@ match m3:
31363136
reveal_type(c3) # N: Revealed type is "builtins.int"
31373137
[builtins fixtures/tuple.pyi]
31383138

3139+
[case testMatchSequencePatternVariadicTuple]
3140+
# flags: --strict-equality --warn-unreachable
3141+
from typing_extensions import Unpack
3142+
3143+
def f1(m: tuple[int, Unpack[tuple[str, ...]], int]) -> None:
3144+
match m:
3145+
case (a1, b1):
3146+
reveal_type(m) # N: Revealed type is "tuple[builtins.int, builtins.int]"
3147+
case (a2, b2, c2):
3148+
reveal_type(m) # N: Revealed type is "tuple[builtins.int, builtins.str, builtins.int]"
3149+
case (a3, b3, c3, d3):
3150+
reveal_type(m) # N: Revealed type is "tuple[builtins.int, builtins.str, builtins.str, builtins.int]"
3151+
case (a4, *b4, c4):
3152+
reveal_type(m) # N: Revealed type is "tuple[builtins.int, Unpack[builtins.tuple[builtins.str, ...]], builtins.int]"
3153+
case _:
3154+
reveal_type(m) # E: Statement is unreachable
3155+
3156+
3157+
def f2(m: tuple[int] | tuple[str, str] | tuple[int, Unpack[tuple[str, ...]], int]):
3158+
match m:
3159+
case (x,):
3160+
reveal_type(m) # N: Revealed type is "tuple[builtins.int]"
3161+
case (x, y):
3162+
reveal_type(m) # N: Revealed type is "tuple[builtins.str, builtins.str] | tuple[builtins.int, builtins.int]"
3163+
case (x, y, z):
3164+
reveal_type(m) # N: Revealed type is "tuple[builtins.int, builtins.str, builtins.int]"
3165+
case _:
3166+
reveal_type(m) # N: Revealed type is "tuple[builtins.int, Unpack[builtins.tuple[builtins.str, ...]], builtins.int]"
3167+
[builtins fixtures/tuple.pyi]
3168+
31393169
[case testMatchSequencePatternTypeVarTupleNotTooShort]
31403170
# flags: --strict-equality --warn-unreachable
31413171
from typing import Tuple

0 commit comments

Comments
 (0)