diff options
author | uHOOCCOOHu <[email protected]> | 2019-09-06 17:55:58 +0100 |
---|---|---|
committer | uHOOCCOOHu <[email protected]> | 2019-09-08 18:33:28 +0100 |
commit | e0f305a6bf710f64f789f909da93a8c362823b67 (patch) | |
tree | c34e3c7e8973c5a7137d1e0cd06ce9903f67b710 /crates/ra_hir/src/nameres/collector.rs | |
parent | 07e3976f426aaab93bfd3056374ec6ed32ffb255 (diff) |
Support textual scoped macros
Diffstat (limited to 'crates/ra_hir/src/nameres/collector.rs')
-rw-r--r-- | crates/ra_hir/src/nameres/collector.rs | 84 |
1 files changed, 52 insertions, 32 deletions
diff --git a/crates/ra_hir/src/nameres/collector.rs b/crates/ra_hir/src/nameres/collector.rs index 1c0d4369e..f897547e3 100644 --- a/crates/ra_hir/src/nameres/collector.rs +++ b/crates/ra_hir/src/nameres/collector.rs | |||
@@ -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,35 @@ 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_textual_macro(module_id, name.clone(), macro_id); |
150 | } | ||
151 | |||
152 | /// Define a macro in current textual scope. | ||
153 | /// | ||
154 | /// We use a map `textual_macros` to store all textual macros visable per module. | ||
155 | /// It will clone all macros from parent textual scope, whose definition is prior to | ||
156 | /// the definition of current module. | ||
157 | /// And also, `macro_use` on a module will import all textual macros visable inside to | ||
158 | /// current textual scope, with possible shadowing. | ||
159 | /// | ||
160 | /// In a single module, the order of definition/usage of textual scoped macros matters. | ||
161 | /// But we ignore it here to make it easy to implement. | ||
162 | fn define_textual_macro(&mut self, module_id: CrateModuleId, name: Name, macro_id: MacroDefId) { | ||
163 | // Always shadowing | ||
164 | self.def_map.modules[module_id] | ||
165 | .scope | ||
166 | .textual_macros | ||
167 | .insert(name, MacroDef { id: macro_id }); | ||
166 | } | 168 | } |
167 | 169 | ||
168 | /// Import macros from `#[macro_use] extern crate`. | 170 | /// Import macros from `#[macro_use] extern crate`. |
169 | /// | 171 | /// |
170 | /// They are non-scoped, and will only be inserted into mutable `global_macro_scope`. | 172 | /// 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) { | 173 | fn import_macros_from_extern_crate( |
174 | &mut self, | ||
175 | current_module_id: CrateModuleId, | ||
176 | import: &raw::ImportData, | ||
177 | ) { | ||
172 | log::debug!( | 178 | log::debug!( |
173 | "importing macros from extern crate: {:?} ({:?})", | 179 | "importing macros from extern crate: {:?} ({:?})", |
174 | import, | 180 | import, |
@@ -184,14 +190,14 @@ where | |||
184 | 190 | ||
185 | if let Some(ModuleDef::Module(m)) = res.take_types() { | 191 | if let Some(ModuleDef::Module(m)) = res.take_types() { |
186 | tested_by!(macro_rules_from_other_crates_are_visible_with_macro_use); | 192 | tested_by!(macro_rules_from_other_crates_are_visible_with_macro_use); |
187 | self.import_all_macros_exported(m); | 193 | self.import_all_macros_exported(current_module_id, m); |
188 | } | 194 | } |
189 | } | 195 | } |
190 | 196 | ||
191 | fn import_all_macros_exported(&mut self, module: Module) { | 197 | fn import_all_macros_exported(&mut self, current_module_id: CrateModuleId, module: Module) { |
192 | let item_map = self.db.crate_def_map(module.krate); | 198 | let item_map = self.db.crate_def_map(module.krate); |
193 | for (name, ¯o_id) in &item_map.exported_macros { | 199 | for (name, ¯o_id) in &item_map.exported_macros { |
194 | self.global_macro_scope.insert(name.clone(), macro_id); | 200 | self.define_textual_macro(current_module_id, name.clone(), macro_id); |
195 | } | 201 | } |
196 | } | 202 | } |
197 | 203 | ||
@@ -528,7 +534,7 @@ where | |||
528 | if let Some(prelude_module) = self.def_collector.def_map.prelude { | 534 | if let Some(prelude_module) = self.def_collector.def_map.prelude { |
529 | if prelude_module.krate != self.def_collector.def_map.krate { | 535 | if prelude_module.krate != self.def_collector.def_map.krate { |
530 | tested_by!(prelude_is_macro_use); | 536 | tested_by!(prelude_is_macro_use); |
531 | self.def_collector.import_all_macros_exported(prelude_module); | 537 | self.def_collector.import_all_macros_exported(self.module_id, prelude_module); |
532 | } | 538 | } |
533 | } | 539 | } |
534 | 540 | ||
@@ -539,7 +545,7 @@ where | |||
539 | if let raw::RawItem::Import(import_id) = *item { | 545 | if let raw::RawItem::Import(import_id) = *item { |
540 | let import = self.raw_items[import_id].clone(); | 546 | let import = self.raw_items[import_id].clone(); |
541 | if import.is_extern_crate && import.is_macro_use { | 547 | if import.is_extern_crate && import.is_macro_use { |
542 | self.def_collector.import_macros_from_extern_crate(&import); | 548 | self.def_collector.import_macros_from_extern_crate(self.module_id, &import); |
543 | } | 549 | } |
544 | } | 550 | } |
545 | } | 551 | } |
@@ -561,10 +567,11 @@ where | |||
561 | fn collect_module(&mut self, module: &raw::ModuleData) { | 567 | fn collect_module(&mut self, module: &raw::ModuleData) { |
562 | match module { | 568 | match module { |
563 | // inline module, just recurse | 569 | // inline module, just recurse |
564 | raw::ModuleData::Definition { name, items, ast_id, attr_path } => { | 570 | raw::ModuleData::Definition { name, items, ast_id, attr_path, is_macro_use } => { |
565 | let module_id = | 571 | let module_id = |
566 | self.push_child_module(name.clone(), ast_id.with_file_id(self.file_id), None); | 572 | 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() }; | 573 | let parent_module = ParentModule { name, attr_path: attr_path.as_ref() }; |
574 | |||
568 | ModCollector { | 575 | ModCollector { |
569 | def_collector: &mut *self.def_collector, | 576 | def_collector: &mut *self.def_collector, |
570 | module_id, | 577 | module_id, |
@@ -573,9 +580,12 @@ where | |||
573 | parent_module: Some(parent_module), | 580 | parent_module: Some(parent_module), |
574 | } | 581 | } |
575 | .collect(&*items); | 582 | .collect(&*items); |
583 | if *is_macro_use { | ||
584 | self.import_all_textual_macros(module_id); | ||
585 | } | ||
576 | } | 586 | } |
577 | // out of line module, resolve, parse and recurse | 587 | // out of line module, resolve, parse and recurse |
578 | raw::ModuleData::Declaration { name, ast_id, attr_path } => { | 588 | raw::ModuleData::Declaration { name, ast_id, attr_path, is_macro_use } => { |
579 | let ast_id = ast_id.with_file_id(self.file_id); | 589 | 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(); | 590 | let is_root = self.def_collector.def_map.modules[self.module_id].parent.is_none(); |
581 | match resolve_submodule( | 591 | match resolve_submodule( |
@@ -596,7 +606,10 @@ where | |||
596 | raw_items: &raw_items, | 606 | raw_items: &raw_items, |
597 | parent_module: None, | 607 | parent_module: None, |
598 | } | 608 | } |
599 | .collect(raw_items.items()) | 609 | .collect(raw_items.items()); |
610 | if *is_macro_use { | ||
611 | self.import_all_textual_macros(module_id); | ||
612 | } | ||
600 | } | 613 | } |
601 | Err(candidate) => self.def_collector.def_map.diagnostics.push( | 614 | Err(candidate) => self.def_collector.def_map.diagnostics.push( |
602 | DefDiagnostic::UnresolvedModule { | 615 | DefDiagnostic::UnresolvedModule { |
@@ -621,6 +634,7 @@ where | |||
621 | modules[res].parent = Some(self.module_id); | 634 | modules[res].parent = Some(self.module_id); |
622 | modules[res].declaration = Some(declaration); | 635 | modules[res].declaration = Some(declaration); |
623 | modules[res].definition = definition; | 636 | modules[res].definition = definition; |
637 | modules[res].scope.textual_macros = modules[self.module_id].scope.textual_macros.clone(); | ||
624 | modules[self.module_id].children.insert(name.clone(), res); | 638 | modules[self.module_id].children.insert(name.clone(), res); |
625 | let resolution = Resolution { | 639 | let resolution = Resolution { |
626 | def: PerNs::types( | 640 | def: PerNs::types( |
@@ -674,12 +688,12 @@ where | |||
674 | 688 | ||
675 | let ast_id = mac.ast_id.with_file_id(self.file_id); | 689 | let ast_id = mac.ast_id.with_file_id(self.file_id); |
676 | 690 | ||
677 | // Case 2: try to expand macro_rules from this crate, triggering | 691 | // Case 2: try to resolve in textual scope and expand macro_rules, triggering |
678 | // recursive item collection. | 692 | // recursive item collection. |
679 | if let Some(macro_id) = | 693 | 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)) | 694 | self.def_collector.def_map[self.module_id].scope.get_textual_macro(&name) |
681 | { | 695 | }) { |
682 | let def = *macro_id; | 696 | let def = macro_def.id; |
683 | let macro_call_id = MacroCallLoc { def, ast_id }.id(self.def_collector.db); | 697 | let macro_call_id = MacroCallLoc { def, ast_id }.id(self.def_collector.db); |
684 | 698 | ||
685 | self.def_collector.collect_macro_expansion(self.module_id, macro_call_id, def); | 699 | self.def_collector.collect_macro_expansion(self.module_id, macro_call_id, def); |
@@ -689,6 +703,13 @@ where | |||
689 | // Case 3: path to a macro from another crate, expand during name resolution | 703 | // Case 3: path to a macro from another crate, expand during name resolution |
690 | self.def_collector.unexpanded_macros.push((self.module_id, ast_id, mac.path.clone())) | 704 | self.def_collector.unexpanded_macros.push((self.module_id, ast_id, mac.path.clone())) |
691 | } | 705 | } |
706 | |||
707 | fn import_all_textual_macros(&mut self, module_id: CrateModuleId) { | ||
708 | let macros = self.def_collector.def_map[module_id].scope.textual_macros.clone(); | ||
709 | for (name, macro_) in macros { | ||
710 | self.def_collector.define_textual_macro(self.module_id, name.clone(), macro_.id); | ||
711 | } | ||
712 | } | ||
692 | } | 713 | } |
693 | 714 | ||
694 | fn is_macro_rules(path: &Path) -> bool { | 715 | fn is_macro_rules(path: &Path) -> bool { |
@@ -715,7 +736,6 @@ mod tests { | |||
715 | glob_imports: FxHashMap::default(), | 736 | glob_imports: FxHashMap::default(), |
716 | unresolved_imports: Vec::new(), | 737 | unresolved_imports: Vec::new(), |
717 | unexpanded_macros: Vec::new(), | 738 | unexpanded_macros: Vec::new(), |
718 | global_macro_scope: FxHashMap::default(), | ||
719 | macro_stack_monitor: monitor, | 739 | macro_stack_monitor: monitor, |
720 | }; | 740 | }; |
721 | collector.collect(); | 741 | collector.collect(); |