diff options
author | Aleksey Kladov <[email protected]> | 2020-01-13 16:15:50 +0000 |
---|---|---|
committer | Aleksey Kladov <[email protected]> | 2020-01-13 18:00:42 +0000 |
commit | 5654387e775d267a1d51976a022ce25df9d70a9e (patch) | |
tree | 8caa433c9c2f84e182cdc29abba3c034b4353db6 /crates | |
parent | 7ea7de338f1c8ad1e89600e04570f03c2688c0c0 (diff) |
Don't panic if chalk panics
Diffstat (limited to 'crates')
-rw-r--r-- | crates/ra_hir_ty/src/traits.rs | 44 |
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. |
2 | use std::sync::{Arc, Mutex}; | 2 | use std::{ |
3 | panic, | ||
4 | sync::{Arc, Mutex}, | ||
5 | }; | ||
3 | 6 | ||
4 | use chalk_ir::cast::Cast; | 7 | use chalk_ir::cast::Cast; |
5 | use hir_def::{expr::ExprId, DefWithBodyId, ImplId, TraitId, TypeAliasId}; | 8 | use hir_def::{expr::ExprId, DefWithBodyId, ImplId, TraitId, TypeAliasId}; |
6 | use log::debug; | 9 | use ra_db::{impl_intern_key, salsa, Canceled, CrateId}; |
7 | use ra_db::{impl_intern_key, salsa, CrateId}; | ||
8 | use ra_prof::profile; | 10 | use ra_prof::profile; |
9 | use rustc_hash::FxHashSet; | 11 | use 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 | |||
99 | fn 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] { |