Skip to content

Commit bb32a14

Browse files
authored
Merge pull request #53 from scalexm/overflow-panic
Panic on overflow
2 parents 07f713e + 08b7cef commit bb32a14

File tree

4 files changed

+63
-7
lines changed

4 files changed

+63
-7
lines changed

src/bin/chalki.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ use std::sync::Arc;
1111

1212
use chalk::ir;
1313
use chalk::lower::*;
14-
use chalk::solve::solver::{Solver, CycleStrategy};
14+
use chalk::solve::solver::{self, Solver, CycleStrategy};
1515

1616
use rustyline::error::ReadlineError;
1717

@@ -44,6 +44,10 @@ impl Program {
4444
quick_main!(run);
4545

4646
fn run() -> Result<()> {
47+
// Initialize global overflow depth before everything
48+
let overflow_depth = 10;
49+
solver::set_overflow_depth(overflow_depth);
50+
4751
let mut prog = None;
4852
readline_loop(&mut rustyline::Editor::new(), "?- ", |rl, line| {
4953
if let Err(e) = process(line, rl, &mut prog) {
@@ -118,7 +122,7 @@ fn read_program(rl: &mut rustyline::Editor<()>) -> Result<String> {
118122

119123
fn goal(text: &str, prog: &Program) -> Result<()> {
120124
let goal = chalk_parse::parse_goal(text)?.lower(&*prog.ir)?;
121-
let mut solver = Solver::new(&prog.env, CycleStrategy::Tabling);
125+
let mut solver = Solver::new(&prog.env, CycleStrategy::Tabling, solver::get_overflow_depth());
122126
let goal = ir::InEnvironment::new(&ir::Environment::new(), *goal);
123127
match solver.solve_closed_goal(goal) {
124128
Ok(v) => println!("{}\n", v),

src/coherence/solve.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,17 @@ use std::sync::Arc;
33
use itertools::Itertools;
44
use errors::*;
55
use ir::*;
6-
use solve::solver::{Solver, CycleStrategy};
6+
use solve::solver::{self, Solver, CycleStrategy};
77

88
impl Program {
99
pub(super) fn visit_specializations<F>(&self, mut record_specialization: F) -> Result<()>
1010
where F: FnMut(ItemId, ItemId)
1111
{
12-
let mut solver = Solver::new(&Arc::new(self.environment()), CycleStrategy::Tabling);
12+
let mut solver = Solver::new(
13+
&Arc::new(self.environment()),
14+
CycleStrategy::Tabling,
15+
solver::get_overflow_depth()
16+
);
1317

1418
// Create a vector of references to impl datums, sorted by trait ref
1519
let impl_data = self.impl_data.iter().sorted_by(|&(_, lhs), &(_, rhs)| {

src/solve/solver.rs

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,20 @@ use std::sync::Arc;
33

44
use super::*;
55
use solve::fulfill::Fulfill;
6+
use std::cell::Cell;
7+
8+
thread_local! {
9+
// Default overflow depth which will be used in tests
10+
static OVERFLOW_DEPTH: Cell<usize> = Cell::new(10);
11+
}
12+
13+
pub fn set_overflow_depth(overflow_depth: usize) {
14+
OVERFLOW_DEPTH.with(|depth| depth.set(overflow_depth));
15+
}
16+
17+
pub fn get_overflow_depth() -> usize {
18+
OVERFLOW_DEPTH.with(|depth| depth.get())
19+
}
620

721
/// We use a stack for detecting cycles. Each stack slot contains:
822
/// - a goal which is being processed
@@ -31,6 +45,7 @@ pub struct Solver {
3145
pub(super) program: Arc<ProgramEnvironment>,
3246
stack: Vec<StackSlot>,
3347
cycle_strategy: CycleStrategy,
48+
overflow_depth: usize,
3449
}
3550

3651
/// An extension trait for merging `Result`s
@@ -52,11 +67,16 @@ impl<T> MergeWith<T> for Result<T> {
5267
}
5368

5469
impl Solver {
55-
pub fn new(program: &Arc<ProgramEnvironment>, cycle_strategy: CycleStrategy) -> Self {
70+
pub fn new(
71+
program: &Arc<ProgramEnvironment>,
72+
cycle_strategy: CycleStrategy,
73+
overflow_depth: usize
74+
) -> Self {
5675
Solver {
5776
program: program.clone(),
5877
stack: vec![],
5978
cycle_strategy,
79+
overflow_depth,
6080
}
6181
}
6282

@@ -105,6 +125,10 @@ impl Solver {
105125
pub fn solve_reduced_goal(&mut self, goal: FullyReducedGoal) -> Result<Solution> {
106126
debug_heading!("Solver::solve({:?})", goal);
107127

128+
if self.stack.len() > self.overflow_depth {
129+
panic!("overflow depth reached");
130+
}
131+
108132
// If the goal is already on the stack, we found a cycle and indicate it by setting
109133
// `slot.cycle = true`. If there is no cached answer, we can't make any more progress
110134
// and return `Err`. If there is one, use this answer.

src/solve/test.rs

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ use chalk_parse;
22
use errors::*;
33
use ir;
44
use lower::*;
5-
use solve::solver::{Solver, CycleStrategy};
5+
use solve::solver::{self, Solver, CycleStrategy};
66
use std::sync::Arc;
77

88
fn parse_and_lower_program(text: &str) -> Result<ir::Program> {
@@ -35,7 +35,7 @@ fn solve_goal(program_text: &str,
3535
assert!(goal_text.ends_with("}"));
3636
let goal = parse_and_lower_goal(&program, &goal_text[1..goal_text.len()-1]).unwrap();
3737

38-
let mut solver = Solver::new(&env, CycleStrategy::Tabling);
38+
let mut solver = Solver::new(&env, CycleStrategy::Tabling, solver::get_overflow_depth());
3939
let goal = ir::InEnvironment::new(&ir::Environment::new(), *goal);
4040
let result = match solver.solve_closed_goal(goal) {
4141
Ok(v) => format!("{}", v),
@@ -349,6 +349,30 @@ fn multiple_ambiguous_cycles() {
349349
}
350350
}
351351

352+
#[test]
353+
#[should_panic]
354+
fn overflow() {
355+
test! {
356+
program {
357+
trait Q { }
358+
struct Z { }
359+
struct G<X>
360+
struct S<X>
361+
362+
impl Q for Z { }
363+
impl<X> Q for G<X> where X: Q { }
364+
impl<X> Q for S<X> where X: Q, S<G<X>>: Q { }
365+
}
366+
367+
// Will try to prove S<G<Z>>: Q then S<G<G<Z>>>: Q etc ad infinitum
368+
goal {
369+
S<Z>: Q
370+
} yields {
371+
""
372+
}
373+
}
374+
}
375+
352376
#[test]
353377
fn normalize_basic() {
354378
test! {

0 commit comments

Comments
 (0)