Skip to content
This repository was archived by the owner on May 28, 2025. It is now read-only.

Commit a5558cd

Browse files
committed
internal: Report macro definition errors on the definition
1 parent 0bb9a17 commit a5558cd

File tree

10 files changed

+115
-14
lines changed

10 files changed

+115
-14
lines changed

crates/hir-def/src/body.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -190,8 +190,9 @@ impl Expander {
190190

191191
let file_id = call_id.as_file();
192192

193-
let raw_node = match db.parse_or_expand(file_id) {
194-
Some(it) => it,
193+
let raw_node = match db.parse_or_expand_with_err(file_id) {
194+
// FIXME: report parse errors
195+
Some(it) => it.syntax_node(),
195196
None => {
196197
// Only `None` if the macro expansion produced no usable AST.
197198
if err.is_none() {

crates/hir-def/src/data.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -641,7 +641,12 @@ impl<'a> AssocItemCollector<'a> {
641641
self.items.push((item.name.clone(), def.into()));
642642
}
643643
AssocItem::MacroCall(call) => {
644-
if let Some(root) = self.db.parse_or_expand(self.expander.current_file_id()) {
644+
if let Some(root) =
645+
self.db.parse_or_expand_with_err(self.expander.current_file_id())
646+
{
647+
// FIXME: report parse errors
648+
let root = root.syntax_node();
649+
645650
let call = &item_tree[call];
646651

647652
let ast_id_map = self.db.ast_id_map(self.expander.current_file_id());

crates/hir-def/src/nameres/collector.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1374,6 +1374,8 @@ impl DefCollector<'_> {
13741374

13751375
// Then, fetch and process the item tree. This will reuse the expansion result from above.
13761376
let item_tree = self.db.file_item_tree(file_id);
1377+
// FIXME: report parse errors for the macro expansion here
1378+
13771379
let mod_dir = self.mod_dirs[&module_id].clone();
13781380
ModCollector {
13791381
def_collector: &mut *self,

crates/hir-def/src/nameres/diagnostics.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@ pub enum DefDiagnosticKind {
3434
InvalidDeriveTarget { ast: AstId<ast::Item>, id: usize },
3535

3636
MalformedDerive { ast: AstId<ast::Adt>, id: usize },
37+
38+
MacroDefError { ast: AstId<ast::Macro>, message: String },
3739
}
3840

3941
#[derive(Debug, PartialEq, Eq)]

crates/hir-expand/src/db.rs

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,8 @@ pub trait ExpandDatabase: SourceDatabase {
9999
/// file or a macro expansion.
100100
#[salsa::transparent]
101101
fn parse_or_expand(&self, file_id: HirFileId) -> Option<SyntaxNode>;
102+
#[salsa::transparent]
103+
fn parse_or_expand_with_err(&self, file_id: HirFileId) -> Option<Parse<SyntaxNode>>;
102104
/// Implementation for the macro case.
103105
fn parse_macro_expansion(
104106
&self,
@@ -252,13 +254,23 @@ fn parse_or_expand(db: &dyn ExpandDatabase, file_id: HirFileId) -> Option<Syntax
252254
match file_id.repr() {
253255
HirFileIdRepr::FileId(file_id) => Some(db.parse(file_id).tree().syntax().clone()),
254256
HirFileIdRepr::MacroFile(macro_file) => {
255-
// FIXME: Note how we convert from `Parse` to `SyntaxNode` here,
256-
// forgetting about parse errors.
257257
db.parse_macro_expansion(macro_file).value.map(|(it, _)| it.syntax_node())
258258
}
259259
}
260260
}
261261

262+
fn parse_or_expand_with_err(
263+
db: &dyn ExpandDatabase,
264+
file_id: HirFileId,
265+
) -> Option<Parse<SyntaxNode>> {
266+
match file_id.repr() {
267+
HirFileIdRepr::FileId(file_id) => Some(db.parse(file_id).to_syntax()),
268+
HirFileIdRepr::MacroFile(macro_file) => {
269+
db.parse_macro_expansion(macro_file).value.map(|(parse, _)| parse)
270+
}
271+
}
272+
}
273+
262274
fn parse_macro_expansion(
263275
db: &dyn ExpandDatabase,
264276
macro_file: MacroFile,

crates/hir-expand/src/eager.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -187,7 +187,10 @@ fn lazy_expand(
187187
);
188188

189189
let err = db.macro_expand_error(id);
190-
let value = db.parse_or_expand(id.as_file()).map(|node| InFile::new(id.as_file(), node));
190+
let value =
191+
db.parse_or_expand_with_err(id.as_file()).map(|node| InFile::new(id.as_file(), node));
192+
// FIXME: report parse errors
193+
let value = value.map(|it| it.map(|it| it.syntax_node()));
191194

192195
ExpandResult { value, err }
193196
}

crates/hir/src/diagnostics.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ diagnostics![
3939
InvalidDeriveTarget,
4040
IncoherentImpl,
4141
MacroError,
42+
MacroDefError,
4243
MalformedDerive,
4344
MismatchedArgCount,
4445
MissingFields,
@@ -131,6 +132,13 @@ pub struct MacroError {
131132
pub message: String,
132133
}
133134

135+
#[derive(Debug, Clone, Eq, PartialEq)]
136+
pub struct MacroDefError {
137+
pub node: InFile<AstPtr<ast::Macro>>,
138+
pub message: String,
139+
pub name: Option<TextRange>,
140+
}
141+
134142
#[derive(Debug)]
135143
pub struct UnimplementedBuiltinMacro {
136144
pub node: InFile<SyntaxNodePtr>,

crates/hir/src/lib.rs

Lines changed: 45 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ use hir_def::{
4646
item_tree::ItemTreeNode,
4747
lang_item::{LangItem, LangItemTarget},
4848
layout::ReprOptions,
49+
macro_id_to_def_id,
4950
nameres::{self, diagnostics::DefDiagnostic, ModuleOrigin},
5051
per_ns::PerNs,
5152
resolver::{HasResolver, Resolver},
@@ -86,12 +87,12 @@ pub use crate::{
8687
attrs::{HasAttrs, Namespace},
8788
diagnostics::{
8889
AnyDiagnostic, BreakOutsideOfLoop, ExpectedFunction, InactiveCode, IncoherentImpl,
89-
IncorrectCase, InvalidDeriveTarget, MacroError, MalformedDerive, MismatchedArgCount,
90-
MissingFields, MissingMatchArms, MissingUnsafe, NeedMut, NoSuchField, PrivateAssocItem,
91-
PrivateField, ReplaceFilterMapNextWithFindMap, TypeMismatch, UndeclaredLabel,
92-
UnimplementedBuiltinMacro, UnreachableLabel, UnresolvedExternCrate, UnresolvedField,
93-
UnresolvedImport, UnresolvedMacroCall, UnresolvedMethodCall, UnresolvedModule,
94-
UnresolvedProcMacro, UnusedMut,
90+
IncorrectCase, InvalidDeriveTarget, MacroDefError, MacroError, MalformedDerive,
91+
MismatchedArgCount, MissingFields, MissingMatchArms, MissingUnsafe, NeedMut, NoSuchField,
92+
PrivateAssocItem, PrivateField, ReplaceFilterMapNextWithFindMap, TypeMismatch,
93+
UndeclaredLabel, UnimplementedBuiltinMacro, UnreachableLabel, UnresolvedExternCrate,
94+
UnresolvedField, UnresolvedImport, UnresolvedMacroCall, UnresolvedMethodCall,
95+
UnresolvedModule, UnresolvedProcMacro, UnusedMut,
9596
},
9697
has_source::HasSource,
9798
semantics::{PathResolution, Semantics, SemanticsScope, TypeInfo, VisibleTraits},
@@ -563,6 +564,7 @@ impl Module {
563564
}
564565
emit_def_diagnostic(db, acc, diag);
565566
}
567+
566568
for decl in self.declarations(db) {
567569
match decl {
568570
ModuleDef::Module(m) => {
@@ -601,9 +603,11 @@ impl Module {
601603
}
602604
acc.extend(decl.diagnostics(db))
603605
}
606+
ModuleDef::Macro(m) => emit_macro_def_diagnostics(db, acc, m),
604607
_ => acc.extend(decl.diagnostics(db)),
605608
}
606609
}
610+
self.legacy_macros(db).into_iter().for_each(|m| emit_macro_def_diagnostics(db, acc, m));
607611

608612
let inherent_impls = db.inherent_impls_in_crate(self.id.krate());
609613

@@ -685,8 +689,31 @@ impl Module {
685689
}
686690
}
687691

692+
fn emit_macro_def_diagnostics(db: &dyn HirDatabase, acc: &mut Vec<AnyDiagnostic>, m: Macro) {
693+
let id = macro_id_to_def_id(db.upcast(), m.id);
694+
if let Err(e) = db.macro_def(id) {
695+
let Some(ast) = id.ast_id().left() else {
696+
never!("MacroDefError for proc-macro: {:?}", e);
697+
return;
698+
};
699+
emit_def_diagnostic_(
700+
db,
701+
acc,
702+
&DefDiagnosticKind::MacroDefError { ast, message: e.to_string() },
703+
);
704+
}
705+
}
706+
688707
fn emit_def_diagnostic(db: &dyn HirDatabase, acc: &mut Vec<AnyDiagnostic>, diag: &DefDiagnostic) {
689-
match &diag.kind {
708+
emit_def_diagnostic_(db, acc, &diag.kind)
709+
}
710+
711+
fn emit_def_diagnostic_(
712+
db: &dyn HirDatabase,
713+
acc: &mut Vec<AnyDiagnostic>,
714+
diag: &DefDiagnosticKind,
715+
) {
716+
match diag {
690717
DefDiagnosticKind::UnresolvedModule { ast: declaration, candidates } => {
691718
let decl = declaration.to_node(db.upcast());
692719
acc.push(
@@ -794,6 +821,17 @@ fn emit_def_diagnostic(db: &dyn HirDatabase, acc: &mut Vec<AnyDiagnostic>, diag:
794821
None => stdx::never!("derive diagnostic on item without derive attribute"),
795822
}
796823
}
824+
DefDiagnosticKind::MacroDefError { ast, message } => {
825+
let node = ast.to_node(db.upcast());
826+
acc.push(
827+
MacroDefError {
828+
node: InFile::new(ast.file_id, AstPtr::new(&node)),
829+
name: node.name().map(|it| it.syntax().text_range()),
830+
message: message.clone(),
831+
}
832+
.into(),
833+
);
834+
}
797835
}
798836
}
799837

crates/ide-diagnostics/src/handlers/macro_error.rs

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,16 @@ pub(crate) fn macro_error(ctx: &DiagnosticsContext<'_>, d: &hir::MacroError) ->
99
Diagnostic::new("macro-error", d.message.clone(), display_range).experimental()
1010
}
1111

12+
// Diagnostic: macro-error
13+
//
14+
// This diagnostic is shown for macro expansion errors.
15+
pub(crate) fn macro_def_error(ctx: &DiagnosticsContext<'_>, d: &hir::MacroDefError) -> Diagnostic {
16+
// Use more accurate position if available.
17+
let display_range =
18+
ctx.resolve_precise_location(&d.node.clone().map(|it| it.syntax_node_ptr()), d.name);
19+
Diagnostic::new("macro-def-error", d.message.clone(), display_range).experimental()
20+
}
21+
1222
#[cfg(test)]
1323
mod tests {
1424
use crate::{
@@ -188,6 +198,7 @@ fn f() {
188198
"#,
189199
);
190200
}
201+
191202
#[test]
192203
fn dollar_crate_in_builtin_macro() {
193204
check_diagnostics(
@@ -209,6 +220,24 @@ macro_rules! outer {
209220
fn f() {
210221
outer!();
211222
} //^^^^^^^^ error: leftover tokens
223+
"#,
224+
)
225+
}
226+
227+
#[test]
228+
fn def_diagnostic() {
229+
check_diagnostics(
230+
r#"
231+
macro_rules! foo {
232+
//^^^ error: expected subtree
233+
f => {};
234+
}
235+
236+
fn f() {
237+
foo!();
238+
//^^^ error: invalid macro definition: expected subtree
239+
240+
}
212241
"#,
213242
)
214243
}

crates/ide-diagnostics/src/lib.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -249,7 +249,7 @@ pub fn diagnostics(
249249

250250
let mut diags = Vec::new();
251251
if let Some(m) = module {
252-
m.diagnostics(db, &mut diags)
252+
m.diagnostics(db, &mut diags);
253253
}
254254

255255
for diag in diags {
@@ -263,6 +263,7 @@ pub fn diagnostics(
263263
AnyDiagnostic::IncoherentImpl(d) => handlers::incoherent_impl::incoherent_impl(&ctx, &d),
264264
AnyDiagnostic::IncorrectCase(d) => handlers::incorrect_case::incorrect_case(&ctx, &d),
265265
AnyDiagnostic::InvalidDeriveTarget(d) => handlers::invalid_derive_target::invalid_derive_target(&ctx, &d),
266+
AnyDiagnostic::MacroDefError(d) => handlers::macro_error::macro_def_error(&ctx, &d),
266267
AnyDiagnostic::MacroError(d) => handlers::macro_error::macro_error(&ctx, &d),
267268
AnyDiagnostic::MalformedDerive(d) => handlers::malformed_derive::malformed_derive(&ctx, &d),
268269
AnyDiagnostic::MismatchedArgCount(d) => handlers::mismatched_arg_count::mismatched_arg_count(&ctx, &d),

0 commit comments

Comments
 (0)