@@ -641,7 +641,9 @@ def _visit_overloaded_func_def(self, defn: OverloadedFuncDef) -> None:
641
641
if defn .impl :
642
642
defn .impl .accept (self )
643
643
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 )
645
647
self .check_inplace_operator_method (defn )
646
648
if not defn .is_property :
647
649
self .check_overlapping_overloads (defn )
@@ -1807,25 +1809,35 @@ def expand_typevars(
1807
1809
else :
1808
1810
return [(defn , typ )]
1809
1811
1810
- def check_method_override (self , defn : FuncDef | OverloadedFuncDef | Decorator ) -> None :
1812
+ def check_method_override (self , defn : FuncDef | OverloadedFuncDef | Decorator ) -> bool | None :
1811
1813
"""Check if function definition is compatible with base classes.
1812
1814
1813
1815
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.
1814
1819
"""
1815
1820
# Check against definitions in base classes.
1821
+ found_base_method = False
1816
1822
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 :
1818
1825
# Node was deferred, we will have another attempt later.
1819
- return
1826
+ return None
1827
+ found_base_method |= result
1828
+ return found_base_method
1820
1829
1821
1830
def check_method_or_accessor_override_for_base (
1822
1831
self , defn : FuncDef | OverloadedFuncDef | Decorator , base : TypeInfo
1823
- ) -> bool :
1832
+ ) -> bool | None :
1824
1833
"""Check if method definition is compatible with a base class.
1825
1834
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
1827
1836
superclass nodes is not ready.
1837
+
1838
+ Return ``True`` if an attribute with the method name was found in the base class.
1828
1839
"""
1840
+ found_base_method = False
1829
1841
if base :
1830
1842
name = defn .name
1831
1843
base_attr = base .names .get (name )
@@ -1836,22 +1848,24 @@ def check_method_or_accessor_override_for_base(
1836
1848
# Second, final can't override anything writeable independently of types.
1837
1849
if defn .is_final :
1838
1850
self .check_if_final_var_override_writable (name , base_attr .node , defn )
1851
+ found_base_method = True
1839
1852
1840
1853
# Check the type of override.
1841
1854
if name not in ("__init__" , "__new__" , "__init_subclass__" ):
1842
1855
# Check method override
1843
1856
# (__init__, __new__, __init_subclass__ are special).
1844
1857
if self .check_method_override_for_base_with_name (defn , name , base ):
1845
- return True
1858
+ return None
1846
1859
if name in operators .inplace_operator_methods :
1847
1860
# Figure out the name of the corresponding operator method.
1848
1861
method = "__" + name [3 :]
1849
1862
# An inplace operator method such as __iadd__ might not be
1850
1863
# always introduced safely if a base class defined __add__.
1851
1864
# TODO can't come up with an example where this is
1852
1865
# 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
1855
1869
1856
1870
def check_method_override_for_base_with_name (
1857
1871
self , defn : FuncDef | OverloadedFuncDef | Decorator , name : str , base : TypeInfo
@@ -4715,7 +4729,9 @@ def visit_decorator(self, e: Decorator) -> None:
4715
4729
self .check_incompatible_property_override (e )
4716
4730
# For overloaded functions we already checked override for overload as a whole.
4717
4731
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 )
4719
4735
4720
4736
if e .func .info and e .func .name in ("__init__" , "__new__" ):
4721
4737
if e .type and not isinstance (get_proper_type (e .type ), (FunctionLike , AnyType )):
0 commit comments