From 1526eb25c98fd16a9c0d114d0ed44e8fec1cc19c Mon Sep 17 00:00:00 2001 From: Florian Diebold Date: Sun, 10 Feb 2019 20:44:34 +0100 Subject: Import the prelude --- crates/ra_hir/src/marks.rs | 1 + crates/ra_hir/src/nameres.rs | 50 +++++++++++++++++++++++++++++++++++--- crates/ra_hir/src/nameres/lower.rs | 7 +++++- crates/ra_hir/src/nameres/tests.rs | 37 ++++++++++++++++++++++++++++ crates/ra_hir/src/resolve.rs | 12 ++++----- 5 files changed, 96 insertions(+), 11 deletions(-) (limited to 'crates/ra_hir/src') diff --git a/crates/ra_hir/src/marks.rs b/crates/ra_hir/src/marks.rs index 50d4e824c..16852a6a1 100644 --- a/crates/ra_hir/src/marks.rs +++ b/crates/ra_hir/src/marks.rs @@ -6,4 +6,5 @@ test_utils::marks!( type_var_resolves_to_int_var glob_enum glob_across_crates + std_prelude ); diff --git a/crates/ra_hir/src/nameres.rs b/crates/ra_hir/src/nameres.rs index ffb20d564..2ba6038c6 100644 --- a/crates/ra_hir/src/nameres.rs +++ b/crates/ra_hir/src/nameres.rs @@ -34,6 +34,10 @@ use crate::{ /// module, the set of visible items. #[derive(Default, Debug, PartialEq, Eq)] pub struct ItemMap { + /// The prelude module for this crate. This either comes from an import + /// marked with the `prelude_import` attribute, or (in the normal case) from + /// a dependency (`std` or `core`). + prelude: Option, pub(crate) extern_prelude: FxHashMap, per_module: ArenaMap, } @@ -211,6 +215,13 @@ where if let Some(module) = dep.krate.root_module(self.db) { self.result.extern_prelude.insert(dep.name.clone(), module.into()); } + // look for the prelude + if self.result.prelude.is_none() { + let item_map = self.db.item_map(dep.krate); + if item_map.prelude.is_some() { + self.result.prelude = item_map.prelude; + } + } } } @@ -279,7 +290,10 @@ where log::debug!("glob import: {:?}", import); match def.take_types() { Some(ModuleDef::Module(m)) => { - if m.krate != self.krate { + if import.is_prelude { + tested_by!(std_prelude); + self.result.prelude = Some(m); + } else if m.krate != self.krate { tested_by!(glob_across_crates); // glob import from other crate => we can just import everything once let item_map = self.db.item_map(m.krate); @@ -434,12 +448,40 @@ impl ItemMap { self.resolve_path_fp(db, original_module, path).0 } - pub(crate) fn resolve_name_in_module(&self, module: Module, name: &Name) -> PerNs { + fn resolve_in_prelude( + &self, + db: &impl PersistentHirDatabase, + original_module: Module, + name: &Name, + ) -> PerNs { + if let Some(prelude) = self.prelude { + let resolution = if prelude.krate == original_module.krate { + self[prelude.module_id].items.get(name).cloned() + } else { + db.item_map(prelude.krate)[prelude.module_id].items.get(name).cloned() + }; + resolution.map(|r| r.def).unwrap_or_else(PerNs::none) + } else { + PerNs::none() + } + } + + pub(crate) fn resolve_name_in_module( + &self, + db: &impl PersistentHirDatabase, + module: Module, + name: &Name, + ) -> PerNs { + // Resolve in: + // - current module / scope + // - extern prelude + // - std prelude let from_scope = self[module.module_id].items.get(name).map_or(PerNs::none(), |it| it.def); let from_extern_prelude = self.extern_prelude.get(name).map_or(PerNs::none(), |&it| PerNs::types(it)); + let from_prelude = self.resolve_in_prelude(db, module, name); - from_scope.or(from_extern_prelude) + from_scope.or(from_extern_prelude).or(from_prelude) } // Returns Yes if we are sure that additions to `ItemMap` wouldn't change @@ -459,7 +501,7 @@ impl ItemMap { Some((_, segment)) => segment, None => return (PerNs::none(), ReachedFixedPoint::Yes), }; - self.resolve_name_in_module(original_module, &segment.name) + self.resolve_name_in_module(db, original_module, &segment.name) } PathKind::Super => { if let Some(p) = original_module.parent(db) { diff --git a/crates/ra_hir/src/nameres/lower.rs b/crates/ra_hir/src/nameres/lower.rs index 3cd496d7f..922dbe9c1 100644 --- a/crates/ra_hir/src/nameres/lower.rs +++ b/crates/ra_hir/src/nameres/lower.rs @@ -2,7 +2,7 @@ use std::sync::Arc; use ra_syntax::{ AstNode, SourceFile, TreeArc, AstPtr, - ast::{self, ModuleItemOwner, NameOwner}, + ast::{self, ModuleItemOwner, NameOwner, AttrsOwner}, }; use ra_arena::{Arena, RawId, impl_arena_id, map::ArenaMap}; use rustc_hash::FxHashMap; @@ -23,6 +23,7 @@ pub(super) struct ImportData { pub(super) path: Path, pub(super) alias: Option, pub(super) is_glob: bool, + pub(super) is_prelude: bool, pub(super) is_extern_crate: bool, } @@ -191,6 +192,7 @@ impl LoweredModule { path, alias, is_glob: false, + is_prelude: false, is_extern_crate: true, }); } @@ -214,11 +216,14 @@ impl LoweredModule { } fn add_use_item(&mut self, source_map: &mut ImportSourceMap, item: &ast::UseItem) { + let is_prelude = + item.attrs().any(|attr| attr.as_atom().map(|s| s == "prelude_import").unwrap_or(false)); Path::expand_use_item(item, |path, segment, alias| { let import = self.imports.alloc(ImportData { path, alias, is_glob: segment.is_none(), + is_prelude, is_extern_crate: false, }); if let Some(segment) = segment { diff --git a/crates/ra_hir/src/nameres/tests.rs b/crates/ra_hir/src/nameres/tests.rs index 6dbe759d1..68ebe963a 100644 --- a/crates/ra_hir/src/nameres/tests.rs +++ b/crates/ra_hir/src/nameres/tests.rs @@ -296,6 +296,43 @@ fn module_resolution_works_for_non_standard_filenames() { ); } +#[test] +fn std_prelude() { + covers!(std_prelude); + let mut db = MockDatabase::with_files( + " + //- /main.rs + use Foo::*; + + //- /lib.rs + mod prelude; + #[prelude_import] + use prelude::*; + + //- /prelude.rs + pub enum Foo { Bar, Baz }; + ", + ); + db.set_crate_graph_from_fixture(crate_graph! { + "main": ("/main.rs", ["test_crate"]), + "test_crate": ("/lib.rs", []), + }); + let main_id = db.file_id_of("/main.rs"); + + let module = crate::source_binder::module_from_file_id(&db, main_id).unwrap(); + let krate = module.krate(&db).unwrap(); + let item_map = db.item_map(krate); + + check_module_item_map( + &item_map, + module.module_id, + " + Bar: t v + Baz: t v + ", + ); +} + #[test] fn name_res_works_for_broken_modules() { covers!(name_res_works_for_broken_modules); diff --git a/crates/ra_hir/src/resolve.rs b/crates/ra_hir/src/resolve.rs index 40c860cf4..fde4d6580 100644 --- a/crates/ra_hir/src/resolve.rs +++ b/crates/ra_hir/src/resolve.rs @@ -56,10 +56,10 @@ pub enum Resolution { } impl Resolver { - pub fn resolve_name(&self, name: &Name) -> PerNs { + pub fn resolve_name(&self, db: &impl HirDatabase, name: &Name) -> PerNs { let mut resolution = PerNs::none(); for scope in self.scopes.iter().rev() { - resolution = resolution.or(scope.resolve_name(name)); + resolution = resolution.or(scope.resolve_name(db, name)); if resolution.is_both() { return resolution; } @@ -69,9 +69,9 @@ impl Resolver { pub fn resolve_path(&self, db: &impl HirDatabase, path: &Path) -> PerNs { if let Some(name) = path.as_ident() { - self.resolve_name(name) + self.resolve_name(db, name) } else if path.is_self() { - self.resolve_name(&Name::self_param()) + self.resolve_name(db, &Name::self_param()) } else { let (item_map, module) = match self.module() { Some(m) => m, @@ -143,13 +143,13 @@ impl Resolver { } impl Scope { - fn resolve_name(&self, name: &Name) -> PerNs { + fn resolve_name(&self, db: &impl HirDatabase, name: &Name) -> PerNs { match self { Scope::ModuleScope(m) => { if let Some(KnownName::SelfParam) = name.as_known_name() { PerNs::types(Resolution::Def(m.module.into())) } else { - m.item_map.resolve_name_in_module(m.module, name).map(Resolution::Def) + m.item_map.resolve_name_in_module(db, m.module, name).map(Resolution::Def) } } Scope::GenericParams(gp) => match gp.find_by_name(name) { -- cgit v1.2.3