1
1
//! Look up accessible paths for items.
2
2
use either:: Either ;
3
- use hir:: { AsAssocItem , AssocItem , Crate , MacroDef , Module , ModuleDef , PrefixKind , Semantics } ;
3
+ use hir:: {
4
+ AsAssocItem , AssocItem , Crate , ItemInNs , MacroDef , ModPath , Module , ModuleDef , PathResolution ,
5
+ PrefixKind , Semantics ,
6
+ } ;
4
7
use rustc_hash:: FxHashSet ;
5
8
use syntax:: { ast, AstNode } ;
6
9
@@ -145,7 +148,6 @@ impl ImportAssets {
145
148
prefixed : Option < hir:: PrefixKind > ,
146
149
) -> Vec < ( hir:: ModPath , hir:: ItemInNs ) > {
147
150
let current_crate = self . module_with_candidate . krate ( ) ;
148
- let import_candidate = & self . import_candidate ;
149
151
150
152
let imports_for_candidate_name = match self . name_to_import ( ) {
151
153
NameToImport :: Exact ( exact_name) => {
@@ -157,7 +159,7 @@ impl ImportAssets {
157
159
// and https://rust-lang.zulipchat.com/#narrow/stream/185405-t-compiler.2Fwg-rls-2.2E0/topic/Blanket.20trait.20impls.20lookup
158
160
// for the details
159
161
NameToImport :: Fuzzy ( fuzzy_name) => {
160
- let ( assoc_item_search, limit) = if import_candidate. is_trait_candidate ( ) {
162
+ let ( assoc_item_search, limit) = if self . import_candidate . is_trait_candidate ( ) {
161
163
( AssocItemSearch :: AssocItemsOnly , None )
162
164
} else {
163
165
( AssocItemSearch :: Exclude , Some ( DEFAULT_QUERY_SEARCH_LIMIT ) )
@@ -172,59 +174,108 @@ impl ImportAssets {
172
174
}
173
175
} ;
174
176
175
- let db = sema. db ;
176
- let mut res =
177
- applicable_defs ( import_candidate, current_crate, db, imports_for_candidate_name)
178
- . filter_map ( |candidate| {
179
- let item: hir:: ItemInNs = candidate. clone ( ) . either ( Into :: into, Into :: into) ;
180
-
181
- let item_to_search = if import_candidate. is_trait_candidate ( ) {
182
- let canidate_trait = match candidate {
183
- Either :: Left ( module_def) => {
184
- module_def. as_assoc_item ( db) ?. containing_trait ( db)
185
- }
186
- _ => None ,
187
- } ?;
188
- ModuleDef :: from ( canidate_trait) . into ( )
189
- } else {
190
- item
191
- } ;
192
- let mod_path = if let Some ( prefix_kind) = prefixed {
193
- self . module_with_candidate . find_use_path_prefixed (
194
- db,
195
- item_to_search,
196
- prefix_kind,
197
- )
198
- } else {
199
- self . module_with_candidate . find_use_path ( db, item_to_search)
200
- } ;
201
-
202
- mod_path. zip ( Some ( item) )
203
- } )
204
- . filter ( |( use_path, _) | use_path. len ( ) > 1 )
205
- . collect :: < Vec < _ > > ( ) ;
177
+ let mut res = self
178
+ . applicable_defs ( sema, prefixed, imports_for_candidate_name)
179
+ . filter ( |( use_path, _) | use_path. len ( ) > 1 )
180
+ . collect :: < Vec < _ > > ( ) ;
206
181
res. sort_by_cached_key ( |( path, _) | path. clone ( ) ) ;
207
182
res
208
183
}
184
+
185
+ fn applicable_defs < ' a > (
186
+ & self ,
187
+ sema : & ' a Semantics < RootDatabase > ,
188
+ prefixed : Option < hir:: PrefixKind > ,
189
+ unfiltered_imports : Box < dyn Iterator < Item = Either < ModuleDef , MacroDef > > + ' a > ,
190
+ ) -> Box < dyn Iterator < Item = ( ModPath , ItemInNs ) > + ' a > {
191
+ let current_crate = self . module_with_candidate . krate ( ) ;
192
+ let db = sema. db ;
193
+
194
+ match & self . import_candidate {
195
+ ImportCandidate :: Path ( path_candidate) => path_applicable_defs (
196
+ sema,
197
+ path_candidate,
198
+ unfiltered_imports,
199
+ self . module_with_candidate ,
200
+ prefixed,
201
+ ) ,
202
+ ImportCandidate :: TraitAssocItem ( trait_candidate) => trait_applicable_defs (
203
+ db,
204
+ current_crate,
205
+ trait_candidate,
206
+ true ,
207
+ unfiltered_imports,
208
+ self . module_with_candidate ,
209
+ prefixed,
210
+ ) ,
211
+ ImportCandidate :: TraitMethod ( trait_candidate) => trait_applicable_defs (
212
+ db,
213
+ current_crate,
214
+ trait_candidate,
215
+ false ,
216
+ unfiltered_imports,
217
+ self . module_with_candidate ,
218
+ prefixed,
219
+ ) ,
220
+ }
221
+ }
209
222
}
210
223
211
- fn applicable_defs < ' a > (
212
- import_candidate : & ImportCandidate ,
213
- current_crate : Crate ,
214
- db : & RootDatabase ,
215
- unfiltered_imports : Box < dyn Iterator < Item = Either < ModuleDef , MacroDef > > + ' a > ,
216
- ) -> Box < dyn Iterator < Item = Either < ModuleDef , MacroDef > > + ' a > {
217
- // TODO kb this needs to consider various path prefixes, etc.
218
- let receiver_ty = match import_candidate {
219
- ImportCandidate :: Path ( _) => return unfiltered_imports,
220
- ImportCandidate :: TraitAssocItem ( candidate) | ImportCandidate :: TraitMethod ( candidate) => {
221
- & candidate. receiver_ty
224
+ fn path_applicable_defs < ' a > (
225
+ sema : & ' a Semantics < RootDatabase > ,
226
+ path_candidate : & PathImportCandidate ,
227
+ unfiltered_defs : Box < dyn Iterator < Item = Either < ModuleDef , MacroDef > > + ' a > ,
228
+ module_with_candidate : Module ,
229
+ prefixed : Option < hir:: PrefixKind > ,
230
+ ) -> Box < dyn Iterator < Item = ( ModPath , ItemInNs ) > + ' a > {
231
+ let applicable_defs = unfiltered_defs
232
+ . map ( |candidate| candidate. either ( ItemInNs :: from, ItemInNs :: from) )
233
+ . filter_map ( move |item_to_search| {
234
+ get_mod_path ( sema. db , item_to_search, & module_with_candidate, prefixed)
235
+ . zip ( Some ( item_to_search) )
236
+ } ) ;
237
+
238
+ let unresolved_qualifier = match & path_candidate. unresolved_qualifier {
239
+ Some ( qualifier) => qualifier,
240
+ None => {
241
+ // TODO kb too many boxes tossed around
242
+ return Box :: new ( applicable_defs) ;
222
243
}
223
244
} ;
224
245
246
+ // TODO kb filter out items: found path should end with `qualifier::Name` or `qualifier::Something` for fuzzy search case.
247
+
248
+ // TODO kb find a way to turn a qualifier into the corresponding ModuleDef. Maybe through the unfiltered data?
249
+ if let Some ( qualifier_start_resolution) = resolve_qualifier_start ( sema, unresolved_qualifier) {
250
+ // TODO kb ascend until an unresolved segment part appears
251
+ } else {
252
+ // first segment is already unresolved, need to turn it into ModuleDef somehow
253
+ }
254
+
255
+ return Box :: new ( applicable_defs) ;
256
+ }
257
+
258
+ fn resolve_qualifier_start (
259
+ sema : & Semantics < RootDatabase > ,
260
+ qualifier : & ast:: Path ,
261
+ ) -> Option < PathResolution > {
262
+ let qualifier_start = qualifier. syntax ( ) . descendants ( ) . find_map ( ast:: NameRef :: cast) ?;
263
+ let qualifier_start_path = qualifier_start. syntax ( ) . ancestors ( ) . find_map ( ast:: Path :: cast) ?;
264
+ sema. resolve_path ( & qualifier_start_path)
265
+ }
266
+
267
+ fn trait_applicable_defs < ' a > (
268
+ db : & ' a RootDatabase ,
269
+ current_crate : Crate ,
270
+ trait_candidate : & TraitImportCandidate ,
271
+ trait_assoc_item : bool ,
272
+ unfiltered_defs : Box < dyn Iterator < Item = Either < ModuleDef , MacroDef > > + ' a > ,
273
+ module_with_candidate : Module ,
274
+ prefixed : Option < hir:: PrefixKind > ,
275
+ ) -> Box < dyn Iterator < Item = ( ModPath , ItemInNs ) > + ' a > {
225
276
let mut required_assoc_items = FxHashSet :: default ( ) ;
226
277
227
- let trait_candidates = unfiltered_imports
278
+ let trait_candidates = unfiltered_defs
228
279
. filter_map ( |input| match input {
229
280
Either :: Left ( module_def) => module_def. as_assoc_item ( db) ,
230
281
_ => None ,
@@ -238,9 +289,8 @@ fn applicable_defs<'a>(
238
289
239
290
let mut applicable_defs = FxHashSet :: default ( ) ;
240
291
241
- match import_candidate {
242
- ImportCandidate :: Path ( _) => unreachable ! ( ) ,
243
- ImportCandidate :: TraitAssocItem ( _) => receiver_ty. iterate_path_candidates (
292
+ if trait_assoc_item {
293
+ trait_candidate. receiver_ty . iterate_path_candidates (
244
294
db,
245
295
current_crate,
246
296
& trait_candidates,
@@ -252,27 +302,52 @@ fn applicable_defs<'a>(
252
302
return None ;
253
303
}
254
304
}
255
- applicable_defs. insert ( Either :: Left ( assoc_to_module_def ( assoc) ) ) ;
305
+ applicable_defs. insert ( assoc_to_module_def ( assoc) ) ;
256
306
}
257
307
None :: < ( ) >
258
308
} ,
259
- ) ,
260
- ImportCandidate :: TraitMethod ( _) => receiver_ty. iterate_method_candidates (
309
+ )
310
+ } else {
311
+ trait_candidate. receiver_ty . iterate_method_candidates (
261
312
db,
262
313
current_crate,
263
314
& trait_candidates,
264
315
None ,
265
316
|_, function| {
266
317
let assoc = function. as_assoc_item ( db) ?;
267
318
if required_assoc_items. contains ( & assoc) {
268
- applicable_defs. insert ( Either :: Left ( assoc_to_module_def ( assoc) ) ) ;
319
+ applicable_defs. insert ( assoc_to_module_def ( assoc) ) ;
269
320
}
270
321
None :: < ( ) >
271
322
} ,
272
- ) ,
323
+ )
273
324
} ;
274
325
275
- Box :: new ( applicable_defs. into_iter ( ) )
326
+ Box :: new (
327
+ applicable_defs
328
+ . into_iter ( )
329
+ . filter_map ( move |candidate| {
330
+ let canidate_trait = candidate. as_assoc_item ( db) ?. containing_trait ( db) ?;
331
+ Some ( ItemInNs :: from ( ModuleDef :: from ( canidate_trait) ) )
332
+ } )
333
+ . filter_map ( move |item_to_search| {
334
+ get_mod_path ( db, item_to_search, & module_with_candidate, prefixed)
335
+ . zip ( Some ( item_to_search) )
336
+ } ) ,
337
+ )
338
+ }
339
+
340
+ fn get_mod_path (
341
+ db : & RootDatabase ,
342
+ item_to_search : ItemInNs ,
343
+ module_with_candidate : & Module ,
344
+ prefixed : Option < hir:: PrefixKind > ,
345
+ ) -> Option < ModPath > {
346
+ if let Some ( prefix_kind) = prefixed {
347
+ module_with_candidate. find_use_path_prefixed ( db, item_to_search, prefix_kind)
348
+ } else {
349
+ module_with_candidate. find_use_path ( db, item_to_search)
350
+ }
276
351
}
277
352
278
353
fn assoc_to_module_def ( assoc : AssocItem ) -> ModuleDef {
0 commit comments