55from collections .abc import Sequence
66from typing import TYPE_CHECKING , Callable , cast
77
8- from mypy import meet , message_registry , subtypes
8+ from mypy import message_registry , subtypes
99from mypy .erasetype import erase_typevars
1010from mypy .expandtype import (
1111 expand_self_type ,
@@ -267,7 +267,9 @@ def may_be_awaitable_attribute(
267267 aw_type = mx .chk .get_precise_awaitable_type (typ , local_errors )
268268 if aw_type is None :
269269 return False
270- _ = _analyze_member_access (name , aw_type , mx , override_info )
270+ _ = _analyze_member_access (
271+ name , aw_type , mx .copy_modified (self_type = aw_type ), override_info
272+ )
271273 return not local_errors .has_new_errors ()
272274
273275
@@ -323,7 +325,7 @@ def analyze_instance_member_access(
323325 assert isinstance (getter , Decorator )
324326 if mx .is_lvalue and (len (items := method .items ) > 1 ):
325327 mx .chk .warn_deprecated (items [1 ], mx .context )
326- return analyze_var (name , getter .var , typ , info , mx )
328+ return analyze_var (name , getter .var , typ , mx )
327329
328330 if mx .is_lvalue :
329331 mx .msg .cant_assign_to_method (mx .context )
@@ -340,11 +342,8 @@ def analyze_instance_member_access(
340342 signature = method .type
341343 signature = freshen_all_functions_type_vars (signature )
342344 if not method .is_static :
343- # TODO: use proper treatment of special methods on unions instead
344- # of this hack here and below (i.e. mx.self_type).
345- dispatched_type = meet .meet_types (mx .original_type , typ )
346345 signature = check_self_arg (
347- signature , dispatched_type , method .is_class , mx .context , name , mx .msg
346+ signature , mx . self_type , method .is_class , mx .context , name , mx .msg
348347 )
349348 signature = bind_self (signature , mx .self_type , is_classmethod = method .is_class )
350349 # TODO: should we skip these steps for static methods as well?
@@ -536,7 +535,7 @@ def analyze_member_var_access(
536535 if mx .is_lvalue and not mx .chk .get_final_context ():
537536 check_final_member (name , info , mx .msg , mx .context )
538537
539- return analyze_var (name , v , itype , info , mx , implicit = implicit )
538+ return analyze_var (name , v , itype , mx , implicit = implicit )
540539 elif isinstance (v , FuncDef ):
541540 assert False , "Did not expect a function"
542541 elif isinstance (v , MypyFile ):
@@ -560,12 +559,7 @@ def analyze_member_var_access(
560559 # that the attribute exists
561560 if method and method .info .fullname != "builtins.object" :
562561 bound_method = analyze_decorator_or_funcbase_access (
563- defn = method ,
564- itype = itype ,
565- info = info ,
566- self_type = mx .self_type ,
567- name = method_name ,
568- mx = mx ,
562+ defn = method , itype = itype , name = method_name , mx = mx
569563 )
570564 typ = map_instance_to_supertype (itype , method .info )
571565 getattr_type = get_proper_type (expand_type_by_instance (bound_method , typ ))
@@ -592,12 +586,7 @@ def analyze_member_var_access(
592586 setattr_meth = info .get_method ("__setattr__" )
593587 if setattr_meth and setattr_meth .info .fullname != "builtins.object" :
594588 bound_type = analyze_decorator_or_funcbase_access (
595- defn = setattr_meth ,
596- itype = itype ,
597- info = info ,
598- self_type = mx .self_type ,
599- name = name ,
600- mx = mx .copy_modified (is_lvalue = False ),
589+ defn = setattr_meth , itype = itype , name = name , mx = mx .copy_modified (is_lvalue = False )
601590 )
602591 typ = map_instance_to_supertype (itype , setattr_meth .info )
603592 setattr_type = get_proper_type (expand_type_by_instance (bound_type , typ ))
@@ -683,10 +672,8 @@ def analyze_descriptor_access(
683672 bound_method = analyze_decorator_or_funcbase_access (
684673 defn = dunder_get ,
685674 itype = descriptor_type ,
686- info = descriptor_type .type ,
687- self_type = descriptor_type ,
688675 name = "__get__" ,
689- mx = mx ,
676+ mx = mx . copy_modified ( self_type = descriptor_type ) ,
690677 )
691678
692679 typ = map_instance_to_supertype (descriptor_type , dunder_get .info )
@@ -762,13 +749,7 @@ def is_instance_var(var: Var) -> bool:
762749
763750
764751def analyze_var (
765- name : str ,
766- var : Var ,
767- itype : Instance ,
768- info : TypeInfo ,
769- mx : MemberContext ,
770- * ,
771- implicit : bool = False ,
752+ name : str , var : Var , itype : Instance , mx : MemberContext , * , implicit : bool = False
772753) -> Type :
773754 """Analyze access to an attribute via a Var node.
774755
@@ -807,7 +788,9 @@ def analyze_var(
807788 if isinstance (typ , FunctionLike ) and not typ .is_type_obj ():
808789 call_type = typ
809790 elif var .is_property :
810- call_type = get_proper_type (_analyze_member_access ("__call__" , typ , mx ))
791+ call_type = get_proper_type (
792+ _analyze_member_access ("__call__" , typ , mx .copy_modified (self_type = typ ))
793+ )
811794 else :
812795 call_type = typ
813796
@@ -823,20 +806,12 @@ def analyze_var(
823806 # Class-level function objects and classmethods become bound methods:
824807 # the former to the instance, the latter to the class.
825808 functype : FunctionLike = call_type
826- # Use meet to narrow original_type to the dispatched type.
827- # For example, assume
828- # * A.f: Callable[[A1], None] where A1 <: A (maybe A1 == A)
829- # * B.f: Callable[[B1], None] where B1 <: B (maybe B1 == B)
830- # * x: Union[A1, B1]
831- # In `x.f`, when checking `x` against A1 we assume x is compatible with A
832- # and similarly for B1 when checking against B
833- dispatched_type = meet .meet_types (mx .original_type , itype )
834809 signature = freshen_all_functions_type_vars (functype )
835810 bound = get_proper_type (expand_self_type (var , signature , mx .original_type ))
836811 assert isinstance (bound , FunctionLike )
837812 signature = bound
838813 signature = check_self_arg (
839- signature , dispatched_type , var .is_classmethod , mx .context , name , mx .msg
814+ signature , mx . self_type , var .is_classmethod , mx .context , name , mx .msg
840815 )
841816 signature = bind_self (signature , mx .self_type , var .is_classmethod )
842817 expanded_signature = expand_type_by_instance (signature , itype )
@@ -946,13 +921,9 @@ def check_self_arg(
946921 For example if the method is defined as:
947922 class A:
948923 def f(self: S) -> T: ...
949- then for 'x.f' we check that meet( type(x), A) <: S. If the method is overloaded, we
950- select only overloads items that satisfy this requirement. If there are no matching
924+ then for 'x.f' we check that type(x) <: S. If the method is overloaded, we select
925+ only overloads items that satisfy this requirement. If there are no matching
951926 overloads, an error is generated.
952-
953- Note: dispatched_arg_type uses a meet to select a relevant item in case if the
954- original type of 'x' is a union. This is done because several special methods
955- treat union types in ad-hoc manner, so we can't use MemberContext.self_type yet.
956927 """
957928 items = functype .items
958929 if not items :
@@ -1436,22 +1407,17 @@ def type_object_type(info: TypeInfo, named_type: Callable[[str], Instance]) -> P
14361407
14371408
14381409def analyze_decorator_or_funcbase_access (
1439- defn : Decorator | FuncBase ,
1440- itype : Instance ,
1441- info : TypeInfo ,
1442- self_type : Type | None ,
1443- name : str ,
1444- mx : MemberContext ,
1410+ defn : Decorator | FuncBase , itype : Instance , name : str , mx : MemberContext
14451411) -> Type :
14461412 """Analyzes the type behind method access.
14471413
14481414 The function itself can possibly be decorated.
14491415 See: https://github.com/python/mypy/issues/10409
14501416 """
14511417 if isinstance (defn , Decorator ):
1452- return analyze_var (name , defn .var , itype , info , mx )
1418+ return analyze_var (name , defn .var , itype , mx )
14531419 return bind_self (
1454- function_type (defn , mx .chk .named_type ("builtins.function" )), original_type = self_type
1420+ function_type (defn , mx .chk .named_type ("builtins.function" )), original_type = mx . self_type
14551421 )
14561422
14571423
0 commit comments