@@ -870,15 +870,13 @@ def analyze_var(
870870 mx .msg .read_only_property (name , itype .type , mx .context )
871871 if var .is_classvar :
872872 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 )
879875
876+ # A non-None value indicates that we should actually bind self for this variable.
880877 call_type : ProperType | None = None
881878 if var .is_initialized_in_class and (not is_instance_var (var ) or mx .is_operator ):
879+ typ = get_proper_type (typ )
882880 if isinstance (typ , FunctionLike ) and not typ .is_type_obj ():
883881 call_type = typ
884882 elif var .is_property :
@@ -888,37 +886,23 @@ def analyze_var(
888886 else :
889887 call_type = typ
890888
889+ # Bound variables with callable types are treated like methods
890+ # (these are usually method aliases like __rmul__ = __mul__).
891891 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 )
920902 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 )
922906 else :
923907 if not var .is_ready and not mx .no_deferral :
924908 mx .not_ready_callback (var .name , mx .context )
@@ -937,6 +921,37 @@ def analyze_var(
937921 return result
938922
939923
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+
940955def expand_self_type_if_needed (
941956 t : Type , mx : MemberContext , var : Var , itype : Instance , is_class : bool = False
942957) -> Type :
0 commit comments