}
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()),
});
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)
+ }
+ }
}
}
&mut self,
e: ast::MacroCall,
syntax_ptr: AstPtr<ast::Expr>,
+ is_error_recoverable: bool,
mut collector: F,
) {
// File containing the macro call. Expansion errors will be attached here.
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 {
}
fn collect_stmt(&mut self, s: ast::Stmt) -> Option<Vec<Statement>> {
- 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)
}
Literal(Literal),
LoopExpr(LoopExpr),
MacroCall(MacroCall),
+ MacroStmts(MacroStmts),
MatchExpr(MatchExpr),
MethodCallExpr(MethodCallExpr),
ParenExpr(ParenExpr),
impl From<MacroCall> for Expr {
fn from(node: MacroCall) -> Expr { Expr::MacroCall(node) }
}
+impl From<MacroStmts> for Expr {
+ fn from(node: MacroStmts) -> Expr { Expr::MacroStmts(node) }
+}
impl From<MatchExpr> for Expr {
fn from(node: MatchExpr) -> Expr { Expr::MatchExpr(node) }
}
match kind {
ARRAY_EXPR | AWAIT_EXPR | BIN_EXPR | BLOCK_EXPR | BOX_EXPR | BREAK_EXPR | CALL_EXPR
| CAST_EXPR | CLOSURE_EXPR | CONTINUE_EXPR | EFFECT_EXPR | FIELD_EXPR | FOR_EXPR
- | IF_EXPR | INDEX_EXPR | LITERAL | LOOP_EXPR | MACRO_CALL | MATCH_EXPR
- | METHOD_CALL_EXPR | PAREN_EXPR | PATH_EXPR | PREFIX_EXPR | RANGE_EXPR
+ | IF_EXPR | INDEX_EXPR | LITERAL | LOOP_EXPR | MACRO_CALL | 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 => true,
_ => false,
LITERAL => Expr::Literal(Literal { syntax }),
LOOP_EXPR => Expr::LoopExpr(LoopExpr { syntax }),
MACRO_CALL => Expr::MacroCall(MacroCall { syntax }),
+ MACRO_STMTS => Expr::MacroStmts(MacroStmts { syntax }),
MATCH_EXPR => Expr::MatchExpr(MatchExpr { syntax }),
METHOD_CALL_EXPR => Expr::MethodCallExpr(MethodCallExpr { syntax }),
PAREN_EXPR => Expr::ParenExpr(ParenExpr { syntax }),
Expr::Literal(it) => &it.syntax,
Expr::LoopExpr(it) => &it.syntax,
Expr::MacroCall(it) => &it.syntax,
+ Expr::MacroStmts(it) => &it.syntax,
Expr::MatchExpr(it) => &it.syntax,
Expr::MethodCallExpr(it) => &it.syntax,
Expr::ParenExpr(it) => &it.syntax,