@@ -97,6 +97,7 @@ def __init__(
97
97
is_self : bool = False ,
98
98
rvalue : Expression | None = None ,
99
99
suppress_errors : bool = False ,
100
+ preserve_type_var_ids : bool = False ,
100
101
) -> None :
101
102
self .is_lvalue = is_lvalue
102
103
self .is_super = is_super
@@ -113,6 +114,10 @@ def __init__(
113
114
assert is_lvalue
114
115
self .rvalue = rvalue
115
116
self .suppress_errors = suppress_errors
117
+ # This attribute is only used to preserve old protocol member access logic.
118
+ # It is needed to avoid infinite recursion in cases involving self-referential
119
+ # generic methods, see find_member() for details. Do not use for other purposes!
120
+ self .preserve_type_var_ids = preserve_type_var_ids
116
121
117
122
def named_type (self , name : str ) -> Instance :
118
123
return self .chk .named_type (name )
@@ -143,6 +148,7 @@ def copy_modified(
143
148
no_deferral = self .no_deferral ,
144
149
rvalue = self .rvalue ,
145
150
suppress_errors = self .suppress_errors ,
151
+ preserve_type_var_ids = self .preserve_type_var_ids ,
146
152
)
147
153
if self_type is not None :
148
154
mx .self_type = self_type
@@ -232,8 +238,6 @@ def analyze_member_access(
232
238
def _analyze_member_access (
233
239
name : str , typ : Type , mx : MemberContext , override_info : TypeInfo | None = None
234
240
) -> Type :
235
- # TODO: This and following functions share some logic with subtypes.find_member;
236
- # consider refactoring.
237
241
typ = get_proper_type (typ )
238
242
if isinstance (typ , Instance ):
239
243
return analyze_instance_member_access (name , typ , mx , override_info )
@@ -358,7 +362,8 @@ def analyze_instance_member_access(
358
362
return AnyType (TypeOfAny .special_form )
359
363
assert isinstance (method .type , Overloaded )
360
364
signature = method .type
361
- signature = freshen_all_functions_type_vars (signature )
365
+ if not mx .preserve_type_var_ids :
366
+ signature = freshen_all_functions_type_vars (signature )
362
367
if not method .is_static :
363
368
if isinstance (method , (FuncDef , OverloadedFuncDef )) and method .is_trivial_self :
364
369
signature = bind_self_fast (signature , mx .self_type )
@@ -943,7 +948,8 @@ def analyze_var(
943
948
def expand_without_binding (
944
949
typ : Type , var : Var , itype : Instance , original_itype : Instance , mx : MemberContext
945
950
) -> Type :
946
- typ = freshen_all_functions_type_vars (typ )
951
+ if not mx .preserve_type_var_ids :
952
+ typ = freshen_all_functions_type_vars (typ )
947
953
typ = expand_self_type_if_needed (typ , mx , var , original_itype )
948
954
expanded = expand_type_by_instance (typ , itype )
949
955
freeze_all_type_vars (expanded )
@@ -958,7 +964,8 @@ def expand_and_bind_callable(
958
964
mx : MemberContext ,
959
965
is_trivial_self : bool ,
960
966
) -> Type :
961
- functype = freshen_all_functions_type_vars (functype )
967
+ if not mx .preserve_type_var_ids :
968
+ functype = freshen_all_functions_type_vars (functype )
962
969
typ = get_proper_type (expand_self_type (var , functype , mx .original_type ))
963
970
assert isinstance (typ , FunctionLike )
964
971
if is_trivial_self :
@@ -1056,10 +1063,12 @@ def f(self: S) -> T: ...
1056
1063
return functype
1057
1064
else :
1058
1065
selfarg = get_proper_type (item .arg_types [0 ])
1059
- # This level of erasure matches the one in checker.check_func_def (),
1060
- # better keep these two checks consistent.
1061
- if subtypes .is_subtype (
1066
+ # This matches similar special-casing in bind_self (), see more details there.
1067
+ self_callable = name == "__call__" and isinstance ( selfarg , CallableType )
1068
+ if self_callable or subtypes .is_subtype (
1062
1069
dispatched_arg_type ,
1070
+ # This level of erasure matches the one in checker.check_func_def(),
1071
+ # better keep these two checks consistent.
1063
1072
erase_typevars (erase_to_bound (selfarg )),
1064
1073
# This is to work around the fact that erased ParamSpec and TypeVarTuple
1065
1074
# callables are not always compatible with non-erased ones both ways.
@@ -1220,9 +1229,6 @@ def analyze_class_attribute_access(
1220
1229
is_classmethod = (is_decorated and cast (Decorator , node .node ).func .is_class ) or (
1221
1230
isinstance (node .node , SYMBOL_FUNCBASE_TYPES ) and node .node .is_class
1222
1231
)
1223
- is_staticmethod = (is_decorated and cast (Decorator , node .node ).func .is_static ) or (
1224
- isinstance (node .node , SYMBOL_FUNCBASE_TYPES ) and node .node .is_static
1225
- )
1226
1232
t = get_proper_type (t )
1227
1233
is_trivial_self = False
1228
1234
if isinstance (node .node , Decorator ):
@@ -1236,8 +1242,7 @@ def analyze_class_attribute_access(
1236
1242
t ,
1237
1243
isuper ,
1238
1244
is_classmethod ,
1239
- is_staticmethod ,
1240
- mx .self_type ,
1245
+ mx ,
1241
1246
original_vars = original_vars ,
1242
1247
is_trivial_self = is_trivial_self ,
1243
1248
)
@@ -1372,8 +1377,7 @@ def add_class_tvars(
1372
1377
t : ProperType ,
1373
1378
isuper : Instance | None ,
1374
1379
is_classmethod : bool ,
1375
- is_staticmethod : bool ,
1376
- original_type : Type ,
1380
+ mx : MemberContext ,
1377
1381
original_vars : Sequence [TypeVarLikeType ] | None = None ,
1378
1382
is_trivial_self : bool = False ,
1379
1383
) -> Type :
@@ -1392,9 +1396,6 @@ class B(A[str]): pass
1392
1396
isuper: Current instance mapped to the superclass where method was defined, this
1393
1397
is usually done by map_instance_to_supertype()
1394
1398
is_classmethod: True if this method is decorated with @classmethod
1395
- is_staticmethod: True if this method is decorated with @staticmethod
1396
- original_type: The value of the type B in the expression B.foo() or the corresponding
1397
- component in case of a union (this is used to bind the self-types)
1398
1399
original_vars: Type variables of the class callable on which the method was accessed
1399
1400
is_trivial_self: if True, we can use fast path for bind_self().
1400
1401
Returns:
@@ -1416,14 +1417,14 @@ class B(A[str]): pass
1416
1417
# (i.e. appear in the return type of the class object on which the method was accessed).
1417
1418
if isinstance (t , CallableType ):
1418
1419
tvars = original_vars if original_vars is not None else []
1419
- t = freshen_all_functions_type_vars (t )
1420
+ if not mx .preserve_type_var_ids :
1421
+ t = freshen_all_functions_type_vars (t )
1420
1422
if is_classmethod :
1421
1423
if is_trivial_self :
1422
- t = bind_self_fast (t , original_type )
1424
+ t = bind_self_fast (t , mx . self_type )
1423
1425
else :
1424
- t = bind_self (t , original_type , is_classmethod = True )
1425
- if is_classmethod or is_staticmethod :
1426
- assert isuper is not None
1426
+ t = bind_self (t , mx .self_type , is_classmethod = True )
1427
+ if isuper is not None :
1427
1428
t = expand_type_by_instance (t , isuper )
1428
1429
freeze_all_type_vars (t )
1429
1430
return t .copy_modified (variables = list (tvars ) + list (t .variables ))
@@ -1432,14 +1433,7 @@ class B(A[str]): pass
1432
1433
[
1433
1434
cast (
1434
1435
CallableType ,
1435
- add_class_tvars (
1436
- item ,
1437
- isuper ,
1438
- is_classmethod ,
1439
- is_staticmethod ,
1440
- original_type ,
1441
- original_vars = original_vars ,
1442
- ),
1436
+ add_class_tvars (item , isuper , is_classmethod , mx , original_vars = original_vars ),
1443
1437
)
1444
1438
for item in t .items
1445
1439
]
0 commit comments