diff --git a/crates/ty_python_semantic/src/types.rs b/crates/ty_python_semantic/src/types.rs index c23738a73b..a5af20fe0c 100644 --- a/crates/ty_python_semantic/src/types.rs +++ b/crates/ty_python_semantic/src/types.rs @@ -259,6 +259,12 @@ pub(crate) type NormalizedVisitor<'db> = TypeTransformer<'db, Normalized>; #[derive(Debug)] pub(crate) struct Normalized; +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub(crate) enum OnlyReorder { + No, + Yes, +} + /// How a generic type has been specialized. /// /// This matters only if there is at least one invariant type parameter. @@ -563,11 +569,18 @@ impl<'db> PropertyInstanceType<'db> { Self::new(db, getter, setter) } - fn normalized_impl(self, db: &'db dyn Db, visitor: &NormalizedVisitor<'db>) -> Self { + fn normalized_impl( + self, + db: &'db dyn Db, + only_reorder: OnlyReorder, + visitor: &NormalizedVisitor<'db>, + ) -> Self { Self::new( db, - self.getter(db).map(|ty| ty.normalized_impl(db, visitor)), - self.setter(db).map(|ty| ty.normalized_impl(db, visitor)), + self.getter(db) + .map(|ty| ty.normalized_impl(db, only_reorder, visitor)), + self.setter(db) + .map(|ty| ty.normalized_impl(db, only_reorder, visitor)), ) } @@ -1560,56 +1573,75 @@ impl<'db> Type<'db> { /// - Converts class-based typeddicts into synthesized typeddicts #[must_use] pub(crate) fn normalized(self, db: &'db dyn Db) -> Self { - self.normalized_impl(db, &NormalizedVisitor::default()) + self.normalized_impl(db, OnlyReorder::No, &NormalizedVisitor::default()) + } + + /// Ensures that all union and intersection elements in this type are in a canonical ordering, + /// but performs no other normalizations. + #[must_use] + pub(crate) fn canonically_ordered(self, db: &'db dyn Db) -> Self { + self.normalized_impl(db, OnlyReorder::Yes, &NormalizedVisitor::default()) } #[must_use] - pub(crate) fn normalized_impl(self, db: &'db dyn Db, visitor: &NormalizedVisitor<'db>) -> Self { + pub(crate) fn normalized_impl( + self, + db: &'db dyn Db, + only_reorder: OnlyReorder, + visitor: &NormalizedVisitor<'db>, + ) -> Self { match self { - Type::Union(union) => visitor.visit(self, || union.normalized_impl(db, visitor)), + Type::Union(union) => { + visitor.visit(self, || union.normalized_impl(db, only_reorder, visitor)) + } Type::Intersection(intersection) => visitor.visit(self, || { - Type::Intersection(intersection.normalized_impl(db, visitor)) + Type::Intersection(intersection.normalized_impl(db, only_reorder, visitor)) }), Type::Callable(callable) => visitor.visit(self, || { - Type::Callable(callable.normalized_impl(db, visitor)) + Type::Callable(callable.normalized_impl(db, only_reorder, visitor)) }), Type::ProtocolInstance(protocol) => { - visitor.visit(self, || protocol.normalized_impl(db, visitor)) + visitor.visit(self, || protocol.normalized_impl(db, only_reorder, visitor)) } Type::NominalInstance(instance) => { - visitor.visit(self, || instance.normalized_impl(db, visitor)) + visitor.visit(self, || instance.normalized_impl(db, only_reorder, visitor)) } Type::FunctionLiteral(function) => visitor.visit(self, || { - Type::FunctionLiteral(function.normalized_impl(db, visitor)) + Type::FunctionLiteral(function.normalized_impl(db, only_reorder, visitor)) }), Type::PropertyInstance(property) => visitor.visit(self, || { - Type::PropertyInstance(property.normalized_impl(db, visitor)) + Type::PropertyInstance(property.normalized_impl(db, only_reorder, visitor)) }), Type::KnownBoundMethod(method_kind) => visitor.visit(self, || { - Type::KnownBoundMethod(method_kind.normalized_impl(db, visitor)) + Type::KnownBoundMethod(method_kind.normalized_impl(db, only_reorder, visitor)) }), Type::BoundMethod(method) => visitor.visit(self, || { - Type::BoundMethod(method.normalized_impl(db, visitor)) + Type::BoundMethod(method.normalized_impl(db, only_reorder, visitor)) }), Type::BoundSuper(bound_super) => visitor.visit(self, || { - Type::BoundSuper(bound_super.normalized_impl(db, visitor)) + Type::BoundSuper(bound_super.normalized_impl(db, only_reorder, visitor)) }), Type::GenericAlias(generic) => visitor.visit(self, || { - Type::GenericAlias(generic.normalized_impl(db, visitor)) + Type::GenericAlias(generic.normalized_impl(db, only_reorder, visitor)) }), Type::SubclassOf(subclass_of) => visitor.visit(self, || { - Type::SubclassOf(subclass_of.normalized_impl(db, visitor)) + Type::SubclassOf(subclass_of.normalized_impl(db, only_reorder, visitor)) }), Type::TypeVar(bound_typevar) => visitor.visit(self, || { - Type::TypeVar(bound_typevar.normalized_impl(db, visitor)) + Type::TypeVar(bound_typevar.normalized_impl(db, only_reorder, visitor)) }), Type::KnownInstance(known_instance) => visitor.visit(self, || { - Type::KnownInstance(known_instance.normalized_impl(db, visitor)) + Type::KnownInstance(known_instance.normalized_impl(db, only_reorder, visitor)) }), Type::TypeIs(type_is) => visitor.visit(self, || { - type_is.with_type(db, type_is.return_type(db).normalized_impl(db, visitor)) + type_is.with_type( + db, + type_is + .return_type(db) + .normalized_impl(db, only_reorder, visitor), + ) }), - Type::Dynamic(dynamic) => Type::Dynamic(dynamic.normalized()), + Type::Dynamic(dynamic) => Type::Dynamic(dynamic.normalized(only_reorder)), Type::EnumLiteral(enum_literal) if is_single_member_enum(db, enum_literal.enum_class(db)) => { @@ -1617,16 +1649,18 @@ impl<'db> Type<'db> { enum_literal.enum_class_instance(db) } Type::TypedDict(typed_dict) => visitor.visit(self, || { - Type::TypedDict(typed_dict.normalized_impl(db, visitor)) + Type::TypedDict(typed_dict.normalized_impl(db, only_reorder, visitor)) }), - Type::TypeAlias(alias) => alias.value_type(db).normalized_impl(db, visitor), - Type::NewTypeInstance(newtype) => { - visitor.visit(self, || { - Type::NewTypeInstance(newtype.map_base_class_type(db, |class_type| { - class_type.normalized_impl(db, visitor) - })) - }) + Type::TypeAlias(alias) => { + alias + .value_type(db) + .normalized_impl(db, only_reorder, visitor) } + Type::NewTypeInstance(newtype) => visitor.visit(self, || { + Type::NewTypeInstance(newtype.map_base_class_type(db, |class_type| { + class_type.normalized_impl(db, only_reorder, visitor) + })) + }), Type::LiteralString | Type::AlwaysFalsy | Type::AlwaysTruthy @@ -8930,31 +8964,45 @@ impl<'db> VarianceInferable<'db> for KnownInstanceType<'db> { } impl<'db> KnownInstanceType<'db> { - fn normalized_impl(self, db: &'db dyn Db, visitor: &NormalizedVisitor<'db>) -> Self { + fn normalized_impl( + self, + db: &'db dyn Db, + only_reorder: OnlyReorder, + visitor: &NormalizedVisitor<'db>, + ) -> Self { match self { Self::SubscriptedProtocol(context) => { - Self::SubscriptedProtocol(context.normalized_impl(db, visitor)) + Self::SubscriptedProtocol(context.normalized_impl(db, only_reorder, visitor)) } Self::SubscriptedGeneric(context) => { - Self::SubscriptedGeneric(context.normalized_impl(db, visitor)) + Self::SubscriptedGeneric(context.normalized_impl(db, only_reorder, visitor)) + } + Self::TypeVar(typevar) => { + Self::TypeVar(typevar.normalized_impl(db, only_reorder, visitor)) } - Self::TypeVar(typevar) => Self::TypeVar(typevar.normalized_impl(db, visitor)), Self::TypeAliasType(type_alias) => { - Self::TypeAliasType(type_alias.normalized_impl(db, visitor)) + Self::TypeAliasType(type_alias.normalized_impl(db, only_reorder, visitor)) + } + Self::Field(field) => Self::Field(field.normalized_impl(db, only_reorder, visitor)), + Self::UnionType(instance) => { + Self::UnionType(instance.normalized_impl(db, only_reorder, visitor)) + } + Self::Literal(ty) => Self::Literal(ty.normalized_impl(db, only_reorder, visitor)), + Self::Annotated(ty) => Self::Annotated(ty.normalized_impl(db, only_reorder, visitor)), + Self::TypeGenericAlias(ty) => { + Self::TypeGenericAlias(ty.normalized_impl(db, only_reorder, visitor)) + } + Self::Callable(callable) => { + Self::Callable(callable.normalized_impl(db, only_reorder, visitor)) } - Self::Field(field) => Self::Field(field.normalized_impl(db, visitor)), - Self::UnionType(instance) => Self::UnionType(instance.normalized_impl(db, visitor)), - Self::Literal(ty) => Self::Literal(ty.normalized_impl(db, visitor)), - Self::Annotated(ty) => Self::Annotated(ty.normalized_impl(db, visitor)), - Self::TypeGenericAlias(ty) => Self::TypeGenericAlias(ty.normalized_impl(db, visitor)), - Self::Callable(callable) => Self::Callable(callable.normalized_impl(db, visitor)), Self::LiteralStringAlias(ty) => { - Self::LiteralStringAlias(ty.normalized_impl(db, visitor)) + Self::LiteralStringAlias(ty.normalized_impl(db, only_reorder, visitor)) + } + Self::NewType(newtype) => { + Self::NewType(newtype.map_base_class_type(db, |class_type| { + class_type.normalized_impl(db, only_reorder, visitor) + })) } - Self::NewType(newtype) => Self::NewType( - newtype - .map_base_class_type(db, |class_type| class_type.normalized_impl(db, visitor)), - ), Self::Deprecated(_) | Self::ConstraintSet(_) | Self::GenericContext(_) @@ -9110,8 +9158,8 @@ pub enum DynamicType<'db> { } impl DynamicType<'_> { - fn normalized(self) -> Self { - if matches!(self, Self::Divergent(_)) { + fn normalized(self, only_reorder: OnlyReorder) -> Self { + if only_reorder == OnlyReorder::Yes || matches!(self, Self::Divergent(_)) { self } else { Self::Any @@ -9483,11 +9531,16 @@ pub struct FieldInstance<'db> { impl get_size2::GetSize for FieldInstance<'_> {} impl<'db> FieldInstance<'db> { - pub(crate) fn normalized_impl(self, db: &'db dyn Db, visitor: &NormalizedVisitor<'db>) -> Self { + pub(crate) fn normalized_impl( + self, + db: &'db dyn Db, + only_reorder: OnlyReorder, + visitor: &NormalizedVisitor<'db>, + ) -> Self { FieldInstance::new( db, self.default_type(db) - .map(|ty| ty.normalized_impl(db, visitor)), + .map(|ty| ty.normalized_impl(db, only_reorder, visitor)), self.init(db), self.kw_only(db), self.alias(db), @@ -9726,28 +9779,41 @@ impl<'db> TypeVarInstance<'db> { }) } - pub(crate) fn normalized_impl(self, db: &'db dyn Db, visitor: &NormalizedVisitor<'db>) -> Self { + pub(crate) fn normalized_impl( + self, + db: &'db dyn Db, + only_reorder: OnlyReorder, + visitor: &NormalizedVisitor<'db>, + ) -> Self { Self::new( db, self.identity(db), self._bound_or_constraints(db) .and_then(|bound_or_constraints| match bound_or_constraints { - TypeVarBoundOrConstraintsEvaluation::Eager(bound_or_constraints) => { - Some(bound_or_constraints.normalized_impl(db, visitor).into()) - } + TypeVarBoundOrConstraintsEvaluation::Eager(bound_or_constraints) => Some( + bound_or_constraints + .normalized_impl(db, only_reorder, visitor) + .into(), + ), TypeVarBoundOrConstraintsEvaluation::LazyUpperBound => self .lazy_bound(db) - .map(|bound| bound.normalized_impl(db, visitor).into()), - TypeVarBoundOrConstraintsEvaluation::LazyConstraints => self - .lazy_constraints(db) - .map(|constraints| constraints.normalized_impl(db, visitor).into()), + .map(|bound| bound.normalized_impl(db, only_reorder, visitor).into()), + TypeVarBoundOrConstraintsEvaluation::LazyConstraints => { + self.lazy_constraints(db).map(|constraints| { + constraints + .normalized_impl(db, only_reorder, visitor) + .into() + }) + } }), self.explicit_variance(db), self._default(db).and_then(|default| match default { - TypeVarDefaultEvaluation::Eager(ty) => Some(ty.normalized_impl(db, visitor).into()), + TypeVarDefaultEvaluation::Eager(ty) => { + Some(ty.normalized_impl(db, only_reorder, visitor).into()) + } TypeVarDefaultEvaluation::Lazy => self .lazy_default(db) - .map(|ty| ty.normalized_impl(db, visitor).into()), + .map(|ty| ty.normalized_impl(db, only_reorder, visitor).into()), }), ) } @@ -10454,10 +10520,15 @@ impl<'db> BoundTypeVarInstance<'db> { }) } - pub(crate) fn normalized_impl(self, db: &'db dyn Db, visitor: &NormalizedVisitor<'db>) -> Self { + pub(crate) fn normalized_impl( + self, + db: &'db dyn Db, + only_reorder: OnlyReorder, + visitor: &NormalizedVisitor<'db>, + ) -> Self { Self::new( db, - self.typevar(db).normalized_impl(db, visitor), + self.typevar(db).normalized_impl(db, only_reorder, visitor), self.binding_context(db), self.paramspec_attr(db), ) @@ -10619,11 +10690,16 @@ impl<'db> TypeVarConstraints<'db> { } } - fn normalized_impl(self, db: &'db dyn Db, visitor: &NormalizedVisitor<'db>) -> Self { + fn normalized_impl( + self, + db: &'db dyn Db, + only_reorder: OnlyReorder, + visitor: &NormalizedVisitor<'db>, + ) -> Self { let normalized = self .elements(db) .iter() - .map(|ty| ty.normalized_impl(db, visitor)) + .map(|ty| ty.normalized_impl(db, only_reorder, visitor)) .collect::>(); TypeVarConstraints::new(db, normalized) } @@ -10663,13 +10739,22 @@ fn walk_type_var_bounds<'db, V: visitor::TypeVisitor<'db> + ?Sized>( } impl<'db> TypeVarBoundOrConstraints<'db> { - fn normalized_impl(self, db: &'db dyn Db, visitor: &NormalizedVisitor<'db>) -> Self { + fn normalized_impl( + self, + db: &'db dyn Db, + only_reorder: OnlyReorder, + visitor: &NormalizedVisitor<'db>, + ) -> Self { match self { - TypeVarBoundOrConstraints::UpperBound(bound) => { - TypeVarBoundOrConstraints::UpperBound(bound.normalized_impl(db, visitor)) - } + TypeVarBoundOrConstraints::UpperBound(bound) => TypeVarBoundOrConstraints::UpperBound( + bound.normalized_impl(db, only_reorder, visitor), + ), TypeVarBoundOrConstraints::Constraints(constraints) => { - TypeVarBoundOrConstraints::Constraints(constraints.normalized_impl(db, visitor)) + TypeVarBoundOrConstraints::Constraints(constraints.normalized_impl( + db, + only_reorder, + visitor, + )) } } } @@ -10850,17 +10935,22 @@ impl<'db> UnionTypeInstance<'db> { } } - pub(crate) fn normalized_impl(self, db: &'db dyn Db, visitor: &NormalizedVisitor<'db>) -> Self { + pub(crate) fn normalized_impl( + self, + db: &'db dyn Db, + only_reorder: OnlyReorder, + visitor: &NormalizedVisitor<'db>, + ) -> Self { let value_expr_types = self._value_expr_types(db).as_ref().map(|types| { types .iter() - .map(|ty| ty.normalized_impl(db, visitor)) + .map(|ty| ty.normalized_impl(db, only_reorder, visitor)) .collect::>() }); let union_type = self .union_type(db) .clone() - .map(|ty| ty.normalized_impl(db, visitor)); + .map(|ty| ty.normalized_impl(db, only_reorder, visitor)); Self::new(db, value_expr_types, union_type) } @@ -10917,8 +11007,16 @@ pub struct InternedType<'db> { impl get_size2::GetSize for InternedType<'_> {} impl<'db> InternedType<'db> { - pub(crate) fn normalized_impl(self, db: &'db dyn Db, visitor: &NormalizedVisitor<'db>) -> Self { - InternedType::new(db, self.inner(db).normalized_impl(db, visitor)) + pub(crate) fn normalized_impl( + self, + db: &'db dyn Db, + only_reorder: OnlyReorder, + visitor: &NormalizedVisitor<'db>, + ) -> Self { + InternedType::new( + db, + self.inner(db).normalized_impl(db, only_reorder, visitor), + ) } fn recursive_type_normalized_impl( @@ -12240,11 +12338,17 @@ impl<'db> BoundMethodType<'db> { ) } - fn normalized_impl(self, db: &'db dyn Db, visitor: &NormalizedVisitor<'db>) -> Self { + fn normalized_impl( + self, + db: &'db dyn Db, + only_reorder: OnlyReorder, + visitor: &NormalizedVisitor<'db>, + ) -> Self { Self::new( db, - self.function(db).normalized_impl(db, visitor), - self.self_instance(db).normalized_impl(db, visitor), + self.function(db).normalized_impl(db, only_reorder, visitor), + self.self_instance(db) + .normalized_impl(db, only_reorder, visitor), ) } @@ -12454,10 +12558,16 @@ impl<'db> CallableType<'db> { /// Return a "normalized" version of this `Callable` type. /// /// See [`Type::normalized`] for more details. - fn normalized_impl(self, db: &'db dyn Db, visitor: &NormalizedVisitor<'db>) -> Self { + fn normalized_impl( + self, + db: &'db dyn Db, + only_reorder: OnlyReorder, + visitor: &NormalizedVisitor<'db>, + ) -> Self { CallableType::new( db, - self.signatures(db).normalized_impl(db, visitor), + self.signatures(db) + .normalized_impl(db, only_reorder, visitor), self.kind(db), ) } @@ -12883,19 +12993,40 @@ impl<'db> KnownBoundMethodType<'db> { } } - fn normalized_impl(self, db: &'db dyn Db, visitor: &NormalizedVisitor<'db>) -> Self { + fn normalized_impl( + self, + db: &'db dyn Db, + only_reorder: OnlyReorder, + visitor: &NormalizedVisitor<'db>, + ) -> Self { match self { KnownBoundMethodType::FunctionTypeDunderGet(function) => { - KnownBoundMethodType::FunctionTypeDunderGet(function.normalized_impl(db, visitor)) + KnownBoundMethodType::FunctionTypeDunderGet(function.normalized_impl( + db, + only_reorder, + visitor, + )) } KnownBoundMethodType::FunctionTypeDunderCall(function) => { - KnownBoundMethodType::FunctionTypeDunderCall(function.normalized_impl(db, visitor)) + KnownBoundMethodType::FunctionTypeDunderCall(function.normalized_impl( + db, + only_reorder, + visitor, + )) } KnownBoundMethodType::PropertyDunderGet(property) => { - KnownBoundMethodType::PropertyDunderGet(property.normalized_impl(db, visitor)) + KnownBoundMethodType::PropertyDunderGet(property.normalized_impl( + db, + only_reorder, + visitor, + )) } KnownBoundMethodType::PropertyDunderSet(property) => { - KnownBoundMethodType::PropertyDunderSet(property.normalized_impl(db, visitor)) + KnownBoundMethodType::PropertyDunderSet(property.normalized_impl( + db, + only_reorder, + visitor, + )) } KnownBoundMethodType::StrStartswith(_) | KnownBoundMethodType::ConstraintSetRange @@ -13529,7 +13660,12 @@ impl<'db> PEP695TypeAliasType<'db> { }) } - fn normalized_impl(self, _db: &'db dyn Db, _visitor: &NormalizedVisitor<'db>) -> Self { + fn normalized_impl( + self, + _db: &'db dyn Db, + _only_reorder: OnlyReorder, + _visitor: &NormalizedVisitor<'db>, + ) -> Self { self } } @@ -13586,12 +13722,17 @@ fn walk_manual_pep_695_type_alias<'db, V: visitor::TypeVisitor<'db> + ?Sized>( } impl<'db> ManualPEP695TypeAliasType<'db> { - fn normalized_impl(self, db: &'db dyn Db, visitor: &NormalizedVisitor<'db>) -> Self { + fn normalized_impl( + self, + db: &'db dyn Db, + only_reorder: OnlyReorder, + visitor: &NormalizedVisitor<'db>, + ) -> Self { Self::new( db, self.name(db), self.definition(db), - self.value(db).normalized_impl(db, visitor), + self.value(db).normalized_impl(db, only_reorder, visitor), ) } @@ -13636,13 +13777,18 @@ fn walk_type_alias_type<'db, V: visitor::TypeVisitor<'db> + ?Sized>( } impl<'db> TypeAliasType<'db> { - pub(crate) fn normalized_impl(self, db: &'db dyn Db, visitor: &NormalizedVisitor<'db>) -> Self { + pub(crate) fn normalized_impl( + self, + db: &'db dyn Db, + only_reorder: OnlyReorder, + visitor: &NormalizedVisitor<'db>, + ) -> Self { match self { TypeAliasType::PEP695(type_alias) => { - TypeAliasType::PEP695(type_alias.normalized_impl(db, visitor)) + TypeAliasType::PEP695(type_alias.normalized_impl(db, only_reorder, visitor)) } TypeAliasType::ManualPEP695(type_alias) => { - TypeAliasType::ManualPEP695(type_alias.normalized_impl(db, visitor)) + TypeAliasType::ManualPEP695(type_alias.normalized_impl(db, only_reorder, visitor)) } } } @@ -13977,21 +14123,26 @@ impl<'db> UnionType<'db> { /// See [`Type::normalized`] for more details. #[must_use] pub(crate) fn normalized(self, db: &'db dyn Db) -> Type<'db> { - self.normalized_impl(db, &NormalizedVisitor::default()) + self.normalized_impl(db, OnlyReorder::No, &NormalizedVisitor::default()) } pub(crate) fn normalized_impl( self, db: &'db dyn Db, + only_reorder: OnlyReorder, visitor: &NormalizedVisitor<'db>, ) -> Type<'db> { self.elements(db) .iter() - .map(|ty| ty.normalized_impl(db, visitor)) + .map(|ty| ty.normalized_impl(db, only_reorder, visitor)) .fold( - UnionBuilder::new(db) - .order_elements(true) - .unpack_aliases(true), + if only_reorder == OnlyReorder::Yes { + UnionBuilder::new(db).order_elements(true) + } else { + UnionBuilder::new(db) + .order_elements(true) + .unpack_aliases(true) + }, UnionBuilder::add, ) .recursively_defined(self.recursively_defined(db)) @@ -14170,18 +14321,24 @@ impl<'db> IntersectionType<'db> { /// See [`Type::normalized`] for more details. #[must_use] pub(crate) fn normalized(self, db: &'db dyn Db) -> Self { - self.normalized_impl(db, &NormalizedVisitor::default()) + self.normalized_impl(db, OnlyReorder::No, &NormalizedVisitor::default()) } - pub(crate) fn normalized_impl(self, db: &'db dyn Db, visitor: &NormalizedVisitor<'db>) -> Self { + pub(crate) fn normalized_impl( + self, + db: &'db dyn Db, + only_reorder: OnlyReorder, + visitor: &NormalizedVisitor<'db>, + ) -> Self { fn normalized_set<'db>( db: &'db dyn Db, elements: &FxOrderSet>, + only_reorder: OnlyReorder, visitor: &NormalizedVisitor<'db>, ) -> FxOrderSet> { let mut elements: FxOrderSet> = elements .iter() - .map(|ty| ty.normalized_impl(db, visitor)) + .map(|ty| ty.normalized_impl(db, only_reorder, visitor)) .collect(); elements.sort_unstable_by(|l, r| union_or_intersection_elements_ordering(db, l, r)); @@ -14190,8 +14347,8 @@ impl<'db> IntersectionType<'db> { IntersectionType::new( db, - normalized_set(db, self.positive(db), visitor), - normalized_set(db, self.negative(db), visitor), + normalized_set(db, self.positive(db), only_reorder, visitor), + normalized_set(db, self.negative(db), only_reorder, visitor), ) } diff --git a/crates/ty_python_semantic/src/types/bound_super.rs b/crates/ty_python_semantic/src/types/bound_super.rs index cea3bc3e54..05366a4e64 100644 --- a/crates/ty_python_semantic/src/types/bound_super.rs +++ b/crates/ty_python_semantic/src/types/bound_super.rs @@ -9,8 +9,8 @@ use crate::{ place::{Place, PlaceAndQualifiers}, types::{ ClassBase, ClassType, DynamicType, IntersectionBuilder, KnownClass, MemberLookupPolicy, - NominalInstanceType, NormalizedVisitor, SpecialFormType, SubclassOfInner, Type, - TypeVarBoundOrConstraints, TypeVarInstance, UnionBuilder, + NominalInstanceType, NormalizedVisitor, OnlyReorder, SpecialFormType, SubclassOfInner, + Type, TypeVarBoundOrConstraints, TypeVarInstance, UnionBuilder, context::InferContext, diagnostic::{INVALID_SUPER_ARGUMENT, UNAVAILABLE_IMPLICIT_SUPER_ARGUMENTS}, todo_type, visitor, @@ -178,14 +178,21 @@ pub enum SuperOwnerKind<'db> { } impl<'db> SuperOwnerKind<'db> { - fn normalized_impl(self, db: &'db dyn Db, visitor: &NormalizedVisitor<'db>) -> Self { + fn normalized_impl( + self, + db: &'db dyn Db, + only_reorder: OnlyReorder, + visitor: &NormalizedVisitor<'db>, + ) -> Self { match self { - SuperOwnerKind::Dynamic(dynamic) => SuperOwnerKind::Dynamic(dynamic.normalized()), + SuperOwnerKind::Dynamic(dynamic) => { + SuperOwnerKind::Dynamic(dynamic.normalized(only_reorder)) + } SuperOwnerKind::Class(class) => { - SuperOwnerKind::Class(class.normalized_impl(db, visitor)) + SuperOwnerKind::Class(class.normalized_impl(db, only_reorder, visitor)) } SuperOwnerKind::Instance(instance) => instance - .normalized_impl(db, visitor) + .normalized_impl(db, only_reorder, visitor) .as_nominal_instance() .map(Self::Instance) .unwrap_or(Self::Dynamic(DynamicType::Any)), @@ -606,11 +613,17 @@ impl<'db> BoundSuperType<'db> { } } - pub(super) fn normalized_impl(self, db: &'db dyn Db, visitor: &NormalizedVisitor<'db>) -> Self { + pub(super) fn normalized_impl( + self, + db: &'db dyn Db, + only_reorder: OnlyReorder, + visitor: &NormalizedVisitor<'db>, + ) -> Self { Self::new( db, - self.pivot_class(db).normalized_impl(db, visitor), - self.owner(db).normalized_impl(db, visitor), + self.pivot_class(db) + .normalized_impl(db, only_reorder, visitor), + self.owner(db).normalized_impl(db, only_reorder, visitor), ) } diff --git a/crates/ty_python_semantic/src/types/class.rs b/crates/ty_python_semantic/src/types/class.rs index 1e29796dad..3147a33aaf 100644 --- a/crates/ty_python_semantic/src/types/class.rs +++ b/crates/ty_python_semantic/src/types/class.rs @@ -38,8 +38,8 @@ use crate::types::{ CallableTypes, DATACLASS_FLAGS, DataclassFlags, DataclassParams, DeprecatedInstance, FindLegacyTypeVarsVisitor, HasRelationToVisitor, IsDisjointVisitor, IsEquivalentVisitor, KnownInstanceType, ManualPEP695TypeAliasType, MaterializationKind, NormalizedVisitor, - PropertyInstanceType, StringLiteralType, TypeAliasType, TypeContext, TypeMapping, TypeRelation, - TypedDictParams, UnionBuilder, VarianceInferable, binding_type, declaration_type, + OnlyReorder, PropertyInstanceType, StringLiteralType, TypeAliasType, TypeContext, TypeMapping, + TypeRelation, TypedDictParams, UnionBuilder, VarianceInferable, binding_type, declaration_type, determine_upper_bound, }; use crate::{ @@ -274,11 +274,17 @@ pub(super) fn walk_generic_alias<'db, V: super::visitor::TypeVisitor<'db> + ?Siz impl get_size2::GetSize for GenericAlias<'_> {} impl<'db> GenericAlias<'db> { - pub(super) fn normalized_impl(self, db: &'db dyn Db, visitor: &NormalizedVisitor<'db>) -> Self { + pub(super) fn normalized_impl( + self, + db: &'db dyn Db, + only_reorder: OnlyReorder, + visitor: &NormalizedVisitor<'db>, + ) -> Self { Self::new( db, self.origin(db), - self.specialization(db).normalized_impl(db, visitor), + self.specialization(db) + .normalized_impl(db, only_reorder, visitor), ) } @@ -442,10 +448,17 @@ impl<'db> ClassType<'db> { } } - pub(super) fn normalized_impl(self, db: &'db dyn Db, visitor: &NormalizedVisitor<'db>) -> Self { + pub(super) fn normalized_impl( + self, + db: &'db dyn Db, + only_reorder: OnlyReorder, + visitor: &NormalizedVisitor<'db>, + ) -> Self { match self { Self::NonGeneric(_) => self, - Self::Generic(generic) => Self::Generic(generic.normalized_impl(db, visitor)), + Self::Generic(generic) => { + Self::Generic(generic.normalized_impl(db, only_reorder, visitor)) + } } } diff --git a/crates/ty_python_semantic/src/types/class_base.rs b/crates/ty_python_semantic/src/types/class_base.rs index 26b490fa3b..3974074e85 100644 --- a/crates/ty_python_semantic/src/types/class_base.rs +++ b/crates/ty_python_semantic/src/types/class_base.rs @@ -4,8 +4,8 @@ use crate::types::generics::Specialization; use crate::types::tuple::TupleType; use crate::types::{ ApplyTypeMappingVisitor, ClassLiteral, ClassType, DynamicType, KnownClass, KnownInstanceType, - MaterializationKind, MroError, MroIterator, NormalizedVisitor, SpecialFormType, Type, - TypeContext, TypeMapping, todo_type, + MaterializationKind, MroError, MroIterator, NormalizedVisitor, OnlyReorder, SpecialFormType, + Type, TypeContext, TypeMapping, todo_type, }; /// Enumeration of the possible kinds of types we allow in class bases. @@ -35,10 +35,15 @@ impl<'db> ClassBase<'db> { Self::Dynamic(DynamicType::Unknown) } - pub(crate) fn normalized_impl(self, db: &'db dyn Db, visitor: &NormalizedVisitor<'db>) -> Self { + pub(crate) fn normalized_impl( + self, + db: &'db dyn Db, + only_reorder: OnlyReorder, + visitor: &NormalizedVisitor<'db>, + ) -> Self { match self { - Self::Dynamic(dynamic) => Self::Dynamic(dynamic.normalized()), - Self::Class(class) => Self::Class(class.normalized_impl(db, visitor)), + Self::Dynamic(dynamic) => Self::Dynamic(dynamic.normalized(only_reorder)), + Self::Class(class) => Self::Class(class.normalized_impl(db, only_reorder, visitor)), Self::Protocol | Self::Generic | Self::TypedDict => self, } } diff --git a/crates/ty_python_semantic/src/types/function.rs b/crates/ty_python_semantic/src/types/function.rs index e727e6663b..89813bed7d 100644 --- a/crates/ty_python_semantic/src/types/function.rs +++ b/crates/ty_python_semantic/src/types/function.rs @@ -83,9 +83,9 @@ use crate::types::{ ApplyTypeMappingVisitor, BoundMethodType, BoundTypeVarInstance, CallableType, CallableTypeKind, ClassBase, ClassLiteral, ClassType, DeprecatedInstance, DynamicType, FindLegacyTypeVarsVisitor, HasRelationToVisitor, IsDisjointVisitor, IsEquivalentVisitor, KnownClass, KnownInstanceType, - NormalizedVisitor, SpecialFormType, SubclassOfInner, SubclassOfType, Truthiness, Type, - TypeContext, TypeMapping, TypeRelation, UnionBuilder, binding_type, definition_expression_type, - infer_definition_types, walk_signature, + NormalizedVisitor, OnlyReorder, SpecialFormType, SubclassOfInner, SubclassOfType, Truthiness, + Type, TypeContext, TypeMapping, TypeRelation, UnionBuilder, binding_type, + definition_expression_type, infer_definition_types, walk_signature, }; use crate::{Db, FxOrderSet, ModuleName, resolve_module}; @@ -1156,17 +1156,22 @@ impl<'db> FunctionType<'db> { } pub(crate) fn normalized(self, db: &'db dyn Db) -> Self { - self.normalized_impl(db, &NormalizedVisitor::default()) + self.normalized_impl(db, OnlyReorder::No, &NormalizedVisitor::default()) } - pub(crate) fn normalized_impl(self, db: &'db dyn Db, visitor: &NormalizedVisitor<'db>) -> Self { + pub(crate) fn normalized_impl( + self, + db: &'db dyn Db, + only_reorder: OnlyReorder, + visitor: &NormalizedVisitor<'db>, + ) -> Self { let literal = self.literal(db); let updated_signature = self .updated_signature(db) - .map(|signature| signature.normalized_impl(db, visitor)); + .map(|signature| signature.normalized_impl(db, only_reorder, visitor)); let updated_last_definition_signature = self .updated_last_definition_signature(db) - .map(|signature| signature.normalized_impl(db, visitor)); + .map(|signature| signature.normalized_impl(db, only_reorder, visitor)); Self::new( db, literal, diff --git a/crates/ty_python_semantic/src/types/generics.rs b/crates/ty_python_semantic/src/types/generics.rs index 1075ac6f0e..2ca4b21564 100644 --- a/crates/ty_python_semantic/src/types/generics.rs +++ b/crates/ty_python_semantic/src/types/generics.rs @@ -21,8 +21,8 @@ use crate::types::{ ApplyTypeMappingVisitor, BindingContext, BoundTypeVarIdentity, BoundTypeVarInstance, ClassLiteral, FindLegacyTypeVarsVisitor, HasRelationToVisitor, IsDisjointVisitor, IsEquivalentVisitor, KnownClass, KnownInstanceType, MaterializationKind, NormalizedVisitor, - Type, TypeContext, TypeMapping, TypeRelation, TypeVarBoundOrConstraints, TypeVarIdentity, - TypeVarInstance, TypeVarKind, TypeVarVariance, UnionType, declaration_type, + OnlyReorder, Type, TypeContext, TypeMapping, TypeRelation, TypeVarBoundOrConstraints, + TypeVarIdentity, TypeVarInstance, TypeVarKind, TypeVarVariance, UnionType, declaration_type, walk_bound_type_var_type, }; use crate::{Db, FxOrderMap, FxOrderSet}; @@ -658,10 +658,15 @@ impl<'db> GenericContext<'db> { Specialization::new(db, self, self.fill_in_defaults(db, types), None, None) } - pub(crate) fn normalized_impl(self, db: &'db dyn Db, visitor: &NormalizedVisitor<'db>) -> Self { + pub(crate) fn normalized_impl( + self, + db: &'db dyn Db, + only_reorder: OnlyReorder, + visitor: &NormalizedVisitor<'db>, + ) -> Self { let variables = self .variables(db) - .map(|bound_typevar| bound_typevar.normalized_impl(db, visitor)); + .map(|bound_typevar| bound_typevar.normalized_impl(db, only_reorder, visitor)); Self::from_typevar_instances(db, variables) } @@ -1098,16 +1103,23 @@ impl<'db> Specialization<'db> { Specialization::new(db, self.generic_context(db), types, None, None) } - pub(crate) fn normalized_impl(self, db: &'db dyn Db, visitor: &NormalizedVisitor<'db>) -> Self { + pub(crate) fn normalized_impl( + self, + db: &'db dyn Db, + only_reorder: OnlyReorder, + visitor: &NormalizedVisitor<'db>, + ) -> Self { let types: Box<[_]> = self .types(db) .iter() - .map(|ty| ty.normalized_impl(db, visitor)) + .map(|ty| ty.normalized_impl(db, only_reorder, visitor)) .collect(); let tuple_inner = self .tuple_inner(db) - .and_then(|tuple| tuple.normalized_impl(db, visitor)); - let context = self.generic_context(db).normalized_impl(db, visitor); + .and_then(|tuple| tuple.normalized_impl(db, only_reorder, visitor)); + let context = self + .generic_context(db) + .normalized_impl(db, only_reorder, visitor); Self::new( db, context, diff --git a/crates/ty_python_semantic/src/types/instance.rs b/crates/ty_python_semantic/src/types/instance.rs index 9e674065b9..b012aacfb2 100644 --- a/crates/ty_python_semantic/src/types/instance.rs +++ b/crates/ty_python_semantic/src/types/instance.rs @@ -14,8 +14,8 @@ use crate::types::protocol_class::{ProtocolClass, walk_protocol_interface}; use crate::types::tuple::{TupleSpec, TupleType, walk_tuple_type}; use crate::types::{ ApplyTypeMappingVisitor, ClassBase, ClassLiteral, FindLegacyTypeVarsVisitor, - HasRelationToVisitor, IsDisjointVisitor, IsEquivalentVisitor, NormalizedVisitor, TypeContext, - TypeMapping, TypeRelation, VarianceInferable, + HasRelationToVisitor, IsDisjointVisitor, IsEquivalentVisitor, NormalizedVisitor, OnlyReorder, + TypeContext, TypeMapping, TypeRelation, VarianceInferable, }; use crate::{Db, FxOrderSet}; @@ -117,6 +117,7 @@ impl<'db> Type<'db> { SynthesizedProtocolType::new( db, ProtocolInterface::with_property_members(db, members), + OnlyReorder::No, &NormalizedVisitor::default(), ), )) @@ -369,14 +370,15 @@ impl<'db> NominalInstanceType<'db> { pub(super) fn normalized_impl( self, db: &'db dyn Db, + only_reorder: OnlyReorder, visitor: &NormalizedVisitor<'db>, ) -> Type<'db> { match self.0 { NominalInstanceInner::ExactTuple(tuple) => { - Type::tuple(tuple.normalized_impl(db, visitor)) + Type::tuple(tuple.normalized_impl(db, only_reorder, visitor)) } NominalInstanceInner::NonTuple(class) => Type::NominalInstance(NominalInstanceType( - NominalInstanceInner::NonTuple(class.normalized_impl(db, visitor)), + NominalInstanceInner::NonTuple(class.normalized_impl(db, only_reorder, visitor)), )), NominalInstanceInner::Object => Type::object(), } @@ -730,7 +732,7 @@ impl<'db> ProtocolInstanceType<'db> { /// /// See [`Type::normalized`] for more details. pub(super) fn normalized(self, db: &'db dyn Db) -> Type<'db> { - self.normalized_impl(db, &NormalizedVisitor::default()) + self.normalized_impl(db, OnlyReorder::No, &NormalizedVisitor::default()) } /// Return a "normalized" version of this `Protocol` type. @@ -739,6 +741,7 @@ impl<'db> ProtocolInstanceType<'db> { pub(super) fn normalized_impl( self, db: &'db dyn Db, + only_reorder: OnlyReorder, visitor: &NormalizedVisitor<'db>, ) -> Type<'db> { if self.is_equivalent_to_object(db) { @@ -746,7 +749,7 @@ impl<'db> ProtocolInstanceType<'db> { } match self.inner { Protocol::FromClass(_) => Type::ProtocolInstance(Self::synthesized( - SynthesizedProtocolType::new(db, self.inner.interface(db), visitor), + SynthesizedProtocolType::new(db, self.inner.interface(db), only_reorder, visitor), )), Protocol::Synthesized(_) => Type::ProtocolInstance(self), } @@ -909,7 +912,8 @@ mod synthesized_protocol { use crate::types::protocol_class::ProtocolInterface; use crate::types::{ ApplyTypeMappingVisitor, BoundTypeVarInstance, FindLegacyTypeVarsVisitor, - NormalizedVisitor, Type, TypeContext, TypeMapping, TypeVarVariance, VarianceInferable, + NormalizedVisitor, OnlyReorder, Type, TypeContext, TypeMapping, TypeVarVariance, + VarianceInferable, }; use crate::{Db, FxOrderSet}; @@ -931,9 +935,10 @@ mod synthesized_protocol { pub(super) fn new( db: &'db dyn Db, interface: ProtocolInterface<'db>, + only_reorder: OnlyReorder, visitor: &NormalizedVisitor<'db>, ) -> Self { - Self(interface.normalized_impl(db, visitor)) + Self(interface.normalized_impl(db, only_reorder, visitor)) } pub(super) fn apply_type_mapping_impl<'a>( diff --git a/crates/ty_python_semantic/src/types/protocol_class.rs b/crates/ty_python_semantic/src/types/protocol_class.rs index 5d3719b8d9..6b3185ab64 100644 --- a/crates/ty_python_semantic/src/types/protocol_class.rs +++ b/crates/ty_python_semantic/src/types/protocol_class.rs @@ -15,8 +15,8 @@ use crate::{ ApplyTypeMappingVisitor, BoundTypeVarInstance, CallableType, ClassBase, ClassLiteral, ClassType, FindLegacyTypeVarsVisitor, HasRelationToVisitor, InstanceFallbackShadowsNonDataDescriptor, IsDisjointVisitor, KnownFunction, - MemberLookupPolicy, NormalizedVisitor, PropertyInstanceType, Signature, Type, TypeMapping, - TypeQualifiers, TypeRelation, TypeVarVariance, VarianceInferable, + MemberLookupPolicy, NormalizedVisitor, OnlyReorder, PropertyInstanceType, Signature, Type, + TypeMapping, TypeQualifiers, TypeRelation, TypeVarVariance, VarianceInferable, constraints::{ConstraintSet, IteratorConstraintsExtension, OptionConstraintsExtension}, context::InferContext, diagnostic::report_undeclared_protocol_member, @@ -369,12 +369,22 @@ impl<'db> ProtocolInterface<'db> { }) } - pub(super) fn normalized_impl(self, db: &'db dyn Db, visitor: &NormalizedVisitor<'db>) -> Self { + pub(super) fn normalized_impl( + self, + db: &'db dyn Db, + only_reorder: OnlyReorder, + visitor: &NormalizedVisitor<'db>, + ) -> Self { Self::new( db, self.inner(db) .iter() - .map(|(name, data)| (name.clone(), data.normalized_impl(db, visitor))) + .map(|(name, data)| { + ( + name.clone(), + data.normalized_impl(db, only_reorder, visitor), + ) + }) .collect::>(), ) } @@ -480,12 +490,17 @@ pub(super) struct ProtocolMemberData<'db> { impl<'db> ProtocolMemberData<'db> { fn normalized(&self, db: &'db dyn Db) -> Self { - self.normalized_impl(db, &NormalizedVisitor::default()) + self.normalized_impl(db, OnlyReorder::No, &NormalizedVisitor::default()) } - fn normalized_impl(&self, db: &'db dyn Db, visitor: &NormalizedVisitor<'db>) -> Self { + fn normalized_impl( + &self, + db: &'db dyn Db, + only_reorder: OnlyReorder, + visitor: &NormalizedVisitor<'db>, + ) -> Self { Self { - kind: self.kind.normalized_impl(db, visitor), + kind: self.kind.normalized_impl(db, only_reorder, visitor), qualifiers: self.qualifiers, } } @@ -593,16 +608,21 @@ enum ProtocolMemberKind<'db> { } impl<'db> ProtocolMemberKind<'db> { - fn normalized_impl(&self, db: &'db dyn Db, visitor: &NormalizedVisitor<'db>) -> Self { + fn normalized_impl( + &self, + db: &'db dyn Db, + only_reorder: OnlyReorder, + visitor: &NormalizedVisitor<'db>, + ) -> Self { match self { ProtocolMemberKind::Method(callable) => { - ProtocolMemberKind::Method(callable.normalized_impl(db, visitor)) + ProtocolMemberKind::Method(callable.normalized_impl(db, only_reorder, visitor)) } ProtocolMemberKind::Property(property) => { - ProtocolMemberKind::Property(property.normalized_impl(db, visitor)) + ProtocolMemberKind::Property(property.normalized_impl(db, only_reorder, visitor)) } ProtocolMemberKind::Other(ty) => { - ProtocolMemberKind::Other(ty.normalized_impl(db, visitor)) + ProtocolMemberKind::Other(ty.normalized_impl(db, only_reorder, visitor)) } } } diff --git a/crates/ty_python_semantic/src/types/signatures.rs b/crates/ty_python_semantic/src/types/signatures.rs index 2ff8fc885b..5a703cba75 100644 --- a/crates/ty_python_semantic/src/types/signatures.rs +++ b/crates/ty_python_semantic/src/types/signatures.rs @@ -25,8 +25,8 @@ use crate::types::infer::{infer_deferred_types, infer_scope_types}; use crate::types::{ ApplyTypeMappingVisitor, BindingContext, BoundTypeVarInstance, CallableType, CallableTypeKind, FindLegacyTypeVarsVisitor, HasRelationToVisitor, IsDisjointVisitor, IsEquivalentVisitor, - KnownClass, MaterializationKind, NormalizedVisitor, ParamSpecAttrKind, TypeContext, - TypeMapping, TypeRelation, VarianceInferable, todo_type, + KnownClass, MaterializationKind, NormalizedVisitor, OnlyReorder, ParamSpecAttrKind, + TypeContext, TypeMapping, TypeRelation, VarianceInferable, todo_type, }; use crate::{Db, FxOrderSet}; use ruff_python_ast::{self as ast, name::Name}; @@ -107,12 +107,13 @@ impl<'db> CallableSignature<'db> { pub(crate) fn normalized_impl( &self, db: &'db dyn Db, + only_reorder: OnlyReorder, visitor: &NormalizedVisitor<'db>, ) -> Self { Self::from_overloads( self.overloads .iter() - .map(|signature| signature.normalized_impl(db, visitor)), + .map(|signature| signature.normalized_impl(db, only_reorder, visitor)), ) } @@ -743,12 +744,13 @@ impl<'db> Signature<'db> { pub(crate) fn normalized_impl( &self, db: &'db dyn Db, + only_reorder: OnlyReorder, visitor: &NormalizedVisitor<'db>, ) -> Self { Self { generic_context: self .generic_context - .map(|ctx| ctx.normalized_impl(db, visitor)), + .map(|ctx| ctx.normalized_impl(db, only_reorder, visitor)), // Discard the definition when normalizing, so that two equivalent signatures // with different `Definition`s share the same Salsa ID when normalized definition: None, @@ -756,11 +758,11 @@ impl<'db> Signature<'db> { db, self.parameters .iter() - .map(|param| param.normalized_impl(db, visitor)), + .map(|param| param.normalized_impl(db, only_reorder, visitor)), ), return_ty: self .return_ty - .map(|return_ty| return_ty.normalized_impl(db, visitor)), + .map(|return_ty| return_ty.normalized_impl(db, only_reorder, visitor)), } } @@ -2133,6 +2135,7 @@ impl<'db> Parameter<'db> { pub(crate) fn normalized_impl( &self, db: &'db dyn Db, + only_reorder: OnlyReorder, visitor: &NormalizedVisitor<'db>, ) -> Self { let Parameter { @@ -2147,9 +2150,17 @@ impl<'db> Parameter<'db> { // with a dynamic type as its annotation. (We must use `Any` here as all dynamic types // normalize to `Any`.) let annotated_type = annotated_type - .map(|ty| ty.normalized_impl(db, visitor)) + .map(|ty| ty.normalized_impl(db, only_reorder, visitor)) .unwrap_or_else(Type::any); + let map_default_type = |ty: Type<'db>| { + if only_reorder == OnlyReorder::Yes { + ty.normalized_impl(db, only_reorder, visitor) + } else { + Type::Never + } + }; + // Ensure that parameter names are stripped from positional-only, variadic and keyword-variadic parameters. // Ensure that we only record whether a parameter *has* a default // (strip the precise *type* of the default from the parameter, replacing it with `Never`). @@ -2159,17 +2170,17 @@ impl<'db> Parameter<'db> { default_type, } => ParameterKind::PositionalOnly { name: None, - default_type: default_type.map(|_| Type::Never), + default_type: default_type.map(map_default_type), }, ParameterKind::PositionalOrKeyword { name, default_type } => { ParameterKind::PositionalOrKeyword { name: name.clone(), - default_type: default_type.map(|_| Type::Never), + default_type: default_type.map(map_default_type), } } ParameterKind::KeywordOnly { name, default_type } => ParameterKind::KeywordOnly { name: name.clone(), - default_type: default_type.map(|_| Type::Never), + default_type: default_type.map(map_default_type), }, ParameterKind::Variadic { name: _ } => ParameterKind::Variadic { name: Name::new_static("args"), diff --git a/crates/ty_python_semantic/src/types/subclass_of.rs b/crates/ty_python_semantic/src/types/subclass_of.rs index eb016199a5..1017ebd7d4 100644 --- a/crates/ty_python_semantic/src/types/subclass_of.rs +++ b/crates/ty_python_semantic/src/types/subclass_of.rs @@ -7,8 +7,8 @@ use crate::types::variance::VarianceInferable; use crate::types::{ ApplyTypeMappingVisitor, BoundTypeVarInstance, ClassType, DynamicType, FindLegacyTypeVarsVisitor, HasRelationToVisitor, IsDisjointVisitor, KnownClass, - MaterializationKind, MemberLookupPolicy, NormalizedVisitor, SpecialFormType, Type, TypeContext, - TypeMapping, TypeRelation, TypeVarBoundOrConstraints, TypedDictType, todo_type, + MaterializationKind, MemberLookupPolicy, NormalizedVisitor, OnlyReorder, SpecialFormType, Type, + TypeContext, TypeMapping, TypeRelation, TypeVarBoundOrConstraints, TypedDictType, todo_type, }; use crate::{Db, FxOrderSet}; @@ -263,9 +263,14 @@ impl<'db> SubclassOfType<'db> { } } - pub(crate) fn normalized_impl(self, db: &'db dyn Db, visitor: &NormalizedVisitor<'db>) -> Self { + pub(crate) fn normalized_impl( + self, + db: &'db dyn Db, + only_reorder: OnlyReorder, + visitor: &NormalizedVisitor<'db>, + ) -> Self { Self { - subclass_of: self.subclass_of.normalized_impl(db, visitor), + subclass_of: self.subclass_of.normalized_impl(db, only_reorder, visitor), } } @@ -434,12 +439,17 @@ impl<'db> SubclassOfInner<'db> { Self::TypeVar(bound_typevar) } - pub(crate) fn normalized_impl(self, db: &'db dyn Db, visitor: &NormalizedVisitor<'db>) -> Self { + pub(crate) fn normalized_impl( + self, + db: &'db dyn Db, + only_reorder: OnlyReorder, + visitor: &NormalizedVisitor<'db>, + ) -> Self { match self { - Self::Class(class) => Self::Class(class.normalized_impl(db, visitor)), - Self::Dynamic(dynamic) => Self::Dynamic(dynamic.normalized()), + Self::Class(class) => Self::Class(class.normalized_impl(db, only_reorder, visitor)), + Self::Dynamic(dynamic) => Self::Dynamic(dynamic.normalized(only_reorder)), Self::TypeVar(bound_typevar) => { - Self::TypeVar(bound_typevar.normalized_impl(db, visitor)) + Self::TypeVar(bound_typevar.normalized_impl(db, only_reorder, visitor)) } } } diff --git a/crates/ty_python_semantic/src/types/tuple.rs b/crates/ty_python_semantic/src/types/tuple.rs index f0cc3bedc8..0d90faeba2 100644 --- a/crates/ty_python_semantic/src/types/tuple.rs +++ b/crates/ty_python_semantic/src/types/tuple.rs @@ -29,8 +29,8 @@ use crate::types::constraints::{ConstraintSet, IteratorConstraintsExtension}; use crate::types::generics::InferableTypeVars; use crate::types::{ ApplyTypeMappingVisitor, BoundTypeVarInstance, FindLegacyTypeVarsVisitor, HasRelationToVisitor, - IsDisjointVisitor, IsEquivalentVisitor, NormalizedVisitor, Type, TypeMapping, TypeRelation, - UnionBuilder, UnionType, + IsDisjointVisitor, IsEquivalentVisitor, NormalizedVisitor, OnlyReorder, Type, TypeMapping, + TypeRelation, UnionBuilder, UnionType, }; use crate::types::{Truthiness, TypeContext}; use crate::{Db, FxOrderSet, Program}; @@ -225,9 +225,13 @@ impl<'db> TupleType<'db> { pub(crate) fn normalized_impl( self, db: &'db dyn Db, + only_reorder: OnlyReorder, visitor: &NormalizedVisitor<'db>, ) -> Option { - TupleType::new(db, &self.tuple(db).normalized_impl(db, visitor)) + TupleType::new( + db, + &self.tuple(db).normalized_impl(db, only_reorder, visitor), + ) } pub(super) fn recursive_type_normalized_impl( @@ -423,8 +427,17 @@ impl<'db> FixedLengthTuple> { } #[must_use] - fn normalized_impl(&self, db: &'db dyn Db, visitor: &NormalizedVisitor<'db>) -> Self { - Self::from_elements(self.0.iter().map(|ty| ty.normalized_impl(db, visitor))) + fn normalized_impl( + &self, + db: &'db dyn Db, + only_reorder: OnlyReorder, + visitor: &NormalizedVisitor<'db>, + ) -> Self { + Self::from_elements( + self.0 + .iter() + .map(|ty| ty.normalized_impl(db, only_reorder, visitor)), + ) } fn recursive_type_normalized_impl( @@ -802,16 +815,21 @@ impl<'db> VariableLengthTuple> { } #[must_use] - fn normalized_impl(&self, db: &'db dyn Db, visitor: &NormalizedVisitor<'db>) -> TupleSpec<'db> { + fn normalized_impl( + &self, + db: &'db dyn Db, + only_reorder: OnlyReorder, + visitor: &NormalizedVisitor<'db>, + ) -> TupleSpec<'db> { let prefix = self .prenormalized_prefix_elements(db, None) - .map(|ty| ty.normalized_impl(db, visitor)) + .map(|ty| ty.normalized_impl(db, only_reorder, visitor)) .collect::>(); let suffix = self .prenormalized_suffix_elements(db, None) - .map(|ty| ty.normalized_impl(db, visitor)) + .map(|ty| ty.normalized_impl(db, only_reorder, visitor)) .collect::>(); - let variable = self.variable.normalized_impl(db, visitor); + let variable = self.variable.normalized_impl(db, only_reorder, visitor); TupleSpec::Variable(Self { prefix, variable, @@ -1280,11 +1298,12 @@ impl<'db> Tuple> { pub(crate) fn normalized_impl( &self, db: &'db dyn Db, + only_reorder: OnlyReorder, visitor: &NormalizedVisitor<'db>, ) -> Self { match self { - Tuple::Fixed(tuple) => Tuple::Fixed(tuple.normalized_impl(db, visitor)), - Tuple::Variable(tuple) => tuple.normalized_impl(db, visitor), + Tuple::Fixed(tuple) => Tuple::Fixed(tuple.normalized_impl(db, only_reorder, visitor)), + Tuple::Variable(tuple) => tuple.normalized_impl(db, only_reorder, visitor), } } diff --git a/crates/ty_python_semantic/src/types/type_ordering.rs b/crates/ty_python_semantic/src/types/type_ordering.rs index c47720011c..add1d600f6 100644 --- a/crates/ty_python_semantic/src/types/type_ordering.rs +++ b/crates/ty_python_semantic/src/types/type_ordering.rs @@ -29,13 +29,13 @@ pub(super) fn union_or_intersection_elements_ordering<'db>( ) -> Ordering { debug_assert_eq!( *left, - left.normalized(db), - "`left` must be normalized before a meaningful ordering can be established" + left.canonically_ordered(db), + "`left` must be canonically ordered before a meaningful ordering can be established" ); debug_assert_eq!( *right, - right.normalized(db), - "`right` must be normalized before a meaningful ordering can be established" + right.canonically_ordered(db), + "`right` must be canonically ordered before a meaningful ordering can be established" ); if left == right { diff --git a/crates/ty_python_semantic/src/types/typed_dict.rs b/crates/ty_python_semantic/src/types/typed_dict.rs index dee49a3afe..b2180f9dd6 100644 --- a/crates/ty_python_semantic/src/types/typed_dict.rs +++ b/crates/ty_python_semantic/src/types/typed_dict.rs @@ -21,8 +21,8 @@ use crate::types::class::FieldKind; use crate::types::constraints::{ConstraintSet, IteratorConstraintsExtension}; use crate::types::generics::InferableTypeVars; use crate::types::{ - HasRelationToVisitor, IsDisjointVisitor, IsEquivalentVisitor, NormalizedVisitor, TypeContext, - TypeRelation, + HasRelationToVisitor, IsDisjointVisitor, IsEquivalentVisitor, NormalizedVisitor, OnlyReorder, + TypeContext, TypeRelation, }; use ordermap::OrderSet; @@ -298,14 +298,19 @@ impl<'db> TypedDictType<'db> { } } - pub(crate) fn normalized_impl(self, db: &'db dyn Db, visitor: &NormalizedVisitor<'db>) -> Self { + pub(crate) fn normalized_impl( + self, + db: &'db dyn Db, + only_reorder: OnlyReorder, + visitor: &NormalizedVisitor<'db>, + ) -> Self { match self { TypedDictType::Class(_) => { let synthesized = SynthesizedTypedDictType::new(db, self.items(db)); - TypedDictType::Synthesized(synthesized.normalized_impl(db, visitor)) + TypedDictType::Synthesized(synthesized.normalized_impl(db, only_reorder, visitor)) } TypedDictType::Synthesized(synthesized) => { - TypedDictType::Synthesized(synthesized.normalized_impl(db, visitor)) + TypedDictType::Synthesized(synthesized.normalized_impl(db, only_reorder, visitor)) } } } @@ -768,12 +773,17 @@ impl<'db> SynthesizedTypedDictType<'db> { SynthesizedTypedDictType::new(db, items) } - pub(crate) fn normalized_impl(self, db: &'db dyn Db, visitor: &NormalizedVisitor<'db>) -> Self { + pub(crate) fn normalized_impl( + self, + db: &'db dyn Db, + only_reorder: OnlyReorder, + visitor: &NormalizedVisitor<'db>, + ) -> Self { let items = self .items(db) .iter() .map(|(name, field)| { - let field = field.clone().normalized_impl(db, visitor); + let field = field.clone().normalized_impl(db, only_reorder, visitor); (name.clone(), field) }) .collect::>(); @@ -845,9 +855,14 @@ impl<'db> TypedDictField<'db> { } } - pub(crate) fn normalized_impl(self, db: &'db dyn Db, visitor: &NormalizedVisitor<'db>) -> Self { + pub(crate) fn normalized_impl( + self, + db: &'db dyn Db, + only_reorder: OnlyReorder, + visitor: &NormalizedVisitor<'db>, + ) -> Self { Self { - declared_ty: self.declared_ty.normalized_impl(db, visitor), + declared_ty: self.declared_ty.normalized_impl(db, only_reorder, visitor), flags: self.flags, // A normalized typed-dict field does not hold onto the original declaration, // since a normalized typed-dict is an abstract type where equality does not depend