8000 Fix crash on Callable self in __call__ (#16453) · python/mypy@f862d3e · GitHub
[go: up one dir, main page]

Skip to content

Commit f862d3e

Browse files
ilevkivskyiJukkaL
authored andcommitted
Fix crash on Callable self in __call__ (#16453)
Fixes #16450 The fix is a bit ad-hoc, but OTOH there is nothing meaningful we can infer in such situation, so it is probably OK.
1 parent fe79a59 commit f862d3e

File tree

2 files changed

+23
-4
lines changed

2 files changed

+23
-4
lines changed

mypy/typeops.py

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -244,15 +244,15 @@ class C(D[E[T]], Generic[T]): ...
244244
return expand_type_by_instance(typ, inst_type)
245245

246246

247-
def supported_self_type(typ: ProperType) -> bool:
247+
def supported_self_type(typ: ProperType, allow_callable: bool = True) -> bool:
248248
"""Is this a supported kind of explicit self-types?
249249
250-
Currently, this means a X or Type[X], where X is an instance or
250+
Currently, this means an X or Type[X], where X is an instance or
251251
a type variable with an instance upper bound.
252252
"""
253253
if isinstance(typ, TypeType):
254254
return supported_self_type(typ.item)
255-
if isinstance(typ, CallableType):
255+
if allow_callable and isinstance(typ, CallableType):
256256
# Special case: allow class callable instead of Type[...] as cls annotation,
257257
# as well as callable self for callback protocols.
258258
return True
@@ -306,7 +306,11 @@ class B(A): pass
306306
self_param_type = get_proper_type(func.arg_types[0])
307307

308308
variables: Sequence[TypeVarLikeType]
309-
if func.variables and supported_self_type(self_param_type):
309+
# Having a def __call__(self: Callable[...], ...) can cause infinite recursion. Although
310+
# this special-casing looks not very principled, there is nothing meaningful we can infer
311+
# from such definition, since it is inherently indefinitely recursive.
312+
allow_callable = func.name is None or not func.name.startswith("__call__ of")
313+
if func.variables and supported_self_type(self_param_type, allow_callable=allow_callable):
310314
from mypy.infer import infer_type_arguments
311315

312316
if original_type is None:

test-data/unit/check-selftype.test

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2056,3 +2056,18 @@ reveal_type(C.copy(c)) # N: Revealed type is "__main__.C[builtins.int, builtins
20562056
B.copy(42) # E: Value of type variable "Self" of "copy" of "B" cannot be "int"
20572057
C.copy(42) # E: Value of type variable "Self" of "copy" of "B" cannot be "int"
20582058
[builtins fixtures/tuple.pyi]
2059+
2060+
[case testRecursiveSelfTypeCallMethodNoCrash]
2061+
from typing import Callable, TypeVar
2062+
2063+
T = TypeVar("T")
2064+
class Partial:
2065+
def __call__(self: Callable[..., T]) -> T: ...
2066+
2067+
class Partial2:
2068+
def __call__(self: Callable[..., T], x: T) -> T: ...
2069+
2070+
p: Partial
2071+
reveal_type(p()) # N: Revealed type is "Never"
2072+
p2: Partial2
2073+
reveal_type(p2(42)) # N: Revealed type is "builtins.int"

0 commit comments

Comments
 (0)
0