115115 ReturnStmt ,
116116 StarExpr ,
117117 Statement ,
118+ SymbolNode ,
118119 SymbolTable ,
119120 SymbolTableNode ,
120121 TempNode ,
@@ -1720,6 +1721,7 @@ def check_method_override_for_base_with_name(
17201721 context = defn .func
17211722
17221723 # Construct the type of the overriding method.
1724+ # TODO: this logic is much less complete than similar one in checkmember.py
17231725 if isinstance (defn , (FuncDef , OverloadedFuncDef )):
17241726 typ : Type = self .function_type (defn )
17251727 override_class_or_static = defn .is_class or defn .is_static
@@ -1769,15 +1771,37 @@ def check_method_override_for_base_with_name(
17691771 original_class_or_static = fdef .is_class or fdef .is_static
17701772 else :
17711773 original_class_or_static = False # a variable can't be class or static
1774+
1775+ if isinstance (original_type , FunctionLike ):
1776+ original_type = self .bind_and_map_method (base_attr , original_type , defn .info , base )
1777+ if original_node and is_property (original_node ):
1778+ original_type = get_property_type (original_type )
1779+
1780+ if isinstance (typ , FunctionLike ) and is_property (defn ):
1781+ typ = get_property_type (typ )
1782+ if (
1783+ isinstance (original_node , Var )
1784+ and not original_node .is_final
1785+ and (not original_node .is_property or original_node .is_settable_property )
1786+ and isinstance (defn , Decorator )
1787+ ):
1788+ # We only give an error where no other similar errors will be given.
1789+ if not isinstance (original_type , AnyType ):
1790+ self .msg .fail (
1791+ "Cannot override writeable attribute with read-only property" ,
1792+ # Give an error on function line to match old behaviour.
1793+ defn .func ,
1794+ code = codes .OVERRIDE ,
1795+ )
1796+
17721797 if isinstance (original_type , AnyType ) or isinstance (typ , AnyType ):
17731798 pass
17741799 elif isinstance (original_type , FunctionLike ) and isinstance (typ , FunctionLike ):
1775- original = self .bind_and_map_method (base_attr , original_type , defn .info , base )
17761800 # Check that the types are compatible.
17771801 # TODO overloaded signatures
17781802 self .check_override (
17791803 typ ,
1780- original ,
1804+ original_type ,
17811805 defn .name ,
17821806 name ,
17831807 base .name ,
@@ -1792,8 +1816,8 @@ def check_method_override_for_base_with_name(
17921816 #
17931817 pass
17941818 elif (
1795- base_attr . node
1796- and not self .is_writable_attribute (base_attr . node )
1819+ original_node
1820+ and not self .is_writable_attribute (original_node )
17971821 and is_subtype (typ , original_type )
17981822 ):
17991823 # If the attribute is read-only, allow covariance
@@ -4311,7 +4335,8 @@ def visit_decorator(self, e: Decorator) -> None:
43114335 if len ([k for k in sig .arg_kinds if k .is_required ()]) > 1 :
43124336 self .msg .fail ("Too many arguments for property" , e )
43134337 self .check_incompatible_property_override (e )
4314- if e .func .info and not e .func .is_dynamic ():
4338+ # For overloaded functions we already checked override for overload as a whole.
4339+ if e .func .info and not e .func .is_dynamic () and not e .is_overload :
43154340 self .check_method_override (e )
43164341
43174342 if e .func .info and e .func .name in ("__init__" , "__new__" ):
@@ -6066,6 +6091,8 @@ def conditional_types_with_intersection(
60666091 def is_writable_attribute (self , node : Node ) -> bool :
60676092 """Check if an attribute is writable"""
60686093 if isinstance (node , Var ):
6094+ if node .is_property and not node .is_settable_property :
6095+ return False
60696096 return True
60706097 elif isinstance (node , OverloadedFuncDef ) and node .is_property :
60716098 first_item = cast (Decorator , node .items [0 ])
@@ -6973,6 +7000,23 @@ def is_static(func: FuncBase | Decorator) -> bool:
69737000 assert False , f"Unexpected func type: { type (func )} "
69747001
69757002
7003+ def is_property (defn : SymbolNode ) -> bool :
7004+ if isinstance (defn , Decorator ):
7005+ return defn .func .is_property
7006+ if isinstance (defn , OverloadedFuncDef ):
7007+ if defn .items and isinstance (defn .items [0 ], Decorator ):
7008+ return defn .items [0 ].func .is_property
7009+ return False
7010+
7011+
7012+ def get_property_type (t : ProperType ) -> ProperType :
7013+ if isinstance (t , CallableType ):
7014+ return get_proper_type (t .ret_type )
7015+ if isinstance (t , Overloaded ):
7016+ return get_proper_type (t .items [0 ].ret_type )
7017+ return t
7018+
7019+
69767020def is_subtype_no_promote (left : Type , right : Type ) -> bool :
69777021 return is_subtype (left , right , ignore_promotions = True )
69787022
0 commit comments