File tree 2 files changed +60
-6
lines changed
2 files changed +60
-6
lines changed Original file line number Diff line number Diff line change @@ -183,12 +183,20 @@ impl Solver {
183
183
match self . cycle_strategy {
184
184
CycleStrategy :: Tabling if slot. cycle => {
185
185
let actual_answer = result. as_ref ( ) . ok ( ) . map ( |s| s. clone ( ) ) ;
186
- if actual_answer == answer {
187
- // Fixed point: break
188
- return result;
189
- } else {
190
- answer = actual_answer;
191
- }
186
+ let fixed_point = answer == actual_answer;
187
+
188
+ // If we reach a fixed point, we can break.
189
+ // If the answer is `Ambig`, then we know that we already have multiple
190
+ // solutions, and we *must* break because an `Ambig` solution may not perform
191
+ // any unification and thus fail to correctly reach a fixed point. See test
192
+ // `multiple_ambiguous_cycles`.
193
+ match ( fixed_point, & actual_answer) {
194
+ ( _, & Some ( Solution :: Ambig ( _) ) ) | ( true , _) =>
195
+ return result,
196
+ _ => ( )
197
+ } ;
198
+
199
+ answer = actual_answer;
192
200
}
193
201
_ => return result,
194
202
} ;
Original file line number Diff line number Diff line change @@ -291,6 +291,52 @@ fn cycle_unique_solution() {
291
291
}
292
292
}
293
293
294
+ #[ test]
295
+ fn multiple_ambiguous_cycles ( ) {
296
+ test ! {
297
+ program {
298
+ trait WF { }
299
+ trait Sized { }
300
+
301
+ struct Vec <T > { }
302
+ struct Int { }
303
+
304
+ impl Sized for Int { }
305
+ impl WF for Int { }
306
+
307
+ impl <T > WF for Vec <T > where T : Sized { }
308
+ impl <T > Sized for Vec <T > where T : WF , T : Sized { }
309
+ }
310
+
311
+ // ?T: WF
312
+ // |
313
+ // |
314
+ // |
315
+ // Int: WF. <-----> (Vec<?T>: WF) :- (?T: Sized)
316
+ // |
317
+ // |
318
+ // |
319
+ // Int: Sized. <-------> (Vec<?T>: Sized) :- (?T: Sized), (?T: WF)
320
+ // | |
321
+ // | |
322
+ // | |
323
+ // cycle cycle
324
+ //
325
+ // Depending on the evaluation order of the above tree (which cycle we come upon first),
326
+ // we may fail to reach a fixed point if we loop continuously because `Ambig` does not perform
327
+ // any unification. We must stop looping as soon as we encounter `Ambig`. In fact without
328
+ // this strategy, the above program will not even be loaded because of the overlap check which
329
+ // will loop forever.
330
+ goal {
331
+ exists<T > {
332
+ T : WF
333
+ }
334
+ } yields {
335
+ "Ambig"
336
+ }
337
+ }
338
+ }
339
+
294
340
#[ test]
295
341
fn normalize_basic ( ) {
296
342
test ! {
You can’t perform that action at this time.
0 commit comments