aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAleksey Kladov <[email protected]>2020-04-03 14:38:42 +0100
committerAleksey Kladov <[email protected]>2020-04-03 15:12:38 +0100
commitda8eb29a2f70a58122903bf087bd6c1d0fbd6d3f (patch)
treeac21306c7bf9dc816f4b0e9b50322f57256eddfa
parent0e46ed8420469741d718ac223fad1088c151b497 (diff)
Macro patterns are not confused with expressions.
We treat macro calls as expressions (there's appropriate Into impl), which causes problem if there's expresison and non-expression macro in the same node (like in the match arm). We fix this problem by nesting macor patterns into another node (the same way we nest path into PathExpr or PathPat). Ideally, we probably should add a similar nesting for macro expressions, but that needs some careful thinking about macros in blocks: `{ am_i_expression!() }`.
-rw-r--r--crates/ra_hir_def/src/body/lower.rs3
-rw-r--r--crates/ra_hir_ty/src/tests/macros.rs31
-rw-r--r--crates/ra_parser/src/grammar/patterns.rs4
-rw-r--r--crates/ra_parser/src/syntax_kind/generated.rs1
-rw-r--r--crates/ra_syntax/src/ast/generated.rs42
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0129_marco_pat.txt21
-rw-r--r--xtask/src/ast_src.rs3
7 files changed, 88 insertions, 17 deletions
diff --git a/crates/ra_hir_def/src/body/lower.rs b/crates/ra_hir_def/src/body/lower.rs
index 28c570c76..8d4b8b0f0 100644
--- a/crates/ra_hir_def/src/body/lower.rs
+++ b/crates/ra_hir_def/src/body/lower.rs
@@ -672,8 +672,7 @@ impl ExprCollector<'_> {
672 } 672 }
673 673
674 // FIXME: implement 674 // FIXME: implement
675 ast::Pat::BoxPat(_) => Pat::Missing, 675 ast::Pat::BoxPat(_) | ast::Pat::RangePat(_) | ast::Pat::MacroPat(_) => Pat::Missing,
676 ast::Pat::RangePat(_) => Pat::Missing,
677 }; 676 };
678 let ptr = AstPtr::new(&pat); 677 let ptr = AstPtr::new(&pat);
679 self.alloc_pat(pattern, Either::Left(ptr)) 678 self.alloc_pat(pattern, Either::Left(ptr))
diff --git a/crates/ra_hir_ty/src/tests/macros.rs b/crates/ra_hir_ty/src/tests/macros.rs
index eb97288f1..ff4599b71 100644
--- a/crates/ra_hir_ty/src/tests/macros.rs
+++ b/crates/ra_hir_ty/src/tests/macros.rs
@@ -1,8 +1,10 @@
1use super::{infer, type_at, type_at_pos};
2use crate::test_db::TestDB;
3use insta::assert_snapshot; 1use insta::assert_snapshot;
4use ra_db::fixture::WithFixture; 2use ra_db::fixture::WithFixture;
5 3
4use super::{infer, type_at, type_at_pos};
5
6use crate::test_db::TestDB;
7
6#[test] 8#[test]
7fn cfg_impl_def() { 9fn cfg_impl_def() {
8 let (db, pos) = TestDB::with_position( 10 let (db, pos) = TestDB::with_position(
@@ -658,3 +660,28 @@ fn test() {
658 ); 660 );
659 assert_eq!("S", type_at_pos(&db, pos)); 661 assert_eq!("S", type_at_pos(&db, pos));
660} 662}
663
664#[test]
665fn macro_in_arm() {
666 assert_snapshot!(
667 infer(r#"
668macro_rules! unit {
669 () => { () };
670}
671
672fn main() {
673 let x = match () {
674 unit!() => 92u32,
675 };
676}
677"#),
678 @r###"
679 [52; 111) '{ ... }; }': ()
680 [62; 63) 'x': u32
681 [66; 108) 'match ... }': u32
682 [72; 74) '()': ()
683 [85; 92) 'unit!()': ()
684 [96; 101) '92u32': u32
685 "###
686 );
687}
diff --git a/crates/ra_parser/src/grammar/patterns.rs b/crates/ra_parser/src/grammar/patterns.rs
index 9bfdcfd41..936d27575 100644
--- a/crates/ra_parser/src/grammar/patterns.rs
+++ b/crates/ra_parser/src/grammar/patterns.rs
@@ -84,7 +84,7 @@ fn atom_pat(p: &mut Parser, recovery_set: TokenSet) -> Option<CompletedMarker> {
84 // Checks the token after an IDENT to see if a pattern is a path (Struct { .. }) or macro 84 // Checks the token after an IDENT to see if a pattern is a path (Struct { .. }) or macro
85 // (T![x]). 85 // (T![x]).
86 T!['('] | T!['{'] | T![!] => path_or_macro_pat(p), 86 T!['('] | T!['{'] | T![!] => path_or_macro_pat(p),
87 T![:] if p.nth_at(1, T![::]) => path_pat(p), 87 T![:] if p.nth_at(1, T![::]) => path_or_macro_pat(p),
88 _ => bind_pat(p, true), 88 _ => bind_pat(p, true),
89 }, 89 },
90 90
@@ -156,7 +156,7 @@ fn path_or_macro_pat(p: &mut Parser) -> CompletedMarker {
156 // } 156 // }
157 T![!] => { 157 T![!] => {
158 items::macro_call_after_excl(p); 158 items::macro_call_after_excl(p);
159 MACRO_CALL 159 return m.complete(p, MACRO_CALL).precede(p).complete(p, MACRO_PAT);
160 } 160 }
161 _ => PATH_PAT, 161 _ => PATH_PAT,
162 }; 162 };
diff --git a/crates/ra_parser/src/syntax_kind/generated.rs b/crates/ra_parser/src/syntax_kind/generated.rs
index dfc30d727..4c16cf1cd 100644
--- a/crates/ra_parser/src/syntax_kind/generated.rs
+++ b/crates/ra_parser/src/syntax_kind/generated.rs
@@ -167,6 +167,7 @@ pub enum SyntaxKind {
167 SLICE_PAT, 167 SLICE_PAT,
168 RANGE_PAT, 168 RANGE_PAT,
169 LITERAL_PAT, 169 LITERAL_PAT,
170 MACRO_PAT,
170 TUPLE_EXPR, 171 TUPLE_EXPR,
171 ARRAY_EXPR, 172 ARRAY_EXPR,
172 PAREN_EXPR, 173 PAREN_EXPR,
diff --git a/crates/ra_syntax/src/ast/generated.rs b/crates/ra_syntax/src/ast/generated.rs
index 7204ca5b1..0c339b987 100644
--- a/crates/ra_syntax/src/ast/generated.rs
+++ b/crates/ra_syntax/src/ast/generated.rs
@@ -2563,6 +2563,38 @@ impl LiteralPat {
2563 } 2563 }
2564} 2564}
2565#[derive(Debug, Clone, PartialEq, Eq, Hash)] 2565#[derive(Debug, Clone, PartialEq, Eq, Hash)]
2566pub struct MacroPat {
2567 pub(crate) syntax: SyntaxNode,
2568}
2569impl std::fmt::Display for MacroPat {
2570 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
2571 std::fmt::Display::fmt(self.syntax(), f)
2572 }
2573}
2574impl AstNode for MacroPat {
2575 fn can_cast(kind: SyntaxKind) -> bool {
2576 match kind {
2577 MACRO_PAT => true,
2578 _ => false,
2579 }
2580 }
2581 fn cast(syntax: SyntaxNode) -> Option<Self> {
2582 if Self::can_cast(syntax.kind()) {
2583 Some(Self { syntax })
2584 } else {
2585 None
2586 }
2587 }
2588 fn syntax(&self) -> &SyntaxNode {
2589 &self.syntax
2590 }
2591}
2592impl MacroPat {
2593 pub fn macro_call(&self) -> Option<MacroCall> {
2594 AstChildren::new(&self.syntax).next()
2595 }
2596}
2597#[derive(Debug, Clone, PartialEq, Eq, Hash)]
2566pub struct RecordPat { 2598pub struct RecordPat {
2567 pub(crate) syntax: SyntaxNode, 2599 pub(crate) syntax: SyntaxNode,
2568} 2600}
@@ -4600,6 +4632,7 @@ pub enum Pat {
4600 SlicePat(SlicePat), 4632 SlicePat(SlicePat),
4601 RangePat(RangePat), 4633 RangePat(RangePat),
4602 LiteralPat(LiteralPat), 4634 LiteralPat(LiteralPat),
4635 MacroPat(MacroPat),
4603} 4636}
4604impl From<OrPat> for Pat { 4637impl From<OrPat> for Pat {
4605 fn from(node: OrPat) -> Pat { 4638 fn from(node: OrPat) -> Pat {
@@ -4671,6 +4704,11 @@ impl From<LiteralPat> for Pat {
4671 Pat::LiteralPat(node) 4704 Pat::LiteralPat(node)
4672 } 4705 }
4673} 4706}
4707impl From<MacroPat> for Pat {
4708 fn from(node: MacroPat) -> Pat {
4709 Pat::MacroPat(node)
4710 }
4711}
4674impl std::fmt::Display for Pat { 4712impl std::fmt::Display for Pat {
4675 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { 4713 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
4676 std::fmt::Display::fmt(self.syntax(), f) 4714 std::fmt::Display::fmt(self.syntax(), f)
@@ -4681,7 +4719,7 @@ impl AstNode for Pat {
4681 match kind { 4719 match kind {
4682 OR_PAT | PAREN_PAT | REF_PAT | BOX_PAT | BIND_PAT | PLACEHOLDER_PAT | DOT_DOT_PAT 4720 OR_PAT | PAREN_PAT | REF_PAT | BOX_PAT | BIND_PAT | PLACEHOLDER_PAT | DOT_DOT_PAT
4683 | PATH_PAT | RECORD_PAT | TUPLE_STRUCT_PAT | TUPLE_PAT | SLICE_PAT | RANGE_PAT 4721 | PATH_PAT | RECORD_PAT | TUPLE_STRUCT_PAT | TUPLE_PAT | SLICE_PAT | RANGE_PAT
4684 | LITERAL_PAT => true, 4722 | LITERAL_PAT | MACRO_PAT => true,
4685 _ => false, 4723 _ => false,
4686 } 4724 }
4687 } 4725 }
@@ -4701,6 +4739,7 @@ impl AstNode for Pat {
4701 SLICE_PAT => Pat::SlicePat(SlicePat { syntax }), 4739 SLICE_PAT => Pat::SlicePat(SlicePat { syntax }),
4702 RANGE_PAT => Pat::RangePat(RangePat { syntax }), 4740 RANGE_PAT => Pat::RangePat(RangePat { syntax }),
4703 LITERAL_PAT => Pat::LiteralPat(LiteralPat { syntax }), 4741 LITERAL_PAT => Pat::LiteralPat(LiteralPat { syntax }),
4742 MACRO_PAT => Pat::MacroPat(MacroPat { syntax }),
4704 _ => return None, 4743 _ => return None,
4705 }; 4744 };
4706 Some(res) 4745 Some(res)
@@ -4721,6 +4760,7 @@ impl AstNode for Pat {
4721 Pat::SlicePat(it) => &it.syntax, 4760 Pat::SlicePat(it) => &it.syntax,
4722 Pat::RangePat(it) => &it.syntax, 4761 Pat::RangePat(it) => &it.syntax,
4723 Pat::LiteralPat(it) => &it.syntax, 4762 Pat::LiteralPat(it) => &it.syntax,
4763 Pat::MacroPat(it) => &it.syntax,
4724 } 4764 }
4725 } 4765 }
4726} 4766}
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0129_marco_pat.txt b/crates/ra_syntax/test_data/parser/inline/ok/0129_marco_pat.txt
index b05ccc0ed..36d8f4a5f 100644
--- a/crates/ra_syntax/test_data/parser/inline/ok/0129_marco_pat.txt
+++ b/crates/ra_syntax/test_data/parser/inline/ok/0129_marco_pat.txt
@@ -15,16 +15,17 @@ SOURCE_FILE@[0; 33)
15 LET_STMT@[16; 30) 15 LET_STMT@[16; 30)
16 LET_KW@[16; 19) "let" 16 LET_KW@[16; 19) "let"
17 WHITESPACE@[19; 20) " " 17 WHITESPACE@[19; 20) " "
18 MACRO_CALL@[20; 25) 18 MACRO_PAT@[20; 25)
19 PATH@[20; 21) 19 MACRO_CALL@[20; 25)
20 PATH_SEGMENT@[20; 21) 20 PATH@[20; 21)
21 NAME_REF@[20; 21) 21 PATH_SEGMENT@[20; 21)
22 IDENT@[20; 21) "m" 22 NAME_REF@[20; 21)
23 EXCL@[21; 22) "!" 23 IDENT@[20; 21) "m"
24 TOKEN_TREE@[22; 25) 24 EXCL@[21; 22) "!"
25 L_PAREN@[22; 23) "(" 25 TOKEN_TREE@[22; 25)
26 IDENT@[23; 24) "x" 26 L_PAREN@[22; 23) "("
27 R_PAREN@[24; 25) ")" 27 IDENT@[23; 24) "x"
28 R_PAREN@[24; 25) ")"
28 WHITESPACE@[25; 26) " " 29 WHITESPACE@[25; 26) " "
29 EQ@[26; 27) "=" 30 EQ@[26; 27) "="
30 WHITESPACE@[27; 28) " " 31 WHITESPACE@[27; 28) " "
diff --git a/xtask/src/ast_src.rs b/xtask/src/ast_src.rs
index 99bd60198..d9f51ec39 100644
--- a/xtask/src/ast_src.rs
+++ b/xtask/src/ast_src.rs
@@ -138,6 +138,7 @@ pub(crate) const KINDS_SRC: KindsSrc = KindsSrc {
138 "SLICE_PAT", 138 "SLICE_PAT",
139 "RANGE_PAT", 139 "RANGE_PAT",
140 "LITERAL_PAT", 140 "LITERAL_PAT",
141 "MACRO_PAT",
141 // atoms 142 // atoms
142 "TUPLE_EXPR", 143 "TUPLE_EXPR",
143 "ARRAY_EXPR", 144 "ARRAY_EXPR",
@@ -440,6 +441,7 @@ pub(crate) const AST_SRC: AstSrc = AstSrc {
440 struct SlicePat { args: [Pat] } 441 struct SlicePat { args: [Pat] }
441 struct RangePat {} 442 struct RangePat {}
442 struct LiteralPat { Literal } 443 struct LiteralPat { Literal }
444 struct MacroPat { MacroCall }
443 445
444 struct RecordPat { RecordFieldPatList, Path } 446 struct RecordPat { RecordFieldPatList, Path }
445 struct RecordFieldPatList { 447 struct RecordFieldPatList {
@@ -622,6 +624,7 @@ pub(crate) const AST_SRC: AstSrc = AstSrc {
622 SlicePat, 624 SlicePat,
623 RangePat, 625 RangePat,
624 LiteralPat, 626 LiteralPat,
627 MacroPat,
625 } 628 }
626 629
627 enum AttrInput { Literal, TokenTree } 630 enum AttrInput { Literal, TokenTree }