about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--crates/hir/src/lib.rs12
-rw-r--r--crates/hir_ty/src/lib.rs1
-rw-r--r--crates/hir_ty/src/utils.rs2
-rw-r--r--crates/ide_completion/src/completions/flyimport.rs23
-rw-r--r--crates/ide_db/src/helpers/import_assets.rs22
5 files changed, 53 insertions, 7 deletions
diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs
index eba46a05696..0acfa582a0b 100644
--- a/crates/hir/src/lib.rs
+++ b/crates/hir/src/lib.rs
@@ -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()
diff --git a/crates/hir_ty/src/lib.rs b/crates/hir_ty/src/lib.rs
index 113234fa48c..0505fa4aeaf 100644
--- a/crates/hir_ty/src/lib.rs
+++ b/crates/hir_ty/src/lib.rs
@@ -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::{
diff --git a/crates/hir_ty/src/utils.rs b/crates/hir_ty/src/utils.rs
index 5f6cb052af7..2f04ee57ae0 100644
--- a/crates/hir_ty/src/utils.rs
+++ b/crates/hir_ty/src/utils.rs
@@ -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_];
diff --git a/crates/ide_completion/src/completions/flyimport.rs b/crates/ide_completion/src/completions/flyimport.rs
index 5e61ecb4dbf..8e211ae1ed4 100644
--- a/crates/ide_completion/src/completions/flyimport.rs
+++ b/crates/ide_completion/src/completions/flyimport.rs
@@ -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#""#]],
+        );
+    }
 }
diff --git a/crates/ide_db/src/helpers/import_assets.rs b/crates/ide_db/src/helpers/import_assets.rs
index 8ce64836711..91d6a466510 100644
--- a/crates/ide_db/src/helpers/import_assets.rs
+++ b/crates/ide_db/src/helpers/import_assets.rs
@@ -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),
                     ));