diff --git a/mypy/meet.py b/mypy/meet.py index d2fb16808425..610185d6bbbf 100644 --- a/mypy/meet.py +++ b/mypy/meet.py @@ -16,6 +16,7 @@ from mypy.typeops import is_recursive_pair, make_simplified_union, tuple_fallback from mypy.types import ( MYPYC_NATIVE_INT_NAMES, + TUPLE_LIKE_INSTANCE_NAMES, AnyType, CallableType, DeletedType, @@ -936,7 +937,7 @@ def visit_tuple_type(self, t: TupleType) -> ProperType: return TupleType(items, tuple_fallback(t)) elif isinstance(self.s, Instance): # meet(Tuple[t1, t2, <...>], Tuple[s, ...]) == Tuple[meet(t1, s), meet(t2, s), <...>]. - if self.s.type.fullname == "builtins.tuple" and self.s.args: + if self.s.type.fullname in TUPLE_LIKE_INSTANCE_NAMES and self.s.args: return t.copy_modified(items=[meet_types(it, self.s.args[0]) for it in t.items]) elif is_proper_subtype(t, self.s): # A named tuple that inherits from a normal class diff --git a/test-data/unit/check-narrowing.test b/test-data/unit/check-narrowing.test index 5b7fadf41c79..d0ad1367aca0 100644 --- a/test-data/unit/check-narrowing.test +++ b/test-data/unit/check-narrowing.test @@ -1910,3 +1910,16 @@ if len(x) == a: else: reveal_type(x) # N: Revealed type is "Union[Tuple[builtins.int, builtins.int], Tuple[builtins.int, builtins.int, builtins.int]]" [builtins fixtures/len.pyi] + +[case testNarrowingLenUnionWithUnreachable] +from typing import Union, Sequence + +def f(x: Union[int, Sequence[int]]) -> None: + if ( + isinstance(x, tuple) + and len(x) == 2 + and isinstance(x[0], int) + and isinstance(x[1], int) + ): + reveal_type(x) # N: Revealed type is "Tuple[builtins.int, builtins.int]" +[builtins fixtures/len.pyi] diff --git a/test-data/unit/fixtures/len.pyi b/test-data/unit/fixtures/len.pyi index c72596661858..ee39d952701f 100644 --- a/test-data/unit/fixtures/len.pyi +++ b/test-data/unit/fixtures/len.pyi @@ -10,7 +10,7 @@ class object: class type: def __init__(self, x) -> None: pass -class tuple(Generic[T]): +class tuple(Sequence[T]): def __len__(self) -> int: pass class list(Sequence[T]): pass