2 use crate::RustIrDatabase
;
3 use chalk_ir
::interner
::Interner
;
6 use tracing
::{debug, instrument}
;
8 /// Methods for splitting up the projections for associated types from
9 /// the surrounding context.
10 pub trait Split
<I
: Interner
>: RustIrDatabase
<I
> {
11 /// Given a projection of an associated type, split the type
12 /// parameters into those that come from the *trait* and those
13 /// that come from the *associated type itself*. So e.g. if you
14 /// have `(Iterator::Item)<F>`, this would return `([F], [])`,
15 /// since `Iterator::Item` is not generic and hence doesn't have
16 /// any type parameters itself.
17 fn split_projection
<'p
>(
19 projection
: &'p ProjectionTy
<I
>,
21 Arc
<AssociatedTyDatum
<I
>>,
25 let interner
= self.interner();
30 let parameters
= substitution
.as_slice(interner
);
31 let associated_ty_data
= &self.associated_ty_data(associated_ty_id
);
32 let (trait_params
, other_params
) =
33 self.split_associated_ty_parameters(parameters
, &**associated_ty_data
);
34 (associated_ty_data
.clone(), trait_params
, other_params
)
37 /// Given a projection `<P0 as Trait<P1..Pn>>::Item<Pn..Pm>`,
38 /// returns the trait parameters `[P0..Pn]` (see
39 /// `split_projection`).
40 fn trait_parameters_from_projection
<'p
>(
42 projection
: &'p ProjectionTy
<I
>,
43 ) -> &'p
[GenericArg
<I
>] {
44 let (_
, trait_params
, _
) = self.split_projection(projection
);
48 /// Given a projection `<P0 as Trait<P1..Pn>>::Item<Pn..Pm>`,
49 /// returns the trait parameters `[P0..Pn]` (see
50 /// `split_projection`).
51 fn trait_ref_from_projection
<'p
>(&self, projection
: &'p ProjectionTy
<I
>) -> TraitRef
<I
> {
52 let interner
= self.interner();
53 let (associated_ty_data
, trait_params
, _
) = self.split_projection(&projection
);
55 trait_id
: associated_ty_data
.trait_id
,
56 substitution
: Substitution
::from_iter(interner
, trait_params
),
60 /// Given the full set of parameters (or binders) for an
61 /// associated type *value* (which appears in an impl), splits
62 /// them into the substitutions for the *impl* and those for the
63 /// *associated type*.
67 /// ```ignore (example)
68 /// impl<T> Iterable for Vec<T> {
73 /// in this example, the full set of parameters would be `['x,
74 /// Y]`, where `'x` is the value for `'a` and `Y` is the value for
79 /// Returns the pair of:
81 /// * the parameters for the impl (`[Y]`, in our example)
82 /// * the parameters for the associated type value (`['a]`, in our example)
83 fn split_associated_ty_value_parameters
<'p
, P
>(
86 associated_ty_value
: &AssociatedTyValue
<I
>,
87 ) -> (&'p
[P
], &'p
[P
]) {
88 let interner
= self.interner();
89 let impl_datum
= self.impl_datum(associated_ty_value
.impl_id
);
90 let impl_params_len
= impl_datum
.binders
.len(interner
);
91 assert
!(parameters
.len() >= impl_params_len
);
93 // the impl parameters are a suffix
95 // [ P0..Pn, Pn...Pm ]
96 // ^^^^^^^ impl parameters
97 let split_point
= parameters
.len() - impl_params_len
;
98 let (other_params
, impl_params
) = parameters
.split_at(split_point
);
99 (impl_params
, other_params
)
102 /// Given the full set of parameters for an associated type *value*
103 /// (which appears in an impl), returns the trait reference
104 /// and projection that are being satisfied by that value.
108 /// ```ignore (example)
109 /// impl<T> Iterable for Vec<T> {
114 /// Here we expect the full set of parameters for `Iter`, which
115 /// would be `['x, Y]`, where `'x` is the value for `'a` and `Y`
116 /// is the value for `T`.
118 /// Returns the pair of:
120 /// * the parameters that apply to the impl (`Y`, in our example)
121 /// * the projection `<Vec<Y> as Iterable>::Iter<'x>`
122 #[instrument(level = "debug", skip(self, associated_ty_value))]
123 fn impl_parameters_and_projection_from_associated_ty_value
<'p
>(
125 parameters
: &'p
[GenericArg
<I
>],
126 associated_ty_value
: &AssociatedTyValue
<I
>,
127 ) -> (&'p
[GenericArg
<I
>], ProjectionTy
<I
>) {
128 let interner
= self.interner();
130 let impl_datum
= self.impl_datum(associated_ty_value
.impl_id
);
132 // Get the trait ref from the impl -- so in our example above
133 // this would be `Box<!T>: Foo`.
134 let (impl_parameters
, atv_parameters
) =
135 self.split_associated_ty_value_parameters(¶meters
, associated_ty_value
);
137 let opaque_ty_ref
= impl_datum
.binders
.map_ref(|b
| &b
.trait_ref
);
138 debug
!(?opaque_ty_ref
);
139 opaque_ty_ref
.substitute(interner
, impl_parameters
)
142 // Create the parameters for the projection -- in our example
143 // above, this would be `['!a, Box<!T>]`, corresponding to
144 // `<Box<!T> as Foo>::Item<'!a>`
145 let projection_substitution
= Substitution
::from_iter(
149 .chain(trait_ref
.substitution
.iter(interner
))
153 let projection
= ProjectionTy
{
154 associated_ty_id
: associated_ty_value
.associated_ty_id
,
155 substitution
: projection_substitution
,
158 debug
!(?impl_parameters
, ?trait_ref
, ?projection
);
160 (impl_parameters
, projection
)
163 /// Given the full set of parameters (or binders) for an
164 /// associated type datum (the one appearing in a trait), splits
165 /// them into the parameters for the *trait* and those for the
166 /// *associated type*.
170 /// ```ignore (example)
176 /// in this example, the full set of parameters would be `['x,
177 /// Y]`, where `'x` is the value for `'a` and `Y` is the value for
182 /// Returns the tuple of:
184 /// * the parameters for the impl (`[Y]`, in our example)
185 /// * the parameters for the associated type value (`['a]`, in our example)
186 fn split_associated_ty_parameters
<'p
, P
>(
189 associated_ty_datum
: &AssociatedTyDatum
<I
>,
190 ) -> (&'p
[P
], &'p
[P
]) {
191 let trait_datum
= &self.trait_datum(associated_ty_datum
.trait_id
);
192 let trait_num_params
= trait_datum
.binders
.len(self.interner());
193 let split_point
= parameters
.len() - trait_num_params
;
194 let (other_params
, trait_params
) = parameters
.split_at(split_point
);
195 (trait_params
, other_params
)
199 impl<DB
: RustIrDatabase
<I
> + ?Sized
, I
: Interner
> Split
<I
> for DB {}