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