diff options
author | Jonas Schievink <[email protected]> | 2021-04-10 22:12:02 +0100 |
---|---|---|
committer | Jonas Schievink <[email protected]> | 2021-04-11 00:25:50 +0100 |
commit | e2c1da36f59cd99d4da4c1d5f8f323626d3dbe61 (patch) | |
tree | e06290db93699c71d1e4c752de6563ff787bd5fa /crates | |
parent | bd675c8a8bdd3fda239bee3d3f31acd8679655b9 (diff) |
Support macros in pattern position
Diffstat (limited to 'crates')
-rw-r--r-- | crates/hir_def/src/body/lower.rs | 34 | ||||
-rw-r--r-- | crates/hir_def/src/item_tree.rs | 5 | ||||
-rw-r--r-- | crates/hir_def/src/item_tree/lower.rs | 2 | ||||
-rw-r--r-- | crates/hir_expand/src/db.rs | 1 | ||||
-rw-r--r-- | crates/hir_ty/src/tests/macros.rs | 2 | ||||
-rw-r--r-- | crates/hir_ty/src/tests/patterns.rs | 28 | ||||
-rw-r--r-- | crates/ide/src/goto_definition.rs | 26 |
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 @@ | |||
1 | use expect_test::expect; | 1 | use expect_test::expect; |
2 | 2 | ||
3 | use super::{check_infer, check_infer_with_mismatches}; | 3 | use super::{check_infer, check_infer_with_mismatches, check_types}; |
4 | 4 | ||
5 | #[test] | 5 | #[test] |
6 | fn infer_pattern() { | 6 | fn infer_pattern() { |
@@ -825,3 +825,29 @@ fn foo(foo: Foo) { | |||
825 | "#]], | 825 | "#]], |
826 | ); | 826 | ); |
827 | } | 827 | } |
828 | |||
829 | #[test] | ||
830 | fn macro_pat() { | ||
831 | check_types( | ||
832 | r#" | ||
833 | macro_rules! pat { | ||
834 | ($name:ident) => { Enum::Variant1($name) } | ||
835 | } | ||
836 | |||
837 | enum Enum { | ||
838 | Variant1(u8), | ||
839 | Variant2, | ||
840 | } | ||
841 | |||
842 | fn 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#" | ||
1196 | macro_rules! pat { | ||
1197 | ($name:ident) => { Enum::Variant1($name) } | ||
1198 | } | ||
1199 | |||
1200 | enum Enum { | ||
1201 | Variant1(u8), | ||
1202 | Variant2, | ||
1203 | } | ||
1204 | |||
1205 | fn f(e: Enum) { | ||
1206 | match e { | ||
1207 | pat!(bind) => { | ||
1208 | //^^^^ | ||
1209 | bind$0 | ||
1210 | } | ||
1211 | Enum::Variant2 => {} | ||
1212 | } | ||
1213 | } | ||
1214 | "#, | ||
1215 | ); | ||
1216 | } | ||
1191 | } | 1217 | } |