mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-10-29 19:17:12 +00:00
Salsify the crate graph
I.e. make it not one giant input but multiple, for incrementality and decreased memory usage for Salsa 3 reasons.
This commit is contained in:
parent
44f18c3d05
commit
c94e9efbef
108 changed files with 3630 additions and 2512 deletions
|
|
@ -233,7 +233,13 @@ impl RootDatabase {
|
|||
// // SourceDatabase
|
||||
// base_db::ParseQuery
|
||||
// base_db::ParseErrorsQuery
|
||||
// base_db::CrateGraphQuery
|
||||
// base_db::AllCratesQuery
|
||||
// base_db::InternUniqueCrateDataQuery
|
||||
// base_db::InternUniqueCrateDataLookupQuery
|
||||
// base_db::CrateDataQuery
|
||||
// base_db::ExtraCrateDataQuery
|
||||
// base_db::CrateCfgQuery
|
||||
// base_db::CrateEnvQuery
|
||||
// base_db::CrateWorkspaceDataQuery
|
||||
|
||||
// // SourceDatabaseExt
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
//! See [`FamousDefs`].
|
||||
|
||||
use base_db::{CrateOrigin, LangCrateOrigin, RootQueryDb as _};
|
||||
use base_db::{CrateOrigin, LangCrateOrigin};
|
||||
use hir::{Crate, Enum, Function, Macro, Module, ScopeDef, Semantics, Trait};
|
||||
|
||||
use crate::RootDatabase;
|
||||
|
|
@ -198,11 +198,10 @@ impl FamousDefs<'_, '_> {
|
|||
fn find_lang_crate(&self, origin: LangCrateOrigin) -> Option<Crate> {
|
||||
let krate = self.1;
|
||||
let db = self.0.db;
|
||||
let crate_graph = self.0.db.crate_graph();
|
||||
let res = krate
|
||||
.dependencies(db)
|
||||
.into_iter()
|
||||
.find(|dep| crate_graph[dep.krate.into()].origin == CrateOrigin::Lang(origin))?
|
||||
.find(|dep| dep.krate.origin(db) == CrateOrigin::Lang(origin))?
|
||||
.krate;
|
||||
Some(res)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -51,9 +51,8 @@ use salsa::Durability;
|
|||
use std::{fmt, mem::ManuallyDrop};
|
||||
|
||||
use base_db::{
|
||||
query_group::{self},
|
||||
FileSourceRootInput, FileText, Files, RootQueryDb, SourceDatabase, SourceRoot, SourceRootId,
|
||||
SourceRootInput, Upcast,
|
||||
query_group, CrateGraphBuilder, CratesMap, FileSourceRootInput, FileText, Files, RootQueryDb,
|
||||
SourceDatabase, SourceRoot, SourceRootId, SourceRootInput, Upcast,
|
||||
};
|
||||
use hir::{
|
||||
db::{DefDatabase, ExpandDatabase, HirDatabase},
|
||||
|
|
@ -85,6 +84,7 @@ pub struct RootDatabase {
|
|||
// compile times of all `ide_*` and downstream crates suffer greatly.
|
||||
storage: ManuallyDrop<salsa::Storage<Self>>,
|
||||
files: Arc<Files>,
|
||||
crates_map: Arc<CratesMap>,
|
||||
}
|
||||
|
||||
impl std::panic::RefUnwindSafe for RootDatabase {}
|
||||
|
|
@ -102,7 +102,11 @@ impl Drop for RootDatabase {
|
|||
|
||||
impl Clone for RootDatabase {
|
||||
fn clone(&self) -> Self {
|
||||
Self { storage: self.storage.clone(), files: self.files.clone() }
|
||||
Self {
|
||||
storage: self.storage.clone(),
|
||||
files: self.files.clone(),
|
||||
crates_map: self.crates_map.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -194,6 +198,10 @@ impl SourceDatabase for RootDatabase {
|
|||
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 Default for RootDatabase {
|
||||
|
|
@ -207,8 +215,11 @@ impl RootDatabase {
|
|||
let mut db = RootDatabase {
|
||||
storage: ManuallyDrop::new(salsa::Storage::default()),
|
||||
files: Default::default(),
|
||||
crates_map: Default::default(),
|
||||
};
|
||||
db.set_crate_graph_with_durability(Default::default(), Durability::HIGH);
|
||||
// This needs to be here otherwise `CrateGraphBuilder` will panic.
|
||||
db.set_all_crates(Arc::new(Box::new([])));
|
||||
CrateGraphBuilder::default().set_in_db(&mut db);
|
||||
db.set_proc_macros_with_durability(Default::default(), Durability::HIGH);
|
||||
db.set_local_roots_with_durability(Default::default(), Durability::HIGH);
|
||||
db.set_library_roots_with_durability(Default::default(), Durability::HIGH);
|
||||
|
|
@ -258,7 +269,11 @@ impl RootDatabase {
|
|||
}
|
||||
|
||||
pub fn snapshot(&self) -> Self {
|
||||
Self { storage: self.storage.clone(), files: self.files.clone() }
|
||||
Self {
|
||||
storage: self.storage.clone(),
|
||||
files: self.files.clone(),
|
||||
crates_map: self.crates_map.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ use itertools::Itertools;
|
|||
use salsa::{Cancelled, Database};
|
||||
|
||||
use crate::{
|
||||
base_db::{CrateId, RootQueryDb},
|
||||
base_db::{Crate, RootQueryDb},
|
||||
symbol_index::SymbolsDatabase,
|
||||
FxIndexMap, RootDatabase,
|
||||
};
|
||||
|
|
@ -35,20 +35,22 @@ pub fn parallel_prime_caches(
|
|||
) {
|
||||
let _p = tracing::info_span!("parallel_prime_caches").entered();
|
||||
|
||||
let graph = db.crate_graph();
|
||||
let mut crates_to_prime = {
|
||||
// FIXME: We already have the crate list topologically sorted (but without the things
|
||||
// `TopologicalSortIter` gives us). Maybe there is a way to avoid using it and rip it out
|
||||
// of the codebase?
|
||||
let mut builder = topologic_sort::TopologicalSortIter::builder();
|
||||
|
||||
for crate_id in graph.iter() {
|
||||
builder.add(crate_id, graph[crate_id].dependencies.iter().map(|d| d.crate_id));
|
||||
for &crate_id in db.all_crates().iter() {
|
||||
builder.add(crate_id, crate_id.data(db).dependencies.iter().map(|d| d.crate_id));
|
||||
}
|
||||
|
||||
builder.build()
|
||||
};
|
||||
|
||||
enum ParallelPrimeCacheWorkerProgress {
|
||||
BeginCrate { crate_id: CrateId, crate_name: Symbol },
|
||||
EndCrate { crate_id: CrateId },
|
||||
BeginCrate { crate_id: Crate, crate_name: Symbol },
|
||||
EndCrate { crate_id: Crate },
|
||||
}
|
||||
|
||||
// We split off def map computation from other work,
|
||||
|
|
@ -108,16 +110,14 @@ pub fn parallel_prime_caches(
|
|||
while crates_done < crates_total {
|
||||
db.unwind_if_revision_cancelled();
|
||||
|
||||
for crate_id in &mut crates_to_prime {
|
||||
let krate = &graph[crate_id];
|
||||
let name = krate
|
||||
.display_name
|
||||
.as_deref()
|
||||
.cloned()
|
||||
.unwrap_or_else(|| Symbol::integer(crate_id.into_raw().into_u32() as usize));
|
||||
if krate.origin.is_lang() {
|
||||
additional_phases.push((crate_id, name.clone(), PrimingPhase::ImportMap));
|
||||
} else if krate.origin.is_local() {
|
||||
for krate in &mut crates_to_prime {
|
||||
let name = krate.extra_data(db).display_name.as_deref().cloned().unwrap_or_else(|| {
|
||||
Symbol::integer(salsa::plumbing::AsId::as_id(&krate).as_u32() as usize)
|
||||
});
|
||||
let origin = &krate.data(db).origin;
|
||||
if origin.is_lang() {
|
||||
additional_phases.push((krate, name.clone(), PrimingPhase::ImportMap));
|
||||
} else if origin.is_local() {
|
||||
// Compute the symbol search index.
|
||||
// This primes the cache for `ide_db::symbol_index::world_symbols()`.
|
||||
//
|
||||
|
|
@ -127,10 +127,10 @@ pub fn parallel_prime_caches(
|
|||
// FIXME: We should do it unconditionally if the configuration is set to default to
|
||||
// searching dependencies (rust-analyzer.workspace.symbol.search.scope), but we
|
||||
// would need to pipe that configuration information down here.
|
||||
additional_phases.push((crate_id, name.clone(), PrimingPhase::CrateSymbols));
|
||||
additional_phases.push((krate, name.clone(), PrimingPhase::CrateSymbols));
|
||||
}
|
||||
|
||||
work_sender.send((crate_id, name, PrimingPhase::DefMap)).ok();
|
||||
work_sender.send((krate, name, PrimingPhase::DefMap)).ok();
|
||||
}
|
||||
|
||||
// recv_timeout is somewhat a hack, we need a way to from this thread check to see if the current salsa revision
|
||||
|
|
|
|||
|
|
@ -162,13 +162,13 @@ impl SearchScope {
|
|||
fn crate_graph(db: &RootDatabase) -> SearchScope {
|
||||
let mut entries = FxHashMap::default();
|
||||
|
||||
let graph = db.crate_graph();
|
||||
for krate in graph.iter() {
|
||||
let root_file = graph[krate].root_file_id;
|
||||
let source_root = db.file_source_root(root_file).source_root_id(db);
|
||||
let all_crates = db.all_crates();
|
||||
for &krate in all_crates.iter() {
|
||||
let crate_data = krate.data(db);
|
||||
let source_root = db.file_source_root(crate_data.root_file_id).source_root_id(db);
|
||||
let source_root = db.source_root(source_root).source_root(db);
|
||||
entries.extend(
|
||||
source_root.iter().map(|id| (EditionedFileId::new(id, graph[krate].edition), None)),
|
||||
source_root.iter().map(|id| (EditionedFileId::new(id, crate_data.edition), None)),
|
||||
);
|
||||
}
|
||||
SearchScope { entries }
|
||||
|
|
|
|||
|
|
@ -2,7 +2,9 @@
|
|||
(
|
||||
Module {
|
||||
id: ModuleId {
|
||||
krate: Idx::<CrateData>(0),
|
||||
krate: Crate {
|
||||
[salsa id]: Id(2c00),
|
||||
},
|
||||
block: None,
|
||||
local_id: Idx::<ModuleData>(0),
|
||||
},
|
||||
|
|
|
|||
|
|
@ -2,7 +2,9 @@
|
|||
(
|
||||
Module {
|
||||
id: ModuleId {
|
||||
krate: Idx::<CrateData>(0),
|
||||
krate: Crate {
|
||||
[salsa id]: Id(2c00),
|
||||
},
|
||||
block: None,
|
||||
local_id: Idx::<ModuleData>(0),
|
||||
},
|
||||
|
|
@ -532,7 +534,9 @@
|
|||
def: Module(
|
||||
Module {
|
||||
id: ModuleId {
|
||||
krate: Idx::<CrateData>(0),
|
||||
krate: Crate {
|
||||
[salsa id]: Id(2c00),
|
||||
},
|
||||
block: None,
|
||||
local_id: Idx::<ModuleData>(1),
|
||||
},
|
||||
|
|
@ -565,7 +569,9 @@
|
|||
def: Module(
|
||||
Module {
|
||||
id: ModuleId {
|
||||
krate: Idx::<CrateData>(0),
|
||||
krate: Crate {
|
||||
[salsa id]: Id(2c00),
|
||||
},
|
||||
block: None,
|
||||
local_id: Idx::<ModuleData>(2),
|
||||
},
|
||||
|
|
@ -827,7 +833,9 @@
|
|||
(
|
||||
Module {
|
||||
id: ModuleId {
|
||||
krate: Idx::<CrateData>(0),
|
||||
krate: Crate {
|
||||
[salsa id]: Id(2c00),
|
||||
},
|
||||
block: None,
|
||||
local_id: Idx::<ModuleData>(1),
|
||||
},
|
||||
|
|
@ -871,7 +879,9 @@
|
|||
(
|
||||
Module {
|
||||
id: ModuleId {
|
||||
krate: Idx::<CrateData>(0),
|
||||
krate: Crate {
|
||||
[salsa id]: Id(2c00),
|
||||
},
|
||||
block: None,
|
||||
local_id: Idx::<ModuleData>(2),
|
||||
},
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue