Skip to content

Commit

Permalink
Fix type aliases with fixed-length tuples (#14184)
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
JukkaL authored Nov 25, 2022
1 parent 7ea5ff6 commit a9024a8
Show file tree
Hide file tree
Showing 3 changed files with 77 additions and 0 deletions.
3 changes: 3 additions & 0 deletions mypy/checkexpr.py
Original file line number Diff line number Diff line change
Expand Up @@ -3969,6 +3969,9 @@ def apply_type_arguments_to_callable(

if isinstance(tp, CallableType):
if len(tp.variables) != len(args):
if tp.is_type_obj() and tp.type_object().fullname == "builtins.tuple":
# TODO: Specialize the callable for the type arguments
return tp
self.msg.incompatible_type_application(len(tp.variables), len(args), ctx)
return AnyType(TypeOfAny.from_error)
return self.apply_generic_arguments(tp, args, ctx)
Expand Down
32 changes: 32 additions & 0 deletions test-data/unit/check-type-aliases.test
Original file line number Diff line number Diff line change
Expand Up @@ -993,3 +993,35 @@ x_bad: A[bytes] # E: Value of type variable "S" of "A" cannot be "bytes"
B = List[C[U]]
y: B[int]
y_bad: B[str] # E: Type argument "str" of "B" must be a subtype of "int"

[case testTupleWithDifferentArgsPy38]
# flags: --python-version 3.8
NotYet1 = tuple[float] # E: "tuple" is not subscriptable
NotYet2 = tuple[float, float] # E: "tuple" is not subscriptable
NotYet3 = tuple[float, ...] # E: Unexpected "..." \
# E: "tuple" is not subscriptable
NotYet4 = tuple[float, float, ...] # E: Unexpected "..." \
# E: "tuple" is not subscriptable
[builtins fixtures/tuple.pyi]

[case testTupleWithDifferentArgsStub]
# https://github.com/python/mypy/issues/11098
import tup

[file tup.pyi]
Correct1 = str | tuple[float, float, str]
Correct2 = tuple[float] | str
Correct3 = tuple[float, ...] | str
Correct4 = tuple[float, str] | str
Correct5 = tuple[int, str]
Correct6 = tuple[int, ...]

RHSAlias1: type = tuple[int, int]
RHSAlias2: type = tuple[int]
RHSAlias3: type = tuple[int, ...]

# Wrong:

WrongTypeElement = str | tuple[float, 1] # E: Invalid type: try using Literal[1] instead?
WrongEllipsis = str | tuple[float, float, ...] # E: Unexpected "..."
[builtins fixtures/tuple.pyi]
42 changes: 42 additions & 0 deletions test-data/unit/pythoneval.test
Original file line number Diff line number Diff line change
Expand Up @@ -1816,3 +1816,45 @@ def foo(k: str) -> TD:
return x.get(k, {})
[out]
_testTypedDictUnionGetFull.py:11: note: Revealed type is "TypedDict('_testTypedDictUnionGetFull.TD', {'x'?: builtins.int, 'y'?: builtins.int})"

[case testTupleWithDifferentArgsPy310]
# https://github.com/python/mypy/issues/11098
# flags: --python-version 3.10
Correct1 = str | tuple[float, float, str]
Correct2 = tuple[float] | str
Correct3 = tuple[float, ...] | str
Correct4 = tuple[float, str]
Correct5 = tuple[float, ...]
Correct6 = list[tuple[int, str]]
c1: Correct1
c2: Correct2
c3: Correct3
c4: Correct4
c5: Correct5
c6: Correct6
reveal_type(c1)
reveal_type(c2)
reveal_type(c3)
reveal_type(c4)
reveal_type(c5)
reveal_type(c6)

RHSAlias1: type = tuple[int, int]
RHSAlias2: type = tuple[int]
RHSAlias3: type = tuple[int, ...]

WrongTypeElement = str | tuple[float, 1] # Error
WrongEllipsis = tuple[float, float, ...] | str # Error

# TODO: This should produce a fixed-length tuple
reveal_type(tuple[int, str]((1, "x")))
[out]
_testTupleWithDifferentArgsPy310.py:15: note: Revealed type is "Union[builtins.str, Tuple[builtins.float, builtins.float, builtins.str]]"
_testTupleWithDifferentArgsPy310.py:16: note: Revealed type is "Union[Tuple[builtins.float], builtins.str]"
_testTupleWithDifferentArgsPy310.py:17: note: Revealed type is "Union[builtins.tuple[builtins.float, ...], builtins.str]"
_testTupleWithDifferentArgsPy310.py:18: note: Revealed type is "Tuple[builtins.float, builtins.str]"
_testTupleWithDifferentArgsPy310.py:19: note: Revealed type is "builtins.tuple[builtins.float, ...]"
_testTupleWithDifferentArgsPy310.py:20: note: Revealed type is "builtins.list[Tuple[builtins.int, builtins.str]]"
_testTupleWithDifferentArgsPy310.py:26: error: Invalid type: try using Literal[1] instead?
_testTupleWithDifferentArgsPy310.py:27: error: Unexpected "..."
_testTupleWithDifferentArgsPy310.py:30: note: Revealed type is "builtins.tuple[builtins.object, ...]"

0 comments on commit a9024a8

Please sign in to comment.