diff options
author | bors[bot] <26634292+bors[bot]@users.noreply.github.com> | 2020-03-15 12:15:09 +0000 |
---|---|---|
committer | GitHub <[email protected]> | 2020-03-15 12:15:09 +0000 |
commit | efa72c899d0c1e628d2e944cac91ac3266da2c59 (patch) | |
tree | 5ddbf69ebecbba36403358829ba63c22a3046dd1 /crates/ra_hir_def/src | |
parent | 5429e6831c7a59425b37dec475f153848254a87d (diff) | |
parent | fe78a14bbb9769c8ccd5cc41415702f5176a8e88 (diff) |
Merge #3591
3591: Support local macro_rules r=matklad a=edwin0cheng
This PR implement local `macro_rules` in function body, by adding following things:
1. While lowering, add a `MacroDefId` in body's `ItemScope` as a textual legacy macro.
2. Make `Expander::enter_expand` search with given `ItemScope`.
3. Make `Resolver::resolve_path_as_macro` search with `LocalItemScope`.
Fix #2181
Co-authored-by: Edwin Cheng <[email protected]>
Diffstat (limited to 'crates/ra_hir_def/src')
-rw-r--r-- | crates/ra_hir_def/src/body.rs | 12 | ||||
-rw-r--r-- | crates/ra_hir_def/src/body/lower.rs | 48 | ||||
-rw-r--r-- | crates/ra_hir_def/src/data.rs | 2 | ||||
-rw-r--r-- | crates/ra_hir_def/src/resolver.rs | 15 |
4 files changed, 61 insertions, 16 deletions
diff --git a/crates/ra_hir_def/src/body.rs b/crates/ra_hir_def/src/body.rs index 57ba45b45..2bc405a59 100644 --- a/crates/ra_hir_def/src/body.rs +++ b/crates/ra_hir_def/src/body.rs | |||
@@ -47,13 +47,19 @@ impl Expander { | |||
47 | pub(crate) fn enter_expand<T: ast::AstNode, DB: DefDatabase>( | 47 | pub(crate) fn enter_expand<T: ast::AstNode, DB: DefDatabase>( |
48 | &mut self, | 48 | &mut self, |
49 | db: &DB, | 49 | db: &DB, |
50 | local_scope: Option<&ItemScope>, | ||
50 | macro_call: ast::MacroCall, | 51 | macro_call: ast::MacroCall, |
51 | ) -> Option<(Mark, T)> { | 52 | ) -> Option<(Mark, T)> { |
52 | let macro_call = InFile::new(self.current_file_id, ¯o_call); | 53 | let macro_call = InFile::new(self.current_file_id, ¯o_call); |
53 | 54 | ||
54 | if let Some(call_id) = | 55 | if let Some(call_id) = macro_call.as_call_id(db, |path| { |
55 | macro_call.as_call_id(db, |path| self.resolve_path_as_macro(db, &path)) | 56 | if let Some(local_scope) = local_scope { |
56 | { | 57 | if let Some(def) = path.as_ident().and_then(|n| local_scope.get_legacy_macro(n)) { |
58 | return Some(def); | ||
59 | } | ||
60 | } | ||
61 | self.resolve_path_as_macro(db, &path) | ||
62 | }) { | ||
57 | let file_id = call_id.as_file(); | 63 | let file_id = call_id.as_file(); |
58 | if let Some(node) = db.parse_or_expand(file_id) { | 64 | if let Some(node) = db.parse_or_expand(file_id) { |
59 | if let Some(expr) = T::cast(node) { | 65 | if let Some(expr) = T::cast(node) { |
diff --git a/crates/ra_hir_def/src/body/lower.rs b/crates/ra_hir_def/src/body/lower.rs index ec1b0c2e7..54b5591d3 100644 --- a/crates/ra_hir_def/src/body/lower.rs +++ b/crates/ra_hir_def/src/body/lower.rs | |||
@@ -3,7 +3,10 @@ | |||
3 | 3 | ||
4 | use either::Either; | 4 | use either::Either; |
5 | 5 | ||
6 | use hir_expand::name::{name, AsName, Name}; | 6 | use hir_expand::{ |
7 | name::{name, AsName, Name}, | ||
8 | MacroDefId, MacroDefKind, | ||
9 | }; | ||
7 | use ra_arena::Arena; | 10 | use ra_arena::Arena; |
8 | use ra_syntax::{ | 11 | use ra_syntax::{ |
9 | ast::{ | 12 | ast::{ |
@@ -452,19 +455,30 @@ where | |||
452 | None => self.alloc_expr(Expr::Missing, syntax_ptr), | 455 | None => self.alloc_expr(Expr::Missing, syntax_ptr), |
453 | } | 456 | } |
454 | } | 457 | } |
455 | // FIXME expand to statements in statement position | ||
456 | ast::Expr::MacroCall(e) => { | 458 | ast::Expr::MacroCall(e) => { |
457 | let macro_call = self.expander.to_source(AstPtr::new(&e)); | 459 | if let Some(name) = is_macro_rules(&e) { |
458 | match self.expander.enter_expand(self.db, e) { | 460 | let mac = MacroDefId { |
459 | Some((mark, expansion)) => { | 461 | krate: Some(self.expander.module.krate), |
460 | self.source_map | 462 | ast_id: Some(self.expander.ast_id(&e)), |
461 | .expansions | 463 | kind: MacroDefKind::Declarative, |
462 | .insert(macro_call, self.expander.current_file_id); | 464 | }; |
463 | let id = self.collect_expr(expansion); | 465 | self.body.item_scope.define_legacy_macro(name, mac); |
464 | self.expander.exit(self.db, mark); | 466 | |
465 | id | 467 | // FIXME: do we still need to allocate this as missing ? |
468 | self.alloc_expr(Expr::Missing, syntax_ptr) | ||
469 | } else { | ||
470 | let macro_call = self.expander.to_source(AstPtr::new(&e)); | ||
471 | match self.expander.enter_expand(self.db, Some(&self.body.item_scope), e) { | ||
472 | Some((mark, expansion)) => { | ||
473 | self.source_map | ||
474 | .expansions | ||
475 | .insert(macro_call, self.expander.current_file_id); | ||
476 | let id = self.collect_expr(expansion); | ||
477 | self.expander.exit(self.db, mark); | ||
478 | id | ||
479 | } | ||
480 | None => self.alloc_expr(Expr::Missing, syntax_ptr), | ||
466 | } | 481 | } |
467 | None => self.alloc_expr(Expr::Missing, syntax_ptr), | ||
468 | } | 482 | } |
469 | } | 483 | } |
470 | 484 | ||
@@ -686,6 +700,16 @@ where | |||
686 | } | 700 | } |
687 | } | 701 | } |
688 | 702 | ||
703 | fn is_macro_rules(m: &ast::MacroCall) -> Option<Name> { | ||
704 | let name = m.path()?.segment()?.name_ref()?.as_name(); | ||
705 | |||
706 | if name == name![macro_rules] { | ||
707 | Some(m.name()?.as_name()) | ||
708 | } else { | ||
709 | None | ||
710 | } | ||
711 | } | ||
712 | |||
689 | impl From<ast::BinOp> for BinaryOp { | 713 | impl From<ast::BinOp> for BinaryOp { |
690 | fn from(ast_op: ast::BinOp) -> Self { | 714 | fn from(ast_op: ast::BinOp) -> Self { |
691 | match ast_op { | 715 | match ast_op { |
diff --git a/crates/ra_hir_def/src/data.rs b/crates/ra_hir_def/src/data.rs index 85df07e60..c0b16b7fa 100644 --- a/crates/ra_hir_def/src/data.rs +++ b/crates/ra_hir_def/src/data.rs | |||
@@ -290,7 +290,7 @@ fn collect_impl_items_in_macro( | |||
290 | return Vec::new(); | 290 | return Vec::new(); |
291 | } | 291 | } |
292 | 292 | ||
293 | if let Some((mark, items)) = expander.enter_expand(db, m) { | 293 | if let Some((mark, items)) = expander.enter_expand(db, None, m) { |
294 | let items: InFile<ast::MacroItems> = expander.to_source(items); | 294 | let items: InFile<ast::MacroItems> = expander.to_source(items); |
295 | let mut res = collect_impl_items( | 295 | let mut res = collect_impl_items( |
296 | db, | 296 | db, |
diff --git a/crates/ra_hir_def/src/resolver.rs b/crates/ra_hir_def/src/resolver.rs index 2734d51a0..123fae72a 100644 --- a/crates/ra_hir_def/src/resolver.rs +++ b/crates/ra_hir_def/src/resolver.rs | |||
@@ -381,6 +381,11 @@ impl Resolver { | |||
381 | db: &impl DefDatabase, | 381 | db: &impl DefDatabase, |
382 | path: &ModPath, | 382 | path: &ModPath, |
383 | ) -> Option<MacroDefId> { | 383 | ) -> Option<MacroDefId> { |
384 | // Search item scope legacy macro first | ||
385 | if let Some(def) = self.resolve_local_macro_def(path) { | ||
386 | return Some(def); | ||
387 | } | ||
388 | |||
384 | let (item_map, module) = self.module_scope()?; | 389 | let (item_map, module) = self.module_scope()?; |
385 | item_map.resolve_path(db, module, &path, BuiltinShadowMode::Other).0.take_macros() | 390 | item_map.resolve_path(db, module, &path, BuiltinShadowMode::Other).0.take_macros() |
386 | } | 391 | } |
@@ -413,6 +418,16 @@ impl Resolver { | |||
413 | }) | 418 | }) |
414 | } | 419 | } |
415 | 420 | ||
421 | fn resolve_local_macro_def(&self, path: &ModPath) -> Option<MacroDefId> { | ||
422 | let name = path.as_ident()?; | ||
423 | self.scopes.iter().rev().find_map(|scope| { | ||
424 | if let Scope::LocalItemsScope(body) = scope { | ||
425 | return body.item_scope.get_legacy_macro(name); | ||
426 | } | ||
427 | None | ||
428 | }) | ||
429 | } | ||
430 | |||
416 | pub fn module(&self) -> Option<ModuleId> { | 431 | pub fn module(&self) -> Option<ModuleId> { |
417 | let (def_map, local_id) = self.module_scope()?; | 432 | let (def_map, local_id) = self.module_scope()?; |
418 | Some(ModuleId { krate: def_map.krate, local_id }) | 433 | Some(ModuleId { krate: def_map.krate, local_id }) |