From c81aa68afe7a39544bccf4a71957b8b5b3ce0254 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Fri, 10 Dec 2021 19:18:21 +0100 Subject: [PATCH] Don't show trait flyimports for impl trait and placeholders --- crates/hir/src/lib.rs | 40 +++++++++++++------- crates/hir_ty/src/method_resolution.rs | 2 +- crates/hir_ty/src/traits.rs | 14 +++---- crates/ide/src/goto_type_definition.rs | 2 +- crates/ide/src/hover.rs | 2 +- crates/ide_assists/src/utils/suggest_name.rs | 2 +- crates/ide_completion/src/tests/flyimport.rs | 38 +++++++++++++++++++ crates/ide_db/src/helpers/import_assets.rs | 8 ++-- 8 files changed, 78 insertions(+), 30 deletions(-) diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs index 3e04ea8da9a..3739e522a18 100644 --- a/crates/hir/src/lib.rs +++ b/crates/hir/src/lib.rs @@ -2623,13 +2623,15 @@ pub fn tuple_fields(&self, _db: &dyn HirDatabase) -> Vec { } pub fn autoderef<'a>(&'a self, db: &'a dyn HirDatabase) -> impl Iterator + 'a { + self.autoderef_(db).map(move |ty| self.derived(ty)) + } + + pub fn autoderef_<'a>(&'a self, db: &'a dyn HirDatabase) -> impl Iterator + 'a { // There should be no inference vars in types passed here let canonical = hir_ty::replace_errors_with_variables(&self.ty); let environment = self.env.env.clone(); let ty = InEnvironment { goal: canonical, environment }; - autoderef(db, Some(self.krate), ty) - .map(|canonical| canonical.value) - .map(move |ty| self.derived(ty)) + autoderef(db, Some(self.krate), ty).map(|canonical| canonical.value) } // This would be nicer if it just returned an iterator, but that runs into @@ -2808,22 +2810,32 @@ pub fn applicable_inherent_traits<'a>( db: &'a dyn HirDatabase, ) -> impl Iterator + 'a { let _p = profile::span("applicable_inherent_traits"); - self.autoderef(db) - .filter_map(|derefed_type| derefed_type.ty.dyn_trait()) + self.autoderef_(db) + .filter_map(|ty| 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> { + pub fn env_traits<'a>(&'a self, db: &'a dyn HirDatabase) -> impl Iterator + 'a { + let _p = profile::span("env_traits"); + self.autoderef_(db) + .filter(|ty| matches!(ty.kind(&Interner), TyKind::Placeholder(_))) + .flat_map(|ty| { + self.env + .traits_in_scope_from_clauses(ty) + .flat_map(|t| hir_ty::all_super_traits(db.upcast(), t)) + }) + .map(Trait::from) + } + + pub fn as_impl_traits(&self, db: &dyn HirDatabase) -> Option> { self.ty.impl_trait_bounds(db).map(|it| { - it.into_iter() - .filter_map(|pred| match pred.skip_binders() { - hir_ty::WhereClause::Implemented(trait_ref) => { - Some(Trait::from(trait_ref.hir_trait_id())) - } - _ => None, - }) - .collect() + it.into_iter().filter_map(|pred| match pred.skip_binders() { + hir_ty::WhereClause::Implemented(trait_ref) => { + Some(Trait::from(trait_ref.hir_trait_id())) + } + _ => None, + }) }) } diff --git a/crates/hir_ty/src/method_resolution.rs b/crates/hir_ty/src/method_resolution.rs index 3fbb6fea197..6af39828be5 100644 --- a/crates/hir_ty/src/method_resolution.rs +++ b/crates/hir_ty/src/method_resolution.rs @@ -719,7 +719,7 @@ fn iterate_trait_method_candidates( let env_traits = match self_ty.value.kind(&Interner) { TyKind::Placeholder(_) => { // if we have `T: Trait` in the param env, the trait doesn't need to be in scope - env.traits_in_scope_from_clauses(&self_ty.value) + env.traits_in_scope_from_clauses(self_ty.value.clone()) .flat_map(|t| all_super_traits(db.upcast(), t)) .collect() } diff --git a/crates/hir_ty/src/traits.rs b/crates/hir_ty/src/traits.rs index 4b89fd5a853..3876a9da269 100644 --- a/crates/hir_ty/src/traits.rs +++ b/crates/hir_ty/src/traits.rs @@ -54,17 +54,13 @@ pub fn empty(krate: CrateId) -> Self { } } - pub(crate) fn traits_in_scope_from_clauses<'a>( + pub fn traits_in_scope_from_clauses<'a>( &'a self, - ty: &'a Ty, + ty: Ty, ) -> impl Iterator + 'a { - self.traits_from_clauses.iter().filter_map(move |(self_ty, trait_id)| { - if self_ty == ty { - Some(*trait_id) - } else { - None - } - }) + self.traits_from_clauses + .iter() + .filter_map(move |(self_ty, trait_id)| (*self_ty == ty).then(|| *trait_id)) } } diff --git a/crates/ide/src/goto_type_definition.rs b/crates/ide/src/goto_type_definition.rs index 031c4af0de2..55cdb3200ea 100644 --- a/crates/ide/src/goto_type_definition.rs +++ b/crates/ide/src/goto_type_definition.rs @@ -75,7 +75,7 @@ pub(crate) fn goto_type_definition( } else if let Some(trait_) = t.as_dyn_trait() { push(trait_.into()); } else if let Some(traits) = t.as_impl_traits(db) { - traits.into_iter().for_each(|it| push(it.into())); + traits.for_each(|it| push(it.into())); } else if let Some(trait_) = t.as_associated_type_parent_trait(db) { push(trait_.into()); } diff --git a/crates/ide/src/hover.rs b/crates/ide/src/hover.rs index dd77dd3e4b7..7d5cfaa9372 100644 --- a/crates/ide/src/hover.rs +++ b/crates/ide/src/hover.rs @@ -337,7 +337,7 @@ fn walk_and_push_ty( } else if let Some(trait_) = t.as_dyn_trait() { push_new_def(trait_.into()); } else if let Some(traits) = t.as_impl_traits(db) { - traits.into_iter().for_each(|it| push_new_def(it.into())); + traits.for_each(|it| push_new_def(it.into())); } else if let Some(trait_) = t.as_associated_type_parent_trait(db) { push_new_def(trait_.into()); } diff --git a/crates/ide_assists/src/utils/suggest_name.rs b/crates/ide_assists/src/utils/suggest_name.rs index 74523234b0e..2021db3abab 100644 --- a/crates/ide_assists/src/utils/suggest_name.rs +++ b/crates/ide_assists/src/utils/suggest_name.rs @@ -243,7 +243,7 @@ fn name_of_type(ty: &hir::Type, db: &RootDatabase) -> Option { } else if let Some(trait_) = ty.as_dyn_trait() { trait_name(&trait_, db)? } else if let Some(traits) = ty.as_impl_traits(db) { - let mut iter = traits.into_iter().filter_map(|t| trait_name(&t, db)); + let mut iter = traits.filter_map(|t| trait_name(&t, db)); let name = iter.next()?; if iter.next().is_some() { return None; diff --git a/crates/ide_completion/src/tests/flyimport.rs b/crates/ide_completion/src/tests/flyimport.rs index 23e5da463c7..1f96e122f95 100644 --- a/crates/ide_completion/src/tests/flyimport.rs +++ b/crates/ide_completion/src/tests/flyimport.rs @@ -924,6 +924,44 @@ fn test(db: &dyn crate::baz::HirDatabase) { "#, expect![[r#""#]], ); + check( + r#" +mod baz { + pub trait DefDatabase { + fn method1(&self); + } + pub trait HirDatabase: DefDatabase { + fn method2(&self); + } +} + +mod bar { + fn test(db: &impl crate::baz::HirDatabase) { + db.metho$0 + } +} +"#, + expect![[r#""#]], + ); + check( + r#" +mod baz { + pub trait DefDatabase { + fn method1(&self); + } + pub trait HirDatabase: DefDatabase { + fn method2(&self); + } +} + +mod bar { + fn test(db: T) { + db.metho$0 + } +} +"#, + expect![[r#""#]], + ); } #[test] diff --git a/crates/ide_db/src/helpers/import_assets.rs b/crates/ide_db/src/helpers/import_assets.rs index 9a8adf167c8..ac0ccfa63f8 100644 --- a/crates/ide_db/src/helpers/import_assets.rs +++ b/crates/ide_db/src/helpers/import_assets.rs @@ -454,8 +454,10 @@ fn trait_applicable_items( let db = sema.db; - let related_dyn_traits = - trait_candidate.receiver_ty.applicable_inherent_traits(db).collect::>(); + let inherent_traits = trait_candidate.receiver_ty.applicable_inherent_traits(db); + let env_traits = trait_candidate.receiver_ty.env_traits(db); + let related_traits = inherent_traits.chain(env_traits).collect::>(); + let mut required_assoc_items = FxHashSet::default(); let trait_candidates = items_locator::items_with_name( sema, @@ -467,7 +469,7 @@ fn trait_applicable_items( .filter_map(|input| item_as_assoc(db, input)) .filter_map(|assoc| { let assoc_item_trait = assoc.containing_trait(db)?; - if related_dyn_traits.contains(&assoc_item_trait) { + if related_traits.contains(&assoc_item_trait) { None } else { required_assoc_items.insert(assoc);