From d4f863e7a3f1ce3c36acbbe133d515f639d86f62 Mon Sep 17 00:00:00 2001 From: Ivan Levkivskyi Date: Sun, 4 Oct 2026 01:11:40 +0100 Subject: [PATCH] Fix unnormalized tuple in deferred type alias --- mypy/semanal.py | 12 ++++++++---- test-data/unit/check-python312.test | 11 +++++++++++ test-data/unit/check-typevar-tuple.test | 13 +++++++++++++ 3 files changed, 32 insertions(+), 4 deletions(-) diff --git a/mypy/semanal.py b/mypy/semanal.py index 5ef5223c2346..251e4115bd66 100644 --- a/mypy/semanal.py +++ b/mypy/semanal.py @@ -5904,7 +5904,9 @@ def visit_type_alias_stmt(self, s: TypeAliasStmt) -> None: python_3_12_type_alias=True, ) alias_node.default_depends = default_depends - s.alias_node = alias_node + if s.alias_node is None: + # If there is an existing node, it will be modified in-place. + s.alias_node = alias_node updated = False if ( @@ -6329,9 +6331,11 @@ def analyze_type_application(self, expr: IndexExpr) -> None: if types is None: return base = expr.base - expr.analyzed = TypeApplication(base, types) - expr.analyzed.line = expr.line - expr.analyzed.column = expr.column + if not isinstance(expr.analyzed, TypeAliasExpr): + # Do not re-point r.h.s. of a type alias, it is all set. + expr.analyzed = TypeApplication(base, types) + expr.analyzed.line = expr.line + expr.analyzed.column = expr.column if isinstance(base, RefExpr) and base.fullname == "librt.vecs.vec": # Apply restrictions specific to vec diff --git a/test-data/unit/check-python312.test b/test-data/unit/check-python312.test index 9d32689a1e98..19b4f1d8b1f1 100644 --- a/test-data/unit/check-python312.test +++ b/test-data/unit/check-python312.test @@ -2401,3 +2401,14 @@ reveal_type(baz(objs)) # N: Revealed type is "builtins.list[__main__.B | __main reveal_type(baz(objs_a)) # N: Revealed type is "builtins.list[__main__.B | __main__.C]" [builtins fixtures/tuple.pyi] [typing fixtures/typing-full.pyi] + +[case testDeferredNestedTupleAliasNewSyntax] +type Inner = tuple[int, str] +type Outer = tuple[bool, *Inner] + +class K(Base): + q: list[Outer] = list() + +class Base: ... +reveal_type(K.q) # N: Revealed type is "builtins.list[tuple[builtins.bool, builtins.int, builtins.str]]" +[builtins fixtures/tuple.pyi] diff --git a/test-data/unit/check-typevar-tuple.test b/test-data/unit/check-typevar-tuple.test index 232d516da85b..37863e6b979f 100644 --- a/test-data/unit/check-typevar-tuple.test +++ b/test-data/unit/check-typevar-tuple.test @@ -3232,3 +3232,16 @@ def foo(x, *args): def test(f: Callable[[object], object]) -> None: ... test(foo) # E: Argument 1 to "test" has incompatible type overloaded function; expected "Callable[[object], object]" [builtins fixtures/tuple.pyi] + +[case testDeferredNestedTupleAlias] +from typing import Unpack + +Inner = tuple[int, str] +Outer = tuple[bool, Unpack[Inner]] + +class K(Base): + q: list[Outer] = list() + +class Base: ... +reveal_type(K.q) # N: Revealed type is "builtins.list[tuple[builtins.bool, builtins.int, builtins.str]]" +[builtins fixtures/tuple.pyi]