[ty] Remove `GenericAlias`-related todo type (#21728)

## Summary

If you manage to create an `typing.GenericAlias` instance without us
knowing how that was created, then we don't know what to do with this in
a type annotation. So it's better to be explicit and show an error
instead of failing silently with a `@Todo` type.

## Test Plan

* New Markdown tests
* Zero ecosystem impact
This commit is contained in:
David Peter 2025-12-01 14:02:38 +01:00 committed by GitHub
parent 5358ddae88
commit 116fd7c7af
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 40 additions and 17 deletions

View File

@ -0,0 +1,34 @@
# GenericAlias in type expressions
We recognize if a `types.GenericAlias` instance is created by specializing a generic class. We don't
explicitly mention it in our type display, but `list[int]` in the example below is a `GenericAlias`
instance at runtime:
```py
Numbers = list[int]
# At runtime, `Numbers` is an instance of `types.GenericAlias`. Showing
# this as `list[int]` is more helpful, though:
reveal_type(Numbers) # revealed: <class 'list[int]'>
def _(numbers: Numbers) -> None:
reveal_type(numbers) # revealed: list[int]
```
It is also valid to create `GenericAlias` instances manually:
```py
from types import GenericAlias
Strings = GenericAlias(list, (str,))
reveal_type(Strings) # revealed: GenericAlias
```
However, using such a `GenericAlias` instance in a type expression is currently not supported:
```py
# error: [invalid-type-form] "Variable of type `GenericAlias` is not allowed in a type expression"
def _(strings: Strings) -> None:
reveal_type(strings) # revealed: Unknown
```

View File

@ -1,24 +1,16 @@
# NewType # NewType
## Valid forms ## Basic usage
`NewType` can be used to create distinct types that are based on existing types:
```py ```py
from typing_extensions import NewType from typing_extensions import NewType
from types import GenericAlias
X = GenericAlias(type, ()) UserId = NewType("UserId", int)
A = NewType("A", int)
# TODO: typeshed for `typing.GenericAlias` uses `type` for the first argument. `NewType` should be special-cased
# to be compatible with `type`
# error: [invalid-argument-type] "Argument to function `__new__` is incorrect: Expected `type`, found `<NewType pseudo-class 'A'>`"
B = GenericAlias(A, ())
def _( def _(user_id: UserId):
a: A, reveal_type(user_id) # revealed: UserId
b: B,
):
reveal_type(a) # revealed: A
reveal_type(b) # revealed: @Todo(Support for `typing.GenericAlias` instances in type expressions)
``` ```
## Subtyping ## Subtyping

View File

@ -7372,9 +7372,6 @@ impl<'db> Type<'db> {
Some(KnownClass::TypeVarTuple) => Ok(todo_type!( Some(KnownClass::TypeVarTuple) => Ok(todo_type!(
"Support for `typing.TypeVarTuple` instances in type expressions" "Support for `typing.TypeVarTuple` instances in type expressions"
)), )),
Some(KnownClass::GenericAlias) => Ok(todo_type!(
"Support for `typing.GenericAlias` instances in type expressions"
)),
_ => Err(InvalidTypeExpressionError { _ => Err(InvalidTypeExpressionError {
invalid_expressions: smallvec::smallvec_inline![ invalid_expressions: smallvec::smallvec_inline![
InvalidTypeExpression::InvalidType(*self, scope_id) InvalidTypeExpression::InvalidType(*self, scope_id)