mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-09-28 04:44:57 +00:00
Use unit of work as fuel instead of time
This commit is contained in:
parent
d253617bba
commit
9e1adc76e5
3 changed files with 48 additions and 42 deletions
|
@ -1,7 +1,5 @@
|
||||||
//! Term search
|
//! Term search
|
||||||
|
|
||||||
use std::time::{Duration, Instant};
|
|
||||||
|
|
||||||
use hir_def::type_ref::Mutability;
|
use hir_def::type_ref::Mutability;
|
||||||
use hir_ty::db::HirDatabase;
|
use hir_ty::db::HirDatabase;
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
|
@ -271,20 +269,13 @@ pub struct TermSearchConfig {
|
||||||
pub enable_borrowcheck: bool,
|
pub enable_borrowcheck: bool,
|
||||||
/// Indicate when to squash multiple trees to `Many` as there are too many to keep track
|
/// Indicate when to squash multiple trees to `Many` as there are too many to keep track
|
||||||
pub many_alternatives_threshold: usize,
|
pub many_alternatives_threshold: usize,
|
||||||
/// Depth of the search i.e. number of cycles to run
|
/// Fuel for term search
|
||||||
pub depth: usize,
|
pub fuel: u64,
|
||||||
/// Time fuel for term search
|
|
||||||
pub fuel: Option<Duration>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for TermSearchConfig {
|
impl Default for TermSearchConfig {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
Self { enable_borrowcheck: true, many_alternatives_threshold: 1, fuel: 400 }
|
||||||
enable_borrowcheck: true,
|
|
||||||
many_alternatives_threshold: 1,
|
|
||||||
depth: 5,
|
|
||||||
fuel: Some(Duration::from_millis(100)),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -319,40 +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 mut lookup = LookupTable::new(ctx.config.many_alternatives_threshold, ctx.goal.clone());
|
||||||
let start = Instant::now();
|
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
|
// Try trivial tactic first, also populates lookup table
|
||||||
let mut solutions: Vec<Expr> = tactics::trivial(ctx, &defs, &mut lookup).collect();
|
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
|
// Use well known types tactic before iterations as it does not depend on other tactics
|
||||||
solutions.extend(tactics::famous_types(ctx, &defs, &mut lookup));
|
solutions.extend(tactics::famous_types(ctx, &defs, &mut lookup));
|
||||||
|
|
||||||
for _ in 0..ctx.config.depth {
|
while should_continue() {
|
||||||
lookup.new_round();
|
lookup.new_round();
|
||||||
|
|
||||||
if ctx.config.fuel.is_some_and(|timeout| start.elapsed() > timeout) {
|
solutions.extend(tactics::type_constructor(ctx, &defs, &mut lookup, should_continue));
|
||||||
break;
|
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::type_constructor(ctx, &defs, &mut lookup));
|
solutions.extend(tactics::struct_projection(ctx, &defs, &mut lookup, should_continue));
|
||||||
if ctx.config.fuel.is_some_and(|timeout| start.elapsed() > timeout) {
|
solutions.extend(tactics::impl_static_method(ctx, &defs, &mut lookup, should_continue));
|
||||||
break;
|
solutions.extend(tactics::make_tuple(ctx, &defs, &mut lookup, should_continue));
|
||||||
}
|
|
||||||
solutions.extend(tactics::free_function(ctx, &defs, &mut lookup));
|
|
||||||
if ctx.config.fuel.is_some_and(|timeout| start.elapsed() > timeout) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
solutions.extend(tactics::impl_method(ctx, &defs, &mut lookup));
|
|
||||||
if ctx.config.fuel.is_some_and(|timeout| start.elapsed() > timeout) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
solutions.extend(tactics::struct_projection(ctx, &defs, &mut lookup));
|
|
||||||
if ctx.config.fuel.is_some_and(|timeout| start.elapsed() > timeout) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
solutions.extend(tactics::impl_static_method(ctx, &defs, &mut lookup));
|
|
||||||
if ctx.config.fuel.is_some_and(|timeout| start.elapsed() > timeout) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
solutions.extend(tactics::make_tuple(ctx, &defs, &mut lookup));
|
|
||||||
|
|
||||||
// Discard not interesting `ScopeDef`s for speedup
|
// Discard not interesting `ScopeDef`s for speedup
|
||||||
for def in lookup.exhausted_scopedefs() {
|
for def in lookup.exhausted_scopedefs() {
|
||||||
|
|
|
@ -101,12 +101,14 @@ pub(super) fn type_constructor<'a, DB: HirDatabase>(
|
||||||
ctx: &'a TermSearchCtx<'a, DB>,
|
ctx: &'a TermSearchCtx<'a, DB>,
|
||||||
defs: &'a FxHashSet<ScopeDef>,
|
defs: &'a FxHashSet<ScopeDef>,
|
||||||
lookup: &'a mut LookupTable,
|
lookup: &'a mut LookupTable,
|
||||||
|
should_continue: &'a dyn std::ops::Fn() -> bool,
|
||||||
) -> impl Iterator<Item = Expr> + 'a {
|
) -> impl Iterator<Item = Expr> + 'a {
|
||||||
let db = ctx.sema.db;
|
let db = ctx.sema.db;
|
||||||
let module = ctx.scope.module();
|
let module = ctx.scope.module();
|
||||||
fn variant_helper(
|
fn variant_helper(
|
||||||
db: &dyn HirDatabase,
|
db: &dyn HirDatabase,
|
||||||
lookup: &mut LookupTable,
|
lookup: &mut LookupTable,
|
||||||
|
should_continue: &dyn std::ops::Fn() -> bool,
|
||||||
parent_enum: Enum,
|
parent_enum: Enum,
|
||||||
variant: Variant,
|
variant: Variant,
|
||||||
config: &TermSearchConfig,
|
config: &TermSearchConfig,
|
||||||
|
@ -152,6 +154,7 @@ pub(super) fn type_constructor<'a, DB: HirDatabase>(
|
||||||
.chain((non_default_type_params_len == 0).then_some(Vec::new()));
|
.chain((non_default_type_params_len == 0).then_some(Vec::new()));
|
||||||
|
|
||||||
generic_params
|
generic_params
|
||||||
|
.filter(|_| should_continue())
|
||||||
.filter_map(move |generics| {
|
.filter_map(move |generics| {
|
||||||
// Insert default type params
|
// Insert default type params
|
||||||
let mut g = generics.into_iter();
|
let mut g = generics.into_iter();
|
||||||
|
@ -194,8 +197,14 @@ pub(super) fn type_constructor<'a, DB: HirDatabase>(
|
||||||
defs.iter()
|
defs.iter()
|
||||||
.filter_map(move |def| match def {
|
.filter_map(move |def| match def {
|
||||||
ScopeDef::ModuleDef(ModuleDef::Variant(it)) => {
|
ScopeDef::ModuleDef(ModuleDef::Variant(it)) => {
|
||||||
let variant_exprs =
|
let variant_exprs = variant_helper(
|
||||||
variant_helper(db, lookup, it.parent_enum(db), *it, &ctx.config);
|
db,
|
||||||
|
lookup,
|
||||||
|
should_continue,
|
||||||
|
it.parent_enum(db),
|
||||||
|
*it,
|
||||||
|
&ctx.config,
|
||||||
|
);
|
||||||
if variant_exprs.is_empty() {
|
if variant_exprs.is_empty() {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
@ -213,7 +222,9 @@ pub(super) fn type_constructor<'a, DB: HirDatabase>(
|
||||||
let exprs: Vec<(Type, Vec<Expr>)> = enum_
|
let exprs: Vec<(Type, Vec<Expr>)> = enum_
|
||||||
.variants(db)
|
.variants(db)
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.flat_map(|it| variant_helper(db, lookup, *enum_, it, &ctx.config))
|
.flat_map(|it| {
|
||||||
|
variant_helper(db, lookup, should_continue, *enum_, it, &ctx.config)
|
||||||
|
})
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
if exprs.is_empty() {
|
if exprs.is_empty() {
|
||||||
|
@ -271,6 +282,7 @@ pub(super) fn type_constructor<'a, DB: HirDatabase>(
|
||||||
.chain((non_default_type_params_len == 0).then_some(Vec::new()));
|
.chain((non_default_type_params_len == 0).then_some(Vec::new()));
|
||||||
|
|
||||||
let exprs = generic_params
|
let exprs = generic_params
|
||||||
|
.filter(|_| should_continue())
|
||||||
.filter_map(|generics| {
|
.filter_map(|generics| {
|
||||||
// Insert default type params
|
// Insert default type params
|
||||||
let mut g = generics.into_iter();
|
let mut g = generics.into_iter();
|
||||||
|
@ -349,6 +361,7 @@ pub(super) fn free_function<'a, DB: HirDatabase>(
|
||||||
ctx: &'a TermSearchCtx<'a, DB>,
|
ctx: &'a TermSearchCtx<'a, DB>,
|
||||||
defs: &'a FxHashSet<ScopeDef>,
|
defs: &'a FxHashSet<ScopeDef>,
|
||||||
lookup: &'a mut LookupTable,
|
lookup: &'a mut LookupTable,
|
||||||
|
should_continue: &'a dyn std::ops::Fn() -> bool,
|
||||||
) -> impl Iterator<Item = Expr> + 'a {
|
) -> impl Iterator<Item = Expr> + 'a {
|
||||||
let db = ctx.sema.db;
|
let db = ctx.sema.db;
|
||||||
let module = ctx.scope.module();
|
let module = ctx.scope.module();
|
||||||
|
@ -390,6 +403,7 @@ pub(super) fn free_function<'a, DB: HirDatabase>(
|
||||||
.permutations(non_default_type_params_len);
|
.permutations(non_default_type_params_len);
|
||||||
|
|
||||||
let exprs: Vec<_> = generic_params
|
let exprs: Vec<_> = generic_params
|
||||||
|
.filter(|_| should_continue())
|
||||||
.filter_map(|generics| {
|
.filter_map(|generics| {
|
||||||
// Insert default type params
|
// Insert default type params
|
||||||
let mut g = generics.into_iter();
|
let mut g = generics.into_iter();
|
||||||
|
@ -478,6 +492,7 @@ pub(super) fn impl_method<'a, DB: HirDatabase>(
|
||||||
ctx: &'a TermSearchCtx<'a, DB>,
|
ctx: &'a TermSearchCtx<'a, DB>,
|
||||||
_defs: &'a FxHashSet<ScopeDef>,
|
_defs: &'a FxHashSet<ScopeDef>,
|
||||||
lookup: &'a mut LookupTable,
|
lookup: &'a mut LookupTable,
|
||||||
|
should_continue: &'a dyn std::ops::Fn() -> bool,
|
||||||
) -> impl Iterator<Item = Expr> + 'a {
|
) -> impl Iterator<Item = Expr> + 'a {
|
||||||
let db = ctx.sema.db;
|
let db = ctx.sema.db;
|
||||||
let module = ctx.scope.module();
|
let module = ctx.scope.module();
|
||||||
|
@ -554,6 +569,7 @@ pub(super) fn impl_method<'a, DB: HirDatabase>(
|
||||||
.permutations(non_default_fn_type_params_len);
|
.permutations(non_default_fn_type_params_len);
|
||||||
|
|
||||||
let exprs: Vec<_> = generic_params
|
let exprs: Vec<_> = generic_params
|
||||||
|
.filter(|_| should_continue())
|
||||||
.filter_map(|generics| {
|
.filter_map(|generics| {
|
||||||
// Insert default type params
|
// Insert default type params
|
||||||
let mut g = generics.into_iter();
|
let mut g = generics.into_iter();
|
||||||
|
@ -649,6 +665,7 @@ pub(super) fn struct_projection<'a, DB: HirDatabase>(
|
||||||
ctx: &'a TermSearchCtx<'a, DB>,
|
ctx: &'a TermSearchCtx<'a, DB>,
|
||||||
_defs: &'a FxHashSet<ScopeDef>,
|
_defs: &'a FxHashSet<ScopeDef>,
|
||||||
lookup: &'a mut LookupTable,
|
lookup: &'a mut LookupTable,
|
||||||
|
should_continue: &'a dyn std::ops::Fn() -> bool,
|
||||||
) -> impl Iterator<Item = Expr> + 'a {
|
) -> impl Iterator<Item = Expr> + 'a {
|
||||||
let db = ctx.sema.db;
|
let db = ctx.sema.db;
|
||||||
let module = ctx.scope.module();
|
let module = ctx.scope.module();
|
||||||
|
@ -656,6 +673,7 @@ pub(super) fn struct_projection<'a, DB: HirDatabase>(
|
||||||
.new_types(NewTypesKey::StructProjection)
|
.new_types(NewTypesKey::StructProjection)
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|ty| (ty.clone(), lookup.find(db, &ty).expect("Expr not in lookup")))
|
.map(|ty| (ty.clone(), lookup.find(db, &ty).expect("Expr not in lookup")))
|
||||||
|
.filter(|_| should_continue())
|
||||||
.flat_map(move |(ty, targets)| {
|
.flat_map(move |(ty, targets)| {
|
||||||
ty.fields(db).into_iter().filter_map(move |(field, filed_ty)| {
|
ty.fields(db).into_iter().filter_map(move |(field, filed_ty)| {
|
||||||
if !field.is_visible_from(db, module) {
|
if !field.is_visible_from(db, module) {
|
||||||
|
@ -720,6 +738,7 @@ pub(super) fn impl_static_method<'a, DB: HirDatabase>(
|
||||||
ctx: &'a TermSearchCtx<'a, DB>,
|
ctx: &'a TermSearchCtx<'a, DB>,
|
||||||
_defs: &'a FxHashSet<ScopeDef>,
|
_defs: &'a FxHashSet<ScopeDef>,
|
||||||
lookup: &'a mut LookupTable,
|
lookup: &'a mut LookupTable,
|
||||||
|
should_continue: &'a dyn std::ops::Fn() -> bool,
|
||||||
) -> impl Iterator<Item = Expr> + 'a {
|
) -> impl Iterator<Item = Expr> + 'a {
|
||||||
let db = ctx.sema.db;
|
let db = ctx.sema.db;
|
||||||
let module = ctx.scope.module();
|
let module = ctx.scope.module();
|
||||||
|
@ -728,6 +747,7 @@ pub(super) fn impl_static_method<'a, DB: HirDatabase>(
|
||||||
.clone()
|
.clone()
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.chain(iter::once(ctx.goal.clone()))
|
.chain(iter::once(ctx.goal.clone()))
|
||||||
|
.filter(|_| should_continue())
|
||||||
.flat_map(|ty| {
|
.flat_map(|ty| {
|
||||||
Impl::all_for_type(db, ty.clone()).into_iter().map(move |imp| (ty.clone(), imp))
|
Impl::all_for_type(db, ty.clone()).into_iter().map(move |imp| (ty.clone(), imp))
|
||||||
})
|
})
|
||||||
|
@ -801,6 +821,7 @@ pub(super) fn impl_static_method<'a, DB: HirDatabase>(
|
||||||
.permutations(non_default_fn_type_params_len);
|
.permutations(non_default_fn_type_params_len);
|
||||||
|
|
||||||
let exprs: Vec<_> = generic_params
|
let exprs: Vec<_> = generic_params
|
||||||
|
.filter(|_| should_continue())
|
||||||
.filter_map(|generics| {
|
.filter_map(|generics| {
|
||||||
// Insert default type params
|
// Insert default type params
|
||||||
let mut g = generics.into_iter();
|
let mut g = generics.into_iter();
|
||||||
|
@ -888,6 +909,7 @@ pub(super) fn make_tuple<'a, DB: HirDatabase>(
|
||||||
ctx: &'a TermSearchCtx<'a, DB>,
|
ctx: &'a TermSearchCtx<'a, DB>,
|
||||||
_defs: &'a FxHashSet<ScopeDef>,
|
_defs: &'a FxHashSet<ScopeDef>,
|
||||||
lookup: &'a mut LookupTable,
|
lookup: &'a mut LookupTable,
|
||||||
|
should_continue: &'a dyn std::ops::Fn() -> bool,
|
||||||
) -> impl Iterator<Item = Expr> + 'a {
|
) -> impl Iterator<Item = Expr> + 'a {
|
||||||
let db = ctx.sema.db;
|
let db = ctx.sema.db;
|
||||||
let module = ctx.scope.module();
|
let module = ctx.scope.module();
|
||||||
|
@ -896,6 +918,7 @@ pub(super) fn make_tuple<'a, DB: HirDatabase>(
|
||||||
.types_wishlist()
|
.types_wishlist()
|
||||||
.clone()
|
.clone()
|
||||||
.into_iter()
|
.into_iter()
|
||||||
|
.filter(|_| should_continue())
|
||||||
.filter(|ty| ty.is_tuple())
|
.filter(|ty| ty.is_tuple())
|
||||||
.filter_map(move |ty| {
|
.filter_map(move |ty| {
|
||||||
// Double check to not contain unknown
|
// Double check to not contain unknown
|
||||||
|
@ -915,6 +938,7 @@ pub(super) fn make_tuple<'a, DB: HirDatabase>(
|
||||||
let exprs: Vec<Expr> = param_exprs
|
let exprs: Vec<Expr> = param_exprs
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.multi_cartesian_product()
|
.multi_cartesian_product()
|
||||||
|
.filter(|_| should_continue())
|
||||||
.map(|params| {
|
.map(|params| {
|
||||||
let tys: Vec<Type> = params.iter().map(|it| it.ty(db)).collect();
|
let tys: Vec<Type> = params.iter().map(|it| it.ty(db)).collect();
|
||||||
let tuple_ty = Type::new_tuple(module.krate().into(), &tys);
|
let tuple_ty = Type::new_tuple(module.krate().into(), &tys);
|
||||||
|
|
|
@ -353,7 +353,7 @@ pub(crate) fn complete_expr(acc: &mut Completions, ctx: &CompletionContext<'_>)
|
||||||
config: hir::term_search::TermSearchConfig {
|
config: hir::term_search::TermSearchConfig {
|
||||||
enable_borrowcheck: false,
|
enable_borrowcheck: false,
|
||||||
many_alternatives_threshold: 1,
|
many_alternatives_threshold: 1,
|
||||||
depth: 3,
|
fuel: 200,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue