Merge #11904
11904: internal: Wrap macros in expr position in `MacroExpr` node r=jonas-schievink a=jonas-schievink This lets us distinguish them from macros in item position just by looking at the syntax tree. Fixes https://github.com/rust-analyzer/rust-analyzer/issues/11854 bors r+ Co-authored-by: Jonas Schievink <jonas.schievink@ferrous-systems.com>
This commit is contained in:
commit
b5eaf56666
@ -110,8 +110,8 @@ fn body(&self) -> Option<&Body> {
|
||||
|
||||
fn expr_id(&self, db: &dyn HirDatabase, expr: &ast::Expr) -> Option<ExprId> {
|
||||
let src = match expr {
|
||||
ast::Expr::MacroCall(call) => {
|
||||
self.expand_expr(db, InFile::new(self.file_id, call.clone()))?
|
||||
ast::Expr::MacroExpr(expr) => {
|
||||
self.expand_expr(db, InFile::new(self.file_id, expr.macro_call()?.clone()))?
|
||||
}
|
||||
_ => InFile::new(self.file_id, expr.clone()),
|
||||
};
|
||||
|
@ -506,7 +506,8 @@ fn maybe_collect_expr(&mut self, expr: ast::Expr) -> Option<ExprId> {
|
||||
None => self.alloc_expr(Expr::Missing, syntax_ptr),
|
||||
}
|
||||
}
|
||||
ast::Expr::MacroCall(e) => {
|
||||
ast::Expr::MacroExpr(e) => {
|
||||
let e = e.macro_call()?;
|
||||
let macro_ptr = AstPtr::new(&e);
|
||||
let id = self.collect_macro_call(e, macro_ptr.clone(), true, |this, expansion| {
|
||||
expansion.map(|it| this.collect_expr(it))
|
||||
@ -629,7 +630,11 @@ fn collect_stmt(&mut self, s: ast::Stmt) {
|
||||
}
|
||||
let has_semi = stmt.semicolon_token().is_some();
|
||||
// Note that macro could be expended to multiple statements
|
||||
if let Some(ast::Expr::MacroCall(m)) = stmt.expr() {
|
||||
if let Some(ast::Expr::MacroExpr(e)) = stmt.expr() {
|
||||
let m = match e.macro_call() {
|
||||
Some(it) => it,
|
||||
None => return,
|
||||
};
|
||||
let macro_ptr = AstPtr::new(&m);
|
||||
let syntax_ptr = AstPtr::new(&stmt.expr().unwrap());
|
||||
|
||||
|
@ -79,6 +79,34 @@ macro_rules! n_nuple {
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn issue_3642_bad_macro_stackover() {
|
||||
lower(
|
||||
r#"
|
||||
#[macro_export]
|
||||
macro_rules! match_ast {
|
||||
(match $node:ident { $($tt:tt)* }) => { match_ast!(match ($node) { $($tt)* }) };
|
||||
|
||||
(match ($node:expr) {
|
||||
$( ast::$ast:ident($it:ident) => $res:expr, )*
|
||||
_ => $catch_all:expr $(,)?
|
||||
}) => {{
|
||||
$( if let Some($it) = ast::$ast::cast($node.clone()) { $res } else )*
|
||||
{ $catch_all }
|
||||
}};
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let anchor = match_ast! {
|
||||
match parent {
|
||||
as => {},
|
||||
_ => return None
|
||||
}
|
||||
};
|
||||
}"#,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn macro_resolve() {
|
||||
// Regression test for a path resolution bug introduced with inner item handling.
|
||||
|
@ -371,3 +371,27 @@ mod tests {
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn stmt_macro_expansion_with_trailing_expr() {
|
||||
cov_mark::check!(macro_stmt_with_trailing_macro_expr);
|
||||
check_at(
|
||||
r#"
|
||||
macro_rules! mac {
|
||||
() => { mac!($) };
|
||||
($x:tt) => { fn inner() {} };
|
||||
}
|
||||
fn foo() {
|
||||
mac!();
|
||||
$0
|
||||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
block scope
|
||||
inner: v
|
||||
|
||||
crate
|
||||
foo: v
|
||||
"#]],
|
||||
)
|
||||
}
|
||||
|
@ -48,22 +48,33 @@ pub(super) fn lower_module_items(mut self, item_owner: &dyn HasModuleItem) -> It
|
||||
pub(super) fn lower_macro_stmts(mut self, stmts: ast::MacroStmts) -> ItemTree {
|
||||
self.tree.top_level = stmts
|
||||
.statements()
|
||||
.filter_map(|stmt| match stmt {
|
||||
.filter_map(|stmt| {
|
||||
match stmt {
|
||||
ast::Stmt::Item(item) => Some(item),
|
||||
// Macro calls can be both items and expressions. The syntax library always treats
|
||||
// them as expressions here, so we undo that.
|
||||
ast::Stmt::ExprStmt(es) => match es.expr()? {
|
||||
ast::Expr::MacroCall(call) => {
|
||||
ast::Expr::MacroExpr(expr) => {
|
||||
cov_mark::hit!(macro_call_in_macro_stmts_is_added_to_item_tree);
|
||||
Some(call.into())
|
||||
Some(expr.macro_call()?.into())
|
||||
}
|
||||
_ => None,
|
||||
},
|
||||
_ => None,
|
||||
}
|
||||
})
|
||||
.flat_map(|item| self.lower_mod_item(&item))
|
||||
.collect();
|
||||
|
||||
if let Some(ast::Expr::MacroExpr(tail_macro)) = stmts.expr() {
|
||||
if let Some(call) = tail_macro.macro_call() {
|
||||
cov_mark::hit!(macro_stmt_with_trailing_macro_expr);
|
||||
if let Some(mod_item) = self.lower_mod_item(&call.into()) {
|
||||
self.tree.top_level.push(mod_item);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
self.tree
|
||||
}
|
||||
|
||||
@ -75,7 +86,7 @@ pub(super) fn lower_block(mut self, block: &ast::BlockExpr) -> ItemTree {
|
||||
// Macro calls can be both items and expressions. The syntax library always treats
|
||||
// them as expressions here, so we undo that.
|
||||
ast::Stmt::ExprStmt(es) => match es.expr()? {
|
||||
ast::Expr::MacroCall(call) => self.lower_mod_item(&call.into()),
|
||||
ast::Expr::MacroExpr(expr) => self.lower_mod_item(&expr.macro_call()?.into()),
|
||||
_ => None,
|
||||
},
|
||||
_ => None,
|
||||
|
@ -249,8 +249,7 @@ macro_rules! format_args {
|
||||
|
||||
fn main() {
|
||||
let _ =
|
||||
// +errors
|
||||
format_args!("{} {:?}", a.);
|
||||
format_args!/*+errors*/("{} {:?}", a.);
|
||||
}
|
||||
"#,
|
||||
expect![[r##"
|
||||
|
@ -530,8 +530,7 @@ macro_rules! m {
|
||||
}
|
||||
|
||||
fn f() -> i32 {
|
||||
// +tree
|
||||
m!{}
|
||||
m!/*+tree*/{}
|
||||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
|
@ -885,6 +885,16 @@ pub fn from_call_site(call: &ast::MacroCall) -> ExpandTo {
|
||||
None => return ExpandTo::Statements,
|
||||
};
|
||||
|
||||
// FIXME: macros in statement position are treated as expression statements, they should
|
||||
// probably be their own statement kind. The *grand*parent indicates what's valid.
|
||||
if parent.kind() == MACRO_EXPR
|
||||
&& parent
|
||||
.parent()
|
||||
.map_or(true, |p| matches!(p.kind(), EXPR_STMT | STMT_LIST | MACRO_STMTS))
|
||||
{
|
||||
return ExpandTo::Statements;
|
||||
}
|
||||
|
||||
match parent.kind() {
|
||||
MACRO_ITEMS | SOURCE_FILE | ITEM_LIST => ExpandTo::Items,
|
||||
MACRO_STMTS | EXPR_STMT | STMT_LIST => ExpandTo::Statements,
|
||||
@ -895,26 +905,13 @@ pub fn from_call_site(call: &ast::MacroCall) -> ExpandTo {
|
||||
| CLOSURE_EXPR | FIELD_EXPR | FOR_EXPR | IF_EXPR | INDEX_EXPR | LET_EXPR
|
||||
| MATCH_ARM | MATCH_EXPR | MATCH_GUARD | METHOD_CALL_EXPR | PAREN_EXPR | PATH_EXPR
|
||||
| PREFIX_EXPR | RANGE_EXPR | RECORD_EXPR_FIELD | REF_EXPR | RETURN_EXPR | TRY_EXPR
|
||||
| TUPLE_EXPR | WHILE_EXPR => ExpandTo::Expr,
|
||||
| TUPLE_EXPR | WHILE_EXPR | MACRO_EXPR => ExpandTo::Expr,
|
||||
_ => {
|
||||
match ast::LetStmt::cast(parent) {
|
||||
Some(let_stmt) => {
|
||||
if let Some(true) = let_stmt.initializer().map(|it| it.syntax() == syn) {
|
||||
ExpandTo::Expr
|
||||
} else if let Some(true) = let_stmt.ty().map(|it| it.syntax() == syn) {
|
||||
ExpandTo::Type
|
||||
} else {
|
||||
ExpandTo::Pattern
|
||||
}
|
||||
}
|
||||
None => {
|
||||
// Unknown , Just guess it is `Items`
|
||||
ExpandTo::Items
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
|
@ -444,34 +444,6 @@ fn test() {
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn issue_3642_bad_macro_stackover() {
|
||||
check_no_mismatches(
|
||||
r#"
|
||||
#[macro_export]
|
||||
macro_rules! match_ast {
|
||||
(match $node:ident { $($tt:tt)* }) => { match_ast!(match ($node) { $($tt)* }) };
|
||||
|
||||
(match ($node:expr) {
|
||||
$( ast::$ast:ident($it:ident) => $res:expr, )*
|
||||
_ => $catch_all:expr $(,)?
|
||||
}) => {{
|
||||
$( if let Some($it) = ast::$ast::cast($node.clone()) { $res } else )*
|
||||
{ $catch_all }
|
||||
}};
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let anchor = match_ast! {
|
||||
match parent {
|
||||
as => {},
|
||||
_ => return None
|
||||
}
|
||||
};
|
||||
}"#,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn issue_3999_slice() {
|
||||
check_infer(
|
||||
|
@ -156,7 +156,7 @@ fn hl(
|
||||
highlights.push(HighlightedRange { category: None, range: token.text_range() });
|
||||
}
|
||||
}
|
||||
ast::Expr::MethodCallExpr(_) | ast::Expr::CallExpr(_) | ast::Expr::MacroCall(_) => {
|
||||
ast::Expr::MethodCallExpr(_) | ast::Expr::CallExpr(_) | ast::Expr::MacroExpr(_) => {
|
||||
if sema.type_of_expr(&expr).map_or(false, |ty| ty.original.is_never()) {
|
||||
highlights.push(HighlightedRange {
|
||||
category: None,
|
||||
|
@ -163,6 +163,7 @@ fn foo() {
|
||||
L_CURLY@10..11 "{"
|
||||
WHITESPACE@11..16 "\n "
|
||||
EXPR_STMT@16..58
|
||||
MACRO_EXPR@16..57
|
||||
MACRO_CALL@16..57
|
||||
PATH@16..22
|
||||
PATH_SEGMENT@16..22
|
||||
@ -214,6 +215,7 @@ fn foo() {
|
||||
}"#,
|
||||
expect![[r#"
|
||||
EXPR_STMT@16..58
|
||||
MACRO_EXPR@16..57
|
||||
MACRO_CALL@16..57
|
||||
PATH@16..22
|
||||
PATH_SEGMENT@16..22
|
||||
|
@ -601,6 +601,17 @@ mod m {}
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn noop_in_item_position_with_macro() {
|
||||
type_char_noop('{', r#"$0println!();"#);
|
||||
type_char_noop(
|
||||
'{',
|
||||
r#"
|
||||
fn main() $0println!("hello");
|
||||
}"#,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn adds_closing_brace_for_use_tree() {
|
||||
type_char(
|
||||
|
@ -111,7 +111,7 @@ pub(crate) fn convert_if_to_bool_then(acc: &mut Assists, ctx: &AssistContext) ->
|
||||
| ast::Expr::ForExpr(_)
|
||||
| ast::Expr::IfExpr(_)
|
||||
| ast::Expr::LoopExpr(_)
|
||||
| ast::Expr::MacroCall(_)
|
||||
| ast::Expr::MacroExpr(_)
|
||||
| ast::Expr::MatchExpr(_)
|
||||
| ast::Expr::PrefixExpr(_)
|
||||
| ast::Expr::RangeExpr(_)
|
||||
|
@ -649,8 +649,8 @@ fn analyze(
|
||||
ast::Expr::PathExpr(path_expr) => {
|
||||
cb(path_expr.path().and_then(|it| it.as_single_name_ref()))
|
||||
}
|
||||
ast::Expr::MacroCall(call) => {
|
||||
if let Some(tt) = call.token_tree() {
|
||||
ast::Expr::MacroExpr(expr) => {
|
||||
if let Some(tt) = expr.macro_call().and_then(|call| call.token_tree()) {
|
||||
tt.syntax()
|
||||
.children_with_tokens()
|
||||
.flat_map(SyntaxElement::into_token)
|
||||
@ -923,7 +923,7 @@ fn reference_is_exclusive(
|
||||
|
||||
/// checks if this expr requires `&mut` access, recurses on field access
|
||||
fn expr_require_exclusive_access(ctx: &AssistContext, expr: &ast::Expr) -> Option<bool> {
|
||||
if let ast::Expr::MacroCall(_) = expr {
|
||||
if let ast::Expr::MacroExpr(_) = expr {
|
||||
// FIXME: expand macro and check output for mutable usages of the variable?
|
||||
return None;
|
||||
}
|
||||
@ -1015,7 +1015,7 @@ fn path_element_of_reference(
|
||||
None
|
||||
})?;
|
||||
stdx::always!(
|
||||
matches!(path, ast::Expr::PathExpr(_) | ast::Expr::MacroCall(_)),
|
||||
matches!(path, ast::Expr::PathExpr(_) | ast::Expr::MacroExpr(_)),
|
||||
"unexpected expression type for variable usage: {:?}",
|
||||
path
|
||||
);
|
||||
|
@ -39,15 +39,16 @@ pub(crate) fn remove_dbg(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
|
||||
.map(|mut tokens| syntax::hacks::parse_expr_from_str(&tokens.join("")))
|
||||
.collect::<Option<Vec<ast::Expr>>>()?;
|
||||
|
||||
let parent = macro_call.syntax().parent()?;
|
||||
let macro_expr = ast::MacroExpr::cast(macro_call.syntax().parent()?)?;
|
||||
let parent = macro_expr.syntax().parent()?;
|
||||
let (range, text) = match &*input_expressions {
|
||||
// dbg!()
|
||||
[] => {
|
||||
match_ast! {
|
||||
match parent {
|
||||
ast::StmtList(__) => {
|
||||
let range = macro_call.syntax().text_range();
|
||||
let range = match whitespace_start(macro_call.syntax().prev_sibling_or_token()) {
|
||||
let range = macro_expr.syntax().text_range();
|
||||
let range = match whitespace_start(macro_expr.syntax().prev_sibling_or_token()) {
|
||||
Some(start) => range.cover_offset(start),
|
||||
None => range,
|
||||
};
|
||||
|
@ -62,11 +62,6 @@ pub fn preorder_expr(start: &ast::Expr, cb: &mut dyn FnMut(WalkEvent<ast::Expr>)
|
||||
match ast::Stmt::cast(node.clone()) {
|
||||
// Don't skip subtree since we want to process the expression child next
|
||||
Some(ast::Stmt::ExprStmt(_)) | Some(ast::Stmt::LetStmt(_)) => (),
|
||||
// This might be an expression
|
||||
Some(ast::Stmt::Item(ast::Item::MacroCall(mcall))) => {
|
||||
cb(WalkEvent::Enter(ast::Expr::MacroCall(mcall)));
|
||||
preorder.skip_subtree();
|
||||
}
|
||||
// skip inner items which might have their own expressions
|
||||
Some(ast::Stmt::Item(_)) => preorder.skip_subtree(),
|
||||
None => {
|
||||
@ -319,7 +314,7 @@ pub fn for_each_tail_expr(expr: &ast::Expr, cb: &mut dyn FnMut(&ast::Expr)) {
|
||||
| ast::Expr::ForExpr(_)
|
||||
| ast::Expr::IndexExpr(_)
|
||||
| ast::Expr::Literal(_)
|
||||
| ast::Expr::MacroCall(_)
|
||||
| ast::Expr::MacroExpr(_)
|
||||
| ast::Expr::MacroStmts(_)
|
||||
| ast::Expr::MethodCallExpr(_)
|
||||
| ast::Expr::ParenExpr(_)
|
||||
|
@ -552,7 +552,7 @@ fn path_expr(p: &mut Parser, r: Restrictions) -> (CompletedMarker, BlockLike) {
|
||||
}
|
||||
T![!] if !p.at(T![!=]) => {
|
||||
let block_like = items::macro_call_after_excl(p);
|
||||
(m.complete(p, MACRO_CALL), block_like)
|
||||
(m.complete(p, MACRO_CALL).precede(p).complete(p, MACRO_EXPR), block_like)
|
||||
}
|
||||
_ => (m.complete(p, PATH_EXPR), BlockLike::NotBlock),
|
||||
}
|
||||
|
@ -605,6 +605,7 @@ fn try_block_expr(p: &mut Parser, m: Option<Marker>) -> CompletedMarker {
|
||||
if p.nth_at(1, T![!]) {
|
||||
// test try_macro_fallback
|
||||
// fn foo() { try!(Ok(())); }
|
||||
let macro_call = p.start();
|
||||
let path = p.start();
|
||||
let path_segment = p.start();
|
||||
let name_ref = p.start();
|
||||
@ -613,7 +614,8 @@ fn try_block_expr(p: &mut Parser, m: Option<Marker>) -> CompletedMarker {
|
||||
path_segment.complete(p, PATH_SEGMENT);
|
||||
path.complete(p, PATH);
|
||||
let _block_like = items::macro_call_after_excl(p);
|
||||
return m.complete(p, MACRO_CALL);
|
||||
macro_call.complete(p, MACRO_CALL);
|
||||
return m.complete(p, MACRO_EXPR);
|
||||
}
|
||||
|
||||
p.bump(T![try]);
|
||||
|
@ -190,6 +190,7 @@ pub enum SyntaxKind {
|
||||
YIELD_EXPR,
|
||||
LET_EXPR,
|
||||
UNDERSCORE_EXPR,
|
||||
MACRO_EXPR,
|
||||
MATCH_EXPR,
|
||||
MATCH_ARM_LIST,
|
||||
MATCH_ARM,
|
||||
|
@ -104,6 +104,7 @@ SOURCE_FILE
|
||||
IDENT "entries"
|
||||
COLON ":"
|
||||
WHITESPACE " "
|
||||
MACRO_EXPR
|
||||
MACRO_CALL
|
||||
PATH
|
||||
PATH_SEGMENT
|
||||
|
@ -12,6 +12,7 @@ SOURCE_FILE
|
||||
STMT_LIST
|
||||
L_CURLY "{"
|
||||
WHITESPACE "\n "
|
||||
MACRO_EXPR
|
||||
MACRO_CALL
|
||||
PATH
|
||||
PATH_SEGMENT
|
||||
|
@ -81,6 +81,7 @@ SOURCE_FILE
|
||||
WHITESPACE " "
|
||||
EQ "="
|
||||
WHITESPACE " "
|
||||
MACRO_EXPR
|
||||
MACRO_CALL
|
||||
PATH
|
||||
PATH_SEGMENT
|
||||
|
@ -110,6 +110,7 @@ SOURCE_FILE
|
||||
WHITESPACE "\n "
|
||||
R_CURLY "}"
|
||||
WHITESPACE "\n "
|
||||
MACRO_EXPR
|
||||
MACRO_CALL
|
||||
PATH
|
||||
PATH_SEGMENT
|
||||
|
@ -35,7 +35,7 @@ SOURCE_FILE
|
||||
SEMICOLON ";"
|
||||
WHITESPACE "\n "
|
||||
EXPR_STMT
|
||||
MACRO_CALL
|
||||
MACRO_EXPR
|
||||
ATTR
|
||||
POUND "#"
|
||||
L_BRACK "["
|
||||
@ -46,6 +46,7 @@ SOURCE_FILE
|
||||
IDENT "B"
|
||||
R_BRACK "]"
|
||||
WHITESPACE " "
|
||||
MACRO_CALL
|
||||
PATH
|
||||
PATH_SEGMENT
|
||||
NAME_REF
|
||||
|
@ -13,6 +13,7 @@ SOURCE_FILE
|
||||
L_CURLY "{"
|
||||
WHITESPACE " "
|
||||
EXPR_STMT
|
||||
MACRO_EXPR
|
||||
MACRO_CALL
|
||||
PATH
|
||||
PATH_SEGMENT
|
||||
|
@ -396,6 +396,7 @@ SOURCE_FILE
|
||||
SEMICOLON ";"
|
||||
WHITESPACE "\n "
|
||||
EXPR_STMT
|
||||
MACRO_EXPR
|
||||
MACRO_CALL
|
||||
PATH
|
||||
PATH_SEGMENT
|
||||
@ -887,6 +888,7 @@ SOURCE_FILE
|
||||
PAREN_EXPR
|
||||
L_PAREN "("
|
||||
BIN_EXPR
|
||||
MACRO_EXPR
|
||||
MACRO_CALL
|
||||
PATH
|
||||
PATH_SEGMENT
|
||||
@ -905,6 +907,7 @@ SOURCE_FILE
|
||||
WHITESPACE " "
|
||||
PAREN_EXPR
|
||||
L_PAREN "("
|
||||
MACRO_EXPR
|
||||
MACRO_CALL
|
||||
PATH
|
||||
PATH_SEGMENT
|
||||
@ -934,6 +937,7 @@ SOURCE_FILE
|
||||
PAREN_EXPR
|
||||
L_PAREN "("
|
||||
BIN_EXPR
|
||||
MACRO_EXPR
|
||||
MACRO_CALL
|
||||
PATH
|
||||
PATH_SEGMENT
|
||||
@ -978,6 +982,7 @@ SOURCE_FILE
|
||||
PAREN_EXPR
|
||||
L_PAREN "("
|
||||
BIN_EXPR
|
||||
MACRO_EXPR
|
||||
MACRO_CALL
|
||||
PATH
|
||||
PATH_SEGMENT
|
||||
@ -1130,6 +1135,7 @@ SOURCE_FILE
|
||||
WHITESPACE " "
|
||||
FAT_ARROW "=>"
|
||||
WHITESPACE " "
|
||||
MACRO_EXPR
|
||||
MACRO_CALL
|
||||
PATH
|
||||
PATH_SEGMENT
|
||||
@ -1176,6 +1182,7 @@ SOURCE_FILE
|
||||
WHITESPACE " "
|
||||
EQ "="
|
||||
WHITESPACE " "
|
||||
MACRO_EXPR
|
||||
MACRO_CALL
|
||||
PATH
|
||||
PATH_SEGMENT
|
||||
@ -1204,6 +1211,7 @@ SOURCE_FILE
|
||||
L_CURLY "{"
|
||||
WHITESPACE "\n "
|
||||
EXPR_STMT
|
||||
MACRO_EXPR
|
||||
MACRO_CALL
|
||||
PATH
|
||||
PATH_SEGMENT
|
||||
@ -1353,6 +1361,7 @@ SOURCE_FILE
|
||||
L_CURLY "{"
|
||||
WHITESPACE "\n "
|
||||
EXPR_STMT
|
||||
MACRO_EXPR
|
||||
MACRO_CALL
|
||||
PATH
|
||||
PATH_SEGMENT
|
||||
@ -1508,6 +1517,7 @@ SOURCE_FILE
|
||||
L_CURLY "{"
|
||||
WHITESPACE "\n "
|
||||
EXPR_STMT
|
||||
MACRO_EXPR
|
||||
MACRO_CALL
|
||||
PATH
|
||||
PATH_SEGMENT
|
||||
@ -1741,6 +1751,7 @@ SOURCE_FILE
|
||||
SEMICOLON ";"
|
||||
WHITESPACE "\n "
|
||||
EXPR_STMT
|
||||
MACRO_EXPR
|
||||
MACRO_CALL
|
||||
PATH
|
||||
PATH_SEGMENT
|
||||
|
@ -42,6 +42,7 @@ SOURCE_FILE
|
||||
STMT_LIST
|
||||
L_CURLY "{"
|
||||
WHITESPACE "\n "
|
||||
MACRO_EXPR
|
||||
MACRO_CALL
|
||||
PATH
|
||||
PATH_SEGMENT
|
||||
|
@ -38,6 +38,7 @@ SOURCE_FILE
|
||||
IDENT "B"
|
||||
R_BRACK "]"
|
||||
WHITESPACE " "
|
||||
MACRO_EXPR
|
||||
MACRO_CALL
|
||||
PATH
|
||||
PATH_SEGMENT
|
||||
|
@ -342,7 +342,7 @@ Expr =
|
||||
| IndexExpr
|
||||
| Literal
|
||||
| LoopExpr
|
||||
| MacroCall
|
||||
| MacroExpr
|
||||
| MacroStmts
|
||||
| MatchExpr
|
||||
| MethodCallExpr
|
||||
@ -360,6 +360,9 @@ Expr =
|
||||
| LetExpr
|
||||
| UnderscoreExpr
|
||||
|
||||
MacroExpr =
|
||||
MacroCall
|
||||
|
||||
Literal =
|
||||
Attr* value:(
|
||||
'int_number' | 'float_number'
|
||||
|
@ -918,6 +918,14 @@ impl LoopExpr {
|
||||
pub fn loop_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![loop]) }
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||
pub struct MacroExpr {
|
||||
pub(crate) syntax: SyntaxNode,
|
||||
}
|
||||
impl MacroExpr {
|
||||
pub fn macro_call(&self) -> Option<MacroCall> { support::child(&self.syntax) }
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||
pub struct MatchExpr {
|
||||
pub(crate) syntax: SyntaxNode,
|
||||
@ -1518,7 +1526,7 @@ pub enum Expr {
|
||||
IndexExpr(IndexExpr),
|
||||
Literal(Literal),
|
||||
LoopExpr(LoopExpr),
|
||||
MacroCall(MacroCall),
|
||||
MacroExpr(MacroExpr),
|
||||
MacroStmts(MacroStmts),
|
||||
MatchExpr(MatchExpr),
|
||||
MethodCallExpr(MethodCallExpr),
|
||||
@ -2532,6 +2540,17 @@ fn cast(syntax: SyntaxNode) -> Option<Self> {
|
||||
}
|
||||
fn syntax(&self) -> &SyntaxNode { &self.syntax }
|
||||
}
|
||||
impl AstNode for MacroExpr {
|
||||
fn can_cast(kind: SyntaxKind) -> bool { kind == MACRO_EXPR }
|
||||
fn cast(syntax: SyntaxNode) -> Option<Self> {
|
||||
if Self::can_cast(syntax.kind()) {
|
||||
Some(Self { syntax })
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
fn syntax(&self) -> &SyntaxNode { &self.syntax }
|
||||
}
|
||||
impl AstNode for MatchExpr {
|
||||
fn can_cast(kind: SyntaxKind) -> bool { kind == MATCH_EXPR }
|
||||
fn cast(syntax: SyntaxNode) -> Option<Self> {
|
||||
@ -3313,8 +3332,8 @@ fn from(node: Literal) -> Expr { Expr::Literal(node) }
|
||||
impl From<LoopExpr> for Expr {
|
||||
fn from(node: LoopExpr) -> Expr { Expr::LoopExpr(node) }
|
||||
}
|
||||
impl From<MacroCall> for Expr {
|
||||
fn from(node: MacroCall) -> Expr { Expr::MacroCall(node) }
|
||||
impl From<MacroExpr> for Expr {
|
||||
fn from(node: MacroExpr) -> Expr { Expr::MacroExpr(node) }
|
||||
}
|
||||
impl From<MacroStmts> for Expr {
|
||||
fn from(node: MacroStmts) -> Expr { Expr::MacroStmts(node) }
|
||||
@ -3369,7 +3388,7 @@ fn can_cast(kind: SyntaxKind) -> bool {
|
||||
match kind {
|
||||
ARRAY_EXPR | AWAIT_EXPR | BIN_EXPR | BLOCK_EXPR | BOX_EXPR | BREAK_EXPR | CALL_EXPR
|
||||
| CAST_EXPR | CLOSURE_EXPR | CONTINUE_EXPR | FIELD_EXPR | FOR_EXPR | IF_EXPR
|
||||
| INDEX_EXPR | LITERAL | LOOP_EXPR | MACRO_CALL | MACRO_STMTS | MATCH_EXPR
|
||||
| INDEX_EXPR | LITERAL | LOOP_EXPR | MACRO_EXPR | MACRO_STMTS | MATCH_EXPR
|
||||
| METHOD_CALL_EXPR | PAREN_EXPR | PATH_EXPR | PREFIX_EXPR | RANGE_EXPR
|
||||
| RECORD_EXPR | REF_EXPR | RETURN_EXPR | TRY_EXPR | TUPLE_EXPR | WHILE_EXPR
|
||||
| YIELD_EXPR | LET_EXPR | UNDERSCORE_EXPR => true,
|
||||
@ -3394,7 +3413,7 @@ fn cast(syntax: SyntaxNode) -> Option<Self> {
|
||||
INDEX_EXPR => Expr::IndexExpr(IndexExpr { syntax }),
|
||||
LITERAL => Expr::Literal(Literal { syntax }),
|
||||
LOOP_EXPR => Expr::LoopExpr(LoopExpr { syntax }),
|
||||
MACRO_CALL => Expr::MacroCall(MacroCall { syntax }),
|
||||
MACRO_EXPR => Expr::MacroExpr(MacroExpr { syntax }),
|
||||
MACRO_STMTS => Expr::MacroStmts(MacroStmts { syntax }),
|
||||
MATCH_EXPR => Expr::MatchExpr(MatchExpr { syntax }),
|
||||
METHOD_CALL_EXPR => Expr::MethodCallExpr(MethodCallExpr { syntax }),
|
||||
@ -3433,7 +3452,7 @@ fn syntax(&self) -> &SyntaxNode {
|
||||
Expr::IndexExpr(it) => &it.syntax,
|
||||
Expr::Literal(it) => &it.syntax,
|
||||
Expr::LoopExpr(it) => &it.syntax,
|
||||
Expr::MacroCall(it) => &it.syntax,
|
||||
Expr::MacroExpr(it) => &it.syntax,
|
||||
Expr::MacroStmts(it) => &it.syntax,
|
||||
Expr::MatchExpr(it) => &it.syntax,
|
||||
Expr::MethodCallExpr(it) => &it.syntax,
|
||||
@ -4506,6 +4525,11 @@ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
std::fmt::Display::fmt(self.syntax(), f)
|
||||
}
|
||||
}
|
||||
impl std::fmt::Display for MacroExpr {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
std::fmt::Display::fmt(self.syntax(), f)
|
||||
}
|
||||
}
|
||||
impl std::fmt::Display for MatchExpr {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
std::fmt::Display::fmt(self.syntax(), f)
|
||||
|
@ -144,6 +144,7 @@ pub(crate) struct KindsSrc<'a> {
|
||||
"YIELD_EXPR",
|
||||
"LET_EXPR",
|
||||
"UNDERSCORE_EXPR",
|
||||
"MACRO_EXPR",
|
||||
"MATCH_EXPR",
|
||||
"MATCH_ARM_LIST",
|
||||
"MATCH_ARM",
|
||||
|
Loading…
Reference in New Issue
Block a user