mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-09-28 04:44:57 +00:00
Auto merge of #14584 - Veykril:macro-def-err, r=Veykril
internal: Report item-level macro expansion syntax errors
This commit is contained in:
commit
697b335fda
22 changed files with 327 additions and 325 deletions
|
@ -21,7 +21,7 @@ use limit::Limit;
|
|||
use once_cell::unsync::OnceCell;
|
||||
use profile::Count;
|
||||
use rustc_hash::FxHashMap;
|
||||
use syntax::{ast, AstPtr, SyntaxNode, SyntaxNodePtr};
|
||||
use syntax::{ast, AstPtr, Parse, SyntaxNode, SyntaxNodePtr};
|
||||
|
||||
use crate::{
|
||||
attr::Attrs,
|
||||
|
@ -137,7 +137,8 @@ impl Expander {
|
|||
&mut self,
|
||||
db: &dyn DefDatabase,
|
||||
macro_call: ast::MacroCall,
|
||||
) -> Result<ExpandResult<Option<(Mark, T)>>, UnresolvedMacro> {
|
||||
) -> Result<ExpandResult<Option<(Mark, Parse<T>)>>, UnresolvedMacro> {
|
||||
// FIXME: within_limit should support this, instead of us having to extract the error
|
||||
let mut unresolved_macro_err = None;
|
||||
|
||||
let result = self.within_limit(db, |this| {
|
||||
|
@ -146,22 +147,13 @@ impl Expander {
|
|||
let resolver =
|
||||
|path| this.resolve_path_as_macro(db, &path).map(|it| macro_id_to_def_id(db, it));
|
||||
|
||||
let mut err = None;
|
||||
let call_id = match macro_call.as_call_id_with_errors(
|
||||
db,
|
||||
this.def_map.krate(),
|
||||
resolver,
|
||||
&mut |e| {
|
||||
err.get_or_insert(e);
|
||||
},
|
||||
) {
|
||||
match macro_call.as_call_id_with_errors(db, this.def_map.krate(), resolver) {
|
||||
Ok(call_id) => call_id,
|
||||
Err(resolve_err) => {
|
||||
unresolved_macro_err = Some(resolve_err);
|
||||
return ExpandResult { value: None, err: None };
|
||||
ExpandResult { value: None, err: None }
|
||||
}
|
||||
};
|
||||
ExpandResult { value: call_id.ok(), err }
|
||||
}
|
||||
});
|
||||
|
||||
if let Some(err) = unresolved_macro_err {
|
||||
|
@ -175,37 +167,37 @@ impl Expander {
|
|||
&mut self,
|
||||
db: &dyn DefDatabase,
|
||||
call_id: MacroCallId,
|
||||
) -> ExpandResult<Option<(Mark, T)>> {
|
||||
) -> ExpandResult<Option<(Mark, Parse<T>)>> {
|
||||
self.within_limit(db, |_this| ExpandResult::ok(Some(call_id)))
|
||||
}
|
||||
|
||||
fn enter_expand_inner(
|
||||
db: &dyn DefDatabase,
|
||||
call_id: MacroCallId,
|
||||
mut err: Option<ExpandError>,
|
||||
) -> ExpandResult<Option<(HirFileId, SyntaxNode)>> {
|
||||
if err.is_none() {
|
||||
err = db.macro_expand_error(call_id);
|
||||
mut error: Option<ExpandError>,
|
||||
) -> ExpandResult<Option<InFile<Parse<SyntaxNode>>>> {
|
||||
let file_id = call_id.as_file();
|
||||
let ExpandResult { value, err } = db.parse_or_expand_with_err(file_id);
|
||||
|
||||
if error.is_none() {
|
||||
error = err;
|
||||
}
|
||||
|
||||
let file_id = call_id.as_file();
|
||||
|
||||
let raw_node = match db.parse_or_expand_with_err(file_id) {
|
||||
// FIXME: report parse errors
|
||||
Some(it) => it.syntax_node(),
|
||||
let parse = match value {
|
||||
Some(it) => it,
|
||||
None => {
|
||||
// Only `None` if the macro expansion produced no usable AST.
|
||||
if err.is_none() {
|
||||
if error.is_none() {
|
||||
tracing::warn!("no error despite `parse_or_expand` failing");
|
||||
}
|
||||
|
||||
return ExpandResult::only_err(err.unwrap_or_else(|| {
|
||||
return ExpandResult::only_err(error.unwrap_or_else(|| {
|
||||
ExpandError::Other("failed to parse macro invocation".into())
|
||||
}));
|
||||
}
|
||||
};
|
||||
|
||||
ExpandResult { value: Some((file_id, raw_node)), err }
|
||||
ExpandResult { value: Some(InFile::new(file_id, parse)), err: error }
|
||||
}
|
||||
|
||||
pub fn exit(&mut self, db: &dyn DefDatabase, mut mark: Mark) {
|
||||
|
@ -267,7 +259,7 @@ impl Expander {
|
|||
&mut self,
|
||||
db: &dyn DefDatabase,
|
||||
op: F,
|
||||
) -> ExpandResult<Option<(Mark, T)>>
|
||||
) -> ExpandResult<Option<(Mark, Parse<T>)>>
|
||||
where
|
||||
F: FnOnce(&mut Self) -> ExpandResult<Option<MacroCallId>>,
|
||||
{
|
||||
|
@ -294,15 +286,15 @@ impl Expander {
|
|||
};
|
||||
|
||||
Self::enter_expand_inner(db, call_id, err).map(|value| {
|
||||
value.and_then(|(new_file_id, node)| {
|
||||
let node = T::cast(node)?;
|
||||
value.and_then(|InFile { file_id, value }| {
|
||||
let parse = value.cast::<T>()?;
|
||||
|
||||
self.recursion_depth += 1;
|
||||
self.cfg_expander.hygiene = Hygiene::new(db.upcast(), new_file_id);
|
||||
let old_file_id = std::mem::replace(&mut self.current_file_id, new_file_id);
|
||||
self.cfg_expander.hygiene = Hygiene::new(db.upcast(), file_id);
|
||||
let old_file_id = std::mem::replace(&mut self.current_file_id, file_id);
|
||||
let mark =
|
||||
Mark { file_id: old_file_id, bomb: DropBomb::new("expansion mark dropped") };
|
||||
Some((mark, node))
|
||||
Some((mark, parse))
|
||||
})
|
||||
})
|
||||
}
|
||||
|
|
|
@ -824,7 +824,11 @@ impl ExprCollector<'_> {
|
|||
self.db.ast_id_map(self.expander.current_file_id),
|
||||
);
|
||||
|
||||
let id = collector(self, Some(expansion));
|
||||
if record_diagnostics {
|
||||
// FIXME: Report parse errors here
|
||||
}
|
||||
|
||||
let id = collector(self, Some(expansion.tree()));
|
||||
self.ast_id_map = prev_ast_id_map;
|
||||
self.expander.exit(self.db, mark);
|
||||
id
|
||||
|
|
|
@ -7,7 +7,7 @@ use std::sync::Arc;
|
|||
use hir_expand::{name::Name, AstId, ExpandResult, HirFileId, InFile, MacroCallId, MacroDefKind};
|
||||
use intern::Interned;
|
||||
use smallvec::SmallVec;
|
||||
use syntax::ast;
|
||||
use syntax::{ast, Parse};
|
||||
|
||||
use crate::{
|
||||
attr::Attrs,
|
||||
|
@ -604,13 +604,10 @@ impl<'a> AssocItemCollector<'a> {
|
|||
continue 'attrs;
|
||||
}
|
||||
}
|
||||
match self.expander.enter_expand_id::<ast::MacroItems>(self.db, call_id) {
|
||||
ExpandResult { value: Some((mark, _)), .. } => {
|
||||
self.collect_macro_items(mark);
|
||||
continue 'items;
|
||||
}
|
||||
ExpandResult { .. } => {}
|
||||
}
|
||||
|
||||
let res = self.expander.enter_expand_id::<ast::MacroItems>(self.db, call_id);
|
||||
self.collect_macro_items(res, &|| loc.kind.clone());
|
||||
continue 'items;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -641,22 +638,23 @@ impl<'a> AssocItemCollector<'a> {
|
|||
self.items.push((item.name.clone(), def.into()));
|
||||
}
|
||||
AssocItem::MacroCall(call) => {
|
||||
if let Some(root) =
|
||||
self.db.parse_or_expand_with_err(self.expander.current_file_id())
|
||||
{
|
||||
// FIXME: report parse errors
|
||||
let root = root.syntax_node();
|
||||
|
||||
let file_id = self.expander.current_file_id();
|
||||
let root = self.db.parse_or_expand(file_id);
|
||||
if let Some(root) = root {
|
||||
let call = &item_tree[call];
|
||||
|
||||
let ast_id_map = self.db.ast_id_map(self.expander.current_file_id());
|
||||
let call = ast_id_map.get(call.ast_id).to_node(&root);
|
||||
let _cx =
|
||||
stdx::panic_context::enter(format!("collect_items MacroCall: {call}"));
|
||||
let res = self.expander.enter_expand::<ast::MacroItems>(self.db, call);
|
||||
|
||||
if let Ok(ExpandResult { value: Some((mark, _)), .. }) = res {
|
||||
self.collect_macro_items(mark);
|
||||
let ast_id_map = self.db.ast_id_map(file_id);
|
||||
let macro_call = ast_id_map.get(call.ast_id).to_node(&root);
|
||||
let _cx = stdx::panic_context::enter(format!(
|
||||
"collect_items MacroCall: {macro_call}"
|
||||
));
|
||||
if let Ok(res) =
|
||||
self.expander.enter_expand::<ast::MacroItems>(self.db, macro_call)
|
||||
{
|
||||
self.collect_macro_items(res, &|| hir_expand::MacroCallKind::FnLike {
|
||||
ast_id: InFile::new(file_id, call.ast_id),
|
||||
expand_to: hir_expand::ExpandTo::Items,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -664,7 +662,28 @@ impl<'a> AssocItemCollector<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
fn collect_macro_items(&mut self, mark: Mark) {
|
||||
fn collect_macro_items(
|
||||
&mut self,
|
||||
ExpandResult { value, err }: ExpandResult<Option<(Mark, Parse<ast::MacroItems>)>>,
|
||||
error_call_kind: &dyn Fn() -> hir_expand::MacroCallKind,
|
||||
) {
|
||||
let Some((mark, parse)) = value else { return };
|
||||
|
||||
if let Some(err) = err {
|
||||
self.inactive_diagnostics.push(DefDiagnostic::macro_error(
|
||||
self.module_id.local_id,
|
||||
error_call_kind(),
|
||||
err.to_string(),
|
||||
));
|
||||
}
|
||||
if let errors @ [_, ..] = parse.errors() {
|
||||
self.inactive_diagnostics.push(DefDiagnostic::macro_expansion_parse_error(
|
||||
self.module_id.local_id,
|
||||
error_call_kind(),
|
||||
errors.into(),
|
||||
));
|
||||
}
|
||||
|
||||
let tree_id = item_tree::TreeId::new(self.expander.current_file_id(), None);
|
||||
let item_tree = tree_id.item_tree(self.db);
|
||||
let iter: SmallVec<[_; 2]> =
|
||||
|
|
|
@ -350,7 +350,7 @@ impl GenericParams {
|
|||
match expander.enter_expand::<ast::Type>(db, macro_call) {
|
||||
Ok(ExpandResult { value: Some((mark, expanded)), .. }) => {
|
||||
let ctx = expander.ctx(db);
|
||||
let type_ref = TypeRef::from_ast(&ctx, expanded);
|
||||
let type_ref = TypeRef::from_ast(&ctx, expanded.tree());
|
||||
self.fill_implicit_impl_trait_args(db, expander, &type_ref);
|
||||
expander.exit(db, mark);
|
||||
}
|
||||
|
|
|
@ -101,6 +101,7 @@ pub struct ItemTree {
|
|||
top_level: SmallVec<[ModItem; 1]>,
|
||||
attrs: FxHashMap<AttrOwner, RawAttrs>,
|
||||
|
||||
// FIXME: Remove this indirection, an item tree is almost always non-empty?
|
||||
data: Option<Box<ItemTreeData>>,
|
||||
}
|
||||
|
||||
|
|
|
@ -65,11 +65,11 @@ use hir_expand::{
|
|||
builtin_attr_macro::BuiltinAttrExpander,
|
||||
builtin_derive_macro::BuiltinDeriveExpander,
|
||||
builtin_fn_macro::{BuiltinFnLikeExpander, EagerExpander},
|
||||
eager::{expand_eager_macro, ErrorEmitted, ErrorSink},
|
||||
eager::expand_eager_macro,
|
||||
hygiene::Hygiene,
|
||||
proc_macro::ProcMacroExpander,
|
||||
AstId, ExpandError, ExpandTo, HirFileId, InFile, MacroCallId, MacroCallKind, MacroDefId,
|
||||
MacroDefKind, UnresolvedMacro,
|
||||
AstId, ExpandError, ExpandResult, ExpandTo, HirFileId, InFile, MacroCallId, MacroCallKind,
|
||||
MacroDefId, MacroDefKind, UnresolvedMacro,
|
||||
};
|
||||
use item_tree::ExternBlock;
|
||||
use la_arena::Idx;
|
||||
|
@ -795,7 +795,7 @@ pub trait AsMacroCall {
|
|||
krate: CrateId,
|
||||
resolver: impl Fn(path::ModPath) -> Option<MacroDefId>,
|
||||
) -> Option<MacroCallId> {
|
||||
self.as_call_id_with_errors(db, krate, resolver, &mut |_| ()).ok()?.ok()
|
||||
self.as_call_id_with_errors(db, krate, resolver).ok()?.value
|
||||
}
|
||||
|
||||
fn as_call_id_with_errors(
|
||||
|
@ -803,8 +803,7 @@ pub trait AsMacroCall {
|
|||
db: &dyn db::DefDatabase,
|
||||
krate: CrateId,
|
||||
resolver: impl Fn(path::ModPath) -> Option<MacroDefId>,
|
||||
error_sink: &mut dyn FnMut(ExpandError),
|
||||
) -> Result<Result<MacroCallId, ErrorEmitted>, UnresolvedMacro>;
|
||||
) -> Result<ExpandResult<Option<MacroCallId>>, UnresolvedMacro>;
|
||||
}
|
||||
|
||||
impl AsMacroCall for InFile<&ast::MacroCall> {
|
||||
|
@ -813,30 +812,23 @@ impl AsMacroCall for InFile<&ast::MacroCall> {
|
|||
db: &dyn db::DefDatabase,
|
||||
krate: CrateId,
|
||||
resolver: impl Fn(path::ModPath) -> Option<MacroDefId>,
|
||||
mut error_sink: &mut dyn FnMut(ExpandError),
|
||||
) -> Result<Result<MacroCallId, ErrorEmitted>, UnresolvedMacro> {
|
||||
) -> Result<ExpandResult<Option<MacroCallId>>, UnresolvedMacro> {
|
||||
let expands_to = hir_expand::ExpandTo::from_call_site(self.value);
|
||||
let ast_id = AstId::new(self.file_id, db.ast_id_map(self.file_id).ast_id(self.value));
|
||||
let h = Hygiene::new(db.upcast(), self.file_id);
|
||||
let path =
|
||||
self.value.path().and_then(|path| path::ModPath::from_src(db.upcast(), path, &h));
|
||||
|
||||
let path = match error_sink
|
||||
.option(path, || ExpandError::Other("malformed macro invocation".into()))
|
||||
{
|
||||
Ok(path) => path,
|
||||
Err(error) => {
|
||||
return Ok(Err(error));
|
||||
}
|
||||
let Some(path) = path else {
|
||||
return Ok(ExpandResult::only_err(ExpandError::Other("malformed macro invocation".into())));
|
||||
};
|
||||
|
||||
macro_call_as_call_id(
|
||||
macro_call_as_call_id_(
|
||||
db,
|
||||
&AstIdWithPath::new(ast_id.file_id, ast_id.value, path),
|
||||
expands_to,
|
||||
krate,
|
||||
resolver,
|
||||
error_sink,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -860,21 +852,33 @@ fn macro_call_as_call_id(
|
|||
expand_to: ExpandTo,
|
||||
krate: CrateId,
|
||||
resolver: impl Fn(path::ModPath) -> Option<MacroDefId>,
|
||||
error_sink: &mut dyn FnMut(ExpandError),
|
||||
) -> Result<Result<MacroCallId, ErrorEmitted>, UnresolvedMacro> {
|
||||
) -> Result<Option<MacroCallId>, UnresolvedMacro> {
|
||||
macro_call_as_call_id_(db, call, expand_to, krate, resolver).map(|res| res.value)
|
||||
}
|
||||
|
||||
fn macro_call_as_call_id_(
|
||||
db: &dyn db::DefDatabase,
|
||||
call: &AstIdWithPath<ast::MacroCall>,
|
||||
expand_to: ExpandTo,
|
||||
krate: CrateId,
|
||||
resolver: impl Fn(path::ModPath) -> Option<MacroDefId>,
|
||||
) -> Result<ExpandResult<Option<MacroCallId>>, UnresolvedMacro> {
|
||||
let def =
|
||||
resolver(call.path.clone()).ok_or_else(|| UnresolvedMacro { path: call.path.clone() })?;
|
||||
|
||||
let res = if let MacroDefKind::BuiltInEager(..) = def.kind {
|
||||
let macro_call = InFile::new(call.ast_id.file_id, call.ast_id.to_node(db.upcast()));
|
||||
|
||||
expand_eager_macro(db.upcast(), krate, macro_call, def, &resolver, error_sink)?
|
||||
expand_eager_macro(db.upcast(), krate, macro_call, def, &resolver)?
|
||||
} else {
|
||||
Ok(def.as_lazy_macro(
|
||||
db.upcast(),
|
||||
krate,
|
||||
MacroCallKind::FnLike { ast_id: call.ast_id, expand_to },
|
||||
))
|
||||
ExpandResult {
|
||||
value: Some(def.as_lazy_macro(
|
||||
db.upcast(),
|
||||
krate,
|
||||
MacroCallKind::FnLike { ast_id: call.ast_id, expand_to },
|
||||
)),
|
||||
err: None,
|
||||
}
|
||||
};
|
||||
Ok(res)
|
||||
}
|
||||
|
|
|
@ -125,21 +125,15 @@ pub fn identity_when_valid(_attr: TokenStream, item: TokenStream) -> TokenStream
|
|||
|
||||
for macro_call in source_file.syntax().descendants().filter_map(ast::MacroCall::cast) {
|
||||
let macro_call = InFile::new(source.file_id, ¯o_call);
|
||||
let mut error = None;
|
||||
let macro_call_id = macro_call
|
||||
.as_call_id_with_errors(
|
||||
&db,
|
||||
krate,
|
||||
|path| {
|
||||
resolver.resolve_path_as_macro(&db, &path).map(|it| macro_id_to_def_id(&db, it))
|
||||
},
|
||||
&mut |err| error = Some(err),
|
||||
)
|
||||
.unwrap()
|
||||
let res = macro_call
|
||||
.as_call_id_with_errors(&db, krate, |path| {
|
||||
resolver.resolve_path_as_macro(&db, &path).map(|it| macro_id_to_def_id(&db, it))
|
||||
})
|
||||
.unwrap();
|
||||
let macro_call_id = res.value.unwrap();
|
||||
let macro_file = MacroFile { macro_call_id };
|
||||
let mut expansion_result = db.parse_macro_expansion(macro_file);
|
||||
expansion_result.err = expansion_result.err.or(error);
|
||||
expansion_result.err = expansion_result.err.or(res.err);
|
||||
expansions.push((macro_call.value.clone(), expansion_result, db.macro_arg(macro_call_id)));
|
||||
}
|
||||
|
||||
|
|
|
@ -16,8 +16,8 @@ use hir_expand::{
|
|||
builtin_fn_macro::find_builtin_macro,
|
||||
name::{name, AsName, Name},
|
||||
proc_macro::ProcMacroExpander,
|
||||
ExpandTo, HirFileId, InFile, MacroCallId, MacroCallKind, MacroCallLoc, MacroDefId,
|
||||
MacroDefKind,
|
||||
ExpandResult, ExpandTo, HirFileId, InFile, MacroCallId, MacroCallKind, MacroCallLoc,
|
||||
MacroDefId, MacroDefKind,
|
||||
};
|
||||
use itertools::{izip, Itertools};
|
||||
use la_arena::Idx;
|
||||
|
@ -1116,10 +1116,10 @@ impl DefCollector<'_> {
|
|||
*expand_to,
|
||||
self.def_map.krate,
|
||||
resolver_def_id,
|
||||
&mut |_err| (),
|
||||
);
|
||||
if let Ok(Ok(call_id)) = call_id {
|
||||
if let Ok(Some(call_id)) = call_id {
|
||||
push_resolved(directive, call_id);
|
||||
|
||||
res = ReachedFixedPoint::No;
|
||||
return false;
|
||||
}
|
||||
|
@ -1355,26 +1355,30 @@ impl DefCollector<'_> {
|
|||
let file_id = macro_call_id.as_file();
|
||||
|
||||
// First, fetch the raw expansion result for purposes of error reporting. This goes through
|
||||
// `macro_expand_error` to avoid depending on the full expansion result (to improve
|
||||
// `parse_macro_expansion_error` to avoid depending on the full expansion result (to improve
|
||||
// incrementality).
|
||||
let loc: MacroCallLoc = self.db.lookup_intern_macro_call(macro_call_id);
|
||||
let err = self.db.macro_expand_error(macro_call_id);
|
||||
let ExpandResult { value, err } = self.db.parse_macro_expansion_error(macro_call_id);
|
||||
if let Some(err) = err {
|
||||
let loc: MacroCallLoc = self.db.lookup_intern_macro_call(macro_call_id);
|
||||
let diag = match err {
|
||||
// why is this reported here?
|
||||
hir_expand::ExpandError::UnresolvedProcMacro(krate) => {
|
||||
always!(krate == loc.def.krate);
|
||||
// Missing proc macros are non-fatal, so they are handled specially.
|
||||
DefDiagnostic::unresolved_proc_macro(module_id, loc.kind.clone(), loc.def.krate)
|
||||
}
|
||||
_ => DefDiagnostic::macro_error(module_id, loc.kind, err.to_string()),
|
||||
_ => DefDiagnostic::macro_error(module_id, loc.kind.clone(), err.to_string()),
|
||||
};
|
||||
|
||||
self.def_map.diagnostics.push(diag);
|
||||
}
|
||||
if let Some(errors) = value {
|
||||
let loc: MacroCallLoc = self.db.lookup_intern_macro_call(macro_call_id);
|
||||
let diag = DefDiagnostic::macro_expansion_parse_error(module_id, loc.kind, &errors);
|
||||
self.def_map.diagnostics.push(diag);
|
||||
}
|
||||
|
||||
// Then, fetch and process the item tree. This will reuse the expansion result from above.
|
||||
let item_tree = self.db.file_item_tree(file_id);
|
||||
// FIXME: report parse errors for the macro expansion here
|
||||
|
||||
let mod_dir = self.mod_dirs[&module_id].clone();
|
||||
ModCollector {
|
||||
|
@ -1396,6 +1400,7 @@ impl DefCollector<'_> {
|
|||
for directive in &self.unresolved_macros {
|
||||
match &directive.kind {
|
||||
MacroDirectiveKind::FnLike { ast_id, expand_to } => {
|
||||
// FIXME: we shouldn't need to re-resolve the macro here just to get the unresolved error!
|
||||
let macro_call_as_call_id = macro_call_as_call_id(
|
||||
self.db,
|
||||
ast_id,
|
||||
|
@ -1414,7 +1419,6 @@ impl DefCollector<'_> {
|
|||
.take_macros()
|
||||
.map(|it| macro_id_to_def_id(self.db, it))
|
||||
},
|
||||
&mut |_| (),
|
||||
);
|
||||
if let Err(UnresolvedMacro { path }) = macro_call_as_call_id {
|
||||
self.def_map.diagnostics.push(DefDiagnostic::unresolved_macro_call(
|
||||
|
@ -2112,8 +2116,7 @@ impl ModCollector<'_, '_> {
|
|||
let ast_id = AstIdWithPath::new(self.file_id(), mac.ast_id, ModPath::clone(&mac.path));
|
||||
|
||||
// Case 1: try to resolve in legacy scope and expand macro_rules
|
||||
let mut error = None;
|
||||
match macro_call_as_call_id(
|
||||
if let Ok(res) = macro_call_as_call_id(
|
||||
self.def_collector.db,
|
||||
&ast_id,
|
||||
mac.expand_to,
|
||||
|
@ -2133,41 +2136,19 @@ impl ModCollector<'_, '_> {
|
|||
)
|
||||
})
|
||||
},
|
||||
&mut |err| {
|
||||
error.get_or_insert(err);
|
||||
},
|
||||
) {
|
||||
Ok(Ok(macro_call_id)) => {
|
||||
// Legacy macros need to be expanded immediately, so that any macros they produce
|
||||
// are in scope.
|
||||
// Legacy macros need to be expanded immediately, so that any macros they produce
|
||||
// are in scope.
|
||||
if let Some(val) = res {
|
||||
self.def_collector.collect_macro_expansion(
|
||||
self.module_id,
|
||||
macro_call_id,
|
||||
val,
|
||||
self.macro_depth + 1,
|
||||
container,
|
||||
);
|
||||
|
||||
if let Some(err) = error {
|
||||
self.def_collector.def_map.diagnostics.push(DefDiagnostic::macro_error(
|
||||
self.module_id,
|
||||
MacroCallKind::FnLike { ast_id: ast_id.ast_id, expand_to: mac.expand_to },
|
||||
err.to_string(),
|
||||
));
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
Ok(Err(_)) => {
|
||||
// Built-in macro failed eager expansion.
|
||||
|
||||
self.def_collector.def_map.diagnostics.push(DefDiagnostic::macro_error(
|
||||
self.module_id,
|
||||
MacroCallKind::FnLike { ast_id: ast_id.ast_id, expand_to: mac.expand_to },
|
||||
error.unwrap().to_string(),
|
||||
));
|
||||
return;
|
||||
}
|
||||
Err(UnresolvedMacro { .. }) => (),
|
||||
return;
|
||||
}
|
||||
|
||||
// Case 2: resolve in module scope, expand during name resolution.
|
||||
|
|
|
@ -4,7 +4,10 @@ use base_db::CrateId;
|
|||
use cfg::{CfgExpr, CfgOptions};
|
||||
use hir_expand::{attrs::AttrId, MacroCallKind};
|
||||
use la_arena::Idx;
|
||||
use syntax::ast::{self, AnyHasAttrs};
|
||||
use syntax::{
|
||||
ast::{self, AnyHasAttrs},
|
||||
SyntaxError,
|
||||
};
|
||||
|
||||
use crate::{
|
||||
item_tree::{self, ItemTreeId},
|
||||
|
@ -29,6 +32,8 @@ pub enum DefDiagnosticKind {
|
|||
|
||||
MacroError { ast: MacroCallKind, message: String },
|
||||
|
||||
MacroExpansionParseError { ast: MacroCallKind, errors: Box<[SyntaxError]> },
|
||||
|
||||
UnimplementedBuiltinMacro { ast: AstId<ast::Macro> },
|
||||
|
||||
InvalidDeriveTarget { ast: AstId<ast::Item>, id: usize },
|
||||
|
@ -91,7 +96,7 @@ impl DefDiagnostic {
|
|||
Self { in_module: container, kind: DefDiagnosticKind::UnresolvedProcMacro { ast, krate } }
|
||||
}
|
||||
|
||||
pub(super) fn macro_error(
|
||||
pub(crate) fn macro_error(
|
||||
container: LocalModuleId,
|
||||
ast: MacroCallKind,
|
||||
message: String,
|
||||
|
@ -99,6 +104,20 @@ impl DefDiagnostic {
|
|||
Self { in_module: container, kind: DefDiagnosticKind::MacroError { ast, message } }
|
||||
}
|
||||
|
||||
pub(crate) fn macro_expansion_parse_error(
|
||||
container: LocalModuleId,
|
||||
ast: MacroCallKind,
|
||||
errors: &[SyntaxError],
|
||||
) -> Self {
|
||||
Self {
|
||||
in_module: container,
|
||||
kind: DefDiagnosticKind::MacroExpansionParseError {
|
||||
ast,
|
||||
errors: errors.to_vec().into_boxed_slice(),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn unresolved_macro_call(
|
||||
container: LocalModuleId,
|
||||
ast: MacroCallKind,
|
||||
|
|
|
@ -140,7 +140,7 @@ m!(Z);
|
|||
let n_recalculated_item_trees = events.iter().filter(|it| it.contains("item_tree")).count();
|
||||
assert_eq!(n_recalculated_item_trees, 6);
|
||||
let n_reparsed_macros =
|
||||
events.iter().filter(|it| it.contains("parse_macro_expansion")).count();
|
||||
events.iter().filter(|it| it.contains("parse_macro_expansion(")).count();
|
||||
assert_eq!(n_reparsed_macros, 3);
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue