mirror of
https://github.com/rust-lang/rust-analyzer
synced 2024-12-29 06:23:25 +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 once_cell::unsync::OnceCell;
|
||||||
use profile::Count;
|
use profile::Count;
|
||||||
use rustc_hash::FxHashMap;
|
use rustc_hash::FxHashMap;
|
||||||
use syntax::{ast, AstPtr, SyntaxNode, SyntaxNodePtr};
|
use syntax::{ast, AstPtr, Parse, SyntaxNode, SyntaxNodePtr};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
attr::Attrs,
|
attr::Attrs,
|
||||||
|
@ -137,7 +137,8 @@ impl Expander {
|
||||||
&mut self,
|
&mut self,
|
||||||
db: &dyn DefDatabase,
|
db: &dyn DefDatabase,
|
||||||
macro_call: ast::MacroCall,
|
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 mut unresolved_macro_err = None;
|
||||||
|
|
||||||
let result = self.within_limit(db, |this| {
|
let result = self.within_limit(db, |this| {
|
||||||
|
@ -146,22 +147,13 @@ impl Expander {
|
||||||
let resolver =
|
let resolver =
|
||||||
|path| this.resolve_path_as_macro(db, &path).map(|it| macro_id_to_def_id(db, it));
|
|path| this.resolve_path_as_macro(db, &path).map(|it| macro_id_to_def_id(db, it));
|
||||||
|
|
||||||
let mut err = None;
|
match macro_call.as_call_id_with_errors(db, this.def_map.krate(), resolver) {
|
||||||
let call_id = match macro_call.as_call_id_with_errors(
|
|
||||||
db,
|
|
||||||
this.def_map.krate(),
|
|
||||||
resolver,
|
|
||||||
&mut |e| {
|
|
||||||
err.get_or_insert(e);
|
|
||||||
},
|
|
||||||
) {
|
|
||||||
Ok(call_id) => call_id,
|
Ok(call_id) => call_id,
|
||||||
Err(resolve_err) => {
|
Err(resolve_err) => {
|
||||||
unresolved_macro_err = Some(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 {
|
if let Some(err) = unresolved_macro_err {
|
||||||
|
@ -175,37 +167,37 @@ impl Expander {
|
||||||
&mut self,
|
&mut self,
|
||||||
db: &dyn DefDatabase,
|
db: &dyn DefDatabase,
|
||||||
call_id: MacroCallId,
|
call_id: MacroCallId,
|
||||||
) -> ExpandResult<Option<(Mark, T)>> {
|
) -> ExpandResult<Option<(Mark, Parse<T>)>> {
|
||||||
self.within_limit(db, |_this| ExpandResult::ok(Some(call_id)))
|
self.within_limit(db, |_this| ExpandResult::ok(Some(call_id)))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn enter_expand_inner(
|
fn enter_expand_inner(
|
||||||
db: &dyn DefDatabase,
|
db: &dyn DefDatabase,
|
||||||
call_id: MacroCallId,
|
call_id: MacroCallId,
|
||||||
mut err: Option<ExpandError>,
|
mut error: Option<ExpandError>,
|
||||||
) -> ExpandResult<Option<(HirFileId, SyntaxNode)>> {
|
) -> ExpandResult<Option<InFile<Parse<SyntaxNode>>>> {
|
||||||
if err.is_none() {
|
let file_id = call_id.as_file();
|
||||||
err = db.macro_expand_error(call_id);
|
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 parse = match value {
|
||||||
|
Some(it) => it,
|
||||||
let raw_node = match db.parse_or_expand_with_err(file_id) {
|
|
||||||
// FIXME: report parse errors
|
|
||||||
Some(it) => it.syntax_node(),
|
|
||||||
None => {
|
None => {
|
||||||
// Only `None` if the macro expansion produced no usable AST.
|
// 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");
|
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())
|
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) {
|
pub fn exit(&mut self, db: &dyn DefDatabase, mut mark: Mark) {
|
||||||
|
@ -267,7 +259,7 @@ impl Expander {
|
||||||
&mut self,
|
&mut self,
|
||||||
db: &dyn DefDatabase,
|
db: &dyn DefDatabase,
|
||||||
op: F,
|
op: F,
|
||||||
) -> ExpandResult<Option<(Mark, T)>>
|
) -> ExpandResult<Option<(Mark, Parse<T>)>>
|
||||||
where
|
where
|
||||||
F: FnOnce(&mut Self) -> ExpandResult<Option<MacroCallId>>,
|
F: FnOnce(&mut Self) -> ExpandResult<Option<MacroCallId>>,
|
||||||
{
|
{
|
||||||
|
@ -294,15 +286,15 @@ impl Expander {
|
||||||
};
|
};
|
||||||
|
|
||||||
Self::enter_expand_inner(db, call_id, err).map(|value| {
|
Self::enter_expand_inner(db, call_id, err).map(|value| {
|
||||||
value.and_then(|(new_file_id, node)| {
|
value.and_then(|InFile { file_id, value }| {
|
||||||
let node = T::cast(node)?;
|
let parse = value.cast::<T>()?;
|
||||||
|
|
||||||
self.recursion_depth += 1;
|
self.recursion_depth += 1;
|
||||||
self.cfg_expander.hygiene = Hygiene::new(db.upcast(), 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, new_file_id);
|
let old_file_id = std::mem::replace(&mut self.current_file_id, file_id);
|
||||||
let mark =
|
let mark =
|
||||||
Mark { file_id: old_file_id, bomb: DropBomb::new("expansion mark dropped") };
|
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),
|
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.ast_id_map = prev_ast_id_map;
|
||||||
self.expander.exit(self.db, mark);
|
self.expander.exit(self.db, mark);
|
||||||
id
|
id
|
||||||
|
|
|
@ -7,7 +7,7 @@ use std::sync::Arc;
|
||||||
use hir_expand::{name::Name, AstId, ExpandResult, HirFileId, InFile, MacroCallId, MacroDefKind};
|
use hir_expand::{name::Name, AstId, ExpandResult, HirFileId, InFile, MacroCallId, MacroDefKind};
|
||||||
use intern::Interned;
|
use intern::Interned;
|
||||||
use smallvec::SmallVec;
|
use smallvec::SmallVec;
|
||||||
use syntax::ast;
|
use syntax::{ast, Parse};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
attr::Attrs,
|
attr::Attrs,
|
||||||
|
@ -604,13 +604,10 @@ impl<'a> AssocItemCollector<'a> {
|
||||||
continue 'attrs;
|
continue 'attrs;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
match self.expander.enter_expand_id::<ast::MacroItems>(self.db, call_id) {
|
|
||||||
ExpandResult { value: Some((mark, _)), .. } => {
|
let res = self.expander.enter_expand_id::<ast::MacroItems>(self.db, call_id);
|
||||||
self.collect_macro_items(mark);
|
self.collect_macro_items(res, &|| loc.kind.clone());
|
||||||
continue 'items;
|
continue 'items;
|
||||||
}
|
|
||||||
ExpandResult { .. } => {}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -641,22 +638,23 @@ impl<'a> AssocItemCollector<'a> {
|
||||||
self.items.push((item.name.clone(), def.into()));
|
self.items.push((item.name.clone(), def.into()));
|
||||||
}
|
}
|
||||||
AssocItem::MacroCall(call) => {
|
AssocItem::MacroCall(call) => {
|
||||||
if let Some(root) =
|
let file_id = self.expander.current_file_id();
|
||||||
self.db.parse_or_expand_with_err(self.expander.current_file_id())
|
let root = self.db.parse_or_expand(file_id);
|
||||||
{
|
if let Some(root) = root {
|
||||||
// FIXME: report parse errors
|
|
||||||
let root = root.syntax_node();
|
|
||||||
|
|
||||||
let call = &item_tree[call];
|
let call = &item_tree[call];
|
||||||
|
|
||||||
let ast_id_map = self.db.ast_id_map(self.expander.current_file_id());
|
let ast_id_map = self.db.ast_id_map(file_id);
|
||||||
let call = ast_id_map.get(call.ast_id).to_node(&root);
|
let macro_call = ast_id_map.get(call.ast_id).to_node(&root);
|
||||||
let _cx =
|
let _cx = stdx::panic_context::enter(format!(
|
||||||
stdx::panic_context::enter(format!("collect_items MacroCall: {call}"));
|
"collect_items MacroCall: {macro_call}"
|
||||||
let res = self.expander.enter_expand::<ast::MacroItems>(self.db, call);
|
));
|
||||||
|
if let Ok(res) =
|
||||||
if let Ok(ExpandResult { value: Some((mark, _)), .. }) = res {
|
self.expander.enter_expand::<ast::MacroItems>(self.db, macro_call)
|
||||||
self.collect_macro_items(mark);
|
{
|
||||||
|
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 tree_id = item_tree::TreeId::new(self.expander.current_file_id(), None);
|
||||||
let item_tree = tree_id.item_tree(self.db);
|
let item_tree = tree_id.item_tree(self.db);
|
||||||
let iter: SmallVec<[_; 2]> =
|
let iter: SmallVec<[_; 2]> =
|
||||||
|
|
|
@ -350,7 +350,7 @@ impl GenericParams {
|
||||||
match expander.enter_expand::<ast::Type>(db, macro_call) {
|
match expander.enter_expand::<ast::Type>(db, macro_call) {
|
||||||
Ok(ExpandResult { value: Some((mark, expanded)), .. }) => {
|
Ok(ExpandResult { value: Some((mark, expanded)), .. }) => {
|
||||||
let ctx = expander.ctx(db);
|
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);
|
self.fill_implicit_impl_trait_args(db, expander, &type_ref);
|
||||||
expander.exit(db, mark);
|
expander.exit(db, mark);
|
||||||
}
|
}
|
||||||
|
|
|
@ -101,6 +101,7 @@ pub struct ItemTree {
|
||||||
top_level: SmallVec<[ModItem; 1]>,
|
top_level: SmallVec<[ModItem; 1]>,
|
||||||
attrs: FxHashMap<AttrOwner, RawAttrs>,
|
attrs: FxHashMap<AttrOwner, RawAttrs>,
|
||||||
|
|
||||||
|
// FIXME: Remove this indirection, an item tree is almost always non-empty?
|
||||||
data: Option<Box<ItemTreeData>>,
|
data: Option<Box<ItemTreeData>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -65,11 +65,11 @@ use hir_expand::{
|
||||||
builtin_attr_macro::BuiltinAttrExpander,
|
builtin_attr_macro::BuiltinAttrExpander,
|
||||||
builtin_derive_macro::BuiltinDeriveExpander,
|
builtin_derive_macro::BuiltinDeriveExpander,
|
||||||
builtin_fn_macro::{BuiltinFnLikeExpander, EagerExpander},
|
builtin_fn_macro::{BuiltinFnLikeExpander, EagerExpander},
|
||||||
eager::{expand_eager_macro, ErrorEmitted, ErrorSink},
|
eager::expand_eager_macro,
|
||||||
hygiene::Hygiene,
|
hygiene::Hygiene,
|
||||||
proc_macro::ProcMacroExpander,
|
proc_macro::ProcMacroExpander,
|
||||||
AstId, ExpandError, ExpandTo, HirFileId, InFile, MacroCallId, MacroCallKind, MacroDefId,
|
AstId, ExpandError, ExpandResult, ExpandTo, HirFileId, InFile, MacroCallId, MacroCallKind,
|
||||||
MacroDefKind, UnresolvedMacro,
|
MacroDefId, MacroDefKind, UnresolvedMacro,
|
||||||
};
|
};
|
||||||
use item_tree::ExternBlock;
|
use item_tree::ExternBlock;
|
||||||
use la_arena::Idx;
|
use la_arena::Idx;
|
||||||
|
@ -795,7 +795,7 @@ pub trait AsMacroCall {
|
||||||
krate: CrateId,
|
krate: CrateId,
|
||||||
resolver: impl Fn(path::ModPath) -> Option<MacroDefId>,
|
resolver: impl Fn(path::ModPath) -> Option<MacroDefId>,
|
||||||
) -> Option<MacroCallId> {
|
) -> 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(
|
fn as_call_id_with_errors(
|
||||||
|
@ -803,8 +803,7 @@ pub trait AsMacroCall {
|
||||||
db: &dyn db::DefDatabase,
|
db: &dyn db::DefDatabase,
|
||||||
krate: CrateId,
|
krate: CrateId,
|
||||||
resolver: impl Fn(path::ModPath) -> Option<MacroDefId>,
|
resolver: impl Fn(path::ModPath) -> Option<MacroDefId>,
|
||||||
error_sink: &mut dyn FnMut(ExpandError),
|
) -> Result<ExpandResult<Option<MacroCallId>>, UnresolvedMacro>;
|
||||||
) -> Result<Result<MacroCallId, ErrorEmitted>, UnresolvedMacro>;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AsMacroCall for InFile<&ast::MacroCall> {
|
impl AsMacroCall for InFile<&ast::MacroCall> {
|
||||||
|
@ -813,30 +812,23 @@ impl AsMacroCall for InFile<&ast::MacroCall> {
|
||||||
db: &dyn db::DefDatabase,
|
db: &dyn db::DefDatabase,
|
||||||
krate: CrateId,
|
krate: CrateId,
|
||||||
resolver: impl Fn(path::ModPath) -> Option<MacroDefId>,
|
resolver: impl Fn(path::ModPath) -> Option<MacroDefId>,
|
||||||
mut error_sink: &mut dyn FnMut(ExpandError),
|
) -> Result<ExpandResult<Option<MacroCallId>>, UnresolvedMacro> {
|
||||||
) -> Result<Result<MacroCallId, ErrorEmitted>, UnresolvedMacro> {
|
|
||||||
let expands_to = hir_expand::ExpandTo::from_call_site(self.value);
|
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 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 h = Hygiene::new(db.upcast(), self.file_id);
|
||||||
let path =
|
let path =
|
||||||
self.value.path().and_then(|path| path::ModPath::from_src(db.upcast(), path, &h));
|
self.value.path().and_then(|path| path::ModPath::from_src(db.upcast(), path, &h));
|
||||||
|
|
||||||
let path = match error_sink
|
let Some(path) = path else {
|
||||||
.option(path, || ExpandError::Other("malformed macro invocation".into()))
|
return Ok(ExpandResult::only_err(ExpandError::Other("malformed macro invocation".into())));
|
||||||
{
|
|
||||||
Ok(path) => path,
|
|
||||||
Err(error) => {
|
|
||||||
return Ok(Err(error));
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
macro_call_as_call_id(
|
macro_call_as_call_id_(
|
||||||
db,
|
db,
|
||||||
&AstIdWithPath::new(ast_id.file_id, ast_id.value, path),
|
&AstIdWithPath::new(ast_id.file_id, ast_id.value, path),
|
||||||
expands_to,
|
expands_to,
|
||||||
krate,
|
krate,
|
||||||
resolver,
|
resolver,
|
||||||
error_sink,
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -860,21 +852,33 @@ fn macro_call_as_call_id(
|
||||||
expand_to: ExpandTo,
|
expand_to: ExpandTo,
|
||||||
krate: CrateId,
|
krate: CrateId,
|
||||||
resolver: impl Fn(path::ModPath) -> Option<MacroDefId>,
|
resolver: impl Fn(path::ModPath) -> Option<MacroDefId>,
|
||||||
error_sink: &mut dyn FnMut(ExpandError),
|
) -> Result<Option<MacroCallId>, UnresolvedMacro> {
|
||||||
) -> Result<Result<MacroCallId, ErrorEmitted>, 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 =
|
let def =
|
||||||
resolver(call.path.clone()).ok_or_else(|| UnresolvedMacro { path: call.path.clone() })?;
|
resolver(call.path.clone()).ok_or_else(|| UnresolvedMacro { path: call.path.clone() })?;
|
||||||
|
|
||||||
let res = if let MacroDefKind::BuiltInEager(..) = def.kind {
|
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()));
|
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 {
|
} else {
|
||||||
Ok(def.as_lazy_macro(
|
ExpandResult {
|
||||||
db.upcast(),
|
value: Some(def.as_lazy_macro(
|
||||||
krate,
|
db.upcast(),
|
||||||
MacroCallKind::FnLike { ast_id: call.ast_id, expand_to },
|
krate,
|
||||||
))
|
MacroCallKind::FnLike { ast_id: call.ast_id, expand_to },
|
||||||
|
)),
|
||||||
|
err: None,
|
||||||
|
}
|
||||||
};
|
};
|
||||||
Ok(res)
|
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) {
|
for macro_call in source_file.syntax().descendants().filter_map(ast::MacroCall::cast) {
|
||||||
let macro_call = InFile::new(source.file_id, ¯o_call);
|
let macro_call = InFile::new(source.file_id, ¯o_call);
|
||||||
let mut error = None;
|
let res = macro_call
|
||||||
let macro_call_id = macro_call
|
.as_call_id_with_errors(&db, krate, |path| {
|
||||||
.as_call_id_with_errors(
|
resolver.resolve_path_as_macro(&db, &path).map(|it| macro_id_to_def_id(&db, it))
|
||||||
&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()
|
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
let macro_call_id = res.value.unwrap();
|
||||||
let macro_file = MacroFile { macro_call_id };
|
let macro_file = MacroFile { macro_call_id };
|
||||||
let mut expansion_result = db.parse_macro_expansion(macro_file);
|
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)));
|
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,
|
builtin_fn_macro::find_builtin_macro,
|
||||||
name::{name, AsName, Name},
|
name::{name, AsName, Name},
|
||||||
proc_macro::ProcMacroExpander,
|
proc_macro::ProcMacroExpander,
|
||||||
ExpandTo, HirFileId, InFile, MacroCallId, MacroCallKind, MacroCallLoc, MacroDefId,
|
ExpandResult, ExpandTo, HirFileId, InFile, MacroCallId, MacroCallKind, MacroCallLoc,
|
||||||
MacroDefKind,
|
MacroDefId, MacroDefKind,
|
||||||
};
|
};
|
||||||
use itertools::{izip, Itertools};
|
use itertools::{izip, Itertools};
|
||||||
use la_arena::Idx;
|
use la_arena::Idx;
|
||||||
|
@ -1116,10 +1116,10 @@ impl DefCollector<'_> {
|
||||||
*expand_to,
|
*expand_to,
|
||||||
self.def_map.krate,
|
self.def_map.krate,
|
||||||
resolver_def_id,
|
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);
|
push_resolved(directive, call_id);
|
||||||
|
|
||||||
res = ReachedFixedPoint::No;
|
res = ReachedFixedPoint::No;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -1355,26 +1355,30 @@ impl DefCollector<'_> {
|
||||||
let file_id = macro_call_id.as_file();
|
let file_id = macro_call_id.as_file();
|
||||||
|
|
||||||
// First, fetch the raw expansion result for purposes of error reporting. This goes through
|
// 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).
|
// incrementality).
|
||||||
let loc: MacroCallLoc = self.db.lookup_intern_macro_call(macro_call_id);
|
let ExpandResult { value, err } = self.db.parse_macro_expansion_error(macro_call_id);
|
||||||
let err = self.db.macro_expand_error(macro_call_id);
|
|
||||||
if let Some(err) = err {
|
if let Some(err) = err {
|
||||||
|
let loc: MacroCallLoc = self.db.lookup_intern_macro_call(macro_call_id);
|
||||||
let diag = match err {
|
let diag = match err {
|
||||||
|
// why is this reported here?
|
||||||
hir_expand::ExpandError::UnresolvedProcMacro(krate) => {
|
hir_expand::ExpandError::UnresolvedProcMacro(krate) => {
|
||||||
always!(krate == loc.def.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::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);
|
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.
|
// 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);
|
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();
|
let mod_dir = self.mod_dirs[&module_id].clone();
|
||||||
ModCollector {
|
ModCollector {
|
||||||
|
@ -1396,6 +1400,7 @@ impl DefCollector<'_> {
|
||||||
for directive in &self.unresolved_macros {
|
for directive in &self.unresolved_macros {
|
||||||
match &directive.kind {
|
match &directive.kind {
|
||||||
MacroDirectiveKind::FnLike { ast_id, expand_to } => {
|
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(
|
let macro_call_as_call_id = macro_call_as_call_id(
|
||||||
self.db,
|
self.db,
|
||||||
ast_id,
|
ast_id,
|
||||||
|
@ -1414,7 +1419,6 @@ impl DefCollector<'_> {
|
||||||
.take_macros()
|
.take_macros()
|
||||||
.map(|it| macro_id_to_def_id(self.db, it))
|
.map(|it| macro_id_to_def_id(self.db, it))
|
||||||
},
|
},
|
||||||
&mut |_| (),
|
|
||||||
);
|
);
|
||||||
if let Err(UnresolvedMacro { path }) = macro_call_as_call_id {
|
if let Err(UnresolvedMacro { path }) = macro_call_as_call_id {
|
||||||
self.def_map.diagnostics.push(DefDiagnostic::unresolved_macro_call(
|
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));
|
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
|
// Case 1: try to resolve in legacy scope and expand macro_rules
|
||||||
let mut error = None;
|
if let Ok(res) = macro_call_as_call_id(
|
||||||
match macro_call_as_call_id(
|
|
||||||
self.def_collector.db,
|
self.def_collector.db,
|
||||||
&ast_id,
|
&ast_id,
|
||||||
mac.expand_to,
|
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
|
||||||
// Legacy macros need to be expanded immediately, so that any macros they produce
|
// are in scope.
|
||||||
// are in scope.
|
if let Some(val) = res {
|
||||||
self.def_collector.collect_macro_expansion(
|
self.def_collector.collect_macro_expansion(
|
||||||
self.module_id,
|
self.module_id,
|
||||||
macro_call_id,
|
val,
|
||||||
self.macro_depth + 1,
|
self.macro_depth + 1,
|
||||||
container,
|
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(
|
return;
|
||||||
self.module_id,
|
|
||||||
MacroCallKind::FnLike { ast_id: ast_id.ast_id, expand_to: mac.expand_to },
|
|
||||||
error.unwrap().to_string(),
|
|
||||||
));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
Err(UnresolvedMacro { .. }) => (),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Case 2: resolve in module scope, expand during name resolution.
|
// Case 2: resolve in module scope, expand during name resolution.
|
||||||
|
|
|
@ -4,7 +4,10 @@ use base_db::CrateId;
|
||||||
use cfg::{CfgExpr, CfgOptions};
|
use cfg::{CfgExpr, CfgOptions};
|
||||||
use hir_expand::{attrs::AttrId, MacroCallKind};
|
use hir_expand::{attrs::AttrId, MacroCallKind};
|
||||||
use la_arena::Idx;
|
use la_arena::Idx;
|
||||||
use syntax::ast::{self, AnyHasAttrs};
|
use syntax::{
|
||||||
|
ast::{self, AnyHasAttrs},
|
||||||
|
SyntaxError,
|
||||||
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
item_tree::{self, ItemTreeId},
|
item_tree::{self, ItemTreeId},
|
||||||
|
@ -29,6 +32,8 @@ pub enum DefDiagnosticKind {
|
||||||
|
|
||||||
MacroError { ast: MacroCallKind, message: String },
|
MacroError { ast: MacroCallKind, message: String },
|
||||||
|
|
||||||
|
MacroExpansionParseError { ast: MacroCallKind, errors: Box<[SyntaxError]> },
|
||||||
|
|
||||||
UnimplementedBuiltinMacro { ast: AstId<ast::Macro> },
|
UnimplementedBuiltinMacro { ast: AstId<ast::Macro> },
|
||||||
|
|
||||||
InvalidDeriveTarget { ast: AstId<ast::Item>, id: usize },
|
InvalidDeriveTarget { ast: AstId<ast::Item>, id: usize },
|
||||||
|
@ -91,7 +96,7 @@ impl DefDiagnostic {
|
||||||
Self { in_module: container, kind: DefDiagnosticKind::UnresolvedProcMacro { ast, krate } }
|
Self { in_module: container, kind: DefDiagnosticKind::UnresolvedProcMacro { ast, krate } }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn macro_error(
|
pub(crate) fn macro_error(
|
||||||
container: LocalModuleId,
|
container: LocalModuleId,
|
||||||
ast: MacroCallKind,
|
ast: MacroCallKind,
|
||||||
message: String,
|
message: String,
|
||||||
|
@ -99,6 +104,20 @@ impl DefDiagnostic {
|
||||||
Self { in_module: container, kind: DefDiagnosticKind::MacroError { ast, message } }
|
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(
|
pub(super) fn unresolved_macro_call(
|
||||||
container: LocalModuleId,
|
container: LocalModuleId,
|
||||||
ast: MacroCallKind,
|
ast: MacroCallKind,
|
||||||
|
|
|
@ -140,7 +140,7 @@ m!(Z);
|
||||||
let n_recalculated_item_trees = events.iter().filter(|it| it.contains("item_tree")).count();
|
let n_recalculated_item_trees = events.iter().filter(|it| it.contains("item_tree")).count();
|
||||||
assert_eq!(n_recalculated_item_trees, 6);
|
assert_eq!(n_recalculated_item_trees, 6);
|
||||||
let n_reparsed_macros =
|
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);
|
assert_eq!(n_reparsed_macros, 3);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -9,7 +9,7 @@ use mbe::syntax_node_to_token_tree;
|
||||||
use rustc_hash::FxHashSet;
|
use rustc_hash::FxHashSet;
|
||||||
use syntax::{
|
use syntax::{
|
||||||
ast::{self, HasAttrs, HasDocComments},
|
ast::{self, HasAttrs, HasDocComments},
|
||||||
AstNode, GreenNode, Parse, SyntaxNode, SyntaxToken, T,
|
AstNode, GreenNode, Parse, SyntaxError, SyntaxNode, SyntaxToken, T,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
@ -100,7 +100,10 @@ pub trait ExpandDatabase: SourceDatabase {
|
||||||
#[salsa::transparent]
|
#[salsa::transparent]
|
||||||
fn parse_or_expand(&self, file_id: HirFileId) -> Option<SyntaxNode>;
|
fn parse_or_expand(&self, file_id: HirFileId) -> Option<SyntaxNode>;
|
||||||
#[salsa::transparent]
|
#[salsa::transparent]
|
||||||
fn parse_or_expand_with_err(&self, file_id: HirFileId) -> Option<Parse<SyntaxNode>>;
|
fn parse_or_expand_with_err(
|
||||||
|
&self,
|
||||||
|
file_id: HirFileId,
|
||||||
|
) -> ExpandResult<Option<Parse<SyntaxNode>>>;
|
||||||
/// Implementation for the macro case.
|
/// Implementation for the macro case.
|
||||||
fn parse_macro_expansion(
|
fn parse_macro_expansion(
|
||||||
&self,
|
&self,
|
||||||
|
@ -129,15 +132,18 @@ pub trait ExpandDatabase: SourceDatabase {
|
||||||
/// just fetches procedural ones.
|
/// just fetches procedural ones.
|
||||||
fn macro_def(&self, id: MacroDefId) -> Result<Arc<TokenExpander>, mbe::ParseError>;
|
fn macro_def(&self, id: MacroDefId) -> Result<Arc<TokenExpander>, mbe::ParseError>;
|
||||||
|
|
||||||
/// Expand macro call to a token tree. This query is LRUed (we keep 128 or so results in memory)
|
/// Expand macro call to a token tree.
|
||||||
fn macro_expand(&self, macro_call: MacroCallId) -> ExpandResult<Option<Arc<tt::Subtree>>>;
|
fn macro_expand(&self, macro_call: MacroCallId) -> ExpandResult<Option<Arc<tt::Subtree>>>;
|
||||||
/// Special case of the previous query for procedural macros. We can't LRU
|
/// Special case of the previous query for procedural macros. We can't LRU
|
||||||
/// proc macros, since they are not deterministic in general, and
|
/// proc macros, since they are not deterministic in general, and
|
||||||
/// non-determinism breaks salsa in a very, very, very bad way. @edwin0cheng
|
/// non-determinism breaks salsa in a very, very, very bad way. @edwin0cheng
|
||||||
/// heroically debugged this once!
|
/// heroically debugged this once!
|
||||||
fn expand_proc_macro(&self, call: MacroCallId) -> ExpandResult<tt::Subtree>;
|
fn expand_proc_macro(&self, call: MacroCallId) -> ExpandResult<tt::Subtree>;
|
||||||
/// Firewall query that returns the error from the `macro_expand` query.
|
/// Firewall query that returns the errors from the `parse_macro_expansion` query.
|
||||||
fn macro_expand_error(&self, macro_call: MacroCallId) -> Option<ExpandError>;
|
fn parse_macro_expansion_error(
|
||||||
|
&self,
|
||||||
|
macro_call: MacroCallId,
|
||||||
|
) -> ExpandResult<Option<Box<[SyntaxError]>>>;
|
||||||
|
|
||||||
fn hygiene_frame(&self, file_id: HirFileId) -> Arc<HygieneFrame>;
|
fn hygiene_frame(&self, file_id: HirFileId) -> Arc<HygieneFrame>;
|
||||||
}
|
}
|
||||||
|
@ -262,11 +268,11 @@ fn parse_or_expand(db: &dyn ExpandDatabase, file_id: HirFileId) -> Option<Syntax
|
||||||
fn parse_or_expand_with_err(
|
fn parse_or_expand_with_err(
|
||||||
db: &dyn ExpandDatabase,
|
db: &dyn ExpandDatabase,
|
||||||
file_id: HirFileId,
|
file_id: HirFileId,
|
||||||
) -> Option<Parse<SyntaxNode>> {
|
) -> ExpandResult<Option<Parse<SyntaxNode>>> {
|
||||||
match file_id.repr() {
|
match file_id.repr() {
|
||||||
HirFileIdRepr::FileId(file_id) => Some(db.parse(file_id).to_syntax()),
|
HirFileIdRepr::FileId(file_id) => ExpandResult::ok(Some(db.parse(file_id).to_syntax())),
|
||||||
HirFileIdRepr::MacroFile(macro_file) => {
|
HirFileIdRepr::MacroFile(macro_file) => {
|
||||||
db.parse_macro_expansion(macro_file).value.map(|(parse, _)| parse)
|
db.parse_macro_expansion(macro_file).map(|it| it.map(|(parse, _)| parse))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -279,25 +285,28 @@ fn parse_macro_expansion(
|
||||||
let mbe::ValueResult { value, err } = db.macro_expand(macro_file.macro_call_id);
|
let mbe::ValueResult { value, err } = db.macro_expand(macro_file.macro_call_id);
|
||||||
|
|
||||||
if let Some(err) = &err {
|
if let Some(err) = &err {
|
||||||
// Note:
|
if tracing::enabled!(tracing::Level::DEBUG) {
|
||||||
// The final goal we would like to make all parse_macro success,
|
// Note:
|
||||||
// such that the following log will not call anyway.
|
// The final goal we would like to make all parse_macro success,
|
||||||
let loc: MacroCallLoc = db.lookup_intern_macro_call(macro_file.macro_call_id);
|
// such that the following log will not call anyway.
|
||||||
let node = loc.kind.to_node(db);
|
let loc: MacroCallLoc = db.lookup_intern_macro_call(macro_file.macro_call_id);
|
||||||
|
let node = loc.kind.to_node(db);
|
||||||
|
|
||||||
// collect parent information for warning log
|
// collect parent information for warning log
|
||||||
let parents =
|
let parents = std::iter::successors(loc.kind.file_id().call_node(db), |it| {
|
||||||
std::iter::successors(loc.kind.file_id().call_node(db), |it| it.file_id.call_node(db))
|
it.file_id.call_node(db)
|
||||||
.map(|n| format!("{:#}", n.value))
|
})
|
||||||
.collect::<Vec<_>>()
|
.map(|n| format!("{:#}", n.value))
|
||||||
.join("\n");
|
.collect::<Vec<_>>()
|
||||||
|
.join("\n");
|
||||||
|
|
||||||
tracing::debug!(
|
tracing::debug!(
|
||||||
"fail on macro_parse: (reason: {:?} macro_call: {:#}) parents: {}",
|
"fail on macro_parse: (reason: {:?} macro_call: {:#}) parents: {}",
|
||||||
err,
|
err,
|
||||||
node.value,
|
node.value,
|
||||||
parents
|
parents
|
||||||
);
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
let tt = match value {
|
let tt = match value {
|
||||||
Some(tt) => tt,
|
Some(tt) => tt,
|
||||||
|
@ -442,14 +451,14 @@ fn macro_def(
|
||||||
fn macro_expand(
|
fn macro_expand(
|
||||||
db: &dyn ExpandDatabase,
|
db: &dyn ExpandDatabase,
|
||||||
id: MacroCallId,
|
id: MacroCallId,
|
||||||
|
// FIXME: Remove the OPtion if possible
|
||||||
) -> ExpandResult<Option<Arc<tt::Subtree>>> {
|
) -> ExpandResult<Option<Arc<tt::Subtree>>> {
|
||||||
let _p = profile::span("macro_expand");
|
let _p = profile::span("macro_expand");
|
||||||
let loc: MacroCallLoc = db.lookup_intern_macro_call(id);
|
let loc: MacroCallLoc = db.lookup_intern_macro_call(id);
|
||||||
if let Some(eager) = &loc.eager {
|
if let Some(eager) = &loc.eager {
|
||||||
return ExpandResult {
|
return ExpandResult {
|
||||||
value: Some(eager.arg_or_expansion.clone()),
|
value: Some(eager.arg_or_expansion.clone()),
|
||||||
// FIXME: There could be errors here!
|
err: eager.error.clone(),
|
||||||
err: None,
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -466,7 +475,8 @@ fn macro_expand(
|
||||||
Ok(it) => it,
|
Ok(it) => it,
|
||||||
// FIXME: This is weird -- we effectively report macro *definition*
|
// FIXME: This is weird -- we effectively report macro *definition*
|
||||||
// errors lazily, when we try to expand the macro. Instead, they should
|
// errors lazily, when we try to expand the macro. Instead, they should
|
||||||
// be reported at the definition site (when we construct a def map).
|
// be reported at the definition site when we construct a def map.
|
||||||
|
// (Note we do report them also at the definition site in the late diagnostic pass)
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
return ExpandResult::only_err(ExpandError::Other(
|
return ExpandResult::only_err(ExpandError::Other(
|
||||||
format!("invalid macro definition: {err}").into(),
|
format!("invalid macro definition: {err}").into(),
|
||||||
|
@ -492,8 +502,12 @@ fn macro_expand(
|
||||||
ExpandResult { value: Some(Arc::new(tt)), err }
|
ExpandResult { value: Some(Arc::new(tt)), err }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn macro_expand_error(db: &dyn ExpandDatabase, macro_call: MacroCallId) -> Option<ExpandError> {
|
fn parse_macro_expansion_error(
|
||||||
db.macro_expand(macro_call).err
|
db: &dyn ExpandDatabase,
|
||||||
|
macro_call_id: MacroCallId,
|
||||||
|
) -> ExpandResult<Option<Box<[SyntaxError]>>> {
|
||||||
|
db.parse_macro_expansion(MacroFile { macro_call_id })
|
||||||
|
.map(|it| it.map(|(it, _)| it.errors().to_vec().into_boxed_slice()))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn expand_proc_macro(db: &dyn ExpandDatabase, id: MacroCallId) -> ExpandResult<tt::Subtree> {
|
fn expand_proc_macro(db: &dyn ExpandDatabase, id: MacroCallId) -> ExpandResult<tt::Subtree> {
|
||||||
|
|
|
@ -21,7 +21,7 @@
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use base_db::CrateId;
|
use base_db::CrateId;
|
||||||
use syntax::{ted, SyntaxNode};
|
use syntax::{ted, Parse, SyntaxNode};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
ast::{self, AstNode},
|
ast::{self, AstNode},
|
||||||
|
@ -32,77 +32,16 @@ use crate::{
|
||||||
MacroCallLoc, MacroDefId, MacroDefKind, UnresolvedMacro,
|
MacroCallLoc, MacroDefId, MacroDefKind, UnresolvedMacro,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct ErrorEmitted {
|
|
||||||
_private: (),
|
|
||||||
}
|
|
||||||
|
|
||||||
pub trait ErrorSink {
|
|
||||||
fn emit(&mut self, err: ExpandError);
|
|
||||||
|
|
||||||
fn option<T>(
|
|
||||||
&mut self,
|
|
||||||
opt: Option<T>,
|
|
||||||
error: impl FnOnce() -> ExpandError,
|
|
||||||
) -> Result<T, ErrorEmitted> {
|
|
||||||
match opt {
|
|
||||||
Some(it) => Ok(it),
|
|
||||||
None => {
|
|
||||||
self.emit(error());
|
|
||||||
Err(ErrorEmitted { _private: () })
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn option_with<T>(
|
|
||||||
&mut self,
|
|
||||||
opt: impl FnOnce() -> Option<T>,
|
|
||||||
error: impl FnOnce() -> ExpandError,
|
|
||||||
) -> Result<T, ErrorEmitted> {
|
|
||||||
self.option(opt(), error)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn result<T>(&mut self, res: Result<T, ExpandError>) -> Result<T, ErrorEmitted> {
|
|
||||||
match res {
|
|
||||||
Ok(it) => Ok(it),
|
|
||||||
Err(e) => {
|
|
||||||
self.emit(e);
|
|
||||||
Err(ErrorEmitted { _private: () })
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn expand_result_option<T>(&mut self, res: ExpandResult<Option<T>>) -> Result<T, ErrorEmitted> {
|
|
||||||
match (res.value, res.err) {
|
|
||||||
(None, Some(err)) => {
|
|
||||||
self.emit(err);
|
|
||||||
Err(ErrorEmitted { _private: () })
|
|
||||||
}
|
|
||||||
(Some(value), opt_err) => {
|
|
||||||
if let Some(err) = opt_err {
|
|
||||||
self.emit(err);
|
|
||||||
}
|
|
||||||
Ok(value)
|
|
||||||
}
|
|
||||||
(None, None) => unreachable!("`ExpandResult` without value or error"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ErrorSink for &'_ mut dyn FnMut(ExpandError) {
|
|
||||||
fn emit(&mut self, err: ExpandError) {
|
|
||||||
self(err);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn expand_eager_macro(
|
pub fn expand_eager_macro(
|
||||||
db: &dyn ExpandDatabase,
|
db: &dyn ExpandDatabase,
|
||||||
krate: CrateId,
|
krate: CrateId,
|
||||||
macro_call: InFile<ast::MacroCall>,
|
macro_call: InFile<ast::MacroCall>,
|
||||||
def: MacroDefId,
|
def: MacroDefId,
|
||||||
resolver: &dyn Fn(ModPath) -> Option<MacroDefId>,
|
resolver: &dyn Fn(ModPath) -> Option<MacroDefId>,
|
||||||
diagnostic_sink: &mut dyn FnMut(ExpandError),
|
) -> Result<ExpandResult<Option<MacroCallId>>, UnresolvedMacro> {
|
||||||
) -> Result<Result<MacroCallId, ErrorEmitted>, UnresolvedMacro> {
|
let MacroDefKind::BuiltInEager(eager, _) = def.kind else {
|
||||||
|
panic!("called `expand_eager_macro` on non-eager macro def {def:?}")
|
||||||
|
};
|
||||||
let hygiene = Hygiene::new(db, macro_call.file_id);
|
let hygiene = Hygiene::new(db, macro_call.file_id);
|
||||||
let parsed_args = macro_call
|
let parsed_args = macro_call
|
||||||
.value
|
.value
|
||||||
|
@ -121,48 +60,44 @@ pub fn expand_eager_macro(
|
||||||
let arg_id = db.intern_macro_call(MacroCallLoc {
|
let arg_id = db.intern_macro_call(MacroCallLoc {
|
||||||
def,
|
def,
|
||||||
krate,
|
krate,
|
||||||
eager: Some(EagerCallInfo {
|
eager: Some(Box::new(EagerCallInfo {
|
||||||
arg_or_expansion: Arc::new(parsed_args.clone()),
|
arg_or_expansion: Arc::new(parsed_args.clone()),
|
||||||
included_file: None,
|
included_file: None,
|
||||||
}),
|
error: None,
|
||||||
|
})),
|
||||||
kind: MacroCallKind::FnLike { ast_id: call_id, expand_to: ExpandTo::Expr },
|
kind: MacroCallKind::FnLike { ast_id: call_id, expand_to: ExpandTo::Expr },
|
||||||
});
|
});
|
||||||
|
|
||||||
let parsed_args = mbe::token_tree_to_syntax_node(&parsed_args, mbe::TopEntryPoint::Expr).0;
|
let parsed_args = mbe::token_tree_to_syntax_node(&parsed_args, mbe::TopEntryPoint::Expr).0;
|
||||||
let result = match eager_macro_recur(
|
let ExpandResult { value, mut err } = eager_macro_recur(
|
||||||
db,
|
db,
|
||||||
&hygiene,
|
&hygiene,
|
||||||
InFile::new(arg_id.as_file(), parsed_args.syntax_node()),
|
InFile::new(arg_id.as_file(), parsed_args.syntax_node()),
|
||||||
krate,
|
krate,
|
||||||
resolver,
|
resolver,
|
||||||
diagnostic_sink,
|
)?;
|
||||||
) {
|
let Some(value ) = value else {
|
||||||
Ok(Ok(it)) => it,
|
return Ok(ExpandResult { value: None, err })
|
||||||
Ok(Err(err)) => return Ok(Err(err)),
|
|
||||||
Err(err) => return Err(err),
|
|
||||||
};
|
};
|
||||||
let subtree = to_subtree(&result);
|
let subtree = to_subtree(&value);
|
||||||
|
|
||||||
if let MacroDefKind::BuiltInEager(eager, _) = def.kind {
|
let res = eager.expand(db, arg_id, &subtree);
|
||||||
let res = eager.expand(db, arg_id, &subtree);
|
if err.is_none() {
|
||||||
if let Some(err) = res.err {
|
err = res.err;
|
||||||
diagnostic_sink(err);
|
|
||||||
}
|
|
||||||
|
|
||||||
let loc = MacroCallLoc {
|
|
||||||
def,
|
|
||||||
krate,
|
|
||||||
eager: Some(EagerCallInfo {
|
|
||||||
arg_or_expansion: Arc::new(res.value.subtree),
|
|
||||||
included_file: res.value.included_file,
|
|
||||||
}),
|
|
||||||
kind: MacroCallKind::FnLike { ast_id: call_id, expand_to },
|
|
||||||
};
|
|
||||||
|
|
||||||
Ok(Ok(db.intern_macro_call(loc)))
|
|
||||||
} else {
|
|
||||||
panic!("called `expand_eager_macro` on non-eager macro def {def:?}");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let loc = MacroCallLoc {
|
||||||
|
def,
|
||||||
|
krate,
|
||||||
|
eager: Some(Box::new(EagerCallInfo {
|
||||||
|
arg_or_expansion: Arc::new(res.value.subtree),
|
||||||
|
included_file: res.value.included_file,
|
||||||
|
error: err.clone(),
|
||||||
|
})),
|
||||||
|
kind: MacroCallKind::FnLike { ast_id: call_id, expand_to },
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(ExpandResult { value: Some(db.intern_macro_call(loc)), err })
|
||||||
}
|
}
|
||||||
|
|
||||||
fn to_subtree(node: &SyntaxNode) -> crate::tt::Subtree {
|
fn to_subtree(node: &SyntaxNode) -> crate::tt::Subtree {
|
||||||
|
@ -176,7 +111,7 @@ fn lazy_expand(
|
||||||
def: &MacroDefId,
|
def: &MacroDefId,
|
||||||
macro_call: InFile<ast::MacroCall>,
|
macro_call: InFile<ast::MacroCall>,
|
||||||
krate: CrateId,
|
krate: CrateId,
|
||||||
) -> ExpandResult<Option<InFile<SyntaxNode>>> {
|
) -> ExpandResult<Option<InFile<Parse<SyntaxNode>>>> {
|
||||||
let ast_id = db.ast_id_map(macro_call.file_id).ast_id(¯o_call.value);
|
let ast_id = db.ast_id_map(macro_call.file_id).ast_id(¯o_call.value);
|
||||||
|
|
||||||
let expand_to = ExpandTo::from_call_site(¯o_call.value);
|
let expand_to = ExpandTo::from_call_site(¯o_call.value);
|
||||||
|
@ -186,13 +121,8 @@ fn lazy_expand(
|
||||||
MacroCallKind::FnLike { ast_id: macro_call.with_value(ast_id), expand_to },
|
MacroCallKind::FnLike { ast_id: macro_call.with_value(ast_id), expand_to },
|
||||||
);
|
);
|
||||||
|
|
||||||
let err = db.macro_expand_error(id);
|
db.parse_or_expand_with_err(id.as_file())
|
||||||
let value =
|
.map(|parse| parse.map(|parse| InFile::new(id.as_file(), parse)))
|
||||||
db.parse_or_expand_with_err(id.as_file()).map(|node| InFile::new(id.as_file(), node));
|
|
||||||
// FIXME: report parse errors
|
|
||||||
let value = value.map(|it| it.map(|it| it.syntax_node()));
|
|
||||||
|
|
||||||
ExpandResult { value, err }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn eager_macro_recur(
|
fn eager_macro_recur(
|
||||||
|
@ -201,23 +131,25 @@ fn eager_macro_recur(
|
||||||
curr: InFile<SyntaxNode>,
|
curr: InFile<SyntaxNode>,
|
||||||
krate: CrateId,
|
krate: CrateId,
|
||||||
macro_resolver: &dyn Fn(ModPath) -> Option<MacroDefId>,
|
macro_resolver: &dyn Fn(ModPath) -> Option<MacroDefId>,
|
||||||
mut diagnostic_sink: &mut dyn FnMut(ExpandError),
|
) -> Result<ExpandResult<Option<SyntaxNode>>, UnresolvedMacro> {
|
||||||
) -> Result<Result<SyntaxNode, ErrorEmitted>, UnresolvedMacro> {
|
|
||||||
let original = curr.value.clone_for_update();
|
let original = curr.value.clone_for_update();
|
||||||
|
|
||||||
let children = original.descendants().filter_map(ast::MacroCall::cast);
|
let children = original.descendants().filter_map(ast::MacroCall::cast);
|
||||||
let mut replacements = Vec::new();
|
let mut replacements = Vec::new();
|
||||||
|
|
||||||
|
// Note: We only report a single error inside of eager expansions
|
||||||
|
let mut error = None;
|
||||||
|
|
||||||
// Collect replacement
|
// Collect replacement
|
||||||
for child in children {
|
for child in children {
|
||||||
let def = match child.path().and_then(|path| ModPath::from_src(db, path, hygiene)) {
|
let def = match child.path().and_then(|path| ModPath::from_src(db, path, hygiene)) {
|
||||||
Some(path) => macro_resolver(path.clone()).ok_or(UnresolvedMacro { path })?,
|
Some(path) => macro_resolver(path.clone()).ok_or(UnresolvedMacro { path })?,
|
||||||
None => {
|
None => {
|
||||||
diagnostic_sink(ExpandError::Other("malformed macro invocation".into()));
|
error = Some(ExpandError::Other("malformed macro invocation".into()));
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
let insert = match def.kind {
|
let ExpandResult { value, err } = match def.kind {
|
||||||
MacroDefKind::BuiltInEager(..) => {
|
MacroDefKind::BuiltInEager(..) => {
|
||||||
let id = match expand_eager_macro(
|
let id = match expand_eager_macro(
|
||||||
db,
|
db,
|
||||||
|
@ -225,45 +157,55 @@ fn eager_macro_recur(
|
||||||
curr.with_value(child.clone()),
|
curr.with_value(child.clone()),
|
||||||
def,
|
def,
|
||||||
macro_resolver,
|
macro_resolver,
|
||||||
diagnostic_sink,
|
|
||||||
) {
|
) {
|
||||||
Ok(Ok(it)) => it,
|
Ok(it) => it,
|
||||||
Ok(Err(err)) => return Ok(Err(err)),
|
|
||||||
Err(err) => return Err(err),
|
Err(err) => return Err(err),
|
||||||
};
|
};
|
||||||
db.parse_or_expand(id.as_file())
|
id.map(|call| {
|
||||||
.expect("successful macro expansion should be parseable")
|
call.and_then(|call| db.parse_or_expand(call.as_file()))
|
||||||
.clone_for_update()
|
.map(|it| it.clone_for_update())
|
||||||
|
})
|
||||||
}
|
}
|
||||||
MacroDefKind::Declarative(_)
|
MacroDefKind::Declarative(_)
|
||||||
| MacroDefKind::BuiltIn(..)
|
| MacroDefKind::BuiltIn(..)
|
||||||
| MacroDefKind::BuiltInAttr(..)
|
| MacroDefKind::BuiltInAttr(..)
|
||||||
| MacroDefKind::BuiltInDerive(..)
|
| MacroDefKind::BuiltInDerive(..)
|
||||||
| MacroDefKind::ProcMacro(..) => {
|
| MacroDefKind::ProcMacro(..) => {
|
||||||
let res = lazy_expand(db, &def, curr.with_value(child.clone()), krate);
|
let ExpandResult { value, err } =
|
||||||
let val = match diagnostic_sink.expand_result_option(res) {
|
lazy_expand(db, &def, curr.with_value(child.clone()), krate);
|
||||||
Ok(it) => it,
|
|
||||||
Err(err) => return Ok(Err(err)),
|
|
||||||
};
|
|
||||||
|
|
||||||
// replace macro inside
|
match value {
|
||||||
let hygiene = Hygiene::new(db, val.file_id);
|
Some(val) => {
|
||||||
match eager_macro_recur(db, &hygiene, val, krate, macro_resolver, diagnostic_sink) {
|
// replace macro inside
|
||||||
Ok(Ok(it)) => it,
|
let hygiene = Hygiene::new(db, val.file_id);
|
||||||
Ok(Err(err)) => return Ok(Err(err)),
|
let ExpandResult { value, err: error } = eager_macro_recur(
|
||||||
Err(err) => return Err(err),
|
db,
|
||||||
|
&hygiene,
|
||||||
|
// FIXME: We discard parse errors here
|
||||||
|
val.map(|it| it.syntax_node()),
|
||||||
|
krate,
|
||||||
|
macro_resolver,
|
||||||
|
)?;
|
||||||
|
let err = if err.is_none() { error } else { err };
|
||||||
|
ExpandResult { value, err }
|
||||||
|
}
|
||||||
|
None => ExpandResult { value: None, err },
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
if err.is_some() {
|
||||||
|
error = err;
|
||||||
|
}
|
||||||
// check if the whole original syntax is replaced
|
// check if the whole original syntax is replaced
|
||||||
if child.syntax() == &original {
|
if child.syntax() == &original {
|
||||||
return Ok(Ok(insert));
|
return Ok(ExpandResult { value, err: error });
|
||||||
}
|
}
|
||||||
|
|
||||||
replacements.push((child, insert));
|
if let Some(insert) = value {
|
||||||
|
replacements.push((child, insert));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
replacements.into_iter().rev().for_each(|(old, new)| ted::replace(old.syntax(), new));
|
replacements.into_iter().rev().for_each(|(old, new)| ted::replace(old.syntax(), new));
|
||||||
Ok(Ok(original))
|
Ok(ExpandResult { value: Some(original), err: error })
|
||||||
}
|
}
|
||||||
|
|
|
@ -52,7 +52,7 @@ use crate::{
|
||||||
|
|
||||||
pub type ExpandResult<T> = ValueResult<T, ExpandError>;
|
pub type ExpandResult<T> = ValueResult<T, ExpandError>;
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq, Clone)]
|
#[derive(Debug, PartialEq, Eq, Clone, Hash)]
|
||||||
pub enum ExpandError {
|
pub enum ExpandError {
|
||||||
UnresolvedProcMacro(CrateId),
|
UnresolvedProcMacro(CrateId),
|
||||||
Mbe(mbe::ExpandError),
|
Mbe(mbe::ExpandError),
|
||||||
|
@ -114,7 +114,7 @@ impl_intern_key!(MacroCallId);
|
||||||
pub struct MacroCallLoc {
|
pub struct MacroCallLoc {
|
||||||
pub def: MacroDefId,
|
pub def: MacroDefId,
|
||||||
pub(crate) krate: CrateId,
|
pub(crate) krate: CrateId,
|
||||||
eager: Option<EagerCallInfo>,
|
eager: Option<Box<EagerCallInfo>>,
|
||||||
pub kind: MacroCallKind,
|
pub kind: MacroCallKind,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -141,6 +141,7 @@ struct EagerCallInfo {
|
||||||
/// NOTE: This can be *either* the expansion result, *or* the argument to the eager macro!
|
/// NOTE: This can be *either* the expansion result, *or* the argument to the eager macro!
|
||||||
arg_or_expansion: Arc<tt::Subtree>,
|
arg_or_expansion: Arc<tt::Subtree>,
|
||||||
included_file: Option<(FileId, TokenMap)>,
|
included_file: Option<(FileId, TokenMap)>,
|
||||||
|
error: Option<ExpandError>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||||
|
@ -206,8 +207,8 @@ impl HirFileId {
|
||||||
HirFileIdRepr::FileId(id) => break id,
|
HirFileIdRepr::FileId(id) => break id,
|
||||||
HirFileIdRepr::MacroFile(MacroFile { macro_call_id }) => {
|
HirFileIdRepr::MacroFile(MacroFile { macro_call_id }) => {
|
||||||
let loc: MacroCallLoc = db.lookup_intern_macro_call(macro_call_id);
|
let loc: MacroCallLoc = db.lookup_intern_macro_call(macro_call_id);
|
||||||
file_id = match loc.eager {
|
file_id = match loc.eager.as_deref() {
|
||||||
Some(EagerCallInfo { included_file: Some((file, _)), .. }) => file.into(),
|
Some(&EagerCallInfo { included_file: Some((file, _)), .. }) => file.into(),
|
||||||
_ => loc.kind.file_id(),
|
_ => loc.kind.file_id(),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -320,7 +321,7 @@ impl HirFileId {
|
||||||
match self.macro_file() {
|
match self.macro_file() {
|
||||||
Some(macro_file) => {
|
Some(macro_file) => {
|
||||||
let loc: MacroCallLoc = db.lookup_intern_macro_call(macro_file.macro_call_id);
|
let loc: MacroCallLoc = db.lookup_intern_macro_call(macro_file.macro_call_id);
|
||||||
matches!(loc.eager, Some(EagerCallInfo { included_file: Some(..), .. }))
|
matches!(loc.eager.as_deref(), Some(EagerCallInfo { included_file: Some(..), .. }))
|
||||||
}
|
}
|
||||||
_ => false,
|
_ => false,
|
||||||
}
|
}
|
||||||
|
|
|
@ -381,7 +381,8 @@ impl<'a> TyLoweringContext<'a> {
|
||||||
match expander.enter_expand::<ast::Type>(self.db.upcast(), macro_call) {
|
match expander.enter_expand::<ast::Type>(self.db.upcast(), macro_call) {
|
||||||
Ok(ExpandResult { value: Some((mark, expanded)), .. }) => {
|
Ok(ExpandResult { value: Some((mark, expanded)), .. }) => {
|
||||||
let ctx = expander.ctx(self.db.upcast());
|
let ctx = expander.ctx(self.db.upcast());
|
||||||
let type_ref = TypeRef::from_ast(&ctx, expanded);
|
// FIXME: Report syntax errors in expansion here
|
||||||
|
let type_ref = TypeRef::from_ast(&ctx, expanded.tree());
|
||||||
|
|
||||||
drop(expander);
|
drop(expander);
|
||||||
let ty = self.lower_ty(&type_ref);
|
let ty = self.lower_ty(&type_ref);
|
||||||
|
|
|
@ -6,8 +6,8 @@
|
||||||
pub use hir_def::db::*;
|
pub use hir_def::db::*;
|
||||||
pub use hir_expand::db::{
|
pub use hir_expand::db::{
|
||||||
AstIdMapQuery, ExpandDatabase, ExpandDatabaseStorage, ExpandProcMacroQuery, HygieneFrameQuery,
|
AstIdMapQuery, ExpandDatabase, ExpandDatabaseStorage, ExpandProcMacroQuery, HygieneFrameQuery,
|
||||||
InternMacroCallQuery, MacroArgTextQuery, MacroDefQuery, MacroExpandErrorQuery,
|
InternMacroCallQuery, MacroArgTextQuery, MacroDefQuery, MacroExpandQuery,
|
||||||
MacroExpandQuery, ParseMacroExpansionQuery,
|
ParseMacroExpansionQuery,
|
||||||
};
|
};
|
||||||
pub use hir_ty::db::*;
|
pub use hir_ty::db::*;
|
||||||
|
|
||||||
|
|
|
@ -10,7 +10,7 @@ use cfg::{CfgExpr, CfgOptions};
|
||||||
use either::Either;
|
use either::Either;
|
||||||
use hir_def::path::ModPath;
|
use hir_def::path::ModPath;
|
||||||
use hir_expand::{name::Name, HirFileId, InFile};
|
use hir_expand::{name::Name, HirFileId, InFile};
|
||||||
use syntax::{ast, AstPtr, SyntaxNodePtr, TextRange};
|
use syntax::{ast, AstPtr, SyntaxError, SyntaxNodePtr, TextRange};
|
||||||
|
|
||||||
use crate::{AssocItem, Field, Local, MacroKind, Type};
|
use crate::{AssocItem, Field, Local, MacroKind, Type};
|
||||||
|
|
||||||
|
@ -38,8 +38,9 @@ diagnostics![
|
||||||
IncorrectCase,
|
IncorrectCase,
|
||||||
InvalidDeriveTarget,
|
InvalidDeriveTarget,
|
||||||
IncoherentImpl,
|
IncoherentImpl,
|
||||||
MacroError,
|
|
||||||
MacroDefError,
|
MacroDefError,
|
||||||
|
MacroError,
|
||||||
|
MacroExpansionParseError,
|
||||||
MalformedDerive,
|
MalformedDerive,
|
||||||
MismatchedArgCount,
|
MismatchedArgCount,
|
||||||
MissingFields,
|
MissingFields,
|
||||||
|
@ -132,6 +133,13 @@ pub struct MacroError {
|
||||||
pub message: String,
|
pub message: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Eq, PartialEq)]
|
||||||
|
pub struct MacroExpansionParseError {
|
||||||
|
pub node: InFile<SyntaxNodePtr>,
|
||||||
|
pub precise_location: Option<TextRange>,
|
||||||
|
pub errors: Box<[SyntaxError]>,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Eq, PartialEq)]
|
#[derive(Debug, Clone, Eq, PartialEq)]
|
||||||
pub struct MacroDefError {
|
pub struct MacroDefError {
|
||||||
pub node: InFile<AstPtr<ast::Macro>>,
|
pub node: InFile<AstPtr<ast::Macro>>,
|
||||||
|
|
|
@ -87,12 +87,12 @@ pub use crate::{
|
||||||
attrs::{HasAttrs, Namespace},
|
attrs::{HasAttrs, Namespace},
|
||||||
diagnostics::{
|
diagnostics::{
|
||||||
AnyDiagnostic, BreakOutsideOfLoop, ExpectedFunction, InactiveCode, IncoherentImpl,
|
AnyDiagnostic, BreakOutsideOfLoop, ExpectedFunction, InactiveCode, IncoherentImpl,
|
||||||
IncorrectCase, InvalidDeriveTarget, MacroDefError, MacroError, MalformedDerive,
|
IncorrectCase, InvalidDeriveTarget, MacroDefError, MacroError, MacroExpansionParseError,
|
||||||
MismatchedArgCount, MissingFields, MissingMatchArms, MissingUnsafe, NeedMut, NoSuchField,
|
MalformedDerive, MismatchedArgCount, MissingFields, MissingMatchArms, MissingUnsafe,
|
||||||
PrivateAssocItem, PrivateField, ReplaceFilterMapNextWithFindMap, TypeMismatch,
|
NeedMut, NoSuchField, PrivateAssocItem, PrivateField, ReplaceFilterMapNextWithFindMap,
|
||||||
UndeclaredLabel, UnimplementedBuiltinMacro, UnreachableLabel, UnresolvedExternCrate,
|
TypeMismatch, UndeclaredLabel, UnimplementedBuiltinMacro, UnreachableLabel,
|
||||||
UnresolvedField, UnresolvedImport, UnresolvedMacroCall, UnresolvedMethodCall,
|
UnresolvedExternCrate, UnresolvedField, UnresolvedImport, UnresolvedMacroCall,
|
||||||
UnresolvedModule, UnresolvedProcMacro, UnusedMut,
|
UnresolvedMethodCall, UnresolvedModule, UnresolvedProcMacro, UnusedMut,
|
||||||
},
|
},
|
||||||
has_source::HasSource,
|
has_source::HasSource,
|
||||||
semantics::{PathResolution, Semantics, SemanticsScope, TypeInfo, VisibleTraits},
|
semantics::{PathResolution, Semantics, SemanticsScope, TypeInfo, VisibleTraits},
|
||||||
|
@ -753,7 +753,6 @@ fn emit_def_diagnostic_(
|
||||||
.into(),
|
.into(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
DefDiagnosticKind::UnresolvedProcMacro { ast, krate } => {
|
DefDiagnosticKind::UnresolvedProcMacro { ast, krate } => {
|
||||||
let (node, precise_location, macro_name, kind) = precise_macro_call_location(ast, db);
|
let (node, precise_location, macro_name, kind) = precise_macro_call_location(ast, db);
|
||||||
acc.push(
|
acc.push(
|
||||||
|
@ -761,7 +760,6 @@ fn emit_def_diagnostic_(
|
||||||
.into(),
|
.into(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
DefDiagnosticKind::UnresolvedMacroCall { ast, path } => {
|
DefDiagnosticKind::UnresolvedMacroCall { ast, path } => {
|
||||||
let (node, precise_location, _, _) = precise_macro_call_location(ast, db);
|
let (node, precise_location, _, _) = precise_macro_call_location(ast, db);
|
||||||
acc.push(
|
acc.push(
|
||||||
|
@ -774,12 +772,16 @@ fn emit_def_diagnostic_(
|
||||||
.into(),
|
.into(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
DefDiagnosticKind::MacroError { ast, message } => {
|
DefDiagnosticKind::MacroError { ast, message } => {
|
||||||
let (node, precise_location, _, _) = precise_macro_call_location(ast, db);
|
let (node, precise_location, _, _) = precise_macro_call_location(ast, db);
|
||||||
acc.push(MacroError { node, precise_location, message: message.clone() }.into());
|
acc.push(MacroError { node, precise_location, message: message.clone() }.into());
|
||||||
}
|
}
|
||||||
|
DefDiagnosticKind::MacroExpansionParseError { ast, errors } => {
|
||||||
|
let (node, precise_location, _, _) = precise_macro_call_location(ast, db);
|
||||||
|
acc.push(
|
||||||
|
MacroExpansionParseError { node, precise_location, errors: errors.clone() }.into(),
|
||||||
|
);
|
||||||
|
}
|
||||||
DefDiagnosticKind::UnimplementedBuiltinMacro { ast } => {
|
DefDiagnosticKind::UnimplementedBuiltinMacro { ast } => {
|
||||||
let node = ast.to_node(db.upcast());
|
let node = ast.to_node(db.upcast());
|
||||||
// Must have a name, otherwise we wouldn't emit it.
|
// Must have a name, otherwise we wouldn't emit it.
|
||||||
|
|
|
@ -80,7 +80,6 @@ impl RootDatabase {
|
||||||
hir::db::MacroDefQuery
|
hir::db::MacroDefQuery
|
||||||
hir::db::MacroExpandQuery
|
hir::db::MacroExpandQuery
|
||||||
hir::db::ExpandProcMacroQuery
|
hir::db::ExpandProcMacroQuery
|
||||||
hir::db::MacroExpandErrorQuery
|
|
||||||
hir::db::HygieneFrameQuery
|
hir::db::HygieneFrameQuery
|
||||||
|
|
||||||
// DefDatabase
|
// DefDatabase
|
||||||
|
|
|
@ -152,7 +152,6 @@ impl RootDatabase {
|
||||||
let lru_capacity = lru_capacity.unwrap_or(base_db::DEFAULT_LRU_CAP);
|
let lru_capacity = lru_capacity.unwrap_or(base_db::DEFAULT_LRU_CAP);
|
||||||
base_db::ParseQuery.in_db_mut(self).set_lru_capacity(lru_capacity);
|
base_db::ParseQuery.in_db_mut(self).set_lru_capacity(lru_capacity);
|
||||||
hir::db::ParseMacroExpansionQuery.in_db_mut(self).set_lru_capacity(lru_capacity);
|
hir::db::ParseMacroExpansionQuery.in_db_mut(self).set_lru_capacity(lru_capacity);
|
||||||
hir::db::MacroExpandQuery.in_db_mut(self).set_lru_capacity(lru_capacity);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn update_lru_capacities(&mut self, lru_capacities: &FxHashMap<Box<str>, usize>) {
|
pub fn update_lru_capacities(&mut self, lru_capacities: &FxHashMap<Box<str>, usize>) {
|
||||||
|
@ -167,12 +166,6 @@ impl RootDatabase {
|
||||||
.copied()
|
.copied()
|
||||||
.unwrap_or(base_db::DEFAULT_LRU_CAP),
|
.unwrap_or(base_db::DEFAULT_LRU_CAP),
|
||||||
);
|
);
|
||||||
hir_db::MacroExpandQuery.in_db_mut(self).set_lru_capacity(
|
|
||||||
lru_capacities
|
|
||||||
.get(stringify!(MacroExpandQuery))
|
|
||||||
.copied()
|
|
||||||
.unwrap_or(base_db::DEFAULT_LRU_CAP),
|
|
||||||
);
|
|
||||||
|
|
||||||
macro_rules! update_lru_capacity_per_query {
|
macro_rules! update_lru_capacity_per_query {
|
||||||
($( $module:ident :: $query:ident )*) => {$(
|
($( $module:ident :: $query:ident )*) => {$(
|
||||||
|
@ -201,7 +194,6 @@ impl RootDatabase {
|
||||||
hir_db::MacroDefQuery
|
hir_db::MacroDefQuery
|
||||||
// hir_db::MacroExpandQuery
|
// hir_db::MacroExpandQuery
|
||||||
hir_db::ExpandProcMacroQuery
|
hir_db::ExpandProcMacroQuery
|
||||||
hir_db::MacroExpandErrorQuery
|
|
||||||
hir_db::HygieneFrameQuery
|
hir_db::HygieneFrameQuery
|
||||||
|
|
||||||
// DefDatabase
|
// DefDatabase
|
||||||
|
|
|
@ -238,6 +238,22 @@ fn f() {
|
||||||
//^^^ error: invalid macro definition: expected subtree
|
//^^^ error: invalid macro definition: expected subtree
|
||||||
|
|
||||||
}
|
}
|
||||||
|
"#,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn expansion_syntax_diagnostic() {
|
||||||
|
check_diagnostics(
|
||||||
|
r#"
|
||||||
|
macro_rules! foo {
|
||||||
|
() => { struct; };
|
||||||
|
}
|
||||||
|
|
||||||
|
fn f() {
|
||||||
|
foo!();
|
||||||
|
//^^^ error: Syntax Error in Expansion: expected a name
|
||||||
|
}
|
||||||
"#,
|
"#,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -265,6 +265,19 @@ pub fn diagnostics(
|
||||||
AnyDiagnostic::InvalidDeriveTarget(d) => handlers::invalid_derive_target::invalid_derive_target(&ctx, &d),
|
AnyDiagnostic::InvalidDeriveTarget(d) => handlers::invalid_derive_target::invalid_derive_target(&ctx, &d),
|
||||||
AnyDiagnostic::MacroDefError(d) => handlers::macro_error::macro_def_error(&ctx, &d),
|
AnyDiagnostic::MacroDefError(d) => handlers::macro_error::macro_def_error(&ctx, &d),
|
||||||
AnyDiagnostic::MacroError(d) => handlers::macro_error::macro_error(&ctx, &d),
|
AnyDiagnostic::MacroError(d) => handlers::macro_error::macro_error(&ctx, &d),
|
||||||
|
AnyDiagnostic::MacroExpansionParseError(d) => {
|
||||||
|
res.extend(d.errors.iter().take(32).map(|err| {
|
||||||
|
{
|
||||||
|
Diagnostic::new(
|
||||||
|
"syntax-error",
|
||||||
|
format!("Syntax Error in Expansion: {err}"),
|
||||||
|
ctx.resolve_precise_location(&d.node.clone(), d.precise_location),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
.experimental()
|
||||||
|
}));
|
||||||
|
continue;
|
||||||
|
},
|
||||||
AnyDiagnostic::MalformedDerive(d) => handlers::malformed_derive::malformed_derive(&ctx, &d),
|
AnyDiagnostic::MalformedDerive(d) => handlers::malformed_derive::malformed_derive(&ctx, &d),
|
||||||
AnyDiagnostic::MismatchedArgCount(d) => handlers::mismatched_arg_count::mismatched_arg_count(&ctx, &d),
|
AnyDiagnostic::MismatchedArgCount(d) => handlers::mismatched_arg_count::mismatched_arg_count(&ctx, &d),
|
||||||
AnyDiagnostic::MissingFields(d) => handlers::missing_fields::missing_fields(&ctx, &d),
|
AnyDiagnostic::MissingFields(d) => handlers::missing_fields::missing_fields(&ctx, &d),
|
||||||
|
|
|
@ -69,7 +69,7 @@ impl fmt::Display for ParseError {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq, Clone)]
|
#[derive(Debug, PartialEq, Eq, Clone, Hash)]
|
||||||
pub enum ExpandError {
|
pub enum ExpandError {
|
||||||
BindingError(Box<Box<str>>),
|
BindingError(Box<Box<str>>),
|
||||||
LeftoverTokens,
|
LeftoverTokens,
|
||||||
|
|
Loading…
Reference in a new issue