completions: speed up completions by filtering non-applicable traits

This commit is contained in:
David Barsky 2024-02-13 13:25:03 -05:00
parent 9f0495761a
commit c246a93046
6 changed files with 243 additions and 4 deletions

View file

@ -1,8 +1,9 @@
//! Look up accessible paths for items.
use hir::{
AsAssocItem, AssocItem, AssocItemContainer, Crate, ItemInNs, ModPath, Module, ModuleDef, Name,
PathResolution, PrefixKind, ScopeDef, Semantics, SemanticsScope, Type,
db::HirDatabase, AsAssocItem, AssocItem, AssocItemContainer, Crate, HasCrate, ItemInNs,
ModPath, Module, ModuleDef, Name, PathResolution, PrefixKind, ScopeDef, Semantics,
SemanticsScope, Trait, Type,
};
use itertools::{EitherOrBoth, Itertools};
use rustc_hash::{FxHashMap, FxHashSet};
@ -517,7 +518,7 @@ fn trait_applicable_items(
let related_traits = inherent_traits.chain(env_traits).collect::<FxHashSet<_>>();
let mut required_assoc_items = FxHashSet::default();
let trait_candidates: FxHashSet<_> = items_locator::items_with_name(
let mut trait_candidates: FxHashSet<_> = items_locator::items_with_name(
sema,
current_crate,
trait_candidate.assoc_item_name.clone(),
@ -538,6 +539,32 @@ fn trait_applicable_items(
})
.collect();
trait_candidates.retain(|&candidate_trait_id| {
// we care about the following cases:
// 1. Trait's definition crate
// 2. Definition crates for all trait's generic arguments
// a. This is recursive for fundamental types: `Into<Box<A>> for ()`` is OK, but
// `Into<Vec<A>> for ()`` is *not*.
// 3. Receiver type definition crate
// a. This is recursive for fundamental types
let defining_crate_for_trait = Trait::from(candidate_trait_id).krate(db);
let Some(receiver) = trait_candidate.receiver_ty.fingerprint_for_trait_impl() else {
return false;
};
let definitions_exist_in_trait_crate = db
.trait_impls_in_crate(defining_crate_for_trait.into())
.has_impls_for_trait_and_self_ty(candidate_trait_id, receiver);
// this is a closure for laziness: if `definitions_exist_in_trait_crate` is true,
// we can avoid a second db lookup.
let definitions_exist_in_receiver_crate = || {
db.trait_impls_in_crate(trait_candidate.receiver_ty.krate(db).into())
.has_impls_for_trait_and_self_ty(candidate_trait_id, receiver)
};
definitions_exist_in_trait_crate || definitions_exist_in_receiver_crate()
});
let mut located_imports = FxHashSet::default();
let mut trait_import_paths = FxHashMap::default();