67
67
IS_CLASSVAR : Final = 2
68
68
IS_CLASS_OR_STATIC : Final = 3
69
69
70
- TypeParameterChecker : _TypeAlias = Callable [[Type , Type , int , bool ], bool ]
70
+ TypeParameterChecker : _TypeAlias = Callable [[Type , Type , int , bool , "SubtypeContext" ], bool ]
71
71
72
72
73
73
class SubtypeContext :
@@ -80,6 +80,7 @@ def __init__(
80
80
ignore_declared_variance : bool = False ,
81
81
# Supported for both proper and non-proper
82
82
ignore_promotions : bool = False ,
83
+ ignore_uninhabited : bool = False ,
83
84
# Proper subtype flags
84
85
erase_instances : bool = False ,
85
86
keep_erased_types : bool = False ,
@@ -89,6 +90,7 @@ def __init__(
89
90
self .ignore_pos_arg_names = ignore_pos_arg_names
90
91
self .ignore_declared_variance = ignore_declared_variance
91
92
self .ignore_promotions = ignore_promotions
93
+ self .ignore_uninhabited = ignore_uninhabited
92
94
self .erase_instances = erase_instances
93
95
self .keep_erased_types = keep_erased_types
94
96
self .options = options
@@ -115,6 +117,7 @@ def is_subtype(
115
117
ignore_pos_arg_names : bool = False ,
116
118
ignore_declared_variance : bool = False ,
117
119
ignore_promotions : bool = False ,
120
+ ignore_uninhabited : bool = False ,
118
121
options : Options | None = None ,
119
122
) -> bool :
120
123
"""Is 'left' subtype of 'right'?
@@ -134,6 +137,7 @@ def is_subtype(
134
137
ignore_pos_arg_names = ignore_pos_arg_names ,
135
138
ignore_declared_variance = ignore_declared_variance ,
136
139
ignore_promotions = ignore_promotions ,
140
+ ignore_uninhabited = ignore_uninhabited ,
137
141
options = options ,
138
142
)
139
143
else :
@@ -143,6 +147,7 @@ def is_subtype(
143
147
ignore_pos_arg_names ,
144
148
ignore_declared_variance ,
145
149
ignore_promotions ,
150
+ ignore_uninhabited ,
146
151
options ,
147
152
}
148
153
), "Don't pass both context and individual flags"
@@ -177,6 +182,7 @@ def is_proper_subtype(
177
182
* ,
178
183
subtype_context : SubtypeContext | None = None ,
179
184
ignore_promotions : bool = False ,
185
+ ignore_uninhabited : bool = False ,
180
186
erase_instances : bool = False ,
181
187
keep_erased_types : bool = False ,
182
188
) -> bool :
@@ -192,12 +198,19 @@ def is_proper_subtype(
192
198
if subtype_context is None :
193
199
subtype_context = SubtypeContext (
194
200
ignore_promotions = ignore_promotions ,
201
+ ignore_uninhabited = ignore_uninhabited ,
195
202
erase_instances = erase_instances ,
196
203
keep_erased_types = keep_erased_types ,
197
204
)
198
205
else :
199
206
assert not any (
200
- {ignore_promotions , erase_instances , keep_erased_types }
207
+ {
208
+ ignore_promotions ,
209
+ ignore_uninhabited ,
210
+ erase_instances ,
211
+ keep_erased_types ,
212
+ ignore_uninhabited ,
213
+ }
201
214
), "Don't pass both context and individual flags"
202
215
if TypeState .is_assumed_proper_subtype (left , right ):
203
216
return True
@@ -215,23 +228,28 @@ def is_equivalent(
215
228
ignore_type_params : bool = False ,
216
229
ignore_pos_arg_names : bool = False ,
217
230
options : Options | None = None ,
231
+ subtype_context : SubtypeContext | None = None ,
218
232
) -> bool :
219
233
return is_subtype (
220
234
a ,
221
235
b ,
222
236
ignore_type_params = ignore_type_params ,
223
237
ignore_pos_arg_names = ignore_pos_arg_names ,
224
238
options = options ,
239
+ subtype_context = subtype_context ,
225
240
) and is_subtype (
226
241
b ,
227
242
a ,
228
243
ignore_type_params = ignore_type_params ,
229
244
ignore_pos_arg_names = ignore_pos_arg_names ,
230
245
options = options ,
246
+ subtype_context = subtype_context ,
231
247
)
232
248
233
249
234
- def is_same_type (a : Type , b : Type , ignore_promotions : bool = True ) -> bool :
250
+ def is_same_type (
251
+ a : Type , b : Type , ignore_promotions : bool = True , subtype_context : SubtypeContext | None = None
252
+ ) -> bool :
235
253
"""Are these types proper subtypes of each other?
236
254
237
255
This means types may have different representation (e.g. an alias, or
@@ -241,8 +259,10 @@ def is_same_type(a: Type, b: Type, ignore_promotions: bool = True) -> bool:
241
259
# considered not the same type (which is the case at runtime).
242
260
# Also Union[bool, int] (if it wasn't simplified before) will be different
243
261
# from plain int, etc.
244
- return is_proper_subtype (a , b , ignore_promotions = ignore_promotions ) and is_proper_subtype (
245
- b , a , ignore_promotions = ignore_promotions
262
+ return is_proper_subtype (
263
+ a , b , ignore_promotions = ignore_promotions , subtype_context = subtype_context
264
+ ) and is_proper_subtype (
265
+ b , a , ignore_promotions = ignore_promotions , subtype_context = subtype_context
246
266
)
247
267
248
268
@@ -306,23 +326,34 @@ def check_item(left: Type, right: Type, subtype_context: SubtypeContext) -> bool
306
326
return left .accept (SubtypeVisitor (orig_right , subtype_context , proper_subtype ))
307
327
308
328
309
- # TODO: should we pass on the original flags here and in couple other places?
310
- # This seems logical but was never done in the past for some reasons.
311
- def check_type_parameter ( lefta : Type , righta : Type , variance : int , proper_subtype : bool ) -> bool :
329
+ def check_type_parameter (
330
+ lefta : Type , righta : Type , variance : int , proper_subtype : bool , subtype_context : SubtypeContext
331
+ ) -> bool :
312
332
def check (left : Type , right : Type ) -> bool :
313
- return is_proper_subtype (left , right ) if proper_subtype else is_subtype (left , right )
333
+ return (
334
+ is_proper_subtype (left , right , subtype_context = subtype_context )
335
+ if proper_subtype
336
+ else is_subtype (left , right , subtype_context = subtype_context )
337
+ )
314
338
315
339
if variance == COVARIANT :
316
340
return check (lefta , righta )
317
341
elif variance == CONTRAVARIANT :
318
342
return check (righta , lefta )
319
343
else :
320
344
if proper_subtype :
321
- return is_same_type (lefta , righta )
322
- return is_equivalent (lefta , righta )
345
+ # We pass ignore_promotions=False because it is a default for subtype checks.
346
+ # The actual value will be taken from the subtype_context, and it is whatever
347
+ # the original caller passed.
348
+ return is_same_type (
349
+ lefta , righta , ignore_promotions = False , subtype_context = subtype_context
350
+ )
351
+ return is_equivalent (lefta , righta , subtype_context = subtype_context )
323
352
324
353
325
- def ignore_type_parameter (lefta : Type , righta : Type , variance : int , proper_subtype : bool ) -> bool :
354
+ def ignore_type_parameter (
355
+ lefta : Type , righta : Type , variance : int , proper_subtype : bool , subtype_context : SubtypeContext
356
+ ) -> bool :
326
357
return True
327
358
328
359
@@ -385,7 +416,11 @@ def visit_none_type(self, left: NoneType) -> bool:
385
416
return True
386
417
387
418
def visit_uninhabited_type (self , left : UninhabitedType ) -> bool :
388
- return True
419
+ # We ignore this for unsafe overload checks, so that and empty list and
420
+ # a list of int will be considered non-overlapping.
421
+ if isinstance (self .right , UninhabitedType ):
422
+ return True
423
+ return not self .subtype_context .ignore_uninhabited
389
424
390
425
def visit_erased_type (self , left : ErasedType ) -> bool :
391
426
# This may be encountered during type inference. The result probably doesn't
@@ -521,12 +556,12 @@ def check_mixed(
521
556
for lefta , righta , tvar in type_params :
522
557
if isinstance (tvar , TypeVarType ):
523
558
if not self .check_type_parameter (
524
- lefta , righta , tvar .variance , self .proper_subtype
559
+ lefta , righta , tvar .variance , self .proper_subtype , self . subtype_context
525
560
):
526
561
nominal = False
527
562
else :
528
563
if not self .check_type_parameter (
529
- lefta , righta , COVARIANT , self .proper_subtype
564
+ lefta , righta , COVARIANT , self .proper_subtype , self . subtype_context
530
565
):
531
566
nominal = False
532
567
if nominal :
@@ -694,6 +729,7 @@ def visit_typeddict_type(self, left: TypedDictType) -> bool:
694
729
if not left .names_are_wider_than (right ):
695
730
return False
696
731
for name , l , r in left .zip (right ):
732
+ # TODO: should we pass on the full subtype_context here and below?
697
733
if self .proper_subtype :
698
734
check = is_same_type (l , r )
699
735
else :
0 commit comments