Skip to content

Commit 6511012

Browse files
authored
Merge pull request #48 from scalexm/master
Return early when treating ambiguous cycles
2 parents ad32300 + 19eac4c commit 6511012

File tree

2 files changed

+60
-6
lines changed

2 files changed

+60
-6
lines changed

src/solve/solver.rs

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -183,12 +183,20 @@ impl Solver {
183183
match self.cycle_strategy {
184184
CycleStrategy::Tabling if slot.cycle => {
185185
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;
192200
}
193201
_ => return result,
194202
};

src/solve/test.rs

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -291,6 +291,52 @@ fn cycle_unique_solution() {
291291
}
292292
}
293293

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+
294340
#[test]
295341
fn normalize_basic() {
296342
test! {

0 commit comments

Comments
 (0)