Compare commits
2 Commits
micha/rele
...
cjm/pep613
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
79a1305bf7 | ||
|
|
546c7e43c0 |
@@ -16,7 +16,7 @@ Alias: TypeAlias = int
|
||||
|
||||
def f(*args: Unpack[Ts]) -> tuple[Unpack[Ts]]:
|
||||
reveal_type(args) # revealed: tuple[@Todo(`Unpack[]` special form), ...]
|
||||
reveal_type(Alias) # revealed: @Todo(Support for `typing.TypeAlias`)
|
||||
reveal_type(Alias) # revealed: Alias
|
||||
return args
|
||||
|
||||
def g() -> TypeGuard[int]: ...
|
||||
|
||||
@@ -2187,9 +2187,9 @@ reveal_type(False.real) # revealed: Literal[0]
|
||||
All attribute access on literal `bytes` types is currently delegated to `builtins.bytes`:
|
||||
|
||||
```py
|
||||
# revealed: bound method Literal[b"foo"].join(iterable_of_bytes: Iterable[@Todo(Support for `typing.TypeAlias`)], /) -> bytes
|
||||
# revealed: bound method Literal[b"foo"].join(iterable_of_bytes: Iterable[Buffer], /) -> bytes
|
||||
reveal_type(b"foo".join)
|
||||
# revealed: bound method Literal[b"foo"].endswith(suffix: @Todo(Support for `typing.TypeAlias`) | tuple[@Todo(Support for `typing.TypeAlias`), ...], start: SupportsIndex | None = None, end: SupportsIndex | None = None, /) -> bool
|
||||
# revealed: bound method Literal[b"foo"].endswith(suffix: Buffer | tuple[Buffer, ...], start: SupportsIndex | None = None, end: SupportsIndex | None = None, /) -> bool
|
||||
reveal_type(b"foo".endswith)
|
||||
```
|
||||
|
||||
|
||||
@@ -313,8 +313,7 @@ reveal_type(A() + "foo") # revealed: A
|
||||
reveal_type("foo" + A()) # revealed: A
|
||||
|
||||
reveal_type(A() + b"foo") # revealed: A
|
||||
# TODO should be `A` since `bytes.__add__` doesn't support `A` instances
|
||||
reveal_type(b"foo" + A()) # revealed: bytes
|
||||
reveal_type(b"foo" + A()) # revealed: A
|
||||
|
||||
reveal_type(A() + ()) # revealed: A
|
||||
reveal_type(() + A()) # revealed: A
|
||||
|
||||
@@ -54,10 +54,8 @@ reveal_type(2**largest_u32) # revealed: int
|
||||
|
||||
def variable(x: int):
|
||||
reveal_type(x**2) # revealed: int
|
||||
# TODO: should be `Any` (overload 5 on `__pow__`), requires correct overload matching
|
||||
reveal_type(2**x) # revealed: int
|
||||
# TODO: should be `Any` (overload 5 on `__pow__`), requires correct overload matching
|
||||
reveal_type(x**x) # revealed: int
|
||||
reveal_type(2**x) # revealed: Any
|
||||
reveal_type(x**x) # revealed: Any
|
||||
```
|
||||
|
||||
If the second argument is \<0, a `float` is returned at runtime. If the first argument is \<0 but
|
||||
|
||||
@@ -127,7 +127,7 @@ x = lambda y: y
|
||||
reveal_type(x.__code__) # revealed: CodeType
|
||||
reveal_type(x.__name__) # revealed: str
|
||||
reveal_type(x.__defaults__) # revealed: tuple[Any, ...] | None
|
||||
reveal_type(x.__annotations__) # revealed: dict[str, @Todo(Support for `typing.TypeAlias`)]
|
||||
reveal_type(x.__annotations__) # revealed: dict[str, AnnotationForm]
|
||||
reveal_type(x.__dict__) # revealed: dict[str, Any]
|
||||
reveal_type(x.__doc__) # revealed: str | None
|
||||
reveal_type(x.__kwdefaults__) # revealed: dict[str, Any] | None
|
||||
|
||||
@@ -146,13 +146,11 @@ def _(flag: bool):
|
||||
def _(flag: bool):
|
||||
x = 1 if flag else "a"
|
||||
|
||||
# TODO: this should cause us to emit a diagnostic during
|
||||
# type checking
|
||||
# error: [invalid-argument-type]
|
||||
if isinstance(x, "a"):
|
||||
reveal_type(x) # revealed: Literal[1, "a"]
|
||||
|
||||
# TODO: this should cause us to emit a diagnostic during
|
||||
# type checking
|
||||
# error: [invalid-argument-type]
|
||||
if isinstance(x, "int"):
|
||||
reveal_type(x) # revealed: Literal[1, "a"]
|
||||
```
|
||||
|
||||
@@ -214,20 +214,13 @@ def flag() -> bool:
|
||||
|
||||
t = int if flag() else str
|
||||
|
||||
# TODO: this should cause us to emit a diagnostic during
|
||||
# type checking
|
||||
# error: [invalid-argument-type]
|
||||
if issubclass(t, "str"):
|
||||
reveal_type(t) # revealed: <class 'int'> | <class 'str'>
|
||||
|
||||
# TODO: this should cause us to emit a diagnostic during
|
||||
# type checking
|
||||
# TODO error: [invalid-argument-type]
|
||||
if issubclass(t, (bytes, "str")):
|
||||
reveal_type(t) # revealed: <class 'int'> | <class 'str'>
|
||||
|
||||
# TODO: this should cause us to emit a diagnostic during
|
||||
# type checking
|
||||
if issubclass(t, Any):
|
||||
reveal_type(t) # revealed: <class 'int'> | <class 'str'>
|
||||
```
|
||||
|
||||
### Do not narrow if there are keyword arguments
|
||||
|
||||
@@ -0,0 +1,272 @@
|
||||
# PEP 613 explicit type aliases
|
||||
|
||||
```toml
|
||||
[environment]
|
||||
python-version = "3.10"
|
||||
```
|
||||
|
||||
Explicit type aliases were introduced in PEP 613. They are defined using an annotated-assignment
|
||||
statement, annotated with `typing.TypeAlias`:
|
||||
|
||||
## Basic
|
||||
|
||||
```py
|
||||
from typing import TypeAlias
|
||||
|
||||
MyInt: TypeAlias = int
|
||||
|
||||
def f(x: MyInt):
|
||||
reveal_type(x) # revealed: int
|
||||
|
||||
f(1)
|
||||
```
|
||||
|
||||
## Union
|
||||
|
||||
For more complex type aliases, such as those involving unions or generics, the inferred value type
|
||||
of the right-hand side is not a valid type for use in a type expression, and we need to infer it as
|
||||
a type expression.
|
||||
|
||||
### Old syntax
|
||||
|
||||
```py
|
||||
from typing import TypeAlias, Union
|
||||
|
||||
IntOrStr: TypeAlias = Union[int, str]
|
||||
|
||||
def f(x: IntOrStr):
|
||||
reveal_type(x) # revealed: int | str
|
||||
if isinstance(x, int):
|
||||
reveal_type(x) # revealed: int
|
||||
else:
|
||||
reveal_type(x) # revealed: str
|
||||
|
||||
f(1)
|
||||
f("foo")
|
||||
```
|
||||
|
||||
### New syntax
|
||||
|
||||
```py
|
||||
from typing import TypeAlias
|
||||
|
||||
IntOrStr: TypeAlias = int | str
|
||||
|
||||
def f(x: IntOrStr):
|
||||
reveal_type(x) # revealed: int | str
|
||||
if isinstance(x, int):
|
||||
reveal_type(x) # revealed: int
|
||||
else:
|
||||
reveal_type(x) # revealed: str
|
||||
|
||||
f(1)
|
||||
f("foo")
|
||||
```
|
||||
|
||||
### Name resolution is not deferred
|
||||
|
||||
Unlike with a PEP 695 type alias, the right-hand side of a PEP 613 type alias is evaluated
|
||||
immediately, name resolution is not deferred.
|
||||
|
||||
```py
|
||||
from typing import TypeAlias
|
||||
|
||||
A: TypeAlias = B | None # error: [unresolved-reference]
|
||||
B: TypeAlias = int
|
||||
|
||||
def _(a: A):
|
||||
reveal_type(a) # revealed: Unknown | None
|
||||
```
|
||||
|
||||
## Multiple layers of union aliases
|
||||
|
||||
```py
|
||||
from typing import TypeAlias
|
||||
|
||||
class A: ...
|
||||
class B: ...
|
||||
class C: ...
|
||||
class D: ...
|
||||
|
||||
W: TypeAlias = A | B
|
||||
X: TypeAlias = C | D
|
||||
Y: TypeAlias = W | X
|
||||
|
||||
from ty_extensions import is_equivalent_to, static_assert
|
||||
|
||||
static_assert(is_equivalent_to(Y, A | B | C | D))
|
||||
```
|
||||
|
||||
## Cycles
|
||||
|
||||
We also support cyclic type aliases:
|
||||
|
||||
### Old syntax
|
||||
|
||||
```py
|
||||
from typing import Union, TypeAlias
|
||||
|
||||
MiniJSON: TypeAlias = Union[int, str, list["MiniJSON"]]
|
||||
|
||||
def f(x: MiniJSON):
|
||||
reveal_type(x) # revealed: int | str | list[MiniJSON]
|
||||
if isinstance(x, int):
|
||||
reveal_type(x) # revealed: int
|
||||
elif isinstance(x, str):
|
||||
reveal_type(x) # revealed: str
|
||||
else:
|
||||
reveal_type(x) # revealed: list[MiniJSON]
|
||||
|
||||
f(1)
|
||||
f("foo")
|
||||
f([1, "foo"])
|
||||
```
|
||||
|
||||
### New syntax
|
||||
|
||||
```py
|
||||
from typing import TypeAlias
|
||||
|
||||
MiniJSON: TypeAlias = int | str | list["MiniJSON"]
|
||||
|
||||
def f(x: MiniJSON):
|
||||
reveal_type(x) # revealed: int | str | list[MiniJSON]
|
||||
if isinstance(x, int):
|
||||
reveal_type(x) # revealed: int
|
||||
elif isinstance(x, str):
|
||||
reveal_type(x) # revealed: str
|
||||
else:
|
||||
reveal_type(x) # revealed: list[MiniJSON]
|
||||
|
||||
f(1)
|
||||
f("foo")
|
||||
f([1, "foo"])
|
||||
```
|
||||
|
||||
### Generic
|
||||
|
||||
```py
|
||||
from typing import TypeAlias, Generic, TypeVar, Union
|
||||
|
||||
T = TypeVar("T")
|
||||
|
||||
Alias: TypeAlias = Union[list["Alias"], int]
|
||||
|
||||
class A(Generic[T]):
|
||||
pass
|
||||
|
||||
class B(A[Alias]):
|
||||
pass
|
||||
```
|
||||
|
||||
### Mutually recursive
|
||||
|
||||
```py
|
||||
from typing import TypeAlias
|
||||
|
||||
A: TypeAlias = tuple["B"] | None
|
||||
B: TypeAlias = tuple[A] | None
|
||||
|
||||
def f(x: A):
|
||||
if x is not None:
|
||||
reveal_type(x) # revealed: tuple[B]
|
||||
y = x[0]
|
||||
if y is not None:
|
||||
reveal_type(y) # revealed: tuple[A]
|
||||
|
||||
def g(x: A | B):
|
||||
reveal_type(x) # revealed: tuple[B] | None
|
||||
|
||||
from ty_extensions import Intersection
|
||||
|
||||
def h(x: Intersection[A, B]):
|
||||
reveal_type(x) # revealed: tuple[B] | None
|
||||
```
|
||||
|
||||
### Self-recursive callable type
|
||||
|
||||
```py
|
||||
from typing import Callable, TypeAlias
|
||||
|
||||
C: TypeAlias = Callable[[], "C" | None]
|
||||
|
||||
def _(x: C):
|
||||
reveal_type(x) # revealed: () -> C | None
|
||||
```
|
||||
|
||||
### Union inside generic
|
||||
|
||||
#### With old-style union
|
||||
|
||||
```py
|
||||
from typing import Union, TypeAlias
|
||||
|
||||
A: TypeAlias = list[Union["A", str]]
|
||||
|
||||
def f(x: A):
|
||||
reveal_type(x) # revealed: list[A | str]
|
||||
for item in x:
|
||||
reveal_type(item) # revealed: list[A | str] | str
|
||||
```
|
||||
|
||||
#### With new-style union
|
||||
|
||||
```py
|
||||
from typing import TypeAlias
|
||||
|
||||
A: TypeAlias = list["A" | str]
|
||||
|
||||
def f(x: A):
|
||||
reveal_type(x) # revealed: list[A | str]
|
||||
for item in x:
|
||||
reveal_type(item) # revealed: list[A | str] | str
|
||||
```
|
||||
|
||||
#### With Optional
|
||||
|
||||
```py
|
||||
from typing import Optional, Union, TypeAlias
|
||||
|
||||
A: TypeAlias = list[Optional[Union["A", str]]]
|
||||
|
||||
def f(x: A):
|
||||
reveal_type(x) # revealed: list[A | str | None]
|
||||
for item in x:
|
||||
reveal_type(item) # revealed: list[A | str | None] | str | None
|
||||
```
|
||||
|
||||
### Invalid examples
|
||||
|
||||
#### No value
|
||||
|
||||
```py
|
||||
from typing import TypeAlias
|
||||
|
||||
# TODO: error
|
||||
Bad: TypeAlias
|
||||
|
||||
# Nested function so we don't emit unresolved-reference for `Bad`:
|
||||
def _():
|
||||
def f(x: Bad):
|
||||
reveal_type(x) # revealed: Unknown
|
||||
```
|
||||
|
||||
#### No value, in stub
|
||||
|
||||
`stub.pyi`:
|
||||
|
||||
```pyi
|
||||
from typing import TypeAlias
|
||||
|
||||
# TODO: error
|
||||
Bad: TypeAlias
|
||||
```
|
||||
|
||||
`main.py`:
|
||||
|
||||
```py
|
||||
from stub import Bad
|
||||
|
||||
def f(x: Bad):
|
||||
reveal_type(x) # revealed: Unknown
|
||||
```
|
||||
@@ -28,7 +28,7 @@ def f() -> None:
|
||||
```py
|
||||
type IntOrStr = int | str
|
||||
|
||||
reveal_type(IntOrStr.__value__) # revealed: @Todo(Support for `typing.TypeAlias`)
|
||||
reveal_type(IntOrStr.__value__) # revealed: Any
|
||||
```
|
||||
|
||||
## Invalid assignment
|
||||
|
||||
@@ -147,8 +147,8 @@ But perhaps the most commonly used tuple subclass instance is the singleton `sys
|
||||
```py
|
||||
import sys
|
||||
|
||||
# revealed: Overload[(self, index: Literal[-5, 0], /) -> Literal[3], (self, index: Literal[-4, 1], /) -> Literal[11], (self, index: Literal[-3, -1, 2, 4], /) -> int, (self, index: Literal[-2, 3], /) -> Literal["alpha", "beta", "candidate", "final"], (self, index: SupportsIndex, /) -> int | Literal["alpha", "beta", "candidate", "final"], (self, index: slice[Any, Any, Any], /) -> tuple[int | Literal["alpha", "beta", "candidate", "final"], ...]]
|
||||
reveal_type(type(sys.version_info).__getitem__)
|
||||
# TODO revealed: Overload[(self, index: Literal[-5, 0], /) -> Literal[3], (self, index: Literal[-4, 1], /) -> Literal[11], (self, index: Literal[-3, -1, 2, 4], /) -> int, (self, index: Literal[-2, 3], /) -> Literal["alpha", "beta", "candidate", "final"], (self, index: SupportsIndex, /) -> int | Literal["alpha", "beta", "candidate", "final"], (self, index: slice[Any, Any, Any], /) -> tuple[int | Literal["alpha", "beta", "candidate", "final"], ...]]
|
||||
reveal_type(type(sys.version_info).__getitem__) # revealed: Unknown
|
||||
```
|
||||
|
||||
Because of the synthesized `__getitem__` overloads we synthesize for tuples and tuple subclasses,
|
||||
|
||||
@@ -122,7 +122,7 @@ properties on instance types:
|
||||
|
||||
```py
|
||||
reveal_type(sys.version_info.micro) # revealed: int
|
||||
reveal_type(sys.version_info.releaselevel) # revealed: @Todo(Support for `typing.TypeAlias`)
|
||||
reveal_type(sys.version_info.releaselevel) # revealed: Literal["alpha", "beta", "candidate", "final"]
|
||||
reveal_type(sys.version_info.serial) # revealed: int
|
||||
```
|
||||
|
||||
|
||||
@@ -693,6 +693,15 @@ impl DefinitionKind<'_> {
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) const fn as_annotated_assignment(
|
||||
&self,
|
||||
) -> Option<&AnnotatedAssignmentDefinitionKind> {
|
||||
match self {
|
||||
DefinitionKind::AnnotatedAssignment(annotated_assignment) => Some(annotated_assignment),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn is_import(&self) -> bool {
|
||||
matches!(
|
||||
self,
|
||||
|
||||
@@ -6257,7 +6257,9 @@ impl<'db> Type<'db> {
|
||||
}),
|
||||
|
||||
Type::KnownInstance(known_instance) => match known_instance {
|
||||
KnownInstanceType::TypeAliasType(alias) => Ok(Type::TypeAlias(*alias)),
|
||||
KnownInstanceType::TypeAliasType(alias) | KnownInstanceType::TypeAlias(alias) => {
|
||||
Ok(Type::TypeAlias(*alias))
|
||||
}
|
||||
KnownInstanceType::TypeVar(typevar) => {
|
||||
let index = semantic_index(db, scope_id.file(db));
|
||||
Ok(bind_typevar(
|
||||
@@ -6353,7 +6355,7 @@ impl<'db> Type<'db> {
|
||||
)
|
||||
.unwrap_or(*self))
|
||||
}
|
||||
SpecialFormType::TypeAlias => Ok(Type::Dynamic(DynamicType::TodoTypeAlias)),
|
||||
SpecialFormType::TypeAlias => Ok(*self),
|
||||
SpecialFormType::TypedDict => Err(InvalidTypeExpressionError {
|
||||
invalid_expressions: smallvec::smallvec_inline![
|
||||
InvalidTypeExpression::TypedDict
|
||||
@@ -7490,6 +7492,10 @@ pub enum KnownInstanceType<'db> {
|
||||
/// A single instance of `typing.TypeAliasType` (PEP 695 type alias)
|
||||
TypeAliasType(TypeAliasType<'db>),
|
||||
|
||||
/// A single instance of a PEP 613 type alias (in other words, an arbitrary type form at
|
||||
/// runtime.)
|
||||
TypeAlias(TypeAliasType<'db>),
|
||||
|
||||
/// A single instance of `warnings.deprecated` or `typing_extensions.deprecated`
|
||||
Deprecated(DeprecatedInstance<'db>),
|
||||
|
||||
@@ -7514,7 +7520,7 @@ fn walk_known_instance_type<'db, V: visitor::TypeVisitor<'db> + ?Sized>(
|
||||
KnownInstanceType::TypeVar(typevar) => {
|
||||
visitor.visit_type_var_type(db, typevar);
|
||||
}
|
||||
KnownInstanceType::TypeAliasType(type_alias) => {
|
||||
KnownInstanceType::TypeAliasType(type_alias) | KnownInstanceType::TypeAlias(type_alias) => {
|
||||
visitor.visit_type_alias_type(db, type_alias);
|
||||
}
|
||||
KnownInstanceType::Deprecated(_) | KnownInstanceType::ConstraintSet(_) => {
|
||||
@@ -7538,7 +7544,7 @@ impl<'db> KnownInstanceType<'db> {
|
||||
Self::SubscriptedGeneric(context.normalized_impl(db, visitor))
|
||||
}
|
||||
Self::TypeVar(typevar) => Self::TypeVar(typevar.normalized_impl(db, visitor)),
|
||||
Self::TypeAliasType(type_alias) => {
|
||||
Self::TypeAliasType(type_alias) | Self::TypeAlias(type_alias) => {
|
||||
Self::TypeAliasType(type_alias.normalized_impl(db, visitor))
|
||||
}
|
||||
Self::Deprecated(deprecated) => {
|
||||
@@ -7561,6 +7567,8 @@ impl<'db> KnownInstanceType<'db> {
|
||||
KnownClass::GenericAlias
|
||||
}
|
||||
Self::TypeAliasType(_) => KnownClass::TypeAliasType,
|
||||
// A PEP 613 type alias could be any type form object at runtime:
|
||||
Self::TypeAlias(_) => KnownClass::Object,
|
||||
Self::Deprecated(_) => KnownClass::Deprecated,
|
||||
Self::Field(_) => KnownClass::Field,
|
||||
Self::ConstraintSet(_) => KnownClass::ConstraintSet,
|
||||
@@ -7617,6 +7625,7 @@ impl<'db> KnownInstanceType<'db> {
|
||||
f.write_str("typing.TypeAliasType")
|
||||
}
|
||||
}
|
||||
KnownInstanceType::TypeAlias(alias) => f.write_str(alias.name(self.db)),
|
||||
// This is a legacy `TypeVar` _outside_ of any generic class or function, so we render
|
||||
// it as an instance of `typing.TypeVar`. Inside of a generic class or function, we'll
|
||||
// have a `Type::TypeVar(_)`, which is rendered as the typevar's name.
|
||||
@@ -7684,9 +7693,6 @@ pub enum DynamicType<'db> {
|
||||
/// A special Todo-variant for PEP-695 `ParamSpec` types. A temporary variant to detect and special-
|
||||
/// case the handling of these types in `Callable` annotations.
|
||||
TodoPEP695ParamSpec,
|
||||
/// A special Todo-variant for type aliases declared using `typing.TypeAlias`.
|
||||
/// A temporary variant to detect and special-case the handling of these aliases in autocomplete suggestions.
|
||||
TodoTypeAlias,
|
||||
/// A special Todo-variant for `Unpack[Ts]`, so that we can treat it specially in `Generic[Unpack[Ts]]`
|
||||
TodoUnpack,
|
||||
/// A type that is determined to be divergent during type inference for a recursive function.
|
||||
@@ -7725,13 +7731,6 @@ impl std::fmt::Display for DynamicType<'_> {
|
||||
f.write_str("@Todo")
|
||||
}
|
||||
}
|
||||
DynamicType::TodoTypeAlias => {
|
||||
if cfg!(debug_assertions) {
|
||||
f.write_str("@Todo(Support for `typing.TypeAlias`)")
|
||||
} else {
|
||||
f.write_str("@Todo")
|
||||
}
|
||||
}
|
||||
DynamicType::Divergent(_) => f.write_str("Divergent"),
|
||||
}
|
||||
}
|
||||
@@ -10779,12 +10778,14 @@ impl<'db> ModuleLiteralType<'db> {
|
||||
}
|
||||
}
|
||||
|
||||
/// A PEP 695 type alias, created by the `type` statement.
|
||||
///
|
||||
/// # Ordering
|
||||
/// Ordering is based on the type alias's salsa-assigned id and not on its values.
|
||||
/// The id may change between runs, or when the alias was garbage collected and recreated.
|
||||
#[salsa::interned(debug, heap_size=ruff_memory_usage::heap_size)]
|
||||
#[derive(PartialOrd, Ord)]
|
||||
pub struct PEP695TypeAliasType<'db> {
|
||||
pub struct PEP695TypeAlias<'db> {
|
||||
#[returns(ref)]
|
||||
pub name: ast::name::Name,
|
||||
|
||||
@@ -10794,25 +10795,25 @@ pub struct PEP695TypeAliasType<'db> {
|
||||
}
|
||||
|
||||
// The Salsa heap is tracked separately.
|
||||
impl get_size2::GetSize for PEP695TypeAliasType<'_> {}
|
||||
impl get_size2::GetSize for PEP695TypeAlias<'_> {}
|
||||
|
||||
fn walk_pep_695_type_alias<'db, V: visitor::TypeVisitor<'db> + ?Sized>(
|
||||
db: &'db dyn Db,
|
||||
type_alias: PEP695TypeAliasType<'db>,
|
||||
type_alias: PEP695TypeAlias<'db>,
|
||||
visitor: &V,
|
||||
) {
|
||||
visitor.visit_type(db, type_alias.value_type(db));
|
||||
}
|
||||
|
||||
#[salsa::tracked]
|
||||
impl<'db> PEP695TypeAliasType<'db> {
|
||||
impl<'db> PEP695TypeAlias<'db> {
|
||||
pub(crate) fn definition(self, db: &'db dyn Db) -> Definition<'db> {
|
||||
let scope = self.rhs_scope(db);
|
||||
let type_alias_stmt_node = scope.node(db).expect_type_alias();
|
||||
semantic_index(db, scope.file(db)).expect_single_definition(type_alias_stmt_node)
|
||||
}
|
||||
|
||||
#[salsa::tracked(cycle_fn=value_type_cycle_recover, cycle_initial=value_type_cycle_initial, heap_size=ruff_memory_usage::heap_size)]
|
||||
#[salsa::tracked(cycle_fn=pep695_alias_value_type_cycle_recover, cycle_initial=pep695_alias_value_type_cycle_initial, heap_size=ruff_memory_usage::heap_size)]
|
||||
pub(crate) fn value_type(self, db: &'db dyn Db) -> Type<'db> {
|
||||
let scope = self.rhs_scope(db);
|
||||
let module = parsed_module(db, scope.file(db)).load(db);
|
||||
@@ -10836,7 +10837,7 @@ impl<'db> PEP695TypeAliasType<'db> {
|
||||
self,
|
||||
db: &'db dyn Db,
|
||||
f: impl FnOnce(GenericContext<'db>) -> Specialization<'db>,
|
||||
) -> PEP695TypeAliasType<'db> {
|
||||
) -> PEP695TypeAlias<'db> {
|
||||
match self.generic_context(db) {
|
||||
None => self,
|
||||
|
||||
@@ -10847,12 +10848,7 @@ impl<'db> PEP695TypeAliasType<'db> {
|
||||
// `typing.TypeAliasType` internally, and pass the specialization through to the value type,
|
||||
// except when resolving to an instance of the type alias, or its display representation.
|
||||
let specialization = f(generic_context);
|
||||
PEP695TypeAliasType::new(
|
||||
db,
|
||||
self.name(db),
|
||||
self.rhs_scope(db),
|
||||
Some(specialization),
|
||||
)
|
||||
PEP695TypeAlias::new(db, self.name(db), self.rhs_scope(db), Some(specialization))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -10889,28 +10885,31 @@ fn generic_context_cycle_recover<'db>(
|
||||
_db: &'db dyn Db,
|
||||
_value: &Option<GenericContext<'db>>,
|
||||
_count: u32,
|
||||
_self: PEP695TypeAliasType<'db>,
|
||||
_self: PEP695TypeAlias<'db>,
|
||||
) -> salsa::CycleRecoveryAction<Option<GenericContext<'db>>> {
|
||||
salsa::CycleRecoveryAction::Iterate
|
||||
}
|
||||
|
||||
fn generic_context_cycle_initial<'db>(
|
||||
_db: &'db dyn Db,
|
||||
_self: PEP695TypeAliasType<'db>,
|
||||
_self: PEP695TypeAlias<'db>,
|
||||
) -> Option<GenericContext<'db>> {
|
||||
None
|
||||
}
|
||||
|
||||
fn value_type_cycle_recover<'db>(
|
||||
fn pep695_alias_value_type_cycle_recover<'db>(
|
||||
_db: &'db dyn Db,
|
||||
_value: &Type<'db>,
|
||||
_count: u32,
|
||||
_self: PEP695TypeAliasType<'db>,
|
||||
_self: PEP695TypeAlias<'db>,
|
||||
) -> salsa::CycleRecoveryAction<Type<'db>> {
|
||||
salsa::CycleRecoveryAction::Iterate
|
||||
}
|
||||
|
||||
fn value_type_cycle_initial<'db>(_db: &'db dyn Db, _self: PEP695TypeAliasType<'db>) -> Type<'db> {
|
||||
fn pep695_alias_value_type_cycle_initial<'db>(
|
||||
_db: &'db dyn Db,
|
||||
_self: PEP695TypeAlias<'db>,
|
||||
) -> Type<'db> {
|
||||
Type::Never
|
||||
}
|
||||
|
||||
@@ -10921,7 +10920,7 @@ fn value_type_cycle_initial<'db>(_db: &'db dyn Db, _self: PEP695TypeAliasType<'d
|
||||
/// The id may change between runs, or when the alias was garbage collected and recreated.
|
||||
#[salsa::interned(debug, heap_size=ruff_memory_usage::heap_size)]
|
||||
#[derive(PartialOrd, Ord)]
|
||||
pub struct ManualPEP695TypeAliasType<'db> {
|
||||
pub struct ManualPEP695TypeAlias<'db> {
|
||||
#[returns(ref)]
|
||||
pub name: ast::name::Name,
|
||||
pub definition: Option<Definition<'db>>,
|
||||
@@ -10929,17 +10928,17 @@ pub struct ManualPEP695TypeAliasType<'db> {
|
||||
}
|
||||
|
||||
// The Salsa heap is tracked separately.
|
||||
impl get_size2::GetSize for ManualPEP695TypeAliasType<'_> {}
|
||||
impl get_size2::GetSize for ManualPEP695TypeAlias<'_> {}
|
||||
|
||||
fn walk_manual_pep_695_type_alias<'db, V: visitor::TypeVisitor<'db> + ?Sized>(
|
||||
db: &'db dyn Db,
|
||||
type_alias: ManualPEP695TypeAliasType<'db>,
|
||||
type_alias: ManualPEP695TypeAlias<'db>,
|
||||
visitor: &V,
|
||||
) {
|
||||
visitor.visit_type(db, type_alias.value(db));
|
||||
}
|
||||
|
||||
impl<'db> ManualPEP695TypeAliasType<'db> {
|
||||
impl<'db> ManualPEP695TypeAlias<'db> {
|
||||
fn normalized_impl(self, db: &'db dyn Db, visitor: &NormalizedVisitor<'db>) -> Self {
|
||||
Self::new(
|
||||
db,
|
||||
@@ -10950,14 +10949,89 @@ impl<'db> ManualPEP695TypeAliasType<'db> {
|
||||
}
|
||||
}
|
||||
|
||||
/// A PEP 613 type alias, annotated with `: typing.TypeAlias`.
|
||||
///
|
||||
/// # Ordering
|
||||
/// Ordering is based on the type alias's salsa-assigned id and not on its values.
|
||||
/// The id may change between runs, or when the alias was garbage collected and recreated.
|
||||
#[salsa::interned(debug, heap_size=ruff_memory_usage::heap_size)]
|
||||
#[derive(PartialOrd, Ord)]
|
||||
pub struct PEP613TypeAlias<'db> {
|
||||
#[returns(ref)]
|
||||
pub name: ast::name::Name,
|
||||
|
||||
/// The definition that created this type alias.
|
||||
pub definition: Definition<'db>,
|
||||
}
|
||||
|
||||
// The Salsa heap is tracked separately.
|
||||
impl get_size2::GetSize for PEP613TypeAlias<'_> {}
|
||||
|
||||
fn walk_pep_613_type_alias<'db, V: visitor::TypeVisitor<'db> + ?Sized>(
|
||||
db: &'db dyn Db,
|
||||
type_alias: PEP613TypeAlias<'db>,
|
||||
visitor: &V,
|
||||
) {
|
||||
visitor.visit_type(db, type_alias.value_type(db));
|
||||
}
|
||||
|
||||
#[salsa::tracked]
|
||||
impl<'db> PEP613TypeAlias<'db> {
|
||||
/// The type that this type alias refers to.
|
||||
#[salsa::tracked(cycle_fn=pep613_alias_value_type_cycle_recover, cycle_initial=pep613_alias_value_type_cycle_initial, heap_size=ruff_memory_usage::heap_size)]
|
||||
pub(crate) fn value_type(self, db: &'db dyn Db) -> Type<'db> {
|
||||
let definition = self.definition(db);
|
||||
let module = parsed_module(db, definition.file(db)).load(db);
|
||||
let value_node = self
|
||||
.definition(db)
|
||||
.kind(db)
|
||||
.as_annotated_assignment()
|
||||
// SAFETY: type inference won't create a PEP 613 type alias for any definition other
|
||||
// than an annotated assignment.
|
||||
.unwrap()
|
||||
.value(&module)
|
||||
// SAFETY: type inference won't create a PEP 613 type alias for an annotated assignment
|
||||
// with no right-hand side.
|
||||
.unwrap();
|
||||
definition_expression_type(db, definition, value_node)
|
||||
}
|
||||
|
||||
fn normalized_impl(self, _db: &'db dyn Db, _visitor: &NormalizedVisitor<'db>) -> Self {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
fn pep613_alias_value_type_cycle_recover<'db>(
|
||||
_db: &'db dyn Db,
|
||||
_value: &Type<'db>,
|
||||
_count: u32,
|
||||
_self: PEP613TypeAlias<'db>,
|
||||
) -> salsa::CycleRecoveryAction<Type<'db>> {
|
||||
salsa::CycleRecoveryAction::Iterate
|
||||
}
|
||||
|
||||
fn pep613_alias_value_type_cycle_initial<'db>(
|
||||
_db: &'db dyn Db,
|
||||
_self: PEP613TypeAlias<'db>,
|
||||
) -> Type<'db> {
|
||||
Type::Never
|
||||
}
|
||||
|
||||
/// Represents a type alias, whether PEP 695 or PEP 613.
|
||||
///
|
||||
/// PEP 613 type aliases are annotated with `: typing.TypeAlias`. PEP 695 type aliases are created
|
||||
/// via instances of `types.TypeAliasType`, whether manually instantiated or via the `type`
|
||||
/// statement.
|
||||
#[derive(
|
||||
Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, salsa::Update, get_size2::GetSize,
|
||||
)]
|
||||
pub enum TypeAliasType<'db> {
|
||||
/// A type alias defined using the PEP 695 `type` statement.
|
||||
PEP695(PEP695TypeAliasType<'db>),
|
||||
PEP695(PEP695TypeAlias<'db>),
|
||||
/// A type alias defined by manually instantiating the PEP 695 `types.TypeAliasType`.
|
||||
ManualPEP695(ManualPEP695TypeAliasType<'db>),
|
||||
ManualPEP695(ManualPEP695TypeAlias<'db>),
|
||||
/// A type alias defined with an annotation of the PEP 613 `typing.TypeAlias` type.
|
||||
PEP613(PEP613TypeAlias<'db>),
|
||||
}
|
||||
|
||||
fn walk_type_alias_type<'db, V: visitor::TypeVisitor<'db> + ?Sized>(
|
||||
@@ -10975,6 +11049,9 @@ fn walk_type_alias_type<'db, V: visitor::TypeVisitor<'db> + ?Sized>(
|
||||
TypeAliasType::ManualPEP695(type_alias) => {
|
||||
walk_manual_pep_695_type_alias(db, type_alias, visitor);
|
||||
}
|
||||
TypeAliasType::PEP613(type_alias) => {
|
||||
walk_pep_613_type_alias(db, type_alias, visitor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10987,6 +11064,9 @@ impl<'db> TypeAliasType<'db> {
|
||||
TypeAliasType::ManualPEP695(type_alias) => {
|
||||
TypeAliasType::ManualPEP695(type_alias.normalized_impl(db, visitor))
|
||||
}
|
||||
TypeAliasType::PEP613(type_alias) => {
|
||||
TypeAliasType::PEP613(type_alias.normalized_impl(db, visitor))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10994,6 +11074,7 @@ impl<'db> TypeAliasType<'db> {
|
||||
match self {
|
||||
TypeAliasType::PEP695(type_alias) => type_alias.name(db),
|
||||
TypeAliasType::ManualPEP695(type_alias) => type_alias.name(db),
|
||||
TypeAliasType::PEP613(type_alias) => type_alias.name(db),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11001,6 +11082,7 @@ impl<'db> TypeAliasType<'db> {
|
||||
match self {
|
||||
TypeAliasType::PEP695(type_alias) => Some(type_alias.definition(db)),
|
||||
TypeAliasType::ManualPEP695(type_alias) => type_alias.definition(db),
|
||||
TypeAliasType::PEP613(type_alias) => Some(type_alias.definition(db)),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11008,13 +11090,14 @@ impl<'db> TypeAliasType<'db> {
|
||||
match self {
|
||||
TypeAliasType::PEP695(type_alias) => type_alias.value_type(db),
|
||||
TypeAliasType::ManualPEP695(type_alias) => type_alias.value(db),
|
||||
TypeAliasType::PEP613(type_alias) => type_alias.value_type(db),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn as_pep_695_type_alias(self) -> Option<PEP695TypeAliasType<'db>> {
|
||||
pub(crate) fn as_pep_695_type_alias(self) -> Option<PEP695TypeAlias<'db>> {
|
||||
match self {
|
||||
TypeAliasType::PEP695(type_alias) => Some(type_alias),
|
||||
TypeAliasType::ManualPEP695(_) => None,
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11022,14 +11105,14 @@ impl<'db> TypeAliasType<'db> {
|
||||
// TODO: Add support for generic non-PEP695 type aliases.
|
||||
match self {
|
||||
TypeAliasType::PEP695(type_alias) => type_alias.generic_context(db),
|
||||
TypeAliasType::ManualPEP695(_) => None,
|
||||
TypeAliasType::ManualPEP695(_) | TypeAliasType::PEP613(_) => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn specialization(self, db: &'db dyn Db) -> Option<Specialization<'db>> {
|
||||
match self {
|
||||
TypeAliasType::PEP695(type_alias) => type_alias.specialization(db),
|
||||
TypeAliasType::ManualPEP695(_) => None,
|
||||
TypeAliasType::ManualPEP695(_) | TypeAliasType::PEP613(_) => None,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11042,7 +11125,7 @@ impl<'db> TypeAliasType<'db> {
|
||||
TypeAliasType::PEP695(type_alias) => {
|
||||
TypeAliasType::PEP695(type_alias.apply_specialization(db, f))
|
||||
}
|
||||
TypeAliasType::ManualPEP695(_) => self,
|
||||
TypeAliasType::ManualPEP695(_) | TypeAliasType::PEP613(_) => self,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -11702,7 +11785,7 @@ pub(super) fn determine_upper_bound<'db>(
|
||||
// Make sure that the `Type` enum does not grow unexpectedly.
|
||||
#[cfg(not(debug_assertions))]
|
||||
#[cfg(target_pointer_width = "64")]
|
||||
static_assertions::assert_eq_size!(Type, [u8; 16]);
|
||||
static_assertions::assert_eq_size!(Type, [u8; 24]);
|
||||
|
||||
#[cfg(test)]
|
||||
pub(crate) mod tests {
|
||||
|
||||
@@ -34,7 +34,7 @@ use crate::types::visitor::{NonAtomicType, TypeKind, TypeVisitor, walk_non_atomi
|
||||
use crate::types::{
|
||||
ApplyTypeMappingVisitor, Binding, BoundSuperType, CallableType, DataclassParams,
|
||||
DeprecatedInstance, FindLegacyTypeVarsVisitor, HasRelationToVisitor, IsDisjointVisitor,
|
||||
IsEquivalentVisitor, KnownInstanceType, ManualPEP695TypeAliasType, MaterializationKind,
|
||||
IsEquivalentVisitor, KnownInstanceType, ManualPEP695TypeAlias, MaterializationKind,
|
||||
NormalizedVisitor, PropertyInstanceType, StringLiteralType, TypeAliasType, TypeContext,
|
||||
TypeMapping, TypeRelation, TypedDictParams, UnionBuilder, VarianceInferable, declaration_type,
|
||||
determine_upper_bound, infer_definition_types,
|
||||
@@ -5328,7 +5328,7 @@ impl KnownClass {
|
||||
return;
|
||||
};
|
||||
overload.set_return_type(Type::KnownInstance(KnownInstanceType::TypeAliasType(
|
||||
TypeAliasType::ManualPEP695(ManualPEP695TypeAliasType::new(
|
||||
TypeAliasType::ManualPEP695(ManualPEP695TypeAlias::new(
|
||||
db,
|
||||
ast::name::Name::new(name.value(db)),
|
||||
containing_assignment,
|
||||
|
||||
@@ -49,10 +49,7 @@ impl<'db> ClassBase<'db> {
|
||||
ClassBase::Dynamic(DynamicType::Any) => "Any",
|
||||
ClassBase::Dynamic(DynamicType::Unknown) => "Unknown",
|
||||
ClassBase::Dynamic(
|
||||
DynamicType::Todo(_)
|
||||
| DynamicType::TodoPEP695ParamSpec
|
||||
| DynamicType::TodoTypeAlias
|
||||
| DynamicType::TodoUnpack,
|
||||
DynamicType::Todo(_) | DynamicType::TodoPEP695ParamSpec | DynamicType::TodoUnpack,
|
||||
) => "@Todo",
|
||||
ClassBase::Dynamic(DynamicType::Divergent(_)) => "Divergent",
|
||||
ClassBase::Protocol => "Protocol",
|
||||
@@ -168,6 +165,7 @@ impl<'db> ClassBase<'db> {
|
||||
KnownInstanceType::SubscriptedGeneric(_) => Some(Self::Generic),
|
||||
KnownInstanceType::SubscriptedProtocol(_) => Some(Self::Protocol),
|
||||
KnownInstanceType::TypeAliasType(_)
|
||||
| KnownInstanceType::TypeAlias(_)
|
||||
| KnownInstanceType::TypeVar(_)
|
||||
| KnownInstanceType::Deprecated(_)
|
||||
| KnownInstanceType::Field(_)
|
||||
|
||||
@@ -13,8 +13,7 @@ use crate::semantic_index::{
|
||||
use crate::types::call::{CallArguments, MatchedArgument};
|
||||
use crate::types::signatures::Signature;
|
||||
use crate::types::{
|
||||
ClassBase, ClassLiteral, DynamicType, KnownClass, KnownInstanceType, Type,
|
||||
class::CodeGeneratorKind,
|
||||
ClassBase, ClassLiteral, KnownClass, KnownInstanceType, Type, class::CodeGeneratorKind,
|
||||
};
|
||||
use crate::{Db, HasType, NameKind, SemanticModel};
|
||||
use ruff_db::files::{File, FileRange};
|
||||
@@ -268,9 +267,10 @@ impl<'db> AllMembers<'db> {
|
||||
}
|
||||
Type::ClassLiteral(class) if class.is_protocol(db) => continue,
|
||||
Type::KnownInstance(
|
||||
KnownInstanceType::TypeVar(_) | KnownInstanceType::TypeAliasType(_),
|
||||
KnownInstanceType::TypeVar(_)
|
||||
| KnownInstanceType::TypeAliasType(_)
|
||||
| KnownInstanceType::TypeAlias(_),
|
||||
) => continue,
|
||||
Type::Dynamic(DynamicType::TodoTypeAlias) => continue,
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -93,9 +93,9 @@ use crate::types::visitor::any_over_type;
|
||||
use crate::types::{
|
||||
CallDunderError, CallableBinding, CallableType, ClassLiteral, ClassType, DataclassParams,
|
||||
DynamicType, IntersectionBuilder, IntersectionType, KnownClass, KnownInstanceType,
|
||||
MemberLookupPolicy, MetaclassCandidate, PEP695TypeAliasType, Parameter, ParameterForm,
|
||||
Parameters, SpecialFormType, SubclassOfType, TrackedConstraintSet, Truthiness, Type,
|
||||
TypeAliasType, TypeAndQualifiers, TypeContext, TypeQualifiers,
|
||||
MemberLookupPolicy, MetaclassCandidate, PEP613TypeAlias, PEP695TypeAlias, Parameter,
|
||||
ParameterForm, Parameters, SpecialFormType, SubclassOfType, TrackedConstraintSet, Truthiness,
|
||||
Type, TypeAliasType, TypeAndQualifiers, TypeContext, TypeQualifiers,
|
||||
TypeVarBoundOrConstraintsEvaluation, TypeVarDefaultEvaluation, TypeVarIdentity,
|
||||
TypeVarInstance, TypeVarKind, TypeVarVariance, TypedDictType, UnionBuilder, UnionType,
|
||||
binding_type, todo_type,
|
||||
@@ -1281,6 +1281,9 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
|
||||
DefinitionKind::Assignment(assignment) => {
|
||||
self.infer_assignment_deferred(assignment.value(self.module()));
|
||||
}
|
||||
DefinitionKind::AnnotatedAssignment(annotated_assignment) => {
|
||||
self.infer_annotated_assignment_deferred(annotated_assignment);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
@@ -2709,7 +2712,7 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
|
||||
.to_scope_id(self.db(), self.file());
|
||||
|
||||
let type_alias_ty = Type::KnownInstance(KnownInstanceType::TypeAliasType(
|
||||
TypeAliasType::PEP695(PEP695TypeAliasType::new(
|
||||
TypeAliasType::PEP695(PEP695TypeAlias::new(
|
||||
self.db(),
|
||||
&type_alias.name.as_name_expr().unwrap().id,
|
||||
rhs_scope,
|
||||
@@ -4474,6 +4477,7 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
|
||||
}
|
||||
}
|
||||
|
||||
// Handle assignments to `TYPE_CHECKING`.
|
||||
if target
|
||||
.as_name_expr()
|
||||
.is_some_and(|name| &name.id == "TYPE_CHECKING")
|
||||
@@ -4502,6 +4506,43 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
|
||||
declared.inner = Type::BooleanLiteral(true);
|
||||
}
|
||||
|
||||
// If the target of an assignment is not one of the place expressions we support,
|
||||
// then they are not definitions, so we can only be here if the target is in a form supported as a place expression.
|
||||
// In this case, we can simply store types in `target` below, instead of calling `infer_expression` (which would return `Never`).
|
||||
debug_assert!(PlaceExpr::try_from_expr(target).is_some());
|
||||
|
||||
// Handle PEP 613 type aliases.
|
||||
if matches!(
|
||||
declared.inner,
|
||||
Type::SpecialForm(SpecialFormType::TypeAlias)
|
||||
) {
|
||||
let ty = if let Some(name_expr) = target.as_name_expr() {
|
||||
if value.is_some() {
|
||||
self.deferred.insert(definition);
|
||||
Type::KnownInstance(KnownInstanceType::TypeAlias(TypeAliasType::PEP613(
|
||||
PEP613TypeAlias::new(self.db(), name_expr.id.clone(), definition),
|
||||
)))
|
||||
} else {
|
||||
// TODO diagnostic: no RHS
|
||||
Type::unknown()
|
||||
}
|
||||
} else {
|
||||
// TODO diagnostic: target is not a name
|
||||
Type::unknown()
|
||||
};
|
||||
// TODO diagnostic if qualifiers are not empty
|
||||
if value.is_some() || self.in_stub() {
|
||||
self.add_declaration_with_binding(
|
||||
target.into(),
|
||||
definition,
|
||||
&DeclaredAndInferredType::AreTheSame(TypeAndQualifiers::declared(ty)),
|
||||
);
|
||||
} else {
|
||||
self.add_declaration(target.into(), definition, TypeAndQualifiers::declared(ty));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Handle various singletons.
|
||||
if let Some(name_expr) = target.as_name_expr() {
|
||||
if let Some(special_form) =
|
||||
@@ -4511,11 +4552,6 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
|
||||
}
|
||||
}
|
||||
|
||||
// If the target of an assignment is not one of the place expressions we support,
|
||||
// then they are not definitions, so we can only be here if the target is in a form supported as a place expression.
|
||||
// In this case, we can simply store types in `target` below, instead of calling `infer_expression` (which would return `Never`).
|
||||
debug_assert!(PlaceExpr::try_from_expr(target).is_some());
|
||||
|
||||
if let Some(value) = value {
|
||||
let inferred_ty = self.infer_maybe_standalone_expression(
|
||||
value,
|
||||
@@ -4557,6 +4593,16 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
|
||||
}
|
||||
}
|
||||
|
||||
fn infer_annotated_assignment_deferred(
|
||||
&mut self,
|
||||
assignment: &'db AnnotatedAssignmentDefinitionKind,
|
||||
) {
|
||||
// Annotated assignments defer the entire value expression in case of a PEP 613 type alias.
|
||||
// SAFETY `infer_annotated_assignment_definition` does not defer it there is no RHS
|
||||
let value_node = assignment.value(self.module()).unwrap();
|
||||
self.infer_type_expression(value_node);
|
||||
}
|
||||
|
||||
fn infer_augmented_assignment_statement(&mut self, assignment: &ast::StmtAugAssign) {
|
||||
if assignment.target.is_name_expr() {
|
||||
self.infer_definition(assignment);
|
||||
@@ -7783,8 +7829,7 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
|
||||
todo @ Type::Dynamic(
|
||||
DynamicType::Todo(_)
|
||||
| DynamicType::TodoPEP695ParamSpec
|
||||
| DynamicType::TodoUnpack
|
||||
| DynamicType::TodoTypeAlias,
|
||||
| DynamicType::TodoUnpack,
|
||||
),
|
||||
_,
|
||||
_,
|
||||
@@ -7794,8 +7839,7 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
|
||||
todo @ Type::Dynamic(
|
||||
DynamicType::Todo(_)
|
||||
| DynamicType::TodoPEP695ParamSpec
|
||||
| DynamicType::TodoUnpack
|
||||
| DynamicType::TodoTypeAlias,
|
||||
| DynamicType::TodoUnpack,
|
||||
),
|
||||
_,
|
||||
) => Some(todo),
|
||||
|
||||
@@ -811,6 +811,13 @@ impl<'db> TypeInferenceBuilder<'db, '_> {
|
||||
self.infer_type_expression(slice);
|
||||
todo_type!("Generic manual PEP-695 type alias")
|
||||
}
|
||||
KnownInstanceType::TypeAliasType(TypeAliasType::PEP613(_)) => {
|
||||
unreachable!("PEP 613 type aliases are not KnownInstance::TypeAliasType");
|
||||
}
|
||||
KnownInstanceType::TypeAlias(_) => {
|
||||
self.infer_type_expression(&subscript.slice);
|
||||
todo_type!("Generic PEP-613 type alias")
|
||||
}
|
||||
},
|
||||
Type::Dynamic(DynamicType::Todo(_)) => {
|
||||
self.infer_type_expression(slice);
|
||||
|
||||
@@ -272,9 +272,6 @@ fn dynamic_elements_ordering(left: DynamicType, right: DynamicType) -> Ordering
|
||||
(DynamicType::TodoUnpack, _) => Ordering::Less,
|
||||
(_, DynamicType::TodoUnpack) => Ordering::Greater,
|
||||
|
||||
(DynamicType::TodoTypeAlias, _) => Ordering::Less,
|
||||
(_, DynamicType::TodoTypeAlias) => Ordering::Greater,
|
||||
|
||||
(DynamicType::Divergent(left), DynamicType::Divergent(right)) => {
|
||||
left.scope.cmp(&right.scope)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user