From e9b1fc3942557bb7ae93ab4106f6869db6aad3c0 Mon Sep 17 00:00:00 2001 From: David Peter Date: Wed, 4 Jun 2025 14:32:51 +0200 Subject: [PATCH] Introduce TypeAliasRef --- crates/ty_python_semantic/src/types.rs | 27 +++++++++++++++++++ .../src/types/class_base.rs | 1 + .../ty_python_semantic/src/types/display.rs | 1 + .../src/types/ide_support.rs | 2 ++ crates/ty_python_semantic/src/types/infer.rs | 5 ++++ .../src/types/type_ordering.rs | 4 +++ 6 files changed, 40 insertions(+) diff --git a/crates/ty_python_semantic/src/types.rs b/crates/ty_python_semantic/src/types.rs index aec03a73a6..af81ff210b 100644 --- a/crates/ty_python_semantic/src/types.rs +++ b/crates/ty_python_semantic/src/types.rs @@ -532,6 +532,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 +661,8 @@ impl<'db> Type<'db> { | Self::DataclassTransformer(_) | Self::SubclassOf(_) | Self::BoundSuper(_) => *self, + + Type::TypeAliasRef(_) => todo!(), } } @@ -670,6 +673,8 @@ impl<'db> Type<'db> { } match self { + Self::TypeAliasRef(_) => todo!(), + Self::AlwaysFalsy | Self::AlwaysTruthy | Self::Never @@ -987,6 +992,7 @@ impl<'db> Type<'db> { #[must_use] pub fn normalized(self, db: &'db dyn Db) -> Self { match self { + Type::TypeAliasRef(_) => todo!(), 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 +1069,10 @@ impl<'db> Type<'db> { (Type::Never, _) => true, (_, Type::Never) => false, + (_, Type::TypeAliasRef(_)) | (Type::TypeAliasRef(_), _) => { + todo!() + } + // Everything is a subtype of `object`. (_, Type::NominalInstance(instance)) if instance.class.is_object(db) => true, @@ -1789,6 +1799,8 @@ impl<'db> Type<'db> { (Type::Dynamic(_), _) | (_, Type::Dynamic(_)) => false, + (Type::TypeAliasRef(_), _) | (_, Type::TypeAliasRef(_)) => todo!(), + // 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 @@ -2237,6 +2249,7 @@ 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 { match self { + Type::TypeAliasRef(_) => todo!(), Type::Dynamic(_) => false, Type::Never | Type::FunctionLiteral(..) @@ -2311,6 +2324,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(_) => todo!(), Type::Dynamic(_) | Type::Never | Type::IntLiteral(..) @@ -2432,6 +2446,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(_) => todo!(), Type::FunctionLiteral(..) | Type::BoundMethod(_) | Type::WrapperDescriptor(_) @@ -2515,6 +2530,7 @@ impl<'db> Type<'db> { policy: MemberLookupPolicy, ) -> Option> { match self { + Type::TypeAliasRef(_) => todo!(), 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 +2682,7 @@ impl<'db> Type<'db> { /// ``` fn instance_member(&self, db: &'db dyn Db, name: &str) -> SymbolAndQualifiers<'db> { match self { + Type::TypeAliasRef(_) => todo!(), Type::Union(union) => { union.map_with_boundness_and_qualifiers(db, |elem| elem.instance_member(db, name)) } @@ -3047,6 +3064,7 @@ impl<'db> Type<'db> { let name_str = name.as_str(); match self { + Type::TypeAliasRef(_) => todo!(), Type::Union(union) => union .map_with_boundness(db, |elem| { elem.member_lookup_with_policy(db, name_str.into(), policy) @@ -3466,6 +3484,8 @@ impl<'db> Type<'db> { }; let truthiness = match self { + Type::TypeAliasRef(_) => todo!(), + Type::Dynamic(_) | Type::Never | Type::Callable(_) | Type::LiteralString => { Truthiness::Ambiguous } @@ -3590,6 +3610,7 @@ 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(_) => todo!(), Type::Callable(callable) => { CallableBinding::from_overloads(self, callable.signatures(db).iter().cloned()) .into() @@ -4847,6 +4868,7 @@ impl<'db> Type<'db> { #[must_use] pub fn to_instance(&self, db: &'db dyn Db) -> Option> { match self { + Type::TypeAliasRef(_) => todo!(), 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))), @@ -4922,6 +4944,7 @@ impl<'db> Type<'db> { scope_id: ScopeId<'db>, ) -> Result, InvalidTypeExpressionError<'db>> { match self { + Type::TypeAliasRef(_) => todo!(), // Special cases for `float` and `complex` // https://typing.python.org/en/latest/spec/special-types.html#special-cases-for-float-and-complex Type::ClassLiteral(class) => { @@ -5201,6 +5224,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::Never => Type::Never, Type::NominalInstance(instance) => instance.to_meta_type(db), Type::KnownInstance(known_instance) => known_instance.to_meta_type(db), @@ -5291,6 +5315,7 @@ impl<'db> Type<'db> { type_mapping: &TypeMapping<'a, 'db>, ) -> Type<'db> { match self { + Type::TypeAliasRef(_) => todo!(), Type::TypeVar(typevar) => match type_mapping { TypeMapping::Specialization(specialization) => { specialization.get(db, typevar).unwrap_or(self) @@ -5420,6 +5445,7 @@ impl<'db> Type<'db> { typevars: &mut FxOrderSet>, ) { match self { + Type::TypeAliasRef(_) => todo!(), Type::TypeVar(typevar) => { if typevar.is_legacy(db) { typevars.insert(typevar); @@ -5563,6 +5589,7 @@ impl<'db> Type<'db> { /// specific to the call site. pub fn definition(&self, db: &'db dyn Db) -> Option> { match self { + Type::TypeAliasRef(_) => todo!(), Self::BoundMethod(method) => { Some(TypeDefinition::Function(method.function(db).definition(db))) } diff --git a/crates/ty_python_semantic/src/types/class_base.rs b/crates/ty_python_semantic/src/types/class_base.rs index cf13ee5b38..43cd7be5f8 100644 --- a/crates/ty_python_semantic/src/types/class_base.rs +++ b/crates/ty_python_semantic/src/types/class_base.rs @@ -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 { match ty { + Type::TypeAliasRef(_) => todo!(), Type::Dynamic(dynamic) => Some(Self::Dynamic(dynamic)), Type::ClassLiteral(literal) => { if literal.is_known(db, KnownClass::Any) { diff --git a/crates/ty_python_semantic/src/types/display.rs b/crates/ty_python_semantic/src/types/display.rs index 645a102e84..6f8587804d 100644 --- a/crates/ty_python_semantic/src/types/display.rs +++ b/crates/ty_python_semantic/src/types/display.rs @@ -67,6 +67,7 @@ struct DisplayRepresentation<'db> { impl Display for DisplayRepresentation<'_> { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { match self.ty { + Type::TypeAliasRef(_) => todo!(), Type::Dynamic(dynamic) => dynamic.fmt(f), Type::Never => f.write_str("Never"), Type::NominalInstance(instance) => { diff --git a/crates/ty_python_semantic/src/types/ide_support.rs b/crates/ty_python_semantic/src/types/ide_support.rs index 2ba4606d6a..19f14a1353 100644 --- a/crates/ty_python_semantic/src/types/ide_support.rs +++ b/crates/ty_python_semantic/src/types/ide_support.rs @@ -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) diff --git a/crates/ty_python_semantic/src/types/infer.rs b/crates/ty_python_semantic/src/types/infer.rs index af77abaabc..6c581b312b 100644 --- a/crates/ty_python_semantic/src/types/infer.rs +++ b/crates/ty_python_semantic/src/types/infer.rs @@ -3012,6 +3012,7 @@ impl<'db> TypeInferenceBuilder<'db> { }; match object_ty { + Type::TypeAliasRef(_) => 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::Dynamic(_)) => operand_type, (_, Type::Never) => Type::Never, @@ -6174,6 +6177,8 @@ impl<'db> TypeInferenceBuilder<'db> { } match (left_ty, right_ty, op) { + (Type::TypeAliasRef(_), _, _) | (_, Type::TypeAliasRef(_), _) => todo!(), + (Type::Union(lhs_union), rhs, _) => { let mut union = UnionBuilder::new(self.db()); for lhs in lhs_union.elements(self.db()) { diff --git a/crates/ty_python_semantic/src/types/type_ordering.rs b/crates/ty_python_semantic/src/types/type_ordering.rs index 669d116fd9..d699e06e1f 100644 --- a/crates/ty_python_semantic/src/types/type_ordering.rs +++ b/crates/ty_python_semantic/src/types/type_ordering.rs @@ -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,