From bc59f83991a6444ff2f2364b0e942e8a82943b6d Mon Sep 17 00:00:00 2001 From: Florian Diebold Date: Sun, 12 May 2019 14:58:37 +0200 Subject: Use traits from prelude for method resolution --- crates/ra_hir/src/resolve.rs | 25 ++++++++++++------------- crates/ra_hir/src/ty/method_resolution.rs | 2 +- crates/ra_hir/src/ty/tests.rs | 29 +++++++++++++++++++++++++++++ 3 files changed, 42 insertions(+), 14 deletions(-) (limited to 'crates') diff --git a/crates/ra_hir/src/resolve.rs b/crates/ra_hir/src/resolve.rs index 707556ef8..2fb219908 100644 --- a/crates/ra_hir/src/resolve.rs +++ b/crates/ra_hir/src/resolve.rs @@ -3,7 +3,7 @@ use std::sync::Arc; use ra_syntax::ast; -use rustc_hash::FxHashMap; +use rustc_hash::{FxHashMap, FxHashSet}; use crate::{ ModuleDef, Trait, @@ -193,19 +193,18 @@ impl Resolver { names } - pub(crate) fn traits_in_scope<'a>(&'a self) -> impl Iterator + 'a { - // FIXME prelude - self.scopes - .iter() - .rev() - .flat_map(|scope| { - match scope { - Scope::ModuleScope(m) => Some(m.crate_def_map[m.module_id].scope.traits()), - _ => None, + pub(crate) fn traits_in_scope(&self, db: &impl HirDatabase) -> FxHashSet { + let mut traits = FxHashSet::default(); + for scope in &self.scopes { + if let Scope::ModuleScope(m) = scope { + if let Some(prelude) = m.crate_def_map.prelude() { + let prelude_def_map = db.crate_def_map(prelude.krate); + traits.extend(prelude_def_map[prelude.module_id].scope.traits()); } - .into_iter() - }) - .flatten() + traits.extend(m.crate_def_map[m.module_id].scope.traits()); + } + } + traits } fn module(&self) -> Option<(&CrateDefMap, CrateModuleId)> { diff --git a/crates/ra_hir/src/ty/method_resolution.rs b/crates/ra_hir/src/ty/method_resolution.rs index e8cfa0b85..34817a5ec 100644 --- a/crates/ra_hir/src/ty/method_resolution.rs +++ b/crates/ra_hir/src/ty/method_resolution.rs @@ -185,7 +185,7 @@ fn iterate_trait_method_candidates( mut callback: impl FnMut(&Ty, Function) -> Option, ) -> Option { let krate = resolver.krate()?; - 'traits: for t in resolver.traits_in_scope() { + 'traits: for t in resolver.traits_in_scope(db) { let data = t.trait_data(db); // we'll be lazy about checking whether the type implements the // trait, but if we find out it doesn't, we'll skip the rest of the diff --git a/crates/ra_hir/src/ty/tests.rs b/crates/ra_hir/src/ty/tests.rs index 510fa5333..978cc2587 100644 --- a/crates/ra_hir/src/ty/tests.rs +++ b/crates/ra_hir/src/ty/tests.rs @@ -2501,6 +2501,35 @@ fn test() { (&S).foo()<|>; } assert_eq!(t, "u128"); } +#[test] +fn method_resolution_trait_from_prelude() { + let (mut db, pos) = MockDatabase::with_position( + r#" +//- /main.rs +struct S; +impl Clone for S {} + +fn test() { + S.clone()<|>; +} + +//- /lib.rs +#[prelude_import] use foo::*; + +mod foo { + trait Clone { + fn clone(&self) -> Self; + } +} +"#, + ); + db.set_crate_graph_from_fixture(crate_graph! { + "main": ("/main.rs", ["other_crate"]), + "other_crate": ("/lib.rs", []), + }); + assert_eq!("S", type_at_pos(&db, pos)); +} + #[test] fn method_resolution_where_clause_for_unknown_trait() { // The blanket impl shouldn't apply because we can't even resolve UnknownTrait -- cgit v1.2.3