@@ -45,11 +45,13 @@ def __init__(self,
4545 original_type : Type ,
4646 context : Context ,
4747 msg : MessageBuilder ,
48- chk : 'mypy.checker.TypeChecker' ) -> None :
48+ chk : 'mypy.checker.TypeChecker' ,
49+ self_type : Optional [Type ]) -> None :
4950 self .is_lvalue = is_lvalue
5051 self .is_super = is_super
5152 self .is_operator = is_operator
5253 self .original_type = original_type
54+ self .self_type = self_type or original_type
5355 self .context = context # Error context
5456 self .msg = msg
5557 self .chk = chk
@@ -60,9 +62,16 @@ def builtin_type(self, name: str) -> Instance:
6062 def not_ready_callback (self , name : str , context : Context ) -> None :
6163 self .chk .handle_cannot_determine_type (name , context )
6264
63- def copy_modified (self , messages : MessageBuilder ) -> 'MemberContext' :
64- return MemberContext (self .is_lvalue , self .is_super , self .is_operator ,
65- self .original_type , self .context , messages , self .chk )
65+ def copy_modified (self , * , messages : Optional [MessageBuilder ] = None ,
66+ self_type : Optional [Type ] = None ) -> 'MemberContext' :
67+ mx = MemberContext (self .is_lvalue , self .is_super , self .is_operator ,
68+ self .original_type , self .context , self .msg , self .chk ,
69+ self .self_type )
70+ if messages is not None :
71+ mx .msg = messages
72+ if self_type is not None :
73+ mx .self_type = self_type
74+ return mx
6675
6776
6877def analyze_member_access (name : str ,
@@ -75,7 +84,8 @@ def analyze_member_access(name: str,
7584 original_type : Type ,
7685 chk : 'mypy.checker.TypeChecker' ,
7786 override_info : Optional [TypeInfo ] = None ,
78- in_literal_context : bool = False ) -> Type :
87+ in_literal_context : bool = False ,
88+ self_type : Optional [Type ] = None ) -> Type :
7989 """Return the type of attribute 'name' of 'typ'.
8090
8191 The actual implementation is in '_analyze_member_access' and this docstring
@@ -91,15 +101,18 @@ def analyze_member_access(name: str,
91101 that we have available. When looking for an attribute of 'typ', we may perform
92102 recursive calls targeting the fallback type, and 'typ' may become some supertype
93103 of 'original_type'. 'original_type' is always preserved as the 'typ' type used in
94- the initial, non-recursive call.
104+ the initial, non-recursive call. The 'self_type' is a component of 'original_type'
105+ to which generic self should be bound (a narrower type that has a fallback to instance).
106+ Currently this is used only for union types.
95107 """
96108 mx = MemberContext (is_lvalue ,
97109 is_super ,
98110 is_operator ,
99111 original_type ,
100112 context ,
101113 msg ,
102- chk = chk )
114+ chk = chk ,
115+ self_type = self_type )
103116 result = _analyze_member_access (name , typ , mx , override_info )
104117 if in_literal_context and isinstance (result , Instance ) and result .last_known_value is not None :
105118 return result .last_known_value
@@ -183,7 +196,7 @@ def analyze_instance_member_access(name: str,
183196 # the first argument.
184197 pass
185198 else :
186- signature = bind_self (signature , mx .original_type )
199+ signature = bind_self (signature , mx .self_type )
187200 typ = map_instance_to_supertype (typ , method .info )
188201 member_type = expand_type_by_instance (signature , typ )
189202 freeze_type_vars (member_type )
@@ -263,8 +276,11 @@ def analyze_type_type_member_access(name: str, typ: TypeType, mx: MemberContext)
263276
264277def analyze_union_member_access (name : str , typ : UnionType , mx : MemberContext ) -> Type :
265278 mx .msg .disable_type_names += 1
266- results = [_analyze_member_access (name , subtype , mx )
267- for subtype in typ .relevant_items ()]
279+ results = []
280+ for subtype in typ .relevant_items ():
281+ # Self types should be bound to every individual item of a union.
282+ item_mx = mx .copy_modified (self_type = subtype )
283+ results .append (_analyze_member_access (name , subtype , item_mx ))
268284 mx .msg .disable_type_names -= 1
269285 return UnionType .make_simplified_union (results )
270286
@@ -342,7 +358,7 @@ def analyze_member_var_access(name: str,
342358 # that the attribute exists
343359 if method and method .info .fullname () != 'builtins.object' :
344360 function = function_type (method , mx .builtin_type ('builtins.function' ))
345- bound_method = bind_self (function , mx .original_type )
361+ bound_method = bind_self (function , mx .self_type )
346362 typ = map_instance_to_supertype (itype , method .info )
347363 getattr_type = expand_type_by_instance (bound_method , typ )
348364 if isinstance (getattr_type , CallableType ):
@@ -359,7 +375,7 @@ def analyze_member_var_access(name: str,
359375 setattr_meth = info .get_method ('__setattr__' )
360376 if setattr_meth and setattr_meth .info .fullname () != 'builtins.object' :
361377 setattr_func = function_type (setattr_meth , mx .builtin_type ('builtins.function' ))
362- bound_type = bind_self (setattr_func , mx .original_type )
378+ bound_type = bind_self (setattr_func , mx .self_type )
363379 typ = map_instance_to_supertype (itype , setattr_meth .info )
364380 setattr_type = expand_type_by_instance (bound_type , typ )
365381 if isinstance (setattr_type , CallableType ) and len (setattr_type .arg_types ) > 0 :
@@ -515,7 +531,7 @@ def analyze_var(name: str,
515531 dispatched_type = meet .meet_types (mx .original_type , itype )
516532 check_self_arg (functype , dispatched_type , var .is_classmethod , mx .context , name ,
517533 mx .msg )
518- signature = bind_self (functype , mx .original_type , var .is_classmethod )
534+ signature = bind_self (functype , mx .self_type , var .is_classmethod )
519535 if var .is_property :
520536 # A property cannot have an overloaded type => the cast is fine.
521537 assert isinstance (signature , CallableType )
0 commit comments