diff --git a/crates/ty_python_semantic/src/types.rs b/crates/ty_python_semantic/src/types.rs index 6b48499e9b..91f4a44c8b 100644 --- a/crates/ty_python_semantic/src/types.rs +++ b/crates/ty_python_semantic/src/types.rs @@ -819,17 +819,6 @@ impl<'db> Type<'db> { .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 fn overrides_equality(&self, db: &'db dyn Db) -> bool { let check_dunder = |dunder_name, allowed_return_value| { @@ -1142,7 +1131,7 @@ impl<'db> Type<'db> { #[cfg(test)] #[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() .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 { - self.as_union().is_some_and(|union| { - union.elements(db).iter().all(|ty| { - ty.is_single_valued(db) - || ty.is_bool(db) - || ty.is_literal_string() - || (ty.is_enum(db) && !ty.overrides_equality(db)) - }) - }) || self.is_bool(db) - || self.is_literal_string() - || (self.is_enum(db) && !self.overrides_equality(db)) + match self { + Type::LiteralString => true, + Type::NominalInstance(instance) => { + instance.has_known_class(db, KnownClass::Bool) + || (enums::enum_metadata(db, instance.class_literal(db)).is_some() + && !self.overrides_equality(db)) + } + Type::Union(union) => union.elements(db).iter().all(|element| { + element.is_single_valued(db) || element.is_union_of_single_valued(db) + }), + _ => false, + } } pub(crate) fn is_union_with_single_valued(&self, db: &'db dyn Db) -> bool { - self.as_union().is_some_and(|union| { - union.elements(db).iter().any(|ty| { - ty.is_single_valued(db) - || ty.is_bool(db) - || ty.is_literal_string() - || (ty.is_enum(db) && !ty.overrides_equality(db)) - }) - }) || self.is_bool(db) - || self.is_literal_string() - || (self.is_enum(db) && !self.overrides_equality(db)) + match self { + Type::LiteralString => true, + Type::NominalInstance(instance) => { + instance.has_known_class(db, KnownClass::Bool) + || (enums::enum_metadata(db, instance.class_literal(db)).is_some() + && !self.overrides_equality(db)) + } + Type::Union(union) => union.elements(db).iter().any(|element| { + element.is_single_valued(db) || element.is_union_of_single_valued(db) + }), + _ => false, + } } - pub(crate) fn as_string_literal(self) -> Option> { + pub(crate) const fn as_string_literal(self) -> Option> { match self { Type::StringLiteral(string_literal) => Some(string_literal), _ => 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 { 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> { - 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 { 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> { + pub(crate) const fn as_pep_695_type_alias(self) -> Option> { match self { TypeAliasType::PEP695(type_alias) => Some(type_alias), TypeAliasType::ManualPEP695(_) => None, diff --git a/crates/ty_python_semantic/src/types/call/arguments.rs b/crates/ty_python_semantic/src/types/call/arguments.rs index fc8bf871e5..55cb039ca7 100644 --- a/crates/ty_python_semantic/src/types/call/arguments.rs +++ b/crates/ty_python_semantic/src/types/call/arguments.rs @@ -256,15 +256,14 @@ impl<'a, 'db> FromIterator<(Argument<'a>, Option>)> for CallArguments< pub(crate) fn is_expandable_type<'db>(db: &'db dyn Db, ty: Type<'db>) -> bool { match ty { Type::NominalInstance(instance) => { - let class = instance.class(db); - class.is_known(db, KnownClass::Bool) + instance.has_known_class(db, KnownClass::Bool) || instance.tuple_spec(db).is_some_and(|spec| match &*spec { Tuple::Fixed(fixed_length_tuple) => fixed_length_tuple .all_elements() .any(|element| is_expandable_type(db, *element)), 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, _ => false, @@ -278,9 +277,7 @@ fn expand_type<'db>(db: &'db dyn Db, ty: Type<'db>) -> Option>> { // NOTE: Update `is_expandable_type` if this logic changes accordingly. match ty { Type::NominalInstance(instance) => { - let class = instance.class(db); - - if class.is_known(db, KnownClass::Bool) { + if instance.has_known_class(db, KnownClass::Bool) { return Some(vec![ Type::BooleanLiteral(true), Type::BooleanLiteral(false), @@ -315,7 +312,7 @@ fn expand_type<'db>(db: &'db dyn Db, ty: Type<'db>) -> Option>> { }; } - 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()); } diff --git a/crates/ty_python_semantic/src/types/class.rs b/crates/ty_python_semantic/src/types/class.rs index 75190a3c3a..52e29d6296 100644 --- a/crates/ty_python_semantic/src/types/class.rs +++ b/crates/ty_python_semantic/src/types/class.rs @@ -377,10 +377,7 @@ impl<'db> ClassType<'db> { } pub(super) fn has_pep_695_type_params(self, db: &'db dyn Db) -> bool { - match self { - Self::NonGeneric(class) => class.has_pep_695_type_params(db), - Self::Generic(generic) => generic.origin(db).has_pep_695_type_params(db), - } + self.class_literal(db).0.has_pep_695_type_params(db) } /// Returns the class literal and specialization for this class. For a non-generic class, this @@ -3463,11 +3460,10 @@ impl<'db> ClassLiteral<'db> { ) -> bool { let mut result = false; for explicit_base in class.explicit_bases(db) { - let explicit_base_class_literal = match explicit_base { - Type::ClassLiteral(class_literal) => *class_literal, - Type::GenericAlias(generic_alias) => generic_alias.origin(db), - _ => continue, + let Some(explicit_base) = explicit_base.to_class_type(db) else { + continue; }; + let explicit_base_class_literal = explicit_base.class_literal(db).0; if !classes_on_stack.insert(explicit_base_class_literal) { return true; } diff --git a/crates/ty_python_semantic/src/types/infer/builder.rs b/crates/ty_python_semantic/src/types/infer/builder.rs index edf8581bcd..48426e0b95 100644 --- a/crates/ty_python_semantic/src/types/infer/builder.rs +++ b/crates/ty_python_semantic/src/types/infer/builder.rs @@ -1379,16 +1379,11 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> { KnownClass::OrderedDict, ]; - SAFE_MUTABLE_CLASSES - .iter() - .map(|class| class.to_instance(db)) - .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) - }) + ty.as_nominal_instance().is_some_and(|instance| { + SAFE_MUTABLE_CLASSES + .iter() + .any(|known_class| instance.has_known_class(db, *known_class)) + }) } debug_assert!( diff --git a/crates/ty_python_semantic/src/types/narrow.rs b/crates/ty_python_semantic/src/types/narrow.rs index 5b709551f5..604c82f0c1 100644 --- a/crates/ty_python_semantic/src/types/narrow.rs +++ b/crates/ty_python_semantic/src/types/narrow.rs @@ -614,9 +614,7 @@ impl<'db, 'ast> NarrowingConstraintsBuilder<'db, 'ast> { for element in lhs_union.elements(self.db) { // Keep only the non-single-valued portion of the original type. if !element.is_single_valued(self.db) - && !element.is_literal_string() - && !element.is_bool(self.db) - && (!element.is_enum(self.db) || element.overrides_equality(self.db)) + && !element.is_union_of_single_valued(self.db) { builder = builder.add(*element); } @@ -650,9 +648,7 @@ impl<'db, 'ast> NarrowingConstraintsBuilder<'db, 'ast> { if let Some(lhs_union) = lhs_ty.as_union() { for element in lhs_union.elements(self.db) { if element.is_single_valued(self.db) - || element.is_literal_string() - || element.is_bool(self.db) - || (element.is_enum(self.db) && !element.overrides_equality(self.db)) + || element.is_union_of_single_valued(self.db) { single_builder = single_builder.add(*element); } else {