diff options
author | bors[bot] <26634292+bors[bot]@users.noreply.github.com> | 2020-12-01 12:27:52 +0000 |
---|---|---|
committer | GitHub <[email protected]> | 2020-12-01 12:27:52 +0000 |
commit | eb7f96951068bd8f8672a8234aa55b2a69d912b0 (patch) | |
tree | 30e949b7972420131a4367369c38b3bf2c5f66fa /crates/hir_def/src | |
parent | 75e037fcf75691a3a87d0cb37ea660dd7105ffba (diff) | |
parent | ea7b81fef990e281b4b958cff7357544076d4b15 (diff) |
Merge #6683
6683: Emit macro diagnostics when lowering bodies r=matklad a=jonas-schievink
Changes `Expander::enter_expand` to return an `ExpandResult`, and adds any contained errors to the body diagnostic list.
Co-authored-by: Jonas Schievink <[email protected]>
Diffstat (limited to 'crates/hir_def/src')
-rw-r--r-- | crates/hir_def/src/body.rs | 73 | ||||
-rw-r--r-- | crates/hir_def/src/body/diagnostics.rs | 10 | ||||
-rw-r--r-- | crates/hir_def/src/body/lower.rs | 31 | ||||
-rw-r--r-- | crates/hir_def/src/data.rs | 2 |
4 files changed, 88 insertions, 28 deletions
diff --git a/crates/hir_def/src/body.rs b/crates/hir_def/src/body.rs index d10b1af01..33eb5e78c 100644 --- a/crates/hir_def/src/body.rs +++ b/crates/hir_def/src/body.rs | |||
@@ -14,8 +14,8 @@ use cfg::CfgOptions; | |||
14 | use drop_bomb::DropBomb; | 14 | use drop_bomb::DropBomb; |
15 | use either::Either; | 15 | use either::Either; |
16 | use hir_expand::{ | 16 | use hir_expand::{ |
17 | ast_id_map::AstIdMap, diagnostics::DiagnosticSink, hygiene::Hygiene, AstId, HirFileId, InFile, | 17 | ast_id_map::AstIdMap, diagnostics::DiagnosticSink, hygiene::Hygiene, AstId, ExpandResult, |
18 | MacroDefId, | 18 | HirFileId, InFile, MacroDefId, |
19 | }; | 19 | }; |
20 | use rustc_hash::FxHashMap; | 20 | use rustc_hash::FxHashMap; |
21 | use syntax::{ast, AstNode, AstPtr}; | 21 | use syntax::{ast, AstNode, AstPtr}; |
@@ -102,11 +102,11 @@ impl Expander { | |||
102 | db: &dyn DefDatabase, | 102 | db: &dyn DefDatabase, |
103 | local_scope: Option<&ItemScope>, | 103 | local_scope: Option<&ItemScope>, |
104 | macro_call: ast::MacroCall, | 104 | macro_call: ast::MacroCall, |
105 | ) -> Option<(Mark, T)> { | 105 | ) -> ExpandResult<Option<(Mark, T)>> { |
106 | self.recursion_limit += 1; | 106 | self.recursion_limit += 1; |
107 | if self.recursion_limit > EXPANSION_RECURSION_LIMIT { | 107 | if self.recursion_limit > EXPANSION_RECURSION_LIMIT { |
108 | mark::hit!(your_stack_belongs_to_me); | 108 | mark::hit!(your_stack_belongs_to_me); |
109 | return None; | 109 | return ExpandResult::str_err("reached recursion limit during macro expansion".into()); |
110 | } | 110 | } |
111 | 111 | ||
112 | let macro_call = InFile::new(self.current_file_id, ¯o_call); | 112 | let macro_call = InFile::new(self.current_file_id, ¯o_call); |
@@ -120,28 +120,55 @@ impl Expander { | |||
120 | self.resolve_path_as_macro(db, &path) | 120 | self.resolve_path_as_macro(db, &path) |
121 | }; | 121 | }; |
122 | 122 | ||
123 | if let Some(call_id) = macro_call.as_call_id(db, self.crate_def_map.krate, resolver) { | 123 | let call_id = match macro_call.as_call_id(db, self.crate_def_map.krate, resolver) { |
124 | let file_id = call_id.as_file(); | 124 | Some(it) => it, |
125 | if let Some(node) = db.parse_or_expand(file_id) { | 125 | None => { |
126 | if let Some(expr) = T::cast(node) { | 126 | // FIXME: this can mean other things too, but `as_call_id` doesn't provide enough |
127 | log::debug!("macro expansion {:#?}", expr.syntax()); | 127 | // info. |
128 | 128 | return ExpandResult::only_err(mbe::ExpandError::Other( | |
129 | let mark = Mark { | 129 | "failed to parse or resolve macro invocation".into(), |
130 | file_id: self.current_file_id, | 130 | )); |
131 | ast_id_map: mem::take(&mut self.ast_id_map), | 131 | } |
132 | bomb: DropBomb::new("expansion mark dropped"), | 132 | }; |
133 | }; | 133 | |
134 | self.cfg_expander.hygiene = Hygiene::new(db.upcast(), file_id); | 134 | let err = db.macro_expand_error(call_id); |
135 | self.current_file_id = file_id; | 135 | |
136 | self.ast_id_map = db.ast_id_map(file_id); | 136 | let file_id = call_id.as_file(); |
137 | return Some((mark, expr)); | 137 | |
138 | let raw_node = match db.parse_or_expand(file_id) { | ||
139 | Some(it) => it, | ||
140 | None => { | ||
141 | // Only `None` if the macro expansion produced no usable AST. | ||
142 | if err.is_none() { | ||
143 | log::warn!("no error despite `parse_or_expand` failing"); | ||
138 | } | 144 | } |
145 | |||
146 | return ExpandResult::only_err(err.unwrap_or_else(|| { | ||
147 | mbe::ExpandError::Other("failed to parse macro invocation".into()) | ||
148 | })); | ||
139 | } | 149 | } |
140 | } | 150 | }; |
151 | |||
152 | let node = match T::cast(raw_node) { | ||
153 | Some(it) => it, | ||
154 | None => { | ||
155 | // This can happen without being an error, so only forward previous errors. | ||
156 | return ExpandResult { value: None, err }; | ||
157 | } | ||
158 | }; | ||
159 | |||
160 | log::debug!("macro expansion {:#?}", node.syntax()); | ||
161 | |||
162 | let mark = Mark { | ||
163 | file_id: self.current_file_id, | ||
164 | ast_id_map: mem::take(&mut self.ast_id_map), | ||
165 | bomb: DropBomb::new("expansion mark dropped"), | ||
166 | }; | ||
167 | self.cfg_expander.hygiene = Hygiene::new(db.upcast(), file_id); | ||
168 | self.current_file_id = file_id; | ||
169 | self.ast_id_map = db.ast_id_map(file_id); | ||
141 | 170 | ||
142 | // FIXME: Instead of just dropping the error from expansion | 171 | ExpandResult { value: Some((mark, node)), err } |
143 | // report it | ||
144 | None | ||
145 | } | 172 | } |
146 | 173 | ||
147 | pub(crate) fn exit(&mut self, db: &dyn DefDatabase, mut mark: Mark) { | 174 | pub(crate) fn exit(&mut self, db: &dyn DefDatabase, mut mark: Mark) { |
diff --git a/crates/hir_def/src/body/diagnostics.rs b/crates/hir_def/src/body/diagnostics.rs index e57bdc133..1de7d30e2 100644 --- a/crates/hir_def/src/body/diagnostics.rs +++ b/crates/hir_def/src/body/diagnostics.rs | |||
@@ -2,11 +2,13 @@ | |||
2 | 2 | ||
3 | use hir_expand::diagnostics::DiagnosticSink; | 3 | use hir_expand::diagnostics::DiagnosticSink; |
4 | 4 | ||
5 | use crate::diagnostics::InactiveCode; | 5 | use crate::diagnostics::{InactiveCode, MacroError, UnresolvedProcMacro}; |
6 | 6 | ||
7 | #[derive(Debug, Eq, PartialEq)] | 7 | #[derive(Debug, Eq, PartialEq)] |
8 | pub(crate) enum BodyDiagnostic { | 8 | pub(crate) enum BodyDiagnostic { |
9 | InactiveCode(InactiveCode), | 9 | InactiveCode(InactiveCode), |
10 | MacroError(MacroError), | ||
11 | UnresolvedProcMacro(UnresolvedProcMacro), | ||
10 | } | 12 | } |
11 | 13 | ||
12 | impl BodyDiagnostic { | 14 | impl BodyDiagnostic { |
@@ -15,6 +17,12 @@ impl BodyDiagnostic { | |||
15 | BodyDiagnostic::InactiveCode(diag) => { | 17 | BodyDiagnostic::InactiveCode(diag) => { |
16 | sink.push(diag.clone()); | 18 | sink.push(diag.clone()); |
17 | } | 19 | } |
20 | BodyDiagnostic::MacroError(diag) => { | ||
21 | sink.push(diag.clone()); | ||
22 | } | ||
23 | BodyDiagnostic::UnresolvedProcMacro(diag) => { | ||
24 | sink.push(diag.clone()); | ||
25 | } | ||
18 | } | 26 | } |
19 | } | 27 | } |
20 | } | 28 | } |
diff --git a/crates/hir_def/src/body/lower.rs b/crates/hir_def/src/body/lower.rs index cd7958746..2c41c0005 100644 --- a/crates/hir_def/src/body/lower.rs +++ b/crates/hir_def/src/body/lower.rs | |||
@@ -8,7 +8,7 @@ use either::Either; | |||
8 | use hir_expand::{ | 8 | use hir_expand::{ |
9 | hygiene::Hygiene, | 9 | hygiene::Hygiene, |
10 | name::{name, AsName, Name}, | 10 | name::{name, AsName, Name}, |
11 | HirFileId, MacroDefId, MacroDefKind, | 11 | ExpandError, HirFileId, MacroDefId, MacroDefKind, |
12 | }; | 12 | }; |
13 | use rustc_hash::FxHashMap; | 13 | use rustc_hash::FxHashMap; |
14 | use syntax::{ | 14 | use syntax::{ |
@@ -25,7 +25,7 @@ use crate::{ | |||
25 | body::{Body, BodySourceMap, Expander, PatPtr, SyntheticSyntax}, | 25 | body::{Body, BodySourceMap, Expander, PatPtr, SyntheticSyntax}, |
26 | builtin_type::{BuiltinFloat, BuiltinInt}, | 26 | builtin_type::{BuiltinFloat, BuiltinInt}, |
27 | db::DefDatabase, | 27 | db::DefDatabase, |
28 | diagnostics::InactiveCode, | 28 | diagnostics::{InactiveCode, MacroError, UnresolvedProcMacro}, |
29 | expr::{ | 29 | expr::{ |
30 | dummy_expr_id, ArithOp, Array, BinaryOp, BindingAnnotation, CmpOp, Expr, ExprId, Literal, | 30 | dummy_expr_id, ArithOp, Array, BinaryOp, BindingAnnotation, CmpOp, Expr, ExprId, Literal, |
31 | LogicOp, MatchArm, Ordering, Pat, PatId, RecordFieldPat, RecordLitField, Statement, | 31 | LogicOp, MatchArm, Ordering, Pat, PatId, RecordFieldPat, RecordLitField, Statement, |
@@ -561,7 +561,32 @@ impl ExprCollector<'_> { | |||
561 | self.alloc_expr(Expr::Missing, syntax_ptr) | 561 | self.alloc_expr(Expr::Missing, syntax_ptr) |
562 | } else { | 562 | } else { |
563 | let macro_call = self.expander.to_source(AstPtr::new(&e)); | 563 | let macro_call = self.expander.to_source(AstPtr::new(&e)); |
564 | match self.expander.enter_expand(self.db, Some(&self.body.item_scope), e) { | 564 | let res = self.expander.enter_expand(self.db, Some(&self.body.item_scope), e); |
565 | |||
566 | match res.err { | ||
567 | Some(ExpandError::UnresolvedProcMacro) => { | ||
568 | self.source_map.diagnostics.push(BodyDiagnostic::UnresolvedProcMacro( | ||
569 | UnresolvedProcMacro { | ||
570 | file: self.expander.current_file_id, | ||
571 | node: syntax_ptr.clone().into(), | ||
572 | precise_location: None, | ||
573 | macro_name: None, | ||
574 | }, | ||
575 | )); | ||
576 | } | ||
577 | Some(err) => { | ||
578 | self.source_map.diagnostics.push(BodyDiagnostic::MacroError( | ||
579 | MacroError { | ||
580 | file: self.expander.current_file_id, | ||
581 | node: syntax_ptr.clone().into(), | ||
582 | message: err.to_string(), | ||
583 | }, | ||
584 | )); | ||
585 | } | ||
586 | None => {} | ||
587 | } | ||
588 | |||
589 | match res.value { | ||
565 | Some((mark, expansion)) => { | 590 | Some((mark, expansion)) => { |
566 | self.source_map | 591 | self.source_map |
567 | .expansions | 592 | .expansions |
diff --git a/crates/hir_def/src/data.rs b/crates/hir_def/src/data.rs index ff1ef0df6..146045938 100644 --- a/crates/hir_def/src/data.rs +++ b/crates/hir_def/src/data.rs | |||
@@ -257,7 +257,7 @@ fn collect_items( | |||
257 | let root = db.parse_or_expand(file_id).unwrap(); | 257 | let root = db.parse_or_expand(file_id).unwrap(); |
258 | let call = ast_id_map.get(call.ast_id).to_node(&root); | 258 | let call = ast_id_map.get(call.ast_id).to_node(&root); |
259 | 259 | ||
260 | if let Some((mark, mac)) = expander.enter_expand(db, None, call) { | 260 | if let Some((mark, mac)) = expander.enter_expand(db, None, call).value { |
261 | let src: InFile<ast::MacroItems> = expander.to_source(mac); | 261 | let src: InFile<ast::MacroItems> = expander.to_source(mac); |
262 | let item_tree = db.item_tree(src.file_id); | 262 | let item_tree = db.item_tree(src.file_id); |
263 | let iter = | 263 | let iter = |