Skip to content

Commit 152f385

Browse files
Merge #8044
8044: Fix macro expansion for statements w/o semicolon r=edwin0cheng a=edwin0cheng Fixes #7845 And up `ungrammer` to 1.12. cc @jonas-schievink bors r+ Co-authored-by: Edwin Cheng <[email protected]>
2 parents c0a2b4e + 8e07b23 commit 152f385

File tree

10 files changed

+103
-65
lines changed

10 files changed

+103
-65
lines changed

Cargo.lock

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/hir_def/src/body/lower.rs

Lines changed: 58 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -519,21 +519,33 @@ impl ExprCollector<'_> {
519519
}
520520
ast::Expr::MacroCall(e) => {
521521
let mut ids = vec![];
522-
self.collect_macro_call(e, syntax_ptr.clone(), |this, expansion| {
522+
self.collect_macro_call(e, syntax_ptr.clone(), true, |this, expansion| {
523523
ids.push(match expansion {
524524
Some(it) => this.collect_expr(it),
525525
None => this.alloc_expr(Expr::Missing, syntax_ptr.clone()),
526526
})
527527
});
528528
ids[0]
529529
}
530+
ast::Expr::MacroStmts(e) => {
531+
// FIXME: these statements should be held by some hir containter
532+
for stmt in e.statements() {
533+
self.collect_stmt(stmt);
534+
}
535+
if let Some(expr) = e.expr() {
536+
self.collect_expr(expr)
537+
} else {
538+
self.alloc_expr(Expr::Missing, syntax_ptr)
539+
}
540+
}
530541
}
531542
}
532543

533544
fn collect_macro_call<F: FnMut(&mut Self, Option<T>), T: ast::AstNode>(
534545
&mut self,
535546
e: ast::MacroCall,
536547
syntax_ptr: AstPtr<ast::Expr>,
548+
is_error_recoverable: bool,
537549
mut collector: F,
538550
) {
539551
// File containing the macro call. Expansion errors will be attached here.
@@ -567,7 +579,7 @@ impl ExprCollector<'_> {
567579
Some((mark, expansion)) => {
568580
// FIXME: Statements are too complicated to recover from error for now.
569581
// It is because we don't have any hygiene for local variable expansion right now.
570-
if T::can_cast(syntax::SyntaxKind::MACRO_STMTS) && res.err.is_some() {
582+
if !is_error_recoverable && res.err.is_some() {
571583
self.expander.exit(self.db, mark);
572584
collector(self, None);
573585
} else {
@@ -591,56 +603,55 @@ impl ExprCollector<'_> {
591603
}
592604

593605
fn collect_stmt(&mut self, s: ast::Stmt) -> Option<Vec<Statement>> {
594-
let stmt =
595-
match s {
596-
ast::Stmt::LetStmt(stmt) => {
597-
self.check_cfg(&stmt)?;
598-
599-
let pat = self.collect_pat_opt(stmt.pat());
600-
let type_ref = stmt.ty().map(|it| TypeRef::from_ast(&self.ctx(), it));
601-
let initializer = stmt.initializer().map(|e| self.collect_expr(e));
602-
vec![Statement::Let { pat, type_ref, initializer }]
603-
}
604-
ast::Stmt::ExprStmt(stmt) => {
605-
self.check_cfg(&stmt)?;
606-
607-
// Note that macro could be expended to multiple statements
608-
if let Some(ast::Expr::MacroCall(m)) = stmt.expr() {
609-
let syntax_ptr = AstPtr::new(&stmt.expr().unwrap());
610-
let mut stmts = vec![];
611-
612-
self.collect_macro_call(m, syntax_ptr.clone(), |this, expansion| {
613-
match expansion {
614-
Some(expansion) => {
615-
let statements: ast::MacroStmts = expansion;
616-
617-
statements.statements().for_each(|stmt| {
618-
if let Some(mut r) = this.collect_stmt(stmt) {
619-
stmts.append(&mut r);
620-
}
621-
});
622-
if let Some(expr) = statements.expr() {
623-
stmts.push(Statement::Expr(this.collect_expr(expr)));
606+
let stmt = match s {
607+
ast::Stmt::LetStmt(stmt) => {
608+
self.check_cfg(&stmt)?;
609+
610+
let pat = self.collect_pat_opt(stmt.pat());
611+
let type_ref = stmt.ty().map(|it| TypeRef::from_ast(&self.ctx(), it));
612+
let initializer = stmt.initializer().map(|e| self.collect_expr(e));
613+
vec![Statement::Let { pat, type_ref, initializer }]
614+
}
615+
ast::Stmt::ExprStmt(stmt) => {
616+
self.check_cfg(&stmt)?;
617+
618+
// Note that macro could be expended to multiple statements
619+
if let Some(ast::Expr::MacroCall(m)) = stmt.expr() {
620+
let syntax_ptr = AstPtr::new(&stmt.expr().unwrap());
621+
let mut stmts = vec![];
622+
623+
self.collect_macro_call(m, syntax_ptr.clone(), false, |this, expansion| {
624+
match expansion {
625+
Some(expansion) => {
626+
let statements: ast::MacroStmts = expansion;
627+
628+
statements.statements().for_each(|stmt| {
629+
if let Some(mut r) = this.collect_stmt(stmt) {
630+
stmts.append(&mut r);
624631
}
625-
}
626-
None => {
627-
stmts.push(Statement::Expr(
628-
this.alloc_expr(Expr::Missing, syntax_ptr.clone()),
629-
));
632+
});
633+
if let Some(expr) = statements.expr() {
634+
stmts.push(Statement::Expr(this.collect_expr(expr)));
630635
}
631636
}
632-
});
633-
stmts
634-
} else {
635-
vec![Statement::Expr(self.collect_expr_opt(stmt.expr()))]
636-
}
637+
None => {
638+
stmts.push(Statement::Expr(
639+
this.alloc_expr(Expr::Missing, syntax_ptr.clone()),
640+
));
641+
}
642+
}
643+
});
644+
stmts
645+
} else {
646+
vec![Statement::Expr(self.collect_expr_opt(stmt.expr()))]
637647
}
638-
ast::Stmt::Item(item) => {
639-
self.check_cfg(&item)?;
648+
}
649+
ast::Stmt::Item(item) => {
650+
self.check_cfg(&item)?;
640651

641-
return None;
642-
}
643-
};
652+
return None;
653+
}
654+
};
644655

645656
Some(stmt)
646657
}

crates/hir_def/src/item_tree.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,11 @@ impl ItemTree {
110110
// still need to collect inner items.
111111
ctx.lower_inner_items(e.syntax())
112112
},
113+
ast::ExprStmt(stmt) => {
114+
// Macros can expand to stmt. We return an empty item tree in this case, but
115+
// still need to collect inner items.
116+
ctx.lower_inner_items(stmt.syntax())
117+
},
113118
_ => {
114119
panic!("cannot create item tree from {:?} {}", syntax, syntax);
115120
},

crates/hir_expand/src/db.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -401,13 +401,14 @@ fn to_fragment_kind(db: &dyn AstDatabase, id: MacroCallId) -> FragmentKind {
401401

402402
match parent.kind() {
403403
MACRO_ITEMS | SOURCE_FILE => FragmentKind::Items,
404+
MACRO_STMTS => FragmentKind::Statement,
404405
ITEM_LIST => FragmentKind::Items,
405406
LET_STMT => {
406407
// FIXME: Handle Pattern
407408
FragmentKind::Expr
408409
}
409410
EXPR_STMT => FragmentKind::Statements,
410-
BLOCK_EXPR => FragmentKind::Expr,
411+
BLOCK_EXPR => FragmentKind::Statements,
411412
ARG_LIST => FragmentKind::Expr,
412413
TRY_EXPR => FragmentKind::Expr,
413414
TUPLE_EXPR => FragmentKind::Expr,

crates/hir_ty/src/tests/macros.rs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -215,6 +215,22 @@ fn expr_macro_expanded_in_various_places() {
215215
);
216216
}
217217

218+
#[test]
219+
fn expr_macro_expanded_in_stmts() {
220+
check_infer(
221+
r#"
222+
macro_rules! id { ($($es:tt)*) => { $($es)* } }
223+
fn foo() {
224+
id! { let a = (); }
225+
}
226+
"#,
227+
expect![[r#"
228+
!0..8 'leta=();': ()
229+
57..84 '{ ...); } }': ()
230+
"#]],
231+
);
232+
}
233+
218234
#[test]
219235
fn infer_type_value_macro_having_same_name() {
220236
check_infer(

crates/mbe/src/tests.rs

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -662,12 +662,11 @@ fn test_tt_to_stmts() {
662662
663663
664664
665-
666-
667-
668-
669-
670-
665+
666+
667+
668+
669+
671670
);
672671
}
673672

crates/parser/src/grammar.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -63,11 +63,11 @@ pub(crate) mod fragments {
6363
}
6464

6565
pub(crate) fn stmt(p: &mut Parser) {
66-
expressions::stmt(p, expressions::StmtWithSemi::No)
66+
expressions::stmt(p, expressions::StmtWithSemi::No, true)
6767
}
6868

6969
pub(crate) fn stmt_optional_semi(p: &mut Parser) {
70-
expressions::stmt(p, expressions::StmtWithSemi::Optional)
70+
expressions::stmt(p, expressions::StmtWithSemi::Optional, false)
7171
}
7272

7373
pub(crate) fn opt_visibility(p: &mut Parser) {
@@ -133,7 +133,7 @@ pub(crate) mod fragments {
133133
continue;
134134
}
135135

136-
expressions::stmt(p, expressions::StmtWithSemi::Optional);
136+
expressions::stmt(p, expressions::StmtWithSemi::Optional, true);
137137
}
138138

139139
m.complete(p, MACRO_STMTS);

crates/parser/src/grammar/expressions.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ fn is_expr_stmt_attr_allowed(kind: SyntaxKind) -> bool {
5454
!forbid
5555
}
5656

57-
pub(super) fn stmt(p: &mut Parser, with_semi: StmtWithSemi) {
57+
pub(super) fn stmt(p: &mut Parser, with_semi: StmtWithSemi, prefer_expr: bool) {
5858
let m = p.start();
5959
// test attr_on_expr_stmt
6060
// fn foo() {
@@ -90,7 +90,7 @@ pub(super) fn stmt(p: &mut Parser, with_semi: StmtWithSemi) {
9090
p.error(format!("attributes are not allowed on {:?}", kind));
9191
}
9292

93-
if p.at(T!['}']) {
93+
if p.at(T!['}']) || (prefer_expr && p.at(EOF)) {
9494
// test attr_on_last_expr_in_block
9595
// fn foo() {
9696
// { #[A] bar!()? }
@@ -198,7 +198,7 @@ pub(super) fn expr_block_contents(p: &mut Parser) {
198198
continue;
199199
}
200200

201-
stmt(p, StmtWithSemi::Yes)
201+
stmt(p, StmtWithSemi::Yes, false)
202202
}
203203
}
204204

crates/syntax/src/ast/generated/nodes.rs

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1336,6 +1336,7 @@ pub enum Expr {
13361336
Literal(Literal),
13371337
LoopExpr(LoopExpr),
13381338
MacroCall(MacroCall),
1339+
MacroStmts(MacroStmts),
13391340
MatchExpr(MatchExpr),
13401341
MethodCallExpr(MethodCallExpr),
13411342
ParenExpr(ParenExpr),
@@ -3034,6 +3035,9 @@ impl From<LoopExpr> for Expr {
30343035
impl From<MacroCall> for Expr {
30353036
fn from(node: MacroCall) -> Expr { Expr::MacroCall(node) }
30363037
}
3038+
impl From<MacroStmts> for Expr {
3039+
fn from(node: MacroStmts) -> Expr { Expr::MacroStmts(node) }
3040+
}
30373041
impl From<MatchExpr> for Expr {
30383042
fn from(node: MatchExpr) -> Expr { Expr::MatchExpr(node) }
30393043
}
@@ -3078,8 +3082,8 @@ impl AstNode for Expr {
30783082
match kind {
30793083
ARRAY_EXPR | AWAIT_EXPR | BIN_EXPR | BLOCK_EXPR | BOX_EXPR | BREAK_EXPR | CALL_EXPR
30803084
| CAST_EXPR | CLOSURE_EXPR | CONTINUE_EXPR | EFFECT_EXPR | FIELD_EXPR | FOR_EXPR
3081-
| IF_EXPR | INDEX_EXPR | LITERAL | LOOP_EXPR | MACRO_CALL | MATCH_EXPR
3082-
| METHOD_CALL_EXPR | PAREN_EXPR | PATH_EXPR | PREFIX_EXPR | RANGE_EXPR
3085+
| IF_EXPR | INDEX_EXPR | LITERAL | LOOP_EXPR | MACRO_CALL | MACRO_STMTS
3086+
| MATCH_EXPR | METHOD_CALL_EXPR | PAREN_EXPR | PATH_EXPR | PREFIX_EXPR | RANGE_EXPR
30833087
| RECORD_EXPR | REF_EXPR | RETURN_EXPR | TRY_EXPR | TUPLE_EXPR | WHILE_EXPR
30843088
| YIELD_EXPR => true,
30853089
_ => false,
@@ -3105,6 +3109,7 @@ impl AstNode for Expr {
31053109
LITERAL => Expr::Literal(Literal { syntax }),
31063110
LOOP_EXPR => Expr::LoopExpr(LoopExpr { syntax }),
31073111
MACRO_CALL => Expr::MacroCall(MacroCall { syntax }),
3112+
MACRO_STMTS => Expr::MacroStmts(MacroStmts { syntax }),
31083113
MATCH_EXPR => Expr::MatchExpr(MatchExpr { syntax }),
31093114
METHOD_CALL_EXPR => Expr::MethodCallExpr(MethodCallExpr { syntax }),
31103115
PAREN_EXPR => Expr::ParenExpr(ParenExpr { syntax }),
@@ -3142,6 +3147,7 @@ impl AstNode for Expr {
31423147
Expr::Literal(it) => &it.syntax,
31433148
Expr::LoopExpr(it) => &it.syntax,
31443149
Expr::MacroCall(it) => &it.syntax,
3150+
Expr::MacroStmts(it) => &it.syntax,
31453151
Expr::MatchExpr(it) => &it.syntax,
31463152
Expr::MethodCallExpr(it) => &it.syntax,
31473153
Expr::ParenExpr(it) => &it.syntax,

xtask/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ anyhow = "1.0.26"
1111
flate2 = "1.0"
1212
proc-macro2 = "1.0.8"
1313
quote = "1.0.2"
14-
ungrammar = "=1.11"
14+
ungrammar = "=1.12"
1515
walkdir = "2.3.1"
1616
write-json = "0.1.0"
1717
xshell = "0.1"

0 commit comments

Comments
 (0)