From f50cc2cb59cf4a9fbcc2359488b4d076074af7ec Mon Sep 17 00:00:00 2001 From: Ivan Levkivskyi Date: Wed, 1 Oct 2025 12:23:04 +0100 Subject: [PATCH] Fix crash on invalid unpack in base class --- mypy/semanal_shared.py | 4 +++- mypy/typeanal.py | 2 +- test-data/unit/check-python312.test | 10 ++++++++++ test-data/unit/check-typevar-tuple.test | 24 ++++++++++++++++++++++++ 4 files changed, 38 insertions(+), 2 deletions(-) diff --git a/mypy/semanal_shared.py b/mypy/semanal_shared.py index e94604b66381..c49b13d08f45 100644 --- a/mypy/semanal_shared.py +++ b/mypy/semanal_shared.py @@ -303,7 +303,9 @@ def calculate_tuple_fallback(typ: TupleType) -> None: ): items.append(unpacked_type.args[0]) else: - raise NotImplementedError + # This is called before semanal_typeargs.py fixes broken unpacks, + # where the error should also be generated. + items.append(AnyType(TypeOfAny.from_error)) else: items.append(item) fallback.args = (make_simplified_union(items),) diff --git a/mypy/typeanal.py b/mypy/typeanal.py index 81fb87fbf9ee..d7a07c9f48e3 100644 --- a/mypy/typeanal.py +++ b/mypy/typeanal.py @@ -634,7 +634,7 @@ def try_analyze_special_unbound_type(self, t: UnboundType, fullname: str) -> Typ ) elif fullname == "typing.Union": items = self.anal_array(t.args) - return UnionType.make_union(items) + return UnionType.make_union(items, line=t.line, column=t.column) elif fullname == "typing.Optional": if len(t.args) != 1: self.fail( diff --git a/test-data/unit/check-python312.test b/test-data/unit/check-python312.test index 382822ced861..6a72a7e4d5b5 100644 --- a/test-data/unit/check-python312.test +++ b/test-data/unit/check-python312.test @@ -2121,3 +2121,13 @@ class A: ... x1: Alias1[A] # ok x2: Alias2[A] # ok + +[case testUndefinedUnpackInPEP696Base] +# Typo below is intentional. +class MyTuple[*Ts](tuple[*TS]): # E: Name "TS" is not defined + ... + +x: MyTuple[int, str] +reveal_type(x[0]) # N: Revealed type is "Any" +[builtins fixtures/tuple.pyi] +[typing fixtures/typing-full.pyi] diff --git a/test-data/unit/check-typevar-tuple.test b/test-data/unit/check-typevar-tuple.test index c668f14eaa50..927a4f037a4a 100644 --- a/test-data/unit/check-typevar-tuple.test +++ b/test-data/unit/check-typevar-tuple.test @@ -2692,3 +2692,27 @@ tuple(a) (x,) = a (_,) = a [builtins fixtures/tuple.pyi] + +[case testNoCrashOnUndefinedUnpackInBase] +from typing import TypeVarTuple, Generic, Unpack + +Ts = TypeVarTuple("Ts") + +class MyTuple(tuple[Unpack[TsWithTypo]], Generic[Unpack[Ts]]): # E: Name "TsWithTypo" is not defined + ... + +x: MyTuple[int, str] +reveal_type(x[0]) # N: Revealed type is "Any" +[builtins fixtures/tuple.pyi] + +[case testNoCrashOnInvalidUnpackInBase] +from typing import TypeVarTuple, Generic, Unpack, Union + +Ts = TypeVarTuple("Ts") + +class MyTuple(tuple[Unpack[Union[int, str]]], Generic[Unpack[Ts]]): # E: "Union[int, str]" cannot be unpacked (must be tuple or TypeVarTuple) + ... + +x: MyTuple[int, str] +reveal_type(x[0]) # N: Revealed type is "Any" +[builtins fixtures/tuple.pyi]