Skip to content

Commit c80c348

Browse files
committed
Improve proc macro errors a bit
Distinguish between - there is no build data (for some reason?) - there is build data, but the cargo package didn't build a proc macro dylib - there is a proc macro dylib, but it didn't contain the proc macro we expected - the name did not resolve to any macro (this is now an unresolved_macro_call even for attributes) I changed the handling of disabled attribute macro expansion to immediately ignore the macro and report an unresolved_proc_macro, because otherwise they would now result in loud unresolved_macro_call errors. I hope this doesn't break anything. Also try to improve error ranges for unresolved_macro_call / macro_error by reusing the code for unresolved_proc_macro. It's not perfect but probably better than before.
1 parent 32b40de commit c80c348

File tree

10 files changed

+164
-163
lines changed

10 files changed

+164
-163
lines changed

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

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

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -436,15 +436,15 @@ impl DefCollector<'_> {
436436
let mut unresolved_macros = mem::take(&mut self.unresolved_macros);
437437
let pos = unresolved_macros.iter().position(|directive| {
438438
if let MacroDirectiveKind::Attr { ast_id, mod_item, attr, tree } = &directive.kind {
439-
self.def_map.diagnostics.push(DefDiagnostic::unresolved_proc_macro(
439+
self.def_map.diagnostics.push(DefDiagnostic::unresolved_macro_call(
440440
directive.module_id,
441441
MacroCallKind::Attr {
442442
ast_id: ast_id.ast_id,
443443
attr_args: Default::default(),
444444
invoc_attr_index: attr.id.ast_index,
445445
is_derive: false,
446446
},
447-
None,
447+
attr.path().clone(),
448448
));
449449

450450
self.skip_attrs.insert(ast_id.ast_id.with_value(*mod_item), attr.id);
@@ -1218,10 +1218,6 @@ impl DefCollector<'_> {
12181218
return recollect_without(self);
12191219
}
12201220

1221-
if !self.db.enable_proc_attr_macros() {
1222-
return true;
1223-
}
1224-
12251221
// Not resolved to a derive helper or the derive attribute, so try to treat as a normal attribute.
12261222
let call_id = attr_macro_as_call_id(
12271223
self.db,
@@ -1233,6 +1229,15 @@ impl DefCollector<'_> {
12331229
);
12341230
let loc: MacroCallLoc = self.db.lookup_intern_macro_call(call_id);
12351231

1232+
if !self.db.enable_proc_attr_macros() {
1233+
self.def_map.diagnostics.push(DefDiagnostic::unresolved_proc_macro(
1234+
directive.module_id,
1235+
loc.kind,
1236+
Some(loc.def.krate),
1237+
));
1238+
return recollect_without(self);
1239+
}
1240+
12361241
// Skip #[test]/#[bench] expansion, which would merely result in more memory usage
12371242
// due to duplicating functions into macro expansions
12381243
if matches!(

crates/hir-expand/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ hashbrown = { version = "0.12.1", features = [
2020
"inline-more",
2121
], default-features = false }
2222

23+
stdx = { path = "../stdx", version = "0.0.0" }
2324
base-db = { path = "../base-db", version = "0.0.0" }
2425
cfg = { path = "../cfg", version = "0.0.0" }
2526
syntax = { path = "../syntax", version = "0.0.0" }

crates/hir-expand/src/proc_macro.rs

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
//! Proc Macro Expander stub
22
33
use base_db::{CrateId, ProcMacroExpansionError, ProcMacroId, ProcMacroKind};
4+
use stdx::never;
45

56
use crate::{db::AstDatabase, ExpandError, ExpandResult};
67

@@ -36,18 +37,20 @@ impl ProcMacroExpander {
3637
let krate_graph = db.crate_graph();
3738
let proc_macros = match &krate_graph[self.krate].proc_macro {
3839
Ok(proc_macros) => proc_macros,
39-
Err(e) => {
40-
return ExpandResult::only_err(ExpandError::Other(
41-
e.clone().into_boxed_str(),
42-
))
40+
Err(_) => {
41+
never!("Non-dummy expander even though there are no proc macros");
42+
return ExpandResult::only_err(ExpandError::Other("Internal error".into()));
4343
}
4444
};
4545
let proc_macro = match proc_macros.get(id.0 as usize) {
4646
Some(proc_macro) => proc_macro,
4747
None => {
48-
return ExpandResult::only_err(ExpandError::Other(
49-
"No proc-macro found.".into(),
50-
))
48+
never!(
49+
"Proc macro index out of bounds: the length is {} but the index is {}",
50+
proc_macros.len(),
51+
id.0
52+
);
53+
return ExpandResult::only_err(ExpandError::Other("Internal error".into()));
5154
}
5255
};
5356

crates/hir/src/diagnostics.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ pub struct UnresolvedImport {
6969
#[derive(Debug, Clone, Eq, PartialEq)]
7070
pub struct UnresolvedMacroCall {
7171
pub macro_call: InFile<SyntaxNodePtr>,
72+
pub precise_location: Option<TextRange>,
7273
pub path: ModPath,
7374
pub is_bang: bool,
7475
}
@@ -95,6 +96,7 @@ pub struct UnresolvedProcMacro {
9596
#[derive(Debug, Clone, Eq, PartialEq)]
9697
pub struct MacroError {
9798
pub node: InFile<SyntaxNodePtr>,
99+
pub precise_location: Option<TextRange>,
98100
pub message: String,
99101
}
100102

crates/hir/src/lib.rs

Lines changed: 81 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ use rustc_hash::FxHashSet;
7373
use stdx::{format_to, impl_from, never};
7474
use syntax::{
7575
ast::{self, HasAttrs as _, HasDocComments, HasName},
76-
AstNode, AstPtr, SmolStr, SyntaxNodePtr, T,
76+
AstNode, AstPtr, SmolStr, SyntaxNodePtr, TextRange, T,
7777
};
7878

7979
use crate::db::{DefDatabase, HirDatabase};
@@ -628,78 +628,19 @@ fn emit_def_diagnostic(db: &dyn HirDatabase, acc: &mut Vec<AnyDiagnostic>, diag:
628628
}
629629

630630
DefDiagnosticKind::UnresolvedProcMacro { ast, krate } => {
631-
let (node, precise_location, macro_name, kind) = match ast {
632-
MacroCallKind::FnLike { ast_id, .. } => {
633-
let node = ast_id.to_node(db.upcast());
634-
(
635-
ast_id.with_value(SyntaxNodePtr::from(AstPtr::new(&node))),
636-
node.path().map(|it| it.syntax().text_range()),
637-
node.path().and_then(|it| it.segment()).map(|it| it.to_string()),
638-
MacroKind::ProcMacro,
639-
)
640-
}
641-
MacroCallKind::Derive { ast_id, derive_attr_index, derive_index } => {
642-
let node = ast_id.to_node(db.upcast());
643-
// Compute the precise location of the macro name's token in the derive
644-
// list.
645-
let token = (|| {
646-
let derive_attr = node
647-
.doc_comments_and_attrs()
648-
.nth(*derive_attr_index as usize)
649-
.and_then(Either::left)?;
650-
let token_tree = derive_attr.meta()?.token_tree()?;
651-
let group_by = token_tree
652-
.syntax()
653-
.children_with_tokens()
654-
.filter_map(|elem| match elem {
655-
syntax::NodeOrToken::Token(tok) => Some(tok),
656-
_ => None,
657-
})
658-
.group_by(|t| t.kind() == T![,]);
659-
let (_, mut group) = group_by
660-
.into_iter()
661-
.filter(|&(comma, _)| !comma)
662-
.nth(*derive_index as usize)?;
663-
group.find(|t| t.kind() == T![ident])
664-
})();
665-
(
666-
ast_id.with_value(SyntaxNodePtr::from(AstPtr::new(&node))),
667-
token.as_ref().map(|tok| tok.text_range()),
668-
token.as_ref().map(ToString::to_string),
669-
MacroKind::Derive,
670-
)
671-
}
672-
MacroCallKind::Attr { ast_id, invoc_attr_index, .. } => {
673-
let node = ast_id.to_node(db.upcast());
674-
let attr = node
675-
.doc_comments_and_attrs()
676-
.nth((*invoc_attr_index) as usize)
677-
.and_then(Either::left)
678-
.unwrap_or_else(|| panic!("cannot find attribute #{}", invoc_attr_index));
679-
680-
(
681-
ast_id.with_value(SyntaxNodePtr::from(AstPtr::new(&attr))),
682-
Some(attr.syntax().text_range()),
683-
attr.path()
684-
.and_then(|path| path.segment())
685-
.and_then(|seg| seg.name_ref())
686-
.as_ref()
687-
.map(ToString::to_string),
688-
MacroKind::Attr,
689-
)
690-
}
691-
};
631+
let (node, precise_location, macro_name, kind) = precise_macro_call_location(ast, db);
692632
acc.push(
693633
UnresolvedProcMacro { node, precise_location, macro_name, kind, krate: *krate }
694634
.into(),
695635
);
696636
}
697637

698638
DefDiagnosticKind::UnresolvedMacroCall { ast, path } => {
699-
let node = ast.to_node(db.upcast());
639+
let (node, precise_location, _, _) = precise_macro_call_location(ast, db);
700640
acc.push(
701641
UnresolvedMacroCall {
702-
macro_call: InFile::new(node.file_id, SyntaxNodePtr::new(&node.value)),
642+
macro_call: node,
643+
precise_location,
703644
path: path.clone(),
704645
is_bang: matches!(ast, MacroCallKind::FnLike { .. }),
705646
}
@@ -708,23 +649,8 @@ fn emit_def_diagnostic(db: &dyn HirDatabase, acc: &mut Vec<AnyDiagnostic>, diag:
708649
}
709650

710651
DefDiagnosticKind::MacroError { ast, message } => {
711-
let node = match ast {
712-
MacroCallKind::FnLike { ast_id, .. } => {
713-
let node = ast_id.to_node(db.upcast());
714-
ast_id.with_value(SyntaxNodePtr::from(AstPtr::new(&node)))
715-
}
716-
MacroCallKind::Derive { ast_id, .. } => {
717-
// FIXME: point to the attribute instead, this creates very large diagnostics
718-
let node = ast_id.to_node(db.upcast());
719-
ast_id.with_value(SyntaxNodePtr::from(AstPtr::new(&node)))
720-
}
721-
MacroCallKind::Attr { ast_id, .. } => {
722-
// FIXME: point to the attribute instead, this creates very large diagnostics
723-
let node = ast_id.to_node(db.upcast());
724-
ast_id.with_value(SyntaxNodePtr::from(AstPtr::new(&node)))
725-
}
726-
};
727-
acc.push(MacroError { node, message: message.clone() }.into());
652+
let (node, precise_location, _, _) = precise_macro_call_location(ast, db);
653+
acc.push(MacroError { node, precise_location, message: message.clone() }.into());
728654
}
729655

730656
DefDiagnosticKind::UnimplementedBuiltinMacro { ast } => {
@@ -771,6 +697,78 @@ fn emit_def_diagnostic(db: &dyn HirDatabase, acc: &mut Vec<AnyDiagnostic>, diag:
771697
}
772698
}
773699

700+
fn precise_macro_call_location(
701+
ast: &MacroCallKind,
702+
db: &dyn HirDatabase,
703+
) -> (InFile<SyntaxNodePtr>, Option<TextRange>, Option<String>, MacroKind) {
704+
// FIXME: maaybe we actually want slightly different ranges for the different macro diagnostics
705+
// - e.g. the full attribute for macro errors, but only the name for name resolution
706+
match ast {
707+
MacroCallKind::FnLike { ast_id, .. } => {
708+
let node = ast_id.to_node(db.upcast());
709+
(
710+
ast_id.with_value(SyntaxNodePtr::from(AstPtr::new(&node))),
711+
node.path()
712+
.and_then(|it| it.segment())
713+
.and_then(|it| it.name_ref())
714+
.map(|it| it.syntax().text_range()),
715+
node.path().and_then(|it| it.segment()).map(|it| it.to_string()),
716+
MacroKind::ProcMacro,
717+
)
718+
}
719+
MacroCallKind::Derive { ast_id, derive_attr_index, derive_index } => {
720+
let node = ast_id.to_node(db.upcast());
721+
// Compute the precise location of the macro name's token in the derive
722+
// list.
723+
let token = (|| {
724+
let derive_attr = node
725+
.doc_comments_and_attrs()
726+
.nth(*derive_attr_index as usize)
727+
.and_then(Either::left)?;
728+
let token_tree = derive_attr.meta()?.token_tree()?;
729+
let group_by = token_tree
730+
.syntax()
731+
.children_with_tokens()
732+
.filter_map(|elem| match elem {
733+
syntax::NodeOrToken::Token(tok) => Some(tok),
734+
_ => None,
735+
})
736+
.group_by(|t| t.kind() == T![,]);
737+
let (_, mut group) = group_by
738+
.into_iter()
739+
.filter(|&(comma, _)| !comma)
740+
.nth(*derive_index as usize)?;
741+
group.find(|t| t.kind() == T![ident])
742+
})();
743+
(
744+
ast_id.with_value(SyntaxNodePtr::from(AstPtr::new(&node))),
745+
token.as_ref().map(|tok| tok.text_range()),
746+
token.as_ref().map(ToString::to_string),
747+
MacroKind::Derive,
748+
)
749+
}
750+
MacroCallKind::Attr { ast_id, invoc_attr_index, .. } => {
751+
let node = ast_id.to_node(db.upcast());
752+
let attr = node
753+
.doc_comments_and_attrs()
754+
.nth((*invoc_attr_index) as usize)
755+
.and_then(Either::left)
756+
.unwrap_or_else(|| panic!("cannot find attribute #{}", invoc_attr_index));
757+
758+
(
759+
ast_id.with_value(SyntaxNodePtr::from(AstPtr::new(&attr))),
760+
Some(attr.syntax().text_range()),
761+
attr.path()
762+
.and_then(|path| path.segment())
763+
.and_then(|seg| seg.name_ref())
764+
.as_ref()
765+
.map(ToString::to_string),
766+
MacroKind::Attr,
767+
)
768+
}
769+
}
770+
}
771+
774772
impl HasVisibility for Module {
775773
fn visibility(&self, db: &dyn HirDatabase) -> Visibility {
776774
let def_map = self.id.def_map(db.upcast());
@@ -1156,6 +1154,7 @@ impl DefWithBody {
11561154
BodyDiagnostic::MacroError { node, message } => acc.push(
11571155
MacroError {
11581156
node: node.clone().map(|it| it.into()),
1157+
precise_location: None,
11591158
message: message.to_string(),
11601159
}
11611160
.into(),
@@ -1173,6 +1172,7 @@ impl DefWithBody {
11731172
BodyDiagnostic::UnresolvedMacroCall { node, path } => acc.push(
11741173
UnresolvedMacroCall {
11751174
macro_call: node.clone().map(|ast_ptr| ast_ptr.into()),
1175+
precise_location: None,
11761176
path: path.clone(),
11771177
is_bang: true,
11781178
}

0 commit comments

Comments
 (0)