mirror of
https://github.com/rust-lang/rust-analyzer
synced 2024-12-26 04:53:34 +00:00
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!() }`.
This commit is contained in:
parent
0e46ed8420
commit
da8eb29a2f
7 changed files with 88 additions and 17 deletions
|
@ -672,8 +672,7 @@ impl ExprCollector<'_> {
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME: implement
|
// FIXME: implement
|
||||||
ast::Pat::BoxPat(_) => Pat::Missing,
|
ast::Pat::BoxPat(_) | ast::Pat::RangePat(_) | ast::Pat::MacroPat(_) => Pat::Missing,
|
||||||
ast::Pat::RangePat(_) => Pat::Missing,
|
|
||||||
};
|
};
|
||||||
let ptr = AstPtr::new(&pat);
|
let ptr = AstPtr::new(&pat);
|
||||||
self.alloc_pat(pattern, Either::Left(ptr))
|
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 insta::assert_snapshot;
|
||||||
use ra_db::fixture::WithFixture;
|
use ra_db::fixture::WithFixture;
|
||||||
|
|
||||||
|
use super::{infer, type_at, type_at_pos};
|
||||||
|
|
||||||
|
use crate::test_db::TestDB;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn cfg_impl_def() {
|
fn cfg_impl_def() {
|
||||||
let (db, pos) = TestDB::with_position(
|
let (db, pos) = TestDB::with_position(
|
||||||
|
@ -658,3 +660,28 @@ fn test() {
|
||||||
);
|
);
|
||||||
assert_eq!("S", type_at_pos(&db, pos));
|
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
|
||||||
|
"###
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
|
@ -84,7 +84,7 @@ fn atom_pat(p: &mut Parser, recovery_set: TokenSet) -> Option<CompletedMarker> {
|
||||||
// Checks the token after an IDENT to see if a pattern is a path (Struct { .. }) or macro
|
// Checks the token after an IDENT to see if a pattern is a path (Struct { .. }) or macro
|
||||||
// (T![x]).
|
// (T![x]).
|
||||||
T!['('] | T!['{'] | T![!] => path_or_macro_pat(p),
|
T!['('] | T!['{'] | T![!] => path_or_macro_pat(p),
|
||||||
T![:] if p.nth_at(1, T![::]) => path_pat(p),
|
T![:] if p.nth_at(1, T![::]) => path_or_macro_pat(p),
|
||||||
_ => bind_pat(p, true),
|
_ => bind_pat(p, true),
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -156,7 +156,7 @@ fn path_or_macro_pat(p: &mut Parser) -> CompletedMarker {
|
||||||
// }
|
// }
|
||||||
T![!] => {
|
T![!] => {
|
||||||
items::macro_call_after_excl(p);
|
items::macro_call_after_excl(p);
|
||||||
MACRO_CALL
|
return m.complete(p, MACRO_CALL).precede(p).complete(p, MACRO_PAT);
|
||||||
}
|
}
|
||||||
_ => PATH_PAT,
|
_ => PATH_PAT,
|
||||||
};
|
};
|
||||||
|
|
|
@ -167,6 +167,7 @@ pub enum SyntaxKind {
|
||||||
SLICE_PAT,
|
SLICE_PAT,
|
||||||
RANGE_PAT,
|
RANGE_PAT,
|
||||||
LITERAL_PAT,
|
LITERAL_PAT,
|
||||||
|
MACRO_PAT,
|
||||||
TUPLE_EXPR,
|
TUPLE_EXPR,
|
||||||
ARRAY_EXPR,
|
ARRAY_EXPR,
|
||||||
PAREN_EXPR,
|
PAREN_EXPR,
|
||||||
|
|
|
@ -2563,6 +2563,38 @@ impl LiteralPat {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
#[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 struct RecordPat {
|
||||||
pub(crate) syntax: SyntaxNode,
|
pub(crate) syntax: SyntaxNode,
|
||||||
}
|
}
|
||||||
|
@ -4600,6 +4632,7 @@ pub enum Pat {
|
||||||
SlicePat(SlicePat),
|
SlicePat(SlicePat),
|
||||||
RangePat(RangePat),
|
RangePat(RangePat),
|
||||||
LiteralPat(LiteralPat),
|
LiteralPat(LiteralPat),
|
||||||
|
MacroPat(MacroPat),
|
||||||
}
|
}
|
||||||
impl From<OrPat> for Pat {
|
impl From<OrPat> for Pat {
|
||||||
fn from(node: OrPat) -> Pat {
|
fn from(node: OrPat) -> Pat {
|
||||||
|
@ -4671,6 +4704,11 @@ impl From<LiteralPat> for Pat {
|
||||||
Pat::LiteralPat(node)
|
Pat::LiteralPat(node)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
impl From<MacroPat> for Pat {
|
||||||
|
fn from(node: MacroPat) -> Pat {
|
||||||
|
Pat::MacroPat(node)
|
||||||
|
}
|
||||||
|
}
|
||||||
impl std::fmt::Display for Pat {
|
impl std::fmt::Display for Pat {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||||
std::fmt::Display::fmt(self.syntax(), f)
|
std::fmt::Display::fmt(self.syntax(), f)
|
||||||
|
@ -4681,7 +4719,7 @@ impl AstNode for Pat {
|
||||||
match kind {
|
match kind {
|
||||||
OR_PAT | PAREN_PAT | REF_PAT | BOX_PAT | BIND_PAT | PLACEHOLDER_PAT | DOT_DOT_PAT
|
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
|
| PATH_PAT | RECORD_PAT | TUPLE_STRUCT_PAT | TUPLE_PAT | SLICE_PAT | RANGE_PAT
|
||||||
| LITERAL_PAT => true,
|
| LITERAL_PAT | MACRO_PAT => true,
|
||||||
_ => false,
|
_ => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4701,6 +4739,7 @@ impl AstNode for Pat {
|
||||||
SLICE_PAT => Pat::SlicePat(SlicePat { syntax }),
|
SLICE_PAT => Pat::SlicePat(SlicePat { syntax }),
|
||||||
RANGE_PAT => Pat::RangePat(RangePat { syntax }),
|
RANGE_PAT => Pat::RangePat(RangePat { syntax }),
|
||||||
LITERAL_PAT => Pat::LiteralPat(LiteralPat { syntax }),
|
LITERAL_PAT => Pat::LiteralPat(LiteralPat { syntax }),
|
||||||
|
MACRO_PAT => Pat::MacroPat(MacroPat { syntax }),
|
||||||
_ => return None,
|
_ => return None,
|
||||||
};
|
};
|
||||||
Some(res)
|
Some(res)
|
||||||
|
@ -4721,6 +4760,7 @@ impl AstNode for Pat {
|
||||||
Pat::SlicePat(it) => &it.syntax,
|
Pat::SlicePat(it) => &it.syntax,
|
||||||
Pat::RangePat(it) => &it.syntax,
|
Pat::RangePat(it) => &it.syntax,
|
||||||
Pat::LiteralPat(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_STMT@[16; 30)
|
||||||
LET_KW@[16; 19) "let"
|
LET_KW@[16; 19) "let"
|
||||||
WHITESPACE@[19; 20) " "
|
WHITESPACE@[19; 20) " "
|
||||||
MACRO_CALL@[20; 25)
|
MACRO_PAT@[20; 25)
|
||||||
PATH@[20; 21)
|
MACRO_CALL@[20; 25)
|
||||||
PATH_SEGMENT@[20; 21)
|
PATH@[20; 21)
|
||||||
NAME_REF@[20; 21)
|
PATH_SEGMENT@[20; 21)
|
||||||
IDENT@[20; 21) "m"
|
NAME_REF@[20; 21)
|
||||||
EXCL@[21; 22) "!"
|
IDENT@[20; 21) "m"
|
||||||
TOKEN_TREE@[22; 25)
|
EXCL@[21; 22) "!"
|
||||||
L_PAREN@[22; 23) "("
|
TOKEN_TREE@[22; 25)
|
||||||
IDENT@[23; 24) "x"
|
L_PAREN@[22; 23) "("
|
||||||
R_PAREN@[24; 25) ")"
|
IDENT@[23; 24) "x"
|
||||||
|
R_PAREN@[24; 25) ")"
|
||||||
WHITESPACE@[25; 26) " "
|
WHITESPACE@[25; 26) " "
|
||||||
EQ@[26; 27) "="
|
EQ@[26; 27) "="
|
||||||
WHITESPACE@[27; 28) " "
|
WHITESPACE@[27; 28) " "
|
||||||
|
|
|
@ -138,6 +138,7 @@ pub(crate) const KINDS_SRC: KindsSrc = KindsSrc {
|
||||||
"SLICE_PAT",
|
"SLICE_PAT",
|
||||||
"RANGE_PAT",
|
"RANGE_PAT",
|
||||||
"LITERAL_PAT",
|
"LITERAL_PAT",
|
||||||
|
"MACRO_PAT",
|
||||||
// atoms
|
// atoms
|
||||||
"TUPLE_EXPR",
|
"TUPLE_EXPR",
|
||||||
"ARRAY_EXPR",
|
"ARRAY_EXPR",
|
||||||
|
@ -440,6 +441,7 @@ pub(crate) const AST_SRC: AstSrc = AstSrc {
|
||||||
struct SlicePat { args: [Pat] }
|
struct SlicePat { args: [Pat] }
|
||||||
struct RangePat {}
|
struct RangePat {}
|
||||||
struct LiteralPat { Literal }
|
struct LiteralPat { Literal }
|
||||||
|
struct MacroPat { MacroCall }
|
||||||
|
|
||||||
struct RecordPat { RecordFieldPatList, Path }
|
struct RecordPat { RecordFieldPatList, Path }
|
||||||
struct RecordFieldPatList {
|
struct RecordFieldPatList {
|
||||||
|
@ -622,6 +624,7 @@ pub(crate) const AST_SRC: AstSrc = AstSrc {
|
||||||
SlicePat,
|
SlicePat,
|
||||||
RangePat,
|
RangePat,
|
||||||
LiteralPat,
|
LiteralPat,
|
||||||
|
MacroPat,
|
||||||
}
|
}
|
||||||
|
|
||||||
enum AttrInput { Literal, TokenTree }
|
enum AttrInput { Literal, TokenTree }
|
||||||
|
|
Loading…
Reference in a new issue