aboutsummaryrefslogtreecommitdiff
path: root/crates
diff options
context:
space:
mode:
authorbors[bot] <26634292+bors[bot]@users.noreply.github.com>2020-03-15 12:15:09 +0000
committerGitHub <[email protected]>2020-03-15 12:15:09 +0000
commitefa72c899d0c1e628d2e944cac91ac3266da2c59 (patch)
tree5ddbf69ebecbba36403358829ba63c22a3046dd1 /crates
parent5429e6831c7a59425b37dec475f153848254a87d (diff)
parentfe78a14bbb9769c8ccd5cc41415702f5176a8e88 (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')
-rw-r--r--crates/ra_hir_def/src/body.rs12
-rw-r--r--crates/ra_hir_def/src/body/lower.rs48
-rw-r--r--crates/ra_hir_def/src/data.rs2
-rw-r--r--crates/ra_hir_def/src/resolver.rs15
-rw-r--r--crates/ra_hir_ty/src/tests/macros.rs20
-rw-r--r--crates/ra_ide/src/goto_definition.rs15
6 files changed, 96 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, &macro_call); 53 let macro_call = InFile::new(self.current_file_id, &macro_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
4use either::Either; 4use either::Either;
5 5
6use hir_expand::name::{name, AsName, Name}; 6use hir_expand::{
7 name::{name, AsName, Name},
8 MacroDefId, MacroDefKind,
9};
7use ra_arena::Arena; 10use ra_arena::Arena;
8use ra_syntax::{ 11use 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
703fn 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
689impl From<ast::BinOp> for BinaryOp { 713impl 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 })
diff --git a/crates/ra_hir_ty/src/tests/macros.rs b/crates/ra_hir_ty/src/tests/macros.rs
index 32457bbf7..3b7022ad5 100644
--- a/crates/ra_hir_ty/src/tests/macros.rs
+++ b/crates/ra_hir_ty/src/tests/macros.rs
@@ -363,6 +363,26 @@ fn main() {
363} 363}
364 364
365#[test] 365#[test]
366fn infer_local_macro() {
367 assert_snapshot!(
368 infer(r#"
369fn main() {
370 macro_rules! foo {
371 () => { 1usize }
372 }
373 let _a = foo!();
374}
375"#),
376 @r###"
377 ![0; 6) '1usize': usize
378 [11; 90) '{ ...!(); }': ()
379 [17; 66) 'macro_... }': {unknown}
380 [75; 77) '_a': usize
381 "###
382 );
383}
384
385#[test]
366fn infer_builtin_macros_line() { 386fn infer_builtin_macros_line() {
367 assert_snapshot!( 387 assert_snapshot!(
368 infer(r#" 388 infer(r#"
diff --git a/crates/ra_ide/src/goto_definition.rs b/crates/ra_ide/src/goto_definition.rs
index a55a13ffc..a7be92ce3 100644
--- a/crates/ra_ide/src/goto_definition.rs
+++ b/crates/ra_ide/src/goto_definition.rs
@@ -788,6 +788,21 @@ mod tests {
788 } 788 }
789 789
790 #[test] 790 #[test]
791 fn goto_def_in_local_macro() {
792 check_goto(
793 "
794 //- /lib.rs
795 fn bar() {
796 macro_rules! foo { () => { () } }
797 <|>foo!();
798 }
799 ",
800 "foo MACRO_CALL FileId(1) [15; 48) [28; 31)",
801 "macro_rules! foo { () => { () } }|foo",
802 );
803 }
804
805 #[test]
791 fn goto_def_for_field_init_shorthand() { 806 fn goto_def_for_field_init_shorthand() {
792 covers!(ra_ide_db::goto_def_for_field_init_shorthand); 807 covers!(ra_ide_db::goto_def_for_field_init_shorthand);
793 check_goto( 808 check_goto(