Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/hir-def/src/nameres.rs')
-rw-r--r--crates/hir-def/src/nameres.rs275
1 files changed, 195 insertions, 80 deletions
diff --git a/crates/hir-def/src/nameres.rs b/crates/hir-def/src/nameres.rs
index 4efe8c58a6..9b520bc303 100644
--- a/crates/hir-def/src/nameres.rs
+++ b/crates/hir-def/src/nameres.rs
@@ -57,9 +57,9 @@ mod path_resolution;
#[cfg(test)]
mod tests;
-use std::{cmp::Ord, ops::Deref, sync::Arc};
+use std::{cmp::Ord, ops::Deref};
-use base_db::{CrateId, Edition, FileId};
+use base_db::{CrateId, Edition, FileId, ProcMacroKind};
use hir_expand::{name::Name, InFile, MacroCallId, MacroDefId};
use itertools::Itertools;
use la_arena::Arena;
@@ -67,6 +67,7 @@ use profile::Count;
use rustc_hash::{FxHashMap, FxHashSet};
use stdx::format_to;
use syntax::{ast, SmolStr};
+use triomphe::Arc;
use crate::{
db::DefDatabase,
@@ -76,7 +77,8 @@ use crate::{
path::ModPath,
per_ns::PerNs,
visibility::Visibility,
- AstId, BlockId, BlockLoc, FunctionId, LocalModuleId, MacroId, ModuleId, ProcMacroId,
+ AstId, BlockId, BlockLoc, FunctionId, LocalModuleId, Lookup, MacroExpander, MacroId, ModuleId,
+ ProcMacroId,
};
/// Contains the results of (early) name resolution.
@@ -92,7 +94,6 @@ use crate::{
pub struct DefMap {
_c: Count<Self>,
block: Option<BlockInfo>,
- root: LocalModuleId,
modules: Arena<ModuleData>,
krate: CrateId,
/// The prelude module for this crate. This either comes from an import
@@ -102,7 +103,22 @@ pub struct DefMap {
/// but that attribute is nightly and when used in a block, it affects resolution globally
/// so we aren't handling this correctly anyways).
prelude: Option<ModuleId>,
- /// The extern prelude is only populated for non-block DefMaps
+ /// `macro_use` prelude that contains macros from `#[macro_use]`'d external crates. Note that
+ /// this contains all kinds of macro, not just `macro_rules!` macro.
+ macro_use_prelude: FxHashMap<Name, MacroId>,
+
+ /// 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, MacroId, MacroCallId)>>,
+
+ diagnostics: Vec<DefDiagnostic>,
+
+ data: Arc<DefMapCrateData>,
+}
+
+/// Data that belongs to a crate which is shared between a crate's def map and all its block def maps.
+#[derive(Clone, Debug, PartialEq, Eq)]
+struct DefMapCrateData {
extern_prelude: FxHashMap<Name, ModuleId>,
/// Side table for resolving derive helpers.
@@ -110,9 +126,6 @@ pub struct DefMap {
fn_proc_macro_mapping: FxHashMap<FunctionId, ProcMacroId>,
/// The error that occurred when failing to load the proc-macro dll.
proc_macro_loading_error: Option<Box<str>>,
- /// 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, MacroId, MacroCallId)>>,
/// Custom attributes registered with `#![register_attr]`.
registered_attrs: Vec<SmolStr>,
@@ -122,10 +135,36 @@ pub struct DefMap {
unstable_features: FxHashSet<SmolStr>,
/// #[rustc_coherence_is_core]
rustc_coherence_is_core: bool,
+ no_core: bool,
+ no_std: bool,
edition: Edition,
recursion_limit: Option<u32>,
- diagnostics: Vec<DefDiagnostic>,
+}
+
+impl DefMapCrateData {
+ fn shrink_to_fit(&mut self) {
+ let Self {
+ extern_prelude,
+ exported_derives,
+ fn_proc_macro_mapping,
+ registered_attrs,
+ registered_tools,
+ unstable_features,
+ proc_macro_loading_error: _,
+ rustc_coherence_is_core: _,
+ no_core: _,
+ no_std: _,
+ edition: _,
+ recursion_limit: _,
+ } = self;
+ extern_prelude.shrink_to_fit();
+ exported_derives.shrink_to_fit();
+ fn_proc_macro_mapping.shrink_to_fit();
+ registered_attrs.shrink_to_fit();
+ registered_tools.shrink_to_fit();
+ unstable_features.shrink_to_fit();
+ }
}
/// For `DefMap`s computed for a block expression, this stores its location in the parent map.
@@ -134,7 +173,23 @@ struct BlockInfo {
/// The `BlockId` this `DefMap` was created from.
block: BlockId,
/// The containing module.
- parent: ModuleId,
+ parent: BlockRelativeModuleId,
+}
+
+#[derive(Debug, PartialEq, Eq, Clone, Copy)]
+struct BlockRelativeModuleId {
+ block: Option<BlockId>,
+ local_id: LocalModuleId,
+}
+
+impl BlockRelativeModuleId {
+ fn def_map(self, db: &dyn DefDatabase, krate: CrateId) -> Arc<DefMap> {
+ self.into_module(krate).def_map(db)
+ }
+
+ fn into_module(self, krate: CrateId) -> ModuleId {
+ ModuleId { krate, block: self.block, local_id: self.local_id }
+ }
}
impl std::ops::Index<LocalModuleId> for DefMap {
@@ -224,6 +279,8 @@ pub struct ModuleData {
}
impl DefMap {
+ pub const ROOT: LocalModuleId = LocalModuleId::from_raw(la_arena::RawIdx::from_u32(0));
+
pub(crate) fn crate_def_map_query(db: &dyn DefDatabase, krate: CrateId) -> Arc<DefMap> {
let _p = profile::span("crate_def_map_query").detail(|| {
db.crate_graph()[krate].display_name.as_deref().unwrap_or_default().to_string()
@@ -243,17 +300,10 @@ impl DefMap {
Arc::new(def_map)
}
- pub(crate) fn block_def_map_query(
- db: &dyn DefDatabase,
- block_id: BlockId,
- ) -> Option<Arc<DefMap>> {
+ pub(crate) fn block_def_map_query(db: &dyn DefDatabase, block_id: BlockId) -> Arc<DefMap> {
let block: BlockLoc = db.lookup_intern_block(block_id);
let tree_id = TreeId::new(block.ast_id.file_id, Some(block_id));
- let item_tree = tree_id.item_tree(db);
- if item_tree.top_level_items().is_empty() {
- return None;
- }
let parent_map = block.module.def_map(db);
let krate = block.module.krate;
@@ -265,36 +315,48 @@ impl DefMap {
let module_data =
ModuleData::new(ModuleOrigin::BlockExpr { block: block.ast_id }, visibility);
- let mut def_map = DefMap::empty(krate, parent_map.edition, module_data);
- def_map.block = Some(BlockInfo { block: block_id, parent: block.module });
+ let mut def_map = DefMap::empty(krate, parent_map.data.edition, module_data);
+ def_map.data = parent_map.data.clone();
+ def_map.block = Some(BlockInfo {
+ block: block_id,
+ parent: BlockRelativeModuleId {
+ block: block.module.block,
+ local_id: block.module.local_id,
+ },
+ });
let def_map = collector::collect_defs(db, def_map, tree_id);
- Some(Arc::new(def_map))
+ Arc::new(def_map)
}
fn empty(krate: CrateId, edition: Edition, module_data: ModuleData) -> DefMap {
let mut modules: Arena<ModuleData> = Arena::default();
let root = modules.alloc(module_data);
+ assert_eq!(root, Self::ROOT);
DefMap {
_c: Count::new(),
block: None,
+ modules,
krate,
- edition,
- recursion_limit: None,
- extern_prelude: FxHashMap::default(),
- exported_derives: FxHashMap::default(),
- fn_proc_macro_mapping: FxHashMap::default(),
- proc_macro_loading_error: None,
- derive_helpers_in_scope: FxHashMap::default(),
prelude: None,
- root,
- modules,
- registered_attrs: Vec::new(),
- registered_tools: Vec::new(),
- unstable_features: FxHashSet::default(),
+ macro_use_prelude: FxHashMap::default(),
+ derive_helpers_in_scope: FxHashMap::default(),
diagnostics: Vec::new(),
- rustc_coherence_is_core: false,
+ data: Arc::new(DefMapCrateData {
+ extern_prelude: FxHashMap::default(),
+ exported_derives: FxHashMap::default(),
+ fn_proc_macro_mapping: FxHashMap::default(),
+ proc_macro_loading_error: None,
+ registered_attrs: Vec::new(),
+ registered_tools: Vec::new(),
+ unstable_features: FxHashSet::default(),
+ rustc_coherence_is_core: false,
+ no_core: false,
+ no_std: false,
+ edition,
+ recursion_limit: None,
+ }),
}
}
@@ -317,31 +379,31 @@ impl DefMap {
}
pub fn registered_tools(&self) -> &[SmolStr] {
- &self.registered_tools
+ &self.data.registered_tools
}
pub fn registered_attrs(&self) -> &[SmolStr] {
- &self.registered_attrs
+ &self.data.registered_attrs
}
pub fn is_unstable_feature_enabled(&self, feature: &str) -> bool {
- self.unstable_features.contains(feature)
+ self.data.unstable_features.contains(feature)
}
pub fn is_rustc_coherence_is_core(&self) -> bool {
- self.rustc_coherence_is_core
+ self.data.rustc_coherence_is_core
}
- pub fn root(&self) -> LocalModuleId {
- self.root
+ pub fn is_no_std(&self) -> bool {
+ self.data.no_std || self.data.no_core
}
pub fn fn_as_proc_macro(&self, id: FunctionId) -> Option<ProcMacroId> {
- self.fn_proc_macro_mapping.get(&id).copied()
+ self.data.fn_proc_macro_mapping.get(&id).copied()
}
pub fn proc_macro_loading_error(&self) -> Option<&str> {
- self.proc_macro_loading_error.as_deref()
+ self.data.proc_macro_loading_error.as_deref()
}
pub fn krate(&self) -> CrateId {
@@ -356,8 +418,12 @@ impl DefMap {
self.prelude
}
- pub(crate) fn extern_prelude(&self) -> impl Iterator<Item = (&Name, &ModuleId)> + '_ {
- self.extern_prelude.iter()
+ pub(crate) fn extern_prelude(&self) -> impl Iterator<Item = (&Name, ModuleId)> + '_ {
+ self.data.extern_prelude.iter().map(|(name, def)| (name, *def))
+ }
+
+ pub(crate) fn macro_use_prelude(&self) -> impl Iterator<Item = (&Name, MacroId)> + '_ {
+ self.macro_use_prelude.iter().map(|(name, def)| (name, *def))
}
pub fn module_id(&self, local_id: LocalModuleId) -> ModuleId {
@@ -365,11 +431,8 @@ impl DefMap {
ModuleId { krate: self.krate, local_id, block }
}
- pub(crate) fn crate_root(&self, db: &dyn DefDatabase) -> ModuleId {
- self.with_ancestor_maps(db, self.root, &mut |def_map, _module| {
- if def_map.block.is_none() { Some(def_map.module_id(def_map.root)) } else { None }
- })
- .expect("DefMap chain without root")
+ pub(crate) fn crate_root(&self) -> ModuleId {
+ ModuleId { krate: self.krate, block: None, local_id: DefMap::ROOT }
}
pub(crate) fn resolve_path(
@@ -378,9 +441,16 @@ impl DefMap {
original_module: LocalModuleId,
path: &ModPath,
shadow: BuiltinShadowMode,
+ expected_macro_subns: Option<MacroSubNs>,
) -> (PerNs, Option<usize>) {
- let res =
- self.resolve_path_fp_with_macro(db, ResolveMode::Other, original_module, path, shadow);
+ let res = self.resolve_path_fp_with_macro(
+ db,
+ ResolveMode::Other,
+ original_module,
+ path,
+ shadow,
+ expected_macro_subns,
+ );
(res.resolved_def, res.segment_index)
}
@@ -397,6 +467,7 @@ impl DefMap {
original_module,
path,
shadow,
+ None, // Currently this function isn't used for macro resolution.
);
(res.resolved_def, res.segment_index)
}
@@ -416,7 +487,7 @@ impl DefMap {
}
let mut block = self.block;
while let Some(block_info) = block {
- let parent = block_info.parent.def_map(db);
+ let parent = block_info.parent.def_map(db, self.krate);
if let Some(it) = f(&parent, block_info.parent.local_id) {
return Some(it);
}
@@ -429,7 +500,8 @@ impl DefMap {
/// If this `DefMap` is for a block expression, returns the module containing the block (which
/// might again be a block, or a module inside a block).
pub fn parent(&self) -> Option<ModuleId> {
- Some(self.block?.parent)
+ let BlockRelativeModuleId { block, local_id } = self.block?.parent;
+ Some(ModuleId { krate: self.krate, block, local_id })
}
/// Returns the module containing `local_mod`, either the parent `mod`, or the module (or block) containing
@@ -437,7 +509,13 @@ impl DefMap {
pub fn containing_module(&self, local_mod: LocalModuleId) -> Option<ModuleId> {
match self[local_mod].parent {
Some(parent) => Some(self.module_id(parent)),
- None => self.block.map(|block| block.parent),
+ None => {
+ self.block.map(
+ |BlockInfo { parent: BlockRelativeModuleId { block, local_id }, .. }| {
+ ModuleId { krate: self.krate, block, local_id }
+ },
+ )
+ }
}
}
@@ -448,25 +526,31 @@ impl DefMap {
let mut arc;
let mut current_map = self;
while let Some(block) = current_map.block {
- go(&mut buf, current_map, "block scope", current_map.root);
+ go(&mut buf, db, current_map, "block scope", Self::ROOT);
buf.push('\n');
- arc = block.parent.def_map(db);
+ arc = block.parent.def_map(db, self.krate);
current_map = &arc;
}
- go(&mut buf, current_map, "crate", current_map.root);
+ go(&mut buf, db, current_map, "crate", Self::ROOT);
return buf;
- fn go(buf: &mut String, map: &DefMap, path: &str, module: LocalModuleId) {
+ fn go(
+ buf: &mut String,
+ db: &dyn DefDatabase,
+ map: &DefMap,
+ path: &str,
+ module: LocalModuleId,
+ ) {
format_to!(buf, "{}\n", path);
- map.modules[module].scope.dump(buf);
+ map.modules[module].scope.dump(db.upcast(), buf);
for (name, child) in
map.modules[module].children.iter().sorted_by(|a, b| Ord::cmp(&a.0, &b.0))
{
- let path = format!("{path}::{name}");
+ let path = format!("{path}::{}", name.display(db.upcast()));
buf.push('\n');
- go(buf, map, &path, *child);
+ go(buf, db, map, &path, *child);
}
}
}
@@ -477,7 +561,7 @@ impl DefMap {
let mut current_map = self;
while let Some(block) = current_map.block {
format_to!(buf, "{:?} in {:?}\n", block.block, block.parent);
- arc = block.parent.def_map(db);
+ arc = block.parent.def_map(db, self.krate);
current_map = &arc;
}
@@ -489,34 +573,20 @@ impl DefMap {
// Exhaustive match to require handling new fields.
let Self {
_c: _,
- exported_derives,
- extern_prelude,
+ macro_use_prelude,
diagnostics,
modules,
- registered_attrs,
- registered_tools,
- fn_proc_macro_mapping,
derive_helpers_in_scope,
- unstable_features,
- proc_macro_loading_error: _,
block: _,
- edition: _,
- recursion_limit: _,
krate: _,
prelude: _,
- root: _,
- rustc_coherence_is_core: _,
+ data: _,
} = self;
- extern_prelude.shrink_to_fit();
- exported_derives.shrink_to_fit();
+ macro_use_prelude.shrink_to_fit();
diagnostics.shrink_to_fit();
modules.shrink_to_fit();
- registered_attrs.shrink_to_fit();
- registered_tools.shrink_to_fit();
- fn_proc_macro_mapping.shrink_to_fit();
derive_helpers_in_scope.shrink_to_fit();
- unstable_features.shrink_to_fit();
for (_, module) in modules.iter_mut() {
module.children.shrink_to_fit();
module.scope.shrink_to_fit();
@@ -529,7 +599,7 @@ impl DefMap {
}
pub fn recursion_limit(&self) -> Option<u32> {
- self.recursion_limit
+ self.data.recursion_limit
}
}
@@ -564,3 +634,48 @@ pub enum ModuleSource {
Module(ast::Module),
BlockExpr(ast::BlockExpr),
}
+
+/// See `sub_namespace_match()`.
+#[derive(Clone, Copy, PartialEq, Eq)]
+pub enum MacroSubNs {
+ /// Function-like macros, suffixed with `!`.
+ Bang,
+ /// Macros inside attributes, i.e. attribute macros and derive macros.
+ Attr,
+}
+
+impl MacroSubNs {
+ fn from_id(db: &dyn DefDatabase, macro_id: MacroId) -> Self {
+ let expander = match macro_id {
+ MacroId::Macro2Id(it) => it.lookup(db).expander,
+ MacroId::MacroRulesId(it) => it.lookup(db).expander,
+ MacroId::ProcMacroId(it) => {
+ return match it.lookup(db).kind {
+ ProcMacroKind::CustomDerive | ProcMacroKind::Attr => Self::Attr,
+ ProcMacroKind::FuncLike => Self::Bang,
+ };
+ }
+ };
+
+ // Eager macros aren't *guaranteed* to be bang macros, but they *are* all bang macros currently.
+ match expander {
+ MacroExpander::Declarative
+ | MacroExpander::BuiltIn(_)
+ | MacroExpander::BuiltInEager(_) => Self::Bang,
+ MacroExpander::BuiltInAttr(_) | MacroExpander::BuiltInDerive(_) => Self::Attr,
+ }
+ }
+}
+
+/// Quoted from [rustc]:
+/// Macro namespace is separated into two sub-namespaces, one for bang macros and
+/// one for attribute-like macros (attributes, derives).
+/// We ignore resolutions from one sub-namespace when searching names in scope for another.
+///
+/// [rustc]: https://github.com/rust-lang/rust/blob/1.69.0/compiler/rustc_resolve/src/macros.rs#L75
+fn sub_namespace_match(candidate: Option<MacroSubNs>, expected: Option<MacroSubNs>) -> bool {
+ match (candidate, expected) {
+ (Some(candidate), Some(expected)) => candidate == expected,
+ _ => true,
+ }
+}