1212import mypy .checkexpr
1313from mypy import errorcodes as codes , join , message_registry , nodes , operators
1414from mypy .binder import ConditionalTypeBinder , Frame , get_declaration
15- from mypy .checkmember import (
16- MemberContext ,
17- analyze_decorator_or_funcbase_access ,
18- analyze_descriptor_access ,
19- analyze_member_access ,
20- )
15+ from mypy .checkmember import analyze_member_access
2116from mypy .checkpattern import PatternChecker
2217from mypy .constraints import SUPERTYPE_OF
2318from mypy .erasetype import erase_type , erase_typevars , remove_instance_last_known_values
@@ -3233,7 +3228,7 @@ def check_assignment(
32333228 )
32343229 else :
32353230 self .try_infer_partial_generic_type_from_assignment (lvalue , rvalue , "=" )
3236- lvalue_type , index_lvalue , inferred = self .check_lvalue (lvalue )
3231+ lvalue_type , index_lvalue , inferred = self .check_lvalue (lvalue , rvalue )
32373232 # If we're assigning to __getattr__ or similar methods, check that the signature is
32383233 # valid.
32393234 if isinstance (lvalue , NameExpr ) and lvalue .node :
@@ -4339,7 +4334,9 @@ def check_multi_assignment_from_iterable(
43394334 else :
43404335 self .msg .type_not_iterable (rvalue_type , context )
43414336
4342- def check_lvalue (self , lvalue : Lvalue ) -> tuple [Type | None , IndexExpr | None , Var | None ]:
4337+ def check_lvalue (
4338+ self , lvalue : Lvalue , rvalue : Expression | None = None
4339+ ) -> tuple [Type | None , IndexExpr | None , Var | None ]:
43434340 lvalue_type = None
43444341 index_lvalue = None
43454342 inferred = None
@@ -4357,7 +4354,7 @@ def check_lvalue(self, lvalue: Lvalue) -> tuple[Type | None, IndexExpr | None, V
43574354 elif isinstance (lvalue , IndexExpr ):
43584355 index_lvalue = lvalue
43594356 elif isinstance (lvalue , MemberExpr ):
4360- lvalue_type = self .expr_checker .analyze_ordinary_member_access (lvalue , True )
4357+ lvalue_type = self .expr_checker .analyze_ordinary_member_access (lvalue , True , rvalue )
43614358 self .store_type (lvalue , lvalue_type )
43624359 elif isinstance (lvalue , NameExpr ):
43634360 lvalue_type = self .expr_checker .analyze_ref_expr (lvalue , lvalue = True )
@@ -4704,12 +4701,8 @@ def check_member_assignment(
47044701
47054702 Return the inferred rvalue_type, inferred lvalue_type, and whether to use the binder
47064703 for this assignment.
4707-
4708- Note: this method exists here and not in checkmember.py, because we need to take
4709- care about interaction between binder and __set__().
47104704 """
47114705 instance_type = get_proper_type (instance_type )
4712- attribute_type = get_proper_type (attribute_type )
47134706 # Descriptors don't participate in class-attribute access
47144707 if (isinstance (instance_type , FunctionLike ) and instance_type .is_type_obj ()) or isinstance (
47154708 instance_type , TypeType
@@ -4721,107 +4714,16 @@ def check_member_assignment(
47214714 get_lvalue_type = self .expr_checker .analyze_ordinary_member_access (
47224715 lvalue , is_lvalue = False
47234716 )
4724- use_binder = is_same_type (get_lvalue_type , attribute_type )
4725-
4726- if not isinstance (attribute_type , Instance ):
4727- # TODO: support __set__() for union types.
4728- rvalue_type , _ = self .check_simple_assignment (attribute_type , rvalue , context )
4729- return rvalue_type , attribute_type , use_binder
4730-
4731- mx = MemberContext (
4732- is_lvalue = False ,
4733- is_super = False ,
4734- is_operator = False ,
4735- original_type = instance_type ,
4736- context = context ,
4737- self_type = None ,
4738- chk = self ,
4739- )
4740- get_type = analyze_descriptor_access (attribute_type , mx , assignment = True )
4741- if not attribute_type .type .has_readable_member ("__set__" ):
4742- # If there is no __set__, we type-check that the assigned value matches
4743- # the return type of __get__. This doesn't match the python semantics,
4744- # (which allow you to override the descriptor with any value), but preserves
4745- # the type of accessing the attribute (even after the override).
4746- rvalue_type , _ = self .check_simple_assignment (get_type , rvalue , context )
4747- return rvalue_type , get_type , use_binder
4748-
4749- dunder_set = attribute_type .type .get_method ("__set__" )
4750- if dunder_set is None :
4751- self .fail (
4752- message_registry .DESCRIPTOR_SET_NOT_CALLABLE .format (
4753- attribute_type .str_with_options (self .options )
4754- ),
4755- context ,
4756- )
4757- return AnyType (TypeOfAny .from_error ), get_type , False
4758-
4759- bound_method = analyze_decorator_or_funcbase_access (
4760- defn = dunder_set ,
4761- itype = attribute_type ,
4762- name = "__set__" ,
4763- mx = mx .copy_modified (self_type = attribute_type ),
4764- )
4765- typ = map_instance_to_supertype (attribute_type , dunder_set .info )
4766- dunder_set_type = expand_type_by_instance (bound_method , typ )
4767-
4768- callable_name = self .expr_checker .method_fullname (attribute_type , "__set__" )
4769- dunder_set_type = self .expr_checker .transform_callee_type (
4770- callable_name ,
4771- dunder_set_type ,
4772- [TempNode (instance_type , context = context ), rvalue ],
4773- [nodes .ARG_POS , nodes .ARG_POS ],
4774- context ,
4775- object_type = attribute_type ,
4776- )
4777-
4778- # For non-overloaded setters, the result should be type-checked like a regular assignment.
4779- # Hence, we first only try to infer the type by using the rvalue as type context.
4780- type_context = rvalue
4781- with self .msg .filter_errors ():
4782- _ , inferred_dunder_set_type = self .expr_checker .check_call (
4783- dunder_set_type ,
4784- [TempNode (instance_type , context = context ), type_context ],
4785- [nodes .ARG_POS , nodes .ARG_POS ],
4786- context ,
4787- object_type = attribute_type ,
4788- callable_name = callable_name ,
4789- )
4790-
4791- # And now we in fact type check the call, to show errors related to wrong arguments
4792- # count, etc., replacing the type context for non-overloaded setters only.
4793- inferred_dunder_set_type = get_proper_type (inferred_dunder_set_type )
4794- if isinstance (inferred_dunder_set_type , CallableType ):
4795- type_context = TempNode (AnyType (TypeOfAny .special_form ), context = context )
4796- self .expr_checker .check_call (
4797- dunder_set_type ,
4798- [TempNode (instance_type , context = context ), type_context ],
4799- [nodes .ARG_POS , nodes .ARG_POS ],
4800- context ,
4801- object_type = attribute_type ,
4802- callable_name = callable_name ,
4803- )
4804-
4805- # Search for possible deprecations:
4806- mx .chk .check_deprecated (dunder_set , mx .context )
4807- mx .chk .warn_deprecated_overload_item (
4808- dunder_set , mx .context , target = inferred_dunder_set_type , selftype = attribute_type
4809- )
48104717
4811- # In the following cases, a message already will have been recorded in check_call.
4812- if (not isinstance (inferred_dunder_set_type , CallableType )) or (
4813- len (inferred_dunder_set_type .arg_types ) < 2
4814- ):
4815- return AnyType (TypeOfAny .from_error ), get_type , False
4816-
4817- set_type = inferred_dunder_set_type .arg_types [1 ]
48184718 # Special case: if the rvalue_type is a subtype of both '__get__' and '__set__' types,
48194719 # and '__get__' type is narrower than '__set__', then we invoke the binder to narrow type
48204720 # by this assignment. Technically, this is not safe, but in practice this is
48214721 # what a user expects.
4822- rvalue_type , _ = self .check_simple_assignment (set_type , rvalue , context )
4823- infer = is_subtype (rvalue_type , get_type ) and is_subtype (get_type , set_type )
4824- return rvalue_type if infer else set_type , get_type , infer
4722+ rvalue_type , _ = self .check_simple_assignment (attribute_type , rvalue , context )
4723+ infer = is_subtype (rvalue_type , get_lvalue_type ) and is_subtype (
4724+ get_lvalue_type , attribute_type
4725+ )
4726+ return rvalue_type if infer else attribute_type , attribute_type , infer
48254727
48264728 def check_indexed_assignment (
48274729 self , lvalue : IndexExpr , rvalue : Expression , context : Context
0 commit comments