Skip to content

Commit 41fd871

Browse files
authored
Fix fine-grained dependency to "__call__" (#8494)
Also fix the inferred type of a callee when we use `__call__`. Previously we stored the callable type inferred from `__call__`, which is incorrect. Fixes #8489.
1 parent df288e4 commit 41fd871

File tree

3 files changed

+65
-2
lines changed

3 files changed

+65
-2
lines changed

mypy/checkexpr.py

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -892,8 +892,13 @@ def check_call(self,
892892
# Apply method signature hook, if one exists
893893
call_function = self.transform_callee_type(
894894
callable_name, call_function, args, arg_kinds, context, arg_names, callee)
895-
return self.check_call(call_function, args, arg_kinds, context, arg_names,
896-
callable_node, arg_messages, callable_name, callee)
895+
result = self.check_call(call_function, args, arg_kinds, context, arg_names,
896+
callable_node, arg_messages, callable_name, callee)
897+
if callable_node:
898+
# check_call() stored "call_function" as the type, which is incorrect.
899+
# Override the type.
900+
self.chk.store_type(callable_node, callee)
901+
return result
897902
elif isinstance(callee, TypeVarType):
898903
return self.check_call(callee.upper_bound, args, arg_kinds, context, arg_names,
899904
callable_node, arg_messages)

mypy/server/deps.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -661,6 +661,11 @@ def visit_call_expr(self, e: CallExpr) -> None:
661661
self.process_isinstance_call(e)
662662
else:
663663
super().visit_call_expr(e)
664+
typ = self.type_map.get(e.callee)
665+
if typ is not None:
666+
typ = get_proper_type(typ)
667+
if not isinstance(typ, FunctionLike):
668+
self.add_attribute_dependency(typ, '__call__')
664669

665670
def process_isinstance_call(self, e: CallExpr) -> None:
666671
"""Process "isinstance(...)" in a way to avoid some extra dependencies."""

test-data/unit/fine-grained.test

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9594,3 +9594,56 @@ class N(p.util.Test):
95949594
[builtins fixtures/list.pyi]
95959595
[out]
95969596
==
9597+
9598+
[case testDunderCall1]
9599+
from a import C
9600+
9601+
c = C()
9602+
c(1)
9603+
9604+
[file a.py]
9605+
class C:
9606+
def __call__(self, x: int) -> None: ...
9607+
9608+
[file a.py.2]
9609+
class C:
9610+
def __call__(self, x: str) -> None: ...
9611+
9612+
[out]
9613+
==
9614+
main:4: error: Argument 1 to "__call__" of "C" has incompatible type "int"; expected "str"
9615+
9616+
[case testDunderCall2]
9617+
from a import C
9618+
9619+
C()(1)
9620+
9621+
[file a.py]
9622+
class C:
9623+
def __call__(self, x: int) -> None: ...
9624+
9625+
[file a.py.2]
9626+
class C:
9627+
def __call__(self, x: str) -> None: ...
9628+
9629+
[out]
9630+
==
9631+
main:3: error: Argument 1 to "__call__" of "C" has incompatible type "int"; expected "str"
9632+
9633+
[case testDunderCallAddition]
9634+
from a import C
9635+
9636+
c = C()
9637+
x = c() # type: ignore
9638+
x + 42
9639+
9640+
[file a.py]
9641+
class C: ...
9642+
9643+
[file a.py.2]
9644+
class C:
9645+
def __call__(self) -> str: ...
9646+
9647+
[out]
9648+
==
9649+
main:5: error: Unsupported left operand type for + ("str")

0 commit comments

Comments
 (0)