Skip to content

Commit af102ba

Browse files
committed
Auto merge of rust-lang#16270 - Veykril:flyimport-perf, r=Veykril
internal: Speed up import searching some more Pushes the sorting to the caller, meaning additional filtering can be done pre-sorting. Similarly a collect call was pushed to the caller for allowing some other filters to run pre-collecting.
2 parents dc31cef + cc2b79f commit af102ba

File tree

4 files changed

+80
-47
lines changed

4 files changed

+80
-47
lines changed

crates/ide-assists/src/handlers/auto_import.rs

+9-6
Original file line numberDiff line numberDiff line change
@@ -89,12 +89,14 @@ use crate::{AssistContext, AssistId, AssistKind, Assists, GroupLabel};
8989
// ```
9090
pub(crate) fn auto_import(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> {
9191
let (import_assets, syntax_under_caret) = find_importable_node(ctx)?;
92-
let mut proposed_imports = import_assets.search_for_imports(
93-
&ctx.sema,
94-
ctx.config.insert_use.prefix_kind,
95-
ctx.config.prefer_no_std,
96-
ctx.config.prefer_no_std,
97-
);
92+
let mut proposed_imports: Vec<_> = import_assets
93+
.search_for_imports(
94+
&ctx.sema,
95+
ctx.config.insert_use.prefix_kind,
96+
ctx.config.prefer_no_std,
97+
ctx.config.prefer_no_std,
98+
)
99+
.collect();
98100
if proposed_imports.is_empty() {
99101
return None;
100102
}
@@ -113,6 +115,7 @@ pub(crate) fn auto_import(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<
113115
)?;
114116

115117
// we aren't interested in different namespaces
118+
proposed_imports.sort_by(|a, b| a.import_path.cmp(&b.import_path));
116119
proposed_imports.dedup_by(|a, b| a.import_path == b.import_path);
117120

118121
let current_node = match ctx.covering_element() {

crates/ide-assists/src/handlers/qualify_path.rs

+4-5
Original file line numberDiff line numberDiff line change
@@ -37,11 +37,9 @@ use crate::{
3737
// ```
3838
pub(crate) fn qualify_path(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> {
3939
let (import_assets, syntax_under_caret) = find_importable_node(ctx)?;
40-
let mut proposed_imports = import_assets.search_for_relative_paths(
41-
&ctx.sema,
42-
ctx.config.prefer_no_std,
43-
ctx.config.prefer_prelude,
44-
);
40+
let mut proposed_imports: Vec<_> = import_assets
41+
.search_for_relative_paths(&ctx.sema, ctx.config.prefer_no_std, ctx.config.prefer_prelude)
42+
.collect();
4543
if proposed_imports.is_empty() {
4644
return None;
4745
}
@@ -82,6 +80,7 @@ pub(crate) fn qualify_path(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option
8280
};
8381

8482
// we aren't interested in different namespaces
83+
proposed_imports.sort_by(|a, b| a.import_path.cmp(&b.import_path));
8584
proposed_imports.dedup_by(|a, b| a.import_path == b.import_path);
8685

8786
let group_label = group_label(candidate);

crates/ide-completion/src/completions/flyimport.rs

+26-10
Original file line numberDiff line numberDiff line change
@@ -263,16 +263,21 @@ fn import_on_the_fly(
263263
ctx.config.prefer_no_std,
264264
ctx.config.prefer_prelude,
265265
)
266-
.into_iter()
267266
.filter(ns_filter)
268267
.filter(|import| {
269268
let original_item = &import.original_item;
270269
!ctx.is_item_hidden(&import.item_to_import)
271270
&& !ctx.is_item_hidden(original_item)
272271
&& ctx.check_stability(original_item.attrs(ctx.db).as_deref())
273272
})
274-
.sorted_by_key(|located_import| {
275-
compute_fuzzy_completion_order_key(&located_import.import_path, &user_input_lowercased)
273+
.sorted_by(|a, b| {
274+
let key = |import_path| {
275+
(
276+
compute_fuzzy_completion_order_key(import_path, &user_input_lowercased),
277+
import_path,
278+
)
279+
};
280+
key(&a.import_path).cmp(&key(&b.import_path))
276281
})
277282
.filter_map(|import| {
278283
render_resolution_with_import(RenderContext::new(ctx), path_ctx, import)
@@ -310,16 +315,21 @@ fn import_on_the_fly_pat_(
310315
ctx.config.prefer_no_std,
311316
ctx.config.prefer_prelude,
312317
)
313-
.into_iter()
314318
.filter(ns_filter)
315319
.filter(|import| {
316320
let original_item = &import.original_item;
317321
!ctx.is_item_hidden(&import.item_to_import)
318322
&& !ctx.is_item_hidden(original_item)
319323
&& ctx.check_stability(original_item.attrs(ctx.db).as_deref())
320324
})
321-
.sorted_by_key(|located_import| {
322-
compute_fuzzy_completion_order_key(&located_import.import_path, &user_input_lowercased)
325+
.sorted_by(|a, b| {
326+
let key = |import_path| {
327+
(
328+
compute_fuzzy_completion_order_key(import_path, &user_input_lowercased),
329+
import_path,
330+
)
331+
};
332+
key(&a.import_path).cmp(&key(&b.import_path))
323333
})
324334
.filter_map(|import| {
325335
render_resolution_with_import_pat(RenderContext::new(ctx), pattern_ctx, import)
@@ -352,13 +362,18 @@ fn import_on_the_fly_method(
352362
ctx.config.prefer_no_std,
353363
ctx.config.prefer_prelude,
354364
)
355-
.into_iter()
356365
.filter(|import| {
357366
!ctx.is_item_hidden(&import.item_to_import)
358367
&& !ctx.is_item_hidden(&import.original_item)
359368
})
360-
.sorted_by_key(|located_import| {
361-
compute_fuzzy_completion_order_key(&located_import.import_path, &user_input_lowercased)
369+
.sorted_by(|a, b| {
370+
let key = |import_path| {
371+
(
372+
compute_fuzzy_completion_order_key(import_path, &user_input_lowercased),
373+
import_path,
374+
)
375+
};
376+
key(&a.import_path).cmp(&key(&b.import_path))
362377
})
363378
.for_each(|import| match import.original_item {
364379
ItemInNs::Values(hir::ModuleDef::Function(f)) => {
@@ -407,7 +422,8 @@ fn compute_fuzzy_completion_order_key(
407422
) -> usize {
408423
cov_mark::hit!(certain_fuzzy_order_test);
409424
let import_name = match proposed_mod_path.segments().last() {
410-
Some(name) => name.to_smol_str().to_lowercase(),
425+
// FIXME: nasty alloc, this is a hot path!
426+
Some(name) => name.to_smol_str().to_ascii_lowercase(),
411427
None => return usize::MAX,
412428
};
413429
match import_name.match_indices(user_input_lowercased).next() {

crates/ide-db/src/imports/import_assets.rs

+41-26
Original file line numberDiff line numberDiff line change
@@ -207,7 +207,7 @@ impl ImportAssets {
207207
prefix_kind: PrefixKind,
208208
prefer_no_std: bool,
209209
prefer_prelude: bool,
210-
) -> Vec<LocatedImport> {
210+
) -> impl Iterator<Item = LocatedImport> {
211211
let _p = profile::span("import_assets::search_for_imports");
212212
self.search_for(sema, Some(prefix_kind), prefer_no_std, prefer_prelude)
213213
}
@@ -218,7 +218,7 @@ impl ImportAssets {
218218
sema: &Semantics<'_, RootDatabase>,
219219
prefer_no_std: bool,
220220
prefer_prelude: bool,
221-
) -> Vec<LocatedImport> {
221+
) -> impl Iterator<Item = LocatedImport> {
222222
let _p = profile::span("import_assets::search_for_relative_paths");
223223
self.search_for(sema, None, prefer_no_std, prefer_prelude)
224224
}
@@ -259,9 +259,15 @@ impl ImportAssets {
259259
prefixed: Option<PrefixKind>,
260260
prefer_no_std: bool,
261261
prefer_prelude: bool,
262-
) -> Vec<LocatedImport> {
262+
) -> impl Iterator<Item = LocatedImport> {
263263
let _p = profile::span("import_assets::search_for");
264264

265+
let scope = match sema.scope(&self.candidate_node) {
266+
Some(it) => it,
267+
None => return <FxHashSet<_>>::default().into_iter(),
268+
};
269+
270+
let krate = self.module_with_candidate.krate();
265271
let scope_definitions = self.scope_definitions(sema);
266272
let mod_path = |item| {
267273
get_mod_path(
@@ -272,30 +278,30 @@ impl ImportAssets {
272278
prefer_no_std,
273279
prefer_prelude,
274280
)
275-
};
276-
277-
let krate = self.module_with_candidate.krate();
278-
let scope = match sema.scope(&self.candidate_node) {
279-
Some(it) => it,
280-
None => return Vec::new(),
281+
.filter(|path| path.len() > 1)
281282
};
282283

283284
match &self.import_candidate {
284285
ImportCandidate::Path(path_candidate) => {
285-
path_applicable_imports(sema, krate, path_candidate, mod_path)
286-
}
287-
ImportCandidate::TraitAssocItem(trait_candidate) => {
288-
trait_applicable_items(sema, krate, &scope, trait_candidate, true, mod_path)
289-
}
290-
ImportCandidate::TraitMethod(trait_candidate) => {
291-
trait_applicable_items(sema, krate, &scope, trait_candidate, false, mod_path)
286+
path_applicable_imports(sema, krate, path_candidate, mod_path, |item_to_import| {
287+
!scope_definitions.contains(&ScopeDef::from(item_to_import))
288+
})
292289
}
290+
ImportCandidate::TraitAssocItem(trait_candidate)
291+
| ImportCandidate::TraitMethod(trait_candidate) => trait_applicable_items(
292+
sema,
293+
krate,
294+
&scope,
295+
trait_candidate,
296+
matches!(self.import_candidate, ImportCandidate::TraitAssocItem(_)),
297+
mod_path,
298+
|trait_to_import| {
299+
!scope_definitions
300+
.contains(&ScopeDef::ModuleDef(ModuleDef::Trait(trait_to_import)))
301+
},
302+
),
293303
}
294304
.into_iter()
295-
.filter(|import| import.import_path.len() > 1)
296-
.filter(|import| !scope_definitions.contains(&ScopeDef::from(import.item_to_import)))
297-
.sorted_by(|a, b| a.import_path.cmp(&b.import_path))
298-
.collect()
299305
}
300306

301307
fn scope_definitions(&self, sema: &Semantics<'_, RootDatabase>) -> FxHashSet<ScopeDef> {
@@ -315,6 +321,7 @@ fn path_applicable_imports(
315321
current_crate: Crate,
316322
path_candidate: &PathImportCandidate,
317323
mod_path: impl Fn(ItemInNs) -> Option<ModPath> + Copy,
324+
scope_filter: impl Fn(ItemInNs) -> bool + Copy,
318325
) -> FxHashSet<LocatedImport> {
319326
let _p = profile::span("import_assets::path_applicable_imports");
320327

@@ -335,6 +342,9 @@ fn path_applicable_imports(
335342
AssocSearchMode::Exclude,
336343
)
337344
.filter_map(|item| {
345+
if !scope_filter(item) {
346+
return None;
347+
}
338348
let mod_path = mod_path(item)?;
339349
Some(LocatedImport::new(mod_path, item, item))
340350
})
@@ -347,7 +357,7 @@ fn path_applicable_imports(
347357
path_candidate.name.clone(),
348358
AssocSearchMode::Include,
349359
)
350-
.filter_map(|item| import_for_item(sema.db, mod_path, &qualifier, item))
360+
.filter_map(|item| import_for_item(sema.db, mod_path, &qualifier, item, scope_filter))
351361
.take(DEFAULT_QUERY_SEARCH_LIMIT.inner())
352362
.collect(),
353363
}
@@ -358,6 +368,7 @@ fn import_for_item(
358368
mod_path: impl Fn(ItemInNs) -> Option<ModPath>,
359369
unresolved_qualifier: &[SmolStr],
360370
original_item: ItemInNs,
371+
scope_filter: impl Fn(ItemInNs) -> bool,
361372
) -> Option<LocatedImport> {
362373
let _p = profile::span("import_assets::import_for_item");
363374
let [first_segment, ..] = unresolved_qualifier else { return None };
@@ -413,15 +424,16 @@ fn import_for_item(
413424
// especially in case of lazy completion edit resolutions.
414425
return None;
415426
}
416-
(false, Some(trait_to_import)) => {
427+
(false, Some(trait_to_import)) if scope_filter(trait_to_import) => {
417428
LocatedImport::new(mod_path(trait_to_import)?, trait_to_import, original_item)
418429
}
419-
(true, None) => {
430+
(true, None) if scope_filter(original_item_candidate) => {
420431
LocatedImport::new(import_path_candidate, original_item_candidate, original_item)
421432
}
422-
(false, None) => {
433+
(false, None) if scope_filter(segment_import) => {
423434
LocatedImport::new(mod_path(segment_import)?, segment_import, original_item)
424435
}
436+
_ => return None,
425437
})
426438
}
427439

@@ -490,6 +502,7 @@ fn trait_applicable_items(
490502
trait_candidate: &TraitImportCandidate,
491503
trait_assoc_item: bool,
492504
mod_path: impl Fn(ItemInNs) -> Option<ModPath>,
505+
scope_filter: impl Fn(hir::Trait) -> bool,
493506
) -> FxHashSet<LocatedImport> {
494507
let _p = profile::span("import_assets::trait_applicable_items");
495508

@@ -533,7 +546,8 @@ fn trait_applicable_items(
533546
None,
534547
|assoc| {
535548
if required_assoc_items.contains(&assoc) {
536-
let located_trait = assoc.containing_trait(db)?;
549+
let located_trait =
550+
assoc.containing_trait(db).filter(|&it| scope_filter(it))?;
537551
let trait_item = ItemInNs::from(ModuleDef::from(located_trait));
538552
let import_path = trait_import_paths
539553
.entry(trait_item)
@@ -558,7 +572,8 @@ fn trait_applicable_items(
558572
|function| {
559573
let assoc = function.as_assoc_item(db)?;
560574
if required_assoc_items.contains(&assoc) {
561-
let located_trait = assoc.containing_trait(db)?;
575+
let located_trait =
576+
assoc.containing_trait(db).filter(|&it| scope_filter(it))?;
562577
let trait_item = ItemInNs::from(ModuleDef::from(located_trait));
563578
let import_path = trait_import_paths
564579
.entry(trait_item)

0 commit comments

Comments
 (0)