8539:  fix: Do not propose inherent traits in flyimports and import assists r=flodiebold a=SomeoneToIgnore

Closes https://github.com/rust-analyzer/rust-analyzer/issues/8520

I've went with a separate method approach, since the [highlighted code](https://github.com/rust-analyzer/rust-analyzer/issues/8520#issuecomment-819856337) has not`Type` and uses `Ty` to get his data, but the code I had to change has no access to `Ty` and has `Type` only.

Co-authored-by: Kirill Bulatov <mail4score@gmail.com>
This commit is contained in:
bors[bot] 2021-04-16 17:54:47 +00:00 committed by GitHub
commit 5274eb12dd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 53 additions and 7 deletions

View File

@ -2066,6 +2066,18 @@ impl Type {
self.ty.dyn_trait().map(Into::into)
}
/// If a type can be represented as `dyn Trait`, returns all traits accessible via this type,
/// or an empty iterator otherwise.
pub fn applicable_inherent_traits<'a>(
&'a self,
db: &'a dyn HirDatabase,
) -> impl Iterator<Item = Trait> + 'a {
self.autoderef(db)
.filter_map(|derefed_type| derefed_type.ty.dyn_trait())
.flat_map(move |dyn_trait_id| hir_ty::all_super_traits(db.upcast(), dyn_trait_id))
.map(Trait::from)
}
pub fn as_impl_traits(&self, db: &dyn HirDatabase) -> Option<Vec<Trait>> {
self.ty.impl_trait_bounds(db).map(|it| {
it.into_iter()

View File

@ -56,6 +56,7 @@ pub use mapping::{
to_foreign_def_id, to_placeholder_idx,
};
pub use traits::TraitEnvironment;
pub use utils::all_super_traits;
pub use walk::TypeWalk;
pub use chalk_ir::{

View File

@ -78,7 +78,7 @@ fn direct_super_trait_refs(db: &dyn HirDatabase, trait_ref: &TraitRef) -> Vec<Tr
/// Returns an iterator over the whole super trait hierarchy (including the
/// trait itself).
pub(super) fn all_super_traits(db: &dyn DefDatabase, trait_: TraitId) -> Vec<TraitId> {
pub fn all_super_traits(db: &dyn DefDatabase, trait_: TraitId) -> Vec<TraitId> {
// we need to take care a bit here to avoid infinite loops in case of cycles
// (i.e. if we have `trait A: B; trait B: A;`)
let mut result = vec![trait_];

View File

@ -1127,4 +1127,27 @@ impl Bar for Foo {
expect![[r#""#]],
);
}
#[test]
fn no_inherent_candidates_proposed() {
check(
r#"
mod baz {
pub trait DefDatabase {
fn method1(&self);
}
pub trait HirDatabase: DefDatabase {
fn method2(&self);
}
}
mod bar {
fn test(db: &dyn crate::baz::HirDatabase) {
db.metho$0
}
}
"#,
expect![[r#""#]],
);
}
}

View File

@ -436,6 +436,8 @@ fn trait_applicable_items(
})
.collect();
let related_dyn_traits =
trait_candidate.receiver_ty.applicable_inherent_traits(db).collect::<FxHashSet<_>>();
let mut located_imports = FxHashSet::default();
if trait_assoc_item {
@ -451,12 +453,16 @@ fn trait_applicable_items(
return None;
}
}
let located_trait = assoc.containing_trait(db)?;
if related_dyn_traits.contains(&located_trait) {
return None;
}
let item = ItemInNs::from(ModuleDef::from(assoc.containing_trait(db)?));
let trait_item = ItemInNs::from(ModuleDef::from(located_trait));
let original_item = assoc_to_item(assoc);
located_imports.insert(LocatedImport::new(
mod_path(item)?,
item,
mod_path(trait_item)?,
trait_item,
original_item,
mod_path(original_item),
));
@ -473,11 +479,15 @@ fn trait_applicable_items(
|_, function| {
let assoc = function.as_assoc_item(db)?;
if required_assoc_items.contains(&assoc) {
let item = ItemInNs::from(ModuleDef::from(assoc.containing_trait(db)?));
let located_trait = assoc.containing_trait(db)?;
if related_dyn_traits.contains(&located_trait) {
return None;
}
let trait_item = ItemInNs::from(ModuleDef::from(located_trait));
let original_item = assoc_to_item(assoc);
located_imports.insert(LocatedImport::new(
mod_path(item)?,
item,
mod_path(trait_item)?,
trait_item,
original_item,
mod_path(original_item),
));