aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--crates/ra_hir/src/marks.rs1
-rw-r--r--crates/ra_hir/src/nameres.rs50
-rw-r--r--crates/ra_hir/src/nameres/lower.rs7
-rw-r--r--crates/ra_hir/src/nameres/tests.rs37
-rw-r--r--crates/ra_hir/src/resolve.rs12
-rw-r--r--crates/ra_syntax/src/ast/generated.rs1
-rw-r--r--crates/ra_syntax/src/grammar.ron3
7 files changed, 99 insertions, 12 deletions
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!(
6 type_var_resolves_to_int_var 6 type_var_resolves_to_int_var
7 glob_enum 7 glob_enum
8 glob_across_crates 8 glob_across_crates
9 std_prelude
9); 10);
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::{
34/// module, the set of visible items. 34/// module, the set of visible items.
35#[derive(Default, Debug, PartialEq, Eq)] 35#[derive(Default, Debug, PartialEq, Eq)]
36pub struct ItemMap { 36pub struct ItemMap {
37 /// The prelude module for this crate. This either comes from an import
38 /// marked with the `prelude_import` attribute, or (in the normal case) from
39 /// a dependency (`std` or `core`).
40 prelude: Option<Module>,
37 pub(crate) extern_prelude: FxHashMap<Name, ModuleDef>, 41 pub(crate) extern_prelude: FxHashMap<Name, ModuleDef>,
38 per_module: ArenaMap<ModuleId, ModuleScope>, 42 per_module: ArenaMap<ModuleId, ModuleScope>,
39} 43}
@@ -211,6 +215,13 @@ where
211 if let Some(module) = dep.krate.root_module(self.db) { 215 if let Some(module) = dep.krate.root_module(self.db) {
212 self.result.extern_prelude.insert(dep.name.clone(), module.into()); 216 self.result.extern_prelude.insert(dep.name.clone(), module.into());
213 } 217 }
218 // look for the prelude
219 if self.result.prelude.is_none() {
220 let item_map = self.db.item_map(dep.krate);
221 if item_map.prelude.is_some() {
222 self.result.prelude = item_map.prelude;
223 }
224 }
214 } 225 }
215 } 226 }
216 227
@@ -279,7 +290,10 @@ where
279 log::debug!("glob import: {:?}", import); 290 log::debug!("glob import: {:?}", import);
280 match def.take_types() { 291 match def.take_types() {
281 Some(ModuleDef::Module(m)) => { 292 Some(ModuleDef::Module(m)) => {
282 if m.krate != self.krate { 293 if import.is_prelude {
294 tested_by!(std_prelude);
295 self.result.prelude = Some(m);
296 } else if m.krate != self.krate {
283 tested_by!(glob_across_crates); 297 tested_by!(glob_across_crates);
284 // glob import from other crate => we can just import everything once 298 // glob import from other crate => we can just import everything once
285 let item_map = self.db.item_map(m.krate); 299 let item_map = self.db.item_map(m.krate);
@@ -434,12 +448,40 @@ impl ItemMap {
434 self.resolve_path_fp(db, original_module, path).0 448 self.resolve_path_fp(db, original_module, path).0
435 } 449 }
436 450
437 pub(crate) fn resolve_name_in_module(&self, module: Module, name: &Name) -> PerNs<ModuleDef> { 451 fn resolve_in_prelude(
452 &self,
453 db: &impl PersistentHirDatabase,
454 original_module: Module,
455 name: &Name,
456 ) -> PerNs<ModuleDef> {
457 if let Some(prelude) = self.prelude {
458 let resolution = if prelude.krate == original_module.krate {
459 self[prelude.module_id].items.get(name).cloned()
460 } else {
461 db.item_map(prelude.krate)[prelude.module_id].items.get(name).cloned()
462 };
463 resolution.map(|r| r.def).unwrap_or_else(PerNs::none)
464 } else {
465 PerNs::none()
466 }
467 }
468
469 pub(crate) fn resolve_name_in_module(
470 &self,
471 db: &impl PersistentHirDatabase,
472 module: Module,
473 name: &Name,
474 ) -> PerNs<ModuleDef> {
475 // Resolve in:
476 // - current module / scope
477 // - extern prelude
478 // - std prelude
438 let from_scope = self[module.module_id].items.get(name).map_or(PerNs::none(), |it| it.def); 479 let from_scope = self[module.module_id].items.get(name).map_or(PerNs::none(), |it| it.def);
439 let from_extern_prelude = 480 let from_extern_prelude =
440 self.extern_prelude.get(name).map_or(PerNs::none(), |&it| PerNs::types(it)); 481 self.extern_prelude.get(name).map_or(PerNs::none(), |&it| PerNs::types(it));
482 let from_prelude = self.resolve_in_prelude(db, module, name);
441 483
442 from_scope.or(from_extern_prelude) 484 from_scope.or(from_extern_prelude).or(from_prelude)
443 } 485 }
444 486
445 // Returns Yes if we are sure that additions to `ItemMap` wouldn't change 487 // Returns Yes if we are sure that additions to `ItemMap` wouldn't change
@@ -459,7 +501,7 @@ impl ItemMap {
459 Some((_, segment)) => segment, 501 Some((_, segment)) => segment,
460 None => return (PerNs::none(), ReachedFixedPoint::Yes), 502 None => return (PerNs::none(), ReachedFixedPoint::Yes),
461 }; 503 };
462 self.resolve_name_in_module(original_module, &segment.name) 504 self.resolve_name_in_module(db, original_module, &segment.name)
463 } 505 }
464 PathKind::Super => { 506 PathKind::Super => {
465 if let Some(p) = original_module.parent(db) { 507 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;
2 2
3use ra_syntax::{ 3use ra_syntax::{
4 AstNode, SourceFile, TreeArc, AstPtr, 4 AstNode, SourceFile, TreeArc, AstPtr,
5 ast::{self, ModuleItemOwner, NameOwner}, 5 ast::{self, ModuleItemOwner, NameOwner, AttrsOwner},
6}; 6};
7use ra_arena::{Arena, RawId, impl_arena_id, map::ArenaMap}; 7use ra_arena::{Arena, RawId, impl_arena_id, map::ArenaMap};
8use rustc_hash::FxHashMap; 8use rustc_hash::FxHashMap;
@@ -23,6 +23,7 @@ pub(super) struct ImportData {
23 pub(super) path: Path, 23 pub(super) path: Path,
24 pub(super) alias: Option<Name>, 24 pub(super) alias: Option<Name>,
25 pub(super) is_glob: bool, 25 pub(super) is_glob: bool,
26 pub(super) is_prelude: bool,
26 pub(super) is_extern_crate: bool, 27 pub(super) is_extern_crate: bool,
27} 28}
28 29
@@ -191,6 +192,7 @@ impl LoweredModule {
191 path, 192 path,
192 alias, 193 alias,
193 is_glob: false, 194 is_glob: false,
195 is_prelude: false,
194 is_extern_crate: true, 196 is_extern_crate: true,
195 }); 197 });
196 } 198 }
@@ -214,11 +216,14 @@ impl LoweredModule {
214 } 216 }
215 217
216 fn add_use_item(&mut self, source_map: &mut ImportSourceMap, item: &ast::UseItem) { 218 fn add_use_item(&mut self, source_map: &mut ImportSourceMap, item: &ast::UseItem) {
219 let is_prelude =
220 item.attrs().any(|attr| attr.as_atom().map(|s| s == "prelude_import").unwrap_or(false));
217 Path::expand_use_item(item, |path, segment, alias| { 221 Path::expand_use_item(item, |path, segment, alias| {
218 let import = self.imports.alloc(ImportData { 222 let import = self.imports.alloc(ImportData {
219 path, 223 path,
220 alias, 224 alias,
221 is_glob: segment.is_none(), 225 is_glob: segment.is_none(),
226 is_prelude,
222 is_extern_crate: false, 227 is_extern_crate: false,
223 }); 228 });
224 if let Some(segment) = segment { 229 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
@@ -297,6 +297,43 @@ fn module_resolution_works_for_non_standard_filenames() {
297} 297}
298 298
299#[test] 299#[test]
300fn std_prelude() {
301 covers!(std_prelude);
302 let mut db = MockDatabase::with_files(
303 "
304 //- /main.rs
305 use Foo::*;
306
307 //- /lib.rs
308 mod prelude;
309 #[prelude_import]
310 use prelude::*;
311
312 //- /prelude.rs
313 pub enum Foo { Bar, Baz };
314 ",
315 );
316 db.set_crate_graph_from_fixture(crate_graph! {
317 "main": ("/main.rs", ["test_crate"]),
318 "test_crate": ("/lib.rs", []),
319 });
320 let main_id = db.file_id_of("/main.rs");
321
322 let module = crate::source_binder::module_from_file_id(&db, main_id).unwrap();
323 let krate = module.krate(&db).unwrap();
324 let item_map = db.item_map(krate);
325
326 check_module_item_map(
327 &item_map,
328 module.module_id,
329 "
330 Bar: t v
331 Baz: t v
332 ",
333 );
334}
335
336#[test]
300fn name_res_works_for_broken_modules() { 337fn name_res_works_for_broken_modules() {
301 covers!(name_res_works_for_broken_modules); 338 covers!(name_res_works_for_broken_modules);
302 let (item_map, module_id) = item_map( 339 let (item_map, module_id) = item_map(
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 {
56} 56}
57 57
58impl Resolver { 58impl Resolver {
59 pub fn resolve_name(&self, name: &Name) -> PerNs<Resolution> { 59 pub fn resolve_name(&self, db: &impl HirDatabase, name: &Name) -> PerNs<Resolution> {
60 let mut resolution = PerNs::none(); 60 let mut resolution = PerNs::none();
61 for scope in self.scopes.iter().rev() { 61 for scope in self.scopes.iter().rev() {
62 resolution = resolution.or(scope.resolve_name(name)); 62 resolution = resolution.or(scope.resolve_name(db, name));
63 if resolution.is_both() { 63 if resolution.is_both() {
64 return resolution; 64 return resolution;
65 } 65 }
@@ -69,9 +69,9 @@ impl Resolver {
69 69
70 pub fn resolve_path(&self, db: &impl HirDatabase, path: &Path) -> PerNs<Resolution> { 70 pub fn resolve_path(&self, db: &impl HirDatabase, path: &Path) -> PerNs<Resolution> {
71 if let Some(name) = path.as_ident() { 71 if let Some(name) = path.as_ident() {
72 self.resolve_name(name) 72 self.resolve_name(db, name)
73 } else if path.is_self() { 73 } else if path.is_self() {
74 self.resolve_name(&Name::self_param()) 74 self.resolve_name(db, &Name::self_param())
75 } else { 75 } else {
76 let (item_map, module) = match self.module() { 76 let (item_map, module) = match self.module() {
77 Some(m) => m, 77 Some(m) => m,
@@ -143,13 +143,13 @@ impl Resolver {
143} 143}
144 144
145impl Scope { 145impl Scope {
146 fn resolve_name(&self, name: &Name) -> PerNs<Resolution> { 146 fn resolve_name(&self, db: &impl HirDatabase, name: &Name) -> PerNs<Resolution> {
147 match self { 147 match self {
148 Scope::ModuleScope(m) => { 148 Scope::ModuleScope(m) => {
149 if let Some(KnownName::SelfParam) = name.as_known_name() { 149 if let Some(KnownName::SelfParam) = name.as_known_name() {
150 PerNs::types(Resolution::Def(m.module.into())) 150 PerNs::types(Resolution::Def(m.module.into()))
151 } else { 151 } else {
152 m.item_map.resolve_name_in_module(m.module, name).map(Resolution::Def) 152 m.item_map.resolve_name_in_module(db, m.module, name).map(Resolution::Def)
153 } 153 }
154 } 154 }
155 Scope::GenericParams(gp) => match gp.find_by_name(name) { 155 Scope::GenericParams(gp) => match gp.find_by_name(name) {
diff --git a/crates/ra_syntax/src/ast/generated.rs b/crates/ra_syntax/src/ast/generated.rs
index 5df3f2ccf..7c5e8ce5e 100644
--- a/crates/ra_syntax/src/ast/generated.rs
+++ b/crates/ra_syntax/src/ast/generated.rs
@@ -4210,6 +4210,7 @@ impl ToOwned for UseItem {
4210} 4210}
4211 4211
4212 4212
4213impl ast::AttrsOwner for UseItem {}
4213impl UseItem { 4214impl UseItem {
4214 pub fn use_tree(&self) -> Option<&UseTree> { 4215 pub fn use_tree(&self) -> Option<&UseTree> {
4215 super::child_opt(self) 4216 super::child_opt(self)
diff --git a/crates/ra_syntax/src/grammar.ron b/crates/ra_syntax/src/grammar.ron
index 2e4b2d776..304bc5909 100644
--- a/crates/ra_syntax/src/grammar.ron
+++ b/crates/ra_syntax/src/grammar.ron
@@ -596,7 +596,8 @@ Grammar(
596 options: [ "Pat", "TypeRef" ], 596 options: [ "Pat", "TypeRef" ],
597 ), 597 ),
598 "UseItem": ( 598 "UseItem": (
599 options: [ "UseTree" ] 599 traits: ["AttrsOwner"],
600 options: [ "UseTree" ],
600 ), 601 ),
601 "UseTree": ( 602 "UseTree": (
602 options: [ "Path", "UseTreeList", "Alias" ] 603 options: [ "Path", "UseTreeList", "Alias" ]