From 28ca37175572403edeb92324d251fbceb4c2487f Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Tue, 25 May 2021 16:08:18 +0200 Subject: Consider trait to be in scope for trait-impl --- crates/hir_def/src/resolver.rs | 38 +++++++++++++++++++++++++------------- crates/hir_ty/src/infer.rs | 2 ++ crates/hir_ty/src/tests/traits.rs | 30 ++++++++++++++++++++++++++++++ 3 files changed, 57 insertions(+), 13 deletions(-) diff --git a/crates/hir_def/src/resolver.rs b/crates/hir_def/src/resolver.rs index 0391cc49b..fb8a6f260 100644 --- a/crates/hir_def/src/resolver.rs +++ b/crates/hir_def/src/resolver.rs @@ -337,22 +337,34 @@ impl Resolver { pub fn traits_in_scope(&self, db: &dyn DefDatabase) -> FxHashSet { let mut traits = FxHashSet::default(); for scope in &self.scopes { - if let Scope::ModuleScope(m) = scope { - if let Some(prelude) = m.def_map.prelude() { - let prelude_def_map = prelude.def_map(db); - traits.extend(prelude_def_map[prelude.local_id].scope.traits()); - } - traits.extend(m.def_map[m.module_id].scope.traits()); - - // Add all traits that are in scope because of the containing DefMaps - m.def_map.with_ancestor_maps(db, m.module_id, &mut |def_map, module| { - if let Some(prelude) = def_map.prelude() { + match scope { + Scope::ModuleScope(m) => { + if let Some(prelude) = m.def_map.prelude() { let prelude_def_map = prelude.def_map(db); traits.extend(prelude_def_map[prelude.local_id].scope.traits()); } - traits.extend(def_map[module].scope.traits()); - None::<()> - }); + traits.extend(m.def_map[m.module_id].scope.traits()); + + // Add all traits that are in scope because of the containing DefMaps + m.def_map.with_ancestor_maps(db, m.module_id, &mut |def_map, module| { + if let Some(prelude) = def_map.prelude() { + let prelude_def_map = prelude.def_map(db); + traits.extend(prelude_def_map[prelude.local_id].scope.traits()); + } + traits.extend(def_map[module].scope.traits()); + None::<()> + }); + } + &Scope::ImplDefScope(impl_) => { + if let Some(target_trait) = &db.impl_data(impl_).target_trait { + if let Some(TypeNs::TraitId(trait_)) = + self.resolve_path_in_type_ns_fully(db, target_trait.path.mod_path()) + { + traits.insert(trait_); + } + } + } + _ => (), } } traits diff --git a/crates/hir_ty/src/infer.rs b/crates/hir_ty/src/infer.rs index edb65622f..164e85050 100644 --- a/crates/hir_ty/src/infer.rs +++ b/crates/hir_ty/src/infer.rs @@ -578,10 +578,12 @@ impl<'a> InferenceContext<'a> { } fn resolve_ops_try_ok(&self) -> Option { + // FIXME resolve via lang_item once try v2 is stable let path = path![core::ops::Try]; let trait_ = self.resolver.resolve_known_trait(self.db.upcast(), &path)?; let trait_data = self.db.trait_data(trait_); trait_data + // FIXME remove once try v2 is stable .associated_type_by_name(&name![Ok]) .or_else(|| trait_data.associated_type_by_name(&name![Output])) } diff --git a/crates/hir_ty/src/tests/traits.rs b/crates/hir_ty/src/tests/traits.rs index 6cd8786ea..6ad96bfe3 100644 --- a/crates/hir_ty/src/tests/traits.rs +++ b/crates/hir_ty/src/tests/traits.rs @@ -3630,3 +3630,33 @@ fn test(f: F) { "#]], ); } + +#[test] +fn trait_in_scope_of_trait_impl() { + check_infer( + r#" +mod foo { + pub trait Foo { + fn foo(self); + fn bar(self) -> usize { 0 } + } +} +impl foo::Foo for u32 { + fn foo(self) { + let _x = self.bar(); + } +} + "#, + expect![[r#" + 45..49 'self': Self + 67..71 'self': Self + 82..87 '{ 0 }': usize + 84..85 '0': usize + 131..135 'self': u32 + 137..173 '{ ... }': () + 151..153 '_x': usize + 156..160 'self': u32 + 156..166 'self.bar()': usize + "#]], + ); +} -- cgit v1.2.3