@@ -870,15 +870,13 @@ def analyze_var(
870
870
mx .msg .read_only_property (name , itype .type , mx .context )
871
871
if var .is_classvar :
872
872
mx .msg .cant_assign_to_classvar (name , mx .context )
873
- t = freshen_all_functions_type_vars (typ )
874
- t = expand_self_type_if_needed (t , mx , var , original_itype )
875
- t = expand_type_by_instance (t , itype )
876
- freeze_all_type_vars (t )
877
- result = t
878
- typ = get_proper_type (typ )
873
+ # This is the most common case for variables, so start with this.
874
+ result = expand_without_binding (typ , var , itype , original_itype , mx )
879
875
876
+ # A non-None value indicates that we should actually bind self for this variable.
880
877
call_type : ProperType | None = None
881
878
if var .is_initialized_in_class and (not is_instance_var (var ) or mx .is_operator ):
879
+ typ = get_proper_type (typ )
882
880
if isinstance (typ , FunctionLike ) and not typ .is_type_obj ():
883
881
call_type = typ
884
882
elif var .is_property :
@@ -888,37 +886,23 @@ def analyze_var(
888
886
else :
889
887
call_type = typ
890
888
889
+ # Bound variables with callable types are treated like methods
890
+ # (these are usually method aliases like __rmul__ = __mul__).
891
891
if isinstance (call_type , FunctionLike ) and not call_type .is_type_obj ():
892
- if mx .is_lvalue and not mx .suppress_errors :
893
- if var .is_property and not var .is_settable_property :
894
- mx .msg .read_only_property (name , itype .type , mx .context )
895
- elif not var .is_property :
896
- mx .msg .cant_assign_to_method (mx .context )
897
-
898
- if not var .is_staticmethod :
899
- # Class-level function objects and classmethods become bound methods:
900
- # the former to the instance, the latter to the class.
901
- functype : FunctionLike = call_type
902
- signature = freshen_all_functions_type_vars (functype )
903
- bound = get_proper_type (expand_self_type (var , signature , mx .original_type ))
904
- assert isinstance (bound , FunctionLike )
905
- signature = bound
906
- signature = check_self_arg (
907
- signature , mx .self_type , var .is_classmethod , mx .context , name , mx .msg
908
- )
909
- signature = bind_self (signature , mx .self_type , var .is_classmethod )
910
- expanded_signature = expand_type_by_instance (signature , itype )
911
- freeze_all_type_vars (expanded_signature )
912
- if var .is_property :
913
- # A property cannot have an overloaded type => the cast is fine.
914
- assert isinstance (expanded_signature , CallableType )
915
- if var .is_settable_property and mx .is_lvalue and var .setter_type is not None :
916
- # TODO: use check_call() to infer better type, same as for __set__().
917
- result = expanded_signature .arg_types [0 ]
918
- else :
919
- result = expanded_signature .ret_type
892
+ if mx .is_lvalue and not var .is_property and not mx .suppress_errors :
893
+ mx .msg .cant_assign_to_method (mx .context )
894
+
895
+ # Bind the self type for each callable component (when needed).
896
+ if call_type and not var .is_staticmethod :
897
+ bound_items = []
898
+ for ct in call_type .items if isinstance (call_type , UnionType ) else [call_type ]:
899
+ p_ct = get_proper_type (ct )
900
+ if isinstance (p_ct , FunctionLike ) and not p_ct .is_type_obj ():
901
+ item = expand_and_bind_callable (p_ct , var , itype , name , mx )
920
902
else :
921
- result = expanded_signature
903
+ item = expand_without_binding (ct , var , itype , original_itype , mx )
904
+ bound_items .append (item )
905
+ result = UnionType .make_union (bound_items )
922
906
else :
923
907
if not var .is_ready and not mx .no_deferral :
924
908
mx .not_ready_callback (var .name , mx .context )
@@ -937,6 +921,37 @@ def analyze_var(
937
921
return result
938
922
939
923
924
+ def expand_without_binding (
925
+ typ : Type , var : Var , itype : Instance , original_itype : Instance , mx : MemberContext
926
+ ) -> Type :
927
+ typ = freshen_all_functions_type_vars (typ )
928
+ typ = expand_self_type_if_needed (typ , mx , var , original_itype )
929
+ expanded = expand_type_by_instance (typ , itype )
930
+ freeze_all_type_vars (expanded )
931
+ return expanded
932
+
933
+
934
+ def expand_and_bind_callable (
935
+ functype : FunctionLike , var : Var , itype : Instance , name : str , mx : MemberContext
936
+ ) -> Type :
937
+ functype = freshen_all_functions_type_vars (functype )
938
+ typ = get_proper_type (expand_self_type (var , functype , mx .original_type ))
939
+ assert isinstance (typ , FunctionLike )
940
+ typ = check_self_arg (typ , mx .self_type , var .is_classmethod , mx .context , name , mx .msg )
941
+ typ = bind_self (typ , mx .self_type , var .is_classmethod )
942
+ expanded = expand_type_by_instance (typ , itype )
943
+ freeze_all_type_vars (expanded )
944
+ if not var .is_property :
945
+ return expanded
946
+ # TODO: a decorated property can result in Overloaded here.
947
+ assert isinstance (expanded , CallableType )
948
+ if var .is_settable_property and mx .is_lvalue and var .setter_type is not None :
949
+ # TODO: use check_call() to infer better type, same as for __set__().
950
+ return expanded .arg_types [0 ]
951
+ else :
952
+ return expanded .ret_type
953
+
954
+
940
955
def expand_self_type_if_needed (
941
956
t : Type , mx : MemberContext , var : Var , itype : Instance , is_class : bool = False
942
957
) -> Type :
0 commit comments