diff --git a/crates/ra_hir_def/src/body/lower.rs b/crates/ra_hir_def/src/body/lower.rs index 28c570c769b..8d4b8b0f0fb 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<'_> { } // FIXME: implement - ast::Pat::BoxPat(_) => Pat::Missing, - ast::Pat::RangePat(_) => Pat::Missing, + ast::Pat::BoxPat(_) | ast::Pat::RangePat(_) | ast::Pat::MacroPat(_) => Pat::Missing, }; let ptr = AstPtr::new(&pat); 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 eb97288f189..ff4599b7128 100644 --- a/crates/ra_hir_ty/src/tests/macros.rs +++ b/crates/ra_hir_ty/src/tests/macros.rs @@ -1,8 +1,10 @@ -use super::{infer, type_at, type_at_pos}; -use crate::test_db::TestDB; use insta::assert_snapshot; use ra_db::fixture::WithFixture; +use super::{infer, type_at, type_at_pos}; + +use crate::test_db::TestDB; + #[test] fn cfg_impl_def() { let (db, pos) = TestDB::with_position( @@ -658,3 +660,28 @@ fn test() { ); assert_eq!("S", type_at_pos(&db, pos)); } + +#[test] +fn macro_in_arm() { + assert_snapshot!( + infer(r#" +macro_rules! unit { + () => { () }; +} + +fn main() { + let x = match () { + unit!() => 92u32, + }; +} +"#), + @r###" + [52; 111) '{ ... }; }': () + [62; 63) 'x': u32 + [66; 108) 'match ... }': u32 + [72; 74) '()': () + [85; 92) 'unit!()': () + [96; 101) '92u32': u32 + "### + ); +} diff --git a/crates/ra_parser/src/grammar/expressions.rs b/crates/ra_parser/src/grammar/expressions.rs index 0c170ac5ec2..c486c02113e 100644 --- a/crates/ra_parser/src/grammar/expressions.rs +++ b/crates/ra_parser/src/grammar/expressions.rs @@ -79,8 +79,6 @@ fn is_expr_stmt_attr_allowed(kind: SyntaxKind) -> bool { } pub(super) fn stmt(p: &mut Parser, with_semi: StmtWithSemi) { - // test block_items - // fn a() { fn b() {} } let m = p.start(); // test attr_on_expr_stmt // fn foo() { @@ -97,6 +95,8 @@ pub(super) fn stmt(p: &mut Parser, with_semi: StmtWithSemi) { return; } + // test block_items + // fn a() { fn b() {} } let m = match items::maybe_item(p, m, items::ItemFlavor::Mod) { Ok(()) => return, Err(m) => m, diff --git a/crates/ra_parser/src/grammar/patterns.rs b/crates/ra_parser/src/grammar/patterns.rs index 3afbaa82b84..936d27575c9 100644 --- a/crates/ra_parser/src/grammar/patterns.rs +++ b/crates/ra_parser/src/grammar/patterns.rs @@ -70,15 +70,6 @@ fn pattern_single_r(p: &mut Parser, recovery_set: TokenSet) { return; } } - // test marco_pat - // fn main() { - // let m!(x) = 0; - // } - if lhs.kind() == PATH_PAT && p.at(T![!]) { - let m = lhs.undo_completion(p); - items::macro_call_after_excl(p); - m.complete(p, MACRO_CALL); - } } } @@ -92,12 +83,12 @@ fn atom_pat(p: &mut Parser, recovery_set: TokenSet) -> Option { IDENT => match p.nth(1) { // Checks the token after an IDENT to see if a pattern is a path (Struct { .. }) or macro // (T![x]). - T!['('] | T!['{'] | T![!] => path_pat(p), - T![:] if p.nth_at(1, T![::]) => path_pat(p), + T!['('] | T!['{'] | T![!] => path_or_macro_pat(p), + T![:] if p.nth_at(1, T![::]) => path_or_macro_pat(p), _ => bind_pat(p, true), }, - _ if paths::is_use_path_start(p) => path_pat(p), + _ if paths::is_use_path_start(p) => path_or_macro_pat(p), _ if is_literal_pat_start(p) => literal_pat(p), T![.] if p.at(T![..]) => dot_dot_pat(p), @@ -146,7 +137,7 @@ fn literal_pat(p: &mut Parser) -> CompletedMarker { // let Bar { .. } = (); // let Bar(..) = (); // } -fn path_pat(p: &mut Parser) -> CompletedMarker { +fn path_or_macro_pat(p: &mut Parser) -> CompletedMarker { assert!(paths::is_use_path_start(p)); let m = p.start(); paths::expr_path(p); @@ -159,6 +150,14 @@ fn path_pat(p: &mut Parser) -> CompletedMarker { record_field_pat_list(p); RECORD_PAT } + // test marco_pat + // fn main() { + // let m!(x) = 0; + // } + T![!] => { + items::macro_call_after_excl(p); + return m.complete(p, MACRO_CALL).precede(p).complete(p, MACRO_PAT); + } _ => PATH_PAT, }; m.complete(p, kind) diff --git a/crates/ra_parser/src/syntax_kind/generated.rs b/crates/ra_parser/src/syntax_kind/generated.rs index dfc30d72783..4c16cf1cd9a 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 { SLICE_PAT, RANGE_PAT, LITERAL_PAT, + MACRO_PAT, TUPLE_EXPR, ARRAY_EXPR, PAREN_EXPR, diff --git a/crates/ra_syntax/src/ast/generated.rs b/crates/ra_syntax/src/ast/generated.rs index 7204ca5b172..0c339b9879d 100644 --- a/crates/ra_syntax/src/ast/generated.rs +++ b/crates/ra_syntax/src/ast/generated.rs @@ -2563,6 +2563,38 @@ impl LiteralPat { } } #[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct MacroPat { + pub(crate) syntax: SyntaxNode, +} +impl std::fmt::Display for MacroPat { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + std::fmt::Display::fmt(self.syntax(), f) + } +} +impl AstNode for MacroPat { + fn can_cast(kind: SyntaxKind) -> bool { + match kind { + MACRO_PAT => true, + _ => false, + } + } + fn cast(syntax: SyntaxNode) -> Option { + if Self::can_cast(syntax.kind()) { + Some(Self { syntax }) + } else { + None + } + } + fn syntax(&self) -> &SyntaxNode { + &self.syntax + } +} +impl MacroPat { + pub fn macro_call(&self) -> Option { + AstChildren::new(&self.syntax).next() + } +} +#[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct RecordPat { pub(crate) syntax: SyntaxNode, } @@ -4600,6 +4632,7 @@ pub enum Pat { SlicePat(SlicePat), RangePat(RangePat), LiteralPat(LiteralPat), + MacroPat(MacroPat), } impl From for Pat { fn from(node: OrPat) -> Pat { @@ -4671,6 +4704,11 @@ impl From for Pat { Pat::LiteralPat(node) } } +impl From for Pat { + fn from(node: MacroPat) -> Pat { + Pat::MacroPat(node) + } +} impl std::fmt::Display for Pat { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { std::fmt::Display::fmt(self.syntax(), f) @@ -4681,7 +4719,7 @@ impl AstNode for Pat { match kind { OR_PAT | PAREN_PAT | REF_PAT | BOX_PAT | BIND_PAT | PLACEHOLDER_PAT | DOT_DOT_PAT | PATH_PAT | RECORD_PAT | TUPLE_STRUCT_PAT | TUPLE_PAT | SLICE_PAT | RANGE_PAT - | LITERAL_PAT => true, + | LITERAL_PAT | MACRO_PAT => true, _ => false, } } @@ -4701,6 +4739,7 @@ impl AstNode for Pat { SLICE_PAT => Pat::SlicePat(SlicePat { syntax }), RANGE_PAT => Pat::RangePat(RangePat { syntax }), LITERAL_PAT => Pat::LiteralPat(LiteralPat { syntax }), + MACRO_PAT => Pat::MacroPat(MacroPat { syntax }), _ => return None, }; Some(res) @@ -4721,6 +4760,7 @@ impl AstNode for Pat { Pat::SlicePat(it) => &it.syntax, Pat::RangePat(it) => &it.syntax, Pat::LiteralPat(it) => &it.syntax, + Pat::MacroPat(it) => &it.syntax, } } } 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 b05ccc0ed57..36d8f4a5f5c 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) LET_STMT@[16; 30) LET_KW@[16; 19) "let" WHITESPACE@[19; 20) " " - MACRO_CALL@[20; 25) - PATH@[20; 21) - PATH_SEGMENT@[20; 21) - NAME_REF@[20; 21) - IDENT@[20; 21) "m" - EXCL@[21; 22) "!" - TOKEN_TREE@[22; 25) - L_PAREN@[22; 23) "(" - IDENT@[23; 24) "x" - R_PAREN@[24; 25) ")" + MACRO_PAT@[20; 25) + MACRO_CALL@[20; 25) + PATH@[20; 21) + PATH_SEGMENT@[20; 21) + NAME_REF@[20; 21) + IDENT@[20; 21) "m" + EXCL@[21; 22) "!" + TOKEN_TREE@[22; 25) + L_PAREN@[22; 23) "(" + IDENT@[23; 24) "x" + R_PAREN@[24; 25) ")" WHITESPACE@[25; 26) " " EQ@[26; 27) "=" WHITESPACE@[27; 28) " " diff --git a/xtask/src/ast_src.rs b/xtask/src/ast_src.rs index 99bd601989f..d9f51ec3994 100644 --- a/xtask/src/ast_src.rs +++ b/xtask/src/ast_src.rs @@ -138,6 +138,7 @@ pub(crate) const KINDS_SRC: KindsSrc = KindsSrc { "SLICE_PAT", "RANGE_PAT", "LITERAL_PAT", + "MACRO_PAT", // atoms "TUPLE_EXPR", "ARRAY_EXPR", @@ -440,6 +441,7 @@ pub(crate) const AST_SRC: AstSrc = AstSrc { struct SlicePat { args: [Pat] } struct RangePat {} struct LiteralPat { Literal } + struct MacroPat { MacroCall } struct RecordPat { RecordFieldPatList, Path } struct RecordFieldPatList { @@ -622,6 +624,7 @@ pub(crate) const AST_SRC: AstSrc = AstSrc { SlicePat, RangePat, LiteralPat, + MacroPat, } enum AttrInput { Literal, TokenTree }