From 7744cd41e2ad79c1b36d3d9fccd3bc0dbfd9e2d9 Mon Sep 17 00:00:00 2001 From: Florian Diebold Date: Tue, 7 May 2019 17:35:45 +0200 Subject: Reduce Chalk max_size parameter, add test for slow case --- crates/ra_hir/src/ty/tests.rs | 29 +++++++++++++++++++++++++++++ crates/ra_hir/src/ty/traits.rs | 9 ++++++++- crates/ra_hir/src/ty/traits/chalk.rs | 7 +++++-- 3 files changed, 42 insertions(+), 3 deletions(-) (limited to 'crates/ra_hir') diff --git a/crates/ra_hir/src/ty/tests.rs b/crates/ra_hir/src/ty/tests.rs index f0793bfb4..6f8d8fa49 100644 --- a/crates/ra_hir/src/ty/tests.rs +++ b/crates/ra_hir/src/ty/tests.rs @@ -2581,6 +2581,35 @@ fn test() { foo.call()<|>; } ); } +#[test] +fn method_resolution_slow() { + // this can get quite slow if we set the solver size limit too high + let t = type_at( + r#" +//- /main.rs +trait Send {} + +struct S1; impl Send for S1; +struct S2; impl Send for S2; +struct U1; + +trait Trait { fn method(self); } + +struct X1 {} +impl Send for X1 where A: Send, B: Send {} + +struct S {} + +trait Fn {} + +impl Trait for S where C: Fn, B: Send {} + +fn test() { (S {}).method()<|>; } +"#, + ); + assert_eq!(t, "{unknown}"); +} + fn type_at_pos(db: &MockDatabase, pos: FilePosition) -> String { let file = db.parse(pos.file_id); let expr = algo::find_node_at_offset::(file.syntax(), pos.offset).unwrap(); diff --git a/crates/ra_hir/src/ty/traits.rs b/crates/ra_hir/src/ty/traits.rs index 4bbc99f0e..4260f7ef7 100644 --- a/crates/ra_hir/src/ty/traits.rs +++ b/crates/ra_hir/src/ty/traits.rs @@ -14,6 +14,11 @@ mod chalk; pub(crate) type Solver = chalk_solve::Solver; +/// This controls the maximum size of types Chalk considers. If we set this too +/// high, we can run into slow edge cases; if we set it too low, Chalk won't +/// find some solutions. +const CHALK_SOLVER_MAX_SIZE: usize = 2; + #[derive(Debug, Copy, Clone)] struct ChalkContext<'a, DB> { db: &'a DB, @@ -22,7 +27,8 @@ struct ChalkContext<'a, DB> { pub(crate) fn solver(_db: &impl HirDatabase, _krate: Crate) -> Arc> { // krate parameter is just so we cache a unique solver per crate - let solver_choice = chalk_solve::SolverChoice::SLG { max_size: 10 }; + let solver_choice = chalk_solve::SolverChoice::SLG { max_size: CHALK_SOLVER_MAX_SIZE }; + debug!("Creating new solver for crate {:?}", _krate); Arc::new(Mutex::new(solver_choice.into_solver())) } @@ -53,6 +59,7 @@ fn solve( ) -> Option { let context = ChalkContext { db, krate }; let solver = db.solver(krate); + debug!("solve goal: {:?}", goal); let solution = solver.lock().unwrap().solve(&context, goal); debug!("solve({:?}) => {:?}", goal, solution); solution diff --git a/crates/ra_hir/src/ty/traits/chalk.rs b/crates/ra_hir/src/ty/traits/chalk.rs index 7bb6a4f4a..8fa0ba7a5 100644 --- a/crates/ra_hir/src/ty/traits/chalk.rs +++ b/crates/ra_hir/src/ty/traits/chalk.rs @@ -345,11 +345,14 @@ where return Vec::new(); } let trait_ = from_chalk(self.db, trait_id); - self.db + let result: Vec<_> = self + .db .impls_for_trait(self.krate, trait_) .iter() .map(|impl_block| impl_block.to_chalk(self.db)) - .collect() + .collect(); + debug!("impls_for_trait returned {} impls", result.len()); + result } fn impl_provided_for( &self, -- cgit v1.2.3