ruff/crates/ty_python_semantic/resources/mdtest
David Peter 42f152108a
[ty] Generic types aliases (implicit and PEP 613) (#21553)
## Summary

Add support for generic PEP 613 type aliases and generic implicit type
aliases:
```py
from typing import TypeVar

T = TypeVar("T")
ListOrSet = list[T] | set[T]

def _(xs: ListOrSet[int]):
    reveal_type(xs)  # list[int] | set[int]
```

closes https://github.com/astral-sh/ty/issues/1643
closes https://github.com/astral-sh/ty/issues/1629
closes https://github.com/astral-sh/ty/issues/1596
closes https://github.com/astral-sh/ty/issues/573
closes https://github.com/astral-sh/ty/issues/221

## Typing conformance

```diff
-aliases_explicit.py:52:5: error[type-assertion-failure] Type `list[int]` does not match asserted type `@Todo(specialized generic alias in type expression)`
-aliases_explicit.py:53:5: error[type-assertion-failure] Type `tuple[str, ...] | list[str]` does not match asserted type `@Todo(Generic specialization of types.UnionType)`
-aliases_explicit.py:54:5: error[type-assertion-failure] Type `tuple[int, int, int, str]` does not match asserted type `@Todo(specialized generic alias in type expression)`
-aliases_explicit.py:56:5: error[type-assertion-failure] Type `(int, str, /) -> str` does not match asserted type `@Todo(Generic specialization of typing.Callable)`
-aliases_explicit.py:59:5: error[type-assertion-failure] Type `int | str | None | list[list[int]]` does not match asserted type `int | str | None | list[@Todo(specialized generic alias in type expression)]`
```

New true negatives ✔️ 

```diff
+aliases_explicit.py:41:36: error[invalid-type-arguments] Too many type arguments: expected 1, got 2
-aliases_explicit.py:57:5: error[type-assertion-failure] Type `(int, str, str, /) -> None` does not match asserted type `@Todo(Generic specialization of typing.Callable)`
+aliases_explicit.py:57:5: error[type-assertion-failure] Type `(int, str, str, /) -> None` does not match asserted type `(...) -> Unknown`
```

These require `ParamSpec`

```diff
+aliases_explicit.py:67:24: error[invalid-type-arguments] Too many type arguments: expected 0, got 1
+aliases_explicit.py:68:24: error[invalid-type-arguments] Too many type arguments: expected 0, got 1
+aliases_explicit.py:69:29: error[invalid-type-arguments] Too many type arguments: expected 1, got 2
+aliases_explicit.py:70:29: error[invalid-type-arguments] Too many type arguments: expected 1, got 2
+aliases_explicit.py:71:29: error[invalid-type-arguments] Too many type arguments: expected 1, got 2
+aliases_explicit.py:102:20: error[invalid-type-arguments] Too many type arguments: expected 0, got 1
```

New true positives ✔️ 

```diff
-aliases_implicit.py:63:5: error[type-assertion-failure] Type `list[int]` does not match asserted type `@Todo(specialized generic alias in type expression)`
-aliases_implicit.py:64:5: error[type-assertion-failure] Type `tuple[str, ...] | list[str]` does not match asserted type `@Todo(Generic specialization of types.UnionType)`
-aliases_implicit.py:65:5: error[type-assertion-failure] Type `tuple[int, int, int, str]` does not match asserted type `@Todo(specialized generic alias in type expression)`
-aliases_implicit.py:67:5: error[type-assertion-failure] Type `(int, str, /) -> str` does not match asserted type `@Todo(Generic specialization of typing.Callable)`
-aliases_implicit.py:70:5: error[type-assertion-failure] Type `int | str | None | list[list[int]]` does not match asserted type `int | str | None | list[@Todo(specialized generic alias in type expression)]`
-aliases_implicit.py:71:5: error[type-assertion-failure] Type `list[bool]` does not match asserted type `@Todo(specialized generic alias in type expression)`
```

New true negatives ✔️ 

```diff
+aliases_implicit.py:54:36: error[invalid-type-arguments] Too many type arguments: expected 1, got 2
-aliases_implicit.py:68:5: error[type-assertion-failure] Type `(int, str, str, /) -> None` does not match asserted type `@Todo(Generic specialization of typing.Callable)`
+aliases_implicit.py:68:5: error[type-assertion-failure] Type `(int, str, str, /) -> None` does not match asserted type `(...) -> Unknown`
```

These require `ParamSpec`

```diff
+aliases_implicit.py:76:24: error[invalid-type-arguments] Too many type arguments: expected 0, got 1
+aliases_implicit.py:77:24: error[invalid-type-arguments] Too many type arguments: expected 0, got 1
+aliases_implicit.py:78:29: error[invalid-type-arguments] Too many type arguments: expected 1, got 2
+aliases_implicit.py:79:29: error[invalid-type-arguments] Too many type arguments: expected 1, got 2
+aliases_implicit.py:80:29: error[invalid-type-arguments] Too many type arguments: expected 1, got 2
+aliases_implicit.py:81:25: error[invalid-type-arguments] Type `str` is not assignable to upper bound `int | float` of type variable `TFloat@GoodTypeAlias12`
+aliases_implicit.py:135:20: error[invalid-type-arguments] Too many type arguments: expected 0, got 1
```

New true positives ✔️ 

```diff
+callables_annotation.py:172:19: error[invalid-type-arguments] Too many type arguments: expected 0, got 1
+callables_annotation.py:175:19: error[invalid-type-arguments] Too many type arguments: expected 0, got 1
+callables_annotation.py:188:25: error[invalid-type-arguments] Too many type arguments: expected 0, got 1
+callables_annotation.py:189:25: error[invalid-type-arguments] Too many type arguments: expected 0, got 1
```

These require `ParamSpec` and `Concatenate`.

```diff
-generics_defaults_specialization.py:26:5: error[type-assertion-failure] Type `SomethingWithNoDefaults[int, str]` does not match asserted type `SomethingWithNoDefaults[int, typing.TypeVar]`
+generics_defaults_specialization.py:26:5: error[type-assertion-failure] Type `SomethingWithNoDefaults[int, str]` does not match asserted type `SomethingWithNoDefaults[int, DefaultStrT]`
```

Favorable diagnostic change ✔️ 

```diff
-generics_defaults_specialization.py:27:5: error[type-assertion-failure] Type `SomethingWithNoDefaults[int, bool]` does not match asserted type `@Todo(specialized generic alias in type expression)`
```

New true negative ✔️ 

```diff
-generics_defaults_specialization.py:30:1: error[non-subscriptable] Cannot subscript object of type `<class 'SomethingWithNoDefaults[int, typing.TypeVar]'>` with no `__class_getitem__` method
+generics_defaults_specialization.py:30:15: error[invalid-type-arguments] Too many type arguments: expected between 0 and 1, got 2
```

Correct new diagnostic ✔️ 


```diff
-generics_variance.py:175:25: error[non-subscriptable] Cannot subscript object of type `<class 'Contra[typing.TypeVar]'>` with no `__class_getitem__` method
-generics_variance.py:175:35: error[non-subscriptable] Cannot subscript object of type `<class 'Co[typing.TypeVar]'>` with no `__class_getitem__` method
-generics_variance.py:179:29: error[non-subscriptable] Cannot subscript object of type `<class 'Contra[typing.TypeVar]'>` with no `__class_getitem__` method
-generics_variance.py:179:39: error[non-subscriptable] Cannot subscript object of type `<class 'Contra[typing.TypeVar]'>` with no `__class_getitem__` method
-generics_variance.py:183:21: error[non-subscriptable] Cannot subscript object of type `<class 'Co[typing.TypeVar]'>` with no `__class_getitem__` method
-generics_variance.py:183:27: error[non-subscriptable] Cannot subscript object of type `<class 'Co[typing.TypeVar]'>` with no `__class_getitem__` method
-generics_variance.py:187:25: error[non-subscriptable] Cannot subscript object of type `<class 'Co[typing.TypeVar]'>` with no `__class_getitem__` method
-generics_variance.py:187:31: error[non-subscriptable] Cannot subscript object of type `<class 'Contra[typing.TypeVar]'>` with no `__class_getitem__` method
-generics_variance.py:191:33: error[non-subscriptable] Cannot subscript object of type `<class 'Contra[typing.TypeVar]'>` with no `__class_getitem__` method
-generics_variance.py:191:43: error[non-subscriptable] Cannot subscript object of type `<class 'Co[typing.TypeVar]'>` with no `__class_getitem__` method
-generics_variance.py:191:49: error[non-subscriptable] Cannot subscript object of type `<class 'Contra[typing.TypeVar]'>` with no `__class_getitem__` method
-generics_variance.py:196:5: error[non-subscriptable] Cannot subscript object of type `<class 'Contra[typing.TypeVar]'>` with no `__class_getitem__` method
-generics_variance.py:196:15: error[non-subscriptable] Cannot subscript object of type `<class 'Contra[typing.TypeVar]'>` with no `__class_getitem__` method
-generics_variance.py:196:25: error[non-subscriptable] Cannot subscript object of type `<class 'Contra[typing.TypeVar]'>` with no `__class_getitem__` method
```

One of these should apparently be an error, but not of this kind, so
this is good ✔️

```diff
-specialtypes_type.py:152:16: error[invalid-type-form] `typing.TypeVar` is not a generic class
-specialtypes_type.py:156:16: error[invalid-type-form] `typing.TypeVar` is not a generic class
```

Good, those were false positives. ✔️ 

I skipped the analysis for everything involving `TypeVarTuple`.

## Ecosystem impact

**[Full report with detailed
diff](https://david-generic-implicit-alias.ecosystem-663.pages.dev/diff)**

Previous iterations of this PR showed all kinds of problems. In it's
current state, I do not see any large systematic problems, but it is
hard to tell with 5k diagnostic changes.

## Performance

* There is a huge 4x regression in `colour-science/colour`, related to
[this large
file](https://github.com/colour-science/colour/blob/develop/colour/io/luts/tests/test_lut.py)
with [many assignments of hard-coded arrays (lists of lists) to
`np.NDArray`
types](83e754c8b6/colour/io/luts/tests/test_lut.py (L701-L781))
that we now understand. We now take ~2 seconds to check this file, so
definitely not great, but maybe acceptable for now.

## Test Plan

Updated and new Markdown tests
2025-11-28 20:38:24 +01:00
..
annotations [ty] Support type[T] with type variables (#21650) 2025-11-28 09:20:24 +01:00
assignment [ty] Avoid expression reinference for diagnostics (#21267) 2025-11-25 09:24:00 -08:00
binary [ty] support PEP 613 type aliases (#21394) 2025-11-20 17:59:35 -08:00
boolean
boundness_declaredness
call [ty] Avoid expression reinference for diagnostics (#21267) 2025-11-25 09:24:00 -08:00
class [ty] Support type[T] with type variables (#21650) 2025-11-28 09:20:24 +01:00
comparison [ty] Check method definitions on subclasses for Liskov violations (#21436) 2025-11-23 18:08:15 +00:00
comprehensions [ty] fix global symbol lookup from eager scopes (#21317) 2025-11-12 10:15:51 -08:00
conditional
dataclasses [ty] Dataclasses: __hash__ semantics and unsafe_hash (#21470) 2025-11-16 09:52:30 +00:00
declaration
diagnostics [ty] support generic aliases in type[...], like type[C[int]] (#21552) 2025-11-24 13:56:42 -08:00
directives [ty] Custom concise diagnostic messages (#21498) 2025-11-18 09:35:40 +01:00
doc
exception [ty] Improve diagnostics for invalid exceptions (#21475) 2025-11-15 22:12:00 +00:00
expression [ty] Check method definitions on subclasses for Liskov violations (#21436) 2025-11-23 18:08:15 +00:00
function [ty] Sync vendored typeshed stubs (#21466) 2025-11-15 17:12:32 +00:00
generics [ty] Support type[T] with type variables (#21650) 2025-11-28 09:20:24 +01:00
ide_support [ty] Support type[T] with type variables (#21650) 2025-11-28 09:20:24 +01:00
import [ty] handle recursive type inference properly (#20566) 2025-11-26 08:50:26 -08:00
libraries [ty] Generic types aliases (implicit and PEP 613) (#21553) 2025-11-28 20:38:24 +01:00
literal [ty] Type inference for genererator expressions (#21437) 2025-11-14 13:04:11 +00:00
loops
narrow [ty] Eagerly evaluate types.UnionType elements as type expressions (#21531) 2025-11-20 17:28:48 +01:00
regression [ty] handle recursive type inference properly (#20566) 2025-11-26 08:50:26 -08:00
scopes [ty] Make __getattr__ available for ModuleType instances (#21450) 2025-11-14 13:59:14 +01:00
shadowing
snapshots [ty] Preserve quoting style when autofixing TypedDict keys (#21682) 2025-11-28 18:40:34 +00:00
stubs [ty] Better invalid-assignment diagnostics (#21476) 2025-11-18 14:31:04 +01:00
subscript [ty] implement TypedDict structural assignment (#21467) 2025-11-20 13:15:28 -08:00
suppressions [ty] Add 'remove unused ignore comment' code action (#21582) 2025-11-25 08:08:21 -05:00
type_compendium [ty] Improve literal promotion heuristics (#21439) 2025-11-14 16:13:56 -05:00
type_of [ty] Support type[T] with type variables (#21650) 2025-11-28 09:20:24 +01:00
type_properties [ty] support generic aliases in type[...], like type[C[int]] (#21552) 2025-11-24 13:56:42 -08:00
type_qualifiers
unary
with
.mdformat.toml
async.md [ty] Generic types aliases (implicit and PEP 613) (#21553) 2025-11-28 20:38:24 +01:00
attributes.md [ty] Support type[T] with type variables (#21650) 2025-11-28 09:20:24 +01:00
bidirectional.md [ty] Avoid expression reinference for diagnostics (#21267) 2025-11-25 09:24:00 -08:00
classes.md
cycle.md [ty] more precise inference for a failed specialization (#21651) 2025-11-27 13:44:28 +01:00
decorators.md
del.md
deprecated.md
descriptor_protocol.md [ty] Use the return type of __get__ for descriptor lookups even when __get__ is called with incorrect arguments (#21424) 2025-11-13 12:05:10 +00:00
enums.md [ty] Support type[T] with type variables (#21650) 2025-11-28 09:20:24 +01:00
exhaustiveness_checking.md
final.md [ty] Implement typing.final for methods (#21646) 2025-11-28 15:18:02 +00:00
implicit_type_aliases.md [ty] Generic types aliases (implicit and PEP 613) (#21553) 2025-11-28 20:38:24 +01:00
instance_layout_conflict.md
intersection_types.md
invalid_syntax.md
known_constants.md
liskov.md [ty] Extend Liskov checks to also cover classmethods and staticmethods (#21598) 2025-11-24 23:14:06 +00:00
literal_promotion.md [ty] Narrow type context during literal promotion in generic class constructors (#21574) 2025-11-21 17:05:32 -05:00
mdtest_config.md
mdtest_custom_typeshed.md
metaclass.md
mro.md [ty] Sync vendored typeshed stubs (#21466) 2025-11-15 17:12:32 +00:00
named_tuple.md
overloads.md
override.md [ty] Implement typing.override (#21627) 2025-11-25 10:42:40 -08:00
paramspec.md [ty] Ensure annotation/type expressions in stub files are always deferred (#21401) 2025-11-13 17:14:54 +00:00
pep613_type_aliases.md [ty] Generic types aliases (implicit and PEP 613) (#21553) 2025-11-28 20:38:24 +01:00
pep695_type_aliases.md [ty] handle recursive type inference properly (#20566) 2025-11-26 08:50:26 -08:00
properties.md [ty] Use the return type of __get__ for descriptor lookups even when __get__ is called with incorrect arguments (#21424) 2025-11-13 12:05:10 +00:00
protocols.md [ty] Support type[T] with type variables (#21650) 2025-11-28 09:20:24 +01:00
public_types.md
statically_known_branches.md
sys_platform.md
sys_version_info.md [ty] support PEP 613 type aliases (#21394) 2025-11-20 17:59:35 -08:00
t_strings.md
terminal_statements.md
ty_extensions.md
typed_dict.md [ty] Preserve quoting style when autofixing TypedDict keys (#21682) 2025-11-28 18:40:34 +00:00
union_types.md
unpacking.md
unreachable.md [ty] Add subdiagnostic hint if a variable with type Never is used in a type expression (#21660) 2025-11-27 12:48:18 +00:00