aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEdwin Cheng <[email protected]>2021-03-16 05:44:50 +0000
committerEdwin Cheng <[email protected]>2021-03-16 05:44:50 +0000
commit8e07b23b84bff16c0decc6f2b80c27862eac6df1 (patch)
treee8470eb83c1bc1283f0bb28ea01db789607a3140
parentc0a2b4e826e1da20d3cfa8c279fcdffa24f32a7d (diff)
Fix macro expansion for statements w/o semicolon
-rw-r--r--Cargo.lock4
-rw-r--r--crates/hir_def/src/body/lower.rs105
-rw-r--r--crates/hir_def/src/item_tree.rs5
-rw-r--r--crates/hir_expand/src/db.rs3
-rw-r--r--crates/hir_ty/src/tests/macros.rs16
-rw-r--r--crates/mbe/src/tests.rs11
-rw-r--r--crates/parser/src/grammar.rs6
-rw-r--r--crates/parser/src/grammar/expressions.rs6
-rw-r--r--crates/syntax/src/ast/generated/nodes.rs10
-rw-r--r--xtask/Cargo.toml2
10 files changed, 103 insertions, 65 deletions
diff --git a/Cargo.lock b/Cargo.lock
index b2d009e38..2efae6a01 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1811,9 +1811,9 @@ checksum = "56dee185309b50d1f11bfedef0fe6d036842e3fb77413abef29f8f8d1c5d4c1c"
1811 1811
1812[[package]] 1812[[package]]
1813name = "ungrammar" 1813name = "ungrammar"
1814version = "1.11.0" 1814version = "1.12.2"
1815source = "registry+https://github.com/rust-lang/crates.io-index" 1815source = "registry+https://github.com/rust-lang/crates.io-index"
1816checksum = "84c629795d377049f2a1dc5f42cf505dc5ba8b28a5df0a03f4183a24480e4a6a" 1816checksum = "df6586a7c530704efe803d49a0b4132dcbdb4063163df39110548e6b5f2373ba"
1817 1817
1818[[package]] 1818[[package]]
1819name = "unicase" 1819name = "unicase"
diff --git a/crates/hir_def/src/body/lower.rs b/crates/hir_def/src/body/lower.rs
index 8934ae6c9..7052058f2 100644
--- a/crates/hir_def/src/body/lower.rs
+++ b/crates/hir_def/src/body/lower.rs
@@ -519,7 +519,7 @@ impl ExprCollector<'_> {
519 } 519 }
520 ast::Expr::MacroCall(e) => { 520 ast::Expr::MacroCall(e) => {
521 let mut ids = vec![]; 521 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| {
523 ids.push(match expansion { 523 ids.push(match expansion {
524 Some(it) => this.collect_expr(it), 524 Some(it) => this.collect_expr(it),
525 None => this.alloc_expr(Expr::Missing, syntax_ptr.clone()), 525 None => this.alloc_expr(Expr::Missing, syntax_ptr.clone()),
@@ -527,6 +527,17 @@ impl ExprCollector<'_> {
527 }); 527 });
528 ids[0] 528 ids[0]
529 } 529 }
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 }
530 } 541 }
531 } 542 }
532 543
@@ -534,6 +545,7 @@ impl ExprCollector<'_> {
534 &mut self, 545 &mut self,
535 e: ast::MacroCall, 546 e: ast::MacroCall,
536 syntax_ptr: AstPtr<ast::Expr>, 547 syntax_ptr: AstPtr<ast::Expr>,
548 is_error_recoverable: bool,
537 mut collector: F, 549 mut collector: F,
538 ) { 550 ) {
539 // File containing the macro call. Expansion errors will be attached here. 551 // File containing the macro call. Expansion errors will be attached here.
@@ -567,7 +579,7 @@ impl ExprCollector<'_> {
567 Some((mark, expansion)) => { 579 Some((mark, expansion)) => {
568 // FIXME: Statements are too complicated to recover from error for now. 580 // FIXME: Statements are too complicated to recover from error for now.
569 // It is because we don't have any hygiene for local variable expansion right now. 581 // 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() {
571 self.expander.exit(self.db, mark); 583 self.expander.exit(self.db, mark);
572 collector(self, None); 584 collector(self, None);
573 } else { 585 } else {
@@ -591,56 +603,55 @@ impl ExprCollector<'_> {
591 } 603 }
592 604
593 fn collect_stmt(&mut self, s: ast::Stmt) -> Option<Vec<Statement>> { 605 fn collect_stmt(&mut self, s: ast::Stmt) -> Option<Vec<Statement>> {
594 let stmt = 606 let stmt = match s {
595 match s { 607 ast::Stmt::LetStmt(stmt) => {
596 ast::Stmt::LetStmt(stmt) => { 608 self.check_cfg(&stmt)?;
597 self.check_cfg(&stmt)?; 609
598 610 let pat = self.collect_pat_opt(stmt.pat());
599 let pat = self.collect_pat_opt(stmt.pat()); 611 let type_ref = stmt.ty().map(|it| TypeRef::from_ast(&self.ctx(), it));
600 let type_ref = stmt.ty().map(|it| TypeRef::from_ast(&self.ctx(), it)); 612 let initializer = stmt.initializer().map(|e| self.collect_expr(e));
601 let initializer = stmt.initializer().map(|e| self.collect_expr(e)); 613 vec![Statement::Let { pat, type_ref, initializer }]
602 vec![Statement::Let { pat, type_ref, initializer }] 614 }
603 } 615 ast::Stmt::ExprStmt(stmt) => {
604 ast::Stmt::ExprStmt(stmt) => { 616 self.check_cfg(&stmt)?;
605 self.check_cfg(&stmt)?; 617
606 618 // Note that macro could be expended to multiple statements
607 // Note that macro could be expended to multiple statements 619 if let Some(ast::Expr::MacroCall(m)) = stmt.expr() {
608 if let Some(ast::Expr::MacroCall(m)) = stmt.expr() { 620 let syntax_ptr = AstPtr::new(&stmt.expr().unwrap());
609 let syntax_ptr = AstPtr::new(&stmt.expr().unwrap()); 621 let mut stmts = vec![];
610 let mut stmts = vec![]; 622
611 623 self.collect_macro_call(m, syntax_ptr.clone(), false, |this, expansion| {
612 self.collect_macro_call(m, syntax_ptr.clone(), |this, expansion| { 624 match expansion {
613 match expansion { 625 Some(expansion) => {
614 Some(expansion) => { 626 let statements: ast::MacroStmts = expansion;
615 let statements: ast::MacroStmts = expansion; 627
616 628 statements.statements().for_each(|stmt| {
617 statements.statements().for_each(|stmt| { 629 if let Some(mut r) = this.collect_stmt(stmt) {
618 if let Some(mut r) = this.collect_stmt(stmt) { 630 stmts.append(&mut r);
619 stmts.append(&mut r);
620 }
621 });
622 if let Some(expr) = statements.expr() {
623 stmts.push(Statement::Expr(this.collect_expr(expr)));
624 } 631 }
625 } 632 });
626 None => { 633 if let Some(expr) = statements.expr() {
627 stmts.push(Statement::Expr( 634 stmts.push(Statement::Expr(this.collect_expr(expr)));
628 this.alloc_expr(Expr::Missing, syntax_ptr.clone()),
629 ));
630 } 635 }
631 } 636 }
632 }); 637 None => {
633 stmts 638 stmts.push(Statement::Expr(
634 } else { 639 this.alloc_expr(Expr::Missing, syntax_ptr.clone()),
635 vec![Statement::Expr(self.collect_expr_opt(stmt.expr()))] 640 ));
636 } 641 }
642 }
643 });
644 stmts
645 } else {
646 vec![Statement::Expr(self.collect_expr_opt(stmt.expr()))]
637 } 647 }
638 ast::Stmt::Item(item) => { 648 }
639 self.check_cfg(&item)?; 649 ast::Stmt::Item(item) => {
650 self.check_cfg(&item)?;
640 651
641 return None; 652 return None;
642 } 653 }
643 }; 654 };
644 655
645 Some(stmt) 656 Some(stmt)
646 } 657 }
diff --git a/crates/hir_def/src/item_tree.rs b/crates/hir_def/src/item_tree.rs
index 09bcb10dc..86239d903 100644
--- a/crates/hir_def/src/item_tree.rs
+++ b/crates/hir_def/src/item_tree.rs
@@ -110,6 +110,11 @@ impl ItemTree {
110 // still need to collect inner items. 110 // still need to collect inner items.
111 ctx.lower_inner_items(e.syntax()) 111 ctx.lower_inner_items(e.syntax())
112 }, 112 },
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 },
113 _ => { 118 _ => {
114 panic!("cannot create item tree from {:?} {}", syntax, syntax); 119 panic!("cannot create item tree from {:?} {}", syntax, syntax);
115 }, 120 },
diff --git a/crates/hir_expand/src/db.rs b/crates/hir_expand/src/db.rs
index 9086e6c17..a3070f1f9 100644
--- a/crates/hir_expand/src/db.rs
+++ b/crates/hir_expand/src/db.rs
@@ -401,13 +401,14 @@ fn to_fragment_kind(db: &dyn AstDatabase, id: MacroCallId) -> FragmentKind {
401 401
402 match parent.kind() { 402 match parent.kind() {
403 MACRO_ITEMS | SOURCE_FILE => FragmentKind::Items, 403 MACRO_ITEMS | SOURCE_FILE => FragmentKind::Items,
404 MACRO_STMTS => FragmentKind::Statement,
404 ITEM_LIST => FragmentKind::Items, 405 ITEM_LIST => FragmentKind::Items,
405 LET_STMT => { 406 LET_STMT => {
406 // FIXME: Handle Pattern 407 // FIXME: Handle Pattern
407 FragmentKind::Expr 408 FragmentKind::Expr
408 } 409 }
409 EXPR_STMT => FragmentKind::Statements, 410 EXPR_STMT => FragmentKind::Statements,
410 BLOCK_EXPR => FragmentKind::Expr, 411 BLOCK_EXPR => FragmentKind::Statements,
411 ARG_LIST => FragmentKind::Expr, 412 ARG_LIST => FragmentKind::Expr,
412 TRY_EXPR => FragmentKind::Expr, 413 TRY_EXPR => FragmentKind::Expr,
413 TUPLE_EXPR => FragmentKind::Expr, 414 TUPLE_EXPR => FragmentKind::Expr,
diff --git a/crates/hir_ty/src/tests/macros.rs b/crates/hir_ty/src/tests/macros.rs
index fb3afaedc..af4f8bb11 100644
--- a/crates/hir_ty/src/tests/macros.rs
+++ b/crates/hir_ty/src/tests/macros.rs
@@ -216,6 +216,22 @@ fn expr_macro_expanded_in_various_places() {
216} 216}
217 217
218#[test] 218#[test]
219fn 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
234#[test]
219fn infer_type_value_macro_having_same_name() { 235fn infer_type_value_macro_having_same_name() {
220 check_infer( 236 check_infer(
221 r#" 237 r#"
diff --git a/crates/mbe/src/tests.rs b/crates/mbe/src/tests.rs
index 3a168bb4b..eca0bcc18 100644
--- a/crates/mbe/src/tests.rs
+++ b/crates/mbe/src/tests.rs
@@ -662,12 +662,11 @@ fn test_tt_to_stmts() {
662 [email protected] 662 [email protected]
663 [email protected] "1" 663 [email protected] "1"
664 [email protected] ";" 664 [email protected] ";"
665 [email protected] 665 [email protected]
666 [email protected] 666 [email protected]
667 [email protected] 667 [email protected]
668 [email protected] 668 [email protected]
669 [email protected] 669 [email protected] "a""#,
670 [email protected] "a""#,
671 ); 670 );
672} 671}
673 672
diff --git a/crates/parser/src/grammar.rs b/crates/parser/src/grammar.rs
index 6c0e22722..cebb8f400 100644
--- a/crates/parser/src/grammar.rs
+++ b/crates/parser/src/grammar.rs
@@ -63,11 +63,11 @@ pub(crate) mod fragments {
63 } 63 }
64 64
65 pub(crate) fn stmt(p: &mut Parser) { 65 pub(crate) fn stmt(p: &mut Parser) {
66 expressions::stmt(p, expressions::StmtWithSemi::No) 66 expressions::stmt(p, expressions::StmtWithSemi::No, true)
67 } 67 }
68 68
69 pub(crate) fn stmt_optional_semi(p: &mut Parser) { 69 pub(crate) fn stmt_optional_semi(p: &mut Parser) {
70 expressions::stmt(p, expressions::StmtWithSemi::Optional) 70 expressions::stmt(p, expressions::StmtWithSemi::Optional, false)
71 } 71 }
72 72
73 pub(crate) fn opt_visibility(p: &mut Parser) { 73 pub(crate) fn opt_visibility(p: &mut Parser) {
@@ -133,7 +133,7 @@ pub(crate) mod fragments {
133 continue; 133 continue;
134 } 134 }
135 135
136 expressions::stmt(p, expressions::StmtWithSemi::Optional); 136 expressions::stmt(p, expressions::StmtWithSemi::Optional, true);
137 } 137 }
138 138
139 m.complete(p, MACRO_STMTS); 139 m.complete(p, MACRO_STMTS);
diff --git a/crates/parser/src/grammar/expressions.rs b/crates/parser/src/grammar/expressions.rs
index 5f885edfd..0d9dc9348 100644
--- a/crates/parser/src/grammar/expressions.rs
+++ b/crates/parser/src/grammar/expressions.rs
@@ -54,7 +54,7 @@ fn is_expr_stmt_attr_allowed(kind: SyntaxKind) -> bool {
54 !forbid 54 !forbid
55} 55}
56 56
57pub(super) fn stmt(p: &mut Parser, with_semi: StmtWithSemi) { 57pub(super) fn stmt(p: &mut Parser, with_semi: StmtWithSemi, prefer_expr: bool) {
58 let m = p.start(); 58 let m = p.start();
59 // test attr_on_expr_stmt 59 // test attr_on_expr_stmt
60 // fn foo() { 60 // fn foo() {
@@ -90,7 +90,7 @@ pub(super) fn stmt(p: &mut Parser, with_semi: StmtWithSemi) {
90 p.error(format!("attributes are not allowed on {:?}", kind)); 90 p.error(format!("attributes are not allowed on {:?}", kind));
91 } 91 }
92 92
93 if p.at(T!['}']) { 93 if p.at(T!['}']) || (prefer_expr && p.at(EOF)) {
94 // test attr_on_last_expr_in_block 94 // test attr_on_last_expr_in_block
95 // fn foo() { 95 // fn foo() {
96 // { #[A] bar!()? } 96 // { #[A] bar!()? }
@@ -198,7 +198,7 @@ pub(super) fn expr_block_contents(p: &mut Parser) {
198 continue; 198 continue;
199 } 199 }
200 200
201 stmt(p, StmtWithSemi::Yes) 201 stmt(p, StmtWithSemi::Yes, false)
202 } 202 }
203} 203}
204 204
diff --git a/crates/syntax/src/ast/generated/nodes.rs b/crates/syntax/src/ast/generated/nodes.rs
index 064931aec..6097178b6 100644
--- a/crates/syntax/src/ast/generated/nodes.rs
+++ b/crates/syntax/src/ast/generated/nodes.rs
@@ -1336,6 +1336,7 @@ pub enum Expr {
1336 Literal(Literal), 1336 Literal(Literal),
1337 LoopExpr(LoopExpr), 1337 LoopExpr(LoopExpr),
1338 MacroCall(MacroCall), 1338 MacroCall(MacroCall),
1339 MacroStmts(MacroStmts),
1339 MatchExpr(MatchExpr), 1340 MatchExpr(MatchExpr),
1340 MethodCallExpr(MethodCallExpr), 1341 MethodCallExpr(MethodCallExpr),
1341 ParenExpr(ParenExpr), 1342 ParenExpr(ParenExpr),
@@ -3034,6 +3035,9 @@ impl From<LoopExpr> for Expr {
3034impl From<MacroCall> for Expr { 3035impl From<MacroCall> for Expr {
3035 fn from(node: MacroCall) -> Expr { Expr::MacroCall(node) } 3036 fn from(node: MacroCall) -> Expr { Expr::MacroCall(node) }
3036} 3037}
3038impl From<MacroStmts> for Expr {
3039 fn from(node: MacroStmts) -> Expr { Expr::MacroStmts(node) }
3040}
3037impl From<MatchExpr> for Expr { 3041impl From<MatchExpr> for Expr {
3038 fn from(node: MatchExpr) -> Expr { Expr::MatchExpr(node) } 3042 fn from(node: MatchExpr) -> Expr { Expr::MatchExpr(node) }
3039} 3043}
@@ -3078,8 +3082,8 @@ impl AstNode for Expr {
3078 match kind { 3082 match kind {
3079 ARRAY_EXPR | AWAIT_EXPR | BIN_EXPR | BLOCK_EXPR | BOX_EXPR | BREAK_EXPR | CALL_EXPR 3083 ARRAY_EXPR | AWAIT_EXPR | BIN_EXPR | BLOCK_EXPR | BOX_EXPR | BREAK_EXPR | CALL_EXPR
3080 | CAST_EXPR | CLOSURE_EXPR | CONTINUE_EXPR | EFFECT_EXPR | FIELD_EXPR | FOR_EXPR 3084 | CAST_EXPR | CLOSURE_EXPR | CONTINUE_EXPR | EFFECT_EXPR | FIELD_EXPR | FOR_EXPR
3081 | IF_EXPR | INDEX_EXPR | LITERAL | LOOP_EXPR | MACRO_CALL | MATCH_EXPR 3085 | IF_EXPR | INDEX_EXPR | LITERAL | LOOP_EXPR | MACRO_CALL | MACRO_STMTS
3082 | METHOD_CALL_EXPR | PAREN_EXPR | PATH_EXPR | PREFIX_EXPR | RANGE_EXPR 3086 | MATCH_EXPR | METHOD_CALL_EXPR | PAREN_EXPR | PATH_EXPR | PREFIX_EXPR | RANGE_EXPR
3083 | RECORD_EXPR | REF_EXPR | RETURN_EXPR | TRY_EXPR | TUPLE_EXPR | WHILE_EXPR 3087 | RECORD_EXPR | REF_EXPR | RETURN_EXPR | TRY_EXPR | TUPLE_EXPR | WHILE_EXPR
3084 | YIELD_EXPR => true, 3088 | YIELD_EXPR => true,
3085 _ => false, 3089 _ => false,
@@ -3105,6 +3109,7 @@ impl AstNode for Expr {
3105 LITERAL => Expr::Literal(Literal { syntax }), 3109 LITERAL => Expr::Literal(Literal { syntax }),
3106 LOOP_EXPR => Expr::LoopExpr(LoopExpr { syntax }), 3110 LOOP_EXPR => Expr::LoopExpr(LoopExpr { syntax }),
3107 MACRO_CALL => Expr::MacroCall(MacroCall { syntax }), 3111 MACRO_CALL => Expr::MacroCall(MacroCall { syntax }),
3112 MACRO_STMTS => Expr::MacroStmts(MacroStmts { syntax }),
3108 MATCH_EXPR => Expr::MatchExpr(MatchExpr { syntax }), 3113 MATCH_EXPR => Expr::MatchExpr(MatchExpr { syntax }),
3109 METHOD_CALL_EXPR => Expr::MethodCallExpr(MethodCallExpr { syntax }), 3114 METHOD_CALL_EXPR => Expr::MethodCallExpr(MethodCallExpr { syntax }),
3110 PAREN_EXPR => Expr::ParenExpr(ParenExpr { syntax }), 3115 PAREN_EXPR => Expr::ParenExpr(ParenExpr { syntax }),
@@ -3142,6 +3147,7 @@ impl AstNode for Expr {
3142 Expr::Literal(it) => &it.syntax, 3147 Expr::Literal(it) => &it.syntax,
3143 Expr::LoopExpr(it) => &it.syntax, 3148 Expr::LoopExpr(it) => &it.syntax,
3144 Expr::MacroCall(it) => &it.syntax, 3149 Expr::MacroCall(it) => &it.syntax,
3150 Expr::MacroStmts(it) => &it.syntax,
3145 Expr::MatchExpr(it) => &it.syntax, 3151 Expr::MatchExpr(it) => &it.syntax,
3146 Expr::MethodCallExpr(it) => &it.syntax, 3152 Expr::MethodCallExpr(it) => &it.syntax,
3147 Expr::ParenExpr(it) => &it.syntax, 3153 Expr::ParenExpr(it) => &it.syntax,
diff --git a/xtask/Cargo.toml b/xtask/Cargo.toml
index e084f0df6..ad93fbe3b 100644
--- a/xtask/Cargo.toml
+++ b/xtask/Cargo.toml
@@ -11,7 +11,7 @@ anyhow = "1.0.26"
11flate2 = "1.0" 11flate2 = "1.0"
12proc-macro2 = "1.0.8" 12proc-macro2 = "1.0.8"
13quote = "1.0.2" 13quote = "1.0.2"
14ungrammar = "=1.11" 14ungrammar = "=1.12"
15walkdir = "2.3.1" 15walkdir = "2.3.1"
16write-json = "0.1.0" 16write-json = "0.1.0"
17xshell = "0.1" 17xshell = "0.1"