diff options
author | Florian Diebold <[email protected]> | 2019-02-10 19:44:34 +0000 |
---|---|---|
committer | Florian Diebold <[email protected]> | 2019-02-13 19:10:09 +0000 |
commit | 1526eb25c98fd16a9c0d114d0ed44e8fec1cc19c (patch) | |
tree | 1acf0f556de14a2fac88929db9af96025a47f79f /crates | |
parent | 65266c644a31e6b321e5afb3c5a2ee75be76cb0c (diff) |
Import the prelude
Diffstat (limited to 'crates')
-rw-r--r-- | crates/ra_hir/src/marks.rs | 1 | ||||
-rw-r--r-- | crates/ra_hir/src/nameres.rs | 50 | ||||
-rw-r--r-- | crates/ra_hir/src/nameres/lower.rs | 7 | ||||
-rw-r--r-- | crates/ra_hir/src/nameres/tests.rs | 37 | ||||
-rw-r--r-- | crates/ra_hir/src/resolve.rs | 12 | ||||
-rw-r--r-- | crates/ra_syntax/src/ast/generated.rs | 1 | ||||
-rw-r--r-- | crates/ra_syntax/src/grammar.ron | 3 |
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)] |
36 | pub struct ItemMap { | 36 | pub 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 | ||
3 | use ra_syntax::{ | 3 | use 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 | }; |
7 | use ra_arena::{Arena, RawId, impl_arena_id, map::ArenaMap}; | 7 | use ra_arena::{Arena, RawId, impl_arena_id, map::ArenaMap}; |
8 | use rustc_hash::FxHashMap; | 8 | use 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] |
300 | fn 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] | ||
300 | fn name_res_works_for_broken_modules() { | 337 | fn 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 | ||
58 | impl Resolver { | 58 | impl 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 | ||
145 | impl Scope { | 145 | impl 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 | ||
4213 | impl ast::AttrsOwner for UseItem {} | ||
4213 | impl UseItem { | 4214 | impl 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" ] |