mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-11-02 12:59:12 +00:00
fix: Fix trait method completions not acknowledging Deref impls
This commit is contained in:
parent
191949eabe
commit
737d5088e5
5 changed files with 90 additions and 33 deletions
|
|
@ -531,40 +531,61 @@ 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;
|
||||
};
|
||||
|
||||
// in order to handle implied bounds through an associated type, keep any
|
||||
// method receiver that matches `TyFingerprint::Unnameable`. this receiver
|
||||
// won't be in `TraitImpls` anyways, as `TraitImpls` only contains actual
|
||||
// implementations.
|
||||
if matches!(receiver, TyFingerprint::Unnameable) {
|
||||
return true;
|
||||
let autoderef_method_receiver = {
|
||||
let mut deref_chain = trait_candidate.receiver_ty.autoderef(db).collect::<Vec<_>>();
|
||||
// As a last step, we can do array unsizing (that's the only unsizing that rustc does for method receivers!)
|
||||
if let Some((ty, _len)) = deref_chain.last().and_then(|ty| ty.as_array(db)) {
|
||||
let slice = Type::new_slice(ty);
|
||||
deref_chain.push(slice);
|
||||
}
|
||||
deref_chain
|
||||
.into_iter()
|
||||
.filter_map(|ty| Some((ty.krate(db).into(), ty.fingerprint_for_trait_impl()?)))
|
||||
.sorted()
|
||||
.unique()
|
||||
.collect::<Vec<_>>()
|
||||
};
|
||||
|
||||
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);
|
||||
// can be empty if the entire deref chain is has no valid trait impl fingerprints
|
||||
if autoderef_method_receiver.is_empty() {
|
||||
return Default::default();
|
||||
}
|
||||
|
||||
// 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)
|
||||
};
|
||||
// in order to handle implied bounds through an associated type, keep all traits if any
|
||||
// type in the deref chain matches `TyFingerprint::Unnameable`. This fingerprint
|
||||
// won't be in `TraitImpls` anyways, as `TraitImpls` only contains actual implementations.
|
||||
if !autoderef_method_receiver
|
||||
.iter()
|
||||
.any(|(_, fingerprint)| matches!(fingerprint, TyFingerprint::Unnameable))
|
||||
{
|
||||
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);
|
||||
|
||||
definitions_exist_in_trait_crate || definitions_exist_in_receiver_crate()
|
||||
});
|
||||
let trait_impls_in_crate = db.trait_impls_in_crate(defining_crate_for_trait.into());
|
||||
let definitions_exist_in_trait_crate =
|
||||
autoderef_method_receiver.iter().any(|&(_, fingerprint)| {
|
||||
trait_impls_in_crate
|
||||
.has_impls_for_trait_and_self_ty(candidate_trait_id, fingerprint)
|
||||
});
|
||||
// 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 = || {
|
||||
autoderef_method_receiver.iter().any(|&(krate, fingerprint)| {
|
||||
db.trait_impls_in_crate(krate)
|
||||
.has_impls_for_trait_and_self_ty(candidate_trait_id, fingerprint)
|
||||
})
|
||||
};
|
||||
|
||||
definitions_exist_in_trait_crate || definitions_exist_in_receiver_crate()
|
||||
});
|
||||
}
|
||||
|
||||
let mut located_imports = FxIndexSet::default();
|
||||
let mut trait_import_paths = FxHashMap::default();
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue