From 8e07b23b84bff16c0decc6f2b80c27862eac6df1 Mon Sep 17 00:00:00 2001 From: Edwin Cheng Date: Tue, 16 Mar 2021 13:44:50 +0800 Subject: Fix macro expansion for statements w/o semicolon --- crates/hir_def/src/body/lower.rs | 105 +++++++++++++++++++++------------------ crates/hir_def/src/item_tree.rs | 5 ++ 2 files changed, 63 insertions(+), 47 deletions(-) (limited to 'crates/hir_def') 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<'_> { } ast::Expr::MacroCall(e) => { let mut ids = vec![]; - self.collect_macro_call(e, syntax_ptr.clone(), |this, expansion| { + self.collect_macro_call(e, syntax_ptr.clone(), true, |this, expansion| { ids.push(match expansion { Some(it) => this.collect_expr(it), None => this.alloc_expr(Expr::Missing, syntax_ptr.clone()), @@ -527,6 +527,17 @@ impl ExprCollector<'_> { }); ids[0] } + ast::Expr::MacroStmts(e) => { + // FIXME: these statements should be held by some hir containter + for stmt in e.statements() { + self.collect_stmt(stmt); + } + if let Some(expr) = e.expr() { + self.collect_expr(expr) + } else { + self.alloc_expr(Expr::Missing, syntax_ptr) + } + } } } @@ -534,6 +545,7 @@ impl ExprCollector<'_> { &mut self, e: ast::MacroCall, syntax_ptr: AstPtr, + is_error_recoverable: bool, mut collector: F, ) { // File containing the macro call. Expansion errors will be attached here. @@ -567,7 +579,7 @@ impl ExprCollector<'_> { Some((mark, expansion)) => { // FIXME: Statements are too complicated to recover from error for now. // It is because we don't have any hygiene for local variable expansion right now. - if T::can_cast(syntax::SyntaxKind::MACRO_STMTS) && res.err.is_some() { + if !is_error_recoverable && res.err.is_some() { self.expander.exit(self.db, mark); collector(self, None); } else { @@ -591,56 +603,55 @@ impl ExprCollector<'_> { } fn collect_stmt(&mut self, s: ast::Stmt) -> Option> { - let stmt = - match s { - ast::Stmt::LetStmt(stmt) => { - self.check_cfg(&stmt)?; - - let pat = self.collect_pat_opt(stmt.pat()); - let type_ref = stmt.ty().map(|it| TypeRef::from_ast(&self.ctx(), it)); - let initializer = stmt.initializer().map(|e| self.collect_expr(e)); - vec![Statement::Let { pat, type_ref, initializer }] - } - ast::Stmt::ExprStmt(stmt) => { - self.check_cfg(&stmt)?; - - // Note that macro could be expended to multiple statements - if let Some(ast::Expr::MacroCall(m)) = stmt.expr() { - let syntax_ptr = AstPtr::new(&stmt.expr().unwrap()); - let mut stmts = vec![]; - - self.collect_macro_call(m, syntax_ptr.clone(), |this, expansion| { - match expansion { - Some(expansion) => { - let statements: ast::MacroStmts = expansion; - - statements.statements().for_each(|stmt| { - if let Some(mut r) = this.collect_stmt(stmt) { - stmts.append(&mut r); - } - }); - if let Some(expr) = statements.expr() { - stmts.push(Statement::Expr(this.collect_expr(expr))); + let stmt = match s { + ast::Stmt::LetStmt(stmt) => { + self.check_cfg(&stmt)?; + + let pat = self.collect_pat_opt(stmt.pat()); + let type_ref = stmt.ty().map(|it| TypeRef::from_ast(&self.ctx(), it)); + let initializer = stmt.initializer().map(|e| self.collect_expr(e)); + vec![Statement::Let { pat, type_ref, initializer }] + } + ast::Stmt::ExprStmt(stmt) => { + self.check_cfg(&stmt)?; + + // Note that macro could be expended to multiple statements + if let Some(ast::Expr::MacroCall(m)) = stmt.expr() { + let syntax_ptr = AstPtr::new(&stmt.expr().unwrap()); + let mut stmts = vec![]; + + self.collect_macro_call(m, syntax_ptr.clone(), false, |this, expansion| { + match expansion { + Some(expansion) => { + let statements: ast::MacroStmts = expansion; + + statements.statements().for_each(|stmt| { + if let Some(mut r) = this.collect_stmt(stmt) { + stmts.append(&mut r); } - } - None => { - stmts.push(Statement::Expr( - this.alloc_expr(Expr::Missing, syntax_ptr.clone()), - )); + }); + if let Some(expr) = statements.expr() { + stmts.push(Statement::Expr(this.collect_expr(expr))); } } - }); - stmts - } else { - vec![Statement::Expr(self.collect_expr_opt(stmt.expr()))] - } + None => { + stmts.push(Statement::Expr( + this.alloc_expr(Expr::Missing, syntax_ptr.clone()), + )); + } + } + }); + stmts + } else { + vec![Statement::Expr(self.collect_expr_opt(stmt.expr()))] } - ast::Stmt::Item(item) => { - self.check_cfg(&item)?; + } + ast::Stmt::Item(item) => { + self.check_cfg(&item)?; - return None; - } - }; + return None; + } + }; Some(stmt) } 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 { // still need to collect inner items. ctx.lower_inner_items(e.syntax()) }, + ast::ExprStmt(stmt) => { + // Macros can expand to stmt. We return an empty item tree in this case, but + // still need to collect inner items. + ctx.lower_inner_items(stmt.syntax()) + }, _ => { panic!("cannot create item tree from {:?} {}", syntax, syntax); }, -- cgit v1.2.3