11//! Term search
22
3+ use std:: time:: { Duration , Instant } ;
4+
35use hir_def:: type_ref:: Mutability ;
46use hir_ty:: db:: HirDatabase ;
57use itertools:: Itertools ;
@@ -190,11 +192,11 @@ impl LookupTable {
190192 }
191193 None => {
192194 self . data . insert ( ty. clone ( ) , AlternativeExprs :: new ( self . many_threshold , exprs) ) ;
195+ for it in self . new_types . values_mut ( ) {
196+ it. push ( ty. clone ( ) ) ;
197+ }
193198 }
194199 }
195- for it in self . new_types . values_mut ( ) {
196- it. push ( ty. clone ( ) ) ;
197- }
198200 }
199201
200202 /// Iterate all the reachable types
@@ -269,13 +271,20 @@ pub struct TermSearchConfig {
269271 pub enable_borrowcheck : bool ,
270272 /// Indicate when to squash multiple trees to `Many` as there are too many to keep track
271273 pub many_alternatives_threshold : usize ,
272- /// Depth of the search eg . number of cycles to run
274+ /// Depth of the search i.e . number of cycles to run
273275 pub depth : usize ,
276+ /// Time fuel for term search
277+ pub fuel : Option < Duration > ,
274278}
275279
276280impl Default for TermSearchConfig {
277281 fn default ( ) -> Self {
278- Self { enable_borrowcheck : true , many_alternatives_threshold : 1 , depth : 6 }
282+ Self {
283+ enable_borrowcheck : true ,
284+ many_alternatives_threshold : 1 ,
285+ depth : 5 ,
286+ fuel : Some ( Duration :: from_millis ( 100 ) ) ,
287+ }
279288 }
280289}
281290
@@ -294,8 +303,7 @@ impl Default for TermSearchConfig {
294303/// transformation tactics. For example functions take as from set of types (arguments) to some
295304/// type (return type). Other transformations include methods on type, type constructors and
296305/// projections to struct fields (field access).
297- /// 3. Once we manage to find path to type we are interested in we continue for single round to see
298- /// if we can find more paths that take us to the `goal` type.
306+ /// 3. If we run out of fuel (term search takes too long) we stop iterating.
299307/// 4. Return all the paths (type trees) that take us to the `goal` type.
300308///
301309/// Note that there are usually more ways we can get to the `goal` type but some are discarded to
@@ -311,6 +319,7 @@ pub fn term_search<DB: HirDatabase>(ctx: &TermSearchCtx<'_, DB>) -> Vec<Expr> {
311319 } ) ;
312320
313321 let mut lookup = LookupTable :: new ( ctx. config . many_alternatives_threshold , ctx. goal . clone ( ) ) ;
322+ let start = Instant :: now ( ) ;
314323
315324 // Try trivial tactic first, also populates lookup table
316325 let mut solutions: Vec < Expr > = tactics:: trivial ( ctx, & defs, & mut lookup) . collect ( ) ;
@@ -320,11 +329,29 @@ pub fn term_search<DB: HirDatabase>(ctx: &TermSearchCtx<'_, DB>) -> Vec<Expr> {
320329 for _ in 0 ..ctx. config . depth {
321330 lookup. new_round ( ) ;
322331
332+ if ctx. config . fuel . is_some_and ( |timeout| start. elapsed ( ) > timeout) {
333+ break ;
334+ }
323335 solutions. extend ( tactics:: type_constructor ( ctx, & defs, & mut lookup) ) ;
336+ if ctx. config . fuel . is_some_and ( |timeout| start. elapsed ( ) > timeout) {
337+ break ;
338+ }
324339 solutions. extend ( tactics:: free_function ( ctx, & defs, & mut lookup) ) ;
340+ if ctx. config . fuel . is_some_and ( |timeout| start. elapsed ( ) > timeout) {
341+ break ;
342+ }
325343 solutions. extend ( tactics:: impl_method ( ctx, & defs, & mut lookup) ) ;
344+ if ctx. config . fuel . is_some_and ( |timeout| start. elapsed ( ) > timeout) {
345+ break ;
346+ }
326347 solutions. extend ( tactics:: struct_projection ( ctx, & defs, & mut lookup) ) ;
348+ if ctx. config . fuel . is_some_and ( |timeout| start. elapsed ( ) > timeout) {
349+ break ;
350+ }
327351 solutions. extend ( tactics:: impl_static_method ( ctx, & defs, & mut lookup) ) ;
352+ if ctx. config . fuel . is_some_and ( |timeout| start. elapsed ( ) > timeout) {
353+ break ;
354+ }
328355 solutions. extend ( tactics:: make_tuple ( ctx, & defs, & mut lookup) ) ;
329356
330357 // Discard not interesting `ScopeDef`s for speedup
0 commit comments