Skip to content

Commit

Permalink
Auto merge of #17270 - davidbarsky:david/fix-completions-from-associa…
Browse files Browse the repository at this point in the history
…ted-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`.)
  • Loading branch information
bors committed May 22, 2024
2 parents 0916e72 + f2c3ef7 commit ac2708a
Show file tree
Hide file tree
Showing 3 changed files with 53 additions and 2 deletions.
3 changes: 2 additions & 1 deletion src/tools/rust-analyzer/crates/hir/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -99,6 +99,7 @@ pub use crate::{
VisibleTraits,
},
};
pub use hir_ty::method_resolution::TyFingerprint;

// Be careful with these re-exports.
//
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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#"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand Down Expand Up @@ -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);
Expand Down

0 comments on commit ac2708a

Please sign in to comment.