Skip to content

Commit 3cb09eb

Browse files
[ty] Support typing.TypeForm (#25334)
## Summary `TypeForm[T]` describes a value that is a valid type expression representing a type assignable to `T`. Unlike `type[T]`, it can describe forms such as parameterized generics and unions, not only runtime class objects: ```python from typing import assert_type from typing_extensions import TypeForm def construct[T](form: TypeForm[T]) -> T: raise NotImplementedError assert_type(construct(int), int) assert_type(construct(list[int]), list[int]) assert_type(construct(int | str), int | str) ``` This PR adds support for `TypeForm[T]`, bringing us into alignment with the conformance suite. For bare `type`, we treat it as a runtime class value, but one that doesn't promise a specific represented type, so it's valid for broad TypeForm destinations, but not narrow ones: ```python def use_bare_runtime_class(runtime_type: type) -> None: any_form: TypeForm[Any] = runtime_type object_form: TypeForm[object] = runtime_type string_form: TypeForm[str] = runtime_type # error ``` Closes astral-sh/ty#2668.
1 parent c8cd59f commit 3cb09eb

25 files changed

Lines changed: 989 additions & 16 deletions

crates/ty_ide/src/completion.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2703,7 +2703,9 @@ fn completion_kind_from_type<'db>(db: &'db dyn Db, ty: Type<'db>) -> Option<Comp
27032703
| Type::NewTypeInstance(_)
27042704
| Type::EnumComplement(_) => CompletionKind::Struct,
27052705
Type::LiteralValue(literal) if literal.is_enum() => CompletionKind::Enum,
2706-
Type::LiteralValue(_) | Type::TypeIs(_) | Type::TypeGuard(_) => CompletionKind::Value,
2706+
Type::LiteralValue(_) | Type::TypeIs(_) | Type::TypeGuard(_) | Type::TypeForm(_) => {
2707+
CompletionKind::Value
2708+
}
27072709
Type::ProtocolInstance(_) => CompletionKind::Interface,
27082710
Type::TypeVar(_) => CompletionKind::TypeParameter,
27092711
Type::Union(union) => union

crates/ty_python_semantic/resources/mdtest/annotations/generic_alias.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,12 @@ Numbers = list[int]
1111
# this as `list[int]` is more helpful, though:
1212
reveal_type(Numbers) # revealed: <class 'list[int]'>
1313

14+
import types
15+
from typing_extensions import TypeForm
16+
17+
generic_alias: types.GenericAlias = list[int]
18+
generic_alias_typeform: TypeForm = list[int]
19+
1420
def _(numbers: Numbers) -> None:
1521
reveal_type(numbers) # revealed: list[int]
1622
```

0 commit comments

Comments
 (0)