Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/hir-def/src/body/lower.rs')
-rw-r--r--crates/hir-def/src/body/lower.rs126
1 files changed, 69 insertions, 57 deletions
diff --git a/crates/hir-def/src/body/lower.rs b/crates/hir-def/src/body/lower.rs
index f6ec8bf7e9..cb6fdbfc56 100644
--- a/crates/hir-def/src/body/lower.rs
+++ b/crates/hir-def/src/body/lower.rs
@@ -550,20 +550,6 @@ impl ExprCollector<'_> {
None => self.alloc_expr(Expr::Missing, syntax_ptr),
}
}
- ast::Expr::MacroStmts(e) => {
- let statements: Box<[_]> =
- e.statements().filter_map(|s| self.collect_stmt(s)).collect();
- let tail = e.expr().map(|e| self.collect_expr(e));
-
- if e.syntax().children().next().is_none() {
- // HACK: make sure that macros that expand to nothing aren't treated as a `()`
- // expression when used in block tail position.
- cov_mark::hit!(empty_macro_in_trailing_position_is_removed);
- return None;
- }
-
- self.alloc_expr(Expr::MacroStmts { tail, statements }, syntax_ptr)
- }
ast::Expr::UnderscoreExpr(_) => self.alloc_expr(Expr::Underscore, syntax_ptr),
})
}
@@ -640,7 +626,58 @@ impl ExprCollector<'_> {
}
}
- fn collect_stmt(&mut self, s: ast::Stmt) -> Option<Statement> {
+ fn collect_macro_as_stmt(
+ &mut self,
+ mac: ast::MacroExpr,
+ ) -> Option<(Vec<Statement>, Option<ExprId>)> {
+ let mac_call = mac.macro_call()?;
+ let syntax_ptr = AstPtr::new(&ast::Expr::from(mac));
+ let macro_ptr = AstPtr::new(&mac_call);
+ let expansion = self.collect_macro_call(
+ mac_call,
+ macro_ptr,
+ false,
+ |this, expansion: Option<ast::MacroStmts>| match expansion {
+ Some(expansion) => {
+ let mut statements: Vec<_> = expansion
+ .statements()
+ .filter_map(|stmt| this.collect_stmt(stmt))
+ .flatten()
+ .collect();
+ let tail = expansion.expr().and_then(|expr| match expr {
+ ast::Expr::MacroExpr(mac) => {
+ let (stmts, tail) = this.collect_macro_as_stmt(mac)?;
+ statements.extend(stmts);
+ tail
+ }
+ expr => Some(this.collect_expr(expr)),
+ });
+ Some((statements, tail))
+ }
+ None => None,
+ },
+ );
+ let mut stmts = Vec::new();
+ let expr = match expansion {
+ Some((statements, tail)) => {
+ stmts.extend(statements);
+ // Make the macro-call point to its expanded expression so we can query
+ // semantics on syntax pointers to the macro
+ let src = self.expander.to_source(syntax_ptr);
+ match tail {
+ Some(tail) => {
+ self.source_map.expr_map.insert(src, tail);
+ tail
+ }
+ None => self.make_expr(Expr::Missing, Ok(src.clone())),
+ }
+ }
+ None => self.alloc_expr(Expr::Missing, syntax_ptr),
+ };
+ Some((stmts, Some(expr)))
+ }
+
+ fn collect_stmt(&mut self, s: ast::Stmt) -> Option<Vec<Statement>> {
match s {
ast::Stmt::LetStmt(stmt) => {
if self.check_cfg(&stmt).is_none() {
@@ -654,7 +691,7 @@ impl ExprCollector<'_> {
.let_else()
.and_then(|let_else| let_else.block_expr())
.map(|block| self.collect_block(block));
- Some(Statement::Let { pat, type_ref, initializer, else_branch })
+ Some(vec![Statement::Let { pat, type_ref, initializer, else_branch }])
}
ast::Stmt::ExprStmt(stmt) => {
let expr = stmt.expr();
@@ -665,47 +702,15 @@ impl ExprCollector<'_> {
}
let has_semi = stmt.semicolon_token().is_some();
// Note that macro could be expanded to multiple statements
- if let Some(expr @ ast::Expr::MacroExpr(mac)) = &expr {
- let mac_call = mac.macro_call()?;
- let syntax_ptr = AstPtr::new(expr);
- let macro_ptr = AstPtr::new(&mac_call);
- let stmt = self.collect_macro_call(
- mac_call,
- macro_ptr,
- false,
- |this, expansion: Option<ast::MacroStmts>| match expansion {
- Some(expansion) => {
- let statements = expansion
- .statements()
- .filter_map(|stmt| this.collect_stmt(stmt))
- .collect();
- let tail = expansion.expr().map(|expr| this.collect_expr(expr));
-
- let mac_stmts = this.alloc_expr(
- Expr::MacroStmts { tail, statements },
- AstPtr::new(&ast::Expr::MacroStmts(expansion)),
- );
-
- Some(mac_stmts)
- }
- None => None,
- },
- );
-
- let expr = match stmt {
- Some(expr) => {
- // Make the macro-call point to its expanded expression so we can query
- // semantics on syntax pointers to the macro
- let src = self.expander.to_source(syntax_ptr);
- self.source_map.expr_map.insert(src, expr);
- expr
- }
- None => self.alloc_expr(Expr::Missing, syntax_ptr),
- };
- Some(Statement::Expr { expr, has_semi })
+ if let Some(ast::Expr::MacroExpr(mac)) = expr {
+ let (mut statements, tail) = self.collect_macro_as_stmt(mac)?;
+ if let Some(expr) = tail {
+ statements.push(Statement::Expr { expr, has_semi });
+ }
+ Some(statements)
} else {
let expr = self.collect_expr_opt(expr);
- Some(Statement::Expr { expr, has_semi })
+ Some(vec![Statement::Expr { expr, has_semi }])
}
}
ast::Stmt::Item(_item) => None,
@@ -730,8 +735,15 @@ impl ExprCollector<'_> {
let prev_local_module = mem::replace(&mut self.expander.module, module);
let mut statements: Vec<_> =
- block.statements().filter_map(|s| self.collect_stmt(s)).collect();
- let tail = block.tail_expr().and_then(|e| self.maybe_collect_expr(e));
+ block.statements().filter_map(|s| self.collect_stmt(s)).flatten().collect();
+ let tail = block.tail_expr().and_then(|e| match e {
+ ast::Expr::MacroExpr(mac) => {
+ let (stmts, tail) = self.collect_macro_as_stmt(mac)?;
+ statements.extend(stmts);
+ tail
+ }
+ expr => self.maybe_collect_expr(expr),
+ });
let tail = tail.or_else(|| {
let stmt = statements.pop()?;
if let Statement::Expr { expr, has_semi: false } = stmt {