@@ -477,21 +477,17 @@ def visit_instance(self, left: Instance) -> bool:
477
477
return self ._is_subtype (left , unpacked )
478
478
if left .type .has_base (right .partial_fallback .type .fullname ):
479
479
if not self .proper_subtype :
480
- # Special case to consider Foo[*tuple[Any, ...]] (i.e. bare Foo) a
481
- # subtype of Foo[<whatever>], when Foo is user defined variadic tuple type.
480
+ # Special cases to consider:
481
+ # * Plain tuple[Any, ...] instance is a subtype of all tuple types.
482
+ # * Foo[*tuple[Any, ...]] (normalized) instance is a subtype of all
483
+ # tuples with fallback to Foo (e.g. for variadic NamedTuples).
482
484
mapped = map_instance_to_supertype (left , right .partial_fallback .type )
483
- for arg in map (get_proper_type , mapped .args ):
484
- if isinstance (arg , UnpackType ):
485
- unpacked = get_proper_type (arg .type )
486
- if not isinstance (unpacked , Instance ):
487
- break
488
- assert unpacked .type .fullname == "builtins.tuple"
489
- if not isinstance (get_proper_type (unpacked .args [0 ]), AnyType ):
490
- break
491
- elif not isinstance (arg , AnyType ):
492
- break
493
- else :
494
- return True
485
+ if is_erased_instance (mapped ):
486
+ if (
487
+ mapped .type .fullname == "builtins.tuple"
488
+ or mapped .type .has_type_var_tuple_type
489
+ ):
490
+ return True
495
491
return False
496
492
if isinstance (right , TypeVarTupleType ):
497
493
# tuple[Any, ...] is like Any in the world of tuples (see special case above).
@@ -559,19 +555,8 @@ def visit_instance(self, left: Instance) -> bool:
559
555
right_args = (
560
556
right_prefix + (TupleType (list (right_middle ), fallback ),) + right_suffix
561
557
)
562
- if not self .proper_subtype and t .args :
563
- for arg in map (get_proper_type , t .args ):
564
- if isinstance (arg , UnpackType ):
565
- unpacked = get_proper_type (arg .type )
566
- if not isinstance (unpacked , Instance ):
567
- break
568
- assert unpacked .type .fullname == "builtins.tuple"
569
- if not isinstance (get_proper_type (unpacked .args [0 ]), AnyType ):
570
- break
571
- elif not isinstance (arg , AnyType ):
572
- break
573
- else :
574
- return True
558
+ if not self .proper_subtype and is_erased_instance (t ):
559
+ return True
575
560
if len (left_args ) != len (right_args ):
576
561
return False
577
562
type_params = zip (left_args , right_args , right .type .defn .type_vars )
@@ -2176,3 +2161,20 @@ def erase_return_self_types(typ: Type, self_type: Instance) -> Type:
2176
2161
]
2177
2162
)
2178
2163
return typ
2164
+
2165
+
2166
+ def is_erased_instance (t : Instance ) -> bool :
2167
+ """Is this an instance where all args are Any types?"""
2168
+ if not t .args :
2169
+ return False
2170
+ for arg in t .args :
2171
+ if isinstance (arg , UnpackType ):
2172
+ unpacked = get_proper_type (arg .type )
2173
+ if not isinstance (unpacked , Instance ):
2174
+ return False
2175
+ assert unpacked .type .fullname == "builtins.tuple"
2176
+ if not isinstance (get_proper_type (unpacked .args [0 ]), AnyType ):
2177
+ return False
2178
+ elif not isinstance (get_proper_type (arg ), AnyType ):
2179
+ return False
2180
+ return True
0 commit comments