Skip to content

Commit a9024a8

Browse files
authored
Fix type aliases with fixed-length tuples (#14184)
Fix type aliases like these: ``` T = tuple[int, str] ``` Type applications involving fixed-length tuples still don't fully work. The inferred type is a variable-length tuple when constructing a tuple using a type application, e.g. `tuple[int, str]((1, ""))`. This seems a pretty low-priority issue, whereas the type alias use case seems common. Most of the work was by @sobolevn originally in #12134. I just finished it up. Fixes #11098.
1 parent 7ea5ff6 commit a9024a8

File tree

3 files changed

+77
-0
lines changed

3 files changed

+77
-0
lines changed

mypy/checkexpr.py

+3
Original file line numberDiff line numberDiff line change
@@ -3969,6 +3969,9 @@ def apply_type_arguments_to_callable(
39693969

39703970
if isinstance(tp, CallableType):
39713971
if len(tp.variables) != len(args):
3972+
if tp.is_type_obj() and tp.type_object().fullname == "builtins.tuple":
3973+
# TODO: Specialize the callable for the type arguments
3974+
return tp
39723975
self.msg.incompatible_type_application(len(tp.variables), len(args), ctx)
39733976
return AnyType(TypeOfAny.from_error)
39743977
return self.apply_generic_arguments(tp, args, ctx)

test-data/unit/check-type-aliases.test

+32
Original file line numberDiff line numberDiff line change
@@ -993,3 +993,35 @@ x_bad: A[bytes] # E: Value of type variable "S" of "A" cannot be "bytes"
993993
B = List[C[U]]
994994
y: B[int]
995995
y_bad: B[str] # E: Type argument "str" of "B" must be a subtype of "int"
996+
997+
[case testTupleWithDifferentArgsPy38]
998+
# flags: --python-version 3.8
999+
NotYet1 = tuple[float] # E: "tuple" is not subscriptable
1000+
NotYet2 = tuple[float, float] # E: "tuple" is not subscriptable
1001+
NotYet3 = tuple[float, ...] # E: Unexpected "..." \
1002+
# E: "tuple" is not subscriptable
1003+
NotYet4 = tuple[float, float, ...] # E: Unexpected "..." \
1004+
# E: "tuple" is not subscriptable
1005+
[builtins fixtures/tuple.pyi]
1006+
1007+
[case testTupleWithDifferentArgsStub]
1008+
# https://github.com/python/mypy/issues/11098
1009+
import tup
1010+
1011+
[file tup.pyi]
1012+
Correct1 = str | tuple[float, float, str]
1013+
Correct2 = tuple[float] | str
1014+
Correct3 = tuple[float, ...] | str
1015+
Correct4 = tuple[float, str] | str
1016+
Correct5 = tuple[int, str]
1017+
Correct6 = tuple[int, ...]
1018+
1019+
RHSAlias1: type = tuple[int, int]
1020+
RHSAlias2: type = tuple[int]
1021+
RHSAlias3: type = tuple[int, ...]
1022+
1023+
# Wrong:
1024+
1025+
WrongTypeElement = str | tuple[float, 1] # E: Invalid type: try using Literal[1] instead?
1026+
WrongEllipsis = str | tuple[float, float, ...] # E: Unexpected "..."
1027+
[builtins fixtures/tuple.pyi]

test-data/unit/pythoneval.test

+42
Original file line numberDiff line numberDiff line change
@@ -1816,3 +1816,45 @@ def foo(k: str) -> TD:
18161816
return x.get(k, {})
18171817
[out]
18181818
_testTypedDictUnionGetFull.py:11: note: Revealed type is "TypedDict('_testTypedDictUnionGetFull.TD', {'x'?: builtins.int, 'y'?: builtins.int})"
1819+
1820+
[case testTupleWithDifferentArgsPy310]
1821+
# https://github.com/python/mypy/issues/11098
1822+
# flags: --python-version 3.10
1823+
Correct1 = str | tuple[float, float, str]
1824+
Correct2 = tuple[float] | str
1825+
Correct3 = tuple[float, ...] | str
1826+
Correct4 = tuple[float, str]
1827+
Correct5 = tuple[float, ...]
1828+
Correct6 = list[tuple[int, str]]
1829+
c1: Correct1
1830+
c2: Correct2
1831+
c3: Correct3
1832+
c4: Correct4
1833+
c5: Correct5
1834+
c6: Correct6
1835+
reveal_type(c1)
1836+
reveal_type(c2)
1837+
reveal_type(c3)
1838+
reveal_type(c4)
1839+
reveal_type(c5)
1840+
reveal_type(c6)
1841+
1842+
RHSAlias1: type = tuple[int, int]
1843+
RHSAlias2: type = tuple[int]
1844+
RHSAlias3: type = tuple[int, ...]
1845+
1846+
WrongTypeElement = str | tuple[float, 1] # Error
1847+
WrongEllipsis = tuple[float, float, ...] | str # Error
1848+
1849+
# TODO: This should produce a fixed-length tuple
1850+
reveal_type(tuple[int, str]((1, "x")))
1851+
[out]
1852+
_testTupleWithDifferentArgsPy310.py:15: note: Revealed type is "Union[builtins.str, Tuple[builtins.float, builtins.float, builtins.str]]"
1853+
_testTupleWithDifferentArgsPy310.py:16: note: Revealed type is "Union[Tuple[builtins.float], builtins.str]"
1854+
_testTupleWithDifferentArgsPy310.py:17: note: Revealed type is "Union[builtins.tuple[builtins.float, ...], builtins.str]"
1855+
_testTupleWithDifferentArgsPy310.py:18: note: Revealed type is "Tuple[builtins.float, builtins.str]"
1856+
_testTupleWithDifferentArgsPy310.py:19: note: Revealed type is "builtins.tuple[builtins.float, ...]"
1857+
_testTupleWithDifferentArgsPy310.py:20: note: Revealed type is "builtins.list[Tuple[builtins.int, builtins.str]]"
1858+
_testTupleWithDifferentArgsPy310.py:26: error: Invalid type: try using Literal[1] instead?
1859+
_testTupleWithDifferentArgsPy310.py:27: error: Unexpected "..."
1860+
_testTupleWithDifferentArgsPy310.py:30: note: Revealed type is "builtins.tuple[builtins.object, ...]"

0 commit comments

Comments
 (0)