diff --git a/mypy/checker.py b/mypy/checker.py index 36751bbc9b15d..7189b3d96fafb 100644 --- a/mypy/checker.py +++ b/mypy/checker.py @@ -1536,6 +1536,16 @@ def check_method_override_for_base_with_name( original_type = self.function_type(original_node) elif isinstance(original_node, Decorator): original_type = self.function_type(original_node.func) + elif isinstance(original_node, Var): + # Super type can define method as an attribute. + # See https://github.com/python/mypy/issues/10134 + + # We also check that sometimes `original_node.type` is None. + # This is the case when we use something like `__hash__ = None`. + if original_node.type is not None: + original_type = get_proper_type(original_node.type) + else: + original_type = NoneType() else: assert False, str(base_attr.node) if isinstance(original_node, (FuncDef, OverloadedFuncDef)): diff --git a/test-data/unit/check-classes.test b/test-data/unit/check-classes.test index 21dae9201c018..b15f9f77f3c7a 100644 --- a/test-data/unit/check-classes.test +++ b/test-data/unit/check-classes.test @@ -114,6 +114,43 @@ class A: A().f = None # E: Cannot assign to a method +[case testOverrideAttributeWithMethod] +# This was crashing: +# https://github.com/python/mypy/issues/10134 +from typing import Protocol + +class Base: + __hash__ = None + +class Derived(Base): + def __hash__(self) -> int: # E: Signature of "__hash__" incompatible with supertype "Base" + pass + +# Correct: + +class CallableProtocol(Protocol): + def __call__(self, arg: int) -> int: + pass + +class CorrectBase: + attr: CallableProtocol + +class CorrectDerived(CorrectBase): + def attr(self, arg: int) -> int: + pass + +[case testOverrideMethodWithAttribute] +# The reverse should not crash as well: +from typing import Callable + +class Base: + def __hash__(self) -> int: + pass + +class Derived(Base): + __hash__ = 1 # E: Incompatible types in assignment (expression has type "int", base class "Base" defined the type as "Callable[[Base], int]") + + -- Attributes -- ----------