diff --git a/mypy/checker.py b/mypy/checker.py index bf34c755f716..f009a668b2be 100644 --- a/mypy/checker.py +++ b/mypy/checker.py @@ -1221,22 +1221,32 @@ def check_method_override_for_base_with_name( # Construct the type of the overriding method. if isinstance(defn, FuncBase): typ = self.function_type(defn) # type: Type + override_class_or_static = defn.is_class or defn.is_static else: assert defn.var.is_ready assert defn.var.type is not None typ = defn.var.type + override_class_or_static = defn.func.is_class or defn.func.is_static if isinstance(typ, FunctionLike) and not is_static(context): typ = bind_self(typ, self.scope.active_self_type()) # Map the overridden method type to subtype context so that # it can be checked for compatibility. original_type = base_attr.type + original_node = base_attr.node if original_type is None: - if isinstance(base_attr.node, FuncDef): - original_type = self.function_type(base_attr.node) - elif isinstance(base_attr.node, Decorator): - original_type = self.function_type(base_attr.node.func) + if isinstance(original_node, FuncBase): + original_type = self.function_type(original_node) + elif isinstance(original_node, Decorator): + original_type = self.function_type(original_node.func) else: assert False, str(base_attr.node) + if isinstance(original_node, FuncBase): + original_class_or_static = original_node.is_class or original_node.is_static + elif isinstance(original_node, Decorator): + fdef = original_node.func + original_class_or_static = fdef.is_class or fdef.is_static + else: + original_class_or_static = False # a variable can't be class or static if isinstance(original_type, AnyType) or isinstance(typ, AnyType): pass elif isinstance(original_type, FunctionLike) and isinstance(typ, FunctionLike): @@ -1253,6 +1263,8 @@ def check_method_override_for_base_with_name( defn.name(), name, base.name(), + original_class_or_static, + override_class_or_static, context) elif is_equivalent(original_type, typ): # Assume invariance for a non-callable attribute here. Note @@ -1267,6 +1279,8 @@ def check_method_override_for_base_with_name( def check_override(self, override: FunctionLike, original: FunctionLike, name: str, name_in_super: str, supertype: str, + original_class_or_static: bool, + override_class_or_static: bool, node: Context) -> None: """Check a method override with given signatures. @@ -1289,8 +1303,7 @@ def check_override(self, override: FunctionLike, original: FunctionLike, fail = True if isinstance(original, FunctionLike) and isinstance(override, FunctionLike): - if ((original.is_classmethod() or original.is_staticmethod()) and - not (override.is_classmethod() or override.is_staticmethod())): + if original_class_or_static and not override_class_or_static: fail = True if fail: diff --git a/mypy/types.py b/mypy/types.py index 9c5edb3af29c..9075ada907d2 100644 --- a/mypy/types.py +++ b/mypy/types.py @@ -645,12 +645,6 @@ def with_name(self, name: str) -> 'FunctionLike': pass @abstractmethod def get_name(self) -> Optional[str]: pass - @abstractmethod - def is_classmethod(self) -> bool: pass - - @abstractmethod - def is_staticmethod(self) -> bool: pass - FormalArgument = NamedTuple('FormalArgument', [ ('name', Optional[str]), @@ -834,12 +828,6 @@ def with_name(self, name: str) -> 'CallableType': def get_name(self) -> Optional[str]: return self.name - def is_classmethod(self) -> bool: - return isinstance(self.definition, FuncBase) and self.definition.is_class - - def is_staticmethod(self) -> bool: - return isinstance(self.definition, FuncBase) and self.definition.is_static - def max_fixed_args(self) -> int: n = len(self.arg_types) if self.is_var_arg: @@ -1058,12 +1046,6 @@ def with_name(self, name: str) -> 'Overloaded': def get_name(self) -> Optional[str]: return self._items[0].name - def is_classmethod(self) -> bool: - return self._items[0].is_classmethod() - - def is_staticmethod(self) -> bool: - return self._items[0].is_staticmethod() - def accept(self, visitor: 'TypeVisitor[T]') -> T: return visitor.visit_overloaded(self) diff --git a/test-data/unit/check-classes.test b/test-data/unit/check-classes.test index b32f93668502..cad65285ebac 100644 --- a/test-data/unit/check-classes.test +++ b/test-data/unit/check-classes.test @@ -4376,3 +4376,19 @@ class C1(object): main:4: error: Revealed local types are: main:4: error: t: builtins.str main:4: error: y: builtins.float + +[case testClassMethodOverride] +from typing import Callable, Any + +def deco(f: Callable[..., Any]) -> Callable[..., Any]: ... + +class B: + @classmethod + def meth(cls, x: int) -> int: ... + +class C(B): + @classmethod + @deco + def meth(cls, x: int) -> int: ... +[builtins fixtures/classmethod.pyi] +[out]