aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir/src/nameres
diff options
context:
space:
mode:
authorAleksey Kladov <[email protected]>2019-03-26 10:09:39 +0000
committerAleksey Kladov <[email protected]>2019-03-26 10:20:54 +0000
commit5270bca5f72fa65f0515be776e06d3d6a4d1efca (patch)
treefa1b8b8ac66713ba29b676e1c2fdd4c4357f24ff /crates/ra_hir/src/nameres
parentdc94f3612583c5e960b334761ad0c18d328840ea (diff)
store macro def inside macro id
This solves the problem of "macro expansion can't call into name resolution, because name resolution calls back into macro expansion" Because we store macro def as a part of call id, macro expansion just knows the def!
Diffstat (limited to 'crates/ra_hir/src/nameres')
-rw-r--r--crates/ra_hir/src/nameres/collector.rs93
-rw-r--r--crates/ra_hir/src/nameres/raw.rs30
-rw-r--r--crates/ra_hir/src/nameres/tests/incremental.rs23
3 files changed, 45 insertions, 101 deletions
diff --git a/crates/ra_hir/src/nameres/collector.rs b/crates/ra_hir/src/nameres/collector.rs
index 8830b4624..89300d2ec 100644
--- a/crates/ra_hir/src/nameres/collector.rs
+++ b/crates/ra_hir/src/nameres/collector.rs
@@ -6,15 +6,15 @@ use ra_db::FileId;
6 6
7use crate::{ 7use crate::{
8 Function, Module, Struct, Enum, Const, Static, Trait, TypeAlias, 8 Function, Module, Struct, Enum, Const, Static, Trait, TypeAlias,
9 DefDatabase, HirFileId, Name, Path, Crate, 9 DefDatabase, HirFileId, Name, Path,
10 KnownName, 10 KnownName,
11 nameres::{ 11 nameres::{
12 Resolution, PerNs, ModuleDef, ReachedFixedPoint, ResolveMode, 12 Resolution, PerNs, ModuleDef, ReachedFixedPoint, ResolveMode,
13 CrateDefMap, CrateModuleId, ModuleData, CrateMacroId, 13 CrateDefMap, CrateModuleId, ModuleData,
14 diagnostics::DefDiagnostic, 14 diagnostics::DefDiagnostic,
15 raw, 15 raw,
16 }, 16 },
17 ids::{AstItemDef, LocationCtx, MacroCallLoc, SourceItemId, MacroCallId}, 17 ids::{AstItemDef, LocationCtx, MacroCallLoc, SourceItemId, MacroCallId, MacroDefId},
18}; 18};
19 19
20pub(super) fn collect_defs(db: &impl DefDatabase, mut def_map: CrateDefMap) -> CrateDefMap { 20pub(super) fn collect_defs(db: &impl DefDatabase, mut def_map: CrateDefMap) -> CrateDefMap {
@@ -51,8 +51,8 @@ struct DefCollector<DB> {
51 def_map: CrateDefMap, 51 def_map: CrateDefMap,
52 glob_imports: FxHashMap<CrateModuleId, Vec<(CrateModuleId, raw::ImportId)>>, 52 glob_imports: FxHashMap<CrateModuleId, Vec<(CrateModuleId, raw::ImportId)>>,
53 unresolved_imports: Vec<(CrateModuleId, raw::ImportId, raw::ImportData)>, 53 unresolved_imports: Vec<(CrateModuleId, raw::ImportId, raw::ImportData)>,
54 unexpanded_macros: Vec<(CrateModuleId, MacroCallId, Path, tt::Subtree)>, 54 unexpanded_macros: Vec<(CrateModuleId, SourceItemId, Path)>,
55 global_macro_scope: FxHashMap<Name, CrateMacroId>, 55 global_macro_scope: FxHashMap<Name, MacroDefId>,
56} 56}
57 57
58impl<'a, DB> DefCollector<&'a DB> 58impl<'a, DB> DefCollector<&'a DB>
@@ -62,7 +62,7 @@ where
62 fn collect(&mut self) { 62 fn collect(&mut self) {
63 let crate_graph = self.db.crate_graph(); 63 let crate_graph = self.db.crate_graph();
64 let file_id = crate_graph.crate_root(self.def_map.krate.crate_id()); 64 let file_id = crate_graph.crate_root(self.def_map.krate.crate_id());
65 let raw_items = self.db.raw_items(file_id); 65 let raw_items = self.db.raw_items(file_id.into());
66 let module_id = self.def_map.root; 66 let module_id = self.def_map.root;
67 self.def_map.modules[module_id].definition = Some(file_id); 67 self.def_map.modules[module_id].definition = Some(file_id);
68 ModCollector { 68 ModCollector {
@@ -93,14 +93,11 @@ where
93 } 93 }
94 } 94 }
95 95
96 fn define_macro(&mut self, name: Name, tt: &tt::Subtree, export: bool) { 96 fn define_macro(&mut self, name: Name, macro_id: MacroDefId, export: bool) {
97 if let Ok(rules) = mbe::MacroRules::parse(tt) { 97 if export {
98 let macro_id = self.def_map.macros.alloc(rules); 98 self.def_map.public_macros.insert(name.clone(), macro_id);
99 if export {
100 self.def_map.public_macros.insert(name.clone(), macro_id);
101 }
102 self.global_macro_scope.insert(name, macro_id);
103 } 99 }
100 self.global_macro_scope.insert(name, macro_id);
104 } 101 }
105 102
106 fn resolve_imports(&mut self) -> ReachedFixedPoint { 103 fn resolve_imports(&mut self) -> ReachedFixedPoint {
@@ -296,7 +293,7 @@ where
296 let mut macros = std::mem::replace(&mut self.unexpanded_macros, Vec::new()); 293 let mut macros = std::mem::replace(&mut self.unexpanded_macros, Vec::new());
297 let mut resolved = Vec::new(); 294 let mut resolved = Vec::new();
298 let mut res = ReachedFixedPoint::Yes; 295 let mut res = ReachedFixedPoint::Yes;
299 macros.retain(|(module_id, call_id, path, tt)| { 296 macros.retain(|(module_id, source_item_id, path)| {
300 if path.segments.len() != 2 { 297 if path.segments.len() != 2 {
301 return true; 298 return true;
302 } 299 }
@@ -312,47 +309,24 @@ where
312 res = ReachedFixedPoint::No; 309 res = ReachedFixedPoint::No;
313 let def_map = self.db.crate_def_map(krate); 310 let def_map = self.db.crate_def_map(krate);
314 if let Some(macro_id) = def_map.public_macros.get(&path.segments[1].name).cloned() { 311 if let Some(macro_id) = def_map.public_macros.get(&path.segments[1].name).cloned() {
315 resolved.push((*module_id, *call_id, (krate, macro_id), tt.clone())); 312 let call_id =
313 MacroCallLoc { def: macro_id, source_item_id: *source_item_id }.id(self.db);
314 resolved.push((*module_id, call_id));
316 } 315 }
317 false 316 false
318 }); 317 });
319 318
320 for (module_id, macro_call_id, macro_def_id, arg) in resolved { 319 for (module_id, macro_call_id) in resolved {
321 self.collect_macro_expansion(module_id, macro_call_id, macro_def_id, arg); 320 self.collect_macro_expansion(module_id, macro_call_id);
322 } 321 }
323 res 322 res
324 } 323 }
325 324
326 fn collect_macro_expansion( 325 fn collect_macro_expansion(&mut self, module_id: CrateModuleId, macro_call_id: MacroCallId) {
327 &mut self, 326 let file_id: HirFileId = macro_call_id.into();
328 module_id: CrateModuleId, 327 let raw_items = self.db.raw_items(file_id);
329 macro_call_id: MacroCallId, 328 ModCollector { def_collector: &mut *self, file_id, module_id, raw_items: &raw_items }
330 macro_def_id: (Crate, CrateMacroId), 329 .collect(raw_items.items())
331 macro_arg: tt::Subtree,
332 ) {
333 let (macro_krate, macro_id) = macro_def_id;
334 let dm;
335 let rules = if macro_krate == self.def_map.krate {
336 &self.def_map[macro_id]
337 } else {
338 dm = self.db.crate_def_map(macro_krate);
339 &dm[macro_id]
340 };
341 if let Ok(expansion) = rules.expand(&macro_arg) {
342 self.def_map.macro_resolutions.insert(macro_call_id, macro_def_id);
343 // XXX: this **does not** go through a database, because we can't
344 // identify macro_call without adding the whole state of name resolution
345 // as a parameter to the query.
346 //
347 // So, we run the queries "manually" and we must ensure that
348 // `db.hir_parse(macro_call_id)` returns the same source_file.
349 let file_id: HirFileId = macro_call_id.into();
350 let source_file = mbe::token_tree_to_ast_item_list(&expansion);
351
352 let raw_items = raw::RawItems::from_source_file(&source_file, file_id);
353 ModCollector { def_collector: &mut *self, file_id, module_id, raw_items: &raw_items }
354 .collect(raw_items.items())
355 }
356 } 330 }
357 331
358 fn finish(self) -> CrateDefMap { 332 fn finish(self) -> CrateDefMap {
@@ -412,7 +386,7 @@ where
412 Ok(file_id) => { 386 Ok(file_id) => {
413 let module_id = 387 let module_id =
414 self.push_child_module(name.clone(), source_item_id, Some(file_id)); 388 self.push_child_module(name.clone(), source_item_id, Some(file_id));
415 let raw_items = self.def_collector.db.raw_items(file_id); 389 let raw_items = self.def_collector.db.raw_items(file_id.into());
416 ModCollector { 390 ModCollector {
417 def_collector: &mut *self.def_collector, 391 def_collector: &mut *self.def_collector,
418 module_id, 392 module_id,
@@ -484,38 +458,33 @@ where
484 // Case 1: macro rules, define a macro in crate-global mutable scope 458 // Case 1: macro rules, define a macro in crate-global mutable scope
485 if is_macro_rules(&mac.path) { 459 if is_macro_rules(&mac.path) {
486 if let Some(name) = &mac.name { 460 if let Some(name) = &mac.name {
487 self.def_collector.define_macro(name.clone(), &mac.arg, mac.export) 461 let macro_id = MacroDefId::MacroByExample {
462 source_item_id: mac.source_item_id.with_file_id(self.file_id),
463 };
464 self.def_collector.define_macro(name.clone(), macro_id, mac.export)
488 } 465 }
489 return; 466 return;
490 } 467 }
491 468
492 let source_item_id = SourceItemId { file_id: self.file_id, item_id: mac.source_item_id }; 469 let source_item_id = SourceItemId { file_id: self.file_id, item_id: mac.source_item_id };
493 let macro_call_id = MacroCallLoc {
494 module: Module { krate: self.def_collector.def_map.krate, module_id: self.module_id },
495 source_item_id,
496 }
497 .id(self.def_collector.db);
498 470
499 // Case 2: try to expand macro_rules from this crate, triggering 471 // Case 2: try to expand macro_rules from this crate, triggering
500 // recursive item collection. 472 // recursive item collection.
501 if let Some(&macro_id) = 473 if let Some(&macro_id) =
502 mac.path.as_ident().and_then(|name| self.def_collector.global_macro_scope.get(name)) 474 mac.path.as_ident().and_then(|name| self.def_collector.global_macro_scope.get(name))
503 { 475 {
504 self.def_collector.collect_macro_expansion( 476 let macro_call_id =
505 self.module_id, 477 MacroCallLoc { def: macro_id, source_item_id }.id(self.def_collector.db);
506 macro_call_id, 478
507 (self.def_collector.def_map.krate, macro_id), 479 self.def_collector.collect_macro_expansion(self.module_id, macro_call_id);
508 mac.arg.clone(),
509 );
510 return; 480 return;
511 } 481 }
512 482
513 // Case 3: path to a macro from another crate, expand during name resolution 483 // Case 3: path to a macro from another crate, expand during name resolution
514 self.def_collector.unexpanded_macros.push(( 484 self.def_collector.unexpanded_macros.push((
515 self.module_id, 485 self.module_id,
516 macro_call_id, 486 source_item_id,
517 mac.path.clone(), 487 mac.path.clone(),
518 mac.arg.clone(),
519 )) 488 ))
520 } 489 }
521} 490}
diff --git a/crates/ra_hir/src/nameres/raw.rs b/crates/ra_hir/src/nameres/raw.rs
index f8ba398ec..7a516e556 100644
--- a/crates/ra_hir/src/nameres/raw.rs
+++ b/crates/ra_hir/src/nameres/raw.rs
@@ -4,7 +4,6 @@ use std::{
4}; 4};
5 5
6use test_utils::tested_by; 6use test_utils::tested_by;
7use ra_db::FileId;
8use ra_arena::{Arena, impl_arena_id, RawId, map::ArenaMap}; 7use ra_arena::{Arena, impl_arena_id, RawId, map::ArenaMap};
9use ra_syntax::{ 8use ra_syntax::{
10 AstNode, SourceFile, AstPtr, TreeArc, 9 AstNode, SourceFile, AstPtr, TreeArc,
@@ -47,20 +46,20 @@ impl ImportSourceMap {
47} 46}
48 47
49impl RawItems { 48impl RawItems {
50 pub(crate) fn raw_items_query(db: &impl DefDatabase, file_id: FileId) -> Arc<RawItems> { 49 pub(crate) fn raw_items_query(db: &impl DefDatabase, file_id: HirFileId) -> Arc<RawItems> {
51 db.raw_items_with_source_map(file_id).0 50 db.raw_items_with_source_map(file_id).0
52 } 51 }
53 52
54 pub(crate) fn raw_items_with_source_map_query( 53 pub(crate) fn raw_items_with_source_map_query(
55 db: &impl DefDatabase, 54 db: &impl DefDatabase,
56 file_id: FileId, 55 file_id: HirFileId,
57 ) -> (Arc<RawItems>, Arc<ImportSourceMap>) { 56 ) -> (Arc<RawItems>, Arc<ImportSourceMap>) {
58 let mut collector = RawItemsCollector { 57 let mut collector = RawItemsCollector {
59 raw_items: RawItems::default(), 58 raw_items: RawItems::default(),
60 source_file_items: db.file_items(file_id.into()), 59 source_file_items: db.file_items(file_id.into()),
61 source_map: ImportSourceMap::default(), 60 source_map: ImportSourceMap::default(),
62 }; 61 };
63 let source_file = db.parse(file_id); 62 let source_file = db.hir_parse(file_id);
64 collector.process_module(None, &*source_file); 63 collector.process_module(None, &*source_file);
65 (Arc::new(collector.raw_items), Arc::new(collector.source_map)) 64 (Arc::new(collector.raw_items), Arc::new(collector.source_map))
66 } 65 }
@@ -68,19 +67,6 @@ impl RawItems {
68 pub(crate) fn items(&self) -> &[RawItem] { 67 pub(crate) fn items(&self) -> &[RawItem] {
69 &self.items 68 &self.items
70 } 69 }
71
72 // We can't use queries during name resolution for fear of cycles, so this
73 // is a query-less variant of the above function.
74 pub(crate) fn from_source_file(source_file: &SourceFile, file_id: HirFileId) -> RawItems {
75 let source_file_items = SourceFileItems::from_source_file(source_file, file_id);
76 let mut collector = RawItemsCollector {
77 raw_items: RawItems::default(),
78 source_file_items: Arc::new(source_file_items),
79 source_map: ImportSourceMap::default(),
80 };
81 collector.process_module(None, &*source_file);
82 collector.raw_items
83 }
84} 70}
85 71
86impl Index<Module> for RawItems { 72impl Index<Module> for RawItems {
@@ -173,7 +159,6 @@ pub(crate) struct MacroData {
173 pub(crate) source_item_id: SourceFileItemId, 159 pub(crate) source_item_id: SourceFileItemId,
174 pub(crate) path: Path, 160 pub(crate) path: Path,
175 pub(crate) name: Option<Name>, 161 pub(crate) name: Option<Name>,
176 pub(crate) arg: tt::Subtree,
177 pub(crate) export: bool, 162 pub(crate) export: bool,
178} 163}
179 164
@@ -291,18 +276,15 @@ impl RawItemsCollector {
291 } 276 }
292 277
293 fn add_macro(&mut self, current_module: Option<Module>, m: &ast::MacroCall) { 278 fn add_macro(&mut self, current_module: Option<Module>, m: &ast::MacroCall) {
294 let (path, arg) = match ( 279 let path = match m.path().and_then(Path::from_ast) {
295 m.path().and_then(Path::from_ast), 280 Some(it) => it,
296 m.token_tree().and_then(mbe::ast_to_token_tree),
297 ) {
298 (Some(path), Some((token_tree, _token_map))) => (path, token_tree),
299 _ => return, 281 _ => return,
300 }; 282 };
301 283
302 let name = m.name().map(|it| it.as_name()); 284 let name = m.name().map(|it| it.as_name());
303 let source_item_id = self.source_file_items.id_of_unchecked(m.syntax()); 285 let source_item_id = self.source_file_items.id_of_unchecked(m.syntax());
304 let export = m.has_atom_attr("macro_export"); 286 let export = m.has_atom_attr("macro_export");
305 let m = self.raw_items.macros.alloc(MacroData { source_item_id, path, arg, name, export }); 287 let m = self.raw_items.macros.alloc(MacroData { source_item_id, path, name, export });
306 self.push_item(current_module, RawItem::Macro(m)); 288 self.push_item(current_module, RawItem::Macro(m));
307 } 289 }
308 290
diff --git a/crates/ra_hir/src/nameres/tests/incremental.rs b/crates/ra_hir/src/nameres/tests/incremental.rs
index 698781923..a059634e2 100644
--- a/crates/ra_hir/src/nameres/tests/incremental.rs
+++ b/crates/ra_hir/src/nameres/tests/incremental.rs
@@ -90,34 +90,27 @@ fn adding_inner_items_should_not_invalidate_def_map() {
90 ); 90 );
91} 91}
92 92
93// It would be awesome to make this work, but it's unclear how
94#[test] 93#[test]
95#[ignore] 94fn typing_inside_a_macro_should_not_invalidate_def_map() {
96fn typing_inside_a_function_inside_a_macro_should_not_invalidate_def_map() {
97 check_def_map_is_not_recomputed( 95 check_def_map_is_not_recomputed(
98 " 96 "
99 //- /lib.rs 97 //- /lib.rs
98 macro_rules! m {
99 ($ident:ident) => {
100 struct Foo;
101 }
102 }
100 mod foo; 103 mod foo;
101 104
102 use crate::foo::bar::Baz;
103
104 //- /foo/mod.rs 105 //- /foo/mod.rs
105 pub mod bar; 106 pub mod bar;
106 107
107 //- /foo/bar.rs 108 //- /foo/bar.rs
108 <|> 109 <|>
109 salsa::query_group! { 110 m!(X);
110 trait Baz {
111 fn foo() -> i32 { 1 + 1 }
112 }
113 }
114 ", 111 ",
115 " 112 "
116 salsa::query_group! { 113 m!(Y);
117 trait Baz {
118 fn foo() -> i32 { 92 }
119 }
120 }
121 ", 114 ",
122 ); 115 );
123} 116}