[ty] Support typing.TypeAliasType (#18156)

## Summary

Support direct uses of `typing.TypeAliasType`, as in:

```py
from typing import TypeAliasType

IntOrStr = TypeAliasType("IntOrStr", int | str)

def f(x: IntOrStr) -> None:
    reveal_type(x)  # revealed: int | str
```

closes https://github.com/astral-sh/ty/issues/392

## Ecosystem

The new false positive here:
```diff
+ error[invalid-type-form] altair/utils/core.py:49:53: The first argument to `Callable` must be either a list of types, ParamSpec, Concatenate, or `...`
```
comes from the fact that we infer the second argument as a type
expression now. We silence false positives for PEP695 `ParamSpec`s, but
not for `P = ParamSpec("P")` inside `Callable[P, ...]`.

## Test Plan

New Markdown tests
This commit is contained in:
David Peter 2025-05-19 16:36:49 +02:00 committed by GitHub
parent 220137ca7b
commit 4c889d5251
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
8 changed files with 347 additions and 74 deletions

View file

@ -50,7 +50,7 @@ Calling a non-callable object will raise a `TypeError` at runtime.
### Links ### Links
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20call-non-callable) * [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20call-non-callable)
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L86) * [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L87)
</details> </details>
## `conflicting-argument-forms` ## `conflicting-argument-forms`
@ -81,7 +81,7 @@ f(int) # error
### Links ### Links
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20conflicting-argument-forms) * [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20conflicting-argument-forms)
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L117) * [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L118)
</details> </details>
## `conflicting-declarations` ## `conflicting-declarations`
@ -111,7 +111,7 @@ a = 1
### Links ### Links
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20conflicting-declarations) * [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20conflicting-declarations)
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L143) * [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L144)
</details> </details>
## `conflicting-metaclass` ## `conflicting-metaclass`
@ -142,7 +142,7 @@ class C(A, B): ...
### Links ### Links
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20conflicting-metaclass) * [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20conflicting-metaclass)
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L168) * [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L169)
</details> </details>
## `cyclic-class-definition` ## `cyclic-class-definition`
@ -173,7 +173,7 @@ class B(A): ...
### Links ### Links
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20cyclic-class-definition) * [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20cyclic-class-definition)
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L194) * [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L195)
</details> </details>
## `division-by-zero` ## `division-by-zero`
@ -196,7 +196,7 @@ Dividing by zero raises a `ZeroDivisionError` at runtime.
### Links ### Links
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20division-by-zero) * [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20division-by-zero)
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L220) * [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L221)
</details> </details>
## `duplicate-base` ## `duplicate-base`
@ -222,7 +222,7 @@ class B(A, A): ...
### Links ### Links
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20duplicate-base) * [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20duplicate-base)
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L238) * [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L239)
</details> </details>
## `escape-character-in-forward-annotation` ## `escape-character-in-forward-annotation`
@ -359,7 +359,7 @@ TypeError: multiple bases have instance lay-out conflict
### Links ### Links
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20incompatible-slots) * [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20incompatible-slots)
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L259) * [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L260)
</details> </details>
## `inconsistent-mro` ## `inconsistent-mro`
@ -388,7 +388,7 @@ class C(A, B): ...
### Links ### Links
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20inconsistent-mro) * [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20inconsistent-mro)
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L345) * [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L346)
</details> </details>
## `index-out-of-bounds` ## `index-out-of-bounds`
@ -413,7 +413,7 @@ t[3] # IndexError: tuple index out of range
### Links ### Links
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20index-out-of-bounds) * [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20index-out-of-bounds)
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L369) * [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L370)
</details> </details>
## `invalid-argument-type` ## `invalid-argument-type`
@ -439,7 +439,7 @@ func("foo") # error: [invalid-argument-type]
### Links ### Links
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-argument-type) * [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-argument-type)
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L389) * [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L390)
</details> </details>
## `invalid-assignment` ## `invalid-assignment`
@ -466,7 +466,7 @@ a: int = ''
### Links ### Links
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-assignment) * [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-assignment)
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L429) * [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L430)
</details> </details>
## `invalid-attribute-access` ## `invalid-attribute-access`
@ -499,7 +499,7 @@ C.instance_var = 3 # error: Cannot assign to instance variable
### Links ### Links
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-attribute-access) * [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-attribute-access)
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1314) * [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1336)
</details> </details>
## `invalid-base` ## `invalid-base`
@ -513,7 +513,7 @@ TODO #14889
### Links ### Links
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-base) * [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-base)
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L451) * [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L452)
</details> </details>
## `invalid-context-manager` ## `invalid-context-manager`
@ -539,7 +539,7 @@ with 1:
### Links ### Links
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-context-manager) * [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-context-manager)
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L460) * [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L461)
</details> </details>
## `invalid-declaration` ## `invalid-declaration`
@ -567,7 +567,7 @@ a: str
### Links ### Links
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-declaration) * [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-declaration)
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L481) * [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L482)
</details> </details>
## `invalid-exception-caught` ## `invalid-exception-caught`
@ -608,7 +608,7 @@ except ZeroDivisionError:
### Links ### Links
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-exception-caught) * [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-exception-caught)
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L504) * [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L505)
</details> </details>
## `invalid-generic-class` ## `invalid-generic-class`
@ -639,7 +639,7 @@ class C[U](Generic[T]): ...
### Links ### Links
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-generic-class) * [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-generic-class)
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L540) * [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L541)
</details> </details>
## `invalid-legacy-type-variable` ## `invalid-legacy-type-variable`
@ -672,7 +672,7 @@ def f(t: TypeVar("U")): ...
### Links ### Links
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-legacy-type-variable) * [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-legacy-type-variable)
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L566) * [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L567)
</details> </details>
## `invalid-metaclass` ## `invalid-metaclass`
@ -704,7 +704,7 @@ class B(metaclass=f): ...
### Links ### Links
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-metaclass) * [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-metaclass)
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L594) * [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L616)
</details> </details>
## `invalid-overload` ## `invalid-overload`
@ -752,7 +752,7 @@ def foo(x: int) -> int: ...
### Links ### Links
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-overload) * [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-overload)
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L621) * [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L643)
</details> </details>
## `invalid-parameter-default` ## `invalid-parameter-default`
@ -777,7 +777,7 @@ def f(a: int = ''): ...
### Links ### Links
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-parameter-default) * [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-parameter-default)
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L664) * [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L686)
</details> </details>
## `invalid-protocol` ## `invalid-protocol`
@ -810,7 +810,7 @@ TypeError: Protocols can only inherit from other protocols, got <class 'int'>
### Links ### Links
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-protocol) * [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-protocol)
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L317) * [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L318)
</details> </details>
## `invalid-raise` ## `invalid-raise`
@ -858,7 +858,7 @@ def g():
### Links ### Links
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-raise) * [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-raise)
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L684) * [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L706)
</details> </details>
## `invalid-return-type` ## `invalid-return-type`
@ -882,7 +882,7 @@ def func() -> int:
### Links ### Links
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-return-type) * [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-return-type)
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L410) * [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L411)
</details> </details>
## `invalid-super-argument` ## `invalid-super-argument`
@ -926,7 +926,7 @@ super(B, A) # error: `A` does not satisfy `issubclass(A, B)`
### Links ### Links
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-super-argument) * [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-super-argument)
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L727) * [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L749)
</details> </details>
## `invalid-syntax-in-forward-annotation` ## `invalid-syntax-in-forward-annotation`
@ -943,6 +943,32 @@ TODO #14889
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fstring_annotation.rs#L111) * [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fstring_annotation.rs#L111)
</details> </details>
## `invalid-type-alias-type`
**Default level**: error
<details>
<summary>detects invalid TypeAliasType definitions</summary>
### What it does
Checks for the creation of invalid `TypeAliasType`s
### Why is this bad?
There are several requirements that you must follow when creating a `TypeAliasType`.
### Examples
```python
from typing import TypeAliasType
IntOrStr = TypeAliasType("IntOrStr", int | str) # okay
NewAlias = TypeAliasType(get_name(), int) # error: TypeAliasType name must be a string literal
```
### Links
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-type-alias-type)
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L595)
</details>
## `invalid-type-checking-constant` ## `invalid-type-checking-constant`
**Default level**: error **Default level**: error
@ -969,7 +995,7 @@ TYPE_CHECKING = ''
### Links ### Links
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-type-checking-constant) * [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-type-checking-constant)
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L766) * [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L788)
</details> </details>
## `invalid-type-form` ## `invalid-type-form`
@ -998,7 +1024,7 @@ b: Annotated[int] # `Annotated` expects at least two arguments
### Links ### Links
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-type-form) * [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-type-form)
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L790) * [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L812)
</details> </details>
## `invalid-type-variable-constraints` ## `invalid-type-variable-constraints`
@ -1032,7 +1058,7 @@ T = TypeVar('T', bound=str) # valid bound TypeVar
### Links ### Links
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-type-variable-constraints) * [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-type-variable-constraints)
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L814) * [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L836)
</details> </details>
## `missing-argument` ## `missing-argument`
@ -1056,7 +1082,7 @@ func() # TypeError: func() missing 1 required positional argument: 'x'
### Links ### Links
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20missing-argument) * [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20missing-argument)
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L843) * [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L865)
</details> </details>
## `no-matching-overload` ## `no-matching-overload`
@ -1084,7 +1110,7 @@ func("string") # error: [no-matching-overload]
### Links ### Links
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20no-matching-overload) * [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20no-matching-overload)
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L862) * [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L884)
</details> </details>
## `non-subscriptable` ## `non-subscriptable`
@ -1107,7 +1133,7 @@ Subscripting an object that does not support it will raise a `TypeError` at runt
### Links ### Links
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20non-subscriptable) * [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20non-subscriptable)
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L885) * [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L907)
</details> </details>
## `not-iterable` ## `not-iterable`
@ -1132,7 +1158,7 @@ for i in 34: # TypeError: 'int' object is not iterable
### Links ### Links
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20not-iterable) * [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20not-iterable)
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L903) * [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L925)
</details> </details>
## `parameter-already-assigned` ## `parameter-already-assigned`
@ -1158,7 +1184,7 @@ f(1, x=2) # Error raised here
### Links ### Links
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20parameter-already-assigned) * [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20parameter-already-assigned)
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L954) * [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L976)
</details> </details>
## `raw-string-type-annotation` ## `raw-string-type-annotation`
@ -1217,7 +1243,7 @@ static_assert(int(2.0 * 3.0) == 6) # error: does not have a statically known tr
### Links ### Links
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20static-assert-error) * [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20static-assert-error)
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1290) * [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1312)
</details> </details>
## `subclass-of-final-class` ## `subclass-of-final-class`
@ -1245,7 +1271,7 @@ class B(A): ... # Error raised here
### Links ### Links
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20subclass-of-final-class) * [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20subclass-of-final-class)
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1045) * [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1067)
</details> </details>
## `too-many-positional-arguments` ## `too-many-positional-arguments`
@ -1271,7 +1297,7 @@ f("foo") # Error raised here
### Links ### Links
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20too-many-positional-arguments) * [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20too-many-positional-arguments)
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1090) * [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1112)
</details> </details>
## `type-assertion-failure` ## `type-assertion-failure`
@ -1298,7 +1324,7 @@ def _(x: int):
### Links ### Links
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20type-assertion-failure) * [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20type-assertion-failure)
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1068) * [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1090)
</details> </details>
## `unavailable-implicit-super-arguments` ## `unavailable-implicit-super-arguments`
@ -1342,7 +1368,7 @@ class A:
### Links ### Links
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20unavailable-implicit-super-arguments) * [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20unavailable-implicit-super-arguments)
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1111) * [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1133)
</details> </details>
## `unknown-argument` ## `unknown-argument`
@ -1368,7 +1394,7 @@ f(x=1, y=2) # Error raised here
### Links ### Links
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20unknown-argument) * [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20unknown-argument)
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1168) * [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1190)
</details> </details>
## `unresolved-attribute` ## `unresolved-attribute`
@ -1395,7 +1421,7 @@ A().foo # AttributeError: 'A' object has no attribute 'foo'
### Links ### Links
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20unresolved-attribute) * [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20unresolved-attribute)
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1189) * [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1211)
</details> </details>
## `unresolved-import` ## `unresolved-import`
@ -1419,7 +1445,7 @@ import foo # ModuleNotFoundError: No module named 'foo'
### Links ### Links
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20unresolved-import) * [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20unresolved-import)
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1211) * [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1233)
</details> </details>
## `unresolved-reference` ## `unresolved-reference`
@ -1443,7 +1469,7 @@ print(x) # NameError: name 'x' is not defined
### Links ### Links
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20unresolved-reference) * [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20unresolved-reference)
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1230) * [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1252)
</details> </details>
## `unsupported-bool-conversion` ## `unsupported-bool-conversion`
@ -1479,7 +1505,7 @@ b1 < b2 < b1 # exception raised here
### Links ### Links
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20unsupported-bool-conversion) * [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20unsupported-bool-conversion)
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L923) * [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L945)
</details> </details>
## `unsupported-operator` ## `unsupported-operator`
@ -1506,7 +1532,7 @@ A() + A() # TypeError: unsupported operand type(s) for +: 'A' and 'A'
### Links ### Links
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20unsupported-operator) * [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20unsupported-operator)
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1249) * [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1271)
</details> </details>
## `zero-stepsize-in-slice` ## `zero-stepsize-in-slice`
@ -1530,7 +1556,7 @@ l[1:10:0] # ValueError: slice step cannot be zero
### Links ### Links
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20zero-stepsize-in-slice) * [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20zero-stepsize-in-slice)
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1271) * [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1293)
</details> </details>
## `call-possibly-unbound-method` ## `call-possibly-unbound-method`
@ -1548,7 +1574,7 @@ Calling an unbound method will raise an `AttributeError` at runtime.
### Links ### Links
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20call-possibly-unbound-method) * [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20call-possibly-unbound-method)
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L104) * [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L105)
</details> </details>
## `invalid-ignore-comment` ## `invalid-ignore-comment`
@ -1604,7 +1630,7 @@ A.c # AttributeError: type object 'A' has no attribute 'c'
### Links ### Links
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20possibly-unbound-attribute) * [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20possibly-unbound-attribute)
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L975) * [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L997)
</details> </details>
## `possibly-unbound-import` ## `possibly-unbound-import`
@ -1635,7 +1661,7 @@ from module import a # ImportError: cannot import name 'a' from 'module'
### Links ### Links
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20possibly-unbound-import) * [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20possibly-unbound-import)
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L997) * [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1019)
</details> </details>
## `redundant-cast` ## `redundant-cast`
@ -1661,7 +1687,7 @@ cast(int, f()) # Redundant
### Links ### Links
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20redundant-cast) * [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20redundant-cast)
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1342) * [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1364)
</details> </details>
## `undefined-reveal` ## `undefined-reveal`
@ -1684,7 +1710,7 @@ reveal_type(1) # NameError: name 'reveal_type' is not defined
### Links ### Links
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20undefined-reveal) * [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20undefined-reveal)
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1150) * [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1172)
</details> </details>
## `unknown-rule` ## `unknown-rule`
@ -1741,7 +1767,7 @@ print(x) # NameError: name 'x' is not defined
### Links ### Links
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20possibly-unresolved-reference) * [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20possibly-unresolved-reference)
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1023) * [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1045)
</details> </details>
## `unused-ignore-comment` ## `unused-ignore-comment`

View file

@ -522,6 +522,40 @@ mod tests {
assert_snapshot!(test.goto_type_definition(), @"No type definitions found"); assert_snapshot!(test.goto_type_definition(), @"No type definitions found");
} }
#[test]
fn goto_type_of_bare_type_alias_type() {
let test = cursor_test(
r#"
from typing_extensions import TypeAliasType
Alias = TypeAliasType("Alias", tuple[int, int])
Alias<CURSOR>
"#,
);
assert_snapshot!(test.goto_type_definition(), @r#"
info[goto-type-definition]: Type definition
--> main.py:4:13
|
2 | from typing_extensions import TypeAliasType
3 |
4 | Alias = TypeAliasType("Alias", tuple[int, int])
| ^^^^^
5 |
6 | Alias
|
info: Source
--> main.py:6:13
|
4 | Alias = TypeAliasType("Alias", tuple[int, int])
5 |
6 | Alias
| ^^^^^
|
"#);
}
#[test] #[test]
fn goto_type_on_keyword_argument() { fn goto_type_on_keyword_argument() {
let test = cursor_test( let test = cursor_test(

View file

@ -294,4 +294,8 @@ impl SourceOrderVisitor<'_> for PullTypesVisitor<'_> {
/// Whether or not the .py/.pyi version of this file is expected to fail /// Whether or not the .py/.pyi version of this file is expected to fail
#[rustfmt::skip] #[rustfmt::skip]
const KNOWN_FAILURES: &[(&str, bool, bool)] = &[]; const KNOWN_FAILURES: &[(&str, bool, bool)] = &[
// Fails with too-many-cycle-iterations due to a self-referential
// type alias, see https://github.com/astral-sh/ty/issues/256
("crates/ruff_linter/resources/test/fixtures/pyflakes/F401_34.py", true, true),
];

View file

@ -87,3 +87,54 @@ type TypeAliasType2 = TypeOf[Alias2]
static_assert(not is_equivalent_to(TypeAliasType1, TypeAliasType2)) static_assert(not is_equivalent_to(TypeAliasType1, TypeAliasType2))
static_assert(is_disjoint_from(TypeAliasType1, TypeAliasType2)) static_assert(is_disjoint_from(TypeAliasType1, TypeAliasType2))
``` ```
## Direct use of `TypeAliasType`
`TypeAliasType` can also be used directly. This is useful for versions of Python prior to 3.12.
```toml
[environment]
python-version = "3.9"
```
### Basic example
```py
from typing_extensions import TypeAliasType, Union
IntOrStr = TypeAliasType("IntOrStr", Union[int, str])
reveal_type(IntOrStr) # revealed: typing.TypeAliasType
reveal_type(IntOrStr.__name__) # revealed: Literal["IntOrStr"]
def f(x: IntOrStr) -> None:
reveal_type(x) # revealed: int | str
```
### Generic example
```py
from typing_extensions import TypeAliasType, TypeVar
T = TypeVar("T")
IntAnd = TypeAliasType("IntAndT", tuple[int, T], type_params=(T,))
def f(x: IntAnd[str]) -> None:
reveal_type(x) # revealed: @Todo(Generic PEP-695 type alias)
```
### Error cases
#### Name is not a string literal
```py
from typing_extensions import TypeAliasType
def get_name() -> str:
return "IntOrStr"
# error: [invalid-type-alias-type] "The name of a `typing.TypeAlias` must be a string literal"
IntOrStr = TypeAliasType(get_name(), int | str)
```

View file

@ -4012,6 +4012,45 @@ impl<'db> Type<'db> {
Signatures::single(signature) Signatures::single(signature)
} }
Some(KnownClass::TypeAliasType) => {
// ```py
// def __new__(
// cls,
// name: str,
// value: Any,
// *,
// type_params: tuple[TypeVar | ParamSpec | TypeVarTuple, ...] = ()
// ) -> Self: ...
// ```
let signature = CallableSignature::single(
self,
Signature::new(
Parameters::new([
Parameter::positional_or_keyword(Name::new_static("name"))
.with_annotated_type(KnownClass::Str.to_instance(db)),
Parameter::positional_or_keyword(Name::new_static("value"))
.with_annotated_type(Type::any())
.type_form(),
Parameter::keyword_only(Name::new_static("type_params"))
.with_annotated_type(KnownClass::Tuple.to_specialized_instance(
db,
[UnionType::from_elements(
db,
[
KnownClass::TypeVar.to_instance(db),
KnownClass::ParamSpec.to_instance(db),
KnownClass::TypeVarTuple.to_instance(db),
],
)],
))
.with_default_type(TupleType::empty(db)),
]),
None,
),
);
Signatures::single(signature)
}
Some(KnownClass::Property) => { Some(KnownClass::Property) => {
let getter_signature = Signature::new( let getter_signature = Signature::new(
Parameters::new([ Parameters::new([
@ -5318,7 +5357,7 @@ impl<'db> Type<'db> {
Some(TypeDefinition::TypeVar(var.definition(db))) Some(TypeDefinition::TypeVar(var.definition(db)))
} }
KnownInstanceType::TypeAliasType(type_alias) => { KnownInstanceType::TypeAliasType(type_alias) => {
Some(TypeDefinition::TypeAlias(type_alias.definition(db))) type_alias.definition(db).map(TypeDefinition::TypeAlias)
} }
_ => None, _ => None,
}, },
@ -7467,7 +7506,7 @@ impl<'db> ModuleLiteralType<'db> {
} }
#[salsa::interned(debug)] #[salsa::interned(debug)]
pub struct TypeAliasType<'db> { pub struct PEP695TypeAliasType<'db> {
#[returns(ref)] #[returns(ref)]
pub name: ast::name::Name, pub name: ast::name::Name,
@ -7475,7 +7514,7 @@ pub struct TypeAliasType<'db> {
} }
#[salsa::tracked] #[salsa::tracked]
impl<'db> TypeAliasType<'db> { impl<'db> PEP695TypeAliasType<'db> {
pub(crate) fn definition(self, db: &'db dyn Db) -> Definition<'db> { pub(crate) fn definition(self, db: &'db dyn Db) -> Definition<'db> {
let scope = self.rhs_scope(db); let scope = self.rhs_scope(db);
let type_alias_stmt_node = scope.node(db).expect_type_alias(); let type_alias_stmt_node = scope.node(db).expect_type_alias();
@ -7492,6 +7531,43 @@ impl<'db> TypeAliasType<'db> {
} }
} }
#[salsa::interned(debug)]
pub struct BareTypeAliasType<'db> {
#[returns(ref)]
pub name: ast::name::Name,
pub definition: Option<Definition<'db>>,
pub value: Type<'db>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, salsa::Update)]
pub enum TypeAliasType<'db> {
PEP695(PEP695TypeAliasType<'db>),
Bare(BareTypeAliasType<'db>),
}
impl<'db> TypeAliasType<'db> {
pub(crate) fn name(self, db: &'db dyn Db) -> &'db str {
match self {
TypeAliasType::PEP695(type_alias) => type_alias.name(db),
TypeAliasType::Bare(type_alias) => type_alias.name(db).as_str(),
}
}
pub(crate) fn definition(self, db: &'db dyn Db) -> Option<Definition<'db>> {
match self {
TypeAliasType::PEP695(type_alias) => Some(type_alias.definition(db)),
TypeAliasType::Bare(type_alias) => type_alias.definition(db),
}
}
pub(crate) fn value_type(self, db: &'db dyn Db) -> Type<'db> {
match self {
TypeAliasType::PEP695(type_alias) => type_alias.value_type(db),
TypeAliasType::Bare(type_alias) => type_alias.value(db),
}
}
}
/// Either the explicit `metaclass=` keyword of the class, or the inferred metaclass of one of its base classes. /// Either the explicit `metaclass=` keyword of the class, or the inferred metaclass of one of its base classes.
#[derive(Debug, Clone, PartialEq, Eq, salsa::Update)] #[derive(Debug, Clone, PartialEq, Eq, salsa::Update)]
pub(super) struct MetaclassCandidate<'db> { pub(super) struct MetaclassCandidate<'db> {
@ -8004,6 +8080,10 @@ impl<'db> TupleType<'db> {
.to_specialized_instance(db, [UnionType::from_elements(db, self.elements(db))]) .to_specialized_instance(db, [UnionType::from_elements(db, self.elements(db))])
} }
pub(crate) fn empty(db: &'db dyn Db) -> Type<'db> {
Type::Tuple(TupleType::new(db, Box::<[Type<'db>]>::from([])))
}
pub(crate) fn from_elements<T: Into<Type<'db>>>( pub(crate) fn from_elements<T: Into<Type<'db>>>(
db: &'db dyn Db, db: &'db dyn Db,
types: impl IntoIterator<Item = T>, types: impl IntoIterator<Item = T>,

View file

@ -41,6 +41,7 @@ pub(crate) fn register_lints(registry: &mut LintRegistryBuilder) {
registry.register_lint(&INVALID_EXCEPTION_CAUGHT); registry.register_lint(&INVALID_EXCEPTION_CAUGHT);
registry.register_lint(&INVALID_GENERIC_CLASS); registry.register_lint(&INVALID_GENERIC_CLASS);
registry.register_lint(&INVALID_LEGACY_TYPE_VARIABLE); registry.register_lint(&INVALID_LEGACY_TYPE_VARIABLE);
registry.register_lint(&INVALID_TYPE_ALIAS_TYPE);
registry.register_lint(&INVALID_METACLASS); registry.register_lint(&INVALID_METACLASS);
registry.register_lint(&INVALID_OVERLOAD); registry.register_lint(&INVALID_OVERLOAD);
registry.register_lint(&INVALID_PARAMETER_DEFAULT); registry.register_lint(&INVALID_PARAMETER_DEFAULT);
@ -591,6 +592,27 @@ declare_lint! {
} }
} }
declare_lint! {
/// ## What it does
/// Checks for the creation of invalid `TypeAliasType`s
///
/// ## Why is this bad?
/// There are several requirements that you must follow when creating a `TypeAliasType`.
///
/// ## Examples
/// ```python
/// from typing import TypeAliasType
///
/// IntOrStr = TypeAliasType("IntOrStr", int | str) # okay
/// NewAlias = TypeAliasType(get_name(), int) # error: TypeAliasType name must be a string literal
/// ```
pub(crate) static INVALID_TYPE_ALIAS_TYPE = {
summary: "detects invalid TypeAliasType definitions",
status: LintStatus::preview("1.0.0"),
default_level: Level::Error,
}
}
declare_lint! { declare_lint! {
/// ## What it does /// ## What it does
/// Checks for arguments to `metaclass=` that are invalid. /// Checks for arguments to `metaclass=` that are invalid.

View file

@ -71,26 +71,26 @@ use crate::types::diagnostic::{
CONFLICTING_METACLASS, CYCLIC_CLASS_DEFINITION, DIVISION_BY_ZERO, INCONSISTENT_MRO, CONFLICTING_METACLASS, CYCLIC_CLASS_DEFINITION, DIVISION_BY_ZERO, INCONSISTENT_MRO,
INVALID_ARGUMENT_TYPE, INVALID_ASSIGNMENT, INVALID_ATTRIBUTE_ACCESS, INVALID_BASE, INVALID_ARGUMENT_TYPE, INVALID_ASSIGNMENT, INVALID_ATTRIBUTE_ACCESS, INVALID_BASE,
INVALID_DECLARATION, INVALID_GENERIC_CLASS, INVALID_LEGACY_TYPE_VARIABLE, INVALID_DECLARATION, INVALID_GENERIC_CLASS, INVALID_LEGACY_TYPE_VARIABLE,
INVALID_PARAMETER_DEFAULT, INVALID_TYPE_FORM, INVALID_TYPE_VARIABLE_CONSTRAINTS, INVALID_PARAMETER_DEFAULT, INVALID_TYPE_ALIAS_TYPE, INVALID_TYPE_FORM,
POSSIBLY_UNBOUND_IMPORT, TypeCheckDiagnostics, UNDEFINED_REVEAL, UNRESOLVED_ATTRIBUTE, INVALID_TYPE_VARIABLE_CONSTRAINTS, POSSIBLY_UNBOUND_IMPORT, TypeCheckDiagnostics,
UNRESOLVED_IMPORT, UNSUPPORTED_OPERATOR, report_implicit_return_type, UNDEFINED_REVEAL, UNRESOLVED_ATTRIBUTE, UNRESOLVED_IMPORT, UNSUPPORTED_OPERATOR,
report_invalid_arguments_to_annotated, report_invalid_arguments_to_callable, report_implicit_return_type, report_invalid_arguments_to_annotated,
report_invalid_assignment, report_invalid_attribute_assignment, report_invalid_arguments_to_callable, report_invalid_assignment,
report_invalid_generator_function_return_type, report_invalid_return_type, report_invalid_attribute_assignment, report_invalid_generator_function_return_type,
report_possibly_unbound_attribute, report_invalid_return_type, report_possibly_unbound_attribute,
}; };
use crate::types::generics::GenericContext; use crate::types::generics::GenericContext;
use crate::types::mro::MroErrorKind; use crate::types::mro::MroErrorKind;
use crate::types::unpacker::{UnpackResult, Unpacker}; use crate::types::unpacker::{UnpackResult, Unpacker};
use crate::types::{ use crate::types::{
CallDunderError, CallableSignature, CallableType, ClassLiteral, ClassType, DataclassParams, BareTypeAliasType, CallDunderError, CallableSignature, CallableType, ClassLiteral, ClassType,
DynamicType, FunctionDecorators, FunctionType, GenericAlias, IntersectionBuilder, DataclassParams, DynamicType, FunctionDecorators, FunctionType, GenericAlias,
IntersectionType, KnownClass, KnownFunction, KnownInstanceType, MemberLookupPolicy, IntersectionBuilder, IntersectionType, KnownClass, KnownFunction, KnownInstanceType,
MetaclassCandidate, Parameter, ParameterForm, Parameters, Signature, Signatures, MemberLookupPolicy, MetaclassCandidate, PEP695TypeAliasType, Parameter, ParameterForm,
StringLiteralType, SubclassOfType, Symbol, SymbolAndQualifiers, Truthiness, TupleType, Type, Parameters, Signature, Signatures, StringLiteralType, SubclassOfType, Symbol,
TypeAliasType, TypeAndQualifiers, TypeArrayDisplay, TypeQualifiers, TypeVarBoundOrConstraints, SymbolAndQualifiers, Truthiness, TupleType, Type, TypeAliasType, TypeAndQualifiers,
TypeVarInstance, TypeVarKind, TypeVarVariance, UnionBuilder, UnionType, binding_type, TypeArrayDisplay, TypeQualifiers, TypeVarBoundOrConstraints, TypeVarInstance, TypeVarKind,
todo_type, TypeVarVariance, UnionBuilder, UnionType, binding_type, todo_type,
}; };
use crate::unpack::{Unpack, UnpackPosition}; use crate::unpack::{Unpack, UnpackPosition};
use crate::util::subscript::{PyIndex, PySlice}; use crate::util::subscript::{PyIndex, PySlice};
@ -2374,12 +2374,13 @@ impl<'db> TypeInferenceBuilder<'db> {
.node_scope(NodeWithScopeRef::TypeAlias(type_alias)) .node_scope(NodeWithScopeRef::TypeAlias(type_alias))
.to_scope_id(self.db(), self.file()); .to_scope_id(self.db(), self.file());
let type_alias_ty = let type_alias_ty = Type::KnownInstance(KnownInstanceType::TypeAliasType(
Type::KnownInstance(KnownInstanceType::TypeAliasType(TypeAliasType::new( TypeAliasType::PEP695(PEP695TypeAliasType::new(
self.db(), self.db(),
&type_alias.name.as_name_expr().unwrap().id, &type_alias.name.as_name_expr().unwrap().id,
rhs_scope, rhs_scope,
))); )),
));
self.add_declaration_with_binding( self.add_declaration_with_binding(
type_alias.into(), type_alias.into(),
@ -4860,6 +4861,7 @@ impl<'db> TypeInferenceBuilder<'db> {
| KnownClass::Super | KnownClass::Super
| KnownClass::TypeVar | KnownClass::TypeVar
| KnownClass::NamedTuple | KnownClass::NamedTuple
| KnownClass::TypeAliasType
) )
) )
// temporary special-casing for all subclasses of `enum.Enum` // temporary special-casing for all subclasses of `enum.Enum`
@ -5363,6 +5365,50 @@ impl<'db> TypeInferenceBuilder<'db> {
)); ));
} }
KnownClass::TypeAliasType => {
let assigned_to = (self.index)
.try_expression(call_expression_node)
.and_then(|expr| expr.assigned_to(self.db()));
let containing_assignment =
assigned_to.as_ref().and_then(|assigned_to| {
match assigned_to.node().targets.as_slice() {
[ast::Expr::Name(target)] => Some(
self.index.expect_single_definition(target),
),
_ => None,
}
});
let [Some(name), Some(value), ..] =
overload.parameter_types()
else {
continue;
};
if let Some(name) = name.into_string_literal() {
overload.set_return_type(Type::KnownInstance(
KnownInstanceType::TypeAliasType(
TypeAliasType::Bare(BareTypeAliasType::new(
self.db(),
ast::name::Name::new(name.value(self.db())),
containing_assignment,
value,
)),
),
));
} else {
if let Some(builder) = self.context.report_lint(
&INVALID_TYPE_ALIAS_TYPE,
call_expression,
) {
builder.into_diagnostic(format_args!(
"The name of a `typing.TypeAlias` must be a string literal",
));
}
}
}
_ => (), _ => (),
} }
} }

View file

@ -550,6 +550,16 @@
} }
] ]
}, },
"invalid-type-alias-type": {
"title": "detects invalid TypeAliasType definitions",
"description": "## What it does\nChecks for the creation of invalid `TypeAliasType`s\n\n## Why is this bad?\nThere are several requirements that you must follow when creating a `TypeAliasType`.\n\n## Examples\n```python\nfrom typing import TypeAliasType\n\nIntOrStr = TypeAliasType(\"IntOrStr\", int | str) # okay\nNewAlias = TypeAliasType(get_name(), int) # error: TypeAliasType name must be a string literal\n```",
"default": "error",
"oneOf": [
{
"$ref": "#/definitions/Level"
}
]
},
"invalid-type-checking-constant": { "invalid-type-checking-constant": {
"title": "detects invalid `TYPE_CHECKING` constant assignments", "title": "detects invalid `TYPE_CHECKING` constant assignments",
"description": "## What it does\nChecks for a value other than `False` assigned to the `TYPE_CHECKING` variable, or an\nannotation not assignable from `bool`.\n\n## Why is this bad?\nThe name `TYPE_CHECKING` is reserved for a flag that can be used to provide conditional\ncode seen only by the type checker, and not at runtime. Normally this flag is imported from\n`typing` or `typing_extensions`, but it can also be defined locally. If defined locally, it\nmust be assigned the value `False` at runtime; the type checker will consider its value to\nbe `True`. If annotated, it must be annotated as a type that can accept `bool` values.\n\n## Examples\n```python\nTYPE_CHECKING: str\nTYPE_CHECKING = ''\n```", "description": "## What it does\nChecks for a value other than `False` assigned to the `TYPE_CHECKING` variable, or an\nannotation not assignable from `bool`.\n\n## Why is this bad?\nThe name `TYPE_CHECKING` is reserved for a flag that can be used to provide conditional\ncode seen only by the type checker, and not at runtime. Normally this flag is imported from\n`typing` or `typing_extensions`, but it can also be defined locally. If defined locally, it\nmust be assigned the value `False` at runtime; the type checker will consider its value to\nbe `True`. If annotated, it must be annotated as a type that can accept `bool` values.\n\n## Examples\n```python\nTYPE_CHECKING: str\nTYPE_CHECKING = ''\n```",