Recover from statement macro expansion errors

This commit is contained in:
Jonas Schievink 2021-09-06 00:16:12 +02:00
parent b73b321478
commit 8e736da456
2 changed files with 43 additions and 32 deletions

View File

@ -558,7 +558,7 @@ fn maybe_collect_expr(&mut self, expr: ast::Expr) -> Option<ExprId> {
ast::Expr::MacroCall(e) => {
let macro_ptr = AstPtr::new(&e);
let mut ids = vec![];
self.collect_macro_call(e, macro_ptr, true, |this, expansion| {
self.collect_macro_call(e, macro_ptr, |this, expansion| {
ids.push(match expansion {
Some(it) => this.collect_expr(it),
None => this.alloc_expr(Expr::Missing, syntax_ptr.clone()),
@ -582,7 +582,6 @@ fn collect_macro_call<F: FnMut(&mut Self, Option<T>), T: ast::AstNode>(
&mut self,
e: ast::MacroCall,
syntax_ptr: AstPtr<ast::MacroCall>,
is_error_recoverable: bool,
mut collector: F,
) {
// File containing the macro call. Expansion errors will be attached here.
@ -620,18 +619,11 @@ fn collect_macro_call<F: FnMut(&mut Self, Option<T>), T: ast::AstNode>(
match res.value {
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 !is_error_recoverable && res.err.is_some() {
self.expander.exit(self.db, mark);
collector(self, None);
} else {
self.source_map.expansions.insert(macro_call, self.expander.current_file_id);
self.source_map.expansions.insert(macro_call, self.expander.current_file_id);
let id = collector(self, Some(expansion));
self.expander.exit(self.db, mark);
id
}
let id = collector(self, Some(expansion));
self.expander.exit(self.db, mark);
id
}
None => collector(self, None),
}
@ -667,27 +659,21 @@ fn collect_stmt(&mut self, s: ast::Stmt) {
let macro_ptr = AstPtr::new(&m);
let syntax_ptr = AstPtr::new(&stmt.expr().unwrap());
self.collect_macro_call(
m,
macro_ptr,
false,
|this, expansion| match expansion {
Some(expansion) => {
let statements: ast::MacroStmts = expansion;
self.collect_macro_call(m, macro_ptr, |this, expansion| match expansion {
Some(expansion) => {
let statements: ast::MacroStmts = expansion;
statements.statements().for_each(|stmt| this.collect_stmt(stmt));
if let Some(expr) = statements.expr() {
let expr = this.collect_expr(expr);
this.statements_in_scope
.push(Statement::Expr { expr, has_semi });
}
}
None => {
let expr = this.alloc_expr(Expr::Missing, syntax_ptr.clone());
statements.statements().for_each(|stmt| this.collect_stmt(stmt));
if let Some(expr) = statements.expr() {
let expr = this.collect_expr(expr);
this.statements_in_scope.push(Statement::Expr { expr, has_semi });
}
},
);
}
None => {
let expr = this.alloc_expr(Expr::Missing, syntax_ptr.clone());
this.statements_in_scope.push(Statement::Expr { expr, has_semi });
}
});
} else {
let expr = self.collect_expr_opt(stmt.expr());
self.statements_in_scope.push(Statement::Expr { expr, has_semi });
@ -889,7 +875,7 @@ fn collect_pat(&mut self, pat: ast::Pat) -> PatId {
Some(call) => {
let macro_ptr = AstPtr::new(&call);
let mut pat = None;
self.collect_macro_call(call, macro_ptr, true, |this, expanded_pat| {
self.collect_macro_call(call, macro_ptr, |this, expanded_pat| {
pat = Some(this.collect_pat_opt(expanded_pat));
});

View File

@ -672,4 +672,29 @@ impl Foo { fn foo(&mut self) { $0 } }"#,
"#]],
);
}
#[test]
fn macro_completion_after_dot() {
check(
r#"
macro_rules! m {
($e:expr) => { $e };
}
struct Completable;
impl Completable {
fn method(&self) {}
}
fn f() {
let c = Completable;
m!(c.$0);
}
"#,
expect![[r#"
me method() fn(&self)
"#]],
);
}
}