aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir/src/nameres/collector.rs
diff options
context:
space:
mode:
authoruHOOCCOOHu <[email protected]>2019-09-06 17:55:58 +0100
committeruHOOCCOOHu <[email protected]>2019-09-08 18:33:28 +0100
commite0f305a6bf710f64f789f909da93a8c362823b67 (patch)
treec34e3c7e8973c5a7137d1e0cd06ce9903f67b710 /crates/ra_hir/src/nameres/collector.rs
parent07e3976f426aaab93bfd3056374ec6ed32ffb255 (diff)
Support textual scoped macros
Diffstat (limited to 'crates/ra_hir/src/nameres/collector.rs')
-rw-r--r--crates/ra_hir/src/nameres/collector.rs84
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, &macro_id) in &item_map.exported_macros { 199 for (name, &macro_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
694fn is_macro_rules(path: &Path) -> bool { 715fn 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();