Skip to content

Commit 43851c2

Browse files
committed
Revert "Allow nonliteral tuple indexing"
This reverts commit 27dcbfa. Embarassing unintentional push to master.
1 parent 27dcbfa commit 43851c2

File tree

5 files changed

+33
-44
lines changed

5 files changed

+33
-44
lines changed

mypy/checkexpr.py

Lines changed: 27 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1570,23 +1570,31 @@ def visit_index_expr_helper(self, e: IndexExpr) -> Type:
15701570
return self.accept(e.analyzed)
15711571
left_type = self.accept(e.base)
15721572
if isinstance(left_type, TupleType) and self.chk.in_checked_function():
1573-
# Special case for tuples. They return a more specific type when
1574-
# indexed by an integer literal.
1573+
# Special case for tuples. They support indexing only by integer
1574+
# literals.
15751575
index = e.index
15761576
if isinstance(index, SliceExpr):
15771577
return self.visit_tuple_slice_helper(left_type, index)
15781578

1579-
n = self._get_value(index)
1580-
if n is not None:
1581-
if n < 0:
1582-
n += len(left_type.items)
1579+
ok = False
1580+
if isinstance(index, IntExpr):
1581+
n = index.value
1582+
ok = True
1583+
elif isinstance(index, UnaryExpr):
1584+
if index.op == '-':
1585+
operand = index.expr
1586+
if isinstance(operand, IntExpr):
1587+
n = len(left_type.items) - operand.value
1588+
ok = True
1589+
if ok:
15831590
if n >= 0 and n < len(left_type.items):
15841591
return left_type.items[n]
15851592
else:
15861593
self.chk.fail(messages.TUPLE_INDEX_OUT_OF_RANGE, e)
15871594
return AnyType()
15881595
else:
1589-
return self.nonliteral_tuple_index_helper(left_type, index)
1596+
self.chk.fail(messages.TUPLE_INDEX_MUST_BE_AN_INT_LITERAL, e)
1597+
return AnyType()
15901598
elif isinstance(left_type, TypedDictType):
15911599
return self.visit_typeddict_index_expr(left_type, e.index)
15921600
elif (isinstance(left_type, CallableType)
@@ -1605,31 +1613,29 @@ def visit_tuple_slice_helper(self, left_type: TupleType, slic: SliceExpr) -> Typ
16051613
if slic.begin_index:
16061614
begin = self._get_value(slic.begin_index)
16071615
if begin is None:
1608-
return self.nonliteral_tuple_index_helper(left_type, slic)
1616+
self.chk.fail(
1617+
messages.TUPLE_SLICE_MUST_BE_AN_INT_LITERAL,
1618+
slic.begin_index)
1619+
return AnyType()
16091620

16101621
if slic.end_index:
16111622
end = self._get_value(slic.end_index)
16121623
if end is None:
1613-
return self.nonliteral_tuple_index_helper(left_type, slic)
1624+
self.chk.fail(
1625+
messages.TUPLE_SLICE_MUST_BE_AN_INT_LITERAL,
1626+
slic.end_index)
1627+
return AnyType()
16141628

16151629
if slic.stride:
16161630
stride = self._get_value(slic.stride)
16171631
if stride is None:
1618-
return self.nonliteral_tuple_index_helper(left_type, slic)
1632+
self.chk.fail(
1633+
messages.TUPLE_SLICE_MUST_BE_AN_INT_LITERAL,
1634+
slic.stride)
1635+
return AnyType()
16191636

16201637
return left_type.slice(begin, stride, end)
16211638

1622-
def nonliteral_tuple_index_helper(self, left_type: TupleType, index: Expression) -> Type:
1623-
index_type = self.accept(index)
1624-
expected_type = UnionType.make_union([self.named_type('builtins.int'),
1625-
self.named_type('builtins.slice')])
1626-
if not self.chk.check_subtype(index_type, expected_type, index,
1627-
messages.INVALID_TUPLE_INDEX_TYPE,
1628-
'actual type', 'expected type'):
1629-
return AnyType()
1630-
else:
1631-
return UnionType.make_simplified_union(left_type.items)
1632-
16331639
def _get_value(self, index: Expression) -> Optional[int]:
16341640
if isinstance(index, IntExpr):
16351641
return index.value

mypy/messages.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,8 @@
5454
INCOMPATIBLE_TYPES_IN_YIELD_FROM = 'Incompatible types in "yield from"'
5555
INCOMPATIBLE_TYPES_IN_STR_INTERPOLATION = 'Incompatible types in string interpolation'
5656
MUST_HAVE_NONE_RETURN_TYPE = 'The return type of "{}" must be None'
57-
INVALID_TUPLE_INDEX_TYPE = 'Invalid tuple index type'
57+
TUPLE_INDEX_MUST_BE_AN_INT_LITERAL = 'Tuple index must be an integer literal'
58+
TUPLE_SLICE_MUST_BE_AN_INT_LITERAL = 'Tuple slice must be an integer literal'
5859
TUPLE_INDEX_OUT_OF_RANGE = 'Tuple index out of range'
5960
NEED_ANNOTATION_FOR_VAR = 'Need type annotation for variable'
6061
ITERABLE_EXPECTED = 'Iterable expected'

test-data/unit/check-class-namedtuple.test

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -542,7 +542,7 @@ class Base(NamedTuple):
542542
reveal_type(self.x) # E: Revealed type is 'builtins.int'
543543
self.x = 3 # E: Property "x" defined in "Base" is read-only
544544
self[1] # E: Tuple index out of range
545-
reveal_type(self[T]) # E: Revealed type is 'builtins.int'
545+
self[T] # E: Tuple index must be an integer literal
546546
return self.x
547547
def bad_override(self) -> int:
548548
return self.x
@@ -571,7 +571,6 @@ reveal_type(Child(1).good_override()) # E: Revealed type is 'builtins.int'
571571
reveal_type(Base(1).bad_override()) # E: Revealed type is 'builtins.int'
572572
reveal_type(takes_base(Base(1))) # E: Revealed type is 'builtins.int'
573573
reveal_type(takes_base(Child(1))) # E: Revealed type is 'builtins.int'
574-
[builtins fixtures/tuple.pyi]
575574

576575
[case testNewNamedTupleIllegalNames]
577576
from typing import Callable, NamedTuple

test-data/unit/check-tuples.test

Lines changed: 2 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -163,8 +163,8 @@ b = t1[0] # E: Incompatible types in assignment (expression has type "A", variab
163163
t1[2] # E: Tuple index out of range
164164
t1[3] # E: Tuple index out of range
165165
t2[1] # E: Tuple index out of range
166-
reveal_type(t1[n]) # E: Revealed type is 'Union[__main__.A, __main__.B]'
167-
reveal_type(t3[n:]) # E: Revealed type is 'Union[__main__.A, __main__.B, __main__.C, __main__.D, __main__.E]'
166+
t1[n] # E: Tuple index must be an integer literal
167+
t3[n:] # E: Tuple slice must be an integer literal
168168
b = t1[(0)] # E: Incompatible types in assignment (expression has type "A", variable has type "B")
169169

170170
a = t1[0]
@@ -925,19 +925,3 @@ f((1,)) # E: Argument 1 to "f" has incompatible type "Tuple[int]"; expected "Tu
925925
f(('', '')) # E: Argument 1 to "f" has incompatible type "Tuple[str, str]"; expected "Tuple[]"
926926
f(0) # E: Argument 1 to "f" has incompatible type "int"; expected "Tuple[]"
927927
[builtins fixtures/tuple.pyi]
928-
929-
[case testNonliteralTupleIndex]
930-
t = (0, "")
931-
x = 0
932-
y = ""
933-
reveal_type(t[x]) # E: Revealed type is 'Union[builtins.int, builtins.str]'
934-
t[y] # E: Invalid tuple index type (actual type "str", expected type "Union[int, slice]")
935-
[builtins fixtures/tuple.pyi]
936-
937-
[case testNonliteralTupleSlice]
938-
t = (0, "")
939-
x = 0
940-
y = ""
941-
reveal_type(t[x:]) # E: Revealed type is 'Union[builtins.int, builtins.str]'
942-
t[y:] # E: Slice index must be an integer or None
943-
[builtins fixtures/tuple.pyi]

test-data/unit/fixtures/tuple.pyi

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,8 @@ class tuple(Sequence[Tco], Generic[Tco]):
1515
def __getitem__(self, x: int) -> Tco: pass
1616
class function: pass
1717

18-
# We need int and slice for indexing tuples.
18+
# We need int for indexing tuples.
1919
class int: pass
20-
class slice: pass
2120
class bool: pass
2221
class str: pass # For convenience
2322
class unicode: pass

0 commit comments

Comments
 (0)