Skip to content

Commit

Permalink
Fix type comments crash inside generic definitions (python#16849)
Browse files Browse the repository at this point in the history
Closes python#16649

It's the first time I am contributing to mypy so I am not very familiar
with how it works entirely behind the scene. The issue that I had is
that a crash happens when using tuple type comments inside
functions/classes that depend on a *constrained* type variable.

After investigation, the reason is that the type checker generates all
possible definitions (since constraints are known) and expands the
functions definitions and bodies accordingly. However, by doing so, a
tuple type comment ('# type: (int, float)') would have a FakeInfo, so
`ExpandTypeVisitor` would fail since it queries `t.type.fullname`.

By the way, feel free to change where my test should lie.
  • Loading branch information
picnixz authored Jul 1, 2024
1 parent 9871771 commit 4ae632b
Show file tree
Hide file tree
Showing 2 changed files with 37 additions and 1 deletion.
12 changes: 11 additions & 1 deletion mypy/expandtype.py
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -208,6 +208,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]
Expand Down
26 changes: 26 additions & 0 deletions test-data/unit/check-typevar-values.test
Original file line number Diff line number Diff line change
Expand Up @@ -706,3 +706,29 @@ 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]

0 comments on commit 4ae632b

Please sign in to comment.