| use crate::rust_ir::*; |
| use crate::RustIrDatabase; |
| use chalk_ir::interner::Interner; |
| use chalk_ir::*; |
| use std::sync::Arc; |
| use tracing::{debug, instrument}; |
| |
| /// Methods for splitting up the projections for associated types from |
| /// the surrounding context. |
| pub trait Split<I: Interner>: RustIrDatabase<I> { |
| /// Given a projection of an associated type, split the type |
| /// parameters into those that come from the *trait* and those |
| /// that come from the *associated type itself*. So e.g. if you |
| /// have `(Iterator::Item)<F>`, this would return `([F], [])`, |
| /// since `Iterator::Item` is not generic and hence doesn't have |
| /// any type parameters itself. |
| fn split_projection<'p>( |
| &self, |
| projection: &'p ProjectionTy<I>, |
| ) -> ( |
| Arc<AssociatedTyDatum<I>>, |
| &'p [GenericArg<I>], |
| &'p [GenericArg<I>], |
| ) { |
| let interner = self.interner(); |
| let ProjectionTy { |
| associated_ty_id, |
| ref substitution, |
| } = *projection; |
| let parameters = substitution.as_slice(interner); |
| let associated_ty_data = &self.associated_ty_data(associated_ty_id); |
| let (trait_params, other_params) = |
| self.split_associated_ty_parameters(parameters, &**associated_ty_data); |
| (associated_ty_data.clone(), trait_params, other_params) |
| } |
| |
| /// Given a projection `<P0 as Trait<P1..Pn>>::Item<Pn..Pm>`, |
| /// returns the trait parameters `[P0..Pn]` (see |
| /// `split_projection`). |
| fn trait_parameters_from_projection<'p>( |
| &self, |
| projection: &'p ProjectionTy<I>, |
| ) -> &'p [GenericArg<I>] { |
| let (_, trait_params, _) = self.split_projection(projection); |
| trait_params |
| } |
| |
| /// Given a projection `<P0 as Trait<P1..Pn>>::Item<Pn..Pm>`, |
| /// returns the trait parameters `[P0..Pn]` (see |
| /// `split_projection`). |
| fn trait_ref_from_projection(&self, projection: &ProjectionTy<I>) -> TraitRef<I> { |
| let interner = self.interner(); |
| let (associated_ty_data, trait_params, _) = self.split_projection(projection); |
| TraitRef { |
| trait_id: associated_ty_data.trait_id, |
| substitution: Substitution::from_iter(interner, trait_params), |
| } |
| } |
| |
| /// Given the full set of parameters (or binders) for an |
| /// associated type *value* (which appears in an impl), splits |
| /// them into the substitutions for the *impl* and those for the |
| /// *associated type*. |
| /// |
| /// # Example |
| /// |
| /// ```ignore (example) |
| /// impl<T> Iterable for Vec<T> { |
| /// type Iter<'a>; |
| /// } |
| /// ``` |
| /// |
| /// in this example, the full set of parameters would be `['x, |
| /// Y]`, where `'x` is the value for `'a` and `Y` is the value for |
| /// `T`. |
| /// |
| /// # Returns |
| /// |
| /// Returns the pair of: |
| /// |
| /// * the parameters for the impl (`[Y]`, in our example) |
| /// * the parameters for the associated type value (`['a]`, in our example) |
| fn split_associated_ty_value_parameters<'p, P>( |
| &self, |
| parameters: &'p [P], |
| associated_ty_value: &AssociatedTyValue<I>, |
| ) -> (&'p [P], &'p [P]) { |
| let interner = self.interner(); |
| let impl_datum = self.impl_datum(associated_ty_value.impl_id); |
| let impl_params_len = impl_datum.binders.len(interner); |
| assert!(parameters.len() >= impl_params_len); |
| |
| // the impl parameters are a suffix |
| // |
| // [ P0..Pn, Pn...Pm ] |
| // ^^^^^^^ impl parameters |
| let split_point = parameters.len() - impl_params_len; |
| let (other_params, impl_params) = parameters.split_at(split_point); |
| (impl_params, other_params) |
| } |
| |
| /// Given the full set of parameters for an associated type *value* |
| /// (which appears in an impl), returns the trait reference |
| /// and projection that are being satisfied by that value. |
| /// |
| /// # Example |
| /// |
| /// ```ignore (example) |
| /// impl<T> Iterable for Vec<T> { |
| /// type Iter<'a>; |
| /// } |
| /// ``` |
| /// |
| /// Here we expect the full set of parameters for `Iter`, which |
| /// would be `['x, Y]`, where `'x` is the value for `'a` and `Y` |
| /// is the value for `T`. |
| /// |
| /// Returns the pair of: |
| /// |
| /// * the parameters that apply to the impl (`Y`, in our example) |
| /// * the projection `<Vec<Y> as Iterable>::Iter<'x>` |
| #[instrument(level = "debug", skip(self, associated_ty_value))] |
| fn impl_parameters_and_projection_from_associated_ty_value<'p>( |
| &self, |
| parameters: &'p [GenericArg<I>], |
| associated_ty_value: &AssociatedTyValue<I>, |
| ) -> (&'p [GenericArg<I>], ProjectionTy<I>) { |
| let interner = self.interner(); |
| |
| let impl_datum = self.impl_datum(associated_ty_value.impl_id); |
| |
| // Get the trait ref from the impl -- so in our example above |
| // this would be `Box<!T>: Foo`. |
| let (impl_parameters, atv_parameters) = |
| self.split_associated_ty_value_parameters(parameters, associated_ty_value); |
| let trait_ref = { |
| let opaque_ty_ref = impl_datum.binders.map_ref(|b| &b.trait_ref).cloned(); |
| debug!(?opaque_ty_ref); |
| opaque_ty_ref.substitute(interner, impl_parameters) |
| }; |
| |
| // Create the parameters for the projection -- in our example |
| // above, this would be `['!a, Box<!T>]`, corresponding to |
| // `<Box<!T> as Foo>::Item<'!a>` |
| let projection_substitution = Substitution::from_iter( |
| interner, |
| atv_parameters |
| .iter() |
| .chain(trait_ref.substitution.iter(interner)) |
| .cloned(), |
| ); |
| |
| let projection = ProjectionTy { |
| associated_ty_id: associated_ty_value.associated_ty_id, |
| substitution: projection_substitution, |
| }; |
| |
| debug!(?impl_parameters, ?trait_ref, ?projection); |
| |
| (impl_parameters, projection) |
| } |
| |
| /// Given the full set of parameters (or binders) for an |
| /// associated type datum (the one appearing in a trait), splits |
| /// them into the parameters for the *trait* and those for the |
| /// *associated type*. |
| /// |
| /// # Example |
| /// |
| /// ```ignore (example) |
| /// trait Foo<T> { |
| /// type Assoc<'a>; |
| /// } |
| /// ``` |
| /// |
| /// in this example, the full set of parameters would be `['x, |
| /// Y]`, where `'x` is the value for `'a` and `Y` is the value for |
| /// `T`. |
| /// |
| /// # Returns |
| /// |
| /// Returns the tuple of: |
| /// |
| /// * the parameters for the impl (`[Y]`, in our example) |
| /// * the parameters for the associated type value (`['a]`, in our example) |
| fn split_associated_ty_parameters<'p, P>( |
| &self, |
| parameters: &'p [P], |
| associated_ty_datum: &AssociatedTyDatum<I>, |
| ) -> (&'p [P], &'p [P]) { |
| let trait_datum = &self.trait_datum(associated_ty_datum.trait_id); |
| let trait_num_params = trait_datum.binders.len(self.interner()); |
| let split_point = parameters.len() - trait_num_params; |
| let (other_params, trait_params) = parameters.split_at(split_point); |
| (trait_params, other_params) |
| } |
| } |
| |
| impl<DB: RustIrDatabase<I> + ?Sized, I: Interner> Split<I> for DB {} |