@@ -19,48 +19,61 @@ enum NewTypesKey {
19
19
StructProjection ,
20
20
}
21
21
22
+ /// Helper enum to squash big number of alternative trees into `Many` variant as there is too many
23
+ /// to take into account.
22
24
#[ derive( Debug ) ]
23
25
enum AlternativeTrees {
26
+ /// There are few trees, so we keep track of them all
24
27
Few ( FxHashSet < TypeTree > ) ,
25
- Many ( Type ) ,
28
+ /// There are too many trees to keep track of
29
+ Many ,
26
30
}
27
31
28
32
impl 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 {
34
39
let mut it = AlternativeTrees :: Few ( Default :: default ( ) ) ;
35
- it. extend_with_threshold ( threshold, ty , trees) ;
40
+ it. extend_with_threshold ( threshold, trees) ;
36
41
it
37
42
}
38
43
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 > {
40
49
match self {
41
50
AlternativeTrees :: Few ( trees) => trees. iter ( ) . cloned ( ) . collect ( ) ,
42
- AlternativeTrees :: Many ( ty ) => vec ! [ TypeTree :: Many ( ty. clone( ) ) ] ,
51
+ AlternativeTrees :: Many => vec ! [ TypeTree :: Many ( ty. clone( ) ) ] ,
43
52
}
44
53
}
45
54
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 (
47
61
& mut self ,
48
62
threshold : usize ,
49
- ty : Type ,
50
63
mut trees : impl Iterator < Item = TypeTree > ,
51
64
) {
52
65
match self {
53
66
AlternativeTrees :: Few ( tts) => {
54
67
while let Some ( it) = trees. next ( ) {
55
68
if tts. len ( ) > threshold {
56
- * self = AlternativeTrees :: Many ( ty ) ;
69
+ * self = AlternativeTrees :: Many ;
57
70
break ;
58
71
}
59
72
60
73
tts. insert ( it) ;
61
74
}
62
75
}
63
- AlternativeTrees :: Many ( _ ) => ( ) ,
76
+ AlternativeTrees :: Many => ( ) ,
64
77
}
65
78
}
66
79
}
@@ -106,7 +119,7 @@ impl LookupTable {
106
119
self . data
107
120
. iter ( )
108
121
. find ( |( t, _) | t. could_unify_with_deeply ( db, ty) )
109
- . map ( |( _ , tts) | tts. trees ( ) )
122
+ . map ( |( t , tts) | tts. trees ( t ) )
110
123
}
111
124
112
125
/// Same as find but automatically creates shared reference of types in the lookup
@@ -117,15 +130,15 @@ impl LookupTable {
117
130
self . data
118
131
. iter ( )
119
132
. find ( |( t, _) | t. could_unify_with_deeply ( db, ty) )
120
- . map ( |( _ , tts) | tts. trees ( ) )
133
+ . map ( |( t , tts) | tts. trees ( t ) )
121
134
. or_else ( || {
122
135
self . data
123
136
. iter ( )
124
137
. find ( |( t, _) | {
125
138
Type :: reference ( t, Mutability :: Shared ) . could_unify_with_deeply ( db, & ty)
126
139
} )
127
- . map ( |( _ , tts) | {
128
- tts. trees ( )
140
+ . map ( |( t , tts) | {
141
+ tts. trees ( t )
129
142
. into_iter ( )
130
143
. map ( |tt| TypeTree :: Reference ( Box :: new ( tt) ) )
131
144
. collect ( )
@@ -140,12 +153,9 @@ impl LookupTable {
140
153
/// but they clearly do not unify themselves.
141
154
fn insert ( & mut self , ty : Type , trees : impl Iterator < Item = TypeTree > ) {
142
155
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) ,
144
157
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) ) ;
149
159
for it in self . new_types . values_mut ( ) {
150
160
it. push ( ty. clone ( ) ) ;
151
161
}
@@ -206,6 +216,7 @@ impl LookupTable {
206
216
}
207
217
208
218
/// Context for the `term_search` function
219
+ #[ derive( Debug ) ]
209
220
pub struct TermSearchCtx < ' a , DB : HirDatabase > {
210
221
/// Semantics for the program
211
222
pub sema : & ' a Semantics < ' a , DB > ,
@@ -230,7 +241,7 @@ pub struct TermSearchConfig {
230
241
231
242
impl Default for TermSearchConfig {
232
243
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 }
234
245
}
235
246
}
236
247
@@ -239,9 +250,7 @@ impl Default for TermSearchConfig {
239
250
/// Search for terms (expressions) that unify with the `goal` type.
240
251
///
241
252
/// # 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
245
254
///
246
255
/// Internally this function uses Breadth First Search to find path to `goal` type.
247
256
/// The general idea is following:
@@ -258,7 +267,7 @@ impl Default for TermSearchConfig {
258
267
/// Note that there are usually more ways we can get to the `goal` type but some are discarded to
259
268
/// reduce the memory consumption. It is also unlikely anyone is willing ti browse through
260
269
/// 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 > {
262
271
let module = ctx. scope . module ( ) ;
263
272
let mut defs = FxHashSet :: default ( ) ;
264
273
defs. insert ( ScopeDef :: ModuleDef ( ModuleDef :: Module ( module) ) ) ;
@@ -270,33 +279,24 @@ pub fn term_search<DB: HirDatabase>(ctx: TermSearchCtx<'_, DB>) -> Vec<TypeTree>
270
279
let mut lookup = LookupTable :: new ( ) ;
271
280
272
281
// 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 ( ) ;
274
283
// 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) ) ;
278
285
279
286
for _ in 0 ..ctx. config . depth {
280
287
lookup. new_round ( ) ;
281
288
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) ) ;
294
294
295
295
// Discard not interesting `ScopeDef`s for speedup
296
296
for def in lookup. exhausted_scopedefs ( ) {
297
297
defs. remove ( def) ;
298
298
}
299
299
}
300
300
301
- solutions. into_iter ( ) . unique ( ) . collect ( )
301
+ solutions. into_iter ( ) . filter ( |it| !it . is_many ( ) ) . unique ( ) . collect ( )
302
302
}
0 commit comments