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.rs170
1 files changed, 111 insertions, 59 deletions
diff --git a/crates/hir-def/src/nameres.rs b/crates/hir-def/src/nameres.rs
index 3b6e3c5916..fc66d8e28d 100644
--- a/crates/hir-def/src/nameres.rs
+++ b/crates/hir-def/src/nameres.rs
@@ -47,6 +47,7 @@
//! path and, upon success, we run macro expansion and "collect module" phase on
//! the result
+pub mod assoc;
pub mod attr_resolution;
mod collector;
pub mod diagnostics;
@@ -59,30 +60,30 @@ mod tests;
use std::ops::Deref;
-use base_db::CrateId;
+use base_db::Crate;
use hir_expand::{
- name::Name, proc_macro::ProcMacroKind, ErasedAstId, HirFileId, InFile, MacroCallId, MacroDefId,
+ EditionedFileId, ErasedAstId, HirFileId, InFile, MacroCallId, MacroDefId, mod_path::ModPath,
+ name::Name, proc_macro::ProcMacroKind,
};
use intern::Symbol;
use itertools::Itertools;
use la_arena::Arena;
use rustc_hash::{FxHashMap, FxHashSet};
-use span::{Edition, EditionedFileId, FileAstId, FileId, ROOT_ERASED_FILE_AST_ID};
+use span::{Edition, FileAstId, FileId, ROOT_ERASED_FILE_AST_ID};
use stdx::format_to;
-use syntax::{ast, AstNode, SmolStr, SyntaxNode};
+use syntax::{AstNode, SmolStr, SyntaxNode, ToSmolStr, ast};
use triomphe::Arc;
use tt::TextRange;
use crate::{
+ AstId, BlockId, BlockLoc, CrateRootModuleId, ExternCrateId, FunctionId, FxIndexMap,
+ LocalModuleId, Lookup, MacroExpander, MacroId, ModuleId, ProcMacroId, UseId,
db::DefDatabase,
item_scope::{BuiltinShadowMode, ItemScope},
item_tree::{ItemTreeId, Mod, TreeId},
nameres::{diagnostics::DefDiagnostic, path_resolution::ResolveMode},
- path::ModPath,
per_ns::PerNs,
visibility::{Visibility, VisibilityExplicitness},
- AstId, BlockId, BlockLoc, CrateRootModuleId, EnumId, EnumVariantId, ExternCrateId, FunctionId,
- FxIndexMap, LocalModuleId, Lookup, MacroExpander, MacroId, ModuleId, ProcMacroId, UseId,
};
pub use self::path_resolution::ResolvePathResultPrefixInfo;
@@ -95,6 +96,39 @@ const PREDEFINED_TOOLS: &[SmolStr] = &[
SmolStr::new_static("rust_analyzer"),
];
+/// Parts of the def map that are only needed when analyzing code in the same crate.
+///
+/// There are some data in the def map (e.g. extern prelude) that is only needed when analyzing
+/// things in the same crate (and maybe in the IDE layer), e.g. the extern prelude. If we put
+/// it in the DefMap dependant DefMaps will be invalidated when they change (e.g. when we add
+/// a dependency to the crate). Instead we split them out of the DefMap into a LocalDefMap struct.
+/// `crate_local_def_map()` returns both, and `crate_def_map()` returns only the external-relevant
+/// DefMap.
+#[derive(Debug, PartialEq, Eq, Default)]
+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>)>,
+}
+
+impl LocalDefMap {
+ pub(crate) const EMPTY: &Self =
+ &Self { extern_prelude: FxIndexMap::with_hasher(rustc_hash::FxBuildHasher) };
+
+ fn shrink_to_fit(&mut self) {
+ let Self { extern_prelude } = self;
+ extern_prelude.shrink_to_fit();
+ }
+
+ pub(crate) fn extern_prelude(
+ &self,
+ ) -> impl DoubleEndedIterator<Item = (&Name, (CrateRootModuleId, Option<ExternCrateId>))> + '_
+ {
+ self.extern_prelude.iter().map(|(name, &def)| (name, def))
+ }
+}
+
/// Contains the results of (early) name resolution.
///
/// A `DefMap` stores the module tree and the definitions that are in scope in every module after
@@ -107,7 +141,7 @@ const PREDEFINED_TOOLS: &[SmolStr] = &[
#[derive(Debug, PartialEq, Eq)]
pub struct DefMap {
/// The crate this `DefMap` belongs to.
- krate: CrateId,
+ krate: Crate,
/// 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>,
@@ -124,12 +158,15 @@ pub struct DefMap {
/// this contains all kinds of macro, not just `macro_rules!` macro.
/// ExternCrateId being None implies it being imported from the general prelude import.
macro_use_prelude: FxHashMap<Name, (MacroId, Option<ExternCrateId>)>,
- pub(crate) enum_definitions: FxHashMap<EnumId, Box<[EnumVariantId]>>,
+ // FIXME: AstId's are fairly unstable
/// Tracks which custom derives are in scope for an item, to allow resolution of derive helper
/// attributes.
// FIXME: Figure out a better way for the IDE layer to resolve these?
derive_helpers_in_scope: FxHashMap<AstId<ast::Item>, Vec<(Name, MacroId, MacroCallId)>>,
+ // FIXME: AstId's are fairly unstable
+ /// A mapping from [`hir_expand::MacroDefId`] to [`crate::MacroId`].
+ pub macro_def_to_macro_id: FxHashMap<ErasedAstId, MacroId>,
/// The diagnostics that need to be emitted for this crate.
diagnostics: Vec<DefDiagnostic>,
@@ -141,9 +178,6 @@ pub struct DefMap {
/// 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 {
- /// The extern prelude which contains all root modules of external crates that are in scope.
- extern_prelude: FxIndexMap<Name, (CrateRootModuleId, Option<ExternCrateId>)>,
-
/// Side table for resolving derive helpers.
exported_derives: FxHashMap<MacroDefId, Box<[Name]>>,
fn_proc_macro_mapping: FxHashMap<FunctionId, ProcMacroId>,
@@ -166,7 +200,6 @@ struct DefMapCrateData {
impl DefMapCrateData {
fn new(edition: Edition) -> Self {
Self {
- extern_prelude: FxIndexMap::default(),
exported_derives: FxHashMap::default(),
fn_proc_macro_mapping: FxHashMap::default(),
registered_attrs: Vec::new(),
@@ -182,7 +215,6 @@ impl DefMapCrateData {
fn shrink_to_fit(&mut self) {
let Self {
- extern_prelude,
exported_derives,
fn_proc_macro_mapping,
registered_attrs,
@@ -194,7 +226,6 @@ impl DefMapCrateData {
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();
@@ -219,11 +250,11 @@ struct BlockRelativeModuleId {
}
impl BlockRelativeModuleId {
- fn def_map(self, db: &dyn DefDatabase, krate: CrateId) -> Arc<DefMap> {
+ fn def_map(self, db: &dyn DefDatabase, krate: Crate) -> Arc<DefMap> {
self.into_module(krate).def_map(db)
}
- fn into_module(self, krate: CrateId) -> ModuleId {
+ fn into_module(self, krate: Crate) -> ModuleId {
ModuleId { krate, block: self.block, local_id: self.local_id }
}
@@ -295,18 +326,19 @@ impl ModuleOrigin {
/// That is, a file or a `mod foo {}` with items.
pub fn definition_source(&self, db: &dyn DefDatabase) -> InFile<ModuleSource> {
match self {
- &ModuleOrigin::File { definition, .. } | &ModuleOrigin::CrateRoot { definition } => {
- let sf = db.parse(definition).tree();
- InFile::new(definition.into(), ModuleSource::SourceFile(sf))
+ &ModuleOrigin::File { definition: editioned_file_id, .. }
+ | &ModuleOrigin::CrateRoot { definition: editioned_file_id } => {
+ let sf = db.parse(editioned_file_id).tree();
+ InFile::new(editioned_file_id.into(), ModuleSource::SourceFile(sf))
}
&ModuleOrigin::Inline { definition, definition_tree_id } => InFile::new(
definition_tree_id.file_id(),
ModuleSource::Module(
- AstId::new(definition_tree_id.file_id(), definition).to_node(db.upcast()),
+ AstId::new(definition_tree_id.file_id(), definition).to_node(db),
),
),
ModuleOrigin::BlockExpr { block, .. } => {
- InFile::new(block.file_id, ModuleSource::BlockExpr(block.to_node(db.upcast())))
+ InFile::new(block.file_id, ModuleSource::BlockExpr(block.to_node(db)))
}
}
}
@@ -334,14 +366,28 @@ impl DefMap {
self.data.edition
}
- pub(crate) fn crate_def_map_query(db: &dyn DefDatabase, crate_id: CrateId) -> Arc<DefMap> {
- let crate_graph = db.crate_graph();
- let krate = &crate_graph[crate_id];
- let name = krate.display_name.as_deref().map(Symbol::as_str).unwrap_or_default();
- let _p = tracing::info_span!("crate_def_map_query", ?name).entered();
+ pub(crate) fn crate_def_map_query(db: &dyn DefDatabase, crate_id: Crate) -> Arc<DefMap> {
+ db.crate_local_def_map(crate_id).0
+ }
+
+ pub(crate) fn crate_local_def_map_query(
+ db: &dyn DefDatabase,
+ crate_id: Crate,
+ ) -> (Arc<DefMap>, Arc<LocalDefMap>) {
+ let krate = crate_id.data(db);
+ let _p = tracing::info_span!(
+ "crate_def_map_query",
+ name=?crate_id
+ .extra_data(db)
+ .display_name
+ .as_ref()
+ .map(|it| it.crate_name().to_smolstr())
+ .unwrap_or_default()
+ )
+ .entered();
let module_data = ModuleData::new(
- ModuleOrigin::CrateRoot { definition: krate.root_file_id() },
+ ModuleOrigin::CrateRoot { definition: krate.root_file_id(db) },
Visibility::Public,
);
@@ -351,10 +397,14 @@ impl DefMap {
module_data,
None,
);
- let def_map =
- collector::collect_defs(db, def_map, TreeId::new(krate.root_file_id().into(), None));
+ let (def_map, local_def_map) = collector::collect_defs(
+ db,
+ def_map,
+ TreeId::new(krate.root_file_id(db).into(), None),
+ None,
+ );
- Arc::new(def_map)
+ (Arc::new(def_map), Arc::new(local_def_map))
}
pub(crate) fn block_def_map_query(db: &dyn DefDatabase, block_id: BlockId) -> Arc<DefMap> {
@@ -367,10 +417,10 @@ impl DefMap {
let module_data =
ModuleData::new(ModuleOrigin::BlockExpr { block: ast_id, id: block_id }, visibility);
- let parent_map = module.def_map(db);
+ let (crate_map, crate_local_map) = db.crate_local_def_map(module.krate);
let def_map = DefMap::empty(
module.krate,
- parent_map.data.clone(),
+ crate_map.data.clone(),
module_data,
Some(BlockInfo {
block: block_id,
@@ -378,13 +428,17 @@ impl DefMap {
}),
);
- let def_map =
- collector::collect_defs(db, def_map, TreeId::new(ast_id.file_id, Some(block_id)));
+ let (def_map, _) = collector::collect_defs(
+ db,
+ def_map,
+ TreeId::new(ast_id.file_id, Some(block_id)),
+ Some(crate_local_map),
+ );
Arc::new(def_map)
}
fn empty(
- krate: CrateId,
+ krate: Crate,
crate_data: Arc<DefMapCrateData>,
module_data: ModuleData,
block: Option<BlockInfo>,
@@ -401,8 +455,8 @@ impl DefMap {
macro_use_prelude: FxHashMap::default(),
derive_helpers_in_scope: FxHashMap::default(),
diagnostics: Vec::new(),
- enum_definitions: FxHashMap::default(),
data: crate_data,
+ macro_def_to_macro_id: FxHashMap::default(),
}
}
fn shrink_to_fit(&mut self) {
@@ -416,14 +470,14 @@ impl DefMap {
krate: _,
prelude: _,
data: _,
- enum_definitions,
+ macro_def_to_macro_id,
} = self;
+ macro_def_to_macro_id.shrink_to_fit();
macro_use_prelude.shrink_to_fit();
diagnostics.shrink_to_fit();
modules.shrink_to_fit();
derive_helpers_in_scope.shrink_to_fit();
- enum_definitions.shrink_to_fit();
for (_, module) in modules.iter_mut() {
module.children.shrink_to_fit();
module.scope.shrink_to_fit();
@@ -432,11 +486,15 @@ impl DefMap {
}
impl DefMap {
- pub fn modules_for_file(&self, file_id: FileId) -> impl Iterator<Item = LocalModuleId> + '_ {
+ pub fn modules_for_file<'a>(
+ &'a self,
+ db: &'a dyn DefDatabase,
+ file_id: FileId,
+ ) -> impl Iterator<Item = LocalModuleId> + 'a {
self.modules
.iter()
.filter(move |(_id, data)| {
- data.origin.file_id().map(EditionedFileId::file_id) == Some(file_id)
+ data.origin.file_id().map(|file_id| file_id.file_id(db)) == Some(file_id)
})
.map(|(id, _data)| id)
}
@@ -476,7 +534,7 @@ impl DefMap {
self.data.fn_proc_macro_mapping.get(&id).copied()
}
- pub fn krate(&self) -> CrateId {
+ pub fn krate(&self) -> Crate {
self.krate
}
@@ -551,12 +609,12 @@ impl DefMap {
) {
format_to!(buf, "{}\n", path);
- map.modules[module].scope.dump(db.upcast(), buf);
+ map.modules[module].scope.dump(db, 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.display(db.upcast(), Edition::LATEST));
+ let path = format!("{path}::{}", name.display(db, Edition::LATEST));
buf.push('\n');
go(buf, db, map, &path, *child);
}
@@ -587,19 +645,13 @@ impl DefMap {
self.prelude
}
- pub(crate) fn extern_prelude(
- &self,
- ) -> impl DoubleEndedIterator<Item = (&Name, (CrateRootModuleId, Option<ExternCrateId>))> + '_
- {
- self.data.extern_prelude.iter().map(|(name, &def)| (name, def))
- }
-
pub(crate) fn macro_use_prelude(&self) -> &FxHashMap<Name, (MacroId, Option<ExternCrateId>)> {
&self.macro_use_prelude
}
pub(crate) fn resolve_path(
&self,
+ local_def_map: &LocalDefMap,
db: &dyn DefDatabase,
original_module: LocalModuleId,
path: &ModPath,
@@ -607,6 +659,7 @@ impl DefMap {
expected_macro_subns: Option<MacroSubNs>,
) -> (PerNs, Option<usize>) {
let res = self.resolve_path_fp_with_macro(
+ local_def_map,
db,
ResolveMode::Other,
original_module,
@@ -621,12 +674,14 @@ impl DefMap {
/// points at the unresolved segments.
pub(crate) fn resolve_path_locally(
&self,
+ local_def_map: &LocalDefMap,
db: &dyn DefDatabase,
original_module: LocalModuleId,
path: &ModPath,
shadow: BuiltinShadowMode,
) -> (PerNs, Option<usize>, ResolvePathResultPrefixInfo) {
let res = self.resolve_path_fp_with_macro_single(
+ local_def_map,
db,
ResolveMode::Other,
original_module,
@@ -695,17 +750,14 @@ impl ModuleData {
&ModuleOrigin::File { definition, .. } | &ModuleOrigin::CrateRoot { definition } => {
InFile::new(
definition.into(),
- ErasedAstId::new(definition.into(), ROOT_ERASED_FILE_AST_ID)
- .to_range(db.upcast()),
+ ErasedAstId::new(definition.into(), ROOT_ERASED_FILE_AST_ID).to_range(db),
)
}
&ModuleOrigin::Inline { definition, definition_tree_id } => InFile::new(
definition_tree_id.file_id(),
- AstId::new(definition_tree_id.file_id(), definition).to_range(db.upcast()),
+ AstId::new(definition_tree_id.file_id(), definition).to_range(db),
),
- ModuleOrigin::BlockExpr { block, .. } => {
- InFile::new(block.file_id, block.to_range(db.upcast()))
- }
+ ModuleOrigin::BlockExpr { block, .. } => InFile::new(block.file_id, block.to_range(db)),
}
}
@@ -713,7 +765,7 @@ impl ModuleData {
/// `None` for the crate root or block.
pub fn declaration_source(&self, db: &dyn DefDatabase) -> Option<InFile<ast::Module>> {
let decl = self.origin.declaration()?;
- let value = decl.to_node(db.upcast());
+ let value = decl.to_node(db);
Some(InFile { file_id: decl.file_id, value })
}
@@ -721,7 +773,7 @@ impl ModuleData {
/// `None` for the crate root or block.
pub fn declaration_source_range(&self, db: &dyn DefDatabase) -> Option<InFile<TextRange>> {
let decl = self.origin.declaration()?;
- Some(InFile { file_id: decl.file_id, value: decl.to_range(db.upcast()) })
+ Some(InFile { file_id: decl.file_id, value: decl.to_range(db) })
}
}