36
36
37
37
def check_type_parameter (lefta : Type , righta : Type , variance : int ) -> bool :
38
38
if variance == COVARIANT :
39
- return is_subtype (lefta , righta , check_type_parameter )
39
+ return is_subtype (lefta , righta )
40
40
elif variance == CONTRAVARIANT :
41
- return is_subtype (righta , lefta , check_type_parameter )
41
+ return is_subtype (righta , lefta )
42
42
else :
43
- return is_equivalent (lefta , righta , check_type_parameter )
43
+ return is_equivalent (lefta , righta )
44
+
45
+
46
+ def ignore_type_parameter (s : Type , t : Type , v : int ) -> bool :
47
+ return True
44
48
45
49
46
50
def is_subtype (left : Type , right : Type ,
47
- type_parameter_checker : Optional [TypeParameterChecker ] = None ,
48
- * , ignore_pos_arg_names : bool = False ,
51
+ * ,
52
+ ignore_type_params : bool = False ,
53
+ ignore_pos_arg_names : bool = False ,
49
54
ignore_declared_variance : bool = False ,
50
55
ignore_promotions : bool = False ) -> bool :
51
56
"""Is 'left' subtype of 'right'?
@@ -59,15 +64,15 @@ def is_subtype(left: Type, right: Type,
59
64
between the type arguments (e.g., A and B), taking the variance of the
60
65
type var into account.
61
66
"""
62
- type_parameter_checker = type_parameter_checker or check_type_parameter
63
67
if (isinstance (right , AnyType ) or isinstance (right , UnboundType )
64
68
or isinstance (right , ErasedType )):
65
69
return True
66
70
elif isinstance (right , UnionType ) and not isinstance (left , UnionType ):
67
71
# Normally, when 'left' is not itself a union, the only way
68
72
# 'left' can be a subtype of the union 'right' is if it is a
69
73
# subtype of one of the items making up the union.
70
- is_subtype_of_item = any (is_subtype (left , item , type_parameter_checker ,
74
+ is_subtype_of_item = any (is_subtype (left , item ,
75
+ ignore_type_params = ignore_type_params ,
71
76
ignore_pos_arg_names = ignore_pos_arg_names ,
72
77
ignore_declared_variance = ignore_declared_variance ,
73
78
ignore_promotions = ignore_promotions )
@@ -83,69 +88,65 @@ def is_subtype(left: Type, right: Type,
83
88
elif is_subtype_of_item :
84
89
return True
85
90
# otherwise, fall through
86
- return left .accept (SubtypeVisitor (right , type_parameter_checker ,
91
+ return left .accept (SubtypeVisitor (right ,
92
+ ignore_type_params = ignore_type_params ,
87
93
ignore_pos_arg_names = ignore_pos_arg_names ,
88
94
ignore_declared_variance = ignore_declared_variance ,
89
95
ignore_promotions = ignore_promotions ))
90
96
91
97
92
98
def is_subtype_ignoring_tvars (left : Type , right : Type ) -> bool :
93
- def ignore_tvars (s : Type , t : Type , v : int ) -> bool :
94
- return True
95
- return is_subtype (left , right , ignore_tvars )
99
+ return is_subtype (left , right , ignore_type_params = True )
96
100
97
101
98
- def is_equivalent (a : Type ,
99
- b : Type ,
100
- type_parameter_checker : Optional [TypeParameterChecker ] = None ,
102
+ def is_equivalent (a : Type , b : Type ,
101
103
* ,
104
+ ignore_type_params : bool = False ,
102
105
ignore_pos_arg_names : bool = False
103
106
) -> bool :
104
107
return (
105
- is_subtype (a , b , type_parameter_checker , ignore_pos_arg_names = ignore_pos_arg_names )
106
- and is_subtype (b , a , type_parameter_checker , ignore_pos_arg_names = ignore_pos_arg_names ))
108
+ is_subtype (a , b , ignore_type_params = ignore_type_params ,
109
+ ignore_pos_arg_names = ignore_pos_arg_names )
110
+ and is_subtype (b , a , ignore_type_params = ignore_type_params ,
111
+ ignore_pos_arg_names = ignore_pos_arg_names ))
107
112
108
113
109
114
class SubtypeVisitor (TypeVisitor [bool ]):
110
115
111
116
def __init__ (self , right : Type ,
112
- type_parameter_checker : TypeParameterChecker ,
113
- * , ignore_pos_arg_names : bool = False ,
117
+ * ,
118
+ ignore_type_params : bool ,
119
+ ignore_pos_arg_names : bool = False ,
114
120
ignore_declared_variance : bool = False ,
115
121
ignore_promotions : bool = False ) -> None :
116
122
self .right = right
117
- self .check_type_parameter = type_parameter_checker
123
+ self .ignore_type_params = ignore_type_params
118
124
self .ignore_pos_arg_names = ignore_pos_arg_names
119
125
self .ignore_declared_variance = ignore_declared_variance
120
126
self .ignore_promotions = ignore_promotions
127
+ self .check_type_parameter = (ignore_type_parameter if ignore_type_params else
128
+ check_type_parameter )
121
129
self ._subtype_kind = SubtypeVisitor .build_subtype_kind (
122
- type_parameter_checker = type_parameter_checker ,
130
+ ignore_type_params = ignore_type_params ,
123
131
ignore_pos_arg_names = ignore_pos_arg_names ,
124
132
ignore_declared_variance = ignore_declared_variance ,
125
133
ignore_promotions = ignore_promotions )
126
134
127
135
@staticmethod
128
136
def build_subtype_kind (* ,
129
- type_parameter_checker : Optional [ TypeParameterChecker ] = None ,
137
+ ignore_type_params : bool = False ,
130
138
ignore_pos_arg_names : bool = False ,
131
139
ignore_declared_variance : bool = False ,
132
140
ignore_promotions : bool = False ) -> SubtypeKind :
133
- type_parameter_checker = type_parameter_checker or check_type_parameter
134
- return ('subtype' ,
135
- type_parameter_checker ,
141
+ return (False , # is proper subtype?
142
+ ignore_type_params ,
136
143
ignore_pos_arg_names ,
137
144
ignore_declared_variance ,
138
145
ignore_promotions )
139
146
140
- def _lookup_cache (self , left : Instance , right : Instance ) -> bool :
141
- return TypeState .is_cached_subtype_check (self ._subtype_kind , left , right )
142
-
143
- def _record_cache (self , left : Instance , right : Instance ) -> None :
144
- TypeState .record_subtype_cache_entry (self ._subtype_kind , left , right )
145
-
146
147
def _is_subtype (self , left : Type , right : Type ) -> bool :
147
148
return is_subtype (left , right ,
148
- type_parameter_checker = self .check_type_parameter ,
149
+ ignore_type_params = self .ignore_type_params ,
149
150
ignore_pos_arg_names = self .ignore_pos_arg_names ,
150
151
ignore_declared_variance = self .ignore_declared_variance ,
151
152
ignore_promotions = self .ignore_promotions )
@@ -190,12 +191,12 @@ def visit_instance(self, left: Instance) -> bool:
190
191
if isinstance (right , TupleType ) and right .fallback .type .is_enum :
191
192
return self ._is_subtype (left , right .fallback )
192
193
if isinstance (right , Instance ):
193
- if self . _lookup_cache ( left , right ):
194
+ if TypeState . is_cached_subtype_check ( self . _subtype_kind , left , right ):
194
195
return True
195
196
if not self .ignore_promotions :
196
197
for base in left .type .mro :
197
198
if base ._promote and self ._is_subtype (base ._promote , self .right ):
198
- self . _record_cache ( left , right )
199
+ TypeState . record_subtype_cache_entry ( self . _subtype_kind , left , right )
199
200
return True
200
201
rname = right .type .fullname ()
201
202
# Always try a nominal check if possible,
@@ -208,7 +209,7 @@ def visit_instance(self, left: Instance) -> bool:
208
209
for lefta , righta , tvar in
209
210
zip (t .args , right .args , right .type .defn .type_vars ))
210
211
if nominal :
211
- self . _record_cache ( left , right )
212
+ TypeState . record_subtype_cache_entry ( self . _subtype_kind , left , right )
212
213
return nominal
213
214
if right .type .is_protocol and is_protocol_implementation (left , right ):
214
215
return True
@@ -303,7 +304,8 @@ def visit_typeddict_type(self, left: TypedDictType) -> bool:
303
304
if not left .names_are_wider_than (right ):
304
305
return False
305
306
for name , l , r in left .zip (right ):
306
- if not is_equivalent (l , r , self .check_type_parameter ):
307
+ if not is_equivalent (l , r ,
308
+ ignore_type_params = self .ignore_type_params ):
307
309
return False
308
310
# Non-required key is not compatible with a required key since
309
311
# indexing may fail unexpectedly if a required key is missing.
@@ -1033,13 +1035,7 @@ def __init__(self, right: Type, *, ignore_promotions: bool = False) -> None:
1033
1035
1034
1036
@staticmethod
1035
1037
def build_subtype_kind (* , ignore_promotions : bool = False ) -> SubtypeKind :
1036
- return ('subtype_proper' , ignore_promotions )
1037
-
1038
- def _lookup_cache (self , left : Instance , right : Instance ) -> bool :
1039
- return TypeState .is_cached_subtype_check (self ._subtype_kind , left , right )
1040
-
1041
- def _record_cache (self , left : Instance , right : Instance ) -> None :
1042
- TypeState .record_subtype_cache_entry (self ._subtype_kind , left , right )
1038
+ return (True , ignore_promotions )
1043
1039
1044
1040
def _is_proper_subtype (self , left : Type , right : Type ) -> bool :
1045
1041
return is_proper_subtype (left , right , ignore_promotions = self .ignore_promotions )
@@ -1073,12 +1069,12 @@ def visit_deleted_type(self, left: DeletedType) -> bool:
1073
1069
def visit_instance (self , left : Instance ) -> bool :
1074
1070
right = self .right
1075
1071
if isinstance (right , Instance ):
1076
- if self . _lookup_cache ( left , right ):
1072
+ if TypeState . is_cached_subtype_check ( self . _subtype_kind , left , right ):
1077
1073
return True
1078
1074
if not self .ignore_promotions :
1079
1075
for base in left .type .mro :
1080
1076
if base ._promote and self ._is_proper_subtype (base ._promote , right ):
1081
- self . _record_cache ( left , right )
1077
+ TypeState . record_subtype_cache_entry ( self . _subtype_kind , left , right )
1082
1078
return True
1083
1079
1084
1080
if left .type .has_base (right .type .fullname ()):
@@ -1095,7 +1091,7 @@ def check_argument(leftarg: Type, rightarg: Type, variance: int) -> bool:
1095
1091
nominal = all (check_argument (ta , ra , tvar .variance ) for ta , ra , tvar in
1096
1092
zip (left .args , right .args , right .type .defn .type_vars ))
1097
1093
if nominal :
1098
- self . _record_cache ( left , right )
1094
+ TypeState . record_subtype_cache_entry ( self . _subtype_kind , left , right )
1099
1095
return nominal
1100
1096
if (right .type .is_protocol and
1101
1097
is_protocol_implementation (left , right , proper_subtype = True )):
0 commit comments