diff --git a/crates/ty_python_semantic/src/types.rs b/crates/ty_python_semantic/src/types.rs index a377a5014d..35f52a652a 100644 --- a/crates/ty_python_semantic/src/types.rs +++ b/crates/ty_python_semantic/src/types.rs @@ -170,6 +170,24 @@ fn definition_expression_type<'db>( } } +/// A [`TypeTransformer`] that is used in `apply_type_mapping` methods. +pub(crate) type ApplyTypeMappingVisitor<'db> = TypeTransformer<'db, TypeMapping<'db, 'db>>; + +/// A [`PairVisitor`] that is used in `has_relation_to` methods. +pub(crate) type HasRelationToVisitor<'db> = PairVisitor<'db, TypeRelation>; + +/// A [`PairVisitor`] that is used in `is_disjoint_from` methods. +pub(crate) type IsDisjointVisitor<'db> = PairVisitor<'db, IsDisjoint>; +pub(crate) struct IsDisjoint; + +/// A [`PairVisitor`] that is used in `is_equivalent` methods. +pub(crate) type IsEquivalentVisitor<'db> = PairVisitor<'db, IsEquivalent>; +pub(crate) struct IsEquivalent; + +/// A [`TypeTransformer`] that is used in `normalized` methods. +pub(crate) type NormalizedVisitor<'db> = TypeTransformer<'db, Normalized>; +pub(crate) struct Normalized; + /// The descriptor protocol distinguishes two kinds of descriptors. Non-data descriptors /// define a `__get__` method, while data descriptors additionally define a `__set__` /// method or a `__delete__` method. This enum is used to categorize attributes into two @@ -419,7 +437,7 @@ impl<'db> PropertyInstanceType<'db> { Self::new(db, getter, setter) } - fn normalized_impl(self, db: &'db dyn Db, visitor: &TypeTransformer<'db>) -> Self { + fn normalized_impl(self, db: &'db dyn Db, visitor: &NormalizedVisitor<'db>) -> Self { Self::new( db, self.getter(db).map(|ty| ty.normalized_impl(db, visitor)), @@ -1068,7 +1086,7 @@ impl<'db> Type<'db> { } #[must_use] - pub(crate) fn normalized_impl(self, db: &'db dyn Db, visitor: &TypeTransformer<'db>) -> Self { + pub(crate) fn normalized_impl(self, db: &'db dyn Db, visitor: &NormalizedVisitor<'db>) -> Self { match self { Type::Union(union) => { visitor.visit(self, || Type::Union(union.normalized_impl(db, visitor))) @@ -1326,7 +1344,7 @@ impl<'db> Type<'db> { db: &'db dyn Db, target: Type<'db>, relation: TypeRelation, - visitor: &PairVisitor<'db>, + visitor: &HasRelationToVisitor<'db>, ) -> bool { // Subtyping implies assignability, so if subtyping is reflexive and the two types are // equal, it is both a subtype and assignable. Assignability is always reflexive. @@ -1762,7 +1780,7 @@ impl<'db> Type<'db> { self, db: &'db dyn Db, other: Type<'db>, - visitor: &PairVisitor<'db>, + visitor: &IsEquivalentVisitor<'db>, ) -> bool { if self == other { return true; @@ -1848,13 +1866,13 @@ impl<'db> Type<'db> { self, db: &'db dyn Db, other: Type<'db>, - visitor: &PairVisitor<'db>, + visitor: &IsDisjointVisitor<'db>, ) -> bool { fn any_protocol_members_absent_or_disjoint<'db>( db: &'db dyn Db, protocol: ProtocolInstanceType<'db>, other: Type<'db>, - visitor: &PairVisitor<'db>, + visitor: &IsDisjointVisitor<'db>, ) -> bool { protocol.interface(db).members(db).any(|member| { other @@ -5743,7 +5761,7 @@ impl<'db> Type<'db> { self, db: &'db dyn Db, type_mapping: &TypeMapping<'a, 'db>, - visitor: &TypeTransformer<'db>, + visitor: &ApplyTypeMappingVisitor<'db>, ) -> Type<'db> { match self { Type::TypeVar(bound_typevar) => match type_mapping { @@ -6265,7 +6283,7 @@ impl<'db> TypeMapping<'_, 'db> { } } - fn normalized_impl(&self, db: &'db dyn Db, visitor: &TypeTransformer<'db>) -> Self { + fn normalized_impl(&self, db: &'db dyn Db, visitor: &NormalizedVisitor<'db>) -> Self { match self { TypeMapping::Specialization(specialization) => { TypeMapping::Specialization(specialization.normalized_impl(db, visitor)) @@ -6351,7 +6369,7 @@ fn walk_known_instance_type<'db, V: visitor::TypeVisitor<'db> + ?Sized>( } impl<'db> KnownInstanceType<'db> { - fn normalized_impl(self, db: &'db dyn Db, visitor: &TypeTransformer<'db>) -> Self { + fn normalized_impl(self, db: &'db dyn Db, visitor: &NormalizedVisitor<'db>) -> Self { match self { Self::SubscriptedProtocol(context) => { Self::SubscriptedProtocol(context.normalized_impl(db, visitor)) @@ -6777,7 +6795,7 @@ 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: &TypeTransformer<'db>) -> Self { + pub(crate) fn normalized_impl(self, db: &'db dyn Db, visitor: &NormalizedVisitor<'db>) -> Self { FieldInstance::new( db, self.default_type(db).normalized_impl(db, visitor), @@ -6901,7 +6919,7 @@ impl<'db> TypeVarInstance<'db> { } } - pub(crate) fn normalized_impl(self, db: &'db dyn Db, visitor: &TypeTransformer<'db>) -> Self { + pub(crate) fn normalized_impl(self, db: &'db dyn Db, visitor: &NormalizedVisitor<'db>) -> Self { Self::new( db, self.name(db), @@ -6997,7 +7015,7 @@ impl<'db> BoundTypeVarInstance<'db> { .map(|ty| ty.apply_type_mapping(db, &TypeMapping::BindLegacyTypevars(binding_context))) } - pub(crate) fn normalized_impl(self, db: &'db dyn Db, visitor: &TypeTransformer<'db>) -> Self { + pub(crate) fn normalized_impl(self, db: &'db dyn Db, visitor: &NormalizedVisitor<'db>) -> Self { Self::new( db, self.typevar(db).normalized_impl(db, visitor), @@ -7056,7 +7074,7 @@ fn walk_type_var_bounds<'db, V: visitor::TypeVisitor<'db> + ?Sized>( } impl<'db> TypeVarBoundOrConstraints<'db> { - fn normalized_impl(self, db: &'db dyn Db, visitor: &TypeTransformer<'db>) -> Self { + fn normalized_impl(self, db: &'db dyn Db, visitor: &NormalizedVisitor<'db>) -> Self { match self { TypeVarBoundOrConstraints::UpperBound(bound) => { TypeVarBoundOrConstraints::UpperBound(bound.normalized_impl(db, visitor)) @@ -8094,7 +8112,7 @@ impl<'db> BoundMethodType<'db> { ) } - fn normalized_impl(self, db: &'db dyn Db, visitor: &TypeTransformer<'db>) -> Self { + fn normalized_impl(self, db: &'db dyn Db, visitor: &NormalizedVisitor<'db>) -> Self { Self::new( db, self.function(db).normalized_impl(db, visitor), @@ -8211,7 +8229,7 @@ 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: &TypeTransformer<'db>) -> Self { + fn normalized_impl(self, db: &'db dyn Db, visitor: &NormalizedVisitor<'db>) -> Self { CallableType::new( db, self.signatures(db).normalized_impl(db, visitor), @@ -8375,7 +8393,7 @@ impl<'db> MethodWrapperKind<'db> { } } - fn normalized_impl(self, db: &'db dyn Db, visitor: &TypeTransformer<'db>) -> Self { + fn normalized_impl(self, db: &'db dyn Db, visitor: &NormalizedVisitor<'db>) -> Self { match self { MethodWrapperKind::FunctionTypeDunderGet(function) => { MethodWrapperKind::FunctionTypeDunderGet(function.normalized_impl(db, visitor)) @@ -8559,7 +8577,7 @@ impl<'db> PEP695TypeAliasType<'db> { definition_expression_type(db, definition, &type_alias_stmt_node.value) } - fn normalized_impl(self, _db: &'db dyn Db, _visitor: &TypeTransformer<'db>) -> Self { + fn normalized_impl(self, _db: &'db dyn Db, _visitor: &NormalizedVisitor<'db>) -> Self { self } } @@ -8601,7 +8619,7 @@ fn walk_bare_type_alias<'db, V: visitor::TypeVisitor<'db> + ?Sized>( } impl<'db> BareTypeAliasType<'db> { - fn normalized_impl(self, db: &'db dyn Db, visitor: &TypeTransformer<'db>) -> Self { + fn normalized_impl(self, db: &'db dyn Db, visitor: &NormalizedVisitor<'db>) -> Self { Self::new( db, self.name(db), @@ -8637,7 +8655,7 @@ 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: &TypeTransformer<'db>) -> Self { + pub(crate) fn normalized_impl(self, db: &'db dyn Db, visitor: &NormalizedVisitor<'db>) -> Self { match self { TypeAliasType::PEP695(type_alias) => { TypeAliasType::PEP695(type_alias.normalized_impl(db, visitor)) @@ -8866,7 +8884,7 @@ impl<'db> UnionType<'db> { self.normalized_impl(db, &TypeTransformer::default()) } - pub(crate) fn normalized_impl(self, db: &'db dyn Db, visitor: &TypeTransformer<'db>) -> Self { + pub(crate) fn normalized_impl(self, db: &'db dyn Db, visitor: &NormalizedVisitor<'db>) -> Self { let mut new_elements: Vec> = self .elements(db) .iter() @@ -8940,11 +8958,11 @@ impl<'db> IntersectionType<'db> { self.normalized_impl(db, &TypeTransformer::default()) } - pub(crate) fn normalized_impl(self, db: &'db dyn Db, visitor: &TypeTransformer<'db>) -> Self { + pub(crate) fn normalized_impl(self, db: &'db dyn Db, visitor: &NormalizedVisitor<'db>) -> Self { fn normalized_set<'db>( db: &'db dyn Db, elements: &FxOrderSet>, - visitor: &TypeTransformer<'db>, + visitor: &NormalizedVisitor<'db>, ) -> FxOrderSet> { let mut elements: FxOrderSet> = elements .iter() @@ -9194,7 +9212,7 @@ impl<'db> TypedDictType<'db> { self, db: &'db dyn Db, type_mapping: &TypeMapping<'a, 'db>, - visitor: &TypeTransformer<'db>, + visitor: &ApplyTypeMappingVisitor<'db>, ) -> Self { Self { defining_class: self @@ -9266,7 +9284,7 @@ pub enum SuperOwnerKind<'db> { } impl<'db> SuperOwnerKind<'db> { - fn normalized_impl(self, db: &'db dyn Db, visitor: &TypeTransformer<'db>) -> Self { + fn normalized_impl(self, db: &'db dyn Db, visitor: &NormalizedVisitor<'db>) -> Self { match self { SuperOwnerKind::Dynamic(dynamic) => SuperOwnerKind::Dynamic(dynamic.normalized()), SuperOwnerKind::Class(class) => { @@ -9538,7 +9556,7 @@ impl<'db> BoundSuperType<'db> { } } - pub(super) fn normalized_impl(self, db: &'db dyn Db, visitor: &TypeTransformer<'db>) -> Self { + pub(super) fn normalized_impl(self, db: &'db dyn Db, visitor: &NormalizedVisitor<'db>) -> Self { Self::new( db, self.pivot_class(db).normalized_impl(db, visitor), diff --git a/crates/ty_python_semantic/src/types/class.rs b/crates/ty_python_semantic/src/types/class.rs index 1737305e81..72e8d20d0b 100644 --- a/crates/ty_python_semantic/src/types/class.rs +++ b/crates/ty_python_semantic/src/types/class.rs @@ -22,10 +22,11 @@ use crate::types::infer::nearest_enclosing_class; use crate::types::signatures::{CallableSignature, Parameter, Parameters, Signature}; use crate::types::tuple::{TupleSpec, TupleType}; use crate::types::{ - BareTypeAliasType, Binding, BoundSuperError, BoundSuperType, CallableType, DataclassParams, - DeprecatedInstance, KnownInstanceType, StringLiteralType, TypeAliasType, TypeMapping, - TypeRelation, TypeTransformer, TypeVarBoundOrConstraints, TypeVarInstance, TypeVarKind, - declaration_type, infer_definition_types, todo_type, + ApplyTypeMappingVisitor, BareTypeAliasType, Binding, BoundSuperError, BoundSuperType, + CallableType, DataclassParams, DeprecatedInstance, HasRelationToVisitor, KnownInstanceType, + NormalizedVisitor, StringLiteralType, TypeAliasType, TypeMapping, TypeRelation, + TypeVarBoundOrConstraints, TypeVarInstance, TypeVarKind, declaration_type, + infer_definition_types, todo_type, }; use crate::{ Db, FxIndexMap, FxOrderSet, Program, @@ -231,7 +232,7 @@ 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: &TypeTransformer<'db>) -> Self { + pub(super) fn normalized_impl(self, db: &'db dyn Db, visitor: &NormalizedVisitor<'db>) -> Self { Self::new( db, self.origin(db), @@ -255,7 +256,7 @@ impl<'db> GenericAlias<'db> { self, db: &'db dyn Db, type_mapping: &TypeMapping<'a, 'db>, - visitor: &TypeTransformer<'db>, + visitor: &ApplyTypeMappingVisitor<'db>, ) -> Self { Self::new( db, @@ -319,7 +320,7 @@ impl<'db> ClassType<'db> { } } - pub(super) fn normalized_impl(self, db: &'db dyn Db, visitor: &TypeTransformer<'db>) -> Self { + pub(super) fn normalized_impl(self, db: &'db dyn Db, visitor: &NormalizedVisitor<'db>) -> Self { match self { Self::NonGeneric(_) => self, Self::Generic(generic) => Self::Generic(generic.normalized_impl(db, visitor)), @@ -406,7 +407,7 @@ impl<'db> ClassType<'db> { self, db: &'db dyn Db, type_mapping: &TypeMapping<'a, 'db>, - visitor: &TypeTransformer<'db>, + visitor: &ApplyTypeMappingVisitor<'db>, ) -> Self { match self { Self::NonGeneric(_) => self, @@ -469,7 +470,7 @@ impl<'db> ClassType<'db> { db: &'db dyn Db, other: Self, relation: TypeRelation, - visitor: &PairVisitor<'db>, + visitor: &HasRelationToVisitor<'db>, ) -> bool { self.iter_mro(db).any(|base| { match base { diff --git a/crates/ty_python_semantic/src/types/class_base.rs b/crates/ty_python_semantic/src/types/class_base.rs index 4bfc834b52..c74dc815f3 100644 --- a/crates/ty_python_semantic/src/types/class_base.rs +++ b/crates/ty_python_semantic/src/types/class_base.rs @@ -2,8 +2,9 @@ use crate::Db; use crate::types::generics::Specialization; use crate::types::tuple::TupleType; use crate::types::{ - ClassLiteral, ClassType, DynamicType, KnownClass, KnownInstanceType, MroError, MroIterator, - SpecialFormType, Type, TypeMapping, TypeTransformer, todo_type, + ApplyTypeMappingVisitor, ClassLiteral, ClassType, DynamicType, KnownClass, KnownInstanceType, + MroError, MroIterator, NormalizedVisitor, SpecialFormType, Type, TypeMapping, TypeTransformer, + todo_type, }; /// Enumeration of the possible kinds of types we allow in class bases. @@ -33,7 +34,7 @@ impl<'db> ClassBase<'db> { Self::Dynamic(DynamicType::Unknown) } - pub(crate) fn normalized_impl(self, db: &'db dyn Db, visitor: &TypeTransformer<'db>) -> Self { + pub(crate) fn normalized_impl(self, db: &'db dyn Db, visitor: &NormalizedVisitor<'db>) -> Self { match self { Self::Dynamic(dynamic) => Self::Dynamic(dynamic.normalized()), Self::Class(class) => Self::Class(class.normalized_impl(db, visitor)), @@ -269,7 +270,7 @@ impl<'db> ClassBase<'db> { self, db: &'db dyn Db, type_mapping: &TypeMapping<'a, 'db>, - visitor: &TypeTransformer<'db>, + visitor: &ApplyTypeMappingVisitor<'db>, ) -> Self { match self { Self::Class(class) => { diff --git a/crates/ty_python_semantic/src/types/cyclic.rs b/crates/ty_python_semantic/src/types/cyclic.rs index 228449a916..27a201143b 100644 --- a/crates/ty_python_semantic/src/types/cyclic.rs +++ b/crates/ty_python_semantic/src/types/cyclic.rs @@ -18,17 +18,20 @@ //! `visitor.visit` when visiting a protocol type, and then internal `has_relation_to_impl` methods //! of the Rust types implementing protocols also call `visitor.visit`. The best way to avoid this //! is to prefer always calling `visitor.visit` only in the main recursive method on `Type`. + +use std::cell::RefCell; +use std::cmp::Eq; +use std::hash::Hash; +use std::marker::PhantomData; + use rustc_hash::FxHashMap; use crate::FxIndexSet; use crate::types::Type; -use std::cell::RefCell; -use std::cmp::Eq; -use std::hash::Hash; -pub(crate) type TypeTransformer<'db> = CycleDetector, Type<'db>>; +pub(crate) type TypeTransformer<'db, Tag> = CycleDetector, Type<'db>>; -impl Default for TypeTransformer<'_> { +impl Default for TypeTransformer<'_, Tag> { fn default() -> Self { // TODO: proper recursive type handling @@ -38,10 +41,10 @@ impl Default for TypeTransformer<'_> { } } -pub(crate) type PairVisitor<'db> = CycleDetector<(Type<'db>, Type<'db>), bool>; +pub(crate) type PairVisitor<'db, Tag> = CycleDetector, Type<'db>), bool>; #[derive(Debug)] -pub(crate) struct CycleDetector { +pub(crate) struct CycleDetector { /// If the type we're visiting is present in `seen`, it indicates that we've hit a cycle (due /// to a recursive type); we need to immediately short circuit the whole operation and return /// the fallback value. That's why we pop items off the end of `seen` after we've visited them. @@ -56,14 +59,17 @@ pub(crate) struct CycleDetector { cache: RefCell>, fallback: R, + + _tag: PhantomData, } -impl CycleDetector { +impl CycleDetector { pub(crate) fn new(fallback: R) -> Self { CycleDetector { seen: RefCell::new(FxIndexSet::default()), cache: RefCell::new(FxHashMap::default()), fallback, + _tag: PhantomData, } } diff --git a/crates/ty_python_semantic/src/types/function.rs b/crates/ty_python_semantic/src/types/function.rs index cbc6e1274a..8a38ea0a84 100644 --- a/crates/ty_python_semantic/src/types/function.rs +++ b/crates/ty_python_semantic/src/types/function.rs @@ -77,8 +77,8 @@ use crate::types::signatures::{CallableSignature, Signature}; use crate::types::visitor::any_over_type; use crate::types::{ BoundMethodType, BoundTypeVarInstance, CallableType, ClassBase, ClassLiteral, ClassType, - DeprecatedInstance, DynamicType, KnownClass, Truthiness, Type, TypeMapping, TypeRelation, - TypeTransformer, UnionBuilder, all_members, walk_type_mapping, + DeprecatedInstance, DynamicType, KnownClass, NormalizedVisitor, Truthiness, Type, TypeMapping, + TypeRelation, TypeTransformer, UnionBuilder, all_members, walk_type_mapping, }; use crate::{Db, FxOrderSet, ModuleName, resolve_module}; @@ -604,7 +604,7 @@ impl<'db> FunctionLiteral<'db> { ) } - fn normalized_impl(self, db: &'db dyn Db, visitor: &TypeTransformer<'db>) -> Self { + fn normalized_impl(self, db: &'db dyn Db, visitor: &NormalizedVisitor<'db>) -> Self { let context = self .inherited_generic_context(db) .map(|ctx| ctx.normalized_impl(db, visitor)); @@ -923,7 +923,7 @@ impl<'db> FunctionType<'db> { self.normalized_impl(db, &TypeTransformer::default()) } - pub(crate) fn normalized_impl(self, db: &'db dyn Db, visitor: &TypeTransformer<'db>) -> Self { + pub(crate) fn normalized_impl(self, db: &'db dyn Db, visitor: &NormalizedVisitor<'db>) -> Self { let mappings: Box<_> = self .type_mappings(db) .iter() diff --git a/crates/ty_python_semantic/src/types/generics.rs b/crates/ty_python_semantic/src/types/generics.rs index 03bcca8ed3..c846ca6ee2 100644 --- a/crates/ty_python_semantic/src/types/generics.rs +++ b/crates/ty_python_semantic/src/types/generics.rs @@ -14,9 +14,10 @@ use crate::types::instance::{Protocol, ProtocolInstanceType}; use crate::types::signatures::{Parameter, Parameters, Signature}; use crate::types::tuple::{TupleSpec, TupleType, walk_tuple_type}; use crate::types::{ - BoundTypeVarInstance, KnownClass, KnownInstanceType, Type, TypeMapping, TypeRelation, - TypeTransformer, TypeVarBoundOrConstraints, TypeVarInstance, TypeVarVariance, UnionType, - binding_type, cyclic::PairVisitor, declaration_type, + ApplyTypeMappingVisitor, BoundTypeVarInstance, HasRelationToVisitor, KnownClass, + KnownInstanceType, NormalizedVisitor, Type, TypeMapping, TypeRelation, TypeTransformer, + TypeVarBoundOrConstraints, TypeVarInstance, TypeVarVariance, UnionType, binding_type, + declaration_type, }; use crate::{Db, FxOrderSet}; @@ -355,7 +356,7 @@ impl<'db> GenericContext<'db> { Specialization::new(db, self, expanded.into_boxed_slice(), None) } - pub(crate) fn normalized_impl(self, db: &'db dyn Db, visitor: &TypeTransformer<'db>) -> Self { + pub(crate) fn normalized_impl(self, db: &'db dyn Db, visitor: &NormalizedVisitor<'db>) -> Self { let variables: FxOrderSet<_> = self .variables(db) .iter() @@ -471,7 +472,7 @@ impl<'db> Specialization<'db> { self, db: &'db dyn Db, type_mapping: &TypeMapping<'a, 'db>, - visitor: &TypeTransformer<'db>, + visitor: &ApplyTypeMappingVisitor<'db>, ) -> Self { let types: Box<[_]> = self .types(db) @@ -522,7 +523,7 @@ impl<'db> Specialization<'db> { Specialization::new(db, self.generic_context(db), types, None) } - pub(crate) fn normalized_impl(self, db: &'db dyn Db, visitor: &TypeTransformer<'db>) -> Self { + pub(crate) fn normalized_impl(self, db: &'db dyn Db, visitor: &NormalizedVisitor<'db>) -> Self { let types: Box<[_]> = self .types(db) .iter() @@ -563,7 +564,7 @@ impl<'db> Specialization<'db> { db: &'db dyn Db, other: Self, relation: TypeRelation, - visitor: &PairVisitor<'db>, + visitor: &HasRelationToVisitor<'db>, ) -> bool { let generic_context = self.generic_context(db); if generic_context != other.generic_context(db) { @@ -716,7 +717,7 @@ impl<'db> PartialSpecialization<'_, 'db> { pub(crate) fn normalized_impl( &self, db: &'db dyn Db, - visitor: &TypeTransformer<'db>, + visitor: &NormalizedVisitor<'db>, ) -> PartialSpecialization<'db, 'db> { let generic_context = self.generic_context.normalized_impl(db, visitor); let types: Cow<_> = self diff --git a/crates/ty_python_semantic/src/types/instance.rs b/crates/ty_python_semantic/src/types/instance.rs index 3c628f7502..ca837cd294 100644 --- a/crates/ty_python_semantic/src/types/instance.rs +++ b/crates/ty_python_semantic/src/types/instance.rs @@ -7,11 +7,13 @@ use super::protocol_class::ProtocolInterface; use super::{BoundTypeVarInstance, ClassType, KnownClass, SubclassOfType, Type, TypeVarVariance}; use crate::place::PlaceAndQualifiers; use crate::semantic_index::definition::Definition; -use crate::types::cyclic::PairVisitor; use crate::types::enums::is_single_member_enum; use crate::types::protocol_class::walk_protocol_interface; use crate::types::tuple::{TupleSpec, TupleType}; -use crate::types::{ClassBase, DynamicType, TypeMapping, TypeRelation, TypeTransformer}; +use crate::types::{ + ApplyTypeMappingVisitor, ClassBase, DynamicType, HasRelationToVisitor, IsDisjointVisitor, + NormalizedVisitor, TypeMapping, TypeRelation, TypeTransformer, +}; use crate::{Db, FxOrderSet}; pub(super) use synthesized_protocol::SynthesizedProtocolType; @@ -241,7 +243,7 @@ impl<'db> NominalInstanceType<'db> { pub(super) fn normalized_impl( self, db: &'db dyn Db, - visitor: &TypeTransformer<'db>, + visitor: &NormalizedVisitor<'db>, ) -> Type<'db> { match self.0 { NominalInstanceInner::ExactTuple(tuple) => { @@ -267,7 +269,7 @@ impl<'db> NominalInstanceType<'db> { db: &'db dyn Db, other: Self, relation: TypeRelation, - visitor: &PairVisitor<'db>, + visitor: &HasRelationToVisitor<'db>, ) -> bool { match (self.0, other.0) { ( @@ -297,7 +299,7 @@ impl<'db> NominalInstanceType<'db> { self, db: &'db dyn Db, other: Self, - visitor: &PairVisitor<'db>, + visitor: &IsDisjointVisitor<'db>, ) -> bool { if let Some(self_spec) = self.tuple_spec(db) { if let Some(other_spec) = other.tuple_spec(db) { @@ -345,7 +347,7 @@ impl<'db> NominalInstanceType<'db> { self, db: &'db dyn Db, type_mapping: &TypeMapping<'a, 'db>, - visitor: &TypeTransformer<'db>, + visitor: &ApplyTypeMappingVisitor<'db>, ) -> Type<'db> { match self.0 { NominalInstanceInner::ExactTuple(tuple) => { @@ -480,7 +482,7 @@ impl<'db> ProtocolInstanceType<'db> { pub(super) fn normalized_impl( self, db: &'db dyn Db, - visitor: &TypeTransformer<'db>, + visitor: &NormalizedVisitor<'db>, ) -> Type<'db> { let object = Type::object(db); if object.satisfies_protocol(db, self, TypeRelation::Subtyping) { @@ -532,7 +534,7 @@ impl<'db> ProtocolInstanceType<'db> { self, _db: &'db dyn Db, _other: Self, - _visitor: &PairVisitor<'db>, + _visitor: &IsDisjointVisitor<'db>, ) -> bool { false } @@ -558,7 +560,7 @@ impl<'db> ProtocolInstanceType<'db> { self, db: &'db dyn Db, type_mapping: &TypeMapping<'a, 'db>, - visitor: &TypeTransformer<'db>, + visitor: &ApplyTypeMappingVisitor<'db>, ) -> Self { match self.inner { Protocol::FromClass(class) => { @@ -619,7 +621,10 @@ impl<'db> Protocol<'db> { mod synthesized_protocol { use crate::semantic_index::definition::Definition; use crate::types::protocol_class::ProtocolInterface; - use crate::types::{BoundTypeVarInstance, TypeMapping, TypeTransformer, TypeVarVariance}; + use crate::types::{ + ApplyTypeMappingVisitor, BoundTypeVarInstance, NormalizedVisitor, TypeMapping, + TypeVarVariance, + }; use crate::{Db, FxOrderSet}; /// A "synthesized" protocol type that is dissociated from a class definition in source code. @@ -640,7 +645,7 @@ mod synthesized_protocol { pub(super) fn new( db: &'db dyn Db, interface: ProtocolInterface<'db>, - visitor: &TypeTransformer<'db>, + visitor: &NormalizedVisitor<'db>, ) -> Self { Self(interface.normalized_impl(db, visitor)) } @@ -653,7 +658,7 @@ mod synthesized_protocol { self, db: &'db dyn Db, type_mapping: &TypeMapping<'a, 'db>, - _visitor: &TypeTransformer<'db>, + _visitor: &ApplyTypeMappingVisitor<'db>, ) -> Self { Self(self.0.specialized_and_normalized(db, type_mapping)) } diff --git a/crates/ty_python_semantic/src/types/protocol_class.rs b/crates/ty_python_semantic/src/types/protocol_class.rs index b129a8800f..77c5607c00 100644 --- a/crates/ty_python_semantic/src/types/protocol_class.rs +++ b/crates/ty_python_semantic/src/types/protocol_class.rs @@ -12,10 +12,9 @@ use crate::{ place::{Boundness, Place, PlaceAndQualifiers, place_from_bindings, place_from_declarations}, semantic_index::{definition::Definition, use_def_map}, types::{ - BoundTypeVarInstance, CallableType, ClassBase, ClassLiteral, KnownFunction, - PropertyInstanceType, Signature, Type, TypeMapping, TypeQualifiers, TypeRelation, - TypeTransformer, - cyclic::PairVisitor, + BoundTypeVarInstance, CallableType, ClassBase, ClassLiteral, IsDisjointVisitor, + KnownFunction, NormalizedVisitor, PropertyInstanceType, Signature, Type, TypeMapping, + TypeQualifiers, TypeRelation, TypeTransformer, signatures::{Parameter, Parameters}, }, }; @@ -165,7 +164,7 @@ impl<'db> ProtocolInterface<'db> { .all(|member_name| other.inner(db).contains_key(member_name)) } - pub(super) fn normalized_impl(self, db: &'db dyn Db, visitor: &TypeTransformer<'db>) -> Self { + pub(super) fn normalized_impl(self, db: &'db dyn Db, visitor: &NormalizedVisitor<'db>) -> Self { Self::new( db, self.inner(db) @@ -252,7 +251,7 @@ impl<'db> ProtocolMemberData<'db> { self.normalized_impl(db, &TypeTransformer::default()) } - fn normalized_impl(&self, db: &'db dyn Db, visitor: &TypeTransformer<'db>) -> Self { + fn normalized_impl(&self, db: &'db dyn Db, visitor: &NormalizedVisitor<'db>) -> Self { Self { kind: self.kind.normalized_impl(db, visitor), qualifiers: self.qualifiers, @@ -327,7 +326,7 @@ enum ProtocolMemberKind<'db> { } impl<'db> ProtocolMemberKind<'db> { - fn normalized_impl(&self, db: &'db dyn Db, visitor: &TypeTransformer<'db>) -> Self { + fn normalized_impl(&self, db: &'db dyn Db, visitor: &NormalizedVisitor<'db>) -> Self { match self { ProtocolMemberKind::Method(callable) => { ProtocolMemberKind::Method(callable.normalized_impl(db, visitor)) @@ -432,7 +431,7 @@ impl<'a, 'db> ProtocolMember<'a, 'db> { &self, db: &'db dyn Db, other: Type<'db>, - visitor: &PairVisitor<'db>, + visitor: &IsDisjointVisitor<'db>, ) -> bool { match &self.kind { // TODO: implement disjointness for property/method members as well as attribute members diff --git a/crates/ty_python_semantic/src/types/signatures.rs b/crates/ty_python_semantic/src/types/signatures.rs index dfcc212ce5..2120c62548 100644 --- a/crates/ty_python_semantic/src/types/signatures.rs +++ b/crates/ty_python_semantic/src/types/signatures.rs @@ -15,10 +15,12 @@ use std::{collections::HashMap, slice::Iter}; use itertools::EitherOrBoth; use smallvec::{SmallVec, smallvec_inline}; -use super::{DynamicType, Type, TypeTransformer, TypeVarVariance, definition_expression_type}; +use super::{DynamicType, Type, TypeVarVariance, definition_expression_type}; use crate::semantic_index::definition::Definition; use crate::types::generics::{GenericContext, walk_generic_context}; -use crate::types::{BoundTypeVarInstance, KnownClass, TypeMapping, TypeRelation, todo_type}; +use crate::types::{ + BoundTypeVarInstance, KnownClass, NormalizedVisitor, TypeMapping, TypeRelation, todo_type, +}; use crate::{Db, FxOrderSet}; use ruff_python_ast::{self as ast, name::Name}; @@ -61,7 +63,11 @@ impl<'db> CallableSignature<'db> { ) } - pub(crate) fn normalized_impl(&self, db: &'db dyn Db, visitor: &TypeTransformer<'db>) -> Self { + pub(crate) fn normalized_impl( + &self, + db: &'db dyn Db, + visitor: &NormalizedVisitor<'db>, + ) -> Self { Self::from_overloads( self.overloads .iter() @@ -380,7 +386,11 @@ impl<'db> Signature<'db> { } } - pub(crate) fn normalized_impl(&self, db: &'db dyn Db, visitor: &TypeTransformer<'db>) -> Self { + pub(crate) fn normalized_impl( + &self, + db: &'db dyn Db, + visitor: &NormalizedVisitor<'db>, + ) -> Self { Self { generic_context: self .generic_context @@ -1360,7 +1370,11 @@ impl<'db> Parameter<'db> { /// Normalize nested unions and intersections in the annotated type, if any. /// /// See [`Type::normalized`] for more details. - pub(crate) fn normalized_impl(&self, db: &'db dyn Db, visitor: &TypeTransformer<'db>) -> Self { + pub(crate) fn normalized_impl( + &self, + db: &'db dyn Db, + visitor: &NormalizedVisitor<'db>, + ) -> Self { let Parameter { annotated_type, kind, diff --git a/crates/ty_python_semantic/src/types/subclass_of.rs b/crates/ty_python_semantic/src/types/subclass_of.rs index 8840bdb025..f1815f50a5 100644 --- a/crates/ty_python_semantic/src/types/subclass_of.rs +++ b/crates/ty_python_semantic/src/types/subclass_of.rs @@ -3,8 +3,9 @@ use ruff_python_ast::name::Name; use crate::place::PlaceAndQualifiers; use crate::semantic_index::definition::Definition; use crate::types::{ - BindingContext, BoundTypeVarInstance, ClassType, DynamicType, KnownClass, MemberLookupPolicy, - Type, TypeMapping, TypeRelation, TypeTransformer, TypeVarInstance, cyclic::PairVisitor, + ApplyTypeMappingVisitor, BindingContext, BoundTypeVarInstance, ClassType, DynamicType, + HasRelationToVisitor, KnownClass, MemberLookupPolicy, NormalizedVisitor, Type, TypeMapping, + TypeRelation, TypeVarInstance, }; use crate::{Db, FxOrderSet}; @@ -116,7 +117,7 @@ impl<'db> SubclassOfType<'db> { self, db: &'db dyn Db, type_mapping: &TypeMapping<'a, 'db>, - visitor: &TypeTransformer<'db>, + visitor: &ApplyTypeMappingVisitor<'db>, ) -> Self { match self.subclass_of { SubclassOfInner::Class(class) => Self { @@ -159,7 +160,7 @@ impl<'db> SubclassOfType<'db> { db: &'db dyn Db, other: SubclassOfType<'db>, relation: TypeRelation, - visitor: &PairVisitor<'db>, + visitor: &HasRelationToVisitor<'db>, ) -> bool { match (self.subclass_of, other.subclass_of) { (SubclassOfInner::Dynamic(_), SubclassOfInner::Dynamic(_)) => { @@ -191,7 +192,7 @@ impl<'db> SubclassOfType<'db> { } } - pub(crate) fn normalized_impl(self, db: &'db dyn Db, visitor: &TypeTransformer<'db>) -> Self { + pub(crate) fn normalized_impl(self, db: &'db dyn Db, visitor: &NormalizedVisitor<'db>) -> Self { Self { subclass_of: self.subclass_of.normalized_impl(db, visitor), } @@ -254,7 +255,7 @@ impl<'db> SubclassOfInner<'db> { } } - pub(crate) fn normalized_impl(self, db: &'db dyn Db, visitor: &TypeTransformer<'db>) -> Self { + pub(crate) fn normalized_impl(self, db: &'db dyn Db, visitor: &NormalizedVisitor<'db>) -> Self { match self { Self::Class(class) => Self::Class(class.normalized_impl(db, visitor)), Self::Dynamic(dynamic) => Self::Dynamic(dynamic.normalized()), diff --git a/crates/ty_python_semantic/src/types/tuple.rs b/crates/ty_python_semantic/src/types/tuple.rs index 8a89235fb4..6058b4e49a 100644 --- a/crates/ty_python_semantic/src/types/tuple.rs +++ b/crates/ty_python_semantic/src/types/tuple.rs @@ -25,8 +25,8 @@ use crate::semantic_index::definition::Definition; use crate::types::Truthiness; use crate::types::class::{ClassType, KnownClass}; use crate::types::{ - BoundTypeVarInstance, Type, TypeMapping, TypeRelation, TypeTransformer, TypeVarVariance, - UnionBuilder, UnionType, cyclic::PairVisitor, + ApplyTypeMappingVisitor, BoundTypeVarInstance, HasRelationToVisitor, IsDisjointVisitor, + NormalizedVisitor, Type, TypeMapping, TypeRelation, TypeVarVariance, UnionBuilder, UnionType, }; use crate::util::subscript::{Nth, OutOfBoundsError, PyIndex, PySlice, StepSizeZeroError}; use crate::{Db, FxOrderSet, Program}; @@ -221,7 +221,7 @@ impl<'db> TupleType<'db> { pub(crate) fn normalized_impl( self, db: &'db dyn Db, - visitor: &TypeTransformer<'db>, + visitor: &NormalizedVisitor<'db>, ) -> Option { TupleType::new(db, &self.tuple(db).normalized_impl(db, visitor)) } @@ -234,7 +234,7 @@ impl<'db> TupleType<'db> { self, db: &'db dyn Db, type_mapping: &TypeMapping<'a, 'db>, - visitor: &TypeTransformer<'db>, + visitor: &ApplyTypeMappingVisitor<'db>, ) -> Option { TupleType::new( db, @@ -259,7 +259,7 @@ impl<'db> TupleType<'db> { db: &'db dyn Db, other: Self, relation: TypeRelation, - visitor: &PairVisitor<'db>, + visitor: &HasRelationToVisitor<'db>, ) -> bool { self.tuple(db) .has_relation_to_impl(db, other.tuple(db), relation, visitor) @@ -377,7 +377,7 @@ impl<'db> FixedLengthTuple> { } #[must_use] - fn normalized_impl(&self, db: &'db dyn Db, visitor: &TypeTransformer<'db>) -> Self { + 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))) } @@ -389,7 +389,7 @@ impl<'db> FixedLengthTuple> { &self, db: &'db dyn Db, type_mapping: &TypeMapping<'a, 'db>, - visitor: &TypeTransformer<'db>, + visitor: &ApplyTypeMappingVisitor<'db>, ) -> Self { Self::from_elements( self.0 @@ -414,7 +414,7 @@ impl<'db> FixedLengthTuple> { db: &'db dyn Db, other: &Tuple>, relation: TypeRelation, - visitor: &PairVisitor<'db>, + visitor: &HasRelationToVisitor<'db>, ) -> bool { match other { Tuple::Fixed(other) => { @@ -658,7 +658,7 @@ impl<'db> VariableLengthTuple> { } #[must_use] - fn normalized_impl(&self, db: &'db dyn Db, visitor: &TypeTransformer<'db>) -> TupleSpec<'db> { + fn normalized_impl(&self, db: &'db dyn Db, visitor: &NormalizedVisitor<'db>) -> TupleSpec<'db> { let prefix = self .prenormalized_prefix_elements(db, None) .map(|ty| ty.normalized_impl(db, visitor)) @@ -687,7 +687,7 @@ impl<'db> VariableLengthTuple> { &self, db: &'db dyn Db, type_mapping: &TypeMapping<'a, 'db>, - visitor: &TypeTransformer<'db>, + visitor: &ApplyTypeMappingVisitor<'db>, ) -> TupleSpec<'db> { Self::mixed( self.prefix @@ -722,7 +722,7 @@ impl<'db> VariableLengthTuple> { db: &'db dyn Db, other: &Tuple>, relation: TypeRelation, - visitor: &PairVisitor<'db>, + visitor: &HasRelationToVisitor<'db>, ) -> bool { match other { Tuple::Fixed(other) => { @@ -983,7 +983,11 @@ impl<'db> Tuple> { } } - pub(crate) fn normalized_impl(&self, db: &'db dyn Db, visitor: &TypeTransformer<'db>) -> Self { + pub(crate) fn normalized_impl( + &self, + db: &'db dyn Db, + visitor: &NormalizedVisitor<'db>, + ) -> Self { match self { Tuple::Fixed(tuple) => Tuple::Fixed(tuple.normalized_impl(db, visitor)), Tuple::Variable(tuple) => tuple.normalized_impl(db, visitor), @@ -1001,7 +1005,7 @@ impl<'db> Tuple> { &self, db: &'db dyn Db, type_mapping: &TypeMapping<'a, 'db>, - visitor: &TypeTransformer<'db>, + visitor: &ApplyTypeMappingVisitor<'db>, ) -> Self { match self { Tuple::Fixed(tuple) => { @@ -1028,7 +1032,7 @@ impl<'db> Tuple> { db: &'db dyn Db, other: &Self, relation: TypeRelation, - visitor: &PairVisitor<'db>, + visitor: &HasRelationToVisitor<'db>, ) -> bool { match self { Tuple::Fixed(self_tuple) => { @@ -1056,7 +1060,7 @@ impl<'db> Tuple> { &self, db: &'db dyn Db, other: &Self, - visitor: &PairVisitor<'db>, + visitor: &IsDisjointVisitor<'db>, ) -> bool { // Two tuples with an incompatible number of required elements must always be disjoint. let (self_min, self_max) = self.len().size_hint(); @@ -1074,7 +1078,7 @@ impl<'db> Tuple> { db: &'db dyn Db, a: impl IntoIterator>, b: impl IntoIterator>, - visitor: &PairVisitor<'db>, + visitor: &IsDisjointVisitor<'db>, ) -> bool where 'db: 's,