Exclude inherent traits from flyimports

This commit is contained in:
Kirill Bulatov 2021-04-15 23:31:42 +03:00
parent 75371eb0fa
commit 739edfd5cf
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),
));