@@ -12,20 +12,59 @@ pub use type_tree::TypeTree;
1212
1313mod tactics;
1414
15- /// # Maximum amount of variations to take per type
16- ///
17- /// This is to speed up term search as there may be huge amount of variations of arguments for
18- /// function, even when the return type is always the same. The idea is to take first n and call it
19- /// a day.
20- const MAX_VARIATIONS : usize = 10 ;
21-
2215/// Key for lookup table to query new types reached.
2316#[ derive( Debug , Hash , PartialEq , Eq ) ]
2417enum NewTypesKey {
2518 ImplMethod ,
2619 StructProjection ,
2720}
2821
22+ #[ derive( Debug ) ]
23+ enum AlternativeTrees {
24+ Few ( FxHashSet < TypeTree > ) ,
25+ Many ( Type ) ,
26+ }
27+
28+ impl AlternativeTrees {
29+ pub fn new (
30+ threshold : usize ,
31+ ty : Type ,
32+ trees : impl Iterator < Item = TypeTree > ,
33+ ) -> AlternativeTrees {
34+ let mut it = AlternativeTrees :: Few ( Default :: default ( ) ) ;
35+ it. extend_with_threshold ( threshold, ty, trees) ;
36+ it
37+ }
38+
39+ pub fn trees ( & self ) -> Vec < TypeTree > {
40+ match self {
41+ AlternativeTrees :: Few ( trees) => trees. iter ( ) . cloned ( ) . collect ( ) ,
42+ AlternativeTrees :: Many ( ty) => vec ! [ TypeTree :: Many ( ty. clone( ) ) ] ,
43+ }
44+ }
45+
46+ pub fn extend_with_threshold (
47+ & mut self ,
48+ threshold : usize ,
49+ ty : Type ,
50+ mut trees : impl Iterator < Item = TypeTree > ,
51+ ) {
52+ match self {
53+ AlternativeTrees :: Few ( tts) => {
54+ while let Some ( it) = trees. next ( ) {
55+ if tts. len ( ) > threshold {
56+ * self = AlternativeTrees :: Many ( ty) ;
57+ break ;
58+ }
59+
60+ tts. insert ( it) ;
61+ }
62+ }
63+ AlternativeTrees :: Many ( _) => ( ) ,
64+ }
65+ }
66+ }
67+
2968/// # Lookup table for term search
3069///
3170/// Lookup table keeps all the state during term search.
@@ -38,7 +77,7 @@ enum NewTypesKey {
3877#[ derive( Default , Debug ) ]
3978struct LookupTable {
4079 /// All the `TypeTree`s in "value" produce the type of "key"
41- data : FxHashMap < Type , FxHashSet < TypeTree > > ,
80+ data : FxHashMap < Type , AlternativeTrees > ,
4281 /// New types reached since last query by the `NewTypesKey`
4382 new_types : FxHashMap < NewTypesKey , Vec < Type > > ,
4483 /// ScopeDefs that are not interesting any more
@@ -49,6 +88,8 @@ struct LookupTable {
4988 rounds_since_sopedef_hit : FxHashMap < ScopeDef , u32 > ,
5089 /// Types queried but not present
5190 types_wishlist : FxHashSet < Type > ,
91+ /// Threshold to squash trees to `Many`
92+ many_threshold : usize ,
5293}
5394
5495impl LookupTable {
@@ -65,7 +106,7 @@ impl LookupTable {
65106 self . data
66107 . iter ( )
67108 . find ( |( t, _) | t. could_unify_with_deeply ( db, ty) )
68- . map ( |( _, tts) | tts. iter ( ) . cloned ( ) . collect ( ) )
109+ . map ( |( _, tts) | tts. trees ( ) )
69110 }
70111
71112 /// Same as find but automatically creates shared reference of types in the lookup
@@ -76,15 +117,18 @@ impl LookupTable {
76117 self . data
77118 . iter ( )
78119 . find ( |( t, _) | t. could_unify_with_deeply ( db, ty) )
79- . map ( |( _, tts) | tts. iter ( ) . cloned ( ) . collect ( ) )
120+ . map ( |( _, tts) | tts. trees ( ) )
80121 . or_else ( || {
81122 self . data
82123 . iter ( )
83124 . find ( |( t, _) | {
84125 Type :: reference ( t, Mutability :: Shared ) . could_unify_with_deeply ( db, & ty)
85126 } )
86127 . map ( |( _, tts) | {
87- tts. iter ( ) . map ( |tt| TypeTree :: Reference ( Box :: new ( tt. clone ( ) ) ) ) . collect ( )
128+ tts. trees ( )
129+ . into_iter ( )
130+ . map ( |tt| TypeTree :: Reference ( Box :: new ( tt) ) )
131+ . collect ( )
88132 } )
89133 } )
90134 }
@@ -96,9 +140,12 @@ impl LookupTable {
96140 /// but they clearly do not unify themselves.
97141 fn insert ( & mut self , ty : Type , trees : impl Iterator < Item = TypeTree > ) {
98142 match self . data . get_mut ( & ty) {
99- Some ( it) => it. extend ( trees . take ( MAX_VARIATIONS ) ) ,
143+ Some ( it) => it. extend_with_threshold ( self . many_threshold , ty , trees ) ,
100144 None => {
101- self . data . insert ( ty. clone ( ) , trees. take ( MAX_VARIATIONS ) . collect ( ) ) ;
145+ self . data . insert (
146+ ty. clone ( ) ,
147+ AlternativeTrees :: new ( self . many_threshold , ty. clone ( ) , trees) ,
148+ ) ;
102149 for it in self . new_types . values_mut ( ) {
103150 it. push ( ty. clone ( ) ) ;
104151 }
@@ -175,11 +222,15 @@ pub struct TermSearchCtx<'a, DB: HirDatabase> {
175222pub struct TermSearchConfig {
176223 /// Enable borrow checking, this guarantees the outputs of the `term_search` to borrow-check
177224 pub enable_borrowcheck : bool ,
225+ /// Indicate when to squash multiple trees to `Many` as there are too many to keep track
226+ pub many_alternatives_threshold : usize ,
227+ /// Depth of the search eg. number of cycles to run
228+ pub depth : usize ,
178229}
179230
180231impl Default for TermSearchConfig {
181232 fn default ( ) -> Self {
182- Self { enable_borrowcheck : true }
233+ Self { enable_borrowcheck : true , many_alternatives_threshold : 1 , depth : 5 }
183234 }
184235}
185236
@@ -225,7 +276,7 @@ pub fn term_search<DB: HirDatabase>(ctx: TermSearchCtx<'_, DB>) -> Vec<TypeTree>
225276
226277 let mut solution_found = !solutions. is_empty ( ) ;
227278
228- for _ in 0 ..5 {
279+ for _ in 0 ..ctx . config . depth {
229280 lookup. new_round ( ) ;
230281
231282 solutions. extend ( tactics:: type_constructor ( & ctx, & defs, & mut lookup) ) ;
0 commit comments