diff --git a/chalk-integration/src/lowering.rs b/chalk-integration/src/lowering.rs index f274997e219..1c0e457025b 100644 --- a/chalk-integration/src/lowering.rs +++ b/chalk-integration/src/lowering.rs @@ -1,7 +1,8 @@ use chalk_ir::cast::{Cast, Caster}; use chalk_ir::interner::ChalkIr; use chalk_ir::{ - self, AssocTypeId, BoundVar, DebruijnIndex, ImplId, StructId, Substitution, TraitId, + self, AssocTypeId, BoundVar, DebruijnIndex, ImplId, QuantifiedWhereClauses, StructId, + Substitution, TraitId, }; use chalk_parse::ast::*; use chalk_rust_ir as rust_ir; @@ -1000,10 +1001,9 @@ impl LowerTy for Ty { // FIXME: Figure out a proper name for this type parameter Some(chalk_ir::ParameterKind::Ty(intern(FIXME_SELF))), |env| { - Ok(bounds - .lower(env)? - .iter() - .flat_map(|qil| { + Ok(QuantifiedWhereClauses::from( + interner, + bounds.lower(env)?.iter().flat_map(|qil| { qil.into_where_clauses( interner, chalk_ir::TyData::BoundVar(BoundVar::new( @@ -1012,8 +1012,8 @@ impl LowerTy for Ty { )) .intern(interner), ) - }) - .collect()) + }), + )) }, )?, }) diff --git a/chalk-integration/src/program.rs b/chalk-integration/src/program.rs index e1ef452c637..e97ab5f93f7 100644 --- a/chalk-integration/src/program.rs +++ b/chalk-integration/src/program.rs @@ -217,6 +217,15 @@ impl tls::DebugContext for Program { let interner = self.interner(); write!(fmt, "{:?}", separator_trait_ref.debug(interner)) } + + fn debug_quantified_where_clauses( + &self, + clauses: &chalk_ir::QuantifiedWhereClauses, + fmt: &mut fmt::Formatter<'_>, + ) -> Result<(), fmt::Error> { + let interner = self.interner(); + write!(fmt, "{:?}", clauses.as_slice(interner)) + } } impl RustIrDatabase for Program { diff --git a/chalk-ir/src/cast.rs b/chalk-ir/src/cast.rs index f9ca2f1e9fc..3f637378ae1 100644 --- a/chalk-ir/src/cast.rs +++ b/chalk-ir/src/cast.rs @@ -81,6 +81,7 @@ reflexive_impl!(for(I: Interner) DomainGoal); reflexive_impl!(for(I: Interner) Goal); reflexive_impl!(for(I: Interner) WhereClause); reflexive_impl!(for(I: Interner) ProgramClause); +reflexive_impl!(for(I: Interner) QuantifiedWhereClause); impl CastTo> for TraitRef { fn cast_to(self, _interner: &I) -> WhereClause { diff --git a/chalk-ir/src/debug.rs b/chalk-ir/src/debug.rs index c2e81b7f78a..482d1b1e66d 100644 --- a/chalk-ir/src/debug.rs +++ b/chalk-ir/src/debug.rs @@ -89,6 +89,13 @@ impl Debug for AliasTy { } } +impl Debug for QuantifiedWhereClauses { + fn fmt(&self, fmt: &mut Formatter<'_>) -> Result<(), Error> { + I::debug_quantified_where_clauses(self, fmt) + .unwrap_or_else(|| write!(fmt, "{:?}", self.interned)) + } +} + impl Display for Substitution { fn fmt(&self, fmt: &mut Formatter<'_>) -> Result<(), Error> { I::debug_substitution(self, fmt).unwrap_or_else(|| write!(fmt, "{:?}", self.parameters)) diff --git a/chalk-ir/src/fold/boring_impls.rs b/chalk-ir/src/fold/boring_impls.rs index 40485b7ca08..9e5d114af0e 100644 --- a/chalk-ir/src/fold/boring_impls.rs +++ b/chalk-ir/src/fold/boring_impls.rs @@ -192,6 +192,29 @@ impl> Fold for ProgramClauses { } } +impl> Fold for QuantifiedWhereClauses { + type Result = QuantifiedWhereClauses; + fn fold_with<'i>( + &self, + folder: &mut dyn Folder<'i, I, TI>, + outer_binder: DebruijnIndex, + ) -> Fallible + where + I: 'i, + TI: 'i, + { + let interner = folder.interner(); + let target_interner = folder.target_interner(); + let folded = self + .iter(interner) + .map(|p| p.fold_with(folder, outer_binder)); + Ok(QuantifiedWhereClauses::from_fallible( + target_interner, + folded, + )?) + } +} + #[macro_export] macro_rules! copy_fold { ($t:ty) => { diff --git a/chalk-ir/src/interner.rs b/chalk-ir/src/interner.rs index bacccd2105b..305f6991f66 100644 --- a/chalk-ir/src/interner.rs +++ b/chalk-ir/src/interner.rs @@ -12,6 +12,8 @@ use crate::ProgramClause; use crate::ProgramClauseData; use crate::ProgramClauseImplication; use crate::ProgramClauses; +use crate::QuantifiedWhereClause; +use crate::QuantifiedWhereClauses; use crate::SeparatorTraitRef; use crate::StructId; use crate::Substitution; @@ -113,6 +115,14 @@ pub trait Interner: Debug + Copy + Eq + Ord + Hash { /// converted back to its underlying data via `program_clause_data`. type InternedProgramClause: Debug + Clone + Eq + Hash; + /// "Interned" representation of a list of quantified where clauses. + /// In normal user code, `Self::InternedQuantifiedWhereClauses` is not referenced. + /// Instead, we refer to `QuantifiedWhereClauses`, which wraps this type. + /// + /// An `InternedQuantifiedWhereClauses` is created by `intern_quantified_where_clauses` + /// and can be converted back to its underlying data via `quantified_where_clauses_data`. + type InternedQuantifiedWhereClauses: Debug + Clone + Eq + Hash; + /// The core "id" type used for struct-ids and the like. type DefId: Debug + Copy + Eq + Ord + Hash; @@ -328,6 +338,21 @@ pub trait Interner: Debug + Copy + Eq + Ord + Hash { None } + /// Prints the debug representation of a QuantifiedWhereClauses. To get good + /// results, this requires inspecting TLS, and is difficult to + /// code without reference to a specific interner (and hence + /// fully known types). + /// + /// Returns `None` to fallback to the default debug output (e.g., + /// if no info about current program is available from TLS). + #[allow(unused_variables)] + fn debug_quantified_where_clauses( + clauses: &QuantifiedWhereClauses, + fmt: &mut fmt::Formatter<'_>, + ) -> Option { + None + } + /// Create an "interned" type from `ty`. This is not normally /// invoked directly; instead, you invoke `TyData::intern` (which /// will ultimately call this method). @@ -413,6 +438,22 @@ pub trait Interner: Debug + Copy + Eq + Ord + Hash { &self, clauses: &'a Self::InternedProgramClauses, ) -> &'a [ProgramClause]; + + /// Create an "interned" quantified where clauses from `data`. This is not + /// normally invoked directly; instead, you invoke + /// `QuantifiedWhereClauses::from` (which will ultimately call this + /// method). + fn intern_quantified_where_clauses( + &self, + data: impl IntoIterator>, + ) -> Self::InternedQuantifiedWhereClauses; + + /// Lookup the slice of `QuantifiedWhereClause` that was interned to + /// create a `QuantifiedWhereClauses`. + fn quantified_where_clauses_data<'a>( + &self, + clauses: &'a Self::InternedQuantifiedWhereClauses, + ) -> &'a [QuantifiedWhereClause]; } pub trait TargetInterner: Interner { @@ -469,6 +510,7 @@ mod default { type InternedSubstitution = Vec>; type InternedProgramClause = ProgramClauseData; type InternedProgramClauses = Vec>; + type InternedQuantifiedWhereClauses = Vec>; type DefId = RawId; type Identifier = Identifier; @@ -574,6 +616,15 @@ mod default { }) } + fn debug_quantified_where_clauses( + clauses: &QuantifiedWhereClauses, + fmt: &mut fmt::Formatter<'_>, + ) -> Option { + tls::with_current_program(|prog| { + Some(prog?.debug_quantified_where_clauses(clauses, fmt)) + }) + } + fn intern_ty(&self, ty: TyData) -> Arc> { Arc::new(ty) } @@ -661,6 +712,20 @@ mod default { ) -> &'a [ProgramClause] { clauses } + + fn intern_quantified_where_clauses( + &self, + data: impl IntoIterator>, + ) -> Self::InternedQuantifiedWhereClauses { + data.into_iter().collect() + } + + fn quantified_where_clauses_data<'a>( + &self, + clauses: &'a Self::InternedQuantifiedWhereClauses, + ) -> &'a [QuantifiedWhereClause] { + clauses + } } impl HasInterner for ChalkIr { diff --git a/chalk-ir/src/lib.rs b/chalk-ir/src/lib.rs index 27b5162f0ba..32751776d34 100644 --- a/chalk-ir/src/lib.rs +++ b/chalk-ir/src/lib.rs @@ -543,7 +543,7 @@ impl DebruijnIndex { /// level of binder). #[derive(Clone, PartialEq, Eq, Hash, Fold)] pub struct DynTy { - pub bounds: Binders>>, + pub bounds: Binders>, } #[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] @@ -1033,6 +1033,62 @@ impl QuantifiedWhereClause { } } +#[derive(Clone, PartialEq, Eq, Hash, PartialOrd, Ord, HasInterner)] +pub struct QuantifiedWhereClauses { + interned: I::InternedQuantifiedWhereClauses, +} + +impl QuantifiedWhereClauses { + pub fn new(interner: &I) -> Self { + Self::from(interner, None::>) + } + + pub fn interned(&self) -> &I::InternedQuantifiedWhereClauses { + &self.interned + } + + pub fn from( + interner: &I, + clauses: impl IntoIterator>>, + ) -> Self { + use crate::cast::Caster; + QuantifiedWhereClauses { + interned: I::intern_quantified_where_clauses( + interner, + clauses.into_iter().casted(interner), + ), + } + } + + pub fn from_fallible( + interner: &I, + clauses: impl IntoIterator>, E>>, + ) -> Result { + use crate::cast::Caster; + let clauses = clauses + .into_iter() + .casted(interner) + .collect::>, _>>()?; + Ok(Self::from(interner, clauses)) + } + + pub fn iter(&self, interner: &I) -> std::slice::Iter<'_, QuantifiedWhereClause> { + self.as_slice(interner).iter() + } + + pub fn is_empty(&self, interner: &I) -> bool { + self.as_slice(interner).is_empty() + } + + pub fn len(&self, interner: &I) -> usize { + self.as_slice(interner).len() + } + + pub fn as_slice(&self, interner: &I) -> &[QuantifiedWhereClause] { + interner.quantified_where_clauses_data(&self.interned) + } +} + impl DomainGoal { /// Convert `Implemented(...)` into `FromEnv(...)`, but leave other /// goals unchanged. diff --git a/chalk-ir/src/tls.rs b/chalk-ir/src/tls.rs index 69be655a9f0..7344e8b8261 100644 --- a/chalk-ir/src/tls.rs +++ b/chalk-ir/src/tls.rs @@ -1,8 +1,8 @@ use crate::interner::ChalkIr; use crate::{ debug::SeparatorTraitRef, AliasTy, ApplicationTy, AssocTypeId, Goal, Goals, Lifetime, - Parameter, ProgramClause, ProgramClauseImplication, ProgramClauses, StructId, Substitution, - TraitId, Ty, + Parameter, ProgramClause, ProgramClauseImplication, ProgramClauses, QuantifiedWhereClauses, + StructId, Substitution, TraitId, Ty, }; use std::cell::RefCell; use std::fmt; @@ -98,6 +98,12 @@ pub trait DebugContext { separator_trait_ref: &SeparatorTraitRef<'_, ChalkIr>, fmt: &mut fmt::Formatter<'_>, ) -> Result<(), fmt::Error>; + + fn debug_quantified_where_clauses( + &self, + clauses: &QuantifiedWhereClauses, + fmt: &mut fmt::Formatter<'_>, + ) -> Result<(), fmt::Error>; } pub fn with_current_program(op: impl FnOnce(Option<&Arc>) -> R) -> R { diff --git a/chalk-ir/src/zip.rs b/chalk-ir/src/zip.rs index 5aef08a92c1..5159ddc078c 100644 --- a/chalk-ir/src/zip.rs +++ b/chalk-ir/src/zip.rs @@ -283,6 +283,17 @@ impl Zip for ProgramClauses { } } +impl Zip for QuantifiedWhereClauses { + fn zip_with<'i, Z: Zipper<'i, I>>(zipper: &mut Z, a: &Self, b: &Self) -> Fallible<()> + where + I: 'i, + { + let interner = zipper.interner(); + Zip::zip_with(zipper, a.as_slice(interner), b.as_slice(interner))?; + Ok(()) + } +} + /// Generates a Zip impl that requires the two enums be the same /// variant, then zips each field of the variant in turn. Only works /// if all variants have a single parenthesized value right now. diff --git a/chalk-solve/src/clauses.rs b/chalk-solve/src/clauses.rs index abc70ae9b29..21c10595aaf 100644 --- a/chalk-solve/src/clauses.rs +++ b/chalk-solve/src/clauses.rs @@ -222,7 +222,7 @@ fn program_clauses_that_could_match( // and `bounded_ty` is the `exists { .. }` // clauses shown above. - for exists_qwc in &dyn_ty.bounds { + for exists_qwc in dyn_ty.bounds.map_ref(|r| r.iter(interner)) { // Replace the `T` from `exists { .. }` with `self_ty`, // yielding clases like // diff --git a/chalk-solve/src/wf.rs b/chalk-solve/src/wf.rs index c3a5f62337b..413ecf57807 100644 --- a/chalk-solve/src/wf.rs +++ b/chalk-solve/src/wf.rs @@ -78,6 +78,12 @@ impl FoldInputTypes for Substitution { } } +impl FoldInputTypes for QuantifiedWhereClauses { + fn fold(&self, interner: &I, accumulator: &mut Vec>) { + self.as_slice(interner).fold(interner, accumulator) + } +} + impl FoldInputTypes for Ty { fn fold(&self, interner: &I, accumulator: &mut Vec>) { match self.data(interner) {