aboutsummaryrefslogtreecommitdiff
path: root/crates
diff options
context:
space:
mode:
authorAleksey Kladov <[email protected]>2020-01-13 16:15:50 +0000
committerAleksey Kladov <[email protected]>2020-01-13 18:00:42 +0000
commit5654387e775d267a1d51976a022ce25df9d70a9e (patch)
tree8caa433c9c2f84e182cdc29abba3c034b4353db6 /crates
parent7ea7de338f1c8ad1e89600e04570f03c2688c0c0 (diff)
Don't panic if chalk panics
Diffstat (limited to 'crates')
-rw-r--r--crates/ra_hir_ty/src/traits.rs44
1 files changed, 35 insertions, 9 deletions
diff --git a/crates/ra_hir_ty/src/traits.rs b/crates/ra_hir_ty/src/traits.rs
index c4dc857bc..4aabd66dc 100644
--- a/crates/ra_hir_ty/src/traits.rs
+++ b/crates/ra_hir_ty/src/traits.rs
@@ -1,10 +1,12 @@
1//! Trait solving using Chalk. 1//! Trait solving using Chalk.
2use std::sync::{Arc, Mutex}; 2use std::{
3 panic,
4 sync::{Arc, Mutex},
5};
3 6
4use chalk_ir::cast::Cast; 7use chalk_ir::cast::Cast;
5use hir_def::{expr::ExprId, DefWithBodyId, ImplId, TraitId, TypeAliasId}; 8use hir_def::{expr::ExprId, DefWithBodyId, ImplId, TraitId, TypeAliasId};
6use log::debug; 9use ra_db::{impl_intern_key, salsa, Canceled, CrateId};
7use ra_db::{impl_intern_key, salsa, CrateId};
8use ra_prof::profile; 10use ra_prof::profile;
9use rustc_hash::FxHashSet; 11use rustc_hash::FxHashSet;
10 12
@@ -39,7 +41,7 @@ impl TraitSolver {
39 goal: &chalk_ir::UCanonical<chalk_ir::InEnvironment<chalk_ir::Goal<TypeFamily>>>, 41 goal: &chalk_ir::UCanonical<chalk_ir::InEnvironment<chalk_ir::Goal<TypeFamily>>>,
40 ) -> Option<chalk_solve::Solution<TypeFamily>> { 42 ) -> Option<chalk_solve::Solution<TypeFamily>> {
41 let context = ChalkContext { db, krate: self.krate }; 43 let context = ChalkContext { db, krate: self.krate };
42 debug!("solve goal: {:?}", goal); 44 log::debug!("solve goal: {:?}", goal);
43 let mut solver = match self.inner.lock() { 45 let mut solver = match self.inner.lock() {
44 Ok(it) => it, 46 Ok(it) => it,
45 // Our cancellation works via unwinding, but, as chalk is not 47 // Our cancellation works via unwinding, but, as chalk is not
@@ -47,8 +49,28 @@ impl TraitSolver {
47 // Ideally, we should also make chalk panic-safe. 49 // Ideally, we should also make chalk panic-safe.
48 Err(_) => ra_db::Canceled::throw(), 50 Err(_) => ra_db::Canceled::throw(),
49 }; 51 };
50 let solution = solver.solve(&context, goal); 52
51 debug!("solve({:?}) => {:?}", goal, solution); 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);
52 solution 74 solution
53 } 75 }
54} 76}
@@ -70,9 +92,13 @@ pub(crate) fn trait_solver_query(
70) -> TraitSolver { 92) -> TraitSolver {
71 db.salsa_runtime().report_untracked_read(); 93 db.salsa_runtime().report_untracked_read();
72 // krate parameter is just so we cache a unique solver per crate 94 // 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
99fn create_chalk_solver() -> chalk_solve::Solver<TypeFamily> {
73 let solver_choice = chalk_solve::SolverChoice::SLG { max_size: CHALK_SOLVER_MAX_SIZE }; 100 let solver_choice = chalk_solve::SolverChoice::SLG { max_size: CHALK_SOLVER_MAX_SIZE };
74 debug!("Creating new solver for crate {:?}", krate); 101 solver_choice.into_solver()
75 TraitSolver { krate, inner: Arc::new(Mutex::new(solver_choice.into_solver())) }
76} 102}
77 103
78/// Collects impls for the given trait in the whole dependency tree of `krate`. 104/// Collects impls for the given trait in the whole dependency tree of `krate`.
@@ -181,7 +207,7 @@ pub(crate) fn trait_solve_query(
181 goal: Canonical<InEnvironment<Obligation>>, 207 goal: Canonical<InEnvironment<Obligation>>,
182) -> Option<Solution> { 208) -> Option<Solution> {
183 let _p = profile("trait_solve_query"); 209 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));
185 211
186 if let Obligation::Projection(pred) = &goal.value.value { 212 if let Obligation::Projection(pred) = &goal.value.value {
187 if let Ty::Bound(_) = &pred.projection_ty.parameters[0] { 213 if let Ty::Bound(_) = &pred.projection_ty.parameters[0] {