Skip to content

Commit 6eafc5e

Browse files
authored
Fixes to generic builtin types (#10766)
This fixes these issues: * Allow variable-length tuple (tuple[int, ...]) in type aliases * Allow generic built-in types (e.g. list[int]) in stubs in all Python versions Fixes #9980. Fixes #10303. Fixes #10731.
1 parent a5a9e15 commit 6eafc5e

File tree

3 files changed

+53
-4
lines changed

3 files changed

+53
-4
lines changed

mypy/semanal.py

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@
7676
get_nongen_builtins, get_member_expr_fullname, REVEAL_TYPE,
7777
REVEAL_LOCALS, is_final_node, TypedDictExpr, type_aliases_source_versions,
7878
EnumCallExpr, RUNTIME_PROTOCOL_DECOS, FakeExpression, Statement, AssignmentExpr,
79-
ParamSpecExpr
79+
ParamSpecExpr, EllipsisExpr
8080
)
8181
from mypy.tvar_scope import TypeVarLikeScope
8282
from mypy.typevars import fill_typevars
@@ -91,7 +91,8 @@
9191
FunctionLike, UnboundType, TypeVarDef, TupleType, UnionType, StarType,
9292
CallableType, Overloaded, Instance, Type, AnyType, LiteralType, LiteralValue,
9393
TypeTranslator, TypeOfAny, TypeType, NoneType, PlaceholderType, TPDICT_NAMES, ProperType,
94-
get_proper_type, get_proper_types, TypeAliasType)
94+
get_proper_type, get_proper_types, TypeAliasType
95+
)
9596
from mypy.typeops import function_type
9697
from mypy.type_visitor import TypeQuery
9798
from mypy.nodes import implicit_module_attrs
@@ -3867,7 +3868,8 @@ def analyze_type_application(self, expr: IndexExpr) -> None:
38673868
# ...or directly.
38683869
else:
38693870
n = self.lookup_type_node(base)
3870-
if n and n.fullname in get_nongen_builtins(self.options.python_version):
3871+
if (n and n.fullname in get_nongen_builtins(self.options.python_version) and
3872+
not self.is_stub_file):
38713873
self.fail(no_subscript_builtin_alias(n.fullname, propose_alt=False), expr)
38723874

38733875
def analyze_type_application_args(self, expr: IndexExpr) -> Optional[List[Type]]:
@@ -3883,6 +3885,9 @@ def analyze_type_application_args(self, expr: IndexExpr) -> Optional[List[Type]]
38833885
types: List[Type] = []
38843886
if isinstance(index, TupleExpr):
38853887
items = index.items
3888+
is_tuple = isinstance(expr.base, RefExpr) and expr.base.fullname == 'builtins.tuple'
3889+
if is_tuple and len(items) == 2 and isinstance(items[-1], EllipsisExpr):
3890+
items = items[:-1]
38863891
else:
38873892
items = [index]
38883893
for item in items:

mypy/typeanal.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -281,7 +281,8 @@ def try_analyze_special_unbound_type(self, t: UnboundType, fullname: str) -> Opt
281281
return AnyType(TypeOfAny.from_error)
282282
elif (fullname == 'typing.Tuple' or
283283
(fullname == 'builtins.tuple' and (self.options.python_version >= (3, 9) or
284-
self.api.is_future_flag_set('annotations')))):
284+
self.api.is_future_flag_set('annotations') or
285+
self.allow_unnormalized))):
285286
# Tuple is special because it is involved in builtin import cycle
286287
# and may be not ready when used.
287288
sym = self.api.lookup_fully_qualified_or_none('builtins.tuple')

test-data/unit/check-generic-alias.test

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -239,3 +239,46 @@ t09: tuple[int, ...] = (1, 2, 3)
239239
from typing import Tuple
240240
t10: Tuple[int, ...] = t09
241241
[builtins fixtures/tuple.pyi]
242+
243+
[case testTypeAliasWithBuiltinTuple]
244+
# flags: --python-version 3.9
245+
246+
A = tuple[int, ...]
247+
a: A = ()
248+
b: A = (1, 2, 3)
249+
c: A = ('x', 'y') # E: Incompatible types in assignment (expression has type "Tuple[str, str]", variable has type "Tuple[int, ...]")
250+
251+
B = tuple[int, str]
252+
x: B = (1, 'x')
253+
y: B = ('x', 1) # E: Incompatible types in assignment (expression has type "Tuple[str, int]", variable has type "Tuple[int, str]")
254+
255+
reveal_type(tuple[int, ...]()) # N: Revealed type is "builtins.tuple[builtins.int*]"
256+
[builtins fixtures/tuple.pyi]
257+
258+
[case testTypeAliasWithBuiltinTupleInStub]
259+
# flags: --python-version 3.6
260+
import m
261+
reveal_type(m.a) # N: Revealed type is "builtins.tuple[builtins.int]"
262+
reveal_type(m.b) # N: Revealed type is "Tuple[builtins.int, builtins.str]"
263+
264+
[file m.pyi]
265+
A = tuple[int, ...]
266+
a: A
267+
B = tuple[int, str]
268+
b: B
269+
[builtins fixtures/tuple.pyi]
270+
271+
[case testTypeAliasWithBuiltinListInStub]
272+
# flags: --python-version 3.6
273+
import m
274+
reveal_type(m.a) # N: Revealed type is "builtins.list[builtins.int]"
275+
reveal_type(m.b) # N: Revealed type is "builtins.list[builtins.list[builtins.int]]"
276+
277+
[file m.pyi]
278+
A = list[int]
279+
a: A
280+
B = list[list[int]]
281+
b: B
282+
class C(list[int]):
283+
pass
284+
[builtins fixtures/list.pyi]

0 commit comments

Comments
 (0)