//! Implementation of the Chalk `Interner` trait, which allows customizing the //! representation of the various objects Chalk deals with (types, goals etc.). use crate::{ chalk_db, tls, AliasTy, CanonicalVarKind, CanonicalVarKinds, ClosureId, Const, ConstData, ConstScalar, Constraint, Constraints, FnAbi, FnDefId, GenericArg, GenericArgData, Goal, GoalData, Goals, InEnvironment, Lifetime, LifetimeData, OpaqueTy, OpaqueTyId, ProgramClause, ProgramClauseData, ProgramClauses, ProjectionTy, QuantifiedWhereClause, QuantifiedWhereClauses, Substitution, Ty, TyData, TyKind, VariableKind, VariableKinds, }; use base_db::salsa::InternId; use chalk_ir::{ProgramClauseImplication, SeparatorTraitRef, Variance}; use hir_def::TypeAliasId; use intern::{impl_internable, Interned}; use smallvec::SmallVec; use std::fmt; use triomphe::Arc; #[derive(Debug, Copy, Clone, Hash, PartialOrd, Ord, PartialEq, Eq)] pub struct Interner; #[derive(PartialEq, Eq, Hash)] pub struct InternedWrapper(T); impl fmt::Debug for InternedWrapper { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fmt::Debug::fmt(&self.0, f) } } impl std::ops::Deref for InternedWrapper { type Target = T; fn deref(&self) -> &Self::Target { &self.0 } } impl_internable!( InternedWrapper>, InternedWrapper>, InternedWrapper, InternedWrapper, InternedWrapper, InternedWrapper, InternedWrapper>, InternedWrapper>, InternedWrapper>, InternedWrapper>, ); impl chalk_ir::interner::Interner for Interner { type InternedType = Interned>; type InternedLifetime = Interned>; type InternedConst = Interned>; type InternedConcreteConst = ConstScalar; type InternedGenericArg = GenericArgData; // We could do the following, but that saves "only" 20mb on self while increasing inferecene // time by ~2.5% // type InternedGoal = Interned>; type InternedGoal = Arc; type InternedGoals = Vec; type InternedSubstitution = Interned>>; type InternedProgramClauses = Interned>>; type InternedProgramClause = ProgramClauseData; type InternedQuantifiedWhereClauses = Interned>>; type InternedVariableKinds = Interned>>; type InternedCanonicalVarKinds = Interned>>; type InternedConstraints = Vec>; type InternedVariances = SmallVec<[Variance; 16]>; type DefId = InternId; type InternedAdtId = hir_def::AdtId; type Identifier = TypeAliasId; type FnAbi = FnAbi; fn debug_adt_id( type_kind_id: chalk_db::AdtId, fmt: &mut fmt::Formatter<'_>, ) -> Option { tls::with_current_program(|prog| Some(prog?.debug_struct_id(type_kind_id, fmt))) } fn debug_trait_id( type_kind_id: chalk_db::TraitId, fmt: &mut fmt::Formatter<'_>, ) -> Option { tls::with_current_program(|prog| Some(prog?.debug_trait_id(type_kind_id, fmt))) } fn debug_assoc_type_id( id: chalk_db::AssocTypeId, fmt: &mut fmt::Formatter<'_>, ) -> Option { tls::with_current_program(|prog| Some(prog?.debug_assoc_type_id(id, fmt))) } fn debug_opaque_ty_id( opaque_ty_id: OpaqueTyId, fmt: &mut fmt::Formatter<'_>, ) -> Option { Some(write!(fmt, "OpaqueTy#{}", opaque_ty_id.0)) } fn debug_fn_def_id(fn_def_id: FnDefId, fmt: &mut fmt::Formatter<'_>) -> Option { tls::with_current_program(|prog| Some(prog?.debug_fn_def_id(fn_def_id, fmt))) } fn debug_closure_id( _fn_def_id: ClosureId, _fmt: &mut fmt::Formatter<'_>, ) -> Option { None } fn debug_alias(alias: &AliasTy, fmt: &mut fmt::Formatter<'_>) -> Option { use std::fmt::Debug; match alias { AliasTy::Projection(projection_ty) => Interner::debug_projection_ty(projection_ty, fmt), AliasTy::Opaque(opaque_ty) => Some(opaque_ty.fmt(fmt)), } } fn debug_projection_ty( proj: &ProjectionTy, fmt: &mut fmt::Formatter<'_>, ) -> Option { tls::with_current_program(|prog| Some(prog?.debug_projection_ty(proj, fmt))) } fn debug_opaque_ty(opaque_ty: &OpaqueTy, fmt: &mut fmt::Formatter<'_>) -> Option { Some(write!(fmt, "{:?}", opaque_ty.opaque_ty_id)) } fn debug_ty(ty: &Ty, fmt: &mut fmt::Formatter<'_>) -> Option { Some(write!(fmt, "{:?}", ty.data(Interner))) } fn debug_lifetime(lifetime: &Lifetime, fmt: &mut fmt::Formatter<'_>) -> Option { Some(write!(fmt, "{:?}", lifetime.data(Interner))) } fn debug_const(constant: &Const, fmt: &mut fmt::Formatter<'_>) -> Option { Some(write!(fmt, "{:?}", constant.data(Interner))) } fn debug_generic_arg( parameter: &GenericArg, fmt: &mut fmt::Formatter<'_>, ) -> Option { Some(write!(fmt, "{:?}", parameter.data(Interner).inner_debug())) } fn debug_variable_kinds( variable_kinds: &VariableKinds, fmt: &mut fmt::Formatter<'_>, ) -> Option { Some(write!(fmt, "{:?}", variable_kinds.as_slice(Interner))) } fn debug_variable_kinds_with_angles( variable_kinds: &VariableKinds, fmt: &mut fmt::Formatter<'_>, ) -> Option { Some(write!(fmt, "{:?}", variable_kinds.inner_debug(Interner))) } fn debug_canonical_var_kinds( canonical_var_kinds: &CanonicalVarKinds, fmt: &mut fmt::Formatter<'_>, ) -> Option { Some(write!(fmt, "{:?}", canonical_var_kinds.as_slice(Interner))) } fn debug_goal(goal: &Goal, fmt: &mut fmt::Formatter<'_>) -> Option { let goal_data = goal.data(Interner); Some(write!(fmt, "{goal_data:?}")) } fn debug_goals(goals: &Goals, fmt: &mut fmt::Formatter<'_>) -> Option { Some(write!(fmt, "{:?}", goals.debug(Interner))) } fn debug_program_clause_implication( pci: &ProgramClauseImplication, fmt: &mut fmt::Formatter<'_>, ) -> Option { Some(write!(fmt, "{:?}", pci.debug(Interner))) } fn debug_program_clause( clause: &ProgramClause, fmt: &mut fmt::Formatter<'_>, ) -> Option { Some(write!(fmt, "{:?}", clause.data(Interner))) } fn debug_program_clauses( clauses: &ProgramClauses, fmt: &mut fmt::Formatter<'_>, ) -> Option { Some(write!(fmt, "{:?}", clauses.as_slice(Interner))) } fn debug_substitution( substitution: &Substitution, fmt: &mut fmt::Formatter<'_>, ) -> Option { Some(write!(fmt, "{:?}", substitution.debug(Interner))) } fn debug_separator_trait_ref( separator_trait_ref: &SeparatorTraitRef<'_, Interner>, fmt: &mut fmt::Formatter<'_>, ) -> Option { Some(write!(fmt, "{:?}", separator_trait_ref.debug(Interner))) } fn debug_quantified_where_clauses( clauses: &QuantifiedWhereClauses, fmt: &mut fmt::Formatter<'_>, ) -> Option { Some(write!(fmt, "{:?}", clauses.as_slice(Interner))) } fn debug_constraints( _clauses: &Constraints, _fmt: &mut fmt::Formatter<'_>, ) -> Option { None } fn intern_ty(self, kind: TyKind) -> Self::InternedType { let flags = kind.compute_flags(self); Interned::new(InternedWrapper(TyData { kind, flags })) } fn ty_data(self, ty: &Self::InternedType) -> &TyData { &ty.0 } fn intern_lifetime(self, lifetime: LifetimeData) -> Self::InternedLifetime { Interned::new(InternedWrapper(lifetime)) } fn lifetime_data(self, lifetime: &Self::InternedLifetime) -> &LifetimeData { &lifetime.0 } fn intern_const(self, constant: ConstData) -> Self::InternedConst { Interned::new(InternedWrapper(constant)) } fn const_data(self, constant: &Self::InternedConst) -> &ConstData { &constant.0 } fn const_eq( self, _ty: &Self::InternedType, c1: &Self::InternedConcreteConst, c2: &Self::InternedConcreteConst, ) -> bool { !matches!(c1, ConstScalar::Bytes(..)) || !matches!(c2, ConstScalar::Bytes(..)) || (c1 == c2) } fn intern_generic_arg(self, parameter: GenericArgData) -> Self::InternedGenericArg { parameter } fn generic_arg_data(self, parameter: &Self::InternedGenericArg) -> &GenericArgData { parameter } fn intern_goal(self, goal: GoalData) -> Self::InternedGoal { Arc::new(goal) } fn goal_data(self, goal: &Self::InternedGoal) -> &GoalData { goal } fn intern_goals( self, data: impl IntoIterator>, ) -> Result { // let hash = // std::hash::BuildHasher::hash_one(&BuildHasherDefault::::default(), &goal); // Interned::new(InternedWrapper(PreHashedWrapper(goal, hash))) data.into_iter().collect() } fn goals_data(self, goals: &Self::InternedGoals) -> &[Goal] { goals } fn intern_substitution( self, data: impl IntoIterator>, ) -> Result { Ok(Interned::new(InternedWrapper(data.into_iter().collect::>()?))) } fn substitution_data(self, substitution: &Self::InternedSubstitution) -> &[GenericArg] { &substitution.as_ref().0 } fn intern_program_clause(self, data: ProgramClauseData) -> Self::InternedProgramClause { data } fn program_clause_data(self, clause: &Self::InternedProgramClause) -> &ProgramClauseData { clause } fn intern_program_clauses( self, data: impl IntoIterator>, ) -> Result { Ok(Interned::new(InternedWrapper(data.into_iter().collect::>()?))) } fn program_clauses_data(self, clauses: &Self::InternedProgramClauses) -> &[ProgramClause] { clauses } fn intern_quantified_where_clauses( self, data: impl IntoIterator>, ) -> Result { Ok(Interned::new(InternedWrapper(data.into_iter().collect::>()?))) } fn quantified_where_clauses_data( self, clauses: &Self::InternedQuantifiedWhereClauses, ) -> &[QuantifiedWhereClause] { clauses } fn intern_generic_arg_kinds( self, data: impl IntoIterator>, ) -> Result { Ok(Interned::new(InternedWrapper(data.into_iter().collect::>()?))) } fn variable_kinds_data(self, parameter_kinds: &Self::InternedVariableKinds) -> &[VariableKind] { ¶meter_kinds.as_ref().0 } fn intern_canonical_var_kinds( self, data: impl IntoIterator>, ) -> Result { Ok(Interned::new(InternedWrapper(data.into_iter().collect::>()?))) } fn canonical_var_kinds_data( self, canonical_var_kinds: &Self::InternedCanonicalVarKinds, ) -> &[CanonicalVarKind] { canonical_var_kinds } fn intern_constraints( self, data: impl IntoIterator, E>>, ) -> Result { data.into_iter().collect() } fn constraints_data( self, constraints: &Self::InternedConstraints, ) -> &[InEnvironment] { constraints } fn intern_variances( self, data: impl IntoIterator>, ) -> Result { data.into_iter().collect::>() } fn variances_data(self, variances: &Self::InternedVariances) -> &[Variance] { variances } } impl chalk_ir::interner::HasInterner for Interner { type Interner = Self; } #[macro_export] macro_rules! has_interner { ($t:ty) => { impl HasInterner for $t { type Interner = $crate::Interner; } }; }