//! Types required for Chalk-related queries //! //! The primary purpose of this file is defining an implementation for the //! `chalk_ir::interner::Interner` trait. The primary purpose of this trait, as //! its name suggest, is to provide an abstraction boundary for creating //! interned Chalk types. use chalk_ir::{GoalData, Parameter}; use rustc_middle::mir::Mutability; use rustc_middle::ty::fold::{TypeFoldable, TypeFolder, TypeVisitor}; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_hir::def_id::DefId; use smallvec::SmallVec; use std::cmp::Ordering; use std::fmt; use std::hash::{Hash, Hasher}; /// Since Chalk doesn't have full support for all Rust builtin types yet, we /// need to use an enum here, rather than just `DefId`. #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] pub enum RustDefId { Adt(DefId), Str, Never, Slice, Array, Ref(Mutability), RawPtr, Trait(DefId), Impl(DefId), FnDef(DefId), AssocTy(DefId), } #[derive(Copy, Clone)] pub struct RustInterner<'tcx> { pub tcx: TyCtxt<'tcx>, } /// We don't ever actually need this. It's only required for derives. impl<'tcx> Hash for RustInterner<'tcx> { fn hash(&self, _state: &mut H) {} } /// We don't ever actually need this. It's only required for derives. impl<'tcx> Ord for RustInterner<'tcx> { fn cmp(&self, _other: &Self) -> Ordering { Ordering::Equal } } /// We don't ever actually need this. It's only required for derives. impl<'tcx> PartialOrd for RustInterner<'tcx> { fn partial_cmp(&self, _other: &Self) -> Option { None } } /// We don't ever actually need this. It's only required for derives. impl<'tcx> PartialEq for RustInterner<'tcx> { fn eq(&self, _other: &Self) -> bool { false } } /// We don't ever actually need this. It's only required for derives. impl<'tcx> Eq for RustInterner<'tcx> {} impl fmt::Debug for RustInterner<'_> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "RustInterner") } } // Right now, there is no interning at all. I was running into problems with // adding interning in `ty/context.rs` for Chalk types with // `parallel-compiler = true`. -jackh726 impl<'tcx> chalk_ir::interner::Interner for RustInterner<'tcx> { type InternedType = Box>; type InternedLifetime = Box>; type InternedParameter = Box>; type InternedGoal = Box>; type InternedGoals = Vec>; type InternedSubstitution = Vec>; type InternedProgramClause = Box>; type InternedProgramClauses = Vec>; type InternedQuantifiedWhereClauses = Vec>; type InternedParameterKinds = Vec>; type InternedCanonicalVarKinds = Vec>; type DefId = RustDefId; type Identifier = (); fn debug_program_clause_implication( pci: &chalk_ir::ProgramClauseImplication, fmt: &mut fmt::Formatter<'_>, ) -> Option { let mut write = || { write!(fmt, "{:?}", pci.consequence)?; let conditions = pci.conditions.interned(); let conds = conditions.len(); if conds == 0 { return Ok(()); } write!(fmt, " :- ")?; for cond in &conditions[..conds - 1] { write!(fmt, "{:?}, ", cond)?; } write!(fmt, "{:?}", conditions[conds - 1])?; Ok(()) }; Some(write()) } fn debug_application_ty( application_ty: &chalk_ir::ApplicationTy, fmt: &mut fmt::Formatter<'_>, ) -> Option { let chalk_ir::ApplicationTy { name, substitution } = application_ty; Some(write!(fmt, "{:?}{:?}", name, chalk_ir::debug::Angle(substitution.interned()))) } fn debug_substitution( substitution: &chalk_ir::Substitution, fmt: &mut fmt::Formatter<'_>, ) -> Option { Some(write!(fmt, "{:?}", substitution.interned())) } fn debug_separator_trait_ref( separator_trait_ref: &chalk_ir::SeparatorTraitRef<'_, Self>, fmt: &mut fmt::Formatter<'_>, ) -> Option { let substitution = &separator_trait_ref.trait_ref.substitution; let parameters = substitution.interned(); Some(write!( fmt, "{:?}{}{:?}{:?}", parameters[0], separator_trait_ref.separator, separator_trait_ref.trait_ref.trait_id, chalk_ir::debug::Angle(¶meters[1..]) )) } fn debug_quantified_where_clauses( clauses: &chalk_ir::QuantifiedWhereClauses, fmt: &mut fmt::Formatter<'_>, ) -> Option { Some(write!(fmt, "{:?}", clauses.interned())) } fn debug_alias( alias_ty: &chalk_ir::AliasTy, fmt: &mut fmt::Formatter<'_>, ) -> Option { match alias_ty { chalk_ir::AliasTy::Projection(projection_ty) => { Self::debug_projection_ty(projection_ty, fmt) } chalk_ir::AliasTy::Opaque(opaque_ty) => Self::debug_opaque_ty(opaque_ty, fmt), } } fn debug_projection_ty( projection_ty: &chalk_ir::ProjectionTy, fmt: &mut fmt::Formatter<'_>, ) -> Option { Some(write!( fmt, "projection: {:?} {:?}", projection_ty.associated_ty_id, projection_ty.substitution, )) } fn debug_opaque_ty( opaque_ty: &chalk_ir::OpaqueTy, fmt: &mut fmt::Formatter<'_>, ) -> Option { Some(write!(fmt, "{:?}", opaque_ty.opaque_ty_id)) } fn intern_ty(&self, ty: chalk_ir::TyData) -> Self::InternedType { Box::new(ty) } fn ty_data<'a>(&self, ty: &'a Self::InternedType) -> &'a chalk_ir::TyData { ty } fn intern_lifetime(&self, lifetime: chalk_ir::LifetimeData) -> Self::InternedLifetime { Box::new(lifetime) } fn lifetime_data<'a>( &self, lifetime: &'a Self::InternedLifetime, ) -> &'a chalk_ir::LifetimeData { &lifetime } fn intern_parameter( &self, parameter: chalk_ir::ParameterData, ) -> Self::InternedParameter { Box::new(parameter) } fn parameter_data<'a>( &self, parameter: &'a Self::InternedParameter, ) -> &'a chalk_ir::ParameterData { ¶meter } fn intern_goal(&self, goal: GoalData) -> Self::InternedGoal { Box::new(goal) } fn goal_data<'a>(&self, goal: &'a Self::InternedGoal) -> &'a GoalData { &goal } fn intern_goals( &self, data: impl IntoIterator, E>>, ) -> Result { data.into_iter().collect::, _>>() } fn goals_data<'a>(&self, goals: &'a Self::InternedGoals) -> &'a [chalk_ir::Goal] { goals } fn intern_substitution( &self, data: impl IntoIterator, E>>, ) -> Result { data.into_iter().collect::, _>>() } fn substitution_data<'a>( &self, substitution: &'a Self::InternedSubstitution, ) -> &'a [Parameter] { substitution } fn intern_program_clause( &self, data: chalk_ir::ProgramClauseData, ) -> Self::InternedProgramClause { Box::new(data) } fn program_clause_data<'a>( &self, clause: &'a Self::InternedProgramClause, ) -> &'a chalk_ir::ProgramClauseData { &clause } fn intern_program_clauses( &self, data: impl IntoIterator, E>>, ) -> Result { data.into_iter().collect::, _>>() } fn program_clauses_data<'a>( &self, clauses: &'a Self::InternedProgramClauses, ) -> &'a [chalk_ir::ProgramClause] { clauses } fn intern_quantified_where_clauses( &self, data: impl IntoIterator, E>>, ) -> Result { data.into_iter().collect::, _>>() } fn quantified_where_clauses_data<'a>( &self, clauses: &'a Self::InternedQuantifiedWhereClauses, ) -> &'a [chalk_ir::QuantifiedWhereClause] { clauses } fn intern_parameter_kinds( &self, data: impl IntoIterator, E>>, ) -> Result { data.into_iter().collect::, _>>() } fn parameter_kinds_data<'a>( &self, parameter_kinds: &'a Self::InternedParameterKinds, ) -> &'a [chalk_ir::ParameterKind<()>] { parameter_kinds } fn intern_canonical_var_kinds( &self, data: impl IntoIterator, E>>, ) -> Result { data.into_iter().collect::, _>>() } fn canonical_var_kinds_data<'a>( &self, canonical_var_kinds: &'a Self::InternedCanonicalVarKinds, ) -> &'a [chalk_ir::ParameterKind] { canonical_var_kinds } } impl<'tcx> chalk_ir::interner::HasInterner for RustInterner<'tcx> { type Interner = Self; } #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, HashStable, TypeFoldable)] pub enum ChalkEnvironmentClause<'tcx> { /// A normal rust `ty::Predicate` in the environment. Predicate(ty::Predicate<'tcx>), /// A special clause in the environment that gets lowered to /// `chalk_ir::FromEnv::Ty`. TypeFromEnv(Ty<'tcx>), } impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::List> { fn super_fold_with>(&self, folder: &mut F) -> Self { let v = self.iter().map(|t| t.fold_with(folder)).collect::>(); folder.tcx().intern_chalk_environment_clause_list(&v) } fn super_visit_with>(&self, visitor: &mut V) -> bool { self.iter().any(|t| t.visit_with(visitor)) } } /// We have to elaborate the environment of a chalk goal *before* /// canonicalization. This type wraps the predicate and the elaborated /// environment. #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, HashStable, TypeFoldable)] pub struct ChalkEnvironmentAndGoal<'tcx> { pub environment: &'tcx ty::List>, pub goal: ty::Predicate<'tcx>, } impl<'tcx> fmt::Display for ChalkEnvironmentAndGoal<'tcx> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "environment: {:?}, goal: {}", self.environment, self.goal) } }