diff options
Diffstat (limited to 'crates/ra_hir/src/nameres.rs')
-rw-r--r-- | crates/ra_hir/src/nameres.rs | 50 |
1 files changed, 46 insertions, 4 deletions
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) { |