Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/hir/src/term_search.rs')
-rw-r--r--crates/hir/src/term_search.rs47
1 files changed, 35 insertions, 12 deletions
diff --git a/crates/hir/src/term_search.rs b/crates/hir/src/term_search.rs
index 93e7300491..5c5ddae19e 100644
--- a/crates/hir/src/term_search.rs
+++ b/crates/hir/src/term_search.rs
@@ -127,6 +127,13 @@ impl LookupTable {
self.types_wishlist.insert(ty.clone());
}
+ // Collapse suggestions if there are many
+ if let Some(res) = &res {
+ if res.len() > self.many_threshold {
+ return Some(vec![Expr::Many(ty.clone())]);
+ }
+ }
+
res
}
@@ -158,6 +165,13 @@ impl LookupTable {
self.types_wishlist.insert(ty.clone());
}
+ // Collapse suggestions if there are many
+ if let Some(res) = &res {
+ if res.len() > self.many_threshold {
+ return Some(vec![Expr::Many(ty.clone())]);
+ }
+ }
+
res
}
@@ -255,13 +269,13 @@ pub struct TermSearchConfig {
pub enable_borrowcheck: bool,
/// Indicate when to squash multiple trees to `Many` as there are too many to keep track
pub many_alternatives_threshold: usize,
- /// Depth of the search eg. number of cycles to run
- pub depth: usize,
+ /// Fuel for term search in "units of work"
+ pub fuel: u64,
}
impl Default for TermSearchConfig {
fn default() -> Self {
- Self { enable_borrowcheck: true, many_alternatives_threshold: 1, depth: 6 }
+ Self { enable_borrowcheck: true, many_alternatives_threshold: 1, fuel: 400 }
}
}
@@ -280,8 +294,7 @@ impl Default for TermSearchConfig {
/// transformation tactics. For example functions take as from set of types (arguments) to some
/// type (return type). Other transformations include methods on type, type constructors and
/// projections to struct fields (field access).
-/// 3. Once we manage to find path to type we are interested in we continue for single round to see
-/// if we can find more paths that take us to the `goal` type.
+/// 3. If we run out of fuel (term search takes too long) we stop iterating.
/// 4. Return all the paths (type trees) that take us to the `goal` type.
///
/// Note that there are usually more ways we can get to the `goal` type but some are discarded to
@@ -297,21 +310,31 @@ pub fn term_search<DB: HirDatabase>(ctx: &TermSearchCtx<'_, DB>) -> Vec<Expr> {
});
let mut lookup = LookupTable::new(ctx.config.many_alternatives_threshold, ctx.goal.clone());
+ let fuel = std::cell::Cell::new(ctx.config.fuel);
+
+ let should_continue = &|| {
+ let remaining = fuel.get();
+ fuel.set(remaining.saturating_sub(1));
+ if remaining == 0 {
+ tracing::debug!("fuel exhausted");
+ }
+ remaining > 0
+ };
// Try trivial tactic first, also populates lookup table
let mut solutions: Vec<Expr> = tactics::trivial(ctx, &defs, &mut lookup).collect();
// Use well known types tactic before iterations as it does not depend on other tactics
solutions.extend(tactics::famous_types(ctx, &defs, &mut lookup));
- for _ in 0..ctx.config.depth {
+ while should_continue() {
lookup.new_round();
- solutions.extend(tactics::type_constructor(ctx, &defs, &mut lookup));
- solutions.extend(tactics::free_function(ctx, &defs, &mut lookup));
- solutions.extend(tactics::impl_method(ctx, &defs, &mut lookup));
- solutions.extend(tactics::struct_projection(ctx, &defs, &mut lookup));
- solutions.extend(tactics::impl_static_method(ctx, &defs, &mut lookup));
- solutions.extend(tactics::make_tuple(ctx, &defs, &mut lookup));
+ solutions.extend(tactics::type_constructor(ctx, &defs, &mut lookup, should_continue));
+ solutions.extend(tactics::free_function(ctx, &defs, &mut lookup, should_continue));
+ solutions.extend(tactics::impl_method(ctx, &defs, &mut lookup, should_continue));
+ solutions.extend(tactics::struct_projection(ctx, &defs, &mut lookup, should_continue));
+ solutions.extend(tactics::impl_static_method(ctx, &defs, &mut lookup, should_continue));
+ solutions.extend(tactics::make_tuple(ctx, &defs, &mut lookup, should_continue));
// Discard not interesting `ScopeDef`s for speedup
for def in lookup.exhausted_scopedefs() {