[ty] Cleanup various APIs

This commit is contained in:
Alex Waygood 2025-10-27 20:32:45 +00:00
parent 13375d0e42
commit 1a30934c33
5 changed files with 42 additions and 83 deletions

View File

@ -819,17 +819,6 @@ impl<'db> Type<'db> {
.is_some_and(|instance| instance.has_known_class(db, KnownClass::NoneType)) .is_some_and(|instance| instance.has_known_class(db, KnownClass::NoneType))
} }
fn is_bool(&self, db: &'db dyn Db) -> bool {
self.as_nominal_instance()
.is_some_and(|instance| instance.has_known_class(db, KnownClass::Bool))
}
fn is_enum(&self, db: &'db dyn Db) -> bool {
self.as_nominal_instance()
.and_then(|instance| crate::types::enums::enum_metadata(db, instance.class_literal(db)))
.is_some()
}
/// Return true if this type overrides __eq__ or __ne__ methods /// Return true if this type overrides __eq__ or __ne__ methods
fn overrides_equality(&self, db: &'db dyn Db) -> bool { fn overrides_equality(&self, db: &'db dyn Db) -> bool {
let check_dunder = |dunder_name, allowed_return_value| { let check_dunder = |dunder_name, allowed_return_value| {
@ -1142,7 +1131,7 @@ impl<'db> Type<'db> {
#[cfg(test)] #[cfg(test)]
#[track_caller] #[track_caller]
pub(crate) fn expect_function_literal(self) -> FunctionType<'db> { pub(crate) const fn expect_function_literal(self) -> FunctionType<'db> {
self.as_function_literal() self.as_function_literal()
.expect("Expected a Type::FunctionLiteral variant") .expect("Expected a Type::FunctionLiteral variant")
} }
@ -1152,42 +1141,42 @@ impl<'db> Type<'db> {
} }
pub(crate) fn is_union_of_single_valued(&self, db: &'db dyn Db) -> bool { pub(crate) fn is_union_of_single_valued(&self, db: &'db dyn Db) -> bool {
self.as_union().is_some_and(|union| { match self {
union.elements(db).iter().all(|ty| { Type::LiteralString => true,
ty.is_single_valued(db) Type::NominalInstance(instance) => {
|| ty.is_bool(db) instance.has_known_class(db, KnownClass::Bool)
|| ty.is_literal_string() || (enums::enum_metadata(db, instance.class_literal(db)).is_some()
|| (ty.is_enum(db) && !ty.overrides_equality(db)) && !self.overrides_equality(db))
}) }
}) || self.is_bool(db) Type::Union(union) => union.elements(db).iter().all(|element| {
|| self.is_literal_string() element.is_single_valued(db) || element.is_union_of_single_valued(db)
|| (self.is_enum(db) && !self.overrides_equality(db)) }),
_ => false,
}
} }
pub(crate) fn is_union_with_single_valued(&self, db: &'db dyn Db) -> bool { pub(crate) fn is_union_with_single_valued(&self, db: &'db dyn Db) -> bool {
self.as_union().is_some_and(|union| { match self {
union.elements(db).iter().any(|ty| { Type::LiteralString => true,
ty.is_single_valued(db) Type::NominalInstance(instance) => {
|| ty.is_bool(db) instance.has_known_class(db, KnownClass::Bool)
|| ty.is_literal_string() || (enums::enum_metadata(db, instance.class_literal(db)).is_some()
|| (ty.is_enum(db) && !ty.overrides_equality(db)) && !self.overrides_equality(db))
}) }
}) || self.is_bool(db) Type::Union(union) => union.elements(db).iter().any(|element| {
|| self.is_literal_string() element.is_single_valued(db) || element.is_union_of_single_valued(db)
|| (self.is_enum(db) && !self.overrides_equality(db)) }),
_ => false,
}
} }
pub(crate) fn as_string_literal(self) -> Option<StringLiteralType<'db>> { pub(crate) const fn as_string_literal(self) -> Option<StringLiteralType<'db>> {
match self { match self {
Type::StringLiteral(string_literal) => Some(string_literal), Type::StringLiteral(string_literal) => Some(string_literal),
_ => None, _ => None,
} }
} }
pub(crate) const fn is_literal_string(&self) -> bool {
matches!(self, Type::LiteralString)
}
pub(crate) fn string_literal(db: &'db dyn Db, string: &str) -> Self { pub(crate) fn string_literal(db: &'db dyn Db, string: &str) -> Self {
Self::StringLiteral(StringLiteralType::new(db, string)) Self::StringLiteral(StringLiteralType::new(db, string))
} }
@ -7291,20 +7280,6 @@ impl<'db> Type<'db> {
} }
} }
pub(crate) fn generic_origin(self, db: &'db dyn Db) -> Option<ClassLiteral<'db>> {
match self {
Type::GenericAlias(generic) => Some(generic.origin(db)),
Type::NominalInstance(instance) => {
if let ClassType::Generic(generic) = instance.class(db) {
Some(generic.origin(db))
} else {
None
}
}
_ => None,
}
}
pub(super) fn has_divergent_type(self, db: &'db dyn Db, div: Type<'db>) -> bool { pub(super) fn has_divergent_type(self, db: &'db dyn Db, div: Type<'db>) -> bool {
any_over_type(db, self, &|ty| ty == div, false) any_over_type(db, self, &|ty| ty == div, false)
} }
@ -11138,7 +11113,7 @@ impl<'db> TypeAliasType<'db> {
} }
} }
pub(crate) fn as_pep_695_type_alias(self) -> Option<PEP695TypeAliasType<'db>> { pub(crate) const fn as_pep_695_type_alias(self) -> Option<PEP695TypeAliasType<'db>> {
match self { match self {
TypeAliasType::PEP695(type_alias) => Some(type_alias), TypeAliasType::PEP695(type_alias) => Some(type_alias),
TypeAliasType::ManualPEP695(_) => None, TypeAliasType::ManualPEP695(_) => None,

View File

@ -256,15 +256,14 @@ impl<'a, 'db> FromIterator<(Argument<'a>, Option<Type<'db>>)> for CallArguments<
pub(crate) fn is_expandable_type<'db>(db: &'db dyn Db, ty: Type<'db>) -> bool { pub(crate) fn is_expandable_type<'db>(db: &'db dyn Db, ty: Type<'db>) -> bool {
match ty { match ty {
Type::NominalInstance(instance) => { Type::NominalInstance(instance) => {
let class = instance.class(db); instance.has_known_class(db, KnownClass::Bool)
class.is_known(db, KnownClass::Bool)
|| instance.tuple_spec(db).is_some_and(|spec| match &*spec { || instance.tuple_spec(db).is_some_and(|spec| match &*spec {
Tuple::Fixed(fixed_length_tuple) => fixed_length_tuple Tuple::Fixed(fixed_length_tuple) => fixed_length_tuple
.all_elements() .all_elements()
.any(|element| is_expandable_type(db, *element)), .any(|element| is_expandable_type(db, *element)),
Tuple::Variable(_) => false, Tuple::Variable(_) => false,
}) })
|| enum_metadata(db, class.class_literal(db).0).is_some() || enum_metadata(db, instance.class_literal(db)).is_some()
} }
Type::Union(_) => true, Type::Union(_) => true,
_ => false, _ => false,
@ -278,9 +277,7 @@ fn expand_type<'db>(db: &'db dyn Db, ty: Type<'db>) -> Option<Vec<Type<'db>>> {
// NOTE: Update `is_expandable_type` if this logic changes accordingly. // NOTE: Update `is_expandable_type` if this logic changes accordingly.
match ty { match ty {
Type::NominalInstance(instance) => { Type::NominalInstance(instance) => {
let class = instance.class(db); if instance.has_known_class(db, KnownClass::Bool) {
if class.is_known(db, KnownClass::Bool) {
return Some(vec![ return Some(vec![
Type::BooleanLiteral(true), Type::BooleanLiteral(true),
Type::BooleanLiteral(false), Type::BooleanLiteral(false),
@ -315,7 +312,7 @@ fn expand_type<'db>(db: &'db dyn Db, ty: Type<'db>) -> Option<Vec<Type<'db>>> {
}; };
} }
if let Some(enum_members) = enum_member_literals(db, class.class_literal(db).0, None) { if let Some(enum_members) = enum_member_literals(db, instance.class_literal(db), None) {
return Some(enum_members.collect()); return Some(enum_members.collect());
} }

View File

@ -377,10 +377,7 @@ impl<'db> ClassType<'db> {
} }
pub(super) fn has_pep_695_type_params(self, db: &'db dyn Db) -> bool { pub(super) fn has_pep_695_type_params(self, db: &'db dyn Db) -> bool {
match self { self.class_literal(db).0.has_pep_695_type_params(db)
Self::NonGeneric(class) => class.has_pep_695_type_params(db),
Self::Generic(generic) => generic.origin(db).has_pep_695_type_params(db),
}
} }
/// Returns the class literal and specialization for this class. For a non-generic class, this /// Returns the class literal and specialization for this class. For a non-generic class, this
@ -3463,11 +3460,10 @@ impl<'db> ClassLiteral<'db> {
) -> bool { ) -> bool {
let mut result = false; let mut result = false;
for explicit_base in class.explicit_bases(db) { for explicit_base in class.explicit_bases(db) {
let explicit_base_class_literal = match explicit_base { let Some(explicit_base) = explicit_base.to_class_type(db) else {
Type::ClassLiteral(class_literal) => *class_literal, continue;
Type::GenericAlias(generic_alias) => generic_alias.origin(db),
_ => continue,
}; };
let explicit_base_class_literal = explicit_base.class_literal(db).0;
if !classes_on_stack.insert(explicit_base_class_literal) { if !classes_on_stack.insert(explicit_base_class_literal) {
return true; return true;
} }

View File

@ -1379,15 +1379,10 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
KnownClass::OrderedDict, KnownClass::OrderedDict,
]; ];
ty.as_nominal_instance().is_some_and(|instance| {
SAFE_MUTABLE_CLASSES SAFE_MUTABLE_CLASSES
.iter() .iter()
.map(|class| class.to_instance(db)) .any(|known_class| instance.has_known_class(db, *known_class))
.any(|safe_mutable_class| {
ty.is_equivalent_to(db, safe_mutable_class)
|| ty
.generic_origin(db)
.zip(safe_mutable_class.generic_origin(db))
.is_some_and(|(l, r)| l == r)
}) })
} }

View File

@ -614,9 +614,7 @@ impl<'db, 'ast> NarrowingConstraintsBuilder<'db, 'ast> {
for element in lhs_union.elements(self.db) { for element in lhs_union.elements(self.db) {
// Keep only the non-single-valued portion of the original type. // Keep only the non-single-valued portion of the original type.
if !element.is_single_valued(self.db) if !element.is_single_valued(self.db)
&& !element.is_literal_string() && !element.is_union_of_single_valued(self.db)
&& !element.is_bool(self.db)
&& (!element.is_enum(self.db) || element.overrides_equality(self.db))
{ {
builder = builder.add(*element); builder = builder.add(*element);
} }
@ -650,9 +648,7 @@ impl<'db, 'ast> NarrowingConstraintsBuilder<'db, 'ast> {
if let Some(lhs_union) = lhs_ty.as_union() { if let Some(lhs_union) = lhs_ty.as_union() {
for element in lhs_union.elements(self.db) { for element in lhs_union.elements(self.db) {
if element.is_single_valued(self.db) if element.is_single_valued(self.db)
|| element.is_literal_string() || element.is_union_of_single_valued(self.db)
|| element.is_bool(self.db)
|| (element.is_enum(self.db) && !element.overrides_equality(self.db))
{ {
single_builder = single_builder.add(*element); single_builder = single_builder.add(*element);
} else { } else {