@@ -641,7 +641,9 @@ def _visit_overloaded_func_def(self, defn: OverloadedFuncDef) -> None:
641641 if defn .impl :
642642 defn .impl .accept (self )
643643 if defn .info :
644- self .check_method_override (defn )
644+ found_base_method = self .check_method_override (defn )
645+ if defn .is_explicit_override and found_base_method is False :
646+ self .msg .no_overridable_method (defn .name , defn )
645647 self .check_inplace_operator_method (defn )
646648 if not defn .is_property :
647649 self .check_overlapping_overloads (defn )
@@ -1807,25 +1809,35 @@ def expand_typevars(
18071809 else :
18081810 return [(defn , typ )]
18091811
1810- def check_method_override (self , defn : FuncDef | OverloadedFuncDef | Decorator ) -> None :
1812+ def check_method_override (self , defn : FuncDef | OverloadedFuncDef | Decorator ) -> bool | None :
18111813 """Check if function definition is compatible with base classes.
18121814
18131815 This may defer the method if a signature is not available in at least one base class.
1816+ Return ``None`` if that happens.
1817+
1818+ Return ``True`` if an attribute with the method name was found in the base class.
18141819 """
18151820 # Check against definitions in base classes.
1821+ found_base_method = False
18161822 for base in defn .info .mro [1 :]:
1817- if self .check_method_or_accessor_override_for_base (defn , base ):
1823+ result = self .check_method_or_accessor_override_for_base (defn , base )
1824+ if result is None :
18181825 # Node was deferred, we will have another attempt later.
1819- return
1826+ return None
1827+ found_base_method |= result
1828+ return found_base_method
18201829
18211830 def check_method_or_accessor_override_for_base (
18221831 self , defn : FuncDef | OverloadedFuncDef | Decorator , base : TypeInfo
1823- ) -> bool :
1832+ ) -> bool | None :
18241833 """Check if method definition is compatible with a base class.
18251834
1826- Return True if the node was deferred because one of the corresponding
1835+ Return ``None`` if the node was deferred because one of the corresponding
18271836 superclass nodes is not ready.
1837+
1838+ Return ``True`` if an attribute with the method name was found in the base class.
18281839 """
1840+ found_base_method = False
18291841 if base :
18301842 name = defn .name
18311843 base_attr = base .names .get (name )
@@ -1836,22 +1848,24 @@ def check_method_or_accessor_override_for_base(
18361848 # Second, final can't override anything writeable independently of types.
18371849 if defn .is_final :
18381850 self .check_if_final_var_override_writable (name , base_attr .node , defn )
1851+ found_base_method = True
18391852
18401853 # Check the type of override.
18411854 if name not in ("__init__" , "__new__" , "__init_subclass__" ):
18421855 # Check method override
18431856 # (__init__, __new__, __init_subclass__ are special).
18441857 if self .check_method_override_for_base_with_name (defn , name , base ):
1845- return True
1858+ return None
18461859 if name in operators .inplace_operator_methods :
18471860 # Figure out the name of the corresponding operator method.
18481861 method = "__" + name [3 :]
18491862 # An inplace operator method such as __iadd__ might not be
18501863 # always introduced safely if a base class defined __add__.
18511864 # TODO can't come up with an example where this is
18521865 # necessary; now it's "just in case"
1853- return self .check_method_override_for_base_with_name (defn , method , base )
1854- return False
1866+ if self .check_method_override_for_base_with_name (defn , method , base ):
1867+ return None
1868+ return found_base_method
18551869
18561870 def check_method_override_for_base_with_name (
18571871 self , defn : FuncDef | OverloadedFuncDef | Decorator , name : str , base : TypeInfo
@@ -4715,7 +4729,9 @@ def visit_decorator(self, e: Decorator) -> None:
47154729 self .check_incompatible_property_override (e )
47164730 # For overloaded functions we already checked override for overload as a whole.
47174731 if e .func .info and not e .func .is_dynamic () and not e .is_overload :
4718- self .check_method_override (e )
4732+ found_base_method = self .check_method_override (e )
4733+ if e .func .is_explicit_override and found_base_method is False :
4734+ self .msg .no_overridable_method (e .func .name , e .func )
47194735
47204736 if e .func .info and e .func .name in ("__init__" , "__new__" ):
47214737 if e .type and not isinstance (get_proper_type (e .type ), (FunctionLike , AnyType )):
0 commit comments