Merge pull request #19337 from ChayimFriedman2/salsify-crate-graph-final

Salsify the crate graph
This commit is contained in:
Chayim Refael Friedman 2025-03-12 19:17:29 +00:00 committed by GitHub
commit 3fc655b239
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
108 changed files with 3630 additions and 2512 deletions

View file

@ -2,7 +2,7 @@
use std::{borrow::Cow, hash::Hash, ops};
use base_db::CrateId;
use base_db::Crate;
use cfg::{CfgExpr, CfgOptions};
use either::Either;
use hir_expand::{
@ -44,7 +44,7 @@ impl Attrs {
(**self).iter().find(|attr| attr.id == id)
}
pub(crate) fn filter(db: &dyn DefDatabase, krate: CrateId, raw_attrs: RawAttrs) -> Attrs {
pub(crate) fn filter(db: &dyn DefDatabase, krate: Crate, raw_attrs: RawAttrs) -> Attrs {
Attrs(raw_attrs.filter(db.upcast(), krate))
}
}
@ -76,7 +76,6 @@ impl Attrs {
// FIXME: There should be some proper form of mapping between item tree field ids and hir field ids
let mut res = ArenaMap::default();
let crate_graph = db.crate_graph();
let item_tree;
let (parent, fields, krate) = match v {
VariantId::EnumVariantId(it) => {
@ -102,7 +101,7 @@ impl Attrs {
}
};
let cfg_options = &crate_graph[krate].cfg_options;
let cfg_options = krate.cfg_options(db);
let mut idx = 0;
for (id, _field) in fields.iter().enumerate() {

View file

@ -2,7 +2,7 @@
pub mod adt;
use base_db::CrateId;
use base_db::Crate;
use hir_expand::{
name::Name, AstId, ExpandResult, HirFileId, InFile, MacroCallId, MacroCallKind, MacroDefKind,
};
@ -22,7 +22,7 @@ use crate::{
attr_resolution::ResolvedAttr,
diagnostics::{DefDiagnostic, DefDiagnostics},
proc_macro::{parse_macro_name_and_helper_attrs, ProcMacroKind},
DefMap, MacroSubNs,
DefMap, LocalDefMap, MacroSubNs,
},
path::ImportAlias,
type_ref::{TraitRef, TypeBound, TypeRefId, TypesMap},
@ -57,8 +57,7 @@ impl FunctionData {
item_tree[func.visibility].clone()
};
let crate_graph = db.crate_graph();
let cfg_options = &crate_graph[krate].cfg_options;
let cfg_options = krate.cfg_options(db);
let attr_owner = |idx| {
item_tree::AttrOwner::Param(loc.id.value, Idx::from_raw(RawIdx::from(idx as u32)))
};
@ -525,7 +524,7 @@ pub struct ExternCrateDeclData {
pub name: Name,
pub alias: Option<ImportAlias>,
pub visibility: RawVisibility,
pub crate_id: Option<CrateId>,
pub crate_id: Option<Crate>,
}
impl ExternCrateDeclData {
@ -542,7 +541,7 @@ impl ExternCrateDeclData {
let crate_id = if name == sym::self_.clone() {
Some(krate)
} else {
db.crate_graph()[krate].dependencies.iter().find_map(|dep| {
krate.data(db).dependencies.iter().find_map(|dep| {
if dep.name.symbol() == name.symbol() {
Some(dep.crate_id)
} else {
@ -633,6 +632,7 @@ struct AssocItemCollector<'a> {
db: &'a dyn DefDatabase,
module_id: ModuleId,
def_map: Arc<DefMap>,
local_def_map: Arc<LocalDefMap>,
diagnostics: Vec<DefDiagnostic>,
container: ItemContainerId,
expander: Expander,
@ -648,10 +648,12 @@ impl<'a> AssocItemCollector<'a> {
file_id: HirFileId,
container: ItemContainerId,
) -> Self {
let (def_map, local_def_map) = module_id.local_def_map(db);
Self {
db,
module_id,
def_map: module_id.def_map(db),
def_map,
local_def_map,
container,
expander: Expander::new(db, file_id, module_id),
items: Vec::new(),
@ -697,6 +699,7 @@ impl<'a> AssocItemCollector<'a> {
let ast_id_with_path = AstIdWithPath { path: attr.path.clone(), ast_id };
match self.def_map.resolve_attr_macro(
&self.local_def_map,
self.db,
self.module_id.local_id,
ast_id_with_path,
@ -780,6 +783,7 @@ impl<'a> AssocItemCollector<'a> {
let resolver = |path: &_| {
self.def_map
.resolve_path(
&self.local_def_map,
self.db,
module,
path,

View file

@ -1,6 +1,6 @@
//! Defines hir-level representation of structs, enums and unions
use base_db::CrateId;
use base_db::Crate;
use bitflags::bitflags;
use cfg::CfgOptions;
use either::Either;
@ -90,7 +90,7 @@ pub struct FieldData {
fn repr_from_value(
db: &dyn DefDatabase,
krate: CrateId,
krate: Crate,
item_tree: &ItemTree,
of: AttrOwner,
) -> Option<ReprOptions> {
@ -222,7 +222,7 @@ impl StructData {
loc.container.local_id,
loc.id.tree_id(),
&item_tree,
&db.crate_graph()[krate].cfg_options,
krate.cfg_options(db),
FieldParent::Struct(loc.id.value),
&strukt.fields,
None,
@ -274,7 +274,7 @@ impl StructData {
loc.container.local_id,
loc.id.tree_id(),
&item_tree,
&db.crate_graph()[krate].cfg_options,
krate.cfg_options(db),
FieldParent::Union(loc.id.value),
&union.fields,
None,
@ -377,7 +377,7 @@ impl EnumVariantData {
container.local_id,
loc.id.tree_id(),
&item_tree,
&db.crate_graph()[krate].cfg_options,
krate.cfg_options(db),
FieldParent::Variant(loc.id.value),
&variant.fields,
Some(item_tree[loc.parent.lookup(db).id.value].visibility),
@ -448,7 +448,7 @@ pub enum StructKind {
fn lower_fields(
db: &dyn DefDatabase,
krate: CrateId,
krate: Crate,
container: LocalModuleId,
tree_id: TreeId,
item_tree: &ItemTree,

View file

@ -1,5 +1,5 @@
//! Defines database & queries for name resolution.
use base_db::{CrateId, RootQueryDb, SourceDatabase, Upcast};
use base_db::{Crate, RootQueryDb, SourceDatabase, Upcast};
use either::Either;
use hir_expand::{db::ExpandDatabase, HirFileId, MacroDefId};
use intern::sym;
@ -20,7 +20,7 @@ use crate::{
import_map::ImportMap,
item_tree::{AttrOwner, ItemTree, ItemTreeSourceMaps},
lang_item::{self, LangItem, LangItemTarget, LangItems},
nameres::{diagnostics::DefDiagnostics, DefMap},
nameres::{diagnostics::DefDiagnostics, DefMap, LocalDefMap},
tt,
type_ref::TypesSourceMap,
visibility::{self, Visibility},
@ -130,8 +130,11 @@ pub trait DefDatabase:
block_id: BlockId,
) -> (Arc<ItemTree>, Arc<ItemTreeSourceMaps>);
#[salsa::invoke(DefMap::crate_def_map_query)]
fn crate_def_map(&self, krate: CrateId) -> Arc<DefMap>;
#[salsa::invoke_actual(DefMap::crate_local_def_map_query)]
fn crate_local_def_map(&self, krate: Crate) -> (Arc<DefMap>, Arc<LocalDefMap>);
#[salsa::invoke_actual(DefMap::crate_def_map_query)]
fn crate_def_map(&self, krate: Crate) -> Arc<DefMap>;
/// Computes the block-level `DefMap`.
#[salsa::invoke_actual(DefMap::block_def_map_query)]
@ -258,10 +261,10 @@ pub trait DefDatabase:
// endregion:attrs
#[salsa::invoke(LangItems::lang_item_query)]
fn lang_item(&self, start_crate: CrateId, item: LangItem) -> Option<LangItemTarget>;
fn lang_item(&self, start_crate: Crate, item: LangItem) -> Option<LangItemTarget>;
#[salsa::invoke(ImportMap::import_map_query)]
fn import_map(&self, krate: CrateId) -> Arc<ImportMap>;
#[salsa::invoke_actual(ImportMap::import_map_query)]
fn import_map(&self, krate: Crate) -> Arc<ImportMap>;
// region:visibilities
@ -277,23 +280,25 @@ pub trait DefDatabase:
// endregion:visibilities
#[salsa::invoke(LangItems::crate_lang_items_query)]
fn crate_lang_items(&self, krate: CrateId) -> Option<Arc<LangItems>>;
#[salsa::invoke_actual(LangItems::crate_lang_items_query)]
fn crate_lang_items(&self, krate: Crate) -> Option<Arc<LangItems>>;
#[salsa::invoke(crate::lang_item::notable_traits_in_deps)]
fn notable_traits_in_deps(&self, krate: CrateId) -> Arc<[Arc<[TraitId]>]>;
#[salsa::invoke(crate::lang_item::crate_notable_traits)]
fn crate_notable_traits(&self, krate: CrateId) -> Option<Arc<[TraitId]>>;
#[salsa::invoke_actual(crate::lang_item::notable_traits_in_deps)]
fn notable_traits_in_deps(&self, krate: Crate) -> Arc<[Arc<[TraitId]>]>;
#[salsa::invoke_actual(crate::lang_item::crate_notable_traits)]
fn crate_notable_traits(&self, krate: Crate) -> Option<Arc<[TraitId]>>;
fn crate_supports_no_std(&self, crate_id: CrateId) -> bool;
#[salsa::invoke_actual(crate_supports_no_std)]
fn crate_supports_no_std(&self, crate_id: Crate) -> bool;
fn include_macro_invoc(&self, crate_id: CrateId) -> Arc<[(MacroCallId, EditionedFileId)]>;
#[salsa::invoke_actual(include_macro_invoc)]
fn include_macro_invoc(&self, crate_id: Crate) -> Arc<[(MacroCallId, EditionedFileId)]>;
}
// return: macro call id and include file id
fn include_macro_invoc(
db: &dyn DefDatabase,
krate: CrateId,
krate: Crate,
) -> Arc<[(MacroCallId, EditionedFileId)]> {
db.crate_def_map(krate)
.modules
@ -307,8 +312,8 @@ fn include_macro_invoc(
.collect()
}
fn crate_supports_no_std(db: &dyn DefDatabase, crate_id: CrateId) -> bool {
let file = db.crate_graph()[crate_id].root_file_id();
fn crate_supports_no_std(db: &dyn DefDatabase, crate_id: Crate) -> bool {
let file = crate_id.data(db).root_file_id();
let item_tree = db.file_item_tree(file.into());
let attrs = item_tree.raw_attrs(AttrOwner::TopLevel);
for attr in &**attrs {

View file

@ -2,7 +2,7 @@
use std::cell::OnceCell;
use base_db::CrateId;
use base_db::Crate;
use cfg::CfgOptions;
use drop_bomb::DropBomb;
use hir_expand::{
@ -44,7 +44,7 @@ impl Expander {
module,
recursion_depth: 0,
recursion_limit,
cfg_options: db.crate_graph()[module.krate].cfg_options.clone(),
cfg_options: Arc::clone(module.krate.cfg_options(db)),
span_map: OnceCell::new(),
}
}
@ -53,7 +53,7 @@ impl Expander {
self.span_map.get_or_init(|| db.span_map(self.current_file_id))
}
pub fn krate(&self) -> CrateId {
pub fn krate(&self) -> Crate {
self.module.krate
}

View file

@ -86,7 +86,6 @@ impl Body {
let item_tree = f.id.item_tree(db);
let func = &item_tree[f.id.value];
let krate = f.container.module(db).krate;
let crate_graph = db.crate_graph();
(
param_list,
(0..func.params.len()).map(move |idx| {
@ -99,7 +98,7 @@ impl Body {
Idx::from_raw(RawIdx::from(idx as u32)),
),
)
.is_cfg_enabled(&crate_graph[krate].cfg_options)
.is_cfg_enabled(krate.cfg_options(db))
}),
)
});

View file

@ -5,7 +5,7 @@ mod asm;
use std::mem;
use base_db::CrateId;
use base_db::Crate;
use either::Either;
use hir_expand::{
mod_path::tool_path,
@ -50,7 +50,7 @@ use crate::{
item_scope::BuiltinShadowMode,
lang_item::LangItem,
lower::LowerCtx,
nameres::{DefMap, MacroSubNs},
nameres::{DefMap, LocalDefMap, MacroSubNs},
path::{GenericArgs, Path},
type_ref::{Mutability, Rawness, TypeRef},
AdtId, BlockId, BlockLoc, ConstBlockLoc, DefWithBodyId, MacroId, ModuleDefId, UnresolvedMacro,
@ -64,7 +64,7 @@ pub(super) fn lower_body(
expander: Expander,
parameters: Option<(ast::ParamList, impl Iterator<Item = bool>)>,
body: Option<ast::Expr>,
krate: CrateId,
krate: Crate,
is_async_fn: bool,
) -> (Body, BodySourceMap) {
// We cannot leave the root span map empty and let any identifier from it be treated as root,
@ -189,7 +189,7 @@ pub(super) fn lower(
owner: ExprStoreOwnerId,
expander: Expander,
body: Option<ast::Expr>,
krate: CrateId,
krate: Crate,
) -> (ExpressionStore, ExpressionStoreSourceMap) {
// We cannot leave the root span map empty and let any identifier from it be treated as root,
// because when inside nested macros `SyntaxContextId`s from the outer macro will be interleaved
@ -214,8 +214,9 @@ struct ExprCollector<'a> {
expander: Expander,
owner: ExprStoreOwnerId,
def_map: Arc<DefMap>,
local_def_map: Arc<LocalDefMap>,
ast_id_map: Arc<AstIdMap>,
krate: CrateId,
krate: Crate,
store: ExpressionStoreBuilder,
source_map: ExpressionStoreSourceMap,
@ -327,14 +328,16 @@ impl ExprCollector<'_> {
db: &dyn DefDatabase,
owner: ExprStoreOwnerId,
expander: Expander,
krate: CrateId,
krate: Crate,
span_map: Option<Arc<ExpansionSpanMap>>,
) -> ExprCollector<'_> {
let (def_map, local_def_map) = expander.module.local_def_map(db);
ExprCollector {
db,
owner,
krate,
def_map: expander.module.def_map(db),
def_map,
local_def_map,
source_map: ExpressionStoreSourceMap::default(),
ast_id_map: db.ast_id_map(expander.current_file_id()),
store: ExpressionStoreBuilder::default(),
@ -1306,6 +1309,7 @@ impl ExprCollector<'_> {
None => self.expander.enter_expand(self.db, mcall, |path| {
self.def_map
.resolve_path(
&self.local_def_map,
self.db,
module,
path,
@ -1608,6 +1612,7 @@ impl ExprCollector<'_> {
// This could also be a single-segment path pattern. To
// decide that, we need to try resolving the name.
let (resolved, _) = self.def_map.resolve_path(
&self.local_def_map,
self.db,
self.expander.module.local_id,
&name.clone().into(),

View file

@ -293,7 +293,7 @@ impl SsrError {
assert_eq!(db.body_with_source_map(def).1.diagnostics(), &[]);
expect![[r#"
fn main() -> () {
_ = $crate::error::SsrError::new(
_ = ra_test_fixture::error::SsrError::new(
builtin#lang(Arguments::new_v1_formatted)(
&[
"Failed to resolve path `", "`",
@ -353,7 +353,7 @@ fn f(a: i32, b: u32) -> String {
expect![[r#"
fn f(a: i32, b: u32) -> String {
{
$crate::panicking::panic_fmt(
core::panicking::panic_fmt(
builtin#lang(Arguments::new_v1_formatted)(
&[
"cc",

View file

@ -2,7 +2,7 @@
use std::{cell::Cell, cmp::Ordering, iter};
use base_db::{CrateId, CrateOrigin, LangCrateOrigin};
use base_db::{Crate, CrateOrigin, LangCrateOrigin};
use hir_expand::{
name::{AsName, Name},
Lookup,
@ -50,7 +50,7 @@ pub fn find_path(
prefix: prefix_kind,
cfg,
ignore_local_imports,
is_std_item: db.crate_graph()[item_module.krate()].origin.is_lang(),
is_std_item: item_module.krate().data(db).origin.is_lang(),
from,
from_def_map: &from.def_map(db),
fuel: Cell::new(FIND_PATH_FUEL),
@ -174,9 +174,9 @@ fn find_path_for_module(
}
// - otherwise if the item is the crate root of a dependency crate, return the name from the extern prelude
let root_def_map = ctx.from.derive_crate_root().def_map(ctx.db);
let root_local_def_map = ctx.from.derive_crate_root().local_def_map(ctx.db).1;
// rev here so we prefer looking at renamed extern decls first
for (name, (def_id, _extern_crate)) in root_def_map.extern_prelude().rev() {
for (name, (def_id, _extern_crate)) in root_local_def_map.extern_prelude().rev() {
if crate_root != def_id {
continue;
}
@ -360,7 +360,7 @@ fn calculate_best_path(
// too (unless we can't name it at all). It could *also* be (re)exported by the same crate
// that wants to import it here, but we always prefer to use the external path here.
ctx.db.crate_graph()[ctx.from.krate].dependencies.iter().for_each(|dep| {
ctx.from.krate.data(ctx.db).dependencies.iter().for_each(|dep| {
find_in_dep(ctx, visited_modules, item, max_len, best_choice, dep.crate_id)
});
}
@ -373,11 +373,10 @@ fn find_in_sysroot(
max_len: usize,
best_choice: &mut Option<Choice>,
) {
let crate_graph = ctx.db.crate_graph();
let dependencies = &crate_graph[ctx.from.krate].dependencies;
let dependencies = &ctx.from.krate.data(ctx.db).dependencies;
let mut search = |lang, best_choice: &mut _| {
if let Some(dep) = dependencies.iter().filter(|it| it.is_sysroot()).find(|dep| {
match crate_graph[dep.crate_id].origin {
match dep.crate_id.data(ctx.db).origin {
CrateOrigin::Lang(l) => l == lang,
_ => false,
}
@ -419,7 +418,7 @@ fn find_in_dep(
item: ItemInNs,
max_len: usize,
best_choice: &mut Option<Choice>,
dep: CrateId,
dep: Crate,
) {
let import_map = ctx.db.import_map(dep);
let Some(import_info_for) = import_map.import_info_for(item) else {
@ -688,9 +687,10 @@ mod tests {
})
.unwrap();
let def_map = module.def_map(&db);
let (def_map, local_def_map) = module.local_def_map(&db);
let resolved = def_map
.resolve_path(
&local_def_map,
&db,
module.local_id,
&mod_path,

View file

@ -24,7 +24,7 @@ use crate::{
expander::Expander,
item_tree::{AttrOwner, FileItemTreeId, GenericModItem, GenericsItemTreeNode, ItemTree},
lower::LowerCtx,
nameres::{DefMap, MacroSubNs},
nameres::{DefMap, LocalDefMap, MacroSubNs},
path::{AssociatedTypeBinding, GenericArg, GenericArgs, NormalPath, Path},
type_ref::{
ArrayType, ConstRef, FnType, LifetimeRef, PathId, RefType, TypeBound, TypeRef, TypeRefId,
@ -314,8 +314,7 @@ impl GenericParams {
let _p = tracing::info_span!("generic_params_query").entered();
let krate = def.krate(db);
let cfg_options = db.crate_graph();
let cfg_options = &cfg_options[krate].cfg_options;
let cfg_options = &krate.cfg_options(db);
// Returns the generic parameters that are enabled under the current `#[cfg]` options
let enabled_params =
@ -414,7 +413,12 @@ impl GenericParams {
&mut types_source_maps,
&mut expander,
&mut || {
(module.def_map(db), Expander::new(db, loc.id.file_id(), module))
let (def_map, local_def_map) = module.local_def_map(db);
(
def_map,
local_def_map,
Expander::new(db, loc.id.file_id(), module),
)
},
param,
&item.types_map,
@ -638,8 +642,8 @@ impl GenericParamsCollector {
generics_types_map: &mut TypesMap,
generics_types_source_map: &mut TypesSourceMap,
// FIXME: Change this back to `LazyCell` if https://github.com/rust-lang/libs-team/issues/429 is accepted.
exp: &mut Option<(Arc<DefMap>, Expander)>,
exp_fill: &mut dyn FnMut() -> (Arc<DefMap>, Expander),
exp: &mut Option<(Arc<DefMap>, Arc<LocalDefMap>, Expander)>,
exp_fill: &mut dyn FnMut() -> (Arc<DefMap>, Arc<LocalDefMap>, Expander),
type_ref: TypeRefId,
types_map: &TypesMap,
types_source_map: &TypesSourceMap,
@ -669,12 +673,13 @@ impl GenericParamsCollector {
if let TypeRef::Macro(mc) = type_ref {
let macro_call = mc.to_node(db.upcast());
let (def_map, expander) = exp.get_or_insert_with(&mut *exp_fill);
let (def_map, local_def_map, expander) = exp.get_or_insert_with(&mut *exp_fill);
let module = expander.module.local_id;
let resolver = |path: &_| {
def_map
.resolve_path(
local_def_map,
db,
module,
path,
@ -702,7 +707,7 @@ impl GenericParamsCollector {
&macro_types_map,
&macro_types_source_map,
);
exp.get_or_insert_with(&mut *exp_fill).1.exit(mark);
exp.get_or_insert_with(&mut *exp_fill).2.exit(mark);
}
}
});

View file

@ -2,7 +2,7 @@
use std::fmt;
use base_db::CrateId;
use base_db::Crate;
use fst::{raw::IndexedValue, Automaton, Streamer};
use hir_expand::name::Name;
use itertools::Itertools;
@ -78,7 +78,7 @@ impl ImportMap {
out
}
pub(crate) fn import_map_query(db: &dyn DefDatabase, krate: CrateId) -> Arc<Self> {
pub(crate) fn import_map_query(db: &dyn DefDatabase, krate: Crate) -> Arc<Self> {
let _p = tracing::info_span!("import_map_query").entered();
let map = Self::collect_import_map(db, krate);
@ -129,7 +129,7 @@ impl ImportMap {
self.item_to_info_map.get(&item).map(|(info, _)| &**info)
}
fn collect_import_map(db: &dyn DefDatabase, krate: CrateId) -> ImportMapIndex {
fn collect_import_map(db: &dyn DefDatabase, krate: Crate) -> ImportMapIndex {
let _p = tracing::info_span!("collect_import_map").entered();
let def_map = db.crate_def_map(krate);
@ -400,15 +400,13 @@ impl Query {
/// This returns a list of items that could be imported from dependencies of `krate`.
pub fn search_dependencies(
db: &dyn DefDatabase,
krate: CrateId,
krate: Crate,
query: &Query,
) -> FxHashSet<ItemInNs> {
let _p = tracing::info_span!("search_dependencies", ?query).entered();
let graph = db.crate_graph();
let import_maps: Vec<_> =
graph[krate].dependencies.iter().map(|dep| db.import_map(dep.crate_id)).collect();
krate.data(db).dependencies.iter().map(|dep| db.import_map(dep.crate_id)).collect();
let mut op = fst::map::OpBuilder::new();
@ -512,11 +510,13 @@ mod tests {
expect: Expect,
) {
let db = TestDB::with_files(ra_fixture);
let crate_graph = db.crate_graph();
let krate = crate_graph
let all_crates = db.all_crates();
let krate = all_crates
.iter()
.copied()
.find(|&krate| {
crate_graph[krate]
krate
.extra_data(&db)
.display_name
.as_ref()
.is_some_and(|it| it.crate_name().as_str() == crate_name)
@ -545,7 +545,7 @@ mod tests {
Some(format!(
"{}::{} ({})\n",
crate_graph[dependency_krate].display_name.as_ref()?,
dependency_krate.extra_data(&db).display_name.as_ref()?,
path,
mark
))
@ -590,12 +590,13 @@ mod tests {
fn check(#[rust_analyzer::rust_fixture] ra_fixture: &str, expect: Expect) {
let db = TestDB::with_files(ra_fixture);
let crate_graph = db.crate_graph();
let all_crates = db.all_crates();
let actual = crate_graph
let actual = all_crates
.iter()
.copied()
.filter_map(|krate| {
let cdata = &crate_graph[krate];
let cdata = &krate.extra_data(&db);
let name = cdata.display_name.as_ref()?;
let map = db.import_map(krate);

View file

@ -3,7 +3,7 @@
use std::sync::LazyLock;
use base_db::CrateId;
use base_db::Crate;
use hir_expand::{attrs::AttrId, db::ExpandDatabase, name::Name, AstId, MacroCallId};
use indexmap::map::Entry;
use itertools::Itertools;
@ -916,7 +916,7 @@ impl ItemInNs {
}
/// Returns the crate defining this item (or `None` if `self` is built-in).
pub fn krate(&self, db: &dyn DefDatabase) -> Option<CrateId> {
pub fn krate(&self, db: &dyn DefDatabase) -> Option<Crate> {
match self {
ItemInNs::Types(id) | ItemInNs::Values(id) => id.module(db).map(|m| m.krate),
ItemInNs::Macros(id) => Some(id.module(db).krate),

View file

@ -44,7 +44,7 @@ use std::{
};
use ast::{AstNode, StructKind};
use base_db::CrateId;
use base_db::Crate;
use either::Either;
use hir_expand::{attrs::RawAttrs, name::Name, ExpandTo, HirFileId, InFile};
use intern::{Interned, Symbol};
@ -202,7 +202,7 @@ impl ItemTree {
}
/// Returns the inner attributes of the source file.
pub fn top_level_attrs(&self, db: &dyn DefDatabase, krate: CrateId) -> Attrs {
pub fn top_level_attrs(&self, db: &dyn DefDatabase, krate: Crate) -> Attrs {
Attrs::filter(
db,
krate,
@ -214,7 +214,7 @@ impl ItemTree {
self.attrs.get(&of).unwrap_or(&RawAttrs::EMPTY)
}
pub(crate) fn attrs(&self, db: &dyn DefDatabase, krate: CrateId, of: AttrOwner) -> Attrs {
pub(crate) fn attrs(&self, db: &dyn DefDatabase, krate: Crate, of: AttrOwner) -> Attrs {
Attrs::filter(db, krate, self.raw_attrs(of).clone())
}

View file

@ -8,7 +8,7 @@ use rustc_hash::FxHashMap;
use triomphe::Arc;
use crate::{
db::DefDatabase, path::Path, AdtId, AssocItemId, AttrDefId, CrateId, EnumId, EnumVariantId,
db::DefDatabase, path::Path, AdtId, AssocItemId, AttrDefId, Crate, EnumId, EnumVariantId,
FunctionId, ImplId, ModuleDefId, StaticId, StructId, TraitId, TypeAliasId, UnionId,
};
@ -96,7 +96,7 @@ impl LangItems {
/// Salsa query. This will look for lang items in a specific crate.
pub(crate) fn crate_lang_items_query(
db: &dyn DefDatabase,
krate: CrateId,
krate: Crate,
) -> Option<Arc<LangItems>> {
let _p = tracing::info_span!("crate_lang_items_query").entered();
@ -175,7 +175,7 @@ impl LangItems {
/// traversing its dependencies.
pub(crate) fn lang_item_query(
db: &dyn DefDatabase,
start_crate: CrateId,
start_crate: Crate,
item: LangItem,
) -> Option<LangItemTarget> {
let _p = tracing::info_span!("lang_item_query").entered();
@ -184,10 +184,7 @@ impl LangItems {
{
return Some(target);
}
db.crate_graph()[start_crate]
.dependencies
.iter()
.find_map(|dep| db.lang_item(dep.crate_id, item))
start_crate.data(db).dependencies.iter().find_map(|dep| db.lang_item(dep.crate_id, item))
}
fn collect_lang_item<T>(
@ -209,19 +206,14 @@ pub(crate) fn lang_attr(db: &dyn DefDatabase, item: AttrDefId) -> Option<LangIte
db.attrs(item).lang_item()
}
pub(crate) fn notable_traits_in_deps(
db: &dyn DefDatabase,
krate: CrateId,
) -> Arc<[Arc<[TraitId]>]> {
pub(crate) fn notable_traits_in_deps(db: &dyn DefDatabase, krate: Crate) -> Arc<[Arc<[TraitId]>]> {
let _p = tracing::info_span!("notable_traits_in_deps", ?krate).entered();
let crate_graph = db.crate_graph();
Arc::from_iter(
crate_graph.transitive_deps(krate).filter_map(|krate| db.crate_notable_traits(krate)),
db.transitive_deps(krate).into_iter().filter_map(|krate| db.crate_notable_traits(krate)),
)
}
pub(crate) fn crate_notable_traits(db: &dyn DefDatabase, krate: CrateId) -> Option<Arc<[TraitId]>> {
pub(crate) fn crate_notable_traits(db: &dyn DefDatabase, krate: Crate) -> Option<Arc<[TraitId]>> {
let _p = tracing::info_span!("crate_notable_traits", ?krate).entered();
let mut traits = Vec::new();
@ -290,17 +282,12 @@ impl LangItem {
Self::from_symbol(name.symbol())
}
pub fn path(&self, db: &dyn DefDatabase, start_crate: CrateId) -> Option<Path> {
pub fn path(&self, db: &dyn DefDatabase, start_crate: Crate) -> Option<Path> {
let t = db.lang_item(start_crate, *self)?;
Some(Path::LangItem(t, None))
}
pub fn ty_rel_path(
&self,
db: &dyn DefDatabase,
start_crate: CrateId,
seg: Name,
) -> Option<Path> {
pub fn ty_rel_path(&self, db: &dyn DefDatabase, start_crate: Crate, seg: Name) -> Option<Path> {
let t = db.lang_item(start_crate, *self)?;
Some(Path::LangItem(t, Some(seg)))
}

View file

@ -71,7 +71,7 @@ mod test_db;
use std::hash::{Hash, Hasher};
use base_db::{impl_intern_key, CrateId};
use base_db::{impl_intern_key, Crate};
use hir_expand::{
builtin::{BuiltinAttrExpander, BuiltinDeriveExpander, BuiltinFnLikeExpander, EagerExpander},
db::ExpandDatabase,
@ -99,10 +99,10 @@ use crate::{
Const, Enum, ExternCrate, Function, Impl, ItemTreeId, ItemTreeNode, Macro2, MacroRules,
Static, Struct, Trait, TraitAlias, TypeAlias, Union, Use, Variant,
},
nameres::LocalDefMap,
};
type FxIndexMap<K, V> =
indexmap::IndexMap<K, V, std::hash::BuildHasherDefault<rustc_hash::FxHasher>>;
type FxIndexMap<K, V> = indexmap::IndexMap<K, V, rustc_hash::FxBuildHasher>;
/// A wrapper around three booleans
#[derive(Debug, Clone, PartialEq, Eq, Hash, Copy)]
pub struct ImportPathConfig {
@ -338,7 +338,7 @@ pub struct ConstBlockLoc {
/// A `ModuleId` that is always a crate's root module.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct CrateRootModuleId {
krate: CrateId,
krate: Crate,
}
impl CrateRootModuleId {
@ -346,7 +346,11 @@ impl CrateRootModuleId {
db.crate_def_map(self.krate)
}
pub fn krate(self) -> CrateId {
pub(crate) fn local_def_map(&self, db: &dyn DefDatabase) -> (Arc<DefMap>, Arc<LocalDefMap>) {
db.crate_local_def_map(self.krate)
}
pub fn krate(self) -> Crate {
self.krate
}
}
@ -374,8 +378,8 @@ impl From<CrateRootModuleId> for ModuleDefId {
}
}
impl From<CrateId> for CrateRootModuleId {
fn from(krate: CrateId) -> Self {
impl From<Crate> for CrateRootModuleId {
fn from(krate: Crate) -> Self {
CrateRootModuleId { krate }
}
}
@ -394,7 +398,7 @@ impl TryFrom<ModuleId> for CrateRootModuleId {
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub struct ModuleId {
krate: CrateId,
krate: Crate,
/// If this `ModuleId` was derived from a `DefMap` for a block expression, this stores the
/// `BlockId` of that block expression. If `None`, this module is part of the crate-level
/// `DefMap` of `krate`.
@ -411,11 +415,22 @@ impl ModuleId {
}
}
pub(crate) fn local_def_map(self, db: &dyn DefDatabase) -> (Arc<DefMap>, Arc<LocalDefMap>) {
match self.block {
Some(block) => (db.block_def_map(block), self.only_local_def_map(db)),
None => db.crate_local_def_map(self.krate),
}
}
pub(crate) fn only_local_def_map(self, db: &dyn DefDatabase) -> Arc<LocalDefMap> {
db.crate_local_def_map(self.krate).1
}
pub fn crate_def_map(self, db: &dyn DefDatabase) -> Arc<DefMap> {
db.crate_def_map(self.krate)
}
pub fn krate(self) -> CrateId {
pub fn krate(self) -> Crate {
self.krate
}
@ -982,7 +997,7 @@ impl From<CallableDefId> for ModuleDefId {
}
impl CallableDefId {
pub fn krate(self, db: &dyn DefDatabase) -> CrateId {
pub fn krate(self, db: &dyn DefDatabase) -> Crate {
match self {
CallableDefId::FunctionId(f) => f.krate(db),
CallableDefId::StructId(s) => s.krate(db),
@ -1119,7 +1134,7 @@ pub trait HasModule {
/// Returns the crate this thing is defined within.
#[inline]
#[doc(alias = "crate")]
fn krate(&self, db: &dyn DefDatabase) -> CrateId {
fn krate(&self, db: &dyn DefDatabase) -> Crate {
self.module(db).krate
}
}
@ -1367,7 +1382,7 @@ pub trait AsMacroCall {
fn as_call_id(
&self,
db: &dyn ExpandDatabase,
krate: CrateId,
krate: Crate,
resolver: impl Fn(&path::ModPath) -> Option<MacroDefId> + Copy,
) -> Option<MacroCallId> {
self.as_call_id_with_errors(db, krate, resolver).ok()?.value
@ -1376,7 +1391,7 @@ pub trait AsMacroCall {
fn as_call_id_with_errors(
&self,
db: &dyn ExpandDatabase,
krate: CrateId,
krate: Crate,
resolver: impl Fn(&path::ModPath) -> Option<MacroDefId> + Copy,
) -> Result<ExpandResult<Option<MacroCallId>>, UnresolvedMacro>;
}
@ -1385,7 +1400,7 @@ impl AsMacroCall for InFile<&ast::MacroCall> {
fn as_call_id_with_errors(
&self,
db: &dyn ExpandDatabase,
krate: CrateId,
krate: Crate,
resolver: impl Fn(&path::ModPath) -> Option<MacroDefId> + Copy,
) -> Result<ExpandResult<Option<MacroCallId>>, UnresolvedMacro> {
let expands_to = hir_expand::ExpandTo::from_call_site(self.value);
@ -1442,7 +1457,7 @@ fn macro_call_as_call_id(
call: &AstIdWithPath<ast::MacroCall>,
call_site: SyntaxContextId,
expand_to: ExpandTo,
krate: CrateId,
krate: Crate,
resolver: impl Fn(&path::ModPath) -> Option<MacroDefId> + Copy,
) -> Result<Option<MacroCallId>, UnresolvedMacro> {
macro_call_as_call_id_with_eager(
@ -1464,7 +1479,7 @@ fn macro_call_as_call_id_with_eager(
path: &path::ModPath,
call_site: SyntaxContextId,
expand_to: ExpandTo,
krate: CrateId,
krate: Crate,
resolver: impl FnOnce(&path::ModPath) -> Option<MacroDefId>,
eager_resolver: impl Fn(&path::ModPath) -> Option<MacroDefId>,
) -> Result<ExpandResult<Option<MacroCallId>>, UnresolvedMacro> {

View file

@ -376,4 +376,8 @@ impl ProcMacroExpander for IdentityWhenValidProcMacroExpander {
panic!("got invalid macro input: {:?}", parse.errors());
}
}
fn eq_dyn(&self, other: &dyn ProcMacroExpander) -> bool {
other.as_any().type_id() == std::any::TypeId::of::<Self>()
}
}

View file

@ -59,7 +59,7 @@ 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,
};
@ -69,7 +69,7 @@ use la_arena::Arena;
use rustc_hash::{FxHashMap, FxHashSet};
use span::{Edition, EditionedFileId, FileAstId, FileId, ROOT_ERASED_FILE_AST_ID};
use stdx::format_to;
use syntax::{ast, AstNode, SmolStr, SyntaxNode};
use syntax::{ast, AstNode, SmolStr, SyntaxNode, ToSmolStr};
use triomphe::Arc;
use tt::TextRange;
@ -95,6 +95,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 +140,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>,
@ -141,9 +174,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 +196,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 +211,6 @@ impl DefMapCrateData {
fn shrink_to_fit(&mut self) {
let Self {
extern_prelude,
exported_derives,
fn_proc_macro_mapping,
registered_attrs,
@ -194,7 +222,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 +246,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 }
}
@ -337,11 +364,25 @@ 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() },
@ -354,10 +395,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().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> {
@ -370,10 +415,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,
@ -381,13 +426,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>,
@ -479,7 +528,7 @@ impl DefMap {
self.data.fn_proc_macro_mapping.get(&id).copied()
}
pub fn krate(&self) -> CrateId {
pub fn krate(&self) -> Crate {
self.krate
}
@ -590,19 +639,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,
@ -610,6 +653,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,
@ -624,12 +668,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,

View file

@ -1,6 +1,6 @@
//! Post-nameres attribute resolution.
use base_db::CrateId;
use base_db::Crate;
use hir_expand::{
attrs::{Attr, AttrId, AttrInput},
inert_attr_macro::find_builtin_attr_idx,
@ -13,7 +13,7 @@ use triomphe::Arc;
use crate::{
db::DefDatabase,
item_scope::BuiltinShadowMode,
nameres::path_resolution::ResolveMode,
nameres::{path_resolution::ResolveMode, LocalDefMap},
path::{self, ModPath, PathKind},
AstIdWithPath, LocalModuleId, MacroId, UnresolvedMacro,
};
@ -30,6 +30,7 @@ pub enum ResolvedAttr {
impl DefMap {
pub(crate) fn resolve_attr_macro(
&self,
local_def_map: &LocalDefMap,
db: &dyn DefDatabase,
original_module: LocalModuleId,
ast_id: AstIdWithPath<ast::Item>,
@ -42,6 +43,7 @@ impl DefMap {
}
let resolved_res = self.resolve_path_fp_with_macro(
local_def_map,
db,
ResolveMode::Other,
original_module,
@ -105,7 +107,7 @@ pub(super) fn attr_macro_as_call_id(
db: &dyn DefDatabase,
item_attr: &AstIdWithPath<ast::Item>,
macro_attr: &Attr,
krate: CrateId,
krate: Crate,
def: MacroDefId,
) -> MacroCallId {
let arg = match macro_attr.input.as_deref() {
@ -136,7 +138,7 @@ pub(super) fn derive_macro_as_call_id(
derive_attr_index: AttrId,
derive_pos: u32,
call_site: SyntaxContextId,
krate: CrateId,
krate: Crate,
resolver: impl Fn(&path::ModPath) -> Option<(MacroId, MacroDefId)>,
derive_macro_id: MacroCallId,
) -> Result<(MacroId, MacroDefId, MacroCallId), UnresolvedMacro> {

View file

@ -5,7 +5,7 @@
use std::{cmp::Ordering, iter, mem, ops::Not};
use base_db::{CrateId, CrateOrigin, Dependency, LangCrateOrigin};
use base_db::{BuiltDependency, Crate, CrateOrigin, LangCrateOrigin};
use cfg::{CfgAtom, CfgExpr, CfgOptions};
use either::Either;
use hir_expand::{
@ -39,8 +39,8 @@ use crate::{
mod_resolution::ModDir,
path_resolution::ReachedFixedPoint,
proc_macro::{parse_macro_name_and_helper_attrs, ProcMacroDef, ProcMacroKind},
sub_namespace_match, BuiltinShadowMode, DefMap, MacroSubNs, ModuleData, ModuleOrigin,
ResolveMode,
sub_namespace_match, BuiltinShadowMode, DefMap, LocalDefMap, MacroSubNs, ModuleData,
ModuleOrigin, ResolveMode,
},
path::{ImportAlias, ModPath, PathKind},
per_ns::{Item, PerNs},
@ -57,10 +57,14 @@ use crate::{
const GLOB_RECURSION_LIMIT: usize = 100;
const FIXED_POINT_LIMIT: usize = 8192;
pub(super) fn collect_defs(db: &dyn DefDatabase, def_map: DefMap, tree_id: TreeId) -> DefMap {
let crate_graph = db.crate_graph();
let krate = &crate_graph[def_map.krate];
pub(super) fn collect_defs(
db: &dyn DefDatabase,
def_map: DefMap,
tree_id: TreeId,
crate_local_def_map: Option<Arc<LocalDefMap>>,
) -> (DefMap, LocalDefMap) {
let krate = &def_map.krate.data(db);
let cfg_options = def_map.krate.cfg_options(db);
// populate external prelude and dependency list
let mut deps =
@ -72,8 +76,10 @@ pub(super) fn collect_defs(db: &dyn DefDatabase, def_map: DefMap, tree_id: TreeI
}
let proc_macros = if krate.is_proc_macro {
db.proc_macros()
.for_crate(def_map.krate, db.syntax_context(tree_id.file_id(), krate.edition))
db.proc_macros_for_crate(def_map.krate)
.and_then(|proc_macros| {
proc_macros.list(db.syntax_context(tree_id.file_id(), krate.edition))
})
.unwrap_or_default()
} else {
Default::default()
@ -82,13 +88,15 @@ pub(super) fn collect_defs(db: &dyn DefDatabase, def_map: DefMap, tree_id: TreeI
let mut collector = DefCollector {
db,
def_map,
local_def_map: LocalDefMap::default(),
crate_local_def_map,
deps,
glob_imports: FxHashMap::default(),
unresolved_imports: Vec::new(),
indeterminate_imports: Vec::new(),
unresolved_macros: Vec::new(),
mod_dirs: FxHashMap::default(),
cfg_options: &krate.cfg_options,
cfg_options,
proc_macros,
from_glob_import: Default::default(),
skip_attrs: Default::default(),
@ -101,9 +109,10 @@ pub(super) fn collect_defs(db: &dyn DefDatabase, def_map: DefMap, tree_id: TreeI
collector.seed_with_top_level();
}
collector.collect();
let mut def_map = collector.finish();
let (mut def_map, mut local_def_map) = collector.finish();
def_map.shrink_to_fit();
def_map
local_def_map.shrink_to_fit();
(def_map, local_def_map)
}
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
@ -205,8 +214,11 @@ enum MacroDirectiveKind {
struct DefCollector<'a> {
db: &'a dyn DefDatabase,
def_map: DefMap,
local_def_map: LocalDefMap,
/// Set only in case of blocks.
crate_local_def_map: Option<Arc<LocalDefMap>>,
// The dependencies of the current crate, including optional deps like `test`.
deps: FxHashMap<Name, Dependency>,
deps: FxHashMap<Name, BuiltDependency>,
glob_imports: FxHashMap<LocalModuleId, Vec<(LocalModuleId, Visibility, GlobId)>>,
unresolved_imports: Vec<ImportDirective>,
indeterminate_imports: Vec<(ImportDirective, PerNs)>,
@ -238,8 +250,7 @@ impl DefCollector<'_> {
fn seed_with_top_level(&mut self) {
let _p = tracing::info_span!("seed_with_top_level").entered();
let crate_graph = self.db.crate_graph();
let file_id = crate_graph[self.def_map.krate].root_file_id();
let file_id = self.def_map.krate.data(self.db).root_file_id();
let item_tree = self.db.file_item_tree(file_id.into());
let attrs = item_tree.top_level_attrs(self.db, self.def_map.krate);
let crate_data = Arc::get_mut(&mut self.def_map.data).unwrap();
@ -310,20 +321,24 @@ impl DefCollector<'_> {
// don't do pre-configured attribute resolution yet.
// So here check if we are no_core / no_std and we are trying to add the
// corresponding dep from the sysroot
let skip = match crate_graph[dep.crate_id].origin {
CrateOrigin::Lang(LangCrateOrigin::Core) => {
crate_data.no_core && dep.is_sysroot()
}
CrateOrigin::Lang(LangCrateOrigin::Std) => {
crate_data.no_std && dep.is_sysroot()
}
_ => false,
};
// Depending on the crate data of a dependency seems bad for incrementality, but
// we only do that for sysroot crates (this is why the order of the `&&` is important)
// - which are normally standard library crate, which realistically aren't going
// to have their crate ID invalidated, because they stay on the same root file and
// they're dependencies of everything else, so if some collision miraculously occurs
// we will resolve it by disambiguating the other crate.
let skip = dep.is_sysroot()
&& match dep.crate_id.data(self.db).origin {
CrateOrigin::Lang(LangCrateOrigin::Core) => crate_data.no_core,
CrateOrigin::Lang(LangCrateOrigin::Std) => crate_data.no_std,
_ => false,
};
if skip {
continue;
}
crate_data
self.local_def_map
.extern_prelude
.insert(name.clone(), (CrateRootModuleId { krate: dep.crate_id }, None));
}
@ -494,7 +509,7 @@ impl DefCollector<'_> {
let krate = if self.def_map.data.no_std {
Name::new_symbol_root(sym::core.clone())
} else if self.def_map.extern_prelude().any(|(name, _)| *name == sym::std.clone()) {
} else if self.local_def_map().extern_prelude().any(|(name, _)| *name == sym::std.clone()) {
Name::new_symbol_root(sym::std.clone())
} else {
// If `std` does not exist for some reason, fall back to core. This mostly helps
@ -518,8 +533,14 @@ impl DefCollector<'_> {
[krate, Name::new_symbol_root(sym::prelude.clone()), edition],
);
let (per_ns, _) =
self.def_map.resolve_path(self.db, DefMap::ROOT, &path, BuiltinShadowMode::Other, None);
let (per_ns, _) = self.def_map.resolve_path(
self.crate_local_def_map.as_deref().unwrap_or(&self.local_def_map),
self.db,
DefMap::ROOT,
&path,
BuiltinShadowMode::Other,
None,
);
match per_ns.types {
Some(Item { def: ModuleDefId::ModuleId(m), import, .. }) => {
@ -535,6 +556,10 @@ impl DefCollector<'_> {
}
}
fn local_def_map(&mut self) -> &LocalDefMap {
self.crate_local_def_map.as_deref().unwrap_or(&self.local_def_map)
}
/// Adds a definition of procedural macro `name` to the root module.
///
/// # Notes on procedural macro resolution
@ -660,7 +685,13 @@ impl DefCollector<'_> {
) {
let vis = self
.def_map
.resolve_visibility(self.db, module_id, vis, false)
.resolve_visibility(
self.crate_local_def_map.as_deref().unwrap_or(&self.local_def_map),
self.db,
module_id,
vis,
false,
)
.unwrap_or(Visibility::Public);
self.def_map.modules[module_id].scope.declare(macro_.into());
self.update(
@ -694,7 +725,7 @@ impl DefCollector<'_> {
/// created by `use` in the root module, ignoring the visibility of `use`.
fn import_macros_from_extern_crate(
&mut self,
krate: CrateId,
krate: Crate,
names: Option<Vec<Name>>,
extern_crate: Option<ExternCrateId>,
) {
@ -779,6 +810,7 @@ impl DefCollector<'_> {
.entered();
tracing::debug!("resolving import: {:?} ({:?})", import, self.def_map.data.edition);
let res = self.def_map.resolve_path_fp_with_macro(
self.crate_local_def_map.as_deref().unwrap_or(&self.local_def_map),
self.db,
ResolveMode::Import,
module_id,
@ -814,7 +846,13 @@ impl DefCollector<'_> {
let mut def = directive.status.namespaces();
let vis = self
.def_map
.resolve_visibility(self.db, module_id, &directive.import.visibility, false)
.resolve_visibility(
self.crate_local_def_map.as_deref().unwrap_or(&self.local_def_map),
self.db,
module_id,
&directive.import.visibility,
false,
)
.unwrap_or(Visibility::Public);
match import.source {
@ -1210,6 +1248,7 @@ impl DefCollector<'_> {
};
let resolver = |path: &_| {
let resolved_res = self.def_map.resolve_path_fp_with_macro(
self.crate_local_def_map.as_deref().unwrap_or(&self.local_def_map),
self.db,
ResolveMode::Other,
directive.module_id,
@ -1495,7 +1534,7 @@ impl DefCollector<'_> {
.collect(item_tree.top_level_items(), container);
}
fn finish(mut self) -> DefMap {
fn finish(mut self) -> (DefMap, LocalDefMap) {
// Emit diagnostics for all remaining unexpanded macros.
let _p = tracing::info_span!("DefCollector::finish").entered();
@ -1511,6 +1550,7 @@ impl DefCollector<'_> {
self.def_map.krate,
|path| {
let resolved_res = self.def_map.resolve_path_fp_with_macro(
self.crate_local_def_map.as_deref().unwrap_or(&self.local_def_map),
self.db,
ResolveMode::Other,
directive.module_id,
@ -1582,7 +1622,7 @@ impl DefCollector<'_> {
));
}
self.def_map
(self.def_map, self.local_def_map)
}
}
@ -1635,9 +1675,9 @@ impl ModCollector<'_, '_> {
None,
)
};
let resolve_vis = |def_map: &DefMap, visibility| {
let resolve_vis = |def_map: &DefMap, local_def_map: &LocalDefMap, visibility| {
def_map
.resolve_visibility(db, module_id, visibility, false)
.resolve_visibility(local_def_map, db, module_id, visibility, false)
.unwrap_or(Visibility::Public)
};
@ -1658,6 +1698,11 @@ impl ModCollector<'_, '_> {
let module = self.def_collector.def_map.module_id(module_id);
let def_map = &mut self.def_collector.def_map;
let local_def_map = self
.def_collector
.crate_local_def_map
.as_deref()
.unwrap_or(&self.def_collector.local_def_map);
match item {
ModItem::Mod(m) => self.collect_module(m, &attrs),
@ -1711,13 +1756,13 @@ impl ModCollector<'_, '_> {
};
if let Some(resolved) = resolved {
let vis = resolve_vis(def_map, &self.item_tree[*visibility]);
let vis = resolve_vis(def_map, local_def_map, &self.item_tree[*visibility]);
if is_crate_root {
// extern crates in the crate root are special-cased to insert entries into the extern prelude: rust-lang/rust#54658
if let Some(name) = name {
Arc::get_mut(&mut def_map.data)
.unwrap()
self.def_collector
.local_def_map
.extern_prelude
.insert(name.clone(), (resolved, Some(id)));
}
@ -1784,7 +1829,7 @@ impl ModCollector<'_, '_> {
let fn_id =
FunctionLoc { container, id: ItemTreeId::new(self.tree_id, id) }.intern(db);
let vis = resolve_vis(def_map, &self.item_tree[it.visibility]);
let vis = resolve_vis(def_map, local_def_map, &self.item_tree[it.visibility]);
if self.def_collector.def_map.block.is_none()
&& self.def_collector.is_proc_macro
@ -1804,7 +1849,7 @@ impl ModCollector<'_, '_> {
ModItem::Struct(id) => {
let it = &self.item_tree[id];
let vis = resolve_vis(def_map, &self.item_tree[it.visibility]);
let vis = resolve_vis(def_map, local_def_map, &self.item_tree[it.visibility]);
update_def(
self.def_collector,
StructLoc { container: module, id: ItemTreeId::new(self.tree_id, id) }
@ -1818,7 +1863,7 @@ impl ModCollector<'_, '_> {
ModItem::Union(id) => {
let it = &self.item_tree[id];
let vis = resolve_vis(def_map, &self.item_tree[it.visibility]);
let vis = resolve_vis(def_map, local_def_map, &self.item_tree[it.visibility]);
update_def(
self.def_collector,
UnionLoc { container: module, id: ItemTreeId::new(self.tree_id, id) }
@ -1835,7 +1880,7 @@ impl ModCollector<'_, '_> {
EnumLoc { container: module, id: ItemTreeId::new(self.tree_id, id) }
.intern(db);
let vis = resolve_vis(def_map, &self.item_tree[it.visibility]);
let vis = resolve_vis(def_map, local_def_map, &self.item_tree[it.visibility]);
update_def(self.def_collector, enum_.into(), &it.name, vis, false);
let mut index = 0;
@ -1878,7 +1923,8 @@ impl ModCollector<'_, '_> {
match &it.name {
Some(name) => {
let vis = resolve_vis(def_map, &self.item_tree[it.visibility]);
let vis =
resolve_vis(def_map, local_def_map, &self.item_tree[it.visibility]);
update_def(self.def_collector, const_id.into(), name, vis, false);
}
None => {
@ -1892,7 +1938,7 @@ impl ModCollector<'_, '_> {
ModItem::Static(id) => {
let it = &self.item_tree[id];
let vis = resolve_vis(def_map, &self.item_tree[it.visibility]);
let vis = resolve_vis(def_map, local_def_map, &self.item_tree[it.visibility]);
update_def(
self.def_collector,
StaticLoc { container, id: ItemTreeId::new(self.tree_id, id) }
@ -1906,7 +1952,7 @@ impl ModCollector<'_, '_> {
ModItem::Trait(id) => {
let it = &self.item_tree[id];
let vis = resolve_vis(def_map, &self.item_tree[it.visibility]);
let vis = resolve_vis(def_map, local_def_map, &self.item_tree[it.visibility]);
update_def(
self.def_collector,
TraitLoc { container: module, id: ItemTreeId::new(self.tree_id, id) }
@ -1920,7 +1966,7 @@ impl ModCollector<'_, '_> {
ModItem::TraitAlias(id) => {
let it = &self.item_tree[id];
let vis = resolve_vis(def_map, &self.item_tree[it.visibility]);
let vis = resolve_vis(def_map, local_def_map, &self.item_tree[it.visibility]);
update_def(
self.def_collector,
TraitAliasLoc { container: module, id: ItemTreeId::new(self.tree_id, id) }
@ -1934,7 +1980,7 @@ impl ModCollector<'_, '_> {
ModItem::TypeAlias(id) => {
let it = &self.item_tree[id];
let vis = resolve_vis(def_map, &self.item_tree[it.visibility]);
let vis = resolve_vis(def_map, local_def_map, &self.item_tree[it.visibility]);
update_def(
self.def_collector,
TypeAliasLoc { container, id: ItemTreeId::new(self.tree_id, id) }
@ -1971,7 +2017,7 @@ impl ModCollector<'_, '_> {
&mut self,
extern_crate_id: ExternCrateId,
macro_use_attrs: impl Iterator<Item = &'a Attr>,
target_crate: CrateId,
target_crate: Crate,
) {
cov_mark::hit!(macro_rules_from_other_crates_are_visible_with_macro_use);
let mut single_imports = Vec::new();
@ -2115,7 +2161,16 @@ impl ModCollector<'_, '_> {
) -> LocalModuleId {
let def_map = &mut self.def_collector.def_map;
let vis = def_map
.resolve_visibility(self.def_collector.db, self.module_id, visibility, false)
.resolve_visibility(
self.def_collector
.crate_local_def_map
.as_deref()
.unwrap_or(&self.def_collector.local_def_map),
self.def_collector.db,
self.module_id,
visibility,
false,
)
.unwrap_or(Visibility::Public);
let origin = match definition {
None => ModuleOrigin::Inline {
@ -2417,6 +2472,10 @@ impl ModCollector<'_, '_> {
},
|path| {
let resolved_res = self.def_collector.def_map.resolve_path_fp_with_macro(
self.def_collector
.crate_local_def_map
.as_deref()
.unwrap_or(&self.def_collector.local_def_map),
db,
ResolveMode::Other,
self.module_id,
@ -2517,7 +2576,6 @@ impl ModCollector<'_, '_> {
#[cfg(test)]
mod tests {
use base_db::RootQueryDb;
use test_fixture::WithFixture;
use crate::{nameres::DefMapCrateData, test_db::TestDB};
@ -2528,6 +2586,8 @@ mod tests {
let mut collector = DefCollector {
db,
def_map,
local_def_map: LocalDefMap::default(),
crate_local_def_map: None,
deps: FxHashMap::default(),
glob_imports: FxHashMap::default(),
unresolved_imports: Vec::new(),
@ -2550,7 +2610,7 @@ mod tests {
let (db, file_id) = TestDB::with_single_file(not_ra_fixture);
let krate = db.test_crate();
let edition = db.crate_graph()[krate].edition;
let edition = krate.data(&db).edition;
let module_origin = ModuleOrigin::CrateRoot { definition: file_id };
let def_map = DefMap::empty(
krate,

View file

@ -19,7 +19,7 @@ use crate::{
db::DefDatabase,
item_scope::{ImportOrExternCrate, BUILTIN_SCOPE},
item_tree::FieldsShape,
nameres::{sub_namespace_match, BlockInfo, BuiltinShadowMode, DefMap, MacroSubNs},
nameres::{sub_namespace_match, BlockInfo, BuiltinShadowMode, DefMap, LocalDefMap, MacroSubNs},
path::{ModPath, PathKind},
per_ns::PerNs,
visibility::{RawVisibility, Visibility},
@ -91,6 +91,7 @@ impl PerNs {
impl DefMap {
pub(crate) fn resolve_visibility(
&self,
local_def_map: &LocalDefMap,
db: &dyn DefDatabase,
// module to import to
original_module: LocalModuleId,
@ -101,8 +102,14 @@ impl DefMap {
) -> Option<Visibility> {
let mut vis = match visibility {
RawVisibility::Module(path, explicitness) => {
let (result, remaining) =
self.resolve_path(db, original_module, path, BuiltinShadowMode::Module, None);
let (result, remaining) = self.resolve_path(
local_def_map,
db,
original_module,
path,
BuiltinShadowMode::Module,
None,
);
if remaining.is_some() {
return None;
}
@ -137,6 +144,7 @@ impl DefMap {
// the result.
pub(super) fn resolve_path_fp_with_macro(
&self,
local_def_map: &LocalDefMap,
db: &dyn DefDatabase,
mode: ResolveMode,
// module to import to
@ -148,6 +156,7 @@ impl DefMap {
expected_macro_subns: Option<MacroSubNs>,
) -> ResolvePathResult {
let mut result = self.resolve_path_fp_with_macro_single(
local_def_map,
db,
mode,
original_module,
@ -196,6 +205,7 @@ impl DefMap {
current_map = &arc;
let new = current_map.resolve_path_fp_in_all_preludes(
local_def_map,
db,
mode,
original_module,
@ -210,6 +220,7 @@ impl DefMap {
}
let new = current_map.resolve_path_fp_with_macro_single(
local_def_map,
db,
mode,
original_module,
@ -224,6 +235,7 @@ impl DefMap {
pub(super) fn resolve_path_fp_with_macro_single(
&self,
local_def_map: &LocalDefMap,
db: &dyn DefDatabase,
mode: ResolveMode,
original_module: LocalModuleId,
@ -258,7 +270,12 @@ impl DefMap {
None => return ResolvePathResult::empty(ReachedFixedPoint::Yes),
};
tracing::debug!("resolving {:?} in crate root (+ extern prelude)", segment);
self.resolve_name_in_crate_root_or_extern_prelude(db, original_module, segment)
self.resolve_name_in_crate_root_or_extern_prelude(
local_def_map,
db,
original_module,
segment,
)
}
PathKind::Plain => {
let (_, segment) = match segments.next() {
@ -276,6 +293,7 @@ impl DefMap {
tracing::debug!("resolving {:?} in module", segment);
self.resolve_name_in_module(
local_def_map,
db,
original_module,
segment,
@ -321,7 +339,9 @@ impl DefMap {
// with), resolve the remaining path segments in that `DefMap`.
let path =
ModPath::from_segments(PathKind::SELF, path.segments().iter().cloned());
// This is the same crate, so the local def map is the same.
return def_map.resolve_path_fp_with_macro(
local_def_map,
db,
mode,
local_id,
@ -333,7 +353,7 @@ impl DefMap {
PerNs::types(module.into(), Visibility::Public, None)
}
PathKind::Abs => match self.resolve_path_abs(&mut segments, path) {
PathKind::Abs => match self.resolve_path_abs(local_def_map, &mut segments, path) {
Either::Left(it) => it,
Either::Right(reached_fixed_point) => {
return ResolvePathResult::empty(reached_fixed_point)
@ -347,6 +367,7 @@ impl DefMap {
/// Resolves a path only in the preludes, without accounting for item scopes.
pub(super) fn resolve_path_fp_in_all_preludes(
&self,
local_def_map: &LocalDefMap,
db: &dyn DefDatabase,
mode: ResolveMode,
original_module: LocalModuleId,
@ -368,7 +389,7 @@ impl DefMap {
None => return ResolvePathResult::empty(ReachedFixedPoint::Yes),
};
tracing::debug!("resolving {:?} in crate root (+ extern prelude)", segment);
self.resolve_name_in_extern_prelude(segment)
self.resolve_name_in_extern_prelude(local_def_map, segment)
}
PathKind::Plain => {
let (_, segment) = match segments.next() {
@ -376,9 +397,9 @@ impl DefMap {
None => return ResolvePathResult::empty(ReachedFixedPoint::Yes),
};
tracing::debug!("resolving {:?} in module", segment);
self.resolve_name_in_all_preludes(db, segment)
self.resolve_name_in_all_preludes(local_def_map, db, segment)
}
PathKind::Abs => match self.resolve_path_abs(&mut segments, path) {
PathKind::Abs => match self.resolve_path_abs(local_def_map, &mut segments, path) {
Either::Left(it) => it,
Either::Right(reached_fixed_point) => {
return ResolvePathResult::empty(reached_fixed_point)
@ -395,6 +416,7 @@ impl DefMap {
/// 2018-style absolute path -- only extern prelude
fn resolve_path_abs<'a>(
&self,
local_def_map: &LocalDefMap,
segments: &mut impl Iterator<Item = (usize, &'a Name)>,
path: &ModPath,
) -> Either<PerNs, ReachedFixedPoint> {
@ -402,7 +424,7 @@ impl DefMap {
Some((_, segment)) => segment,
None => return Either::Right(ReachedFixedPoint::Yes),
};
if let Some(&(def, extern_crate)) = self.data.extern_prelude.get(segment) {
if let Some(&(def, extern_crate)) = local_def_map.extern_prelude.get(segment) {
tracing::debug!("absolute path {:?} resolved to crate {:?}", path, def);
Either::Left(PerNs::types(
def.into(),
@ -451,6 +473,7 @@ impl DefMap {
// this point, we know we're resolving a multi-segment path so macro kind
// expectation is discarded.
let resolution = defp_map.resolve_path_fp_with_macro(
LocalDefMap::EMPTY,
db,
ResolveMode::Other,
module.local_id,
@ -568,6 +591,7 @@ impl DefMap {
fn resolve_name_in_module(
&self,
local_def_map: &LocalDefMap,
db: &dyn DefDatabase,
module: LocalModuleId,
name: &Name,
@ -611,7 +635,7 @@ impl DefMap {
// they might been shadowed by local names.
return PerNs::none();
}
self.resolve_name_in_extern_prelude(name)
self.resolve_name_in_extern_prelude(local_def_map, name)
};
let macro_use_prelude = || self.resolve_in_macro_use_prelude(name);
let prelude = || {
@ -628,19 +652,24 @@ impl DefMap {
.or_else(prelude)
}
fn resolve_name_in_all_preludes(&self, db: &dyn DefDatabase, name: &Name) -> PerNs {
fn resolve_name_in_all_preludes(
&self,
local_def_map: &LocalDefMap,
db: &dyn DefDatabase,
name: &Name,
) -> PerNs {
// Resolve in:
// - extern prelude / macro_use prelude
// - std prelude
let extern_prelude = self.resolve_name_in_extern_prelude(name);
let extern_prelude = self.resolve_name_in_extern_prelude(local_def_map, name);
let macro_use_prelude = || self.resolve_in_macro_use_prelude(name);
let prelude = || self.resolve_in_prelude(db, name);
extern_prelude.or_else(macro_use_prelude).or_else(prelude)
}
fn resolve_name_in_extern_prelude(&self, name: &Name) -> PerNs {
self.data.extern_prelude.get(name).map_or(PerNs::none(), |&(it, extern_crate)| {
fn resolve_name_in_extern_prelude(&self, local_def_map: &LocalDefMap, name: &Name) -> PerNs {
local_def_map.extern_prelude.get(name).map_or(PerNs::none(), |&(it, extern_crate)| {
PerNs::types(
it.into(),
Visibility::Public,
@ -662,6 +691,7 @@ impl DefMap {
fn resolve_name_in_crate_root_or_extern_prelude(
&self,
local_def_map: &LocalDefMap,
db: &dyn DefDatabase,
module: LocalModuleId,
name: &Name,
@ -678,7 +708,7 @@ impl DefMap {
// Don't resolve extern prelude in pseudo-module of a block.
return PerNs::none();
}
self.resolve_name_in_extern_prelude(name)
self.resolve_name_in_extern_prelude(local_def_map, name)
};
from_crate_root.or_else(from_extern_prelude)

View file

@ -1,5 +1,11 @@
use base_db::SourceDatabase;
use base_db::{
CrateDisplayName, CrateGraphBuilder, CrateName, CrateOrigin, CrateWorkspaceData,
DependencyBuilder, Env, RootQueryDb, SourceDatabase,
};
use intern::Symbol;
use span::Edition;
use test_fixture::WithFixture;
use triomphe::Arc;
use crate::{db::DefDatabase, nameres::tests::TestDB, AdtId, ModuleDefId};
@ -22,6 +28,73 @@ fn check_def_map_is_not_recomputed(ra_fixture_initial: &str, ra_fixture_change:
}
}
#[test]
fn crate_metadata_changes_should_not_invalidate_unrelated_def_maps() {
let (mut db, files) = TestDB::with_many_files(
r#"
//- /a.rs crate:a
pub fn foo() {}
//- /b.rs crate:b
pub struct Bar;
//- /c.rs crate:c deps:b
pub const BAZ: u32 = 0;
"#,
);
for &krate in db.all_crates().iter() {
db.crate_def_map(krate);
}
let all_crates_before = db.all_crates();
{
// Add a dependency a -> b.
let mut new_crate_graph = CrateGraphBuilder::default();
let mut add_crate = |crate_name, root_file_idx: usize| {
new_crate_graph.add_crate_root(
files[root_file_idx].file_id(),
Edition::CURRENT,
Some(CrateDisplayName::from_canonical_name(crate_name)),
None,
Arc::default(),
None,
Env::default(),
CrateOrigin::Local { repo: None, name: Some(Symbol::intern(crate_name)) },
false,
None,
Arc::new(CrateWorkspaceData { data_layout: Err("".into()), toolchain: None }),
)
};
let a = add_crate("a", 0);
let b = add_crate("b", 1);
let c = add_crate("c", 2);
new_crate_graph
.add_dep(c, DependencyBuilder::new(CrateName::new("b").unwrap(), b))
.unwrap();
new_crate_graph
.add_dep(b, DependencyBuilder::new(CrateName::new("a").unwrap(), a))
.unwrap();
new_crate_graph.set_in_db(&mut db);
}
let all_crates_after = db.all_crates();
assert!(
Arc::ptr_eq(&all_crates_before, &all_crates_after),
"the all_crates list should not have been invalidated"
);
let events = db.log_executed(|| {
for &krate in db.all_crates().iter() {
db.crate_def_map(krate);
}
});
let invalidated_def_maps =
events.iter().filter(|event| event.contains("crate_def_map")).count();
assert_eq!(invalidated_def_maps, 1, "{events:#?}")
}
#[test]
fn typing_inside_a_function_should_not_invalidate_def_map() {
check_def_map_is_not_recomputed(

View file

@ -1095,7 +1095,7 @@ pub fn derive_macro_2(_item: TokenStream) -> TokenStream {
}
"#,
);
let krate = db.crate_graph().iter().next().unwrap();
let krate = *db.all_crates().last().unwrap();
let def_map = db.crate_def_map(krate);
assert_eq!(def_map.data.exported_derives.len(), 1);
@ -1445,7 +1445,7 @@ struct TokenStream;
fn proc_attr(a: TokenStream, b: TokenStream) -> TokenStream { a }
"#,
);
let krate = db.crate_graph().iter().next().unwrap();
let krate = *db.all_crates().last().unwrap();
let def_map = db.crate_def_map(krate);
let root_module = &def_map[DefMap::ROOT].scope;

View file

@ -80,7 +80,16 @@ pub(crate) fn print_path(
}
PathKind::Crate => write!(buf, "crate")?,
PathKind::Abs => {}
PathKind::DollarCrate(_) => write!(buf, "$crate")?,
PathKind::DollarCrate(krate) => write!(
buf,
"{}",
krate
.extra_data(db)
.display_name
.as_ref()
.map(|it| it.crate_name().symbol().as_str())
.unwrap_or("$crate")
)?,
},
}

View file

@ -1,7 +1,7 @@
//! Name resolution façade.
use std::{fmt, iter, mem};
use base_db::CrateId;
use base_db::Crate;
use hir_expand::{name::Name, MacroDefId};
use intern::{sym, Symbol};
use itertools::Itertools as _;
@ -22,7 +22,7 @@ use crate::{
hir::{BindingId, ExprId, LabelId},
item_scope::{BuiltinShadowMode, ImportOrExternCrate, ImportOrGlob, BUILTIN_SCOPE},
lang_item::LangItemTarget,
nameres::{DefMap, MacroSubNs, ResolvePathResultPrefixInfo},
nameres::{DefMap, LocalDefMap, MacroSubNs, ResolvePathResultPrefixInfo},
path::{ModPath, Path, PathKind},
per_ns::PerNs,
type_ref::{LifetimeRef, TypesMap},
@ -47,6 +47,7 @@ pub struct Resolver {
#[derive(Clone)]
struct ModuleItemMap {
def_map: Arc<DefMap>,
local_def_map: Arc<LocalDefMap>,
module_id: LocalModuleId,
}
@ -278,8 +279,8 @@ impl Resolver {
let within_impl = self.scopes().any(|scope| matches!(scope, Scope::ImplDefScope(_)));
match visibility {
RawVisibility::Module(_, _) => {
let (item_map, module) = self.item_scope();
item_map.resolve_visibility(db, module, visibility, within_impl)
let (item_map, item_local_map, module) = self.item_scope();
item_map.resolve_visibility(item_local_map, db, module, visibility, within_impl)
}
RawVisibility::Public => Some(Visibility::Public),
}
@ -474,9 +475,16 @@ impl Resolver {
path: &ModPath,
expected_macro_kind: Option<MacroSubNs>,
) -> Option<(MacroId, Option<ImportOrGlob>)> {
let (item_map, module) = self.item_scope();
let (item_map, item_local_map, module) = self.item_scope();
item_map
.resolve_path(db, module, path, BuiltinShadowMode::Other, expected_macro_kind)
.resolve_path(
item_local_map,
db,
module,
path,
BuiltinShadowMode::Other,
expected_macro_kind,
)
.0
.take_macros_import()
}
@ -550,7 +558,7 @@ impl Resolver {
for scope in self.scopes() {
scope.process_names(&mut res, db);
}
let ModuleItemMap { ref def_map, module_id } = self.module_scope;
let ModuleItemMap { ref def_map, module_id, ref local_def_map } = self.module_scope;
// FIXME: should we provide `self` here?
// f(
// Name::self_param(),
@ -572,7 +580,7 @@ impl Resolver {
res.add(name, ScopeDef::ModuleDef(def.into()));
},
);
def_map.extern_prelude().for_each(|(name, (def, _extern_crate))| {
local_def_map.extern_prelude().for_each(|(name, (def, _extern_crate))| {
res.add(name, ScopeDef::ModuleDef(ModuleDefId::ModuleId(def.into())));
});
BUILTIN_SCOPE.iter().for_each(|(name, &def)| {
@ -599,7 +607,7 @@ impl Resolver {
pub fn extern_crates_in_scope(&self) -> impl Iterator<Item = (Name, ModuleId)> + '_ {
self.module_scope
.def_map
.local_def_map
.extern_prelude()
.map(|(name, module_id)| (name.clone(), module_id.0.into()))
}
@ -647,11 +655,11 @@ impl Resolver {
}
pub fn module(&self) -> ModuleId {
let (def_map, local_id) = self.item_scope();
let (def_map, _, local_id) = self.item_scope();
def_map.module_id(local_id)
}
pub fn krate(&self) -> CrateId {
pub fn krate(&self) -> Crate {
self.module_scope.def_map.krate()
}
@ -844,9 +852,12 @@ impl Resolver {
}));
if let Some(block) = expr_scopes.block(scope_id) {
let def_map = db.block_def_map(block);
resolver
.scopes
.push(Scope::BlockScope(ModuleItemMap { def_map, module_id: DefMap::ROOT }));
let local_def_map = block.lookup(db).module.only_local_def_map(db);
resolver.scopes.push(Scope::BlockScope(ModuleItemMap {
def_map,
local_def_map,
module_id: DefMap::ROOT,
}));
// FIXME: This adds as many module scopes as there are blocks, but resolving in each
// already traverses all parents, so this is O(n²). I think we could only store the
// innermost module scope instead?
@ -933,9 +944,10 @@ impl Resolver {
path: &ModPath,
shadow: BuiltinShadowMode,
) -> PerNs {
let (item_map, module) = self.item_scope();
let (item_map, item_local_map, module) = self.item_scope();
// This method resolves `path` just like import paths, so no expected macro subns is given.
let (module_res, segment_index) = item_map.resolve_path(db, module, path, shadow, None);
let (module_res, segment_index) =
item_map.resolve_path(item_local_map, db, module, path, shadow, None);
if segment_index.is_some() {
return PerNs::none();
}
@ -943,13 +955,17 @@ impl Resolver {
}
/// The innermost block scope that contains items or the module scope that contains this resolver.
fn item_scope(&self) -> (&DefMap, LocalModuleId) {
fn item_scope(&self) -> (&DefMap, &LocalDefMap, LocalModuleId) {
self.scopes()
.find_map(|scope| match scope {
Scope::BlockScope(m) => Some((&*m.def_map, m.module_id)),
Scope::BlockScope(m) => Some((&*m.def_map, &*m.local_def_map, m.module_id)),
_ => None,
})
.unwrap_or((&self.module_scope.def_map, self.module_scope.module_id))
.unwrap_or((
&self.module_scope.def_map,
&self.module_scope.local_def_map,
self.module_scope.module_id,
))
}
}
@ -1050,7 +1066,8 @@ fn resolver_for_scope_(
for scope in scope_chain.into_iter().rev() {
if let Some(block) = scopes.block(scope) {
let def_map = db.block_def_map(block);
r = r.push_block_scope(def_map);
let local_def_map = block.lookup(db).module.only_local_def_map(db);
r = r.push_block_scope(def_map, local_def_map);
// FIXME: This adds as many module scopes as there are blocks, but resolving in each
// already traverses all parents, so this is O(n²). I think we could only store the
// innermost module scope instead?
@ -1079,9 +1096,12 @@ impl Resolver {
self.push_scope(Scope::ImplDefScope(impl_def))
}
fn push_block_scope(self, def_map: Arc<DefMap>) -> Resolver {
debug_assert!(def_map.block_id().is_some());
self.push_scope(Scope::BlockScope(ModuleItemMap { def_map, module_id: DefMap::ROOT }))
fn push_block_scope(self, def_map: Arc<DefMap>, local_def_map: Arc<LocalDefMap>) -> Resolver {
self.push_scope(Scope::BlockScope(ModuleItemMap {
def_map,
local_def_map,
module_id: DefMap::ROOT,
}))
}
fn push_expr_scope(
@ -1100,8 +1120,13 @@ impl ModuleItemMap {
db: &dyn DefDatabase,
path: &ModPath,
) -> Option<(ResolveValueResult, ResolvePathResultPrefixInfo)> {
let (module_def, unresolved_idx, prefix_info) =
self.def_map.resolve_path_locally(db, self.module_id, path, BuiltinShadowMode::Other);
let (module_def, unresolved_idx, prefix_info) = self.def_map.resolve_path_locally(
&self.local_def_map,
db,
self.module_id,
path,
BuiltinShadowMode::Other,
);
match unresolved_idx {
None => {
let (value, import) = to_value_ns(module_def)?;
@ -1134,8 +1159,13 @@ impl ModuleItemMap {
path: &ModPath,
) -> Option<(TypeNs, Option<usize>, Option<ImportOrExternCrate>, ResolvePathResultPrefixInfo)>
{
let (module_def, idx, prefix_info) =
self.def_map.resolve_path_locally(db, self.module_id, path, BuiltinShadowMode::Other);
let (module_def, idx, prefix_info) = self.def_map.resolve_path_locally(
&self.local_def_map,
db,
self.module_id,
path,
BuiltinShadowMode::Other,
);
let (res, import) = to_type_ns(module_def)?;
Some((res, idx, import, prefix_info))
}
@ -1230,11 +1260,14 @@ pub trait HasResolver: Copy {
impl HasResolver for ModuleId {
fn resolver(self, db: &dyn DefDatabase) -> Resolver {
let mut def_map = self.def_map(db);
let (mut def_map, local_def_map) = self.local_def_map(db);
let mut module_id = self.local_id;
if !self.is_block_module() {
return Resolver { scopes: vec![], module_scope: ModuleItemMap { def_map, module_id } };
return Resolver {
scopes: vec![],
module_scope: ModuleItemMap { def_map, local_def_map, module_id },
};
}
let mut modules: SmallVec<[_; 1]> = smallvec![];
@ -1248,10 +1281,14 @@ impl HasResolver for ModuleId {
}
let mut resolver = Resolver {
scopes: Vec::with_capacity(modules.len()),
module_scope: ModuleItemMap { def_map, module_id },
module_scope: ModuleItemMap {
def_map,
local_def_map: local_def_map.clone(),
module_id,
},
};
for def_map in modules.into_iter().rev() {
resolver = resolver.push_block_scope(def_map);
resolver = resolver.push_block_scope(def_map, local_def_map.clone());
}
resolver
}
@ -1259,9 +1296,10 @@ impl HasResolver for ModuleId {
impl HasResolver for CrateRootModuleId {
fn resolver(self, db: &dyn DefDatabase) -> Resolver {
let (def_map, local_def_map) = self.local_def_map(db);
Resolver {
scopes: vec![],
module_scope: ModuleItemMap { def_map: self.def_map(db), module_id: DefMap::ROOT },
module_scope: ModuleItemMap { def_map, local_def_map, module_id: DefMap::ROOT },
}
}
}

View file

@ -158,7 +158,7 @@ impl HasChildSource<LocalFieldId> for VariantId {
let mut map = ArenaMap::new();
match &src.value {
ast::StructKind::Tuple(fl) => {
let cfg_options = &db.crate_graph()[container.krate].cfg_options;
let cfg_options = container.krate.cfg_options(db);
let mut idx = 0;
for (i, fd) in fl.fields().enumerate() {
let attrs = item_tree.attrs(
@ -177,7 +177,7 @@ impl HasChildSource<LocalFieldId> for VariantId {
}
}
ast::StructKind::Record(fl) => {
let cfg_options = &db.crate_graph()[container.krate].cfg_options;
let cfg_options = container.krate.cfg_options(db);
let mut idx = 0;
for (i, fd) in fl.fields().enumerate() {
let attrs = item_tree.attrs(

View file

@ -3,8 +3,8 @@
use std::{fmt, panic, sync::Mutex};
use base_db::{
CrateId, FileSourceRootInput, FileText, RootQueryDb, SourceDatabase, SourceRoot, SourceRootId,
SourceRootInput, Upcast,
Crate, CrateGraphBuilder, CratesMap, FileSourceRootInput, FileText, RootQueryDb,
SourceDatabase, SourceRoot, SourceRootId, SourceRootInput, Upcast,
};
use hir_expand::{db::ExpandDatabase, files::FilePosition, InFile};
use salsa::{AsDynDatabase, Durability};
@ -24,6 +24,7 @@ use crate::{
pub(crate) struct TestDB {
storage: salsa::Storage<Self>,
files: Arc<base_db::Files>,
crates_map: Arc<CratesMap>,
events: Arc<Mutex<Option<Vec<salsa::Event>>>>,
}
@ -33,8 +34,12 @@ impl Default for TestDB {
storage: Default::default(),
events: Default::default(),
files: Default::default(),
crates_map: Default::default(),
};
this.set_expand_proc_attr_macros_with_durability(true, Durability::HIGH);
// This needs to be here otherwise `CrateGraphBuilder` panics.
this.set_all_crates(Arc::new(Box::new([])));
CrateGraphBuilder::default().set_in_db(&mut this);
this
}
}
@ -133,20 +138,23 @@ impl SourceDatabase for TestDB {
let files = Arc::clone(&self.files);
files.set_file_source_root_with_durability(self, id, source_root_id, durability);
}
fn crates_map(&self) -> Arc<CratesMap> {
self.crates_map.clone()
}
}
impl TestDB {
pub(crate) fn fetch_test_crate(&self) -> CrateId {
let crate_graph = self.crate_graph();
let it = crate_graph
pub(crate) fn fetch_test_crate(&self) -> Crate {
let all_crates = self.all_crates();
all_crates
.iter()
.find(|&idx| {
crate_graph[idx].display_name.as_ref().map(|it| it.canonical_name().as_str())
.copied()
.find(|&krate| {
krate.extra_data(self).display_name.as_ref().map(|it| it.canonical_name().as_str())
== Some("ra_test_fixture")
})
.or_else(|| crate_graph.iter().next())
.unwrap();
it
.unwrap_or(*all_crates.last().unwrap())
}
pub(crate) fn module_for_file(&self, file_id: FileId) -> ModuleId {