[ty] support `type[tuple[...]]` (#21652)

Fixes https://github.com/astral-sh/ty/issues/1649

## Summary

We missed this when adding support for `type[]` of a specialized
generic.

## Test Plan

Added mdtests.
This commit is contained in:
Carl Meyer 2025-12-01 02:49:26 -08:00 committed by GitHub
parent bc6517a807
commit c2773b4c6f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 19 additions and 3 deletions

View File

@ -329,6 +329,16 @@ reveal_type(tuple[int, str]) # revealed: <class 'tuple[int, str]'>
reveal_type(tuple[int, ...]) # revealed: <class 'tuple[int, ...]'>
```
```py
from typing import Any
def _(a: type[tuple], b: type[tuple[int]], c: type[tuple[int, ...]], d: type[tuple[Any, ...]]) -> None:
reveal_type(a) # revealed: type[tuple[Unknown, ...]]
reveal_type(b) # revealed: type[tuple[int]]
reveal_type(c) # revealed: type[tuple[int, ...]]
reveal_type(d) # revealed: type[tuple[Any, ...]]
```
## Inheritance
```toml
@ -392,7 +402,7 @@ class C(Tuple): ...
reveal_mro(C)
```
### Union subscript access
## Union subscript access
```py
def test(val: tuple[str] | tuple[int]):
@ -402,7 +412,7 @@ def test2(val: tuple[str, None] | list[int | float]):
reveal_type(val[0]) # revealed: str | int | float
```
### Union subscript access with non-indexable type
## Union subscript access with non-indexable type
```py
def test3(val: tuple[str] | tuple[int] | int):
@ -410,7 +420,7 @@ def test3(val: tuple[str] | tuple[int] | int):
reveal_type(val[0]) # revealed: str | int | Unknown
```
### Intersection subscript access
## Intersection subscript access
```py
from ty_extensions import Intersection

View File

@ -691,6 +691,12 @@ impl<'db> TypeInferenceBuilder<'db, '_> {
self.db(),
todo_type!("type[T] for protocols").expect_dynamic(),
)
} else if class_literal.is_tuple(self.db()) {
let class_type = self
.infer_tuple_type_expression(parameters)
.map(|tuple_type| tuple_type.to_class_type(self.db()))
.unwrap_or_else(|| class_literal.default_specialization(self.db()));
SubclassOfType::from(self.db(), class_type)
} else {
match class_literal.generic_context(self.db()) {
Some(generic_context) => {