@@ -477,21 +477,17 @@ def visit_instance(self, left: Instance) -> bool:
477477 return self ._is_subtype (left , unpacked )
478478 if left .type .has_base (right .partial_fallback .type .fullname ):
479479 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).
482484 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
495491 return False
496492 if isinstance (right , TypeVarTupleType ):
497493 # 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:
559555 right_args = (
560556 right_prefix + (TupleType (list (right_middle ), fallback ),) + right_suffix
561557 )
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
575560 if len (left_args ) != len (right_args ):
576561 return False
577562 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:
21762161 ]
21772162 )
21782163 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