Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/hir_def/src/nameres/collector.rs')
-rw-r--r--crates/hir_def/src/nameres/collector.rs235
1 files changed, 123 insertions, 112 deletions
diff --git a/crates/hir_def/src/nameres/collector.rs b/crates/hir_def/src/nameres/collector.rs
index 9176c90ae9..e1a297a3fc 100644
--- a/crates/hir_def/src/nameres/collector.rs
+++ b/crates/hir_def/src/nameres/collector.rs
@@ -5,8 +5,9 @@
use std::iter;
-use base_db::{CrateId, Edition, FileId, ProcMacroId};
+use base_db::{CrateId, Edition, FileId};
use cfg::{CfgExpr, CfgOptions};
+use either::Either;
use hir_expand::{
ast_id_map::FileAstId,
builtin_attr_macro::find_builtin_attr,
@@ -34,7 +35,7 @@ use crate::{
self, Fields, FileItemTreeId, ImportKind, ItemTree, ItemTreeId, ItemTreeNode, MacroCall,
MacroDef, MacroRules, Mod, ModItem, ModKind, TreeId,
},
- macro_call_as_call_id,
+ macro_call_as_call_id, macro_id_to_def_id,
nameres::{
diagnostics::DefDiagnostic,
mod_resolution::ModDir,
@@ -45,9 +46,10 @@ use crate::{
path::{ImportAlias, ModPath, PathKind},
per_ns::PerNs,
visibility::{RawVisibility, Visibility},
- AdtId, AstId, AstIdWithPath, ConstLoc, EnumLoc, EnumVariantId, ExternBlockLoc, FunctionLoc,
- ImplLoc, Intern, ItemContainerId, LocalModuleId, ModuleDefId, StaticLoc, StructLoc, TraitLoc,
- TypeAliasLoc, UnionLoc, UnresolvedMacro,
+ AdtId, AstId, AstIdWithPath, ConstLoc, EnumLoc, EnumVariantId, ExternBlockLoc, FunctionId,
+ FunctionLoc, ImplLoc, Intern, ItemContainerId, LocalModuleId, Macro2Id, Macro2Loc,
+ MacroExpander, MacroId, MacroRulesId, MacroRulesLoc, ModuleDefId, ModuleId, ProcMacroId,
+ ProcMacroLoc, StaticLoc, StructLoc, TraitLoc, TypeAliasLoc, UnionLoc, UnresolvedMacro,
};
static GLOB_RECURSION_LIMIT: Limit = Limit::new(100);
@@ -79,7 +81,10 @@ pub(super) fn collect_defs(db: &dyn DefDatabase, mut def_map: DefMap, tree_id: T
.map(|(idx, it)| {
// FIXME: a hacky way to create a Name from string.
let name = tt::Ident { text: it.name.clone(), id: tt::TokenId::unspecified() };
- (name.as_name(), ProcMacroExpander::new(def_map.krate, ProcMacroId(idx as u32)))
+ (
+ name.as_name(),
+ ProcMacroExpander::new(def_map.krate, base_db::ProcMacroId(idx as u32)),
+ )
})
.collect();
@@ -543,28 +548,30 @@ impl DefCollector<'_> {
/// use a dummy expander that always errors. This comes with the drawback of macros potentially
/// going out of sync with what the build system sees (since we resolve using VFS state, but
/// Cargo builds only on-disk files). We could and probably should add diagnostics for that.
- fn export_proc_macro(&mut self, def: ProcMacroDef, ast_id: AstId<ast::Fn>) {
- let kind = def.kind.to_basedb_kind();
+ fn export_proc_macro(
+ &mut self,
+ def: ProcMacroDef,
+ id: ItemTreeId<item_tree::Function>,
+ fn_id: FunctionId,
+ module_id: ModuleId,
+ ) {
self.exports_proc_macros = true;
- let macro_def = match self.proc_macros.iter().find(|(n, _)| n == &def.name) {
- Some(&(_, expander)) => MacroDefId {
- krate: self.def_map.krate,
- kind: MacroDefKind::ProcMacro(expander, kind, ast_id),
- local_inner: false,
- },
- None => MacroDefId {
- krate: self.def_map.krate,
- kind: MacroDefKind::ProcMacro(
- ProcMacroExpander::dummy(self.def_map.krate),
- kind,
- ast_id,
- ),
- local_inner: false,
- },
+
+ let kind = def.kind.to_basedb_kind();
+ let (expander, kind) = match self.proc_macros.iter().find(|(n, _)| n == &def.name) {
+ Some(&(_, expander)) => (expander, kind),
+ None => (ProcMacroExpander::dummy(self.def_map.krate), kind),
};
- self.define_proc_macro(def.name.clone(), macro_def);
- self.def_map.exported_proc_macros.insert(macro_def, def);
+ let proc_macro_id =
+ ProcMacroLoc { container: module_id, id, expander, kind }.intern(self.db);
+ self.define_proc_macro(def.name.clone(), proc_macro_id.into());
+ if let ProcMacroKind::CustomDerive { helpers } = def.kind {
+ self.def_map
+ .exported_derives
+ .insert(macro_id_to_def_id(self.db, proc_macro_id.into()), helpers);
+ }
+ self.def_map.fn_proc_macro_mapping.insert(fn_id, proc_macro_id);
}
/// Define a macro with `macro_rules`.
@@ -596,20 +603,21 @@ impl DefCollector<'_> {
&mut self,
module_id: LocalModuleId,
name: Name,
- macro_: MacroDefId,
+ macro_: MacroRulesId,
export: bool,
) {
// Textual scoping
self.define_legacy_macro(module_id, name.clone(), macro_);
- self.def_map.modules[module_id].scope.declare_macro(macro_);
// Module scoping
// In Rust, `#[macro_export]` macros are unconditionally visible at the
// crate root, even if the parent modules is **not** visible.
if export {
+ let module_id = self.def_map.root;
+ self.def_map.modules[module_id].scope.declare(macro_.into());
self.update(
- self.def_map.root,
- &[(Some(name), PerNs::macros(macro_, Visibility::Public))],
+ module_id,
+ &[(Some(name), PerNs::macros(macro_.into(), Visibility::Public))],
Visibility::Public,
ImportType::Named,
);
@@ -623,7 +631,7 @@ impl DefCollector<'_> {
/// the definition of current module.
/// And also, `macro_use` on a module will import all legacy macros visible inside to
/// current legacy scope, with possible shadowing.
- fn define_legacy_macro(&mut self, module_id: LocalModuleId, name: Name, mac: MacroDefId) {
+ fn define_legacy_macro(&mut self, module_id: LocalModuleId, name: Name, mac: MacroRulesId) {
// Always shadowing
self.def_map.modules[module_id].scope.define_legacy_macro(name, mac);
}
@@ -635,24 +643,30 @@ impl DefCollector<'_> {
&mut self,
module_id: LocalModuleId,
name: Name,
- macro_: MacroDefId,
+ macro_: Macro2Id,
vis: &RawVisibility,
) {
let vis =
self.def_map.resolve_visibility(self.db, module_id, vis).unwrap_or(Visibility::Public);
- self.def_map.modules[module_id].scope.declare_macro(macro_);
- self.update(module_id, &[(Some(name), PerNs::macros(macro_, vis))], vis, ImportType::Named);
+ self.def_map.modules[module_id].scope.declare(macro_.into());
+ self.update(
+ module_id,
+ &[(Some(name), PerNs::macros(macro_.into(), Visibility::Public))],
+ vis,
+ ImportType::Named,
+ );
}
/// Define a proc macro
///
/// A proc macro is similar to normal macro scope, but it would not visible in legacy textual scoped.
/// And unconditionally exported.
- fn define_proc_macro(&mut self, name: Name, macro_: MacroDefId) {
- self.def_map.modules[self.def_map.root].scope.declare_macro(macro_);
+ fn define_proc_macro(&mut self, name: Name, macro_: ProcMacroId) {
+ let module_id = self.def_map.root;
+ self.def_map.modules[module_id].scope.declare(macro_.into());
self.update(
- self.def_map.root,
- &[(Some(name), PerNs::macros(macro_, Visibility::Public))],
+ module_id,
+ &[(Some(name), PerNs::macros(macro_.into(), Visibility::Public))],
Visibility::Public,
ImportType::Named,
);
@@ -691,8 +705,10 @@ impl DefCollector<'_> {
fn import_all_macros_exported(&mut self, current_module_id: LocalModuleId, krate: CrateId) {
let def_map = self.db.crate_def_map(krate);
for (name, def) in def_map[def_map.root].scope.macros() {
- // `macro_use` only bring things into legacy scope.
- self.define_legacy_macro(current_module_id, name.clone(), def);
+ if let MacroId::MacroRulesId(def) = def {
+ // `macro_use` only bring things into legacy scope.
+ self.define_legacy_macro(current_module_id, name.clone(), def);
+ }
}
}
@@ -1049,7 +1065,7 @@ impl DefCollector<'_> {
&path,
BuiltinShadowMode::Module,
);
- resolved_res.resolved_def.take_macros()
+ resolved_res.resolved_def.take_macros().map(|it| macro_id_to_def_id(self.db, it))
};
match &directive.kind {
@@ -1293,13 +1309,11 @@ impl DefCollector<'_> {
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.map(|it| it.upcast()))
- .or_default()
- .extend(helpers.iter().cloned());
- }
+ if let Some(helpers) = def_map.exported_derives.get(&loc.def) {
+ self.derive_helpers_in_scope
+ .entry(ast_id.map(|it| it.upcast()))
+ .or_default()
+ .extend(helpers.iter().cloned());
}
}
}
@@ -1339,7 +1353,10 @@ impl DefCollector<'_> {
&path,
BuiltinShadowMode::Module,
);
- resolved_res.resolved_def.take_macros()
+ resolved_res
+ .resolved_def
+ .take_macros()
+ .map(|it| macro_id_to_def_id(self.db, it))
},
&mut |_| (),
);
@@ -1525,10 +1542,9 @@ impl ModCollector<'_, '_> {
),
),
ModItem::MacroCall(mac) => self.collect_macro_call(&self.item_tree[mac], container),
- ModItem::MacroRules(id) => self.collect_macro_rules(id),
- ModItem::MacroDef(id) => self.collect_macro_def(id),
+ ModItem::MacroRules(id) => self.collect_macro_rules(id, module),
+ ModItem::MacroDef(id) => self.collect_macro_def(id, module),
ModItem::Impl(imp) => {
- let module = self.def_collector.def_map.module_id(self.module_id);
let impl_id =
ImplLoc { container: module, id: ItemTreeId::new(self.tree_id, imp) }
.intern(db);
@@ -1536,27 +1552,26 @@ impl ModCollector<'_, '_> {
}
ModItem::Function(id) => {
let it = &self.item_tree[id];
+ let fn_id =
+ FunctionLoc { container, id: ItemTreeId::new(self.tree_id, id) }.intern(db);
let is_proc_macro = attrs.parse_proc_macro_decl(&it.name);
let vis = match is_proc_macro {
Some(proc_macro) => {
// FIXME: this should only be done in the root module of `proc-macro` crates, not everywhere
- let ast_id = InFile::new(self.tree_id.file_id(), it.ast_id);
let module_id = def_map.module_id(def_map.root());
- self.def_collector.export_proc_macro(proc_macro, ast_id);
+
+ self.def_collector.export_proc_macro(
+ proc_macro,
+ ItemTreeId::new(self.tree_id, id),
+ fn_id,
+ module_id,
+ );
Visibility::Module(module_id)
}
None => resolve_vis(def_map, &self.item_tree[it.visibility]),
};
- update_def(
- self.def_collector,
- FunctionLoc { container, id: ItemTreeId::new(self.tree_id, id) }
- .intern(db)
- .into(),
- &it.name,
- vis,
- false,
- );
+ update_def(self.def_collector, fn_id.into(), &it.name, vis, false);
}
ModItem::Struct(id) => {
let it = &self.item_tree[id];
@@ -1845,7 +1860,7 @@ impl ModCollector<'_, '_> {
Ok(())
}
- fn collect_macro_rules(&mut self, id: FileItemTreeId<MacroRules>) {
+ fn collect_macro_rules(&mut self, id: FileItemTreeId<MacroRules>, module: ModuleId) {
let krate = self.def_collector.def_map.krate;
let mac = &self.item_tree[id];
let attrs = self.item_tree.attrs(self.def_collector.db, krate, ModItem::from(id).into());
@@ -1854,7 +1869,7 @@ impl ModCollector<'_, '_> {
let export_attr = attrs.by_key("macro_export");
let is_export = export_attr.exists();
- let is_local_inner = if is_export {
+ let local_inner = if is_export {
export_attr.tt_values().flat_map(|it| &it.token_trees).any(|it| match it {
tt::TokenTree::Leaf(tt::Leaf::Ident(ident)) => {
ident.text.contains("local_inner_macros")
@@ -1866,7 +1881,7 @@ impl ModCollector<'_, '_> {
};
// Case 1: builtin macros
- if attrs.by_key("rustc_builtin_macro").exists() {
+ let expander = if attrs.by_key("rustc_builtin_macro").exists() {
// `#[rustc_builtin_macro = "builtin_name"]` overrides the `macro_rules!` name.
let name;
let name = match attrs.by_key("rustc_builtin_macro").string_value() {
@@ -1892,32 +1907,29 @@ impl ModCollector<'_, '_> {
}
}
};
- let krate = self.def_collector.def_map.krate;
- match find_builtin_macro(name, krate, ast_id) {
- Some(macro_id) => {
- self.def_collector.define_macro_rules(
- self.module_id,
- mac.name.clone(),
- macro_id,
- is_export,
- );
- return;
- }
+ match find_builtin_macro(name) {
+ Some(Either::Left(it)) => MacroExpander::BuiltIn(it),
+ Some(Either::Right(it)) => MacroExpander::BuiltInEager(it),
None => {
self.def_collector
.def_map
.diagnostics
.push(DefDiagnostic::unimplemented_builtin_macro(self.module_id, ast_id));
+ return;
}
}
- }
-
- // Case 2: normal `macro_rules!` macro
- let macro_id = MacroDefId {
- krate: self.def_collector.def_map.krate,
- kind: MacroDefKind::Declarative(ast_id),
- local_inner: is_local_inner,
+ } else {
+ // Case 2: normal `macro_rules!` macro
+ MacroExpander::Declarative
};
+
+ let macro_id = MacroRulesLoc {
+ container: module,
+ id: ItemTreeId::new(self.tree_id, id),
+ local_inner,
+ expander,
+ }
+ .intern(self.def_collector.db);
self.def_collector.define_macro_rules(
self.module_id,
mac.name.clone(),
@@ -1926,44 +1938,38 @@ impl ModCollector<'_, '_> {
);
}
- fn collect_macro_def(&mut self, id: FileItemTreeId<MacroDef>) {
+ fn collect_macro_def(&mut self, id: FileItemTreeId<MacroDef>, module: ModuleId) {
let krate = self.def_collector.def_map.krate;
let mac = &self.item_tree[id];
let ast_id = InFile::new(self.file_id(), mac.ast_id.upcast());
// Case 1: builtin macros
let attrs = self.item_tree.attrs(self.def_collector.db, krate, ModItem::from(id).into());
- if attrs.by_key("rustc_builtin_macro").exists() {
- let macro_id = find_builtin_macro(&mac.name, krate, ast_id)
- .or_else(|| find_builtin_derive(&mac.name, krate, ast_id))
- .or_else(|| find_builtin_attr(&mac.name, krate, ast_id));
-
- match macro_id {
- Some(macro_id) => {
- self.def_collector.define_macro_def(
- self.module_id,
- mac.name.clone(),
- macro_id,
- &self.item_tree[mac.visibility],
- );
- return;
- }
- None => {
- self.def_collector
- .def_map
- .diagnostics
- .push(DefDiagnostic::unimplemented_builtin_macro(self.module_id, ast_id));
+ let expander = if attrs.by_key("rustc_builtin_macro").exists() {
+ if let Some(expander) = find_builtin_macro(&mac.name) {
+ match expander {
+ Either::Left(it) => MacroExpander::BuiltIn(it),
+ Either::Right(it) => MacroExpander::BuiltInEager(it),
}
+ } else if let Some(expander) = find_builtin_derive(&mac.name) {
+ MacroExpander::BuiltInDerive(expander)
+ } else if let Some(expander) = find_builtin_attr(&mac.name) {
+ MacroExpander::BuiltInAttr(expander)
+ } else {
+ self.def_collector
+ .def_map
+ .diagnostics
+ .push(DefDiagnostic::unimplemented_builtin_macro(self.module_id, ast_id));
+ return;
}
- }
-
- // Case 2: normal `macro`
- let macro_id = MacroDefId {
- krate: self.def_collector.def_map.krate,
- kind: MacroDefKind::Declarative(ast_id),
- local_inner: false,
+ } else {
+ // Case 2: normal `macro`
+ MacroExpander::Declarative
};
+ let macro_id =
+ Macro2Loc { container: module, id: ItemTreeId::new(self.tree_id, id), expander }
+ .intern(self.def_collector.db);
self.def_collector.define_macro_def(
self.module_id,
mac.name.clone(),
@@ -1987,7 +1993,12 @@ impl ModCollector<'_, '_> {
self.def_collector.def_map.with_ancestor_maps(
self.def_collector.db,
self.module_id,
- &mut |map, module| map[module].scope.get_legacy_macro(name),
+ &mut |map, module| {
+ map[module]
+ .scope
+ .get_legacy_macro(name)
+ .map(|it| macro_id_to_def_id(self.def_collector.db, it.into()))
+ },
)
})
},