aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir/src/nameres/collector.rs
diff options
context:
space:
mode:
authorbors[bot] <26634292+bors[bot]@users.noreply.github.com>2019-09-09 09:04:00 +0100
committerGitHub <[email protected]>2019-09-09 09:04:00 +0100
commit1db08a54c20c244718e2378272c72ae5c6651f06 (patch)
tree90fe99eb39d045d9bac34cc200a74d0410d51763 /crates/ra_hir/src/nameres/collector.rs
parent72259b67bf2393bec1faf6a9f95a575d6fe9cfea (diff)
parent9ed21d65fb6727f6de4961dfa440981864451af6 (diff)
Merge #1784
1784: Support textual scoped macros r=matklad a=uHOOCCOOHu Refactor the old simulation with `global_macro_scope`. Now it is quite accurate to resolve textual scoped macros. - Expand textual scoped macros in item and non-item place. - Support `#[macro_use]` on `mod`. - Textual scoped macros are collected into `nameres::ModuleScope`, so I think it makes #1727 easier to fix. - It is implemented in a simple way to `clone()` current scoped macro ids into sub-modules. Though only indices are cloned, it will still increase some resolving time. Well, I've not bench-marked yet. In my test with vscode extension, it can now successfully expand `dbg!` from `std` without `std::` prefix. "Goto definition" also works. Screenshot here: <img width="281" alt="Screenshot_20190907_043442" src="https://user-images.githubusercontent.com/14816024/64458794-ddb47900-d128-11e9-95e3-1c8569978825.png"> Co-authored-by: uHOOCCOOHu <[email protected]>
Diffstat (limited to 'crates/ra_hir/src/nameres/collector.rs')
-rw-r--r--crates/ra_hir/src/nameres/collector.rs91
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
21pub(super) fn collect_defs(db: &impl DefDatabase, mut def_map: CrateDefMap) -> CrateDefMap { 21pub(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, &macro_id) in &item_map.exported_macros { 193 for (name, &macro_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();