Skip to content

Commit eb7f969

Browse files
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]>
2 parents 75e037f + ea7b81f commit eb7f969

File tree

4 files changed

+88
-28
lines changed

4 files changed

+88
-28
lines changed

crates/hir_def/src/body.rs

Lines changed: 50 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,8 @@ use cfg::CfgOptions;
1414
use drop_bomb::DropBomb;
1515
use either::Either;
1616
use hir_expand::{
17-
ast_id_map::AstIdMap, diagnostics::DiagnosticSink, hygiene::Hygiene, AstId, HirFileId, InFile,
18-
MacroDefId,
17+
ast_id_map::AstIdMap, diagnostics::DiagnosticSink, hygiene::Hygiene, AstId, ExpandResult,
18+
HirFileId, InFile, MacroDefId,
1919
};
2020
use rustc_hash::FxHashMap;
2121
use syntax::{ast, AstNode, AstPtr};
@@ -102,11 +102,11 @@ impl Expander {
102102
db: &dyn DefDatabase,
103103
local_scope: Option<&ItemScope>,
104104
macro_call: ast::MacroCall,
105-
) -> Option<(Mark, T)> {
105+
) -> ExpandResult<Option<(Mark, T)>> {
106106
self.recursion_limit += 1;
107107
if self.recursion_limit > EXPANSION_RECURSION_LIMIT {
108108
mark::hit!(your_stack_belongs_to_me);
109-
return None;
109+
return ExpandResult::str_err("reached recursion limit during macro expansion".into());
110110
}
111111

112112
let macro_call = InFile::new(self.current_file_id, &macro_call);
@@ -120,28 +120,55 @@ impl Expander {
120120
self.resolve_path_as_macro(db, &path)
121121
};
122122

123-
if let Some(call_id) = macro_call.as_call_id(db, self.crate_def_map.krate, resolver) {
124-
let file_id = call_id.as_file();
125-
if let Some(node) = db.parse_or_expand(file_id) {
126-
if let Some(expr) = T::cast(node) {
127-
log::debug!("macro expansion {:#?}", expr.syntax());
128-
129-
let mark = Mark {
130-
file_id: self.current_file_id,
131-
ast_id_map: mem::take(&mut self.ast_id_map),
132-
bomb: DropBomb::new("expansion mark dropped"),
133-
};
134-
self.cfg_expander.hygiene = Hygiene::new(db.upcast(), file_id);
135-
self.current_file_id = file_id;
136-
self.ast_id_map = db.ast_id_map(file_id);
137-
return Some((mark, expr));
123+
let call_id = match macro_call.as_call_id(db, self.crate_def_map.krate, resolver) {
124+
Some(it) => it,
125+
None => {
126+
// FIXME: this can mean other things too, but `as_call_id` doesn't provide enough
127+
// info.
128+
return ExpandResult::only_err(mbe::ExpandError::Other(
129+
"failed to parse or resolve macro invocation".into(),
130+
));
131+
}
132+
};
133+
134+
let err = db.macro_expand_error(call_id);
135+
136+
let file_id = call_id.as_file();
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");
138144
}
145+
146+
return ExpandResult::only_err(err.unwrap_or_else(|| {
147+
mbe::ExpandError::Other("failed to parse macro invocation".into())
148+
}));
139149
}
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);
141170

142-
// FIXME: Instead of just dropping the error from expansion
143-
// report it
144-
None
171+
ExpandResult { value: Some((mark, node)), err }
145172
}
146173

147174
pub(crate) fn exit(&mut self, db: &dyn DefDatabase, mut mark: Mark) {

crates/hir_def/src/body/diagnostics.rs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,13 @@
22
33
use hir_expand::diagnostics::DiagnosticSink;
44

5-
use crate::diagnostics::InactiveCode;
5+
use crate::diagnostics::{InactiveCode, MacroError, UnresolvedProcMacro};
66

77
#[derive(Debug, Eq, PartialEq)]
88
pub(crate) enum BodyDiagnostic {
99
InactiveCode(InactiveCode),
10+
MacroError(MacroError),
11+
UnresolvedProcMacro(UnresolvedProcMacro),
1012
}
1113

1214
impl BodyDiagnostic {
@@ -15,6 +17,12 @@ impl BodyDiagnostic {
1517
BodyDiagnostic::InactiveCode(diag) => {
1618
sink.push(diag.clone());
1719
}
20+
BodyDiagnostic::MacroError(diag) => {
21+
sink.push(diag.clone());
22+
}
23+
BodyDiagnostic::UnresolvedProcMacro(diag) => {
24+
sink.push(diag.clone());
25+
}
1826
}
1927
}
2028
}

crates/hir_def/src/body/lower.rs

Lines changed: 28 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ use either::Either;
88
use hir_expand::{
99
hygiene::Hygiene,
1010
name::{name, AsName, Name},
11-
HirFileId, MacroDefId, MacroDefKind,
11+
ExpandError, HirFileId, MacroDefId, MacroDefKind,
1212
};
1313
use rustc_hash::FxHashMap;
1414
use syntax::{
@@ -25,7 +25,7 @@ use crate::{
2525
body::{Body, BodySourceMap, Expander, PatPtr, SyntheticSyntax},
2626
builtin_type::{BuiltinFloat, BuiltinInt},
2727
db::DefDatabase,
28-
diagnostics::InactiveCode,
28+
diagnostics::{InactiveCode, MacroError, UnresolvedProcMacro},
2929
expr::{
3030
dummy_expr_id, ArithOp, Array, BinaryOp, BindingAnnotation, CmpOp, Expr, ExprId, Literal,
3131
LogicOp, MatchArm, Ordering, Pat, PatId, RecordFieldPat, RecordLitField, Statement,
@@ -561,7 +561,32 @@ impl ExprCollector<'_> {
561561
self.alloc_expr(Expr::Missing, syntax_ptr)
562562
} else {
563563
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 {
565590
Some((mark, expansion)) => {
566591
self.source_map
567592
.expansions

crates/hir_def/src/data.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -257,7 +257,7 @@ fn collect_items(
257257
let root = db.parse_or_expand(file_id).unwrap();
258258
let call = ast_id_map.get(call.ast_id).to_node(&root);
259259

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 {
261261
let src: InFile<ast::MacroItems> = expander.to_source(mac);
262262
let item_tree = db.item_tree(src.file_id);
263263
let iter =

0 commit comments

Comments
 (0)