From 3be726ff31e4714b4b9f1578fff16d784ad2133d Mon Sep 17 00:00:00 2001 From: cherith <315844584+Cherith1222@users.noreply.github.com> Date: Tue, 6 Oct 2026 11:47:24 +0800 Subject: [PATCH 1/2] Transform inner expression of StarExpr in TreeTransform Functions using value-constrained type variables are checked as copies made by TreeTransform. visit_star_expr reused the original inner expression, so in '(*result,)' the NameExpr kept pointing at the original Var, which is never inferred because only the copies are checked. That produced a spurious has-type error and an Any tuple. Transform the inner expression and preserve the 'valid' flag. Fixes #21693. AI-assisted (Cursor). Not yet reviewed by a human. --- mypy/treetransform.py | 4 +++- test-data/unit/check-typevar-tuple.test | 18 ++++++++++++++++++ 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/mypy/treetransform.py b/mypy/treetransform.py index f33cba1e3c7a6..2c1ce2b19a738 100644 --- a/mypy/treetransform.py +++ b/mypy/treetransform.py @@ -450,7 +450,9 @@ def visit_match_stmt(self, o: MatchStmt) -> MatchStmt: ) def visit_star_expr(self, node: StarExpr) -> StarExpr: - return StarExpr(node.expr) + new = StarExpr(self.expr(node.expr)) + new.valid = node.valid + return new def visit_int_expr(self, node: IntExpr) -> IntExpr: return IntExpr(node.value) diff --git a/test-data/unit/check-typevar-tuple.test b/test-data/unit/check-typevar-tuple.test index 6d8c69a147a3f..0d4ed2cbbc81c 100644 --- a/test-data/unit/check-typevar-tuple.test +++ b/test-data/unit/check-typevar-tuple.test @@ -3255,3 +3255,21 @@ class K(Base): class Base: ... reveal_type(K.q) # N: Revealed type is "builtins.list[tuple[builtins.bool, builtins.int, builtins.str]]" [builtins fixtures/tuple.pyi] + +[case testUnpackTypeVarTupleInFunctionWithConstrainedTypeVar] +from typing import Generic, TypeVar, Tuple +from typing_extensions import TypeVarTuple, Unpack + +T = TypeVar("T") +P = TypeVar("P", int, str) +Ts = TypeVarTuple("Ts") + +class Container(Generic[T, P]): + def foo(self) -> T: ... + +def f(container: Container[Tuple[Unpack[Ts]], P]) -> None: + result = container.foo() + reveal_type(result) # N: Revealed type is "tuple[Unpack[Ts`-1]]" + y = (*result,) + reveal_type(y) # N: Revealed type is "tuple[Unpack[Ts`-1]]" +[builtins fixtures/tuple.pyi] \ No newline at end of file From b0c7abbb0ed32aaf73e94a054f106357765981ca Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Wed, 7 Oct 2026 07:28:23 +0000 Subject: [PATCH 2/2] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- test-data/unit/check-typevar-tuple.test | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test-data/unit/check-typevar-tuple.test b/test-data/unit/check-typevar-tuple.test index 0d4ed2cbbc81c..655a89d8cc813 100644 --- a/test-data/unit/check-typevar-tuple.test +++ b/test-data/unit/check-typevar-tuple.test @@ -3272,4 +3272,4 @@ def f(container: Container[Tuple[Unpack[Ts]], P]) -> None: reveal_type(result) # N: Revealed type is "tuple[Unpack[Ts`-1]]" y = (*result,) reveal_type(y) # N: Revealed type is "tuple[Unpack[Ts`-1]]" -[builtins fixtures/tuple.pyi] \ No newline at end of file +[builtins fixtures/tuple.pyi]