aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJonas Schievink <[email protected]>2021-04-10 22:12:02 +0100
committerJonas Schievink <[email protected]>2021-04-11 00:25:50 +0100
commite2c1da36f59cd99d4da4c1d5f8f323626d3dbe61 (patch)
treee06290db93699c71d1e4c752de6563ff787bd5fa
parentbd675c8a8bdd3fda239bee3d3f31acd8679655b9 (diff)
Support macros in pattern position
-rw-r--r--crates/hir_def/src/body/lower.rs34
-rw-r--r--crates/hir_def/src/item_tree.rs5
-rw-r--r--crates/hir_def/src/item_tree/lower.rs2
-rw-r--r--crates/hir_expand/src/db.rs1
-rw-r--r--crates/hir_ty/src/tests/macros.rs2
-rw-r--r--crates/hir_ty/src/tests/patterns.rs28
-rw-r--r--crates/ide/src/goto_definition.rs26
7 files changed, 88 insertions, 10 deletions
diff --git a/crates/hir_def/src/body/lower.rs b/crates/hir_def/src/body/lower.rs
index bfb75a8a5..ed07d6928 100644
--- a/crates/hir_def/src/body/lower.rs
+++ b/crates/hir_def/src/body/lower.rs
@@ -531,8 +531,9 @@ impl ExprCollector<'_> {
531 } 531 }
532 } 532 }
533 ast::Expr::MacroCall(e) => { 533 ast::Expr::MacroCall(e) => {
534 let macro_ptr = AstPtr::new(&e);
534 let mut ids = vec![]; 535 let mut ids = vec![];
535 self.collect_macro_call(e, syntax_ptr.clone(), true, |this, expansion| { 536 self.collect_macro_call(e, macro_ptr, true, |this, expansion| {
536 ids.push(match expansion { 537 ids.push(match expansion {
537 Some(it) => this.collect_expr(it), 538 Some(it) => this.collect_expr(it),
538 None => this.alloc_expr(Expr::Missing, syntax_ptr.clone()), 539 None => this.alloc_expr(Expr::Missing, syntax_ptr.clone()),
@@ -555,7 +556,7 @@ impl ExprCollector<'_> {
555 fn collect_macro_call<F: FnMut(&mut Self, Option<T>), T: ast::AstNode>( 556 fn collect_macro_call<F: FnMut(&mut Self, Option<T>), T: ast::AstNode>(
556 &mut self, 557 &mut self,
557 e: ast::MacroCall, 558 e: ast::MacroCall,
558 syntax_ptr: AstPtr<ast::Expr>, 559 syntax_ptr: AstPtr<ast::MacroCall>,
559 is_error_recoverable: bool, 560 is_error_recoverable: bool,
560 mut collector: F, 561 mut collector: F,
561 ) { 562 ) {
@@ -643,10 +644,14 @@ impl ExprCollector<'_> {
643 644
644 // Note that macro could be expended to multiple statements 645 // Note that macro could be expended to multiple statements
645 if let Some(ast::Expr::MacroCall(m)) = stmt.expr() { 646 if let Some(ast::Expr::MacroCall(m)) = stmt.expr() {
647 let macro_ptr = AstPtr::new(&m);
646 let syntax_ptr = AstPtr::new(&stmt.expr().unwrap()); 648 let syntax_ptr = AstPtr::new(&stmt.expr().unwrap());
647 649
648 self.collect_macro_call(m, syntax_ptr.clone(), false, |this, expansion| { 650 self.collect_macro_call(
649 match expansion { 651 m,
652 macro_ptr,
653 false,
654 |this, expansion| match expansion {
650 Some(expansion) => { 655 Some(expansion) => {
651 let statements: ast::MacroStmts = expansion; 656 let statements: ast::MacroStmts = expansion;
652 657
@@ -660,8 +665,8 @@ impl ExprCollector<'_> {
660 let expr = this.alloc_expr(Expr::Missing, syntax_ptr.clone()); 665 let expr = this.alloc_expr(Expr::Missing, syntax_ptr.clone());
661 this.statements_in_scope.push(Statement::Expr(expr)); 666 this.statements_in_scope.push(Statement::Expr(expr));
662 } 667 }
663 } 668 },
664 }); 669 );
665 } else { 670 } else {
666 let expr = self.collect_expr_opt(stmt.expr()); 671 let expr = self.collect_expr_opt(stmt.expr());
667 self.statements_in_scope.push(Statement::Expr(expr)); 672 self.statements_in_scope.push(Statement::Expr(expr));
@@ -848,8 +853,23 @@ impl ExprCollector<'_> {
848 Pat::Missing 853 Pat::Missing
849 } 854 }
850 } 855 }
856 ast::Pat::MacroPat(mac) => match mac.macro_call() {
857 Some(call) => {
858 let macro_ptr = AstPtr::new(&call);
859 let mut pat = None;
860 self.collect_macro_call(call, macro_ptr, true, |this, expanded_pat| {
861 pat = Some(this.collect_pat_opt(expanded_pat));
862 });
863
864 match pat {
865 Some(pat) => return pat,
866 None => Pat::Missing,
867 }
868 }
869 None => Pat::Missing,
870 },
851 // FIXME: implement 871 // FIXME: implement
852 ast::Pat::RangePat(_) | ast::Pat::MacroPat(_) => Pat::Missing, 872 ast::Pat::RangePat(_) => Pat::Missing,
853 }; 873 };
854 let ptr = AstPtr::new(&pat); 874 let ptr = AstPtr::new(&pat);
855 self.alloc_pat(pattern, Either::Left(ptr)) 875 self.alloc_pat(pattern, Either::Left(ptr))
diff --git a/crates/hir_def/src/item_tree.rs b/crates/hir_def/src/item_tree.rs
index 240662486..94e08f835 100644
--- a/crates/hir_def/src/item_tree.rs
+++ b/crates/hir_def/src/item_tree.rs
@@ -99,6 +99,11 @@ impl ItemTree {
99 // items. 99 // items.
100 ctx.lower_macro_stmts(stmts) 100 ctx.lower_macro_stmts(stmts)
101 }, 101 },
102 ast::Pat(_pat) => {
103 // FIXME: This occurs because macros in pattern position are treated as inner
104 // items and expanded during block DefMap computation
105 return Default::default();
106 },
102 ast::Expr(e) => { 107 ast::Expr(e) => {
103 // Macros can expand to expressions. We return an empty item tree in this case, but 108 // Macros can expand to expressions. We return an empty item tree in this case, but
104 // still need to collect inner items. 109 // still need to collect inner items.
diff --git a/crates/hir_def/src/item_tree/lower.rs b/crates/hir_def/src/item_tree/lower.rs
index c5629af24..45b099cf3 100644
--- a/crates/hir_def/src/item_tree/lower.rs
+++ b/crates/hir_def/src/item_tree/lower.rs
@@ -189,7 +189,7 @@ impl Ctx {
189 block_stack.push(self.source_ast_id_map.ast_id(&block)); 189 block_stack.push(self.source_ast_id_map.ast_id(&block));
190 }, 190 },
191 ast::Item(item) => { 191 ast::Item(item) => {
192 // FIXME: This triggers for macro calls in expression position 192 // FIXME: This triggers for macro calls in expression/pattern/type position
193 let mod_items = self.lower_mod_item(&item, true); 193 let mod_items = self.lower_mod_item(&item, true);
194 let current_block = block_stack.last(); 194 let current_block = block_stack.last();
195 if let (Some(mod_items), Some(block)) = (mod_items, current_block) { 195 if let (Some(mod_items), Some(block)) = (mod_items, current_block) {
diff --git a/crates/hir_expand/src/db.rs b/crates/hir_expand/src/db.rs
index 10fe60821..ca705ee9d 100644
--- a/crates/hir_expand/src/db.rs
+++ b/crates/hir_expand/src/db.rs
@@ -439,6 +439,7 @@ fn to_fragment_kind(db: &dyn AstDatabase, id: MacroCallId) -> FragmentKind {
439 match parent.kind() { 439 match parent.kind() {
440 MACRO_ITEMS | SOURCE_FILE => FragmentKind::Items, 440 MACRO_ITEMS | SOURCE_FILE => FragmentKind::Items,
441 MACRO_STMTS => FragmentKind::Statements, 441 MACRO_STMTS => FragmentKind::Statements,
442 MACRO_PAT => FragmentKind::Pattern,
442 ITEM_LIST => FragmentKind::Items, 443 ITEM_LIST => FragmentKind::Items,
443 LET_STMT => { 444 LET_STMT => {
444 // FIXME: Handle LHS Pattern 445 // FIXME: Handle LHS Pattern
diff --git a/crates/hir_ty/src/tests/macros.rs b/crates/hir_ty/src/tests/macros.rs
index 86e3d8b86..b8e373ed8 100644
--- a/crates/hir_ty/src/tests/macros.rs
+++ b/crates/hir_ty/src/tests/macros.rs
@@ -1065,11 +1065,11 @@ fn macro_in_arm() {
1065 } 1065 }
1066 "#, 1066 "#,
1067 expect![[r#" 1067 expect![[r#"
1068 !0..2 '()': ()
1068 51..110 '{ ... }; }': () 1069 51..110 '{ ... }; }': ()
1069 61..62 'x': u32 1070 61..62 'x': u32
1070 65..107 'match ... }': u32 1071 65..107 'match ... }': u32
1071 71..73 '()': () 1072 71..73 '()': ()
1072 84..91 'unit!()': ()
1073 95..100 '92u32': u32 1073 95..100 '92u32': u32
1074 "#]], 1074 "#]],
1075 ); 1075 );
diff --git a/crates/hir_ty/src/tests/patterns.rs b/crates/hir_ty/src/tests/patterns.rs
index 85a28e76b..f514b3efe 100644
--- a/crates/hir_ty/src/tests/patterns.rs
+++ b/crates/hir_ty/src/tests/patterns.rs
@@ -1,6 +1,6 @@
1use expect_test::expect; 1use expect_test::expect;
2 2
3use super::{check_infer, check_infer_with_mismatches}; 3use super::{check_infer, check_infer_with_mismatches, check_types};
4 4
5#[test] 5#[test]
6fn infer_pattern() { 6fn infer_pattern() {
@@ -825,3 +825,29 @@ fn foo(foo: Foo) {
825 "#]], 825 "#]],
826 ); 826 );
827} 827}
828
829#[test]
830fn macro_pat() {
831 check_types(
832 r#"
833macro_rules! pat {
834 ($name:ident) => { Enum::Variant1($name) }
835}
836
837enum Enum {
838 Variant1(u8),
839 Variant2,
840}
841
842fn f(e: Enum) {
843 match e {
844 pat!(bind) => {
845 bind;
846 //^^^^ u8
847 }
848 Enum::Variant2 => {}
849 }
850}
851 "#,
852 )
853}
diff --git a/crates/ide/src/goto_definition.rs b/crates/ide/src/goto_definition.rs
index ca8ccb2da..d057d5402 100644
--- a/crates/ide/src/goto_definition.rs
+++ b/crates/ide/src/goto_definition.rs
@@ -1188,4 +1188,30 @@ pub fn gimme() -> theitem::TheItem {
1188"#, 1188"#,
1189 ); 1189 );
1190 } 1190 }
1191
1192 #[test]
1193 fn goto_ident_from_pat_macro() {
1194 check(
1195 r#"
1196macro_rules! pat {
1197 ($name:ident) => { Enum::Variant1($name) }
1198}
1199
1200enum Enum {
1201 Variant1(u8),
1202 Variant2,
1203}
1204
1205fn f(e: Enum) {
1206 match e {
1207 pat!(bind) => {
1208 //^^^^
1209 bind$0
1210 }
1211 Enum::Variant2 => {}
1212 }
1213}
1214"#,
1215 );
1216 }
1191} 1217}