Auto merge of #17270 - davidbarsky:david/fix-completions-from-associated-types, r=Veykril

fix: ensure implied bounds from associated types are considered in autocomplete

closes: #16989

rust-analyzer needs to consider implied bounds from associated types in order to get all methods suggestions people expect. A pretty easy way to do that is to keep the `candidate_trait_id`'s receiver if it matches `TyFingerprint::Unnameable`.  When benchmarking this change, I didn't notice a meaningful difference in autocomplete latency.

(`TyFingerprint::Unnameable` corresponds to `TyKind::AssociatedType`, `TyKind::OpaqueType`, `TyKind::FnDef`, `TyKind::Closure`, `TyKind::Coroutine`, and `TyKind::CoroutineWitness`.)
This commit is contained in:
bors 2024-05-22 20:38:28 +00:00
commit 653b69eb42
3 changed files with 53 additions and 2 deletions

View file

@ -68,7 +68,7 @@ use hir_ty::{
diagnostics::BodyValidationDiagnostic,
error_lifetime, known_const_to_ast,
layout::{Layout as TyLayout, RustcEnumVariantIdx, RustcFieldIdx, TagEncoding},
method_resolution::{self, TyFingerprint},
method_resolution::{self},
mir::{interpret_mir, MutBorrowKind},
primitive::UintTy,
traits::FnTrait,
@ -99,6 +99,7 @@ pub use crate::{
VisibleTraits,
},
};
pub use hir_ty::method_resolution::TyFingerprint;
// Be careful with these re-exports.
//

View file

@ -472,6 +472,47 @@ fn main() {
);
}
#[test]
fn trait_completions_handle_associated_types() {
let fixture = r#"
//- /foo.rs crate:foo
pub trait NotInScope {
fn not_in_scope(&self);
}
pub trait Wrapper {
type Inner: NotInScope;
fn inner(&self) -> Self::Inner;
}
//- /main.rs crate:main deps:foo
use foo::Wrapper;
fn completion<T: Wrapper>(whatever: T) {
whatever.inner().$0
}
"#;
check(
fixture,
expect![[r#"
me not_in_scope() (use foo::NotInScope) fn(&self)
"#]],
);
check_edit(
"not_in_scope",
fixture,
r#"
use foo::{NotInScope, Wrapper};
fn completion<T: Wrapper>(whatever: T) {
whatever.inner().not_in_scope()$0
}
"#,
);
}
#[test]
fn trait_method_fuzzy_completion_aware_of_unit_type() {
let fixture = r#"

View file

@ -3,7 +3,7 @@
use hir::{
db::HirDatabase, AsAssocItem, AssocItem, AssocItemContainer, Crate, HasCrate, ImportPathConfig,
ItemInNs, ModPath, Module, ModuleDef, Name, PathResolution, PrefixKind, ScopeDef, Semantics,
SemanticsScope, Trait, Type,
SemanticsScope, Trait, TyFingerprint, Type,
};
use itertools::{EitherOrBoth, Itertools};
use rustc_hash::{FxHashMap, FxHashSet};
@ -545,6 +545,15 @@ fn trait_applicable_items(
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 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);