[ty] Make tuple instantiations sound (#18987)

## Summary

Ensure that we correctly infer calls such as `tuple((1, 2))`,
`tuple(range(42))`, etc. Ensure that we emit errors on invalid calls
such as `tuple[int, str]()`.

## Test Plan

Mdtests
This commit is contained in:
Alex Waygood 2025-06-27 19:37:16 +01:00 committed by GitHub
parent 6802c4702f
commit a50a993b9c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 105 additions and 19 deletions

View file

@ -41,9 +41,7 @@ bar"""
reveal_type(len(())) # revealed: Literal[0]
reveal_type(len((1,))) # revealed: Literal[1]
reveal_type(len((1, 2))) # revealed: Literal[2]
# TODO: Handle constructor calls
reveal_type(len(tuple())) # revealed: int
reveal_type(len(tuple())) # revealed: Literal[0]
# TODO: Handle star unpacks; Should be: Literal[0]
reveal_type(len((*[],))) # revealed: Literal[1]

View file

@ -23,18 +23,36 @@ specialization of `tuple` we (TODO: should) check that the values passed in matc
defined in the specialization.
```py
# TODO: revealed: tuple[()]
reveal_type(tuple()) # revealed: tuple[Unknown, ...]
# TODO: revealed: tuple[Literal[1]]
reveal_type(tuple([1])) # revealed: tuple[Unknown, ...]
reveal_type(tuple[int]([1])) # revealed: tuple[int]
# TODO: error for invalid arguments
reveal_type(tuple[int, str]([1])) # revealed: tuple[int, str]
from typing_extensions import Iterable, Never
reveal_type(tuple()) # revealed: tuple[()]
reveal_type(tuple[int]((1,))) # revealed: tuple[int]
reveal_type(().__class__()) # revealed: tuple[()]
# TODO: error for invalid arguments
reveal_type((1, 2).__class__((1, 2))) # revealed: tuple[Literal[1], Literal[2]]
def f(x: Iterable[int], y: list[str], z: Never, aa: list[Never]):
reveal_type(tuple(x)) # revealed: tuple[int, ...]
reveal_type(tuple(y)) # revealed: tuple[str, ...]
reveal_type(tuple(z)) # revealed: tuple[Unknown, ...]
# This is correct as the only inhabitants of `list[Never]` can be empty lists
reveal_type(tuple(aa)) # revealed: tuple[()]
reveal_type(tuple((1, 2))) # revealed: tuple[Literal[1], Literal[2]]
# TODO: should be `tuple[Literal[1], ...]`
reveal_type(tuple([1])) # revealed: tuple[Unknown, ...]
# error: [invalid-argument-type] "Argument is incorrect: Expected `tuple[int]`, found `list[Unknown]`"
reveal_type(tuple[int]([1])) # revealed: tuple[int]
# error: [invalid-argument-type] "Argument is incorrect: Expected `tuple[int, str]`, found `tuple[Literal[1]]`"
reveal_type(tuple[int, str]((1,))) # revealed: tuple[int, str]
# error: [missing-argument] "No argument provided for required parameter `iterable`"
reveal_type((1,).__class__()) # revealed: tuple[Literal[1]]
# TODO: error for invalid arguments
# error: [missing-argument] "No argument provided for required parameter `iterable`"
reveal_type((1, 2).__class__()) # revealed: tuple[Literal[1], Literal[2]]
```