mirror of
https://github.com/rust-lang/rust-analyzer
synced 2025-01-13 13:48:50 +00:00
Merge #3836
3836: Macro patterns are not confused with expressions. r=matklad a=matklad
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!() }`.
bors r+
🤖
Co-authored-by: Aleksey Kladov <aleksey.kladov@gmail.com>
This commit is contained in:
commit
6a2dd7bafc
8 changed files with 100 additions and 30 deletions
|
@ -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))
|
||||
|
|
|
@ -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
|
||||
"###
|
||||
);
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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<CompletedMarker> {
|
|||
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)
|
||||
|
|
|
@ -167,6 +167,7 @@ pub enum SyntaxKind {
|
|||
SLICE_PAT,
|
||||
RANGE_PAT,
|
||||
LITERAL_PAT,
|
||||
MACRO_PAT,
|
||||
TUPLE_EXPR,
|
||||
ARRAY_EXPR,
|
||||
PAREN_EXPR,
|
||||
|
|
|
@ -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<Self> {
|
||||
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<MacroCall> {
|
||||
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<OrPat> for Pat {
|
||||
fn from(node: OrPat) -> Pat {
|
||||
|
@ -4671,6 +4704,11 @@ impl From<LiteralPat> for Pat {
|
|||
Pat::LiteralPat(node)
|
||||
}
|
||||
}
|
||||
impl From<MacroPat> 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,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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) " "
|
||||
|
|
|
@ -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 }
|
||||
|
|
Loading…
Reference in a new issue