Compare commits
7 Commits
micha/ty-p
...
david/opaq
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0252ee6531 | ||
|
|
969efae929 | ||
|
|
e08024ffda | ||
|
|
9981ac7ecc | ||
|
|
30c9a5d47e | ||
|
|
7684e23612 | ||
|
|
e9b1fc3942 |
@@ -20,7 +20,99 @@ x: IntOrStr = 1
|
||||
reveal_type(x) # revealed: Literal[1]
|
||||
|
||||
def f() -> None:
|
||||
reveal_type(x) # revealed: int | str
|
||||
reveal_type(x) # revealed: IntOrStr
|
||||
```
|
||||
|
||||
## Type properties
|
||||
|
||||
### Equivalence
|
||||
|
||||
```py
|
||||
from ty_extensions import static_assert, is_equivalent_to
|
||||
|
||||
type IntOrStr = int | str
|
||||
type StrOrInt = str | int
|
||||
|
||||
static_assert(is_equivalent_to(IntOrStr, IntOrStr))
|
||||
static_assert(is_equivalent_to(IntOrStr, StrOrInt))
|
||||
|
||||
type Rec1 = tuple[Rec1, int]
|
||||
type Rec2 = tuple[Rec2, int]
|
||||
|
||||
type Other = tuple[Other, str]
|
||||
|
||||
static_assert(is_equivalent_to(Rec1, Rec2))
|
||||
static_assert(not is_equivalent_to(Rec1, Other))
|
||||
|
||||
type Cycle1A = tuple[Cycle1B, int]
|
||||
type Cycle1B = tuple[Cycle1A, str]
|
||||
|
||||
type Cycle2A = tuple[Cycle2B, int]
|
||||
type Cycle2B = tuple[Cycle2A, str]
|
||||
|
||||
static_assert(is_equivalent_to(Cycle1A, Cycle2A))
|
||||
static_assert(is_equivalent_to(Cycle1B, Cycle2B))
|
||||
static_assert(not is_equivalent_to(Cycle1A, Cycle1B))
|
||||
static_assert(not is_equivalent_to(Cycle1A, Cycle2B))
|
||||
|
||||
# type Cycle3A = tuple[Cycle3B] | None
|
||||
# type Cycle3B = tuple[Cycle3A] | None
|
||||
|
||||
# static_assert(is_equivalent_to(Cycle3A, Cycle3A))
|
||||
# static_assert(is_equivalent_to(Cycle3A, Cycle3B))
|
||||
```
|
||||
|
||||
### Assignability
|
||||
|
||||
```py
|
||||
type IntOrStr = int | str
|
||||
|
||||
x1: IntOrStr = 1
|
||||
x2: IntOrStr = "1"
|
||||
x3: IntOrStr | None = None
|
||||
|
||||
def _(int_or_str: IntOrStr) -> None:
|
||||
# TODO: those should not be errors
|
||||
x3: int | str = int_or_str # error: [invalid-assignment]
|
||||
x4: int | str | None = int_or_str # error: [invalid-assignment]
|
||||
x5: int | str | None = int_or_str or None # error: [invalid-assignment]
|
||||
```
|
||||
|
||||
### Narrowing (intersections)
|
||||
|
||||
```py
|
||||
class P: ...
|
||||
class Q: ...
|
||||
|
||||
type EitherOr = P | Q
|
||||
|
||||
def _(x: EitherOr) -> None:
|
||||
if isinstance(x, P):
|
||||
reveal_type(x) # revealed: P
|
||||
elif isinstance(x, Q):
|
||||
reveal_type(x) # revealed: Q & ~P
|
||||
else:
|
||||
# TODO: This should be Never
|
||||
reveal_type(x) # revealed: EitherOr & ~P & ~Q
|
||||
```
|
||||
|
||||
### Fully static
|
||||
|
||||
```py
|
||||
from typing import Any
|
||||
from ty_extensions import static_assert, is_fully_static
|
||||
|
||||
type IntOrStr = int | str
|
||||
type RecFullyStatic = int | tuple[RecFullyStatic]
|
||||
|
||||
static_assert(is_fully_static(IntOrStr))
|
||||
static_assert(is_fully_static(RecFullyStatic))
|
||||
|
||||
type IntOrAny = int | Any
|
||||
type RecNotFullyStatic = Any | tuple[RecNotFullyStatic]
|
||||
|
||||
static_assert(not is_fully_static(IntOrAny))
|
||||
static_assert(not is_fully_static(RecNotFullyStatic))
|
||||
```
|
||||
|
||||
## `__value__` attribute
|
||||
@@ -49,7 +141,7 @@ type IntOrStrOrBytes = IntOrStr | bytes
|
||||
x: IntOrStrOrBytes = 1
|
||||
|
||||
def f() -> None:
|
||||
reveal_type(x) # revealed: int | str | bytes
|
||||
reveal_type(x) # revealed: IntOrStrOrBytes
|
||||
```
|
||||
|
||||
## Aliased type aliases
|
||||
@@ -109,7 +201,7 @@ reveal_type(IntOrStr) # revealed: typing.TypeAliasType
|
||||
reveal_type(IntOrStr.__name__) # revealed: Literal["IntOrStr"]
|
||||
|
||||
def f(x: IntOrStr) -> None:
|
||||
reveal_type(x) # revealed: int | str
|
||||
reveal_type(x) # revealed: IntOrStr
|
||||
```
|
||||
|
||||
### Generic example
|
||||
@@ -138,3 +230,12 @@ def get_name() -> str:
|
||||
# error: [invalid-type-alias-type] "The name of a `typing.TypeAlias` must be a string literal"
|
||||
IntOrStr = TypeAliasType(get_name(), int | str)
|
||||
```
|
||||
|
||||
## Recursive type aliases
|
||||
|
||||
```py
|
||||
type Recursive = dict[str, "Recursive"]
|
||||
|
||||
# TODO: this should not be an error
|
||||
r: Recursive = {"key": {}} # error: [invalid-assignment]
|
||||
```
|
||||
|
||||
@@ -396,10 +396,11 @@ type LiteralInt = TypeOf[int]
|
||||
type LiteralStr = TypeOf[str]
|
||||
type LiteralObject = TypeOf[object]
|
||||
|
||||
assert_type(bool, LiteralBool)
|
||||
assert_type(int, LiteralInt)
|
||||
assert_type(str, LiteralStr)
|
||||
assert_type(object, LiteralObject)
|
||||
# TODO: these should not be errors
|
||||
assert_type(bool, LiteralBool) # error: [type-assertion-failure]
|
||||
assert_type(int, LiteralInt) # error: [type-assertion-failure]
|
||||
assert_type(str, LiteralStr) # error: [type-assertion-failure]
|
||||
assert_type(object, LiteralObject) # error: [type-assertion-failure]
|
||||
|
||||
# bool
|
||||
|
||||
@@ -462,9 +463,10 @@ type LiteralBase = TypeOf[Base]
|
||||
type LiteralDerived = TypeOf[Derived]
|
||||
type LiteralUnrelated = TypeOf[Unrelated]
|
||||
|
||||
assert_type(Base, LiteralBase)
|
||||
assert_type(Derived, LiteralDerived)
|
||||
assert_type(Unrelated, LiteralUnrelated)
|
||||
# TODO: these should not be errors
|
||||
assert_type(Base, LiteralBase) # error: [type-assertion-failure]
|
||||
assert_type(Derived, LiteralDerived) # error: [type-assertion-failure]
|
||||
assert_type(Unrelated, LiteralUnrelated) # error: [type-assertion-failure]
|
||||
|
||||
static_assert(is_subtype_of(LiteralBase, type))
|
||||
static_assert(is_subtype_of(LiteralBase, object))
|
||||
|
||||
@@ -196,21 +196,21 @@ def _(
|
||||
bytes_or_falsy: bytes | AlwaysFalsy,
|
||||
falsy_or_bytes: AlwaysFalsy | bytes,
|
||||
):
|
||||
reveal_type(strings_or_truthy) # revealed: Literal[""] | AlwaysTruthy
|
||||
reveal_type(truthy_or_strings) # revealed: AlwaysTruthy | Literal[""]
|
||||
reveal_type(strings_or_truthy) # revealed: strings | AlwaysTruthy
|
||||
reveal_type(truthy_or_strings) # revealed: AlwaysTruthy | strings
|
||||
|
||||
reveal_type(strings_or_falsy) # revealed: Literal["foo"] | AlwaysFalsy
|
||||
reveal_type(falsy_or_strings) # revealed: AlwaysFalsy | Literal["foo"]
|
||||
reveal_type(strings_or_falsy) # revealed: strings | AlwaysFalsy
|
||||
reveal_type(falsy_or_strings) # revealed: AlwaysFalsy | strings
|
||||
|
||||
reveal_type(ints_or_truthy) # revealed: Literal[0] | AlwaysTruthy
|
||||
reveal_type(truthy_or_ints) # revealed: AlwaysTruthy | Literal[0]
|
||||
reveal_type(ints_or_truthy) # revealed: ints | AlwaysTruthy
|
||||
reveal_type(truthy_or_ints) # revealed: AlwaysTruthy | ints
|
||||
|
||||
reveal_type(ints_or_falsy) # revealed: Literal[1] | AlwaysFalsy
|
||||
reveal_type(falsy_or_ints) # revealed: AlwaysFalsy | Literal[1]
|
||||
reveal_type(ints_or_falsy) # revealed: ints | AlwaysFalsy
|
||||
reveal_type(falsy_or_ints) # revealed: AlwaysFalsy | ints
|
||||
|
||||
reveal_type(bytes_or_truthy) # revealed: Literal[b""] | AlwaysTruthy
|
||||
reveal_type(truthy_or_bytes) # revealed: AlwaysTruthy | Literal[b""]
|
||||
reveal_type(bytes_or_truthy) # revealed: bytes | AlwaysTruthy
|
||||
reveal_type(truthy_or_bytes) # revealed: AlwaysTruthy | bytes
|
||||
|
||||
reveal_type(bytes_or_falsy) # revealed: Literal[b"foo"] | AlwaysFalsy
|
||||
reveal_type(falsy_or_bytes) # revealed: AlwaysFalsy | Literal[b"foo"]
|
||||
reveal_type(bytes_or_falsy) # revealed: bytes | AlwaysFalsy
|
||||
reveal_type(falsy_or_bytes) # revealed: AlwaysFalsy | bytes
|
||||
```
|
||||
|
||||
@@ -260,6 +260,40 @@ fn member_lookup_cycle_initial<'db>(
|
||||
Symbol::bound(Type::Never).into()
|
||||
}
|
||||
|
||||
#[expect(clippy::trivially_copy_pass_by_ref)]
|
||||
fn is_fully_static_cycle_recover<'db>(
|
||||
_db: &'db dyn Db,
|
||||
_value: &bool,
|
||||
_count: u32,
|
||||
_self: Type<'db>,
|
||||
_dummy: (),
|
||||
) -> salsa::CycleRecoveryAction<bool> {
|
||||
salsa::CycleRecoveryAction::Iterate
|
||||
}
|
||||
|
||||
fn is_fully_static_cycle_initial<'db>(_db: &'db dyn Db, _self: Type<'db>, _dummy: ()) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
#[expect(clippy::trivially_copy_pass_by_ref)]
|
||||
fn is_equivalent_to_cycle_recover<'db>(
|
||||
_db: &'db dyn Db,
|
||||
_value: &bool,
|
||||
_count: u32,
|
||||
_self: Type<'db>,
|
||||
_other: Type<'db>,
|
||||
) -> salsa::CycleRecoveryAction<bool> {
|
||||
salsa::CycleRecoveryAction::Iterate
|
||||
}
|
||||
|
||||
fn is_equivalent_to_cycle_initial<'db>(
|
||||
_db: &'db dyn Db,
|
||||
_self: Type<'db>,
|
||||
_other: Type<'db>,
|
||||
) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
/// Meta data for `Type::Todo`, which represents a known limitation in ty.
|
||||
#[cfg(debug_assertions)]
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
|
||||
@@ -532,6 +566,7 @@ pub enum Type<'db> {
|
||||
// a `Type::NominalInstance` of `builtins.super`.
|
||||
BoundSuper(BoundSuperType<'db>),
|
||||
// TODO protocols, overloads, generics
|
||||
TypeAliasRef(TypeAliasType<'db>),
|
||||
}
|
||||
|
||||
#[salsa::tracked]
|
||||
@@ -660,6 +695,8 @@ impl<'db> Type<'db> {
|
||||
| Self::DataclassTransformer(_)
|
||||
| Self::SubclassOf(_)
|
||||
| Self::BoundSuper(_) => *self,
|
||||
|
||||
Type::TypeAliasRef(_) => todo_type!("replace_self_reference for TypeAliasRef"),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -670,6 +707,8 @@ impl<'db> Type<'db> {
|
||||
}
|
||||
|
||||
match self {
|
||||
Self::TypeAliasRef(_) => false, // TODO
|
||||
|
||||
Self::AlwaysFalsy
|
||||
| Self::AlwaysTruthy
|
||||
| Self::Never
|
||||
@@ -987,6 +1026,7 @@ impl<'db> Type<'db> {
|
||||
#[must_use]
|
||||
pub fn normalized(self, db: &'db dyn Db) -> Self {
|
||||
match self {
|
||||
Type::TypeAliasRef(_) => self,
|
||||
Type::Union(union) => Type::Union(union.normalized(db)),
|
||||
Type::Intersection(intersection) => Type::Intersection(intersection.normalized(db)),
|
||||
Type::Tuple(tuple) => Type::Tuple(tuple.normalized(db)),
|
||||
@@ -1063,6 +1103,9 @@ impl<'db> Type<'db> {
|
||||
(Type::Never, _) => true,
|
||||
(_, Type::Never) => false,
|
||||
|
||||
(left, Type::TypeAliasRef(right)) => left.is_subtype_of(db, right.value_type(db)),
|
||||
(Type::TypeAliasRef(left), right) => left.value_type(db).is_subtype_of(db, right),
|
||||
|
||||
// Everything is a subtype of `object`.
|
||||
(_, Type::NominalInstance(instance)) if instance.class.is_object(db) => true,
|
||||
|
||||
@@ -1682,6 +1725,8 @@ impl<'db> Type<'db> {
|
||||
/// This method returns `false` if either `self` or `other` is not fully static.
|
||||
///
|
||||
/// [equivalent to]: https://typing.python.org/en/latest/spec/glossary.html#term-equivalent
|
||||
|
||||
#[salsa::tracked(cycle_fn=is_equivalent_to_cycle_recover, cycle_initial=is_equivalent_to_cycle_initial)]
|
||||
pub(crate) fn is_equivalent_to(self, db: &'db dyn Db, other: Type<'db>) -> bool {
|
||||
// TODO equivalent but not identical types: TypedDicts, Protocols, type aliases, etc.
|
||||
|
||||
@@ -1711,6 +1756,9 @@ impl<'db> Type<'db> {
|
||||
| (nominal @ Type::NominalInstance(n), Type::ProtocolInstance(protocol)) => {
|
||||
n.class.is_object(db) && protocol.normalized(db) == nominal
|
||||
}
|
||||
(Type::TypeAliasRef(left), right) => left.value_type(db).is_equivalent_to(db, right),
|
||||
(left, Type::TypeAliasRef(right)) => left.is_equivalent_to(db, right.value_type(db)),
|
||||
|
||||
_ => self == other && self.is_fully_static(db) && other.is_fully_static(db),
|
||||
}
|
||||
}
|
||||
@@ -1789,6 +1837,9 @@ impl<'db> Type<'db> {
|
||||
|
||||
(Type::Dynamic(_), _) | (_, Type::Dynamic(_)) => false,
|
||||
|
||||
(Type::TypeAliasRef(left), right) => left.value_type(db).is_disjoint_from(db, right),
|
||||
(left, Type::TypeAliasRef(right)) => left.is_disjoint_from(db, right.value_type(db)),
|
||||
|
||||
// A typevar is never disjoint from itself, since all occurrences of the typevar must
|
||||
// be specialized to the same type. (This is an important difference between typevars
|
||||
// and `Any`!) Different typevars might be disjoint, depending on their bounds and
|
||||
@@ -2235,8 +2286,15 @@ impl<'db> Type<'db> {
|
||||
}
|
||||
|
||||
/// Returns true if the type does not contain any gradual forms (as a sub-part).
|
||||
pub(crate) fn is_fully_static(&self, db: &'db dyn Db) -> bool {
|
||||
pub(crate) fn is_fully_static(self, db: &'db dyn Db) -> bool {
|
||||
self.is_fully_static_impl(db, ())
|
||||
}
|
||||
|
||||
#[allow(clippy::used_underscore_binding)]
|
||||
#[salsa::tracked(cycle_fn=is_fully_static_cycle_recover, cycle_initial=is_fully_static_cycle_initial)]
|
||||
pub(crate) fn is_fully_static_impl(self, db: &'db dyn Db, _dummy: ()) -> bool {
|
||||
match self {
|
||||
Type::TypeAliasRef(alias) => alias.value_type(db).is_fully_static(db),
|
||||
Type::Dynamic(_) => false,
|
||||
Type::Never
|
||||
| Type::FunctionLiteral(..)
|
||||
@@ -2311,6 +2369,7 @@ impl<'db> Type<'db> {
|
||||
/// for more complicated types that are actually singletons.
|
||||
pub(crate) fn is_singleton(self, db: &'db dyn Db) -> bool {
|
||||
match self {
|
||||
Type::TypeAliasRef(_) => false, //TODO
|
||||
Type::Dynamic(_)
|
||||
| Type::Never
|
||||
| Type::IntLiteral(..)
|
||||
@@ -2432,6 +2491,7 @@ impl<'db> Type<'db> {
|
||||
/// Return true if this type is non-empty and all inhabitants of this type compare equal.
|
||||
pub(crate) fn is_single_valued(self, db: &'db dyn Db) -> bool {
|
||||
match self {
|
||||
Type::TypeAliasRef(_) => false, // TODO
|
||||
Type::FunctionLiteral(..)
|
||||
| Type::BoundMethod(_)
|
||||
| Type::WrapperDescriptor(_)
|
||||
@@ -2515,6 +2575,9 @@ impl<'db> Type<'db> {
|
||||
policy: MemberLookupPolicy,
|
||||
) -> Option<SymbolAndQualifiers<'db>> {
|
||||
match self {
|
||||
Type::TypeAliasRef(_) => {
|
||||
Some(Symbol::bound(todo_type!("TypeAliasRef::find_name_in_mro_with_policy")).into())
|
||||
}
|
||||
Type::Union(union) => Some(union.map_with_boundness_and_qualifiers(db, |elem| {
|
||||
elem.find_name_in_mro_with_policy(db, name, policy)
|
||||
// If some elements are classes, and some are not, we simply fall back to `Unbound` for the non-class
|
||||
@@ -2666,6 +2729,9 @@ impl<'db> Type<'db> {
|
||||
/// ```
|
||||
fn instance_member(&self, db: &'db dyn Db, name: &str) -> SymbolAndQualifiers<'db> {
|
||||
match self {
|
||||
Type::TypeAliasRef(_) => {
|
||||
Symbol::bound(todo_type!("TypeAliasRef::instance_member")).into()
|
||||
}
|
||||
Type::Union(union) => {
|
||||
union.map_with_boundness_and_qualifiers(db, |elem| elem.instance_member(db, name))
|
||||
}
|
||||
@@ -3047,6 +3113,7 @@ impl<'db> Type<'db> {
|
||||
let name_str = name.as_str();
|
||||
|
||||
match self {
|
||||
Type::TypeAliasRef(_) => Symbol::bound(todo_type!("type alias member lookup")).into(),
|
||||
Type::Union(union) => union
|
||||
.map_with_boundness(db, |elem| {
|
||||
elem.member_lookup_with_policy(db, name_str.into(), policy)
|
||||
@@ -3466,6 +3533,8 @@ impl<'db> Type<'db> {
|
||||
};
|
||||
|
||||
let truthiness = match self {
|
||||
Type::TypeAliasRef(_) => Truthiness::Ambiguous, // TODO
|
||||
|
||||
Type::Dynamic(_) | Type::Never | Type::Callable(_) | Type::LiteralString => {
|
||||
Truthiness::Ambiguous
|
||||
}
|
||||
@@ -3590,6 +3659,9 @@ impl<'db> Type<'db> {
|
||||
/// argument list, via [`try_call`][Self::try_call] and [`CallErrorKind::NotCallable`].
|
||||
fn bindings(self, db: &'db dyn Db) -> Bindings<'db> {
|
||||
match self {
|
||||
Type::TypeAliasRef(_) => {
|
||||
CallableBinding::not_callable(todo_type!("type alias bindings")).into()
|
||||
}
|
||||
Type::Callable(callable) => {
|
||||
CallableBinding::from_overloads(self, callable.signatures(db).iter().cloned())
|
||||
.into()
|
||||
@@ -4847,6 +4919,7 @@ impl<'db> Type<'db> {
|
||||
#[must_use]
|
||||
pub fn to_instance(&self, db: &'db dyn Db) -> Option<Type<'db>> {
|
||||
match self {
|
||||
Type::TypeAliasRef(_) => Some(todo_type!("Type::TypeAliasRef.to_instance")),
|
||||
Type::Dynamic(_) | Type::Never => Some(*self),
|
||||
Type::ClassLiteral(class) => Some(Type::instance(db, class.default_specialization(db))),
|
||||
Type::GenericAlias(alias) => Some(Type::instance(db, ClassType::from(*alias))),
|
||||
@@ -4969,7 +5042,8 @@ impl<'db> Type<'db> {
|
||||
| Type::FunctionLiteral(_)
|
||||
| Type::BoundSuper(_)
|
||||
| Type::ProtocolInstance(_)
|
||||
| Type::PropertyInstance(_) => Err(InvalidTypeExpressionError {
|
||||
| Type::PropertyInstance(_)
|
||||
| Type::TypeAliasRef(_) => Err(InvalidTypeExpressionError {
|
||||
invalid_expressions: smallvec::smallvec![InvalidTypeExpression::InvalidType(
|
||||
*self, scope_id
|
||||
)],
|
||||
@@ -4977,7 +5051,7 @@ impl<'db> Type<'db> {
|
||||
}),
|
||||
|
||||
Type::KnownInstance(known_instance) => match known_instance {
|
||||
KnownInstanceType::TypeAliasType(alias) => Ok(alias.value_type(db)),
|
||||
KnownInstanceType::TypeAliasType(alias) => Ok(Type::TypeAliasRef(*alias)),
|
||||
KnownInstanceType::TypeVar(typevar) => Ok(Type::TypeVar(*typevar)),
|
||||
KnownInstanceType::SubscriptedProtocol(_) => Err(InvalidTypeExpressionError {
|
||||
invalid_expressions: smallvec::smallvec![InvalidTypeExpression::Protocol],
|
||||
@@ -5201,6 +5275,7 @@ impl<'db> Type<'db> {
|
||||
#[must_use]
|
||||
pub fn to_meta_type(&self, db: &'db dyn Db) -> Type<'db> {
|
||||
match self {
|
||||
Type::TypeAliasRef(_) => todo_type!("Type::TypeAliasRef.to_meta_type"),
|
||||
Type::Never => Type::Never,
|
||||
Type::NominalInstance(instance) => instance.to_meta_type(db),
|
||||
Type::KnownInstance(known_instance) => known_instance.to_meta_type(db),
|
||||
@@ -5291,6 +5366,7 @@ impl<'db> Type<'db> {
|
||||
type_mapping: &TypeMapping<'a, 'db>,
|
||||
) -> Type<'db> {
|
||||
match self {
|
||||
Type::TypeAliasRef(_) => self,
|
||||
Type::TypeVar(typevar) => match type_mapping {
|
||||
TypeMapping::Specialization(specialization) => {
|
||||
specialization.get(db, typevar).unwrap_or(self)
|
||||
@@ -5420,6 +5496,7 @@ impl<'db> Type<'db> {
|
||||
typevars: &mut FxOrderSet<TypeVarInstance<'db>>,
|
||||
) {
|
||||
match self {
|
||||
Type::TypeAliasRef(_) => {} // TODO
|
||||
Type::TypeVar(typevar) => {
|
||||
if typevar.is_legacy(db) {
|
||||
typevars.insert(typevar);
|
||||
@@ -5563,6 +5640,7 @@ impl<'db> Type<'db> {
|
||||
/// specific to the call site.
|
||||
pub fn definition(&self, db: &'db dyn Db) -> Option<TypeDefinition<'db>> {
|
||||
match self {
|
||||
Type::TypeAliasRef(_) => None, // TODO
|
||||
Self::BoundMethod(method) => {
|
||||
Some(TypeDefinition::Function(method.function(db).definition(db)))
|
||||
}
|
||||
|
||||
@@ -63,6 +63,7 @@ impl<'db> ClassBase<'db> {
|
||||
/// Return `None` if `ty` is not an acceptable type for a class base.
|
||||
pub(super) fn try_from_type(db: &'db dyn Db, ty: Type<'db>) -> Option<Self> {
|
||||
match ty {
|
||||
Type::TypeAliasRef(_) => None, //TODO
|
||||
Type::Dynamic(dynamic) => Some(Self::Dynamic(dynamic)),
|
||||
Type::ClassLiteral(literal) => {
|
||||
if literal.is_known(db, KnownClass::Any) {
|
||||
|
||||
@@ -67,6 +67,7 @@ struct DisplayRepresentation<'db> {
|
||||
impl Display for DisplayRepresentation<'_> {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
||||
match self.ty {
|
||||
Type::TypeAliasRef(alias) => f.write_str(alias.name(self.db)),
|
||||
Type::Dynamic(dynamic) => dynamic.fmt(f),
|
||||
Type::Never => f.write_str("Never"),
|
||||
Type::NominalInstance(instance) => {
|
||||
|
||||
@@ -23,6 +23,8 @@ impl AllMembers {
|
||||
|
||||
fn extend_with_type<'db>(&mut self, db: &'db dyn Db, ty: Type<'db>) {
|
||||
match ty {
|
||||
Type::TypeAliasRef(_) => {} // TODO
|
||||
|
||||
Type::Union(union) => self.members.extend(
|
||||
union
|
||||
.elements(db)
|
||||
|
||||
@@ -3012,6 +3012,7 @@ impl<'db> TypeInferenceBuilder<'db> {
|
||||
};
|
||||
|
||||
match object_ty {
|
||||
Type::TypeAliasRef(_) => true, // TODO
|
||||
Type::Union(union) => {
|
||||
if union.elements(self.db()).iter().all(|elem| {
|
||||
self.validate_attribute_assignment(target, *elem, attribute, value_ty, false)
|
||||
@@ -6033,6 +6034,8 @@ impl<'db> TypeInferenceBuilder<'db> {
|
||||
let operand_type = self.infer_expression(operand);
|
||||
|
||||
match (op, operand_type) {
|
||||
(_, Type::TypeAliasRef(_)) => todo_type!("type alias in unary expression"),
|
||||
|
||||
(_, Type::Dynamic(_)) => operand_type,
|
||||
(_, Type::Never) => Type::Never,
|
||||
|
||||
@@ -6174,6 +6177,21 @@ impl<'db> TypeInferenceBuilder<'db> {
|
||||
}
|
||||
|
||||
match (left_ty, right_ty, op) {
|
||||
(Type::TypeAliasRef(alias), _, _) => self.infer_binary_expression_type(
|
||||
node,
|
||||
emitted_division_by_zero_diagnostic,
|
||||
alias.value_type(self.db()),
|
||||
right_ty,
|
||||
op,
|
||||
),
|
||||
(_, Type::TypeAliasRef(alias), _) => self.infer_binary_expression_type(
|
||||
node,
|
||||
emitted_division_by_zero_diagnostic,
|
||||
left_ty,
|
||||
alias.value_type(self.db()),
|
||||
op,
|
||||
),
|
||||
|
||||
(Type::Union(lhs_union), rhs, _) => {
|
||||
let mut union = UnionBuilder::new(self.db());
|
||||
for lhs in lhs_union.elements(self.db()) {
|
||||
|
||||
@@ -187,6 +187,10 @@ pub(super) fn union_or_intersection_elements_ordering<'db>(
|
||||
(Type::KnownInstance(_), _) => Ordering::Less,
|
||||
(_, Type::KnownInstance(_)) => Ordering::Greater,
|
||||
|
||||
(Type::TypeAliasRef(left), Type::TypeAliasRef(right)) => left.cmp(right),
|
||||
(Type::TypeAliasRef(_), _) => Ordering::Less,
|
||||
(_, Type::TypeAliasRef(_)) => Ordering::Greater,
|
||||
|
||||
(Type::PropertyInstance(left), Type::PropertyInstance(right)) => left.cmp(right),
|
||||
(Type::PropertyInstance(_), _) => Ordering::Less,
|
||||
(_, Type::PropertyInstance(_)) => Ordering::Greater,
|
||||
|
||||
Reference in New Issue
Block a user