From 5cd8d1d0e6f6a283f98b7e08624cbc240f28db0e Mon Sep 17 00:00:00 2001 From: apoorva-01 Date: Sat, 11 Jul 2026 05:21:42 +0530 Subject: [PATCH] Fix inferred type of a tuple indexed by a slice value The subscript path only treated literal slice syntax as a slice, so `t[s]` with `s: slice` fell through to the int-index result instead of tuple[...]. Fixes #21708. --- mypy/checkexpr.py | 7 ++++++- test-data/unit/check-tuples.test | 9 +++++++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/mypy/checkexpr.py b/mypy/checkexpr.py index 172d44555b946..a8542b58615a6 100644 --- a/mypy/checkexpr.py +++ b/mypy/checkexpr.py @@ -4774,7 +4774,12 @@ def nonliteral_tuple_index_helper(self, left_type: TupleType, index: Expression) self.check_method_call_by_name("__getitem__", left_type, [index], [ARG_POS], context=index) # We could return the return type from above, but unions are often better than the join union = self.union_tuple_fallback_item(left_type) - if isinstance(index, SliceExpr): + # A slice always yields a tuple, whether written as slice syntax (a SliceExpr) or + # passed as a value of type slice (e.g. a variable), which isn't a SliceExpr. + index_type = get_proper_type(self.chk.lookup_type_or_none(index)) + if isinstance(index, SliceExpr) or ( + isinstance(index_type, Instance) and index_type.type.fullname == "builtins.slice" + ): return self.chk.named_generic_type("builtins.tuple", [union]) return union diff --git a/test-data/unit/check-tuples.test b/test-data/unit/check-tuples.test index bfbd2e631f5d8..6b366e10daa72 100644 --- a/test-data/unit/check-tuples.test +++ b/test-data/unit/check-tuples.test @@ -1447,6 +1447,15 @@ reveal_type(t[x:]) # N: Revealed type is "builtins.tuple[builtins.int | builtin t[y:] # E: Invalid index type "slice[str, None, None]" for "tuple[int, str]"; expected type "slice[int | None]" [builtins fixtures/tuple.pyi] +[case testTupleIndexBySliceVariable] +# https://github.com/python/mypy/issues/21708 +s: slice +t = (0, "") +reveal_type(t[s]) # N: Revealed type is "builtins.tuple[builtins.int | builtins.str, ...]" +u = (0, 0) +reveal_type(u[s]) # N: Revealed type is "builtins.tuple[builtins.int, ...]" +[builtins fixtures/tuple.pyi] + [case testTupleSliceStepZeroNoCrash] # This was crashing: https://github.com/python/mypy/issues/18062 # TODO: emit better error when 0 is used for step