Skip to content

Commit 0d2c594

Browse files
authored
Bare Tuple should mean Tuple[Any, ...]. (#2185)
* Fix #2184.
1 parent 2fbf387 commit 0d2c594

5 files changed

Lines changed: 31 additions & 4 deletions

File tree

‎mypy/fastparse.py‎

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -833,12 +833,15 @@ def visit_Subscript(self, n: ast35.Subscript) -> Type:
833833
assert isinstance(value, UnboundType)
834834
assert not value.args
835835

836+
empty_tuple_index = False
836837
if isinstance(n.slice.value, ast35.Tuple):
837838
params = self.visit_list(n.slice.value.elts)
839+
if len(n.slice.value.elts) == 0:
840+
empty_tuple_index = True
838841
else:
839842
params = [self.visit(n.slice.value)]
840843

841-
return UnboundType(value.name, params, line=self.line)
844+
return UnboundType(value.name, params, line=self.line, empty_tuple_index=empty_tuple_index)
842845

843846
def visit_Tuple(self, n: ast35.Tuple) -> Type:
844847
return TupleType(self.visit_list(n.elts), None, implicit=True, line=self.line)

‎mypy/typeanal.py‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,9 @@ def visit_unbound_type(self, t: UnboundType) -> Type:
107107
elif fullname == 'typing.Any':
108108
return AnyType()
109109
elif fullname == 'typing.Tuple':
110+
if len(t.args) == 0 and not t.empty_tuple_index:
111+
# Bare 'Tuple' is same as 'tuple'
112+
return self.builtin_type('builtins.tuple')
110113
if len(t.args) == 2 and isinstance(t.args[1], EllipsisType):
111114
# Tuple[T, ...] (uniform, variable-length tuple)
112115
node = self.lookup_fqn_func('builtins.tuple')

‎mypy/types.py‎

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -181,20 +181,24 @@ class UnboundType(Type):
181181
optional = False
182182
# is this type a return type?
183183
is_ret_type = False
184+
# special case for X[()]
185+
empty_tuple_index = False
184186

185187
def __init__(self,
186188
name: str,
187189
args: List[Type] = None,
188190
line: int = -1,
189191
column: int = -1,
190192
optional: bool = False,
191-
is_ret_type: bool = False) -> None:
193+
is_ret_type: bool = False,
194+
empty_tuple_index: bool = False) -> None:
192195
if not args:
193196
args = []
194197
self.name = name
195198
self.args = args
196199
self.optional = optional
197200
self.is_ret_type = is_ret_type
201+
self.empty_tuple_index = empty_tuple_index
198202
super().__init__(line, column)
199203

200204
def accept(self, visitor: 'TypeVisitor[T]') -> T:

‎test-data/unit/check-tuples.test‎

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -820,3 +820,22 @@ from typing import List, Tuple
820820
def f() -> Tuple[List[str], ...]:
821821
return ([],)
822822
[builtins fixtures/tuple.pyi]
823+
824+
[case testTupleWithoutArgs]
825+
from typing import Tuple
826+
def f(a: Tuple) -> None: pass
827+
f(())
828+
f((1,))
829+
f(('', ''))
830+
f(0) # E: Argument 1 to "f" has incompatible type "int"; expected Tuple[Any, ...]
831+
[builtins fixtures/tuple.pyi]
832+
833+
[case testTupleSingleton]
834+
# flags: --fast-parser
835+
from typing import Tuple
836+
def f(a: Tuple[()]) -> None: pass
837+
f(())
838+
f((1,)) # E: Argument 1 to "f" has incompatible type "Tuple[int]"; expected "Tuple[]"
839+
f(('', '')) # E: Argument 1 to "f" has incompatible type "Tuple[str, str]"; expected "Tuple[]"
840+
f(0) # E: Argument 1 to "f" has incompatible type "int"; expected "Tuple[]"
841+
[builtins fixtures/tuple.pyi]

‎test-data/unit/fixtures/tuple.pyi‎

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,5 +25,3 @@ T = TypeVar('T')
2525
class list(Sequence[T], Generic[T]): pass
2626

2727
def sum(iterable: Iterable[T], start: T = None) -> T: pass
28-
29-
True = bool()

0 commit comments

Comments
 (0)