From 8e736da4563871186a9b0feebfa8e4398e37f684 Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Mon, 6 Sep 2021 00:16:12 +0200 Subject: [PATCH] Recover from statement macro expansion errors --- crates/hir_def/src/body/lower.rs | 50 +++++++------------- crates/ide_completion/src/completions/dot.rs | 25 ++++++++++ 2 files changed, 43 insertions(+), 32 deletions(-) diff --git a/crates/hir_def/src/body/lower.rs b/crates/hir_def/src/body/lower.rs index d8dac66556b..759f2cc8657 100644 --- a/crates/hir_def/src/body/lower.rs +++ b/crates/hir_def/src/body/lower.rs @@ -558,7 +558,7 @@ impl ExprCollector<'_> { 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 @@ 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. @@ -620,18 +619,11 @@ impl ExprCollector<'_> { 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 @@ impl ExprCollector<'_> { 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 @@ impl ExprCollector<'_> { 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)); }); diff --git a/crates/ide_completion/src/completions/dot.rs b/crates/ide_completion/src/completions/dot.rs index fdd6e59ffe9..94a5ebabf9b 100644 --- a/crates/ide_completion/src/completions/dot.rs +++ b/crates/ide_completion/src/completions/dot.rs @@ -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) + "#]], + ); + } }