11//! Trait solving using Chalk.
2- use std:: sync:: { Arc , Mutex } ;
2+ use std:: {
3+ panic,
4+ sync:: { Arc , Mutex } ,
5+ } ;
36
47use chalk_ir:: cast:: Cast ;
58use 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 } ;
810use ra_prof:: profile;
911use 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