From e8b0554b2ba0bad884d619084b2561aaaae048a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?B=C3=A9n=C3=A9dikt=20Tran?= <10796600+picnixz@users.noreply.github.com> Date: Thu, 1 Feb 2024 15:34:06 +0100 Subject: [PATCH 1/2] Fix type comments crash inside generic definitions --- mypy/expandtype.py | 12 +++++- test-data/unit/check-typevar-values.test | 52 ++++++++++++++++++++++++ 2 files changed, 63 insertions(+), 1 deletion(-) diff --git a/mypy/expandtype.py b/mypy/expandtype.py index f6aa74add9d8..160b1011fef5 100644 --- a/mypy/expandtype.py +++ b/mypy/expandtype.py @@ -2,7 +2,7 @@ from typing import Final, Iterable, Mapping, Sequence, TypeVar, cast, overload -from mypy.nodes import ARG_STAR, Var +from mypy.nodes import ARG_STAR, FakeInfo, Var from mypy.state import state from mypy.types import ( ANY_STRATEGY, @@ -212,6 +212,16 @@ def visit_erased_type(self, t: ErasedType) -> Type: def visit_instance(self, t: Instance) -> Type: args = self.expand_types_with_unpack(list(t.args)) + + if isinstance(t.type, FakeInfo): + # The type checker expands function definitions and bodies + # if they depend on constrained type variables but the body + # might contain a tuple type comment (e.g., # type: (int, float)), + # in which case 't.type' is not yet available. + # + # See: https://github.com/python/mypy/issues/16649 + return t.copy_modified(args=args) + if t.type.fullname == "builtins.tuple": # Normalize Tuple[*Tuple[X, ...], ...] -> Tuple[X, ...] arg = args[0] diff --git a/test-data/unit/check-typevar-values.test b/test-data/unit/check-typevar-values.test index effaf620f1f0..4ab65f1522e1 100644 --- a/test-data/unit/check-typevar-values.test +++ b/test-data/unit/check-typevar-values.test @@ -706,3 +706,55 @@ Func = Callable[[], T] class A: ... class B: ... + +[case testTypeCommentInGenericTypeWithConstrainedTypeVar] +from typing import Generic, TypeVar + +NT = TypeVar("NT", int, float) + +class Foo1(Generic[NT]): + p = 1 # type: int + +class Foo2(Generic[NT]): + p, q = 1, 2.0 # type: (int, float) + +class Foo3(Generic[NT]): + def bar(self) -> None: + p = 1 # type: int + +class Foo4(Generic[NT]): + def bar(self) -> None: + p, q = 1, 2.0 # type: (int, float) + +def foo3(x: NT) -> None: + p = 1 # type: int + +def foo4(x: NT) -> None: + p, q = 1, 2.0 # type: (int, float) +[builtins fixtures/tuple.pyi] + +[case testTypeCommentInGenericTypeWithBoundedTypeVar] +from typing import Generic, TypeVar + +NT = TypeVar("NT", bound=int) + +class Foo1(Generic[NT]): + p = 1 # type: int + +class Foo2(Generic[NT]): + p, q = 1, 2.0 # type: (int, float) + +class Foo3(Generic[NT]): + def bar(self) -> None: + p = 1 # type: int + +class Foo4(Generic[NT]): + def bar(self) -> None: + p, q = 1, 2.0 # type: (int, float) + +def foo3(x: NT) -> None: + p = 1 # type: int + +def foo4(x: NT) -> None: + p, q = 1, 2.0 # type: (int, float) +[builtins fixtures/tuple.pyi] From 472fcf100d7272573865cfae4478fe2af8988808 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?B=C3=A9n=C3=A9dikt=20Tran?= <10796600+picnixz@users.noreply.github.com> Date: Thu, 1 Feb 2024 15:44:13 +0100 Subject: [PATCH 2/2] remove unnecessary test --- test-data/unit/check-typevar-values.test | 26 ------------------------ 1 file changed, 26 deletions(-) diff --git a/test-data/unit/check-typevar-values.test b/test-data/unit/check-typevar-values.test index 4ab65f1522e1..8b961d88d23d 100644 --- a/test-data/unit/check-typevar-values.test +++ b/test-data/unit/check-typevar-values.test @@ -732,29 +732,3 @@ def foo3(x: NT) -> None: def foo4(x: NT) -> None: p, q = 1, 2.0 # type: (int, float) [builtins fixtures/tuple.pyi] - -[case testTypeCommentInGenericTypeWithBoundedTypeVar] -from typing import Generic, TypeVar - -NT = TypeVar("NT", bound=int) - -class Foo1(Generic[NT]): - p = 1 # type: int - -class Foo2(Generic[NT]): - p, q = 1, 2.0 # type: (int, float) - -class Foo3(Generic[NT]): - def bar(self) -> None: - p = 1 # type: int - -class Foo4(Generic[NT]): - def bar(self) -> None: - p, q = 1, 2.0 # type: (int, float) - -def foo3(x: NT) -> None: - p = 1 # type: int - -def foo4(x: NT) -> None: - p, q = 1, 2.0 # type: (int, float) -[builtins fixtures/tuple.pyi]