diff --git a/chalk-integration/src/lowering.rs b/chalk-integration/src/lowering.rs index 885c215de92..3592fe43232 100644 --- a/chalk-integration/src/lowering.rs +++ b/chalk-integration/src/lowering.rs @@ -904,7 +904,7 @@ impl LowerProjectionTy for ProjectionTy { } = *self; let chalk_ir::TraitRef { trait_id, - parameters: trait_parameters, + substitution: trait_substitution, } = trait_ref.lower(env)?; let lookup = match env.associated_ty_lookups.get(&(trait_id.into(), name.str)) { Some(lookup) => lookup, @@ -933,11 +933,11 @@ impl LowerProjectionTy for ProjectionTy { } } - args.extend(trait_parameters); + args.extend(trait_substitution.iter().cloned()); Ok(chalk_ir::ProjectionTy { associated_ty_id: lookup.id, - parameters: args, + substitution: chalk_ir::Substitution::from(args), }) } } @@ -961,7 +961,7 @@ impl LowerTy for Ty { } else { Ok(chalk_ir::TyData::Apply(chalk_ir::ApplicationTy { name: chalk_ir::TypeName::Struct(id), - parameters: vec![], + substitution: chalk_ir::Substitution::empty(), }) .intern()) } @@ -1001,10 +1001,8 @@ impl LowerTy for Ty { })?; } - let parameters = args - .iter() - .map(|t| Ok(t.lower(env)?)) - .collect::>>()?; + let substitution = + chalk_ir::Substitution::from_fallible(args.iter().map(|t| Ok(t.lower(env)?)))?; for (param, arg) in k.binders.binders.iter().zip(args.iter()) { if param.kind() != arg.kind() { @@ -1018,7 +1016,7 @@ impl LowerTy for Ty { Ok(chalk_ir::TyData::Apply(chalk_ir::ApplicationTy { name: chalk_ir::TypeName::Struct(id), - parameters: parameters, + substitution: substitution, }) .intern()) } diff --git a/chalk-integration/src/program.rs b/chalk-integration/src/program.rs index 6680870f119..0a1970f249f 100644 --- a/chalk-integration/src/program.rs +++ b/chalk-integration/src/program.rs @@ -163,8 +163,11 @@ impl RustIrDatabase for Program { .filter(|(_, impl_datum)| { let trait_ref = &impl_datum.binders.value.trait_ref; trait_id == trait_ref.trait_id && { - assert_eq!(trait_ref.parameters.len(), parameters.len()); - <[_] as CouldMatch<[_]>>::could_match(¶meters, &trait_ref.parameters) + assert_eq!(trait_ref.substitution.len(), parameters.len()); + <[_] as CouldMatch<[_]>>::could_match( + ¶meters, + &trait_ref.substitution.parameters(), + ) } }) .map(|(&impl_id, _)| impl_id) @@ -191,7 +194,7 @@ impl RustIrDatabase for Program { self.impl_data.values().any(|impl_datum| { let impl_trait_ref = &impl_datum.binders.value.trait_ref; impl_trait_ref.trait_id == auto_trait_id - && match impl_trait_ref.parameters[0].assert_ty_ref().data() { + && match impl_trait_ref.self_type_parameter().data() { TyData::Apply(apply) => match apply.name { TypeName::Struct(id) => id == struct_id, _ => false, diff --git a/chalk-ir/src/cast.rs b/chalk-ir/src/cast.rs index 10734ab6c1b..3cce691392d 100644 --- a/chalk-ir/src/cast.rs +++ b/chalk-ir/src/cast.rs @@ -169,6 +169,12 @@ impl CastTo> for Lifetime { } } +impl CastTo> for Parameter { + fn cast_to(self) -> Parameter { + self + } +} + impl CastTo> for T where T: CastTo>, diff --git a/chalk-ir/src/could_match.rs b/chalk-ir/src/could_match.rs index dc21b34ee4b..ed366b7ef4a 100644 --- a/chalk-ir/src/could_match.rs +++ b/chalk-ir/src/could_match.rs @@ -24,10 +24,10 @@ where let names_could_match = a.name == b.name; names_could_match - && a.parameters + && a.substitution .iter() - .zip(&b.parameters) - .all(|(p_a, p_b)| p_a.could_match(p_b)) + .zip(&b.substitution) + .all(|(p_a, p_b)| p_a.could_match(&p_b)) } _ => true, diff --git a/chalk-ir/src/debug.rs b/chalk-ir/src/debug.rs index 6465bc1f715..309926c96fd 100644 --- a/chalk-ir/src/debug.rs +++ b/chalk-ir/src/debug.rs @@ -115,7 +115,8 @@ impl Debug for PlaceholderIndex { impl Debug for ApplicationTy { fn fmt(&self, fmt: &mut Formatter) -> Result<(), Error> { - write!(fmt, "{:?}{:?}", self.name, Angle(&self.parameters)) + let ApplicationTy { name, substitution } = self; + write!(fmt, "{:?}{:?}", name, substitution.with_angle()) } } @@ -150,13 +151,14 @@ struct SeparatorTraitRef<'me, TF: TypeFamily> { impl Debug for SeparatorTraitRef<'_, TF> { fn fmt(&self, fmt: &mut Formatter) -> Result<(), Error> { + let parameters = self.trait_ref.substitution.parameters(); write!( fmt, "{:?}{}{:?}{:?}", - self.trait_ref.parameters[0], + parameters[0], self.separator, self.trait_ref.trait_id, - Angle(&self.trait_ref.parameters[1..]) + Angle(¶meters[1..]) ) } } @@ -168,7 +170,7 @@ impl Debug for ProjectionTy { fmt, "({:?}){:?}", self.associated_ty_id, - Angle(&self.parameters) + self.substitution.with_angle() ) }) } @@ -242,13 +244,9 @@ impl Debug for DomainGoal { DomainGoal::IsLocal(n) => write!(fmt, "IsLocal({:?})", n), DomainGoal::IsUpstream(n) => write!(fmt, "IsUpstream({:?})", n), DomainGoal::IsFullyVisible(n) => write!(fmt, "IsFullyVisible({:?})", n), - DomainGoal::LocalImplAllowed(tr) => write!( - fmt, - "LocalImplAllowed({:?}: {:?}{:?})", - tr.parameters[0], - tr.trait_id, - Angle(&tr.parameters[1..]) - ), + DomainGoal::LocalImplAllowed(tr) => { + write!(fmt, "LocalImplAllowed({:?})", tr.with_colon(),) + } DomainGoal::Compatible(_) => write!(fmt, "Compatible"), DomainGoal::DownstreamType(n) => write!(fmt, "DownstreamType({:?})", n), } @@ -413,9 +411,17 @@ impl Display for ConstrainedSubst { } } +impl Substitution { + /// Displays the substitution in the form `< P0, .. Pn >`, or (if + /// the substitution is empty) as an empty string. + pub fn with_angle(&self) -> Angle<'_, Parameter> { + Angle(self.parameters()) + } +} + impl Debug for Substitution { - fn fmt(&self, f: &mut Formatter) -> Result<(), Error> { - Display::fmt(self, f) + fn fmt(&self, fmt: &mut Formatter) -> Result<(), Error> { + Display::fmt(self, fmt) } } @@ -425,7 +431,7 @@ impl Display for Substitution { write!(f, "[")?; - for (index, value) in self.parameters.iter().enumerate() { + for (index, value) in self.iter().enumerate() { if first { first = false; } else { diff --git a/chalk-ir/src/family.rs b/chalk-ir/src/family.rs index 63262a8c482..cd2ae9191e6 100644 --- a/chalk-ir/src/family.rs +++ b/chalk-ir/src/family.rs @@ -2,6 +2,7 @@ use crate::tls; use crate::AssocTypeId; use crate::GoalData; use crate::LifetimeData; +use crate::Parameter; use crate::ParameterData; use crate::ProjectionTy; use crate::RawId; @@ -68,6 +69,14 @@ pub trait TypeFamily: Debug + Copy + Eq + Ord + Hash { /// converted back to its underlying data via `goal_data`. type InternedGoal: Debug + Clone + Eq + Ord + Hash; + /// "Interned" representation of a "substitution". In normal user code, + /// `Self::InternedSubstitution` is not referenced. Instead, we refer to + /// `Substitution`, which wraps this type. + /// + /// An `InternedSubstitution` is created by `intern_substitution` and can be + /// converted back to its underlying data via `substitution_data`. + type InternedSubstitution: Debug + Clone + Eq + Ord + Hash; + /// The core "id" type used for struct-ids and the like. type DefId: Debug + Copy + Eq + Ord + Hash; @@ -147,7 +156,18 @@ pub trait TypeFamily: Debug + Copy + Eq + Ord + Hash { fn intern_goal(data: GoalData) -> Self::InternedGoal; /// Lookup the `GoalData` that was interned to create a `InternedGoal`. - fn goal_data(lifetime: &Self::InternedGoal) -> &GoalData; + fn goal_data(goal: &Self::InternedGoal) -> &GoalData; + + /// Create an "interned" substitution from `data`. This is not + /// normally invoked directly; instead, you invoke + /// `SubstitutionData::intern` (which will ultimately call this + /// method). + fn intern_substitution( + data: impl IntoIterator, E>>, + ) -> Result; + + /// Lookup the `SubstitutionData` that was interned to create a `InternedSubstitution`. + fn substitution_data(substitution: &Self::InternedSubstitution) -> &[Parameter]; } pub trait TargetTypeFamily: TypeFamily { @@ -181,6 +201,7 @@ impl TypeFamily for ChalkIr { type InternedLifetime = LifetimeData; type InternedParameter = ParameterData; type InternedGoal = Arc>; + type InternedSubstitution = Vec>; type DefId = RawId; fn debug_struct_id( @@ -242,6 +263,16 @@ impl TypeFamily for ChalkIr { fn goal_data(goal: &Arc>) -> &GoalData { goal } + + fn intern_substitution( + data: impl IntoIterator, E>>, + ) -> Result>, E> { + data.into_iter().collect() + } + + fn substitution_data(substitution: &Vec>) -> &[Parameter] { + substitution + } } impl HasTypeFamily for ChalkIr { diff --git a/chalk-ir/src/fold/boring_impls.rs b/chalk-ir/src/fold/boring_impls.rs index 1d5014069b7..43c5c30280a 100644 --- a/chalk-ir/src/fold/boring_impls.rs +++ b/chalk-ir/src/fold/boring_impls.rs @@ -86,6 +86,7 @@ impl, TF: TypeFamily, TTF: TargetTypeFamily> Fold } } } + impl> Fold for Parameter { type Result = Parameter; fn fold_with( @@ -110,6 +111,19 @@ impl> Fold for Goal { } } +impl> Fold for Substitution { + type Result = Substitution; + fn fold_with( + &self, + folder: &mut dyn Folder, + binders: usize, + ) -> Fallible { + Ok(Substitution::from_fallible( + self.iter().map(|p| p.fold_with(folder, binders)), + )?) + } +} + #[macro_export] macro_rules! copy_fold { ($t:ty) => { diff --git a/chalk-ir/src/lib.rs b/chalk-ir/src/lib.rs index 36fb938986c..d96d1d7cd5f 100644 --- a/chalk-ir/src/lib.rs +++ b/chalk-ir/src/lib.rs @@ -428,7 +428,7 @@ impl PlaceholderIndex { #[derive(Clone, PartialEq, Eq, Hash, PartialOrd, Fold, Ord, HasTypeFamily)] pub struct ApplicationTy { pub name: TypeName, - pub parameters: Vec>, + pub substitution: Substitution, } impl ApplicationTy { @@ -437,7 +437,7 @@ impl ApplicationTy { } pub fn type_parameters<'a>(&'a self) -> impl Iterator> + 'a { - self.parameters.iter().filter_map(|p| p.ty()).cloned() + self.substitution.iter().filter_map(|p| p.ty()).cloned() } pub fn first_type_parameter(&self) -> Option> { @@ -574,7 +574,7 @@ impl ParameterData { #[derive(Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Fold, HasTypeFamily)] pub struct ProjectionTy { pub associated_ty_id: AssocTypeId, - pub parameters: Vec>, + pub substitution: Substitution, } impl ProjectionTy { @@ -586,16 +586,16 @@ impl ProjectionTy { #[derive(Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Fold, HasTypeFamily)] pub struct TraitRef { pub trait_id: TraitId, - pub parameters: Vec>, + pub substitution: Substitution, } impl TraitRef { pub fn type_parameters<'a>(&'a self) -> impl Iterator> + 'a { - self.parameters.iter().filter_map(|p| p.ty()).cloned() + self.substitution.iter().filter_map(|p| p.ty()).cloned() } - pub fn self_type_parameter(&self) -> Option> { - self.type_parameters().next() + pub fn self_type_parameter(&self) -> Ty { + self.type_parameters().next().unwrap() } pub fn from_env(self) -> FromEnv { @@ -897,7 +897,8 @@ where /// binders. So if the binders represent (e.g.) ` { T }` and /// parameters is the slice `[A, B]`, then returns `[X => A, Y => /// B] T`. - pub fn substitute(&self, parameters: &[Parameter]) -> T::Result { + pub fn substitute(&self, parameters: &(impl AsParameters + ?Sized)) -> T::Result { + let parameters = parameters.as_parameters(); assert_eq!(self.binders.len(), parameters.len()); Subst::apply(parameters, &self.value) } @@ -1009,7 +1010,7 @@ impl UCanonical { canonical_subst: &Canonical>, ) -> bool { let subst = &canonical_subst.value.subst; - assert_eq!(self.canonical.binders.len(), subst.parameters.len()); + assert_eq!(self.canonical.binders.len(), subst.parameters().len()); subst.is_identity_subst() } } @@ -1175,17 +1176,60 @@ pub enum Constraint { } /// A mapping of inference variables to instantiations thereof. -#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Fold, Hash, HasTypeFamily)] +#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, HasTypeFamily)] pub struct Substitution { /// Map free variable with given index to the value with the same /// index. Naturally, the kind of the variable must agree with /// the kind of the value. - pub parameters: Vec>, + parameters: TF::InternedSubstitution, } impl Substitution { + pub fn from(parameters: impl IntoIterator>>) -> Self { + Self::from_fallible( + parameters + .into_iter() + .map(|p| -> Result, ()> { Ok(p.cast()) }), + ) + .unwrap() + } + + pub fn from_fallible( + parameters: impl IntoIterator>, E>>, + ) -> Result { + use crate::cast::Caster; + Ok(Substitution { + parameters: TF::intern_substitution(parameters.into_iter().casted())?, + }) + } + + /// Index into the list of parameters + pub fn at(&self, index: usize) -> &Parameter { + &self.parameters()[index] + } + + pub fn from1(parameter: impl CastTo>) -> Self { + Self::from(Some(parameter)) + } + + pub fn empty() -> Self { + Self::from(None::>) + } + pub fn is_empty(&self) -> bool { - self.parameters.is_empty() + self.parameters().is_empty() + } + + pub fn iter(&self) -> std::slice::Iter<'_, Parameter> { + self.parameters().iter() + } + + pub fn parameters(&self) -> &[Parameter] { + TF::substitution_data(&self.parameters) + } + + pub fn len(&self) -> usize { + self.parameters().len() } /// A substitution is an **identity substitution** if it looks @@ -1201,8 +1245,7 @@ impl Substitution { /// Basically, each value is mapped to a type or lifetime with its /// same index. pub fn is_identity_subst(&self) -> bool { - self.parameters - .iter() + self.iter() .zip(0..) .all(|(parameter, index)| match parameter.data() { ParameterKind::Ty(ty) => match ty.data() { @@ -1217,19 +1260,68 @@ impl Substitution { } } +pub trait AsParameters { + fn as_parameters(&self) -> &[Parameter]; +} + +impl AsParameters for Substitution { + fn as_parameters(&self) -> &[Parameter] { + self.parameters() + } +} + +impl AsParameters for [Parameter] { + fn as_parameters(&self) -> &[Parameter] { + self + } +} + +impl AsParameters for [Parameter; 1] { + fn as_parameters(&self) -> &[Parameter] { + self + } +} + +impl AsParameters for Vec> { + fn as_parameters(&self) -> &[Parameter] { + self + } +} + +impl AsParameters for &T +where + T: ?Sized + AsParameters, +{ + fn as_parameters(&self) -> &[Parameter] { + T::as_parameters(self) + } +} + +impl<'me, TF> std::iter::IntoIterator for &'me Substitution +where + TF: TypeFamily, +{ + type IntoIter = std::slice::Iter<'me, Parameter>; + type Item = &'me Parameter; + + fn into_iter(self) -> Self::IntoIter { + self.iter() + } +} + impl<'a, TF: TypeFamily> DefaultTypeFolder for &'a Substitution {} impl<'a, TF: TypeFamily> DefaultInferenceFolder for &'a Substitution {} impl<'a, TF: TypeFamily> FreeVarFolder for &'a Substitution { fn fold_free_var_ty(&mut self, depth: usize, binders: usize) -> Fallible> { - let ty = &self.parameters[depth]; + let ty = self.at(depth); let ty = ty.assert_ty_ref(); Ok(ty.shifted_in(binders)) } fn fold_free_var_lifetime(&mut self, depth: usize, binders: usize) -> Fallible> { - let l = &self.parameters[depth]; + let l = self.at(depth); let l = l.assert_lifetime_ref(); Ok(l.shifted_in(binders)) } diff --git a/chalk-ir/src/macros.rs b/chalk-ir/src/macros.rs index 9fb0d38d9d3..05005d70e68 100644 --- a/chalk-ir/src/macros.rs +++ b/chalk-ir/src/macros.rs @@ -5,7 +5,7 @@ macro_rules! ty { (apply $n:tt $($arg:tt)*) => { $crate::TyData::Apply(ApplicationTy { name: ty_name!($n), - parameters: vec![$(arg!($arg)),*], + substitution: $crate::Substitution::from(vec![$(arg!($arg)),*] as Vec<$crate::Parameter<_>>), }).intern() }; @@ -26,7 +26,7 @@ macro_rules! ty { (projection (item $n:tt) $($arg:tt)*) => { $crate::TyData::Projection(ProjectionTy { associated_ty_id: AssocTypeId(RawId { index: $n }), - parameters: vec![$(arg!($arg)),*], + substitution: $crate::Substitution::from(vec![$(arg!($arg)),*] as Vec<$crate::Parameter<_>>), }).intern() }; diff --git a/chalk-ir/src/zip.rs b/chalk-ir/src/zip.rs index 54b21b0aa8f..1524e93305e 100644 --- a/chalk-ir/src/zip.rs +++ b/chalk-ir/src/zip.rs @@ -181,7 +181,7 @@ macro_rules! struct_zip { struct_zip!(impl[TF: TypeFamily] Zip for TraitRef { trait_id, - parameters, + substitution, }); struct_zip!(impl[ T: HasTypeFamily + Zip, @@ -190,11 +190,11 @@ struct_zip!(impl[ environment, goal, }); -struct_zip!(impl[TF: TypeFamily] Zip for ApplicationTy { name, parameters }); +struct_zip!(impl[TF: TypeFamily] Zip for ApplicationTy { name, substitution }); struct_zip!(impl[TF: TypeFamily] Zip for DynTy { bounds }); struct_zip!(impl[TF: TypeFamily] Zip for ProjectionTy { associated_ty_id, - parameters, + substitution, }); struct_zip!(impl[TF: TypeFamily] Zip for Normalize { projection, ty }); struct_zip!(impl[TF: TypeFamily] Zip for ProjectionEq { projection, ty }); @@ -253,6 +253,12 @@ enum_zip!(impl for DomainGoal { }); enum_zip!(impl for ProgramClause { Implies, ForAll }); +impl Zip for Substitution { + fn zip_with>(zipper: &mut Z, a: &Self, b: &Self) -> Fallible<()> { + Zip::zip_with(zipper, a.parameters(), b.parameters()) + } +} + // Annoyingly, Goal cannot use `enum_zip` because some variants have // two parameters, and I'm too lazy to make the macro account for the // relevant name mangling. diff --git a/chalk-rust-ir/src/lib.rs b/chalk-rust-ir/src/lib.rs index c9211c7df6b..d0b9c9a2f4d 100644 --- a/chalk-rust-ir/src/lib.rs +++ b/chalk-rust-ir/src/lib.rs @@ -8,8 +8,8 @@ use chalk_ir::family::{HasTypeFamily, TargetTypeFamily, TypeFamily}; use chalk_ir::fold::{shift::Shift, Fold, Folder}; use chalk_ir::{ AssocTypeId, Binders, Identifier, ImplId, LifetimeData, Parameter, ParameterKind, ProjectionEq, - ProjectionTy, QuantifiedWhereClause, RawId, StructId, TraitId, TraitRef, Ty, TyData, TypeName, - WhereClause, + ProjectionTy, QuantifiedWhereClause, RawId, StructId, Substitution, TraitId, TraitRef, Ty, + TyData, TypeName, WhereClause, }; use std::iter; @@ -201,9 +201,9 @@ impl TraitBound { pub fn as_trait_ref(&self, self_ty: Ty) -> TraitRef { TraitRef { trait_id: self.trait_id, - parameters: iter::once(self_ty.cast()) - .chain(self.args_no_self.iter().cloned()) - .collect(), + substitution: Substitution::from( + iter::once(self_ty.cast()).chain(self.args_no_self.iter().cloned()), + ), } } } @@ -223,15 +223,19 @@ impl ProjectionEqBound { fn into_where_clauses(&self, self_ty: Ty) -> Vec> { let trait_ref = self.trait_bound.as_trait_ref(self_ty); - let mut parameters = self.parameters.clone(); - parameters.extend(trait_ref.parameters.clone()); + let substitution = Substitution::from( + self.parameters + .iter() + .cloned() + .chain(trait_ref.substitution.iter().cloned()), + ); vec![ WhereClause::Implemented(trait_ref), WhereClause::ProjectionEq(ProjectionEq { projection: ProjectionTy { associated_ty_id: self.associated_ty_id, - parameters: parameters, + substitution, }, ty: self.value.clone(), }), @@ -335,12 +339,12 @@ impl AssociatedTyDatum { // Create a list `P0...Pn` of references to the binders in // scope for this associated type: - let parameters = binders.iter().zip(0..).map(|p| p.to_parameter()).collect(); + let substitution = Substitution::from(binders.iter().zip(0..).map(|p| p.to_parameter())); // The self type will be `>::Item` etc let self_ty = TyData::Projection(ProjectionTy { associated_ty_id: self.id, - parameters, + substitution, }) .intern(); diff --git a/chalk-solve/src/clauses.rs b/chalk-solve/src/clauses.rs index 57357aa4045..0bea7e7bea2 100644 --- a/chalk-solve/src/clauses.rs +++ b/chalk-solve/src/clauses.rs @@ -74,14 +74,14 @@ pub fn push_auto_trait_impls( builder.push_binders(&binders, |builder, fields| { let self_ty: Ty<_> = ApplicationTy { name: struct_id.cast(), - parameters: builder.placeholders_in_scope().to_vec(), + substitution: builder.substitution_in_scope(), } .intern(); // trait_ref = `MyStruct<...>: MyAutoTrait` let auto_trait_ref = TraitRef { trait_id: auto_trait_id, - parameters: vec![self_ty.cast()], + substitution: Substitution::from1(self_ty), }; // forall { // generic parameters from struct @@ -94,7 +94,7 @@ pub fn push_auto_trait_impls( auto_trait_ref, fields.iter().map(|field_ty| TraitRef { trait_id: auto_trait_id, - parameters: vec![field_ty.clone().cast()], + substitution: Substitution::from1(field_ty.clone()), }), ); }); @@ -147,7 +147,9 @@ fn program_clauses_that_could_match( // as for the `Implemented(Foo) :- FromEnv(Foo)` rule. db.trait_datum(trait_id).to_program_clauses(builder); - for impl_id in db.impls_for_trait(trait_ref.trait_id, &trait_ref.parameters) { + for impl_id in + db.impls_for_trait(trait_ref.trait_id, trait_ref.substitution.parameters()) + { db.impl_datum(impl_id).to_program_clauses(builder); } @@ -155,7 +157,7 @@ fn program_clauses_that_could_match( // the automatic impls for `Foo`. let trait_datum = db.trait_datum(trait_id); if trait_datum.is_auto_trait() { - match trait_ref.parameters[0].assert_ty_ref().data() { + match trait_ref.self_type_parameter().data() { TyData::Apply(apply) => { if let Some(struct_id) = db.as_struct_id(&apply.name) { push_auto_trait_impls(builder, trait_id, struct_id); @@ -209,7 +211,7 @@ fn program_clauses_that_could_match( // generated two clauses that are totally irrelevant to // that goal, because they let us prove other things but // not `Clone`. - let self_ty = trait_ref.self_type_parameter().unwrap(); // This cannot be None + let self_ty = trait_ref.self_type_parameter(); if let TyData::Dyn(dyn_ty) = self_ty.data() { // In this arm, `self_ty` is the `dyn Fn(&u8)`, // and `bounded_ty` is the `exists { .. }` diff --git a/chalk-solve/src/clauses/builder.rs b/chalk-solve/src/clauses/builder.rs index 3e1adea1f38..4a71aa5c3de 100644 --- a/chalk-solve/src/clauses/builder.rs +++ b/chalk-solve/src/clauses/builder.rs @@ -66,6 +66,12 @@ impl<'me, TF: TypeFamily> ClauseBuilder<'me, TF> { &self.parameters } + /// Accesses the placeholders for the current list of parameters in scope, + /// in the form of a `Substitution`. + pub fn substitution_in_scope(&self) -> Substitution { + Substitution::from(self.placeholders_in_scope().iter().cloned()) + } + /// Executes `op` with the `binders` in-scope; `op` is invoked /// with the bound value `v` as a parameter. After `op` finishes, /// the binders are popped from scope. diff --git a/chalk-solve/src/clauses/program_clauses.rs b/chalk-solve/src/clauses/program_clauses.rs index 2a4e06d3dce..96f07d1a860 100644 --- a/chalk-solve/src/clauses/program_clauses.rs +++ b/chalk-solve/src/clauses/program_clauses.rs @@ -94,7 +94,7 @@ impl ToProgramClauses for AssociatedTyValue { .binders .map_ref(|b| &b.where_clauses) .into_iter() - .map(|wc| wc.substitute(&projection.parameters)); + .map(|wc| wc.substitute(&projection.substitution)); // Create the final program clause: // @@ -173,7 +173,7 @@ impl ToProgramClauses for StructDatum { builder.push_binders(&binders, |builder, where_clauses| { let self_appl_ty = &ApplicationTy { name: self.id.cast(), - parameters: builder.placeholders_in_scope().to_vec(), + substitution: builder.substitution_in_scope(), }; let self_ty = self_appl_ty.clone().intern(); @@ -387,11 +387,9 @@ impl ToProgramClauses for TraitDatum { fn to_program_clauses(&self, builder: &mut ClauseBuilder<'_, TF>) { let binders = self.binders.map_ref(|b| &b.where_clauses); builder.push_binders(&binders, |builder, where_clauses| { - let parameters = builder.placeholders_in_scope().to_vec(); - let trait_ref = chalk_ir::TraitRef { trait_id: self.id, - parameters, + substitution: builder.substitution_in_scope(), }; builder.push_clause( @@ -568,11 +566,11 @@ impl ToProgramClauses for AssociatedTyDatum { fn to_program_clauses(&self, builder: &mut ClauseBuilder<'_, TF>) { let binders = self.binders.map_ref(|b| (&b.where_clauses, &b.bounds)); builder.push_binders(&binders, |builder, (where_clauses, bounds)| { - let parameters = builder.placeholders_in_scope().to_vec(); + let substitution = builder.substitution_in_scope(); let projection = ProjectionTy { associated_ty_id: self.id, - parameters: parameters.clone(), + substitution: substitution.clone(), }; let projection_ty = projection.clone().intern(); @@ -583,7 +581,7 @@ impl ToProgramClauses for AssociatedTyDatum { // we would produce `(Iterator::Item)`. let app_ty: Ty<_> = ApplicationTy { name: TypeName::AssociatedType(self.id), - parameters, + substitution, } .intern(); diff --git a/chalk-solve/src/coherence/solve.rs b/chalk-solve/src/coherence/solve.rs index cfdc68497c2..742735a4f84 100644 --- a/chalk-solve/src/coherence/solve.rs +++ b/chalk-solve/src/coherence/solve.rs @@ -218,5 +218,5 @@ impl CoherenceSolver<'_, TF> { } fn params(impl_datum: &ImplDatum) -> &[Parameter] { - &impl_datum.binders.value.trait_ref.parameters + impl_datum.binders.value.trait_ref.substitution.parameters() } diff --git a/chalk-solve/src/infer/instantiate.rs b/chalk-solve/src/infer/instantiate.rs index a2b3a5e2d33..c5352171397 100644 --- a/chalk-solve/src/infer/instantiate.rs +++ b/chalk-solve/src/infer/instantiate.rs @@ -13,15 +13,10 @@ impl InferenceTable { &mut self, binders: &[ParameterKind], ) -> Substitution { - Substitution { - parameters: binders - .iter() - .map(|kind| { - let param_infer_var = kind.map(|ui| self.new_variable(ui)); - param_infer_var.to_parameter() - }) - .collect(), - } + Substitution::from(binders.iter().map(|kind| { + let param_infer_var = kind.map(|ui| self.new_variable(ui)); + param_infer_var.to_parameter() + })) } /// Variant on `instantiate` that takes a `Canonical`. diff --git a/chalk-solve/src/solve/slg.rs b/chalk-solve/src/solve/slg.rs index c2d93fa843a..5ed27a4fdf6 100644 --- a/chalk-solve/src/solve/slg.rs +++ b/chalk-solve/src/solve/slg.rs @@ -186,7 +186,7 @@ impl<'me, TF: TypeFamily> context::ContextOps> for SlgContextOps< DomainGoal::Holds(WhereClause::Implemented(trait_ref)) => { let trait_datum = self.program.trait_datum(trait_ref.trait_id); if trait_datum.is_non_enumerable_trait() || trait_datum.is_auto_trait() { - let self_ty = trait_ref.self_type_parameter().unwrap(); + let self_ty = trait_ref.self_type_parameter(); if let Some(v) = self_ty.inference_var() { if !infer.infer.var_is_bound(v) { return Err(Floundered); @@ -450,9 +450,8 @@ trait SubstitutionExt { impl SubstitutionExt for Substitution { fn may_invalidate(&self, subst: &Canonical>) -> bool { - self.parameters - .iter() - .zip(&subst.value.parameters) + self.iter() + .zip(subst.value.iter()) .any(|(new, current)| MayInvalidate.aggregate_parameters(new, current)) } } @@ -546,14 +545,19 @@ impl MayInvalidate { ) -> bool { let ApplicationTy { name: new_name, - parameters: new_parameters, + substitution: new_substitution, } = new; let ApplicationTy { name: current_name, - parameters: current_parameters, + substitution: current_substitution, } = current; - self.aggregate_name_and_substs(new_name, new_parameters, current_name, current_parameters) + self.aggregate_name_and_substs( + new_name, + new_substitution, + current_name, + current_substitution, + ) } fn aggregate_placeholder_tys( @@ -571,22 +575,27 @@ impl MayInvalidate { ) -> bool { let ProjectionTy { associated_ty_id: new_name, - parameters: new_parameters, + substitution: new_substitution, } = new; let ProjectionTy { associated_ty_id: current_name, - parameters: current_parameters, + substitution: current_substitution, } = current; - self.aggregate_name_and_substs(new_name, new_parameters, current_name, current_parameters) + self.aggregate_name_and_substs( + new_name, + new_substitution, + current_name, + current_substitution, + ) } fn aggregate_name_and_substs( &mut self, new_name: N, - new_parameters: &[Parameter], + new_substitution: &Substitution, current_name: N, - current_parameters: &[Parameter], + current_substitution: &Substitution, ) -> bool where N: Copy + Eq + Debug, @@ -599,17 +608,17 @@ impl MayInvalidate { let name = new_name; assert_eq!( - new_parameters.len(), - current_parameters.len(), - "does {:?} take {} parameters or {}? can't both be right", + new_substitution.len(), + current_substitution.len(), + "does {:?} take {} substitution or {}? can't both be right", name, - new_parameters.len(), - current_parameters.len() + new_substitution.len(), + current_substitution.len() ); - new_parameters + new_substitution .iter() - .zip(current_parameters) + .zip(current_substitution) .any(|(new, current)| self.aggregate_parameters(new, current)) } } diff --git a/chalk-solve/src/solve/slg/aggregate.rs b/chalk-solve/src/solve/slg/aggregate.rs index 81d78af0f8c..b2de3769444 100644 --- a/chalk-solve/src/solve/slg/aggregate.rs +++ b/chalk-solve/src/solve/slg/aggregate.rs @@ -95,9 +95,8 @@ fn merge_into_guidance( // common. let aggr_parameters: Vec<_> = guidance .value - .parameters .iter() - .zip(&subst1.parameters) + .zip(subst1.iter()) .enumerate() .map(|(index, (value, value1))| { // We have two values for some variable X that @@ -125,9 +124,7 @@ fn merge_into_guidance( }) .collect(); - let aggr_subst = Substitution { - parameters: aggr_parameters, - }; + let aggr_subst = Substitution::from(aggr_parameters); infer.canonicalize(&aggr_subst).quantified } @@ -136,7 +133,6 @@ fn is_trivial(subst: &Canonical>) -> bool { // A subst is trivial if.. subst .value - .parameters .iter() .enumerate() .all(|(index, parameter)| match parameter.data() { @@ -213,15 +209,17 @@ impl AntiUnifier<'_, TF> { ) -> Ty { let ApplicationTy { name: name1, - parameters: parameters1, + substitution: substitution1, } = apply1; let ApplicationTy { name: name2, - parameters: parameters2, + substitution: substitution2, } = apply2; - self.aggregate_name_and_substs(name1, parameters1, name2, parameters2) - .map(|(&name, parameters)| TyData::Apply(ApplicationTy { name, parameters }).intern()) + self.aggregate_name_and_substs(name1, substitution1, name2, substitution2) + .map(|(&name, substitution)| { + TyData::Apply(ApplicationTy { name, substitution }).intern() + }) .unwrap_or_else(|| self.new_variable()) } @@ -244,18 +242,18 @@ impl AntiUnifier<'_, TF> { ) -> Ty { let ProjectionTy { associated_ty_id: name1, - parameters: parameters1, + substitution: substitution1, } = proj1; let ProjectionTy { associated_ty_id: name2, - parameters: parameters2, + substitution: substitution2, } = proj2; - self.aggregate_name_and_substs(name1, parameters1, name2, parameters2) - .map(|(&associated_ty_id, parameters)| { + self.aggregate_name_and_substs(name1, substitution1, name2, substitution2) + .map(|(&associated_ty_id, substitution)| { TyData::Projection(ProjectionTy { associated_ty_id, - parameters, + substitution, }) .intern() }) @@ -265,10 +263,10 @@ impl AntiUnifier<'_, TF> { fn aggregate_name_and_substs( &mut self, name1: N, - parameters1: &[Parameter], + substitution1: &Substitution, name2: N, - parameters2: &[Parameter], - ) -> Option<(N, Vec>)> + substitution2: &Substitution, + ) -> Option<(N, Substitution)> where N: Copy + Eq + Debug, { @@ -279,21 +277,22 @@ impl AntiUnifier<'_, TF> { let name = name1; assert_eq!( - parameters1.len(), - parameters2.len(), - "does {:?} take {} parameters or {}? can't both be right", + substitution1.len(), + substitution2.len(), + "does {:?} take {} substitution or {}? can't both be right", name, - parameters1.len(), - parameters2.len() + substitution1.len(), + substitution2.len() ); - let parameters: Vec<_> = parameters1 - .iter() - .zip(parameters2) - .map(|(p1, p2)| self.aggregate_parameters(p1, p2)) - .collect(); + let substitution = Substitution::from( + substitution1 + .iter() + .zip(substitution2) + .map(|(p1, p2)| self.aggregate_parameters(p1, p2)), + ); - Some((name, parameters)) + Some((name, substitution)) } fn aggregate_parameters(&mut self, p1: &Parameter, p2: &Parameter) -> Parameter { diff --git a/chalk-solve/src/solve/slg/resolvent.rs b/chalk-solve/src/solve/slg/resolvent.rs index d16b7ad036c..5aabf71123b 100644 --- a/chalk-solve/src/solve/slg/resolvent.rs +++ b/chalk-solve/src/solve/slg/resolvent.rs @@ -297,7 +297,7 @@ impl AnswerSubstitutor<'_, TF> { return Ok(false); } - let answer_param = &self.answer_subst.parameters[answer_depth - self.answer_binders]; + let answer_param = self.answer_subst.at(answer_depth - self.answer_binders); let pending_shifted = pending .shifted_out(self.pending_binders) diff --git a/chalk-solve/src/split.rs b/chalk-solve/src/split.rs index 9475b64505d..1e6c0141791 100644 --- a/chalk-solve/src/split.rs +++ b/chalk-solve/src/split.rs @@ -23,8 +23,9 @@ pub trait Split: RustIrDatabase { ) { let ProjectionTy { associated_ty_id, - ref parameters, + ref substitution, } = *projection; + let parameters = substitution.parameters(); let associated_ty_data = &self.associated_ty_data(associated_ty_id); let trait_datum = &self.trait_datum(associated_ty_data.trait_id); let trait_num_params = trait_datum.binders.len(); @@ -51,7 +52,7 @@ pub trait Split: RustIrDatabase { let (associated_ty_data, trait_params, _) = self.split_projection(&projection); TraitRef { trait_id: associated_ty_data.trait_id, - parameters: trait_params.to_owned(), + substitution: Substitution::from(trait_params), } } @@ -135,21 +136,22 @@ pub trait Split: RustIrDatabase { let trait_ref = { let impl_trait_ref = impl_datum.binders.map_ref(|b| &b.trait_ref); debug!("impl_trait_ref: {:?}", impl_trait_ref); - impl_trait_ref.substitute(&impl_parameters) + impl_trait_ref.substitute(impl_parameters) }; // Create the parameters for the projection -- in our example // above, this would be `['!a, Box]`, corresponding to // ` as Foo>::Item<'!a>` - let projection_parameters: Vec<_> = atv_parameters - .iter() - .chain(&trait_ref.parameters) - .cloned() - .collect(); + let projection_substitution = Substitution::from( + atv_parameters + .iter() + .chain(&trait_ref.substitution) + .cloned(), + ); let projection = ProjectionTy { associated_ty_id: associated_ty_value.associated_ty_id, - parameters: projection_parameters, + substitution: projection_substitution, }; debug!("impl_parameters: {:?}", impl_parameters); diff --git a/chalk-solve/src/wf.rs b/chalk-solve/src/wf.rs index 5299c57e556..b030b1200db 100644 --- a/chalk-solve/src/wf.rs +++ b/chalk-solve/src/wf.rs @@ -44,6 +44,14 @@ trait FoldInputTypes: HasTypeFamily { fn fold(&self, accumulator: &mut Vec>); } +impl FoldInputTypes for [T] { + fn fold(&self, accumulator: &mut Vec>) { + for f in self { + f.fold(accumulator); + } + } +} + impl FoldInputTypes for Vec { fn fold(&self, accumulator: &mut Vec>) { for f in self { @@ -60,12 +68,18 @@ impl FoldInputTypes for Parameter { } } +impl FoldInputTypes for Substitution { + fn fold(&self, accumulator: &mut Vec>) { + self.parameters().fold(accumulator) + } +} + impl FoldInputTypes for Ty { fn fold(&self, accumulator: &mut Vec>) { match self.data() { TyData::Apply(app) => { accumulator.push(self.clone()); - app.parameters.fold(accumulator); + app.substitution.fold(accumulator); } TyData::Dyn(qwc) => { @@ -75,7 +89,7 @@ impl FoldInputTypes for Ty { TyData::Projection(proj) => { accumulator.push(self.clone()); - proj.parameters.fold(accumulator); + proj.substitution.fold(accumulator); } TyData::Placeholder(_) => { @@ -101,7 +115,7 @@ impl FoldInputTypes for Ty { impl FoldInputTypes for TraitRef { fn fold(&self, accumulator: &mut Vec>) { - self.parameters.fold(accumulator); + self.substitution.fold(accumulator); } } @@ -369,7 +383,7 @@ where let AssociatedTyDatumBound { bounds: defn_bounds, where_clauses: defn_where_clauses, - } = assoc_ty_datum.binders.substitute(&projection.parameters); + } = assoc_ty_datum.binders.substitute(&projection.substitution); // Check that the `value_ty` meets the bounds from the trait. // Here we take the substituted bounds (`defn_bounds`) and we