Skip to content

Commit ea0ee8e

Browse files
bors[bot]matklad
andauthored
Merge #2818
2818: Don't panic if chalk panics r=matklad a=matklad r? @flodiebold Trying to paper-over panicking chalk. Not sure if this'll make situation better or worse, but I hope it'll be better, as we won't be tearing down type-inference as a whole Co-authored-by: Aleksey Kladov <aleksey.kladov@gmail.com>
2 parents 7ea7de3 + 5654387 commit ea0ee8e

File tree

1 file changed

+35
-9
lines changed

1 file changed

+35
-9
lines changed

crates/ra_hir_ty/src/traits.rs

Lines changed: 35 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
//! Trait solving using Chalk.
2-
use std::sync::{Arc, Mutex};
2+
use std::{
3+
panic,
4+
sync::{Arc, Mutex},
5+
};
36

47
use chalk_ir::cast::Cast;
58
use hir_def::{expr::ExprId, DefWithBodyId, ImplId, TraitId, TypeAliasId};
6-
use log::debug;
7-
use ra_db::{impl_intern_key, salsa, CrateId};
9+
use ra_db::{impl_intern_key, salsa, Canceled, CrateId};
810
use ra_prof::profile;
911
use rustc_hash::FxHashSet;
1012

@@ -39,16 +41,36 @@ impl TraitSolver {
3941
goal: &chalk_ir::UCanonical<chalk_ir::InEnvironment<chalk_ir::Goal<TypeFamily>>>,
4042
) -> Option<chalk_solve::Solution<TypeFamily>> {
4143
let context = ChalkContext { db, krate: self.krate };
42-
debug!("solve goal: {:?}", goal);
44+
log::debug!("solve goal: {:?}", goal);
4345
let mut solver = match self.inner.lock() {
4446
Ok(it) => it,
4547
// Our cancellation works via unwinding, but, as chalk is not
4648
// panic-safe, we need to make sure to propagate the cancellation.
4749
// Ideally, we should also make chalk panic-safe.
4850
Err(_) => ra_db::Canceled::throw(),
4951
};
50-
let solution = solver.solve(&context, goal);
51-
debug!("solve({:?}) => {:?}", goal, solution);
52+
53+
let solution = panic::catch_unwind({
54+
let solver = panic::AssertUnwindSafe(&mut solver);
55+
let context = panic::AssertUnwindSafe(&context);
56+
move || solver.0.solve(context.0, goal)
57+
});
58+
59+
let solution = match solution {
60+
Ok(it) => it,
61+
Err(err) => {
62+
if err.downcast_ref::<Canceled>().is_some() {
63+
panic::resume_unwind(err)
64+
} else {
65+
log::error!("chalk panicked :-(");
66+
// Reset the solver, as it is not panic-safe.
67+
*solver = create_chalk_solver();
68+
None
69+
}
70+
}
71+
};
72+
73+
log::debug!("solve({:?}) => {:?}", goal, solution);
5274
solution
5375
}
5476
}
@@ -70,9 +92,13 @@ pub(crate) fn trait_solver_query(
7092
) -> TraitSolver {
7193
db.salsa_runtime().report_untracked_read();
7294
// krate parameter is just so we cache a unique solver per crate
95+
log::debug!("Creating new solver for crate {:?}", krate);
96+
TraitSolver { krate, inner: Arc::new(Mutex::new(create_chalk_solver())) }
97+
}
98+
99+
fn create_chalk_solver() -> chalk_solve::Solver<TypeFamily> {
73100
let solver_choice = chalk_solve::SolverChoice::SLG { max_size: CHALK_SOLVER_MAX_SIZE };
74-
debug!("Creating new solver for crate {:?}", krate);
75-
TraitSolver { krate, inner: Arc::new(Mutex::new(solver_choice.into_solver())) }
101+
solver_choice.into_solver()
76102
}
77103

78104
/// Collects impls for the given trait in the whole dependency tree of `krate`.
@@ -181,7 +207,7 @@ pub(crate) fn trait_solve_query(
181207
goal: Canonical<InEnvironment<Obligation>>,
182208
) -> Option<Solution> {
183209
let _p = profile("trait_solve_query");
184-
debug!("trait_solve_query({})", goal.value.value.display(db));
210+
log::debug!("trait_solve_query({})", goal.value.value.display(db));
185211

186212
if let Obligation::Projection(pred) = &goal.value.value {
187213
if let Ty::Bound(_) = &pred.projection_ty.parameters[0] {

0 commit comments

Comments
 (0)