Repository: rust-lang/rust-analyzer
Pull request #17270 (2024-05-21 16:22:56)

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`.)

bors: :v: @davidbarsky, you can now approve this pull request!

If @Veykril told you to "`r=me`" after making some further change, please make that change, then do `@bors r=@Veykril`
<!-- homu: {"type":"Delegated","delegator":"Veykril","delegate":"davidbarsky"} -->
davidbarsky: > Would be good to add the reproduction as a test to `crates\ide-completion\src\tests\special.rs` or `crates\ide-completion\src\tests\expression.rs`

Good point! I ended up adding a test in `crates/ide-completion/src/tests/flyimport.rs` instead because some of the other tests I wrote for this functionality were in that file.
davidbarsky: @bors r=@Veykril
bors: :pushpin: Commit f14d86272c560742f1db860d35235e699b2af89c has been approved by `Veykril`

It is now in the [queue](https://bors.rust-lang.org/homu/queue/rust-analyzer) for this repository.

<!-- @bors r=Veykril f14d86272c560742f1db860d35235e699b2af89c -->
<!-- homu: {"type":"Approved","sha":"f14d86272c560742f1db860d35235e699b2af89c","approver":"Veykril","queue":"https://bors.rust-lang.org/homu/queue/rust-analyzer"} -->
bors: :umbrella: The latest upstream changes (presumably #17252) made this pull request unmergeable. Please [resolve the merge conflicts](https://rustc-dev-guide.rust-lang.org/git.html#rebasing-and-conflicts).

Patch:
diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs
index 0b68762e4f..777be711a5 100644
--- a/crates/hir/src/lib.rs
+++ b/crates/hir/src/lib.rs
@@ -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.
 //
diff --git a/crates/ide-db/src/imports/import_assets.rs b/crates/ide-db/src/imports/import_assets.rs
index 6e708182d0..4caecb3f2f 100644
--- a/crates/ide-db/src/imports/import_assets.rs
+++ b/crates/ide-db/src/imports/import_assets.rs
@@ -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);


Test patch:
diff --git a/crates/ide-completion/src/tests/flyimport.rs b/crates/ide-completion/src/tests/flyimport.rs
index d2227d23cd..abffa73c3b 100644
--- a/crates/ide-completion/src/tests/flyimport.rs
+++ b/crates/ide-completion/src/tests/flyimport.rs
@@ -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#"