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.rs330
1 files changed, 193 insertions, 137 deletions
diff --git a/crates/hir-def/src/nameres.rs b/crates/hir-def/src/nameres.rs
index 7d5e627964..5f05cdb1e2 100644
--- a/crates/hir-def/src/nameres.rs
+++ b/crates/hir-def/src/nameres.rs
@@ -58,7 +58,7 @@ pub mod proc_macro;
#[cfg(test)]
mod tests;
-use std::ops::Deref;
+use std::ops::{Deref, DerefMut, Index, IndexMut};
use base_db::Crate;
use hir_expand::{
@@ -67,7 +67,6 @@ use hir_expand::{
};
use intern::Symbol;
use itertools::Itertools;
-use la_arena::Arena;
use rustc_hash::{FxHashMap, FxHashSet};
use span::{Edition, FileAstId, FileId, ROOT_ERASED_FILE_AST_ID};
use stdx::format_to;
@@ -76,8 +75,8 @@ use triomphe::Arc;
use tt::TextRange;
use crate::{
- AstId, BlockId, BlockLoc, CrateRootModuleId, ExternCrateId, FunctionId, FxIndexMap,
- LocalModuleId, Lookup, MacroExpander, MacroId, ModuleId, ProcMacroId, UseId,
+ AstId, BlockId, BlockLoc, ExternCrateId, FunctionId, FxIndexMap, Lookup, MacroCallStyles,
+ MacroExpander, MacroId, ModuleId, ModuleIdLt, ProcMacroId, UseId,
db::DefDatabase,
item_scope::{BuiltinShadowMode, ItemScope},
item_tree::TreeId,
@@ -88,6 +87,25 @@ use crate::{
pub use self::path_resolution::ResolvePathResultPrefixInfo;
+#[cfg(test)]
+thread_local! {
+ /// HACK: In order to test builtin derive expansion, we gate their fast path with this atomic when cfg(test).
+ pub(crate) static ENABLE_BUILTIN_DERIVE_FAST_PATH: std::cell::Cell<bool> =
+ const { std::cell::Cell::new(true) };
+}
+
+#[inline]
+#[cfg(test)]
+fn enable_builtin_derive_fast_path() -> bool {
+ ENABLE_BUILTIN_DERIVE_FAST_PATH.get()
+}
+
+#[inline(always)]
+#[cfg(not(test))]
+fn enable_builtin_derive_fast_path() -> bool {
+ true
+}
+
const PREDEFINED_TOOLS: &[SmolStr] = &[
SmolStr::new_static("clippy"),
SmolStr::new_static("rustfmt"),
@@ -109,7 +127,7 @@ pub struct LocalDefMap {
// FIXME: There are probably some other things that could be here, but this is less severe and you
// need to be careful with things that block def maps also have.
/// The extern prelude which contains all root modules of external crates that are in scope.
- extern_prelude: FxIndexMap<Name, (CrateRootModuleId, Option<ExternCrateId>)>,
+ extern_prelude: FxIndexMap<Name, (ModuleId, Option<ExternCrateId>)>,
}
impl std::hash::Hash for LocalDefMap {
@@ -135,8 +153,7 @@ impl LocalDefMap {
pub(crate) fn extern_prelude(
&self,
- ) -> impl DoubleEndedIterator<Item = (&Name, (CrateRootModuleId, Option<ExternCrateId>))> + '_
- {
+ ) -> impl DoubleEndedIterator<Item = (&Name, (ModuleId, Option<ExternCrateId>))> + '_ {
self.extern_prelude.iter().map(|(name, &def)| (name, def))
}
}
@@ -157,8 +174,9 @@ pub struct DefMap {
/// When this is a block def map, this will hold the block id of the block and module that
/// contains this block.
block: Option<BlockInfo>,
+ pub root: ModuleId,
/// The modules and their data declared in this crate.
- pub modules: Arena<ModuleData>,
+ pub modules: ModulesMap,
/// The prelude module for this crate. This either comes from an import
/// marked with the `prelude_import` attribute, or (in the normal case) from
/// a dependency (`std` or `core`).
@@ -245,33 +263,22 @@ struct BlockInfo {
/// The `BlockId` this `DefMap` was created from.
block: BlockId,
/// The containing module.
- parent: BlockRelativeModuleId,
+ parent: ModuleId,
}
-#[derive(Debug, PartialEq, Eq, Clone, Copy)]
-struct BlockRelativeModuleId {
- block: Option<BlockId>,
- local_id: LocalModuleId,
-}
-
-impl BlockRelativeModuleId {
- fn def_map(self, db: &dyn DefDatabase, krate: Crate) -> &DefMap {
- self.into_module(krate).def_map(db)
- }
-
- fn into_module(self, krate: Crate) -> ModuleId {
- ModuleId { krate, block: self.block, local_id: self.local_id }
- }
+impl std::ops::Index<ModuleId> for DefMap {
+ type Output = ModuleData;
- fn is_block_module(self) -> bool {
- self.block.is_some() && self.local_id == DefMap::ROOT
+ fn index(&self, id: ModuleId) -> &ModuleData {
+ self.modules
+ .get(&id)
+ .unwrap_or_else(|| panic!("ModuleId not found in ModulesMap {:#?}: {id:#?}", self.root))
}
}
-impl std::ops::Index<LocalModuleId> for DefMap {
- type Output = ModuleData;
- fn index(&self, id: LocalModuleId) -> &ModuleData {
- &self.modules[id]
+impl std::ops::IndexMut<ModuleId> for DefMap {
+ fn index_mut(&mut self, id: ModuleId) -> &mut ModuleData {
+ &mut self.modules[id]
}
}
@@ -358,8 +365,8 @@ pub struct ModuleData {
/// Parent module in the same `DefMap`.
///
/// [`None`] for block modules because they are always its `DefMap`'s root.
- pub parent: Option<LocalModuleId>,
- pub children: FxIndexMap<Name, LocalModuleId>,
+ pub parent: Option<ModuleId>,
+ pub children: FxIndexMap<Name, ModuleId>,
pub scope: ItemScope,
}
@@ -391,19 +398,22 @@ pub(crate) fn crate_local_def_map(db: &dyn DefDatabase, crate_id: Crate) -> DefM
)
.entered();
+ let root_file_id = crate_id.root_file_id(db);
let module_data = ModuleData::new(
- ModuleOrigin::CrateRoot { definition: krate.root_file_id(db) },
+ ModuleOrigin::CrateRoot { definition: root_file_id },
Visibility::Public,
+ None,
);
- let def_map =
- DefMap::empty(crate_id, Arc::new(DefMapCrateData::new(krate.edition)), module_data, None);
- let (def_map, local_def_map) = collector::collect_defs(
+ let def_map = DefMap::empty(
db,
- def_map,
- TreeId::new(krate.root_file_id(db).into(), None),
+ crate_id,
+ Arc::new(DefMapCrateData::new(krate.edition)),
+ module_data,
None,
);
+ let (def_map, local_def_map) =
+ collector::collect_defs(db, def_map, TreeId::new(root_file_id.into(), None), None);
DefMapPair::new(db, def_map, local_def_map)
}
@@ -412,22 +422,18 @@ pub(crate) fn crate_local_def_map(db: &dyn DefDatabase, crate_id: Crate) -> DefM
pub fn block_def_map(db: &dyn DefDatabase, block_id: BlockId) -> DefMap {
let BlockLoc { ast_id, module } = block_id.lookup(db);
- let visibility = Visibility::Module(
- ModuleId { krate: module.krate, local_id: DefMap::ROOT, block: module.block },
- VisibilityExplicitness::Implicit,
- );
+ let visibility = Visibility::Module(module, VisibilityExplicitness::Implicit);
let module_data =
- ModuleData::new(ModuleOrigin::BlockExpr { block: ast_id, id: block_id }, visibility);
+ ModuleData::new(ModuleOrigin::BlockExpr { block: ast_id, id: block_id }, visibility, None);
- let local_def_map = crate_local_def_map(db, module.krate);
+ let krate = module.krate(db);
+ let local_def_map = crate_local_def_map(db, krate);
let def_map = DefMap::empty(
- module.krate,
+ db,
+ krate,
local_def_map.def_map(db).data.clone(),
module_data,
- Some(BlockInfo {
- block: block_id,
- parent: BlockRelativeModuleId { block: module.block, local_id: module.local_id },
- }),
+ Some(BlockInfo { block: block_id, parent: module }),
);
let (def_map, _) = collector::collect_defs(
@@ -440,25 +446,24 @@ pub fn block_def_map(db: &dyn DefDatabase, block_id: BlockId) -> DefMap {
}
impl DefMap {
- /// The module id of a crate or block root.
- pub const ROOT: LocalModuleId = LocalModuleId::from_raw(la_arena::RawIdx::from_u32(0));
-
pub fn edition(&self) -> Edition {
self.data.edition
}
fn empty(
+ db: &dyn DefDatabase,
krate: Crate,
crate_data: Arc<DefMapCrateData>,
module_data: ModuleData,
block: Option<BlockInfo>,
) -> DefMap {
- let mut modules: Arena<ModuleData> = Arena::default();
- let root = modules.alloc(module_data);
- assert_eq!(root, Self::ROOT);
+ let mut modules = ModulesMap::new();
+ let root = unsafe { ModuleIdLt::new(db, krate, block.map(|it| it.block)).to_static() };
+ modules.insert(root, module_data);
DefMap {
block,
+ root,
modules,
krate,
prelude: None,
@@ -476,6 +481,7 @@ impl DefMap {
diagnostics,
modules,
derive_helpers_in_scope,
+ root: _,
block: _,
krate: _,
prelude: _,
@@ -496,23 +502,41 @@ impl DefMap {
}
impl DefMap {
+ /// Returns all modules in the crate that are associated with the given file.
pub fn modules_for_file<'a>(
&'a self,
db: &'a dyn DefDatabase,
file_id: FileId,
- ) -> impl Iterator<Item = LocalModuleId> + 'a {
+ ) -> impl Iterator<Item = ModuleId> + 'a {
self.modules
.iter()
- .filter(move |(_id, data)| {
+ .filter(move |(_, data)| {
data.origin.file_id().map(|file_id| file_id.file_id(db)) == Some(file_id)
})
- .map(|(id, _data)| id)
+ .map(|(id, _)| id)
}
- pub fn modules(&self) -> impl Iterator<Item = (LocalModuleId, &ModuleData)> + '_ {
+ pub fn modules(&self) -> impl Iterator<Item = (ModuleId, &ModuleData)> + '_ {
self.modules.iter()
}
+ /// Returns all inline modules (mod name { ... }) in the crate that are associated with the given macro expansion.
+ pub fn inline_modules_for_macro_file(
+ &self,
+ file_id: MacroCallId,
+ ) -> impl Iterator<Item = ModuleId> + '_ {
+ self.modules
+ .iter()
+ .filter(move |(_, data)| {
+ matches!(
+ data.origin,
+ ModuleOrigin::Inline { definition_tree_id, .. }
+ if definition_tree_id.file_id().macro_file() == Some(file_id)
+ )
+ })
+ .map(|(id, _)| id)
+ }
+
pub fn derive_helpers_in_scope(
&self,
id: AstId<ast::Adt>,
@@ -548,40 +572,32 @@ impl DefMap {
self.krate
}
- pub fn module_id(&self, local_id: LocalModuleId) -> ModuleId {
- let block = self.block.map(|b| b.block);
- ModuleId { krate: self.krate, local_id, block }
- }
-
- pub fn crate_root(&self) -> CrateRootModuleId {
- CrateRootModuleId { krate: self.krate }
+ #[inline]
+ pub fn crate_root(&self, db: &dyn DefDatabase) -> ModuleId {
+ match self.block {
+ Some(_) => crate_def_map(db, self.krate()).root,
+ None => self.root,
+ }
}
/// This is the same as [`Self::crate_root`] for crate def maps, but for block def maps, it
/// returns the root block module.
pub fn root_module_id(&self) -> ModuleId {
- self.module_id(Self::ROOT)
+ self.root
}
/// 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> {
- let BlockRelativeModuleId { block, local_id } = self.block?.parent;
- Some(ModuleId { krate: self.krate, block, local_id })
+ Some(self.block?.parent)
}
/// Returns the module containing `local_mod`, either the parent `mod`, or the module (or block) containing
/// the block, if `self` corresponds to a block expression.
- pub fn containing_module(&self, local_mod: LocalModuleId) -> Option<ModuleId> {
+ pub fn containing_module(&self, local_mod: ModuleId) -> Option<ModuleId> {
match self[local_mod].parent {
- Some(parent) => Some(self.module_id(parent)),
- None => {
- self.block.map(
- |BlockInfo { parent: BlockRelativeModuleId { block, local_id }, .. }| {
- ModuleId { krate: self.krate, block, local_id }
- },
- )
- }
+ Some(parent) => Some(parent),
+ None => self.block.map(|BlockInfo { parent, .. }| parent),
}
}
@@ -599,30 +615,21 @@ impl DefMap {
// even), as this should be a great debugging aid.
pub fn dump(&self, db: &dyn DefDatabase) -> String {
let mut buf = String::new();
- let mut arc;
let mut current_map = self;
while let Some(block) = current_map.block {
- go(&mut buf, db, current_map, "block scope", Self::ROOT);
+ go(&mut buf, db, current_map, "(block scope)", current_map.root);
buf.push('\n');
- arc = block.parent.def_map(db, self.krate);
- current_map = arc;
+ current_map = block.parent.def_map(db);
}
- go(&mut buf, db, current_map, "crate", Self::ROOT);
+ go(&mut buf, db, current_map, "crate", current_map.root);
return buf;
- fn go(
- buf: &mut String,
- db: &dyn DefDatabase,
- map: &DefMap,
- path: &str,
- module: LocalModuleId,
- ) {
+ fn go(buf: &mut String, db: &dyn DefDatabase, map: &DefMap, path: &str, module: ModuleId) {
format_to!(buf, "{}\n", path);
- map.modules[module].scope.dump(db, buf);
+ map[module].scope.dump(db, buf);
- for (name, child) in
- map.modules[module].children.iter().sorted_by(|a, b| Ord::cmp(&a.0, &b.0))
+ for (name, child) in map[module].children.iter().sorted_by(|a, b| Ord::cmp(&a.0, &b.0))
{
let path = format!("{path}::{}", name.display(db, Edition::LATEST));
buf.push('\n');
@@ -630,20 +637,6 @@ impl DefMap {
}
}
}
-
- pub fn dump_block_scopes(&self, db: &dyn DefDatabase) -> String {
- let mut buf = String::new();
- let mut arc;
- 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, self.krate);
- current_map = arc;
- }
-
- format_to!(buf, "crate scope\n");
- buf
- }
}
impl DefMap {
@@ -663,7 +656,7 @@ impl DefMap {
&self,
local_def_map: &LocalDefMap,
db: &dyn DefDatabase,
- original_module: LocalModuleId,
+ original_module: ModuleId,
path: &ModPath,
shadow: BuiltinShadowMode,
expected_macro_subns: Option<MacroSubNs>,
@@ -686,7 +679,7 @@ impl DefMap {
&self,
local_def_map: &LocalDefMap,
db: &dyn DefDatabase,
- original_module: LocalModuleId,
+ original_module: ModuleId,
path: &ModPath,
shadow: BuiltinShadowMode,
) -> (PerNs, Option<usize>, ResolvePathResultPrefixInfo) {
@@ -709,16 +702,16 @@ impl DefMap {
pub(crate) fn with_ancestor_maps<T>(
&self,
db: &dyn DefDatabase,
- local_mod: LocalModuleId,
- f: &mut dyn FnMut(&DefMap, LocalModuleId) -> Option<T>,
+ local_mod: ModuleId,
+ f: &mut dyn FnMut(&DefMap, ModuleId) -> Option<T>,
) -> Option<T> {
if let Some(it) = f(self, local_mod) {
return Some(it);
}
let mut block = self.block;
while let Some(block_info) = block {
- let parent = block_info.parent.def_map(db, self.krate);
- if let Some(it) = f(parent, block_info.parent.local_id) {
+ let parent = block_info.parent.def_map(db);
+ if let Some(it) = f(parent, block_info.parent) {
return Some(it);
}
block = parent.block;
@@ -729,11 +722,15 @@ impl DefMap {
}
impl ModuleData {
- pub(crate) fn new(origin: ModuleOrigin, visibility: Visibility) -> Self {
+ pub(crate) fn new(
+ origin: ModuleOrigin,
+ visibility: Visibility,
+ parent: Option<ModuleId>,
+ ) -> Self {
ModuleData {
origin,
visibility,
- parent: None,
+ parent,
children: Default::default(),
scope: ItemScope::default(),
}
@@ -744,7 +741,7 @@ impl ModuleData {
self.origin.definition_source(db)
}
- /// Same as [`definition_source`] but only returns the file id to prevent parsing the ASt.
+ /// Same as [`ModuleData::definition_source`] but only returns the file id to prevent parsing the ASt.
pub fn definition_source_file_id(&self) -> HirFileId {
match self.origin {
ModuleOrigin::File { definition, .. } | ModuleOrigin::CrateRoot { definition } => {
@@ -813,26 +810,25 @@ pub enum MacroSubNs {
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::Bang => Self::Bang,
- };
- }
- };
+pub(crate) fn macro_styles_from_id(db: &dyn DefDatabase, macro_id: MacroId) -> MacroCallStyles {
+ 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 => MacroCallStyles::DERIVE,
+ ProcMacroKind::Bang => MacroCallStyles::FN_LIKE,
+ ProcMacroKind::Attr => MacroCallStyles::ATTR,
+ };
+ }
+ };
+ match expander {
+ MacroExpander::Declarative { styles } => styles,
// 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,
- }
+ MacroExpander::BuiltIn(_) | MacroExpander::BuiltInEager(_) => MacroCallStyles::FN_LIKE,
+ MacroExpander::BuiltInAttr(_) => MacroCallStyles::ATTR,
+ MacroExpander::BuiltInDerive(_) => MacroCallStyles::DERIVE,
}
}
@@ -842,9 +838,69 @@ impl MacroSubNs {
/// 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,
+fn sub_namespace_match(
+ db: &dyn DefDatabase,
+ macro_id: MacroId,
+ expected: Option<MacroSubNs>,
+) -> bool {
+ let candidate = macro_styles_from_id(db, macro_id);
+ match expected {
+ Some(MacroSubNs::Bang) => candidate.contains(MacroCallStyles::FN_LIKE),
+ Some(MacroSubNs::Attr) => {
+ candidate.contains(MacroCallStyles::ATTR) || candidate.contains(MacroCallStyles::DERIVE)
+ }
+ // If we aren't expecting a specific sub-namespace
+ // (e.g. in `use` declarations), match any macro.
+ None => true,
+ }
+}
+
+/// A newtype wrapper around `FxHashMap<ModuleId, ModuleData>` that implements `IndexMut`.
+#[derive(Debug, PartialEq, Eq)]
+pub struct ModulesMap {
+ inner: FxIndexMap<ModuleId, ModuleData>,
+}
+
+impl ModulesMap {
+ fn new() -> Self {
+ Self { inner: FxIndexMap::default() }
+ }
+
+ fn iter(&self) -> impl Iterator<Item = (ModuleId, &ModuleData)> + '_ {
+ self.inner.iter().map(|(&k, v)| (k, v))
+ }
+
+ fn iter_mut(&mut self) -> impl Iterator<Item = (ModuleId, &mut ModuleData)> + '_ {
+ self.inner.iter_mut().map(|(&k, v)| (k, v))
+ }
+}
+
+impl Deref for ModulesMap {
+ type Target = FxIndexMap<ModuleId, ModuleData>;
+
+ fn deref(&self) -> &Self::Target {
+ &self.inner
+ }
+}
+
+impl DerefMut for ModulesMap {
+ fn deref_mut(&mut self) -> &mut Self::Target {
+ &mut self.inner
+ }
+}
+
+impl Index<ModuleId> for ModulesMap {
+ type Output = ModuleData;
+
+ fn index(&self, id: ModuleId) -> &ModuleData {
+ self.inner.get(&id).unwrap_or_else(|| panic!("ModuleId not found in ModulesMap: {id:#?}"))
+ }
+}
+
+impl IndexMut<ModuleId> for ModulesMap {
+ fn index_mut(&mut self, id: ModuleId) -> &mut ModuleData {
+ self.inner
+ .get_mut(&id)
+ .unwrap_or_else(|| panic!("ModuleId not found in ModulesMap: {id:#?}"))
}
}