Track in-scope derive helpers during nameres

This commit is contained in:
Jonas Schievink 2021-05-19 23:35:09 +02:00
parent 7cb5920372
commit d4eb6708d9
2 changed files with 27 additions and 9 deletions

View File

@ -43,7 +43,7 @@
UnresolvedMacro,
};
use super::proc_macro::ProcMacroDef;
use super::proc_macro::{ProcMacroDef, ProcMacroKind};
const GLOB_RECURSION_LIMIT: usize = 100;
const EXPANSION_DEPTH_LIMIT: usize = 128;
@ -101,6 +101,7 @@ pub(super) fn collect_defs(
exports_proc_macros: false,
from_glob_import: Default::default(),
ignore_attrs_on: FxHashSet::default(),
derive_helpers_in_scope: FxHashMap::default(),
};
match block {
Some(block) => {
@ -247,6 +248,9 @@ struct DefCollector<'a> {
exports_proc_macros: bool,
from_glob_import: PerNsGlobImports,
ignore_attrs_on: FxHashSet<InFile<ModItem>>,
/// Tracks which custom derives are in scope for an item, to allow resolution of derive helper
/// attributes.
derive_helpers_in_scope: FxHashMap<AstId<ast::Item>, Vec<Name>>,
}
impl DefCollector<'_> {
@ -950,21 +954,35 @@ fn collect_macro_expansion(
// 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
// incrementality).
let loc: MacroCallLoc = self.db.lookup_intern_macro(macro_call_id);
let err = self.db.macro_expand_error(macro_call_id);
if let Some(err) = err {
let loc: MacroCallLoc = self.db.lookup_intern_macro(macro_call_id);
let diag = match err {
hir_expand::ExpandError::UnresolvedProcMacro => {
// Missing proc macros are non-fatal, so they are handled specially.
DefDiagnostic::unresolved_proc_macro(module_id, loc.kind)
DefDiagnostic::unresolved_proc_macro(module_id, loc.kind.clone())
}
_ => 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 we've just resolved a derive, record its helper attributes.
if let MacroCallKind::Derive { ast_id, .. } = &loc.kind {
if loc.def.krate != self.def_map.krate {
let def_map = self.db.crate_def_map(loc.def.krate);
if let Some(def) = def_map.exported_proc_macros.get(&loc.def) {
if let ProcMacroKind::CustomDerive { helpers } = &def.kind {
self.derive_helpers_in_scope
.entry(*ast_id)
.or_default()
.extend(helpers.iter().cloned());
}
}
}
}
// 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 mod_dir = self.mod_dirs[&module_id].clone();
@ -1120,9 +1138,8 @@ fn collect(&mut self, items: &[ModItem]) {
}
if let Err(()) = self.resolve_attributes(&attrs, item) {
// Do not process the item. It has at least one non-builtin attribute, which *must*
// resolve to a proc macro (or fail to resolve), so we'll never see this item during
// normal name resolution.
// Do not process the item. It has at least one non-builtin attribute, so the
// fixed-point algorithm is required to resolve the rest of them.
continue;
}
@ -1721,6 +1738,7 @@ fn do_collect_defs(db: &dyn DefDatabase, def_map: DefMap) -> DefMap {
exports_proc_macros: false,
from_glob_import: Default::default(),
ignore_attrs_on: FxHashSet::default(),
derive_helpers_in_scope: FxHashMap::default(),
};
collector.seed_with_top_level();
collector.collect();

View File

@ -237,7 +237,7 @@ struct EagerCallInfo {
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct MacroCallLoc {
pub(crate) def: MacroDefId,
pub def: MacroDefId,
pub(crate) krate: CrateId,
eager: Option<EagerCallInfo>,
pub kind: MacroCallKind,