Skip to content

Commit 4acecc2

Browse files
committed
port coherence code to use goal builder
1 parent ab25299 commit 4acecc2

File tree

1 file changed

+85
-64
lines changed

1 file changed

+85
-64
lines changed

chalk-solve/src/coherence/solve.rs

Lines changed: 85 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use crate::coherence::{CoherenceError, CoherenceSolver};
22
use crate::ext::*;
3-
use crate::Solution;
3+
use crate::{goal_builder::GoalBuilder, Solution};
44
use chalk_ir::cast::*;
55
use chalk_ir::fold::shift::Shift;
66
use chalk_ir::interner::Interner;
@@ -34,7 +34,7 @@ impl<I: Interner> CoherenceSolver<'_, I> {
3434
// the other. Note that specialization can only run one way - if both
3535
// specialization checks return *either* true or false, that's an error.
3636
if !self.disjoint(lhs, rhs) {
37-
match (self.specializes(lhs, rhs), self.specializes(rhs, lhs)) {
37+
match (self.specializes(l_id, r_id), self.specializes(r_id, l_id)) {
3838
(true, false) => record_specialization(l_id, r_id),
3939
(false, true) => record_specialization(r_id, l_id),
4040
(_, _) => {
@@ -145,23 +145,56 @@ impl<I: Interner> CoherenceSolver<'_, I> {
145145
result
146146
}
147147

148-
// Test for specialization.
148+
// Creates a goal which, if provable, means "more special" impl specializes the "less special" one.
149149
//
150-
// If this test succeeds, the second impl specializes the first.
150+
// # General rule
151151
//
152-
// Example lowering:
152+
// Given the more special impl:
153153
//
154-
// more: impl<T: Clone> Foo for Vec<T>
155-
// less: impl<U: Clone> Foo for U
154+
// ```ignore
155+
// impl<P0..Pn> SomeTrait<T1..Tm> for T0 where WC_more
156+
// ```
156157
//
158+
// and less special impl
159+
//
160+
// ```ignore
161+
// impl<Q0..Qo> SomeTrait<U1..Um> for U0 where WC_less
162+
// ```
163+
//
164+
// create the goal:
165+
//
166+
// ```ignore
167+
// forall<P0..Pn> {
168+
// if (WC_more) {}
169+
// exists<Q0..Qo> {
170+
// T0 = U0, ..., Tm = Um,
171+
// WC_less
172+
// }
173+
// }
174+
// }
175+
// ```
176+
//
177+
// # Example
178+
//
179+
// Given:
180+
//
181+
// * more: `impl<T: Clone> Foo for Vec<T>`
182+
// * less: `impl<U: Clone> Foo for U`
183+
//
184+
// Resulting goal:
185+
//
186+
// ```ignore
157187
// forall<T> {
158188
// if (T: Clone) {
159189
// exists<U> {
160190
// Vec<T> = U, U: Clone
161191
// }
162192
// }
163193
// }
164-
fn specializes(&self, less_special: &ImplDatum<I>, more_special: &ImplDatum<I>) -> bool {
194+
// ```
195+
fn specializes(&self, less_special_id: ImplId<I>, more_special_id: ImplId<I>) -> bool {
196+
let more_special = &self.db.impl_datum(more_special_id);
197+
let less_special = &self.db.impl_datum(less_special_id);
165198
debug_heading!(
166199
"specializes(less_special={:#?}, more_special={:#?})",
167200
less_special,
@@ -170,66 +203,54 @@ impl<I: Interner> CoherenceSolver<'_, I> {
170203

171204
let interner = self.db.interner();
172205

173-
// Negative impls cannot specialize.
174-
if !less_special.is_positive() || !more_special.is_positive() {
175-
return false;
176-
}
206+
let gb = &mut GoalBuilder::new(self.db);
177207

178-
// Create parameter equality goals. Note that parameters from
179-
// the "more special" goal have to be "shifted in" across the
180-
// binder for the "less special" impl.
181-
let more_special_params = params(interner, more_special)
182-
.iter()
183-
.map(|p| p.shifted_in(interner));
184-
let less_special_params = params(interner, less_special).iter().cloned();
185-
let params_goals = more_special_params
186-
.zip(less_special_params)
187-
.map(|(a, b)| GoalData::EqGoal(EqGoal { a, b }).intern(interner));
208+
// forall<P0..Pn> { ... }
209+
let goal = gb.forall(
210+
&more_special.binders,
211+
less_special_id,
212+
|gb, _, more_special_impl, less_special_id| {
213+
// if (WC_more) { ... }
214+
gb.implies(more_special_impl.where_clauses.iter().cloned(), |gb| {
215+
let less_special = &gb.db().impl_datum(less_special_id);
188216

189-
// Create less special where clause goals. These reference the parameters
190-
// from the "less special" impl, which are at the same debruijn depth here.
191-
let less_special_wc = less_special
192-
.binders
193-
.value
194-
.where_clauses
195-
.iter()
196-
.cloned()
197-
.casted(interner);
217+
// exists<Q0..Qn> { ... }
218+
gb.exists(
219+
&less_special.binders,
220+
&more_special_impl.trait_ref,
221+
|gb, _, less_special_impl, more_special_trait_ref| {
222+
let interner = gb.interner();
198223

199-
// Create the "more special" where clause goals. These will be
200-
// added as an implication without the "less special" goals in
201-
// scope, no shift required.
202-
let more_special_wc = more_special
203-
.binders
204-
.value
205-
.where_clauses
206-
.iter()
207-
.cloned()
208-
.casted(interner)
209-
.collect();
224+
// T0 = U0, ..., Tm = Um
225+
let params_goals = more_special_trait_ref
226+
.substitution
227+
.parameters(interner)
228+
.iter()
229+
.cloned()
230+
.zip(
231+
less_special_impl
232+
.trait_ref
233+
.substitution
234+
.parameters(interner)
235+
.iter()
236+
.cloned(),
237+
)
238+
.map(|(a, b)| GoalData::EqGoal(EqGoal { a, b }).intern(interner));
210239

211-
// Join all of the goals together:
212-
//
213-
// forall<..more special..> {
214-
// if (<more special wc>) {
215-
// exists<..less special..> {
216-
// ..less special goals..
217-
// ..equality goals..
218-
// }
219-
// }
220-
// }
221-
let goal = Box::new(Goal::all(interner, params_goals.chain(less_special_wc)))
222-
.quantify(
223-
interner,
224-
QuantifierKind::Exists,
225-
less_special.binders.binders.clone(),
226-
)
227-
.implied_by(interner, more_special_wc)
228-
.quantify(
229-
interner,
230-
QuantifierKind::ForAll,
231-
more_special.binders.binders.clone(),
232-
);
240+
// <less_special_wc_goals> = where clauses from the less special impl
241+
let less_special_wc_goals = less_special_impl
242+
.where_clauses
243+
.iter()
244+
.cloned()
245+
.casted(interner);
246+
247+
// <equality_goals> && WC_less
248+
gb.all(params_goals.chain(less_special_wc_goals))
249+
},
250+
)
251+
})
252+
},
253+
);
233254

234255
let canonical_goal = &goal.into_closed_goal(interner);
235256
let result = match self

0 commit comments

Comments
 (0)