@@ -19,48 +19,61 @@ enum NewTypesKey {
1919 StructProjection ,
2020}
2121
22+ /// Helper enum to squash big number of alternative trees into `Many` variant as there is too many
23+ /// to take into account.
2224#[ derive( Debug ) ]
2325enum AlternativeTrees {
26+ /// There are few trees, so we keep track of them all
2427 Few ( FxHashSet < TypeTree > ) ,
25- Many ( Type ) ,
28+ /// There are too many trees to keep track of
29+ Many ,
2630}
2731
2832impl AlternativeTrees {
29- pub fn new (
30- threshold : usize ,
31- ty : Type ,
32- trees : impl Iterator < Item = TypeTree > ,
33- ) -> AlternativeTrees {
33+ /// Construct alternative trees
34+ ///
35+ /// # Arguments
36+ /// `threshold` - threshold value for many trees (more than that is many)
37+ /// `trees` - trees iterator
38+ fn new ( threshold : usize , trees : impl Iterator < Item = TypeTree > ) -> AlternativeTrees {
3439 let mut it = AlternativeTrees :: Few ( Default :: default ( ) ) ;
35- it. extend_with_threshold ( threshold, ty , trees) ;
40+ it. extend_with_threshold ( threshold, trees) ;
3641 it
3742 }
3843
39- pub fn trees ( & self ) -> Vec < TypeTree > {
44+ /// Get type trees stored in alternative trees (or `TypeTree::Many` in case of many)
45+ ///
46+ /// # Arguments
47+ /// `ty` - Type of trees queried (this is used to give type to `TypeTree::Many`)
48+ fn trees ( & self , ty : & Type ) -> Vec < TypeTree > {
4049 match self {
4150 AlternativeTrees :: Few ( trees) => trees. iter ( ) . cloned ( ) . collect ( ) ,
42- AlternativeTrees :: Many ( ty ) => vec ! [ TypeTree :: Many ( ty. clone( ) ) ] ,
51+ AlternativeTrees :: Many => vec ! [ TypeTree :: Many ( ty. clone( ) ) ] ,
4352 }
4453 }
4554
46- pub fn extend_with_threshold (
55+ /// Extend alternative trees
56+ ///
57+ /// # Arguments
58+ /// `threshold` - threshold value for many trees (more than that is many)
59+ /// `trees` - trees iterator
60+ fn extend_with_threshold (
4761 & mut self ,
4862 threshold : usize ,
49- ty : Type ,
5063 mut trees : impl Iterator < Item = TypeTree > ,
5164 ) {
5265 match self {
5366 AlternativeTrees :: Few ( tts) => {
5467 while let Some ( it) = trees. next ( ) {
5568 if tts. len ( ) > threshold {
56- * self = AlternativeTrees :: Many ( ty ) ;
69+ * self = AlternativeTrees :: Many ;
5770 break ;
5871 }
5972
6073 tts. insert ( it) ;
6174 }
6275 }
63- AlternativeTrees :: Many ( _ ) => ( ) ,
76+ AlternativeTrees :: Many => ( ) ,
6477 }
6578 }
6679}
@@ -106,7 +119,7 @@ impl LookupTable {
106119 self . data
107120 . iter ( )
108121 . find ( |( t, _) | t. could_unify_with_deeply ( db, ty) )
109- . map ( |( _ , tts) | tts. trees ( ) )
122+ . map ( |( t , tts) | tts. trees ( t ) )
110123 }
111124
112125 /// Same as find but automatically creates shared reference of types in the lookup
@@ -117,15 +130,15 @@ impl LookupTable {
117130 self . data
118131 . iter ( )
119132 . find ( |( t, _) | t. could_unify_with_deeply ( db, ty) )
120- . map ( |( _ , tts) | tts. trees ( ) )
133+ . map ( |( t , tts) | tts. trees ( t ) )
121134 . or_else ( || {
122135 self . data
123136 . iter ( )
124137 . find ( |( t, _) | {
125138 Type :: reference ( t, Mutability :: Shared ) . could_unify_with_deeply ( db, & ty)
126139 } )
127- . map ( |( _ , tts) | {
128- tts. trees ( )
140+ . map ( |( t , tts) | {
141+ tts. trees ( t )
129142 . into_iter ( )
130143 . map ( |tt| TypeTree :: Reference ( Box :: new ( tt) ) )
131144 . collect ( )
@@ -140,12 +153,9 @@ impl LookupTable {
140153 /// but they clearly do not unify themselves.
141154 fn insert ( & mut self , ty : Type , trees : impl Iterator < Item = TypeTree > ) {
142155 match self . data . get_mut ( & ty) {
143- Some ( it) => it. extend_with_threshold ( self . many_threshold , ty , trees) ,
156+ Some ( it) => it. extend_with_threshold ( self . many_threshold , trees) ,
144157 None => {
145- self . data . insert (
146- ty. clone ( ) ,
147- AlternativeTrees :: new ( self . many_threshold , ty. clone ( ) , trees) ,
148- ) ;
158+ self . data . insert ( ty. clone ( ) , AlternativeTrees :: new ( self . many_threshold , trees) ) ;
149159 for it in self . new_types . values_mut ( ) {
150160 it. push ( ty. clone ( ) ) ;
151161 }
@@ -206,6 +216,7 @@ impl LookupTable {
206216}
207217
208218/// Context for the `term_search` function
219+ #[ derive( Debug ) ]
209220pub struct TermSearchCtx < ' a , DB : HirDatabase > {
210221 /// Semantics for the program
211222 pub sema : & ' a Semantics < ' a , DB > ,
@@ -230,7 +241,7 @@ pub struct TermSearchConfig {
230241
231242impl Default for TermSearchConfig {
232243 fn default ( ) -> Self {
233- Self { enable_borrowcheck : true , many_alternatives_threshold : 1 , depth : 5 }
244+ Self { enable_borrowcheck : true , many_alternatives_threshold : 1 , depth : 6 }
234245 }
235246}
236247
@@ -239,9 +250,7 @@ impl Default for TermSearchConfig {
239250/// Search for terms (expressions) that unify with the `goal` type.
240251///
241252/// # Arguments
242- /// * `sema` - Semantics for the program
243- /// * `scope` - Semantic scope, captures context for the term search
244- /// * `goal` - Target / expected output type
253+ /// * `ctx` - Context for term search
245254///
246255/// Internally this function uses Breadth First Search to find path to `goal` type.
247256/// The general idea is following:
@@ -258,7 +267,7 @@ impl Default for TermSearchConfig {
258267/// Note that there are usually more ways we can get to the `goal` type but some are discarded to
259268/// reduce the memory consumption. It is also unlikely anyone is willing ti browse through
260269/// thousands of possible responses so we currently take first 10 from every tactic.
261- pub fn term_search < DB : HirDatabase > ( ctx : TermSearchCtx < ' _ , DB > ) -> Vec < TypeTree > {
270+ pub fn term_search < DB : HirDatabase > ( ctx : & TermSearchCtx < ' _ , DB > ) -> Vec < TypeTree > {
262271 let module = ctx. scope . module ( ) ;
263272 let mut defs = FxHashSet :: default ( ) ;
264273 defs. insert ( ScopeDef :: ModuleDef ( ModuleDef :: Module ( module) ) ) ;
@@ -270,33 +279,24 @@ pub fn term_search<DB: HirDatabase>(ctx: TermSearchCtx<'_, DB>) -> Vec<TypeTree>
270279 let mut lookup = LookupTable :: new ( ) ;
271280
272281 // Try trivial tactic first, also populates lookup table
273- let mut solutions: Vec < TypeTree > = tactics:: trivial ( & ctx, & defs, & mut lookup) . collect ( ) ;
282+ let mut solutions: Vec < TypeTree > = tactics:: trivial ( ctx, & defs, & mut lookup) . collect ( ) ;
274283 // Use well known types tactic before iterations as it does not depend on other tactics
275- solutions. extend ( tactics:: famous_types ( & ctx, & defs, & mut lookup) ) ;
276-
277- let mut solution_found = !solutions. is_empty ( ) ;
284+ solutions. extend ( tactics:: famous_types ( ctx, & defs, & mut lookup) ) ;
278285
279286 for _ in 0 ..ctx. config . depth {
280287 lookup. new_round ( ) ;
281288
282- solutions. extend ( tactics:: type_constructor ( & ctx, & defs, & mut lookup) ) ;
283- solutions. extend ( tactics:: free_function ( & ctx, & defs, & mut lookup) ) ;
284- solutions. extend ( tactics:: impl_method ( & ctx, & defs, & mut lookup) ) ;
285- solutions. extend ( tactics:: struct_projection ( & ctx, & defs, & mut lookup) ) ;
286- solutions. extend ( tactics:: impl_static_method ( & ctx, & defs, & mut lookup) ) ;
287-
288- // Break after 1 round after successful solution
289- if solution_found {
290- break ;
291- }
292-
293- solution_found = !solutions. is_empty ( ) ;
289+ solutions. extend ( tactics:: type_constructor ( ctx, & defs, & mut lookup) ) ;
290+ solutions. extend ( tactics:: free_function ( ctx, & defs, & mut lookup) ) ;
291+ solutions. extend ( tactics:: impl_method ( ctx, & defs, & mut lookup) ) ;
292+ solutions. extend ( tactics:: struct_projection ( ctx, & defs, & mut lookup) ) ;
293+ solutions. extend ( tactics:: impl_static_method ( ctx, & defs, & mut lookup) ) ;
294294
295295 // Discard not interesting `ScopeDef`s for speedup
296296 for def in lookup. exhausted_scopedefs ( ) {
297297 defs. remove ( def) ;
298298 }
299299 }
300300
301- solutions. into_iter ( ) . unique ( ) . collect ( )
301+ solutions. into_iter ( ) . filter ( |it| !it . is_many ( ) ) . unique ( ) . collect ( )
302302}
0 commit comments