diff options
Diffstat (limited to 'crates/ra_hir/src/nameres/collector.rs')
-rw-r--r-- | crates/ra_hir/src/nameres/collector.rs | 91 |
1 files changed, 55 insertions, 36 deletions
diff --git a/crates/ra_hir/src/nameres/collector.rs b/crates/ra_hir/src/nameres/collector.rs index 1c0d4369e..09cda7656 100644 --- a/crates/ra_hir/src/nameres/collector.rs +++ b/crates/ra_hir/src/nameres/collector.rs | |||
@@ -14,8 +14,8 @@ use crate::{ | |||
14 | raw, CrateDefMap, CrateModuleId, ItemOrMacro, ModuleData, ModuleDef, PerNs, | 14 | raw, CrateDefMap, CrateModuleId, ItemOrMacro, ModuleData, ModuleDef, PerNs, |
15 | ReachedFixedPoint, Resolution, ResolveMode, | 15 | ReachedFixedPoint, Resolution, ResolveMode, |
16 | }, | 16 | }, |
17 | AstId, Const, Enum, Function, HirFileId, MacroDef, Module, Name, Path, Static, Struct, Trait, | 17 | AstId, Const, Enum, Function, HirFileId, MacroDef, Module, Name, Path, PathKind, Static, |
18 | TypeAlias, Union, | 18 | Struct, Trait, TypeAlias, Union, |
19 | }; | 19 | }; |
20 | 20 | ||
21 | pub(super) fn collect_defs(db: &impl DefDatabase, mut def_map: CrateDefMap) -> CrateDefMap { | 21 | pub(super) fn collect_defs(db: &impl DefDatabase, mut def_map: CrateDefMap) -> CrateDefMap { |
@@ -40,7 +40,6 @@ pub(super) fn collect_defs(db: &impl DefDatabase, mut def_map: CrateDefMap) -> C | |||
40 | glob_imports: FxHashMap::default(), | 40 | glob_imports: FxHashMap::default(), |
41 | unresolved_imports: Vec::new(), | 41 | unresolved_imports: Vec::new(), |
42 | unexpanded_macros: Vec::new(), | 42 | unexpanded_macros: Vec::new(), |
43 | global_macro_scope: FxHashMap::default(), | ||
44 | macro_stack_monitor: MacroStackMonitor::default(), | 43 | macro_stack_monitor: MacroStackMonitor::default(), |
45 | }; | 44 | }; |
46 | collector.collect(); | 45 | collector.collect(); |
@@ -82,7 +81,6 @@ struct DefCollector<DB> { | |||
82 | glob_imports: FxHashMap<CrateModuleId, Vec<(CrateModuleId, raw::ImportId)>>, | 81 | glob_imports: FxHashMap<CrateModuleId, Vec<(CrateModuleId, raw::ImportId)>>, |
83 | unresolved_imports: Vec<(CrateModuleId, raw::ImportId, raw::ImportData)>, | 82 | unresolved_imports: Vec<(CrateModuleId, raw::ImportId, raw::ImportData)>, |
84 | unexpanded_macros: Vec<(CrateModuleId, AstId<ast::MacroCall>, Path)>, | 83 | unexpanded_macros: Vec<(CrateModuleId, AstId<ast::MacroCall>, Path)>, |
85 | global_macro_scope: FxHashMap<Name, MacroDefId>, | ||
86 | 84 | ||
87 | /// Some macro use `$tt:tt which mean we have to handle the macro perfectly | 85 | /// Some macro use `$tt:tt which mean we have to handle the macro perfectly |
88 | /// To prevent stack overflow, we add a deep counter here for prevent that. | 86 | /// To prevent stack overflow, we add a deep counter here for prevent that. |
@@ -136,20 +134,6 @@ where | |||
136 | macro_id: MacroDefId, | 134 | macro_id: MacroDefId, |
137 | export: bool, | 135 | export: bool, |
138 | ) { | 136 | ) { |
139 | // macro-by-example in Rust have completely weird name resolution logic, | ||
140 | // unlike anything else in the language. We'd don't fully implement yet, | ||
141 | // just give a somewhat precise approximation. | ||
142 | // | ||
143 | // Specifically, we store a set of visible macros in each module, just | ||
144 | // like how we do with usual items. This is wrong, however, because | ||
145 | // macros can be shadowed and their scopes are mostly unrelated to | ||
146 | // modules. To paper over the second problem, we also maintain | ||
147 | // `global_macro_scope` which works when we construct `CrateDefMap`, but | ||
148 | // is completely ignored in expressions. | ||
149 | // | ||
150 | // What we should do is that, in CrateDefMap, we should maintain a | ||
151 | // separate tower of macro scopes, with ids. Then, for each item in the | ||
152 | // module, we need to store it's macro scope. | ||
153 | let def = Either::B(MacroDef { id: macro_id }); | 137 | let def = Either::B(MacroDef { id: macro_id }); |
154 | 138 | ||
155 | // In Rust, `#[macro_export]` macros are unconditionally visible at the | 139 | // In Rust, `#[macro_export]` macros are unconditionally visible at the |
@@ -162,13 +146,29 @@ where | |||
162 | self.def_map.exported_macros.insert(name.clone(), macro_id); | 146 | self.def_map.exported_macros.insert(name.clone(), macro_id); |
163 | } | 147 | } |
164 | self.update(module_id, None, &[(name.clone(), def)]); | 148 | self.update(module_id, None, &[(name.clone(), def)]); |
165 | self.global_macro_scope.insert(name, macro_id); | 149 | self.define_legacy_macro(module_id, name.clone(), macro_id); |
150 | } | ||
151 | |||
152 | /// Define a legacy textual scoped macro in module | ||
153 | /// | ||
154 | /// We use a map `legacy_macros` to store all legacy textual scoped macros visable per module. | ||
155 | /// It will clone all macros from parent legacy scope, whose definition is prior to | ||
156 | /// the definition of current module. | ||
157 | /// And also, `macro_use` on a module will import all legacy macros visable inside to | ||
158 | /// current legacy scope, with possible shadowing. | ||
159 | fn define_legacy_macro(&mut self, module_id: CrateModuleId, name: Name, macro_id: MacroDefId) { | ||
160 | // Always shadowing | ||
161 | self.def_map.modules[module_id].scope.legacy_macros.insert(name, MacroDef { id: macro_id }); | ||
166 | } | 162 | } |
167 | 163 | ||
168 | /// Import macros from `#[macro_use] extern crate`. | 164 | /// Import macros from `#[macro_use] extern crate`. |
169 | /// | 165 | /// |
170 | /// They are non-scoped, and will only be inserted into mutable `global_macro_scope`. | 166 | /// They are non-scoped, and will only be inserted into mutable `global_macro_scope`. |
171 | fn import_macros_from_extern_crate(&mut self, import: &raw::ImportData) { | 167 | fn import_macros_from_extern_crate( |
168 | &mut self, | ||
169 | current_module_id: CrateModuleId, | ||
170 | import: &raw::ImportData, | ||
171 | ) { | ||
172 | log::debug!( | 172 | log::debug!( |
173 | "importing macros from extern crate: {:?} ({:?})", | 173 | "importing macros from extern crate: {:?} ({:?})", |
174 | import, | 174 | import, |
@@ -184,14 +184,14 @@ where | |||
184 | 184 | ||
185 | if let Some(ModuleDef::Module(m)) = res.take_types() { | 185 | if let Some(ModuleDef::Module(m)) = res.take_types() { |
186 | tested_by!(macro_rules_from_other_crates_are_visible_with_macro_use); | 186 | tested_by!(macro_rules_from_other_crates_are_visible_with_macro_use); |
187 | self.import_all_macros_exported(m); | 187 | self.import_all_macros_exported(current_module_id, m); |
188 | } | 188 | } |
189 | } | 189 | } |
190 | 190 | ||
191 | fn import_all_macros_exported(&mut self, module: Module) { | 191 | fn import_all_macros_exported(&mut self, current_module_id: CrateModuleId, module: Module) { |
192 | let item_map = self.db.crate_def_map(module.krate); | 192 | let item_map = self.db.crate_def_map(module.krate); |
193 | for (name, ¯o_id) in &item_map.exported_macros { | 193 | for (name, ¯o_id) in &item_map.exported_macros { |
194 | self.global_macro_scope.insert(name.clone(), macro_id); | 194 | self.define_legacy_macro(current_module_id, name.clone(), macro_id); |
195 | } | 195 | } |
196 | } | 196 | } |
197 | 197 | ||
@@ -528,7 +528,7 @@ where | |||
528 | if let Some(prelude_module) = self.def_collector.def_map.prelude { | 528 | if let Some(prelude_module) = self.def_collector.def_map.prelude { |
529 | if prelude_module.krate != self.def_collector.def_map.krate { | 529 | if prelude_module.krate != self.def_collector.def_map.krate { |
530 | tested_by!(prelude_is_macro_use); | 530 | tested_by!(prelude_is_macro_use); |
531 | self.def_collector.import_all_macros_exported(prelude_module); | 531 | self.def_collector.import_all_macros_exported(self.module_id, prelude_module); |
532 | } | 532 | } |
533 | } | 533 | } |
534 | 534 | ||
@@ -539,7 +539,7 @@ where | |||
539 | if let raw::RawItem::Import(import_id) = *item { | 539 | if let raw::RawItem::Import(import_id) = *item { |
540 | let import = self.raw_items[import_id].clone(); | 540 | let import = self.raw_items[import_id].clone(); |
541 | if import.is_extern_crate && import.is_macro_use { | 541 | if import.is_extern_crate && import.is_macro_use { |
542 | self.def_collector.import_macros_from_extern_crate(&import); | 542 | self.def_collector.import_macros_from_extern_crate(self.module_id, &import); |
543 | } | 543 | } |
544 | } | 544 | } |
545 | } | 545 | } |
@@ -561,10 +561,11 @@ where | |||
561 | fn collect_module(&mut self, module: &raw::ModuleData) { | 561 | fn collect_module(&mut self, module: &raw::ModuleData) { |
562 | match module { | 562 | match module { |
563 | // inline module, just recurse | 563 | // inline module, just recurse |
564 | raw::ModuleData::Definition { name, items, ast_id, attr_path } => { | 564 | raw::ModuleData::Definition { name, items, ast_id, attr_path, is_macro_use } => { |
565 | let module_id = | 565 | let module_id = |
566 | self.push_child_module(name.clone(), ast_id.with_file_id(self.file_id), None); | 566 | self.push_child_module(name.clone(), ast_id.with_file_id(self.file_id), None); |
567 | let parent_module = ParentModule { name, attr_path: attr_path.as_ref() }; | 567 | let parent_module = ParentModule { name, attr_path: attr_path.as_ref() }; |
568 | |||
568 | ModCollector { | 569 | ModCollector { |
569 | def_collector: &mut *self.def_collector, | 570 | def_collector: &mut *self.def_collector, |
570 | module_id, | 571 | module_id, |
@@ -573,9 +574,12 @@ where | |||
573 | parent_module: Some(parent_module), | 574 | parent_module: Some(parent_module), |
574 | } | 575 | } |
575 | .collect(&*items); | 576 | .collect(&*items); |
577 | if *is_macro_use { | ||
578 | self.import_all_legacy_macros(module_id); | ||
579 | } | ||
576 | } | 580 | } |
577 | // out of line module, resolve, parse and recurse | 581 | // out of line module, resolve, parse and recurse |
578 | raw::ModuleData::Declaration { name, ast_id, attr_path } => { | 582 | raw::ModuleData::Declaration { name, ast_id, attr_path, is_macro_use } => { |
579 | let ast_id = ast_id.with_file_id(self.file_id); | 583 | let ast_id = ast_id.with_file_id(self.file_id); |
580 | let is_root = self.def_collector.def_map.modules[self.module_id].parent.is_none(); | 584 | let is_root = self.def_collector.def_map.modules[self.module_id].parent.is_none(); |
581 | match resolve_submodule( | 585 | match resolve_submodule( |
@@ -596,7 +600,10 @@ where | |||
596 | raw_items: &raw_items, | 600 | raw_items: &raw_items, |
597 | parent_module: None, | 601 | parent_module: None, |
598 | } | 602 | } |
599 | .collect(raw_items.items()) | 603 | .collect(raw_items.items()); |
604 | if *is_macro_use { | ||
605 | self.import_all_legacy_macros(module_id); | ||
606 | } | ||
600 | } | 607 | } |
601 | Err(candidate) => self.def_collector.def_map.diagnostics.push( | 608 | Err(candidate) => self.def_collector.def_map.diagnostics.push( |
602 | DefDiagnostic::UnresolvedModule { | 609 | DefDiagnostic::UnresolvedModule { |
@@ -621,6 +628,7 @@ where | |||
621 | modules[res].parent = Some(self.module_id); | 628 | modules[res].parent = Some(self.module_id); |
622 | modules[res].declaration = Some(declaration); | 629 | modules[res].declaration = Some(declaration); |
623 | modules[res].definition = definition; | 630 | modules[res].definition = definition; |
631 | modules[res].scope.legacy_macros = modules[self.module_id].scope.legacy_macros.clone(); | ||
624 | modules[self.module_id].children.insert(name.clone(), res); | 632 | modules[self.module_id].children.insert(name.clone(), res); |
625 | let resolution = Resolution { | 633 | let resolution = Resolution { |
626 | def: PerNs::types( | 634 | def: PerNs::types( |
@@ -674,20 +682,32 @@ where | |||
674 | 682 | ||
675 | let ast_id = mac.ast_id.with_file_id(self.file_id); | 683 | let ast_id = mac.ast_id.with_file_id(self.file_id); |
676 | 684 | ||
677 | // Case 2: try to expand macro_rules from this crate, triggering | 685 | // Case 2: try to resolve in legacy scope and expand macro_rules, triggering |
678 | // recursive item collection. | 686 | // recursive item collection. |
679 | if let Some(macro_id) = | 687 | if let Some(macro_def) = mac.path.as_ident().and_then(|name| { |
680 | mac.path.as_ident().and_then(|name| self.def_collector.global_macro_scope.get(&name)) | 688 | self.def_collector.def_map[self.module_id].scope.get_legacy_macro(&name) |
681 | { | 689 | }) { |
682 | let def = *macro_id; | 690 | let def = macro_def.id; |
683 | let macro_call_id = MacroCallLoc { def, ast_id }.id(self.def_collector.db); | 691 | let macro_call_id = MacroCallLoc { def, ast_id }.id(self.def_collector.db); |
684 | 692 | ||
685 | self.def_collector.collect_macro_expansion(self.module_id, macro_call_id, def); | 693 | self.def_collector.collect_macro_expansion(self.module_id, macro_call_id, def); |
686 | return; | 694 | return; |
687 | } | 695 | } |
688 | 696 | ||
689 | // Case 3: path to a macro from another crate, expand during name resolution | 697 | // Case 3: resolve in module scope, expand during name resolution. |
690 | self.def_collector.unexpanded_macros.push((self.module_id, ast_id, mac.path.clone())) | 698 | // We rewrite simple path `macro_name` to `self::macro_name` to force resolve in module scope only. |
699 | let mut path = mac.path.clone(); | ||
700 | if path.is_ident() { | ||
701 | path.kind = PathKind::Self_; | ||
702 | } | ||
703 | self.def_collector.unexpanded_macros.push((self.module_id, ast_id, path)); | ||
704 | } | ||
705 | |||
706 | fn import_all_legacy_macros(&mut self, module_id: CrateModuleId) { | ||
707 | let macros = self.def_collector.def_map[module_id].scope.legacy_macros.clone(); | ||
708 | for (name, macro_) in macros { | ||
709 | self.def_collector.define_legacy_macro(self.module_id, name.clone(), macro_.id); | ||
710 | } | ||
691 | } | 711 | } |
692 | } | 712 | } |
693 | 713 | ||
@@ -715,7 +735,6 @@ mod tests { | |||
715 | glob_imports: FxHashMap::default(), | 735 | glob_imports: FxHashMap::default(), |
716 | unresolved_imports: Vec::new(), | 736 | unresolved_imports: Vec::new(), |
717 | unexpanded_macros: Vec::new(), | 737 | unexpanded_macros: Vec::new(), |
718 | global_macro_scope: FxHashMap::default(), | ||
719 | macro_stack_monitor: monitor, | 738 | macro_stack_monitor: monitor, |
720 | }; | 739 | }; |
721 | collector.collect(); | 740 | collector.collect(); |