Skip to content

Commit 1362212

Browse files
committed
Apply method signature hooks to super calls
1 parent ed90eaf commit 1362212

2 files changed

Lines changed: 36 additions & 0 deletions

File tree

mypy/checkexpr.py

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -610,6 +610,13 @@ def visit_call_expr_inner(self, e: CallExpr, allow_none_return: bool = False) ->
610610
):
611611
member = e.callee.name
612612
object_type = self.chk.lookup_type(e.callee.expr)
613+
elif isinstance(e.callee, SuperExpr):
614+
# SuperExpr is not a RefExpr, so its method cannot be identified from
615+
# the expression node. Use the definition attached to the resolved
616+
# callable instead, just as regular method calls use the defining class.
617+
fullname = self.super_method_fullname(callee_type)
618+
if fullname is not None:
619+
object_type = self.super_method_object_type(e.callee)
613620

614621
if (
615622
self.chk.options.disallow_untyped_calls
@@ -653,6 +660,31 @@ def visit_call_expr_inner(self, e: CallExpr, allow_none_return: bool = False) ->
653660
self.chk.msg.does_not_return_value(callee_type, e)
654661
return ret_type
655662

663+
def super_method_fullname(self, callee_type: Type) -> str | None:
664+
"""Return the defining fullname for a method resolved through super()."""
665+
callee_type = get_proper_type(callee_type)
666+
if isinstance(callee_type, CallableType):
667+
definition = callee_type.definition
668+
return definition.fullname if definition is not None else None
669+
if isinstance(callee_type, Overloaded):
670+
for item in callee_type.items:
671+
if item.definition is not None:
672+
return item.definition.fullname
673+
return None
674+
675+
def super_method_object_type(self, e: SuperExpr) -> Type | None:
676+
"""Return the object type passed to the super() proxy for plugin contexts."""
677+
if len(e.call.args) == 2 and self.chk.has_type(e.call.args[1]):
678+
return self.chk.lookup_type(e.call.args[1])
679+
if e.info is not None:
680+
method = self.chk.scope.current_function()
681+
if method is not None and method.arguments:
682+
instance_type = method.arguments[0].variable.type
683+
if instance_type is not None:
684+
return instance_type
685+
return fill_typevars(e.info)
686+
return None
687+
656688
def check_str_format_call(self, e: CallExpr) -> None:
657689
"""More precise type checking for str.format() calls on literals and folded constants."""
658690
assert isinstance(e.callee, MemberExpr)

test-data/unit/check-custom-plugin.test

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -572,6 +572,10 @@ foo[4] = 5
572572
for x in foo:
573573
reveal_type(x) # N: Revealed type is "builtins.int"
574574

575+
class Bar(Foo):
576+
def super_m(self) -> None:
577+
reveal_type(super().m(2)) # N: Revealed type is "builtins.int"
578+
575579
[file mypy.ini]
576580
\[mypy]
577581
plugins=<ROOT>/test-data/unit/plugins/method_sig_hook.py

0 commit comments

Comments
 (0)