From 5f587cef096bec68667832149b3a1cda6edacdbe Mon Sep 17 00:00:00 2001 From: afonsojanu Date: Thu, 3 Sep 2026 17:06:59 +0100 Subject: [PATCH] Fix crash when a fixed-length tuple gets unpacked into a tuple type tuple_fallback() only knew how to handle two shapes for an unpacked item inside a tuple: a TypeVarTuple (via its upper bound) or a variable-length tuple Instance. Unpacking a fixed-length tuple, which PEP 646 also allows and which shows up easily through a type alias like `type Outer = tuple[bool, *tuple[int, str]]`, fell through to the NotImplementedError branch and crashed mypy outright whenever that tuple type needed its fallback computed (e.g. when checking it against a generic upper bound during overload resolution). Handle the TupleType case the same way as the others: recurse into its own tuple_fallback() to get the right combined element type, then fold that into the union like everything else here does. Fixes #21933. --- mypy/typeops.py | 5 +++++ test-data/unit/pythoneval.test | 18 ++++++++++++++++++ 2 files changed, 23 insertions(+) diff --git a/mypy/typeops.py b/mypy/typeops.py index 8453da4dd31c0..a85560d3f1da0 100644 --- a/mypy/typeops.py +++ b/mypy/typeops.py @@ -119,6 +119,11 @@ def tuple_fallback(typ: TupleType) -> Instance: and unpacked_type.type.fullname == "builtins.tuple" ): items.append(unpacked_type.args[0]) + elif isinstance(unpacked_type, TupleType): + # A fixed-length tuple being unpacked (e.g. *tuple[int, str], possibly + # via a type alias) isn't a TypeVarTupleType or a variable-length tuple + # Instance, but its own fallback already gives us the right element type. + items.append(tuple_fallback(unpacked_type).args[0]) else: raise NotImplementedError else: diff --git a/test-data/unit/pythoneval.test b/test-data/unit/pythoneval.test index 8c37e48d7c332..b6f574efa5244 100644 --- a/test-data/unit/pythoneval.test +++ b/test-data/unit/pythoneval.test @@ -2310,3 +2310,21 @@ type Alias[T] = list[T] def g[T = int](x: T) -> T: ... [out] _testNativeParserPEP695InStubNoVersionError.py:3: note: Revealed type is "def [T] (x: T) -> T" + +[case testNoCrashOnFixedTupleUnpackInGenericInferenceContext] +# https://github.com/python/mypy/issues/21933 +# flags: --python-version=3.12 +from collections import deque + +type Inner = tuple[int, str] +type Outer = tuple[bool, *Inner] + + +class K(Base): + q: deque[Outer] = deque() + reveal_type(q) + + +class Base: ... +[out] +_testNoCrashOnFixedTupleUnpackInGenericInferenceContext.py:11: note: Revealed type is "collections.deque[tuple[bool, *tuple[int, str]]]"