1
1
use crate :: coherence:: { CoherenceError , CoherenceSolver } ;
2
2
use crate :: ext:: * ;
3
- use crate :: Solution ;
3
+ use crate :: { goal_builder :: GoalBuilder , Solution } ;
4
4
use chalk_ir:: cast:: * ;
5
5
use chalk_ir:: fold:: shift:: Shift ;
6
6
use chalk_ir:: interner:: Interner ;
@@ -34,7 +34,7 @@ impl<I: Interner> CoherenceSolver<'_, I> {
34
34
// the other. Note that specialization can only run one way - if both
35
35
// specialization checks return *either* true or false, that's an error.
36
36
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 ) ) {
38
38
( true , false ) => record_specialization ( l_id, r_id) ,
39
39
( false , true ) => record_specialization ( r_id, l_id) ,
40
40
( _, _) => {
@@ -145,23 +145,56 @@ impl<I: Interner> CoherenceSolver<'_, I> {
145
145
result
146
146
}
147
147
148
- // Test for specialization .
148
+ // Creates a goal which, if provable, means "more special" impl specializes the "less special" one .
149
149
//
150
- // If this test succeeds, the second impl specializes the first.
150
+ // # General rule
151
151
//
152
- // Example lowering :
152
+ // Given the more special impl :
153
153
//
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
+ // ```
156
157
//
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
157
187
// forall<T> {
158
188
// if (T: Clone) {
159
189
// exists<U> {
160
190
// Vec<T> = U, U: Clone
161
191
// }
162
192
// }
163
193
// }
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) ;
165
198
debug_heading ! (
166
199
"specializes(less_special={:#?}, more_special={:#?})" ,
167
200
less_special,
@@ -170,66 +203,54 @@ impl<I: Interner> CoherenceSolver<'_, I> {
170
203
171
204
let interner = self . db . interner ( ) ;
172
205
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 ) ;
177
207
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) ;
188
216
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 ( ) ;
198
223
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) ) ;
210
239
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
+ ) ;
233
254
234
255
let canonical_goal = & goal. into_closed_goal ( interner) ;
235
256
let result = match self
0 commit comments