diff --git a/mypy/checkexpr.py b/mypy/checkexpr.py index e81fba9bc9ef5..a2141680b6cbb 100644 --- a/mypy/checkexpr.py +++ b/mypy/checkexpr.py @@ -4271,7 +4271,7 @@ def visit_tuple_slice_helper(self, left_type: TupleType, slic: SliceExpr) -> Typ items: list[Type] = [] for b, e, s in itertools.product(begin, end, stride): - item = left_type.slice(b, e, s) + item = left_type.slice(b, e, s, fallback=self.named_type("builtins.tuple")) if item is None: self.chk.fail(message_registry.AMBIGUOUS_SLICE_OF_VARIADIC_TUPLE, slic) return AnyType(TypeOfAny.from_error) diff --git a/mypy/types.py b/mypy/types.py index 9817043db6c29..34ea96be25ee3 100644 --- a/mypy/types.py +++ b/mypy/types.py @@ -2416,7 +2416,12 @@ def copy_modified( items = self.items return TupleType(items, fallback, self.line, self.column) - def slice(self, begin: int | None, end: int | None, stride: int | None) -> TupleType | None: + def slice( + self, begin: int | None, end: int | None, stride: int | None, *, fallback: Instance | None + ) -> TupleType | None: + if fallback is None: + fallback = self.partial_fallback + if any(isinstance(t, UnpackType) for t in self.items): total = len(self.items) unpack_index = find_unpack_in_list(self.items) @@ -2462,7 +2467,7 @@ def slice(self, begin: int | None, end: int | None, stride: int | None) -> Tuple return None else: slice_items = self.items[begin:end:stride] - return TupleType(slice_items, self.partial_fallback, self.line, self.column, self.implicit) + return TupleType(slice_items, fallback, self.line, self.column, self.implicit) class TypedDictType(ProperType): diff --git a/test-data/unit/check-literal.test b/test-data/unit/check-literal.test index 08c709c6b7771..d9ad68385ad1e 100644 --- a/test-data/unit/check-literal.test +++ b/test-data/unit/check-literal.test @@ -1872,8 +1872,9 @@ reveal_type(tup2[idx3]) # N: Revealed type is "__main__.D" reveal_type(tup2[idx4]) # N: Revealed type is "__main__.E" reveal_type(tup2[idx_neg1]) # N: Revealed type is "__main__.E" tup2[idx5] # E: Tuple index out of range -reveal_type(tup2[idx2:idx4]) # N: Revealed type is "Tuple[__main__.C, __main__.D, fallback=__main__.Tup2Class]" -reveal_type(tup2[::idx2]) # N: Revealed type is "Tuple[__main__.A, __main__.C, __main__.E, fallback=__main__.Tup2Class]" +reveal_type(tup2[idx2:idx4]) # N: Revealed type is "Tuple[__main__.C, __main__.D]" +reveal_type(tup2[::idx2]) # N: Revealed type is "Tuple[__main__.A, __main__.C, __main__.E]" +tup3: Tup2Class = tup2[:] # E: Incompatible types in assignment (expression has type "Tuple[A, B, C, D, E]", variable has type "Tup2Class") [builtins fixtures/slice.pyi] [case testLiteralIntelligentIndexingTypedDict] @@ -1977,8 +1978,8 @@ reveal_type(tup1[0::idx1]) # N: Revealed type is "Union[Tuple[__main__.A, _ tup1[idx_bad] # E: Tuple index out of range reveal_type(tup2[idx1]) # N: Revealed type is "Union[__main__.B, __main__.C]" -reveal_type(tup2[idx1:idx2]) # N: Revealed type is "Union[Tuple[__main__.B, __main__.C, fallback=__main__.Tup2Class], Tuple[__main__.B, __main__.C, __main__.D, fallback=__main__.Tup2Class], Tuple[__main__.C, fallback=__main__.Tup2Class], Tuple[__main__.C, __main__.D, fallback=__main__.Tup2Class]]" -reveal_type(tup2[0::idx1]) # N: Revealed type is "Union[Tuple[__main__.A, __main__.B, __main__.C, __main__.D, __main__.E, fallback=__main__.Tup2Class], Tuple[__main__.A, __main__.C, __main__.E, fallback=__main__.Tup2Class]]" +reveal_type(tup2[idx1:idx2]) # N: Revealed type is "Union[Tuple[__main__.B, __main__.C], Tuple[__main__.B, __main__.C, __main__.D], Tuple[__main__.C], Tuple[__main__.C, __main__.D]]" +reveal_type(tup2[0::idx1]) # N: Revealed type is "Union[Tuple[__main__.A, __main__.B, __main__.C, __main__.D, __main__.E], Tuple[__main__.A, __main__.C, __main__.E]]" tup2[idx_bad] # E: Tuple index out of range [builtins fixtures/slice.pyi] [out] diff --git a/test-data/unit/check-tuples.test b/test-data/unit/check-tuples.test index 9dfee38bc0c6f..1447321c0c493 100644 --- a/test-data/unit/check-tuples.test +++ b/test-data/unit/check-tuples.test @@ -1681,3 +1681,13 @@ def g(t: Tuple): reveal_type(zip(*t)) # N: Revealed type is "typing.Iterator[builtins.tuple[Any, ...]]" reveal_type(zip(t)) # N: Revealed type is "typing.Iterator[Tuple[Any]]" [builtins fixtures/tuple.pyi] + +[case testTupleSubclassSlice] +from typing import Tuple + +class A: ... + +class tuple_aa_subclass(Tuple[A, A]): ... + +inst_tuple_aa_subclass: tuple_aa_subclass = tuple_aa_subclass((A(), A()))[:] # E: Incompatible types in assignment (expression has type "Tuple[A, A]", variable has type "tuple_aa_subclass") +[builtins fixtures/tuple.pyi]