diff options
author | Aleksey Kladov <[email protected]> | 2019-03-26 10:09:39 +0000 |
---|---|---|
committer | Aleksey Kladov <[email protected]> | 2019-03-26 10:20:54 +0000 |
commit | 5270bca5f72fa65f0515be776e06d3d6a4d1efca (patch) | |
tree | fa1b8b8ac66713ba29b676e1c2fdd4c4357f24ff /crates/ra_hir/src/nameres/collector.rs | |
parent | dc94f3612583c5e960b334761ad0c18d328840ea (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/collector.rs')
-rw-r--r-- | crates/ra_hir/src/nameres/collector.rs | 93 |
1 files changed, 31 insertions, 62 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 | ||
7 | use crate::{ | 7 | use 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 | ||
20 | pub(super) fn collect_defs(db: &impl DefDatabase, mut def_map: CrateDefMap) -> CrateDefMap { | 20 | pub(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 | ||
58 | impl<'a, DB> DefCollector<&'a DB> | 58 | impl<'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(¯o_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(¯o_id) = | 473 | if let Some(¯o_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 | } |