115
115
ReturnStmt ,
116
116
StarExpr ,
117
117
Statement ,
118
+ SymbolNode ,
118
119
SymbolTable ,
119
120
SymbolTableNode ,
120
121
TempNode ,
@@ -1720,6 +1721,7 @@ def check_method_override_for_base_with_name(
1720
1721
context = defn .func
1721
1722
1722
1723
# Construct the type of the overriding method.
1724
+ # TODO: this logic is much less complete than similar one in checkmember.py
1723
1725
if isinstance (defn , (FuncDef , OverloadedFuncDef )):
1724
1726
typ : Type = self .function_type (defn )
1725
1727
override_class_or_static = defn .is_class or defn .is_static
@@ -1769,15 +1771,37 @@ def check_method_override_for_base_with_name(
1769
1771
original_class_or_static = fdef .is_class or fdef .is_static
1770
1772
else :
1771
1773
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
+
1772
1797
if isinstance (original_type , AnyType ) or isinstance (typ , AnyType ):
1773
1798
pass
1774
1799
elif isinstance (original_type , FunctionLike ) and isinstance (typ , FunctionLike ):
1775
- original = self .bind_and_map_method (base_attr , original_type , defn .info , base )
1776
1800
# Check that the types are compatible.
1777
1801
# TODO overloaded signatures
1778
1802
self .check_override (
1779
1803
typ ,
1780
- original ,
1804
+ original_type ,
1781
1805
defn .name ,
1782
1806
name ,
1783
1807
base .name ,
@@ -1792,8 +1816,8 @@ def check_method_override_for_base_with_name(
1792
1816
#
1793
1817
pass
1794
1818
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 )
1797
1821
and is_subtype (typ , original_type )
1798
1822
):
1799
1823
# If the attribute is read-only, allow covariance
@@ -4311,7 +4335,8 @@ def visit_decorator(self, e: Decorator) -> None:
4311
4335
if len ([k for k in sig .arg_kinds if k .is_required ()]) > 1 :
4312
4336
self .msg .fail ("Too many arguments for property" , e )
4313
4337
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 :
4315
4340
self .check_method_override (e )
4316
4341
4317
4342
if e .func .info and e .func .name in ("__init__" , "__new__" ):
@@ -6066,6 +6091,8 @@ def conditional_types_with_intersection(
6066
6091
def is_writable_attribute (self , node : Node ) -> bool :
6067
6092
"""Check if an attribute is writable"""
6068
6093
if isinstance (node , Var ):
6094
+ if node .is_property and not node .is_settable_property :
6095
+ return False
6069
6096
return True
6070
6097
elif isinstance (node , OverloadedFuncDef ) and node .is_property :
6071
6098
first_item = cast (Decorator , node .items [0 ])
@@ -6973,6 +7000,23 @@ def is_static(func: FuncBase | Decorator) -> bool:
6973
7000
assert False , f"Unexpected func type: { type (func )} "
6974
7001
6975
7002
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
+
6976
7020
def is_subtype_no_promote (left : Type , right : Type ) -> bool :
6977
7021
return is_subtype (left , right , ignore_promotions = True )
6978
7022
0 commit comments