Skip to content

Commit c2fd9d3

Browse files
authored
Fix crash on unhandled meet variadic tuple vs indtance (#21558)
Fixes #20526 Fix is straightforward: handle previously unhandled scenario.
1 parent 5f9371e commit c2fd9d3

3 files changed

Lines changed: 35 additions & 3 deletions

File tree

‎mypy/meet.py‎

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1090,7 +1090,28 @@ def visit_tuple_type(self, t: TupleType) -> ProperType:
10901090
elif isinstance(self.s, Instance):
10911091
# meet(Tuple[t1, t2, <...>], Tuple[s, ...]) == Tuple[meet(t1, s), meet(t2, s), <...>].
10921092
if self.s.type.fullname in TUPLE_LIKE_INSTANCE_NAMES and self.s.args:
1093-
return t.copy_modified(items=[meet_types(it, self.s.args[0]) for it in t.items])
1093+
arg = self.s.args[0]
1094+
new_items: list[Type] = []
1095+
for it in t.items:
1096+
# Unpack items need to be handled by the caller.
1097+
if isinstance(it, UnpackType):
1098+
unpacked = get_proper_type(it.type)
1099+
if isinstance(unpacked, TypeVarTupleType):
1100+
# We can't infer anything in this case.
1101+
new_arg = UninhabitedType()
1102+
instance = unpacked.tuple_fallback
1103+
else:
1104+
assert (
1105+
isinstance(unpacked, Instance)
1106+
and unpacked.type.fullname == "builtins.tuple"
1107+
)
1108+
new_arg = meet_types(unpacked.args[0], arg)
1109+
instance = unpacked
1110+
new_items.append(UnpackType(instance.copy_modified(args=[new_arg])))
1111+
else:
1112+
# All other items can be processed in a regular way.
1113+
new_items.append(meet_types(it, arg))
1114+
return t.copy_modified(items=new_items)
10941115
elif is_proper_subtype(t, self.s):
10951116
# A named tuple that inherits from a normal class
10961117
return t

‎test-data/unit/check-typeis.test‎

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -213,8 +213,7 @@ def test5(t: tuple[A | B, ...]) -> None:
213213

214214
def test6(t: tuple[B, Unpack[tuple[A | B, ...]], B]) -> None:
215215
if is_tuple_of_B(t):
216-
# Should this be tuple[B, *tuple[B, ...], B]
217-
reveal_type(t) # N: Revealed type is "tuple[__main__.B, Never, __main__.B]"
216+
reveal_type(t) # N: Revealed type is "tuple[__main__.B, Unpack[builtins.tuple[__main__.B, ...]], __main__.B]"
218217
else:
219218
reveal_type(t) # N: Revealed type is "tuple[__main__.B, Unpack[builtins.tuple[__main__.A | __main__.B, ...]], __main__.B]"
220219
[builtins fixtures/tuple.pyi]

‎test-data/unit/check-typevar-tuple.test‎

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2873,3 +2873,15 @@ reveal_type(x) # N: Revealed type is "builtins.list[tuple[()]]"
28732873
reveal_type(y) # N: Revealed type is "builtins.list[tuple[()]]"
28742874
reveal_type(z) # N: Revealed type is "builtins.list[tuple[()]]"
28752875
[builtins fixtures/tuple.pyi]
2876+
2877+
[case testMeetTupleWithUnpackVsInstanceWorks_no_verbose_reveal]
2878+
from typing import TypeVar, Unpack, Union
2879+
2880+
K = TypeVar("K")
2881+
Prefix = tuple[Union[K, list[int]], ...]
2882+
2883+
def g(x: K) -> None:
2884+
d: Union[Prefix[K], tuple[Unpack[Prefix[int]], int], None] = None
2885+
assert d is not None
2886+
reveal_type(d) # N: Revealed type is "tuple[K | list[int], ...] | tuple[*tuple[int | list[int], ...], int]"
2887+
[builtins fixtures/tuple.pyi]

0 commit comments

Comments
 (0)