diff --git a/Cargo.lock b/Cargo.lock index efd7362594..00da1c973d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2418,6 +2418,7 @@ dependencies = [ "span", "stdx", "test-utils", + "triomphe", "tt", ] diff --git a/crates/base-db/src/change.rs b/crates/base-db/src/change.rs index 90413a573a..1f19556a76 100644 --- a/crates/base-db/src/change.rs +++ b/crates/base-db/src/change.rs @@ -3,20 +3,18 @@ use std::fmt; -use rustc_hash::FxHashMap; use salsa::Durability; use triomphe::Arc; use vfs::FileId; -use crate::{CrateGraph, CrateId, CrateWorkspaceData, RootQueryDb, SourceRoot, SourceRootId}; +use crate::{CrateGraphBuilder, CratesIdMap, RootQueryDb, SourceRoot, SourceRootId}; /// Encapsulate a bunch of raw `.set` calls on the database. #[derive(Default)] pub struct FileChange { pub roots: Option>, pub files_changed: Vec<(FileId, Option)>, - pub crate_graph: Option, - pub ws_data: Option>>, + pub crate_graph: Option, } impl fmt::Debug for FileChange { @@ -48,15 +46,11 @@ impl FileChange { self.files_changed.push((file_id, new_text)) } - pub fn set_crate_graph(&mut self, graph: CrateGraph) { + pub fn set_crate_graph(&mut self, graph: CrateGraphBuilder) { self.crate_graph = Some(graph); } - pub fn set_ws_data(&mut self, data: FxHashMap>) { - self.ws_data = Some(data); - } - - pub fn apply(self, db: &mut dyn RootQueryDb) { + pub fn apply(self, db: &mut dyn RootQueryDb) -> Option { let _p = tracing::info_span!("FileChange::apply").entered(); if let Some(roots) = self.roots { for (idx, root) in roots.into_iter().enumerate() { @@ -79,12 +73,11 @@ impl FileChange { let text = text.unwrap_or_default(); db.set_file_text_with_durability(file_id, &text, durability) } + if let Some(crate_graph) = self.crate_graph { - db.set_crate_graph_with_durability(Arc::new(crate_graph), Durability::HIGH); - } - if let Some(data) = self.ws_data { - db.set_crate_workspace_data_with_durability(Arc::new(data), Durability::HIGH); + return Some(crate_graph.set_in_db(db)); } + None } } diff --git a/crates/base-db/src/input.rs b/crates/base-db/src/input.rs index bd08387b58..c4e64b372f 100644 --- a/crates/base-db/src/input.rs +++ b/crates/base-db/src/input.rs @@ -6,17 +6,23 @@ //! actual IO. See `vfs` and `project_model` in the `rust-analyzer` crate for how //! actual IO is done and lowered to input. +use std::hash::BuildHasherDefault; use std::{fmt, mem, ops}; -use cfg::CfgOptions; +use cfg::{CfgOptions, HashableCfgOptions}; +use dashmap::mapref::entry::Entry; +use dashmap::DashMap; use intern::Symbol; use la_arena::{Arena, Idx, RawIdx}; -use rustc_hash::{FxHashMap, FxHashSet}; +use rustc_hash::{FxHashMap, FxHashSet, FxHasher}; +use salsa::{Durability, Setter}; use span::{Edition, EditionedFileId}; use triomphe::Arc; use vfs::{file_set::FileSet, AbsPathBuf, AnchoredPath, FileId, VfsPath}; -pub type ProcMacroPaths = FxHashMap>; +use crate::{CrateWorkspaceData, RootQueryDb}; + +pub type ProcMacroPaths = FxHashMap>; #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)] pub struct SourceRootId(pub u32); @@ -64,30 +70,31 @@ impl SourceRoot { } } -/// `CrateGraph` is a bit of information which turns a set of text files into a -/// number of Rust crates. -/// -/// Each crate is defined by the `FileId` of its root module, the set of enabled -/// `cfg` flags and the set of dependencies. -/// -/// Note that, due to cfg's, there might be several crates for a single `FileId`! -/// -/// For the purposes of analysis, a crate does not have a name. Instead, names -/// are specified on dependency edges. That is, a crate might be known under -/// different names in different dependent crates. -/// -/// Note that `CrateGraph` is build-system agnostic: it's a concept of the Rust -/// language proper, not a concept of the build system. In practice, we get -/// `CrateGraph` by lowering `cargo metadata` output. -/// -/// `CrateGraph` is `!Serialize` by design, see -/// -#[derive(Clone, Default)] -pub struct CrateGraph { - arena: Arena, +#[derive(Default, Clone)] +pub struct CrateGraphBuilder { + arena: Arena, } -impl fmt::Debug for CrateGraph { +pub type CrateBuilderId = Idx; + +impl ops::Index for CrateGraphBuilder { + type Output = CrateBuilder; + + fn index(&self, index: CrateBuilderId) -> &Self::Output { + &self.arena[index] + } +} + +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct CrateBuilder { + pub basic: CrateDataBuilder, + pub extra: ExtraCrateData, + pub cfg_options: Arc, + pub env: Env, + ws_data: Arc, +} + +impl fmt::Debug for CrateGraphBuilder { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_map() .entries(self.arena.iter().map(|(id, data)| (u32::from(id.into_raw()), data))) @@ -95,8 +102,6 @@ impl fmt::Debug for CrateGraph { } } -pub type CrateId = Idx; - #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct CrateName(Symbol); @@ -272,10 +277,46 @@ impl ReleaseChannel { } } -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct CrateData { +/// The crate data from which we derive the `Crate`. +/// +/// We want this to contain as little data as possible, because if it contains dependencies and +/// something changes, this crate and all of its dependencies ids are invalidated, which causes +/// pretty much everything to be recomputed. If the crate id is not invalidated, only this crate's +/// information needs to be recomputed. +/// +/// *Most* different crates have different root files (actually, pretty much all of them). +/// Still, it is possible to have crates distinguished by other factors (e.g. dependencies). +/// So we store only the root file - unless we find that this crate has the same root file as +/// another crate, in which case we store all data for one of them (if one is a dependency of +/// the other, we store for it, because it has more dependencies to be invalidated). +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct UniqueCrateData { + root_file_id: FileId, + disambiguator: Option>, +} + +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct CrateData { pub root_file_id: FileId, pub edition: Edition, + /// The dependencies of this crate. + /// + /// Note that this may contain more dependencies than the crate actually uses. + /// A common example is the test crate which is included but only actually is active when + /// declared in source via `extern crate test`. + pub dependencies: Vec>, + pub origin: CrateOrigin, + pub is_proc_macro: bool, + /// The working directory to run proc-macros in. This is the workspace root of the cargo workspace + /// for workspace members, the crate manifest dir otherwise. + pub proc_macro_cwd: Option, +} + +pub type CrateDataBuilder = CrateData; +pub type BuiltCrateData = CrateData; + +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct ExtraCrateData { pub version: Option, /// A name used in the package's project declaration: for Cargo projects, /// its `[package].name` can be different for other project types or even @@ -284,21 +325,8 @@ pub struct CrateData { /// For purposes of analysis, crates are anonymous (only names in /// `Dependency` matters), this name should only be used for UI. pub display_name: Option, - pub cfg_options: Arc, /// The cfg options that could be used by the crate - pub potential_cfg_options: Option>, - pub env: Env, - /// The dependencies of this crate. - /// - /// Note that this may contain more dependencies than the crate actually uses. - /// A common example is the test crate which is included but only actually is active when - /// declared in source via `extern crate test`. - pub dependencies: Vec, - pub origin: CrateOrigin, - pub is_proc_macro: bool, - /// The working directory to run proc-macros in. This is the workspace root of the cargo workspace - /// for workspace members, the crate manifest dir otherwise. - pub proc_macro_cwd: Option, + pub potential_cfg_options: Option, } #[derive(Default, Clone, PartialEq, Eq)] @@ -326,22 +354,32 @@ impl fmt::Debug for Env { } #[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub struct Dependency { - pub crate_id: CrateId, +pub struct Dependency { + pub crate_id: Id, pub name: CrateName, prelude: bool, sysroot: bool, } -impl Dependency { - pub fn new(name: CrateName, crate_id: CrateId) -> Self { +pub type DependencyBuilder = Dependency; +pub type BuiltDependency = Dependency; + +impl DependencyBuilder { + pub fn new(name: CrateName, crate_id: CrateBuilderId) -> Self { Self { name, crate_id, prelude: true, sysroot: false } } - pub fn with_prelude(name: CrateName, crate_id: CrateId, prelude: bool, sysroot: bool) -> Self { + pub fn with_prelude( + name: CrateName, + crate_id: CrateBuilderId, + prelude: bool, + sysroot: bool, + ) -> Self { Self { name, crate_id, prelude, sysroot } } +} +impl BuiltDependency { /// Whether this dependency is to be added to the depending crate's extern prelude. pub fn is_prelude(&self) -> bool { self.prelude @@ -353,7 +391,32 @@ impl Dependency { } } -impl CrateGraph { +pub type CratesIdMap = FxHashMap; + +#[salsa::input] +pub struct Crate { + #[return_ref] + pub data: BuiltCrateData, + /// Crate data that is not needed for analysis. + /// + /// This is split into a separate field to increase incrementality. + #[return_ref] + pub extra_data: ExtraCrateData, + // This is in `Arc` because it is shared for all crates in a workspace. + #[return_ref] + pub workspace_data: Arc, + // FIXME: Remove this `Arc`. + #[return_ref] + pub cfg_options: Arc, + #[return_ref] + pub env: Env, +} + +/// The mapping from [`UniqueCrateData`] to their [`Crate`] input. +#[derive(Debug, Default)] +pub struct CratesMap(DashMap>); + +impl CrateGraphBuilder { pub fn add_crate_root( &mut self, root_file_id: FileId, @@ -361,33 +424,34 @@ impl CrateGraph { display_name: Option, version: Option, cfg_options: Arc, - potential_cfg_options: Option>, + potential_cfg_options: Option, mut env: Env, origin: CrateOrigin, is_proc_macro: bool, proc_macro_cwd: Option, - ) -> CrateId { + ws_data: Arc, + ) -> CrateBuilderId { env.entries.shrink_to_fit(); - let data = CrateData { - root_file_id, - edition, - version, - display_name, + self.arena.alloc(CrateBuilder { + basic: CrateData { + root_file_id, + edition, + dependencies: Vec::new(), + origin, + is_proc_macro, + proc_macro_cwd, + }, + extra: ExtraCrateData { version, display_name, potential_cfg_options }, cfg_options, - potential_cfg_options, env, - dependencies: Vec::new(), - origin, - is_proc_macro, - proc_macro_cwd, - }; - self.arena.alloc(data) + ws_data, + }) } pub fn add_dep( &mut self, - from: CrateId, - dep: Dependency, + from: CrateBuilderId, + dep: DependencyBuilder, ) -> Result<(), CyclicDependenciesError> { let _p = tracing::info_span!("add_dep").entered(); @@ -395,37 +459,160 @@ impl CrateGraph { // that out, look for a path in the *opposite* direction, from `to` to // `from`. if let Some(path) = self.find_path(&mut FxHashSet::default(), dep.crate_id, from) { - let path = path.into_iter().map(|it| (it, self[it].display_name.clone())).collect(); + let path = + path.into_iter().map(|it| (it, self[it].extra.display_name.clone())).collect(); let err = CyclicDependenciesError { path }; assert!(err.from().0 == from && err.to().0 == dep.crate_id); return Err(err); } - self.arena[from].add_dep(dep); + self.arena[from].basic.dependencies.push(dep); Ok(()) } - pub fn is_empty(&self) -> bool { - self.arena.is_empty() + pub fn set_in_db(self, db: &mut dyn RootQueryDb) -> CratesIdMap { + let mut all_crates = Vec::with_capacity(self.arena.len()); + let mut visited = FxHashMap::default(); + let mut visited_root_files = FxHashSet::default(); + + let old_all_crates = db.all_crates(); + + let crates_map = db.crates_map(); + // salsa doesn't compare new input to old input to see if they are the same, so here we are doing all the work ourselves. + for krate in self.iter() { + go( + &self, + db, + &crates_map, + &mut visited, + &mut visited_root_files, + &mut all_crates, + krate, + ); + } + + if **old_all_crates != *all_crates { + db.set_all_crates_with_durability( + Arc::new(all_crates.into_boxed_slice()), + Durability::HIGH, + ); + } + + return visited; + + fn go( + graph: &CrateGraphBuilder, + db: &mut dyn RootQueryDb, + crates_map: &CratesMap, + visited: &mut FxHashMap, + visited_root_files: &mut FxHashSet, + all_crates: &mut Vec, + source: CrateBuilderId, + ) -> Crate { + if let Some(&crate_id) = visited.get(&source) { + return crate_id; + } + let krate = &graph[source]; + let dependencies = krate + .basic + .dependencies + .iter() + .map(|dep| BuiltDependency { + crate_id: go( + graph, + db, + crates_map, + visited, + visited_root_files, + all_crates, + dep.crate_id, + ), + name: dep.name.clone(), + prelude: dep.prelude, + sysroot: dep.sysroot, + }) + .collect::>(); + let crate_data = BuiltCrateData { + dependencies, + edition: krate.basic.edition, + is_proc_macro: krate.basic.is_proc_macro, + origin: krate.basic.origin.clone(), + root_file_id: krate.basic.root_file_id, + proc_macro_cwd: krate.basic.proc_macro_cwd.clone(), + }; + let disambiguator = if visited_root_files.insert(krate.basic.root_file_id) { + None + } else { + Some(Box::new((crate_data.clone(), krate.cfg_options.to_hashable()))) + }; + + let unique_crate_data = + UniqueCrateData { root_file_id: krate.basic.root_file_id, disambiguator }; + let crate_input = match crates_map.0.entry(unique_crate_data) { + Entry::Occupied(entry) => { + let old_crate = *entry.get(); + if crate_data != *old_crate.data(db) { + old_crate.set_data(db).with_durability(Durability::HIGH).to(crate_data); + } + if krate.extra != *old_crate.extra_data(db) { + old_crate + .set_extra_data(db) + .with_durability(Durability::HIGH) + .to(krate.extra.clone()); + } + if krate.cfg_options != *old_crate.cfg_options(db) { + old_crate + .set_cfg_options(db) + .with_durability(Durability::HIGH) + .to(krate.cfg_options.clone()); + } + if krate.env != *old_crate.env(db) { + old_crate + .set_env(db) + .with_durability(Durability::HIGH) + .to(krate.env.clone()); + } + if krate.ws_data != *old_crate.workspace_data(db) { + old_crate + .set_workspace_data(db) + .with_durability(Durability::HIGH) + .to(krate.ws_data.clone()); + } + old_crate + } + Entry::Vacant(entry) => { + let input = Crate::builder( + crate_data, + krate.extra.clone(), + krate.ws_data.clone(), + krate.cfg_options.clone(), + krate.env.clone(), + ) + .durability(Durability::HIGH) + .new(db); + entry.insert(input); + input + } + }; + all_crates.push(crate_input); + visited.insert(source, crate_input); + crate_input + } } - pub fn len(&self) -> usize { - self.arena.len() - } - - pub fn iter(&self) -> impl Iterator + '_ { + pub fn iter(&self) -> impl Iterator + '_ { self.arena.iter().map(|(idx, _)| idx) } // FIXME: used for fixing up the toolchain sysroot, should be removed and done differently #[doc(hidden)] - pub fn iter_mut(&mut self) -> impl Iterator + '_ { + pub fn iter_mut(&mut self) -> impl Iterator + '_ { self.arena.iter_mut() } /// Returns an iterator over all transitive dependencies of the given crate, /// including the crate itself. - pub fn transitive_deps(&self, of: CrateId) -> impl Iterator { + pub fn transitive_deps(&self, of: CrateBuilderId) -> impl Iterator { let mut worklist = vec![of]; let mut deps = FxHashSet::default(); @@ -434,42 +621,15 @@ impl CrateGraph { continue; } - worklist.extend(self[krate].dependencies.iter().map(|dep| dep.crate_id)); + worklist.extend(self[krate].basic.dependencies.iter().map(|dep| dep.crate_id)); } deps.into_iter() } - /// Returns all transitive reverse dependencies of the given crate, - /// including the crate itself. - pub fn transitive_rev_deps(&self, of: CrateId) -> impl Iterator { - let mut worklist = vec![of]; - let mut rev_deps = FxHashSet::default(); - rev_deps.insert(of); - - let mut inverted_graph = FxHashMap::<_, Vec<_>>::default(); - self.arena.iter().for_each(|(krate, data)| { - data.dependencies - .iter() - .for_each(|dep| inverted_graph.entry(dep.crate_id).or_default().push(krate)) - }); - - while let Some(krate) = worklist.pop() { - if let Some(krate_rev_deps) = inverted_graph.get(&krate) { - krate_rev_deps - .iter() - .copied() - .filter(|&rev_dep| rev_deps.insert(rev_dep)) - .for_each(|rev_dep| worklist.push(rev_dep)); - } - } - - rev_deps.into_iter() - } - /// Returns all crates in the graph, sorted in topological order (ie. dependencies of a crate /// come before the crate itself). - pub fn crates_in_topological_order(&self) -> Vec { + fn crates_in_topological_order(&self) -> Vec { let mut res = Vec::new(); let mut visited = FxHashSet::default(); @@ -480,15 +640,15 @@ impl CrateGraph { return res; fn go( - graph: &CrateGraph, - visited: &mut FxHashSet, - res: &mut Vec, - source: CrateId, + graph: &CrateGraphBuilder, + visited: &mut FxHashSet, + res: &mut Vec, + source: CrateBuilderId, ) { if !visited.insert(source) { return; } - for dep in graph[source].dependencies.iter() { + for dep in graph[source].basic.dependencies.iter() { go(graph, visited, res, dep.crate_id) } res.push(source) @@ -504,23 +664,27 @@ impl CrateGraph { /// Returns a map mapping `other`'s IDs to the new IDs in `self`. pub fn extend( &mut self, - mut other: CrateGraph, + mut other: CrateGraphBuilder, proc_macros: &mut ProcMacroPaths, - ) -> FxHashMap { + ) -> FxHashMap { // Sorting here is a bit pointless because the input is likely already sorted. // However, the overhead is small and it makes the `extend` method harder to misuse. self.arena .iter_mut() - .for_each(|(_, data)| data.dependencies.sort_by_key(|dep| dep.crate_id)); + .for_each(|(_, data)| data.basic.dependencies.sort_by_key(|dep| dep.crate_id)); - let m = self.len(); + let m = self.arena.len(); let topo = other.crates_in_topological_order(); - let mut id_map: FxHashMap = FxHashMap::default(); + let mut id_map: FxHashMap = FxHashMap::default(); for topo in topo { let crate_data = &mut other.arena[topo]; - crate_data.dependencies.iter_mut().for_each(|dep| dep.crate_id = id_map[&dep.crate_id]); - crate_data.dependencies.sort_by_key(|dep| dep.crate_id); + crate_data + .basic + .dependencies + .iter_mut() + .for_each(|dep| dep.crate_id = id_map[&dep.crate_id]); + crate_data.basic.dependencies.sort_by_key(|dep| dep.crate_id); let find = self.arena.iter().take(m).find_map(|(k, v)| (v == crate_data).then_some(k)); let new_id = find.unwrap_or_else(|| self.arena.alloc(crate_data.clone())); @@ -534,10 +698,10 @@ impl CrateGraph { fn find_path( &self, - visited: &mut FxHashSet, - from: CrateId, - to: CrateId, - ) -> Option> { + visited: &mut FxHashSet, + from: CrateBuilderId, + to: CrateBuilderId, + ) -> Option> { if !visited.insert(from) { return None; } @@ -546,7 +710,7 @@ impl CrateGraph { return Some(vec![to]); } - for dep in &self[from].dependencies { + for dep in &self[from].basic.dependencies { let crate_id = dep.crate_id; if let Some(mut path) = self.find_path(visited, crate_id, to) { path.push(from); @@ -559,7 +723,10 @@ impl CrateGraph { /// Removes all crates from this crate graph except for the ones in `to_keep` and fixes up the dependencies. /// Returns a mapping from old crate ids to new crate ids. - pub fn remove_crates_except(&mut self, to_keep: &[CrateId]) -> Vec> { + pub fn remove_crates_except( + &mut self, + to_keep: &[CrateBuilderId], + ) -> Vec> { let mut id_map = vec![None; self.arena.len()]; self.arena = std::mem::take(&mut self.arena) .into_iter() @@ -567,12 +734,12 @@ impl CrateGraph { .enumerate() .map(|(new_id, (id, data))| { id_map[id.into_raw().into_u32() as usize] = - Some(CrateId::from_raw(RawIdx::from_u32(new_id as u32))); + Some(CrateBuilderId::from_raw(RawIdx::from_u32(new_id as u32))); data }) .collect(); for (_, data) in self.arena.iter_mut() { - data.dependencies.iter_mut().for_each(|dep| { + data.basic.dependencies.iter_mut().for_each(|dep| { dep.crate_id = id_map[dep.crate_id.into_raw().into_u32() as usize].expect("crate was filtered") }); @@ -585,20 +752,34 @@ impl CrateGraph { } } -impl ops::Index for CrateGraph { - type Output = CrateData; - fn index(&self, crate_id: CrateId) -> &CrateData { - &self.arena[crate_id] +pub(crate) fn transitive_rev_deps(db: &dyn RootQueryDb, of: Crate) -> FxHashSet { + let mut worklist = vec![of]; + let mut rev_deps = FxHashSet::default(); + rev_deps.insert(of); + + let mut inverted_graph = FxHashMap::<_, Vec<_>>::default(); + db.all_crates().iter().for_each(|&krate| { + krate + .data(db) + .dependencies + .iter() + .for_each(|dep| inverted_graph.entry(dep.crate_id).or_default().push(krate)) + }); + + while let Some(krate) = worklist.pop() { + if let Some(crate_rev_deps) = inverted_graph.get(&krate) { + crate_rev_deps + .iter() + .copied() + .filter(|&rev_dep| rev_deps.insert(rev_dep)) + .for_each(|rev_dep| worklist.push(rev_dep)); + } } + + rev_deps } -impl CrateData { - /// Add a dependency to `self` without checking if the dependency - // is existent among `self.dependencies`. - fn add_dep(&mut self, dep: Dependency) { - self.dependencies.push(dep) - } - +impl BuiltCrateData { pub fn root_file_id(&self) -> EditionedFileId { EditionedFileId::new(self.root_file_id, self.edition) } @@ -657,21 +838,21 @@ impl<'a> IntoIterator for &'a Env { #[derive(Debug)] pub struct CyclicDependenciesError { - path: Vec<(CrateId, Option)>, + path: Vec<(CrateBuilderId, Option)>, } impl CyclicDependenciesError { - fn from(&self) -> &(CrateId, Option) { + fn from(&self) -> &(CrateBuilderId, Option) { self.path.first().unwrap() } - fn to(&self) -> &(CrateId, Option) { + fn to(&self) -> &(CrateBuilderId, Option) { self.path.last().unwrap() } } impl fmt::Display for CyclicDependenciesError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let render = |(id, name): &(CrateId, Option)| match name { + let render = |(id, name): &(CrateBuilderId, Option)| match name { Some(it) => format!("{it}({id:?})"), None => format!("{id:?}"), }; @@ -688,13 +869,19 @@ impl fmt::Display for CyclicDependenciesError { #[cfg(test)] mod tests { - use crate::CrateOrigin; + use triomphe::Arc; - use super::{CrateGraph, CrateName, Dependency, Edition::Edition2018, Env, FileId}; + use crate::{CrateWorkspaceData, DependencyBuilder}; + + use super::{CrateGraphBuilder, CrateName, CrateOrigin, Edition::Edition2018, Env, FileId}; + + fn empty_ws_data() -> Arc { + Arc::new(CrateWorkspaceData { data_layout: Err("".into()), toolchain: None }) + } #[test] fn detect_cyclic_dependency_indirect() { - let mut graph = CrateGraph::default(); + let mut graph = CrateGraphBuilder::default(); let crate1 = graph.add_crate_root( FileId::from_raw(1u32), Edition2018, @@ -706,6 +893,7 @@ mod tests { CrateOrigin::Local { repo: None, name: None }, false, None, + empty_ws_data(), ); let crate2 = graph.add_crate_root( FileId::from_raw(2u32), @@ -718,6 +906,7 @@ mod tests { CrateOrigin::Local { repo: None, name: None }, false, None, + empty_ws_data(), ); let crate3 = graph.add_crate_root( FileId::from_raw(3u32), @@ -730,21 +919,22 @@ mod tests { CrateOrigin::Local { repo: None, name: None }, false, None, + empty_ws_data(), ); assert!(graph - .add_dep(crate1, Dependency::new(CrateName::new("crate2").unwrap(), crate2,)) + .add_dep(crate1, DependencyBuilder::new(CrateName::new("crate2").unwrap(), crate2,)) .is_ok()); assert!(graph - .add_dep(crate2, Dependency::new(CrateName::new("crate3").unwrap(), crate3,)) + .add_dep(crate2, DependencyBuilder::new(CrateName::new("crate3").unwrap(), crate3,)) .is_ok()); assert!(graph - .add_dep(crate3, Dependency::new(CrateName::new("crate1").unwrap(), crate1,)) + .add_dep(crate3, DependencyBuilder::new(CrateName::new("crate1").unwrap(), crate1,)) .is_err()); } #[test] fn detect_cyclic_dependency_direct() { - let mut graph = CrateGraph::default(); + let mut graph = CrateGraphBuilder::default(); let crate1 = graph.add_crate_root( FileId::from_raw(1u32), Edition2018, @@ -756,6 +946,7 @@ mod tests { CrateOrigin::Local { repo: None, name: None }, false, None, + empty_ws_data(), ); let crate2 = graph.add_crate_root( FileId::from_raw(2u32), @@ -768,18 +959,19 @@ mod tests { CrateOrigin::Local { repo: None, name: None }, false, None, + empty_ws_data(), ); assert!(graph - .add_dep(crate1, Dependency::new(CrateName::new("crate2").unwrap(), crate2,)) + .add_dep(crate1, DependencyBuilder::new(CrateName::new("crate2").unwrap(), crate2,)) .is_ok()); assert!(graph - .add_dep(crate2, Dependency::new(CrateName::new("crate2").unwrap(), crate2,)) + .add_dep(crate2, DependencyBuilder::new(CrateName::new("crate2").unwrap(), crate2,)) .is_err()); } #[test] fn it_works() { - let mut graph = CrateGraph::default(); + let mut graph = CrateGraphBuilder::default(); let crate1 = graph.add_crate_root( FileId::from_raw(1u32), Edition2018, @@ -791,6 +983,7 @@ mod tests { CrateOrigin::Local { repo: None, name: None }, false, None, + empty_ws_data(), ); let crate2 = graph.add_crate_root( FileId::from_raw(2u32), @@ -803,6 +996,7 @@ mod tests { CrateOrigin::Local { repo: None, name: None }, false, None, + empty_ws_data(), ); let crate3 = graph.add_crate_root( FileId::from_raw(3u32), @@ -815,18 +1009,19 @@ mod tests { CrateOrigin::Local { repo: None, name: None }, false, None, + empty_ws_data(), ); assert!(graph - .add_dep(crate1, Dependency::new(CrateName::new("crate2").unwrap(), crate2,)) + .add_dep(crate1, DependencyBuilder::new(CrateName::new("crate2").unwrap(), crate2,)) .is_ok()); assert!(graph - .add_dep(crate2, Dependency::new(CrateName::new("crate3").unwrap(), crate3,)) + .add_dep(crate2, DependencyBuilder::new(CrateName::new("crate3").unwrap(), crate3,)) .is_ok()); } #[test] fn dashes_are_normalized() { - let mut graph = CrateGraph::default(); + let mut graph = CrateGraphBuilder::default(); let crate1 = graph.add_crate_root( FileId::from_raw(1u32), Edition2018, @@ -838,6 +1033,7 @@ mod tests { CrateOrigin::Local { repo: None, name: None }, false, None, + empty_ws_data(), ); let crate2 = graph.add_crate_root( FileId::from_raw(2u32), @@ -850,16 +1046,22 @@ mod tests { CrateOrigin::Local { repo: None, name: None }, false, None, + empty_ws_data(), ); assert!(graph .add_dep( crate1, - Dependency::new(CrateName::normalize_dashes("crate-name-with-dashes"), crate2,) + DependencyBuilder::new( + CrateName::normalize_dashes("crate-name-with-dashes"), + crate2, + ) ) .is_ok()); assert_eq!( - graph[crate1].dependencies, - vec![Dependency::new(CrateName::new("crate_name_with_dashes").unwrap(), crate2,)] + graph.arena[crate1].basic.dependencies, + vec![ + DependencyBuilder::new(CrateName::new("crate_name_with_dashes").unwrap(), crate2,) + ] ); } } diff --git a/crates/base-db/src/lib.rs b/crates/base-db/src/lib.rs index 9ec9100968..324979b2e4 100644 --- a/crates/base-db/src/lib.rs +++ b/crates/base-db/src/lib.rs @@ -8,14 +8,15 @@ use std::hash::BuildHasherDefault; pub use crate::{ change::FileChange, input::{ - CrateData, CrateDisplayName, CrateGraph, CrateId, CrateName, CrateOrigin, Dependency, Env, - LangCrateOrigin, ProcMacroPaths, ReleaseChannel, SourceRoot, SourceRootId, - TargetLayoutLoadResult, + BuiltCrateData, BuiltDependency, Crate, CrateBuilder, CrateBuilderId, CrateDataBuilder, + CrateDisplayName, CrateGraphBuilder, CrateName, CrateOrigin, CratesIdMap, CratesMap, + DependencyBuilder, Env, ExtraCrateData, LangCrateOrigin, ProcMacroPaths, ReleaseChannel, + SourceRoot, SourceRootId, TargetLayoutLoadResult, UniqueCrateData, }, }; use dashmap::{mapref::entry::Entry, DashMap}; pub use query_group::{self}; -use rustc_hash::{FxHashMap, FxHasher}; +use rustc_hash::{FxHashSet, FxHasher}; pub use salsa::{self}; use salsa::{Durability, Setter}; pub use semver::{BuildMetadata, Prerelease, Version, VersionReq}; @@ -200,21 +201,53 @@ pub trait RootQueryDb: SourceDatabase + salsa::Database { /// Returns the set of errors obtained from parsing the file including validation errors. fn parse_errors(&self, file_id: EditionedFileId) -> Option>; - /// The crate graph. - #[salsa::input] - fn crate_graph(&self) -> Arc; - - #[salsa::input] - fn crate_workspace_data(&self) -> Arc>>; - #[salsa::transparent] - fn toolchain_channel(&self, krate: CrateId) -> Option; + fn toolchain_channel(&self, krate: Crate) -> Option; /// Crates whose root file is in `id`. - fn source_root_crates(&self, id: SourceRootId) -> Arc<[CrateId]>; + fn source_root_crates(&self, id: SourceRootId) -> Arc<[Crate]>; #[salsa::transparent] - fn relevant_crates(&self, file_id: FileId) -> Arc<[CrateId]>; + fn relevant_crates(&self, file_id: FileId) -> Arc<[Crate]>; + + /// Returns the crates in topological order. + /// + /// **Warning**: do not use this query in analysis! It kills incrementality across crate metadata modifications. + #[salsa::input] + fn all_crates(&self) -> Arc>; + + /// Returns an iterator over all transitive dependencies of the given crate, + /// including the crate itself. + /// + /// **Warning**: do not use this query in analysis! It kills incrementality across crate metadata modifications. + /// + #[salsa::transparent] + fn transitive_deps(&self, crate_id: Crate) -> FxHashSet; + + /// Returns all transitive reverse dependencies of the given crate, + /// including the crate itself. + /// + /// **Warning**: Do not use this query in analysis! It kills incrementality across crate metadata modifications. + #[salsa::invoke(input::transitive_rev_deps)] + #[salsa::transparent] + fn transitive_rev_deps(&self, of: Crate) -> FxHashSet; +} + +pub fn transitive_deps(db: &dyn SourceDatabase, crate_id: Crate) -> FxHashSet { + // There is a bit of duplication here and in `CrateGraphBuilder` in the same method, but it's not terrible + // and removing that is a bit difficult. + let mut worklist = vec![crate_id]; + let mut deps = FxHashSet::default(); + + while let Some(krate) = worklist.pop() { + if !deps.insert(krate) { + continue; + } + + worklist.extend(krate.data(db).dependencies.iter().map(|dep| dep.crate_id)); + } + + deps } #[salsa::db] @@ -257,6 +290,9 @@ pub trait SourceDatabase: salsa::Database { let source_root = self.source_root(source_root.source_root_id(self)); source_root.source_root(self).resolve_path(path) } + + #[doc(hidden)] + fn crates_map(&self) -> Arc; } /// Crate related data shared by the whole workspace. @@ -268,12 +304,8 @@ pub struct CrateWorkspaceData { pub toolchain: Option, } -fn toolchain_channel(db: &dyn RootQueryDb, krate: CrateId) -> Option { - db.crate_workspace_data() - .get(&krate)? - .toolchain - .as_ref() - .and_then(|v| ReleaseChannel::from_str(&v.pre)) +fn toolchain_channel(db: &dyn RootQueryDb, krate: Crate) -> Option { + krate.workspace_data(db).toolchain.as_ref().and_then(|v| ReleaseChannel::from_str(&v.pre)) } fn parse(db: &dyn RootQueryDb, file_id: EditionedFileId) -> Parse { @@ -291,21 +323,19 @@ fn parse_errors(db: &dyn RootQueryDb, file_id: EditionedFileId) -> Option Arc<[CrateId]> { - let graph = db.crate_graph(); - let mut crates = graph +fn source_root_crates(db: &dyn RootQueryDb, id: SourceRootId) -> Arc<[Crate]> { + let crates = db.all_crates(); + crates .iter() + .copied() .filter(|&krate| { - let root_file = graph[krate].root_file_id; + let root_file = krate.data(db).root_file_id; db.file_source_root(root_file).source_root_id(db) == id }) - .collect::>(); - crates.sort(); - crates.dedup(); - crates.into_iter().collect() + .collect() } -fn relevant_crates(db: &dyn RootQueryDb, file_id: FileId) -> Arc<[CrateId]> { +fn relevant_crates(db: &dyn RootQueryDb, file_id: FileId) -> Arc<[Crate]> { let _p = tracing::info_span!("relevant_crates").entered(); let source_root = db.file_source_root(file_id); diff --git a/crates/cfg/src/lib.rs b/crates/cfg/src/lib.rs index 08545b6851..26860fb932 100644 --- a/crates/cfg/src/lib.rs +++ b/crates/cfg/src/lib.rs @@ -104,6 +104,12 @@ impl CfgOptions { _ => None, }) } + + pub fn to_hashable(&self) -> HashableCfgOptions { + let mut enabled = self.enabled.iter().cloned().collect::>(); + enabled.sort_unstable(); + HashableCfgOptions { _enabled: enabled } + } } impl Extend for CfgOptions { @@ -256,3 +262,9 @@ impl fmt::Display for InactiveReason { Ok(()) } } + +/// A `CfgOptions` that implements `Hash`, for the sake of hashing only. +#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub struct HashableCfgOptions { + _enabled: Box<[CfgAtom]>, +} diff --git a/crates/hir-def/src/attr.rs b/crates/hir-def/src/attr.rs index 52a72bce91..579ea12e6a 100644 --- a/crates/hir-def/src/attr.rs +++ b/crates/hir-def/src/attr.rs @@ -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() { diff --git a/crates/hir-def/src/data.rs b/crates/hir-def/src/data.rs index bec6627877..9c87dc31db 100644 --- a/crates/hir-def/src/data.rs +++ b/crates/hir-def/src/data.rs @@ -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, pub visibility: RawVisibility, - pub crate_id: Option, + pub crate_id: Option, } 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, + local_def_map: Arc, diagnostics: Vec, 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, diff --git a/crates/hir-def/src/data/adt.rs b/crates/hir-def/src/data/adt.rs index 28992ec600..bf8f5024c2 100644 --- a/crates/hir-def/src/data/adt.rs +++ b/crates/hir-def/src/data/adt.rs @@ -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 { @@ -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, diff --git a/crates/hir-def/src/db.rs b/crates/hir-def/src/db.rs index 0772d00f03..b6707af618 100644 --- a/crates/hir-def/src/db.rs +++ b/crates/hir-def/src/db.rs @@ -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, Arc); - #[salsa::invoke(DefMap::crate_def_map_query)] - fn crate_def_map(&self, krate: CrateId) -> Arc; + #[salsa::invoke_actual(DefMap::crate_local_def_map_query)] + fn crate_local_def_map(&self, krate: Crate) -> (Arc, Arc); + + #[salsa::invoke_actual(DefMap::crate_def_map_query)] + fn crate_def_map(&self, krate: Crate) -> Arc; /// 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; + fn lang_item(&self, start_crate: Crate, item: LangItem) -> Option; - #[salsa::invoke(ImportMap::import_map_query)] - fn import_map(&self, krate: CrateId) -> Arc; + #[salsa::invoke_actual(ImportMap::import_map_query)] + fn import_map(&self, krate: Crate) -> Arc; // 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>; + #[salsa::invoke_actual(LangItems::crate_lang_items_query)] + fn crate_lang_items(&self, krate: Crate) -> Option>; - #[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>; + #[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>; - 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 { diff --git a/crates/hir-def/src/expander.rs b/crates/hir-def/src/expander.rs index a1b3123c99..c5ce8c454c 100644 --- a/crates/hir-def/src/expander.rs +++ b/crates/hir-def/src/expander.rs @@ -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 } diff --git a/crates/hir-def/src/expr_store/body.rs b/crates/hir-def/src/expr_store/body.rs index a55fec4f8b..8aca4eb9bc 100644 --- a/crates/hir-def/src/expr_store/body.rs +++ b/crates/hir-def/src/expr_store/body.rs @@ -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)) }), ) }); diff --git a/crates/hir-def/src/expr_store/lower.rs b/crates/hir-def/src/expr_store/lower.rs index c3ca610fae..c346cec242 100644 --- a/crates/hir-def/src/expr_store/lower.rs +++ b/crates/hir-def/src/expr_store/lower.rs @@ -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)>, body: Option, - 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, - 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, + local_def_map: Arc, ast_id_map: Arc, - 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>, ) -> 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(), diff --git a/crates/hir-def/src/expr_store/tests.rs b/crates/hir-def/src/expr_store/tests.rs index 16bf46d3e3..7bf27747c4 100644 --- a/crates/hir-def/src/expr_store/tests.rs +++ b/crates/hir-def/src/expr_store/tests.rs @@ -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", diff --git a/crates/hir-def/src/find_path.rs b/crates/hir-def/src/find_path.rs index c30ad0163b..48f31698dd 100644 --- a/crates/hir-def/src/find_path.rs +++ b/crates/hir-def/src/find_path.rs @@ -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, ) { - 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, - 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, diff --git a/crates/hir-def/src/generics.rs b/crates/hir-def/src/generics.rs index ed5038c5ae..6f1650adeb 100644 --- a/crates/hir-def/src/generics.rs +++ b/crates/hir-def/src/generics.rs @@ -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, Expander)>, - exp_fill: &mut dyn FnMut() -> (Arc, Expander), + exp: &mut Option<(Arc, Arc, Expander)>, + exp_fill: &mut dyn FnMut() -> (Arc, Arc, 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 { ¯o_types_map, ¯o_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); } } }); diff --git a/crates/hir-def/src/import_map.rs b/crates/hir-def/src/import_map.rs index 64c1d0d274..1cdc4c0259 100644 --- a/crates/hir-def/src/import_map.rs +++ b/crates/hir-def/src/import_map.rs @@ -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 { + pub(crate) fn import_map_query(db: &dyn DefDatabase, krate: Crate) -> Arc { 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 { 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); diff --git a/crates/hir-def/src/item_scope.rs b/crates/hir-def/src/item_scope.rs index 0ca1eb9bcf..0c683f3531 100644 --- a/crates/hir-def/src/item_scope.rs +++ b/crates/hir-def/src/item_scope.rs @@ -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 { + pub fn krate(&self, db: &dyn DefDatabase) -> Option { match self { ItemInNs::Types(id) | ItemInNs::Values(id) => id.module(db).map(|m| m.krate), ItemInNs::Macros(id) => Some(id.module(db).krate), diff --git a/crates/hir-def/src/item_tree.rs b/crates/hir-def/src/item_tree.rs index 382afbcb1d..9acf98e62c 100644 --- a/crates/hir-def/src/item_tree.rs +++ b/crates/hir-def/src/item_tree.rs @@ -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()) } diff --git a/crates/hir-def/src/lang_item.rs b/crates/hir-def/src/lang_item.rs index 59f51db9f7..70c28009f4 100644 --- a/crates/hir-def/src/lang_item.rs +++ b/crates/hir-def/src/lang_item.rs @@ -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> { 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 { 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( @@ -209,19 +206,14 @@ pub(crate) fn lang_attr(db: &dyn DefDatabase, item: AttrDefId) -> Option 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> { +pub(crate) fn crate_notable_traits(db: &dyn DefDatabase, krate: Crate) -> Option> { 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 { + pub fn path(&self, db: &dyn DefDatabase, start_crate: Crate) -> Option { 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 { + pub fn ty_rel_path(&self, db: &dyn DefDatabase, start_crate: Crate, seg: Name) -> Option { let t = db.lang_item(start_crate, *self)?; Some(Path::LangItem(t, Some(seg))) } diff --git a/crates/hir-def/src/lib.rs b/crates/hir-def/src/lib.rs index 15ef8364ed..fbbeb4beb9 100644 --- a/crates/hir-def/src/lib.rs +++ b/crates/hir-def/src/lib.rs @@ -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 = - indexmap::IndexMap>; +type FxIndexMap = indexmap::IndexMap; /// 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, Arc) { + db.crate_local_def_map(self.krate) + } + + pub fn krate(self) -> Crate { self.krate } } @@ -374,8 +378,8 @@ impl From for ModuleDefId { } } -impl From for CrateRootModuleId { - fn from(krate: CrateId) -> Self { +impl From for CrateRootModuleId { + fn from(krate: Crate) -> Self { CrateRootModuleId { krate } } } @@ -394,7 +398,7 @@ impl TryFrom 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, Arc) { + 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 { + db.crate_local_def_map(self.krate).1 + } + pub fn crate_def_map(self, db: &dyn DefDatabase) -> Arc { db.crate_def_map(self.krate) } - pub fn krate(self) -> CrateId { + pub fn krate(self) -> Crate { self.krate } @@ -982,7 +997,7 @@ impl From 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 + Copy, ) -> Option { 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 + Copy, ) -> Result>, 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 + Copy, ) -> Result>, UnresolvedMacro> { let expands_to = hir_expand::ExpandTo::from_call_site(self.value); @@ -1442,7 +1457,7 @@ fn macro_call_as_call_id( call: &AstIdWithPath, call_site: SyntaxContextId, expand_to: ExpandTo, - krate: CrateId, + krate: Crate, resolver: impl Fn(&path::ModPath) -> Option + Copy, ) -> Result, 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, eager_resolver: impl Fn(&path::ModPath) -> Option, ) -> Result>, UnresolvedMacro> { diff --git a/crates/hir-def/src/macro_expansion_tests/mod.rs b/crates/hir-def/src/macro_expansion_tests/mod.rs index d0678a4065..70b512c014 100644 --- a/crates/hir-def/src/macro_expansion_tests/mod.rs +++ b/crates/hir-def/src/macro_expansion_tests/mod.rs @@ -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::() + } } diff --git a/crates/hir-def/src/nameres.rs b/crates/hir-def/src/nameres.rs index 5b3d75c4ee..054c285fa2 100644 --- a/crates/hir-def/src/nameres.rs +++ b/crates/hir-def/src/nameres.rs @@ -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)>, +} + +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))> + '_ + { + 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, @@ -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)>, - /// Side table for resolving derive helpers. exported_derives: FxHashMap>, fn_proc_macro_mapping: FxHashMap, @@ -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 { + fn def_map(self, db: &dyn DefDatabase, krate: Crate) -> Arc { 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 { - 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 { + db.crate_local_def_map(crate_id).0 + } + + pub(crate) fn crate_local_def_map_query( + db: &dyn DefDatabase, + crate_id: Crate, + ) -> (Arc, Arc) { + 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 { @@ -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, module_data: ModuleData, block: Option, @@ -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))> + '_ - { - self.data.extern_prelude.iter().map(|(name, &def)| (name, def)) - } - pub(crate) fn macro_use_prelude(&self) -> &FxHashMap)> { &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, ) -> (PerNs, Option) { 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, ResolvePathResultPrefixInfo) { let res = self.resolve_path_fp_with_macro_single( + local_def_map, db, ResolveMode::Other, original_module, diff --git a/crates/hir-def/src/nameres/attr_resolution.rs b/crates/hir-def/src/nameres/attr_resolution.rs index d1f6ed023c..289b9e2fb7 100644 --- a/crates/hir-def/src/nameres/attr_resolution.rs +++ b/crates/hir-def/src/nameres/attr_resolution.rs @@ -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, @@ -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, 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> { diff --git a/crates/hir-def/src/nameres/collector.rs b/crates/hir-def/src/nameres/collector.rs index bf013c25ef..371e994334 100644 --- a/crates/hir-def/src/nameres/collector.rs +++ b/crates/hir-def/src/nameres/collector.rs @@ -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>, +) -> (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>, // The dependencies of the current crate, including optional deps like `test`. - deps: FxHashMap, + deps: FxHashMap, glob_imports: FxHashMap>, unresolved_imports: Vec, 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>, extern_crate: Option, ) { @@ -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, - 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, diff --git a/crates/hir-def/src/nameres/path_resolution.rs b/crates/hir-def/src/nameres/path_resolution.rs index 47c08d3d1d..977bc16adf 100644 --- a/crates/hir-def/src/nameres/path_resolution.rs +++ b/crates/hir-def/src/nameres/path_resolution.rs @@ -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 { 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, ) -> 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, path: &ModPath, ) -> Either { @@ -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) diff --git a/crates/hir-def/src/nameres/tests/incremental.rs b/crates/hir-def/src/nameres/tests/incremental.rs index cd59020576..9a601e0f01 100644 --- a/crates/hir-def/src/nameres/tests/incremental.rs +++ b/crates/hir-def/src/nameres/tests/incremental.rs @@ -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( diff --git a/crates/hir-def/src/nameres/tests/macros.rs b/crates/hir-def/src/nameres/tests/macros.rs index 610886d55f..0348a7076a 100644 --- a/crates/hir-def/src/nameres/tests/macros.rs +++ b/crates/hir-def/src/nameres/tests/macros.rs @@ -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; diff --git a/crates/hir-def/src/pretty.rs b/crates/hir-def/src/pretty.rs index eb9488feaa..c431b45dc7 100644 --- a/crates/hir-def/src/pretty.rs +++ b/crates/hir-def/src/pretty.rs @@ -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") + )?, }, } diff --git a/crates/hir-def/src/resolver.rs b/crates/hir-def/src/resolver.rs index f4773de085..72723499fc 100644 --- a/crates/hir-def/src/resolver.rs +++ b/crates/hir-def/src/resolver.rs @@ -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, + local_def_map: Arc, 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, ) -> Option<(MacroId, Option)> { - 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 + '_ { 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) -> 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, local_def_map: Arc) -> 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, Option, 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 }, } } } diff --git a/crates/hir-def/src/src.rs b/crates/hir-def/src/src.rs index c7ebfeecf5..43d31aa503 100644 --- a/crates/hir-def/src/src.rs +++ b/crates/hir-def/src/src.rs @@ -158,7 +158,7 @@ impl HasChildSource 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 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( diff --git a/crates/hir-def/src/test_db.rs b/crates/hir-def/src/test_db.rs index b6f08c0caf..0b97e6c9ce 100644 --- a/crates/hir-def/src/test_db.rs +++ b/crates/hir-def/src/test_db.rs @@ -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, files: Arc, + crates_map: Arc, events: Arc>>>, } @@ -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 { + 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 { diff --git a/crates/hir-expand/src/attrs.rs b/crates/hir-expand/src/attrs.rs index c9c793d54f..64b9b49b3e 100644 --- a/crates/hir-expand/src/attrs.rs +++ b/crates/hir-expand/src/attrs.rs @@ -1,7 +1,7 @@ //! A higher level attributes based on TokenTree, with also some shortcuts. use std::{borrow::Cow, fmt, ops}; -use base_db::CrateId; +use base_db::Crate; use cfg::CfgExpr; use either::Either; use intern::{sym, Interned, Symbol}; @@ -119,7 +119,7 @@ impl RawAttrs { /// Processes `cfg_attr`s, returning the resulting semantic `Attrs`. // FIXME: This should return a different type, signaling it was filtered? - pub fn filter(self, db: &dyn ExpandDatabase, krate: CrateId) -> RawAttrs { + pub fn filter(self, db: &dyn ExpandDatabase, krate: Crate) -> RawAttrs { let has_cfg_attrs = self .iter() .any(|attr| attr.path.as_ident().is_some_and(|name| *name == sym::cfg_attr.clone())); @@ -127,7 +127,7 @@ impl RawAttrs { return self; } - let crate_graph = db.crate_graph(); + let cfg_options = krate.cfg_options(db); let new_attrs = self.iter() .flat_map(|attr| -> SmallVec<[_; 1]> { @@ -151,7 +151,6 @@ impl RawAttrs { |(idx, attr)| Attr::from_tt(db, attr, index.with_cfg_attr(idx)), ); - let cfg_options = &crate_graph[krate].cfg_options; let cfg = TopSubtree::from_token_trees(subtree.top_subtree().delimiter, cfg); let cfg = CfgExpr::parse(&cfg); if cfg_options.check(&cfg) == Some(false) { diff --git a/crates/hir-expand/src/builtin/fn_macro.rs b/crates/hir-expand/src/builtin/fn_macro.rs index d8b3f40e8f..b56ec3d04c 100644 --- a/crates/hir-expand/src/builtin/fn_macro.rs +++ b/crates/hir-expand/src/builtin/fn_macro.rs @@ -231,7 +231,7 @@ fn assert_expand( let cond = expect_fragment( &mut iter, parser::PrefixEntryPoint::Expr, - db.crate_graph()[id.lookup(db).krate].edition, + id.lookup(db).krate.data(db).edition, tt.top_subtree().delimiter.delim_span(), ); _ = iter.expect_char(','); @@ -333,7 +333,7 @@ fn cfg_expand( ) -> ExpandResult { let loc = db.lookup_intern_macro_call(id); let expr = CfgExpr::parse(tt); - let enabled = db.crate_graph()[loc.krate].cfg_options.check(&expr) != Some(false); + let enabled = loc.krate.cfg_options(db).check(&expr) != Some(false); let expanded = if enabled { quote!(span=>true) } else { quote!(span=>false) }; ExpandResult::ok(expanded) } @@ -669,7 +669,7 @@ fn relative_file( if res == call_site && !allow_recursion { Err(ExpandError::other(err_span, format!("recursive inclusion of `{path_str}`"))) } else { - Ok(EditionedFileId::new(res, db.crate_graph()[lookup.krate].edition)) + Ok(EditionedFileId::new(res, lookup.krate.data(db).edition)) } } @@ -812,7 +812,7 @@ fn include_str_expand( fn get_env_inner(db: &dyn ExpandDatabase, arg_id: MacroCallId, key: &Symbol) -> Option { let krate = db.lookup_intern_macro_call(arg_id).krate; - db.crate_graph()[krate].env.get(key.as_str()) + krate.env(db).get(key.as_str()) } fn env_expand( diff --git a/crates/hir-expand/src/cfg_process.rs b/crates/hir-expand/src/cfg_process.rs index 626a82ae08..0ceab3c890 100644 --- a/crates/hir-expand/src/cfg_process.rs +++ b/crates/hir-expand/src/cfg_process.rs @@ -1,7 +1,7 @@ //! Processes out #[cfg] and #[cfg_attr] attributes from the input for the derive macro use std::iter::Peekable; -use base_db::CrateId; +use base_db::Crate; use cfg::{CfgAtom, CfgExpr}; use intern::{sym, Symbol}; use rustc_hash::FxHashSet; @@ -13,16 +13,16 @@ use tracing::{debug, warn}; use crate::{db::ExpandDatabase, proc_macro::ProcMacroKind, MacroCallLoc, MacroDefKind}; -fn check_cfg(db: &dyn ExpandDatabase, attr: &Attr, krate: CrateId) -> Option { +fn check_cfg(db: &dyn ExpandDatabase, attr: &Attr, krate: Crate) -> Option { if !attr.simple_name().as_deref().map(|v| v == "cfg")? { return None; } let cfg = parse_from_attr_token_tree(&attr.meta()?.token_tree()?)?; - let enabled = db.crate_graph()[krate].cfg_options.check(&cfg) != Some(false); + let enabled = krate.cfg_options(db).check(&cfg) != Some(false); Some(enabled) } -fn check_cfg_attr(db: &dyn ExpandDatabase, attr: &Attr, krate: CrateId) -> Option { +fn check_cfg_attr(db: &dyn ExpandDatabase, attr: &Attr, krate: Crate) -> Option { if !attr.simple_name().as_deref().map(|v| v == "cfg_attr")? { return None; } @@ -32,17 +32,17 @@ fn check_cfg_attr(db: &dyn ExpandDatabase, attr: &Attr, krate: CrateId) -> Optio pub fn check_cfg_attr_value( db: &dyn ExpandDatabase, attr: &TokenTree, - krate: CrateId, + krate: Crate, ) -> Option { let cfg_expr = parse_from_attr_token_tree(attr)?; - let enabled = db.crate_graph()[krate].cfg_options.check(&cfg_expr) != Some(false); + let enabled = krate.cfg_options(db).check(&cfg_expr) != Some(false); Some(enabled) } fn process_has_attrs_with_possible_comma( db: &dyn ExpandDatabase, items: impl Iterator, - krate: CrateId, + krate: Crate, remove: &mut FxHashSet, ) -> Option<()> { for item in items { @@ -144,7 +144,7 @@ fn remove_possible_comma(item: &impl AstNode, res: &mut FxHashSet fn process_enum( db: &dyn ExpandDatabase, variants: VariantList, - krate: CrateId, + krate: Crate, remove: &mut FxHashSet, ) -> Option<()> { 'variant: for variant in variants.variants() { diff --git a/crates/hir-expand/src/change.rs b/crates/hir-expand/src/change.rs index 7a42d66260..3f5b8fdc9b 100644 --- a/crates/hir-expand/src/change.rs +++ b/crates/hir-expand/src/change.rs @@ -1,17 +1,16 @@ //! Defines a unit of change that can applied to the database to get the next //! state. Changes are transactional. -use base_db::{CrateGraph, CrateId, CrateWorkspaceData, FileChange, SourceRoot}; -use rustc_hash::FxHashMap; +use base_db::{CrateGraphBuilder, FileChange, SourceRoot}; use salsa::Durability; use span::FileId; use triomphe::Arc; -use crate::{db::ExpandDatabase, proc_macro::ProcMacros}; +use crate::{db::ExpandDatabase, proc_macro::ProcMacrosBuilder}; #[derive(Debug, Default)] pub struct ChangeWithProcMacros { pub source_change: FileChange, - pub proc_macros: Option, + pub proc_macros: Option, } impl ChangeWithProcMacros { @@ -20,8 +19,13 @@ impl ChangeWithProcMacros { } pub fn apply(self, db: &mut impl ExpandDatabase) { - self.source_change.apply(db); + let crates_id_map = self.source_change.apply(db); if let Some(proc_macros) = self.proc_macros { + let proc_macros = proc_macros.build( + crates_id_map + .as_ref() + .expect("cannot set proc macros without setting the crate graph too"), + ); db.set_proc_macros_with_durability(Arc::new(proc_macros), Durability::HIGH); } } @@ -30,16 +34,11 @@ impl ChangeWithProcMacros { self.source_change.change_file(file_id, new_text) } - pub fn set_crate_graph( - &mut self, - graph: CrateGraph, - ws_data: FxHashMap>, - ) { + pub fn set_crate_graph(&mut self, graph: CrateGraphBuilder) { self.source_change.set_crate_graph(graph); - self.source_change.set_ws_data(ws_data); } - pub fn set_proc_macros(&mut self, proc_macros: ProcMacros) { + pub fn set_proc_macros(&mut self, proc_macros: ProcMacrosBuilder) { self.proc_macros = Some(proc_macros); } diff --git a/crates/hir-expand/src/db.rs b/crates/hir-expand/src/db.rs index 2f97cceab5..112327f11e 100644 --- a/crates/hir-expand/src/db.rs +++ b/crates/hir-expand/src/db.rs @@ -1,6 +1,6 @@ //! Defines database & queries for macro expansion. -use base_db::{CrateId, RootQueryDb}; +use base_db::{Crate, RootQueryDb}; use either::Either; use mbe::MatchedArmIndex; use rustc_hash::FxHashSet; @@ -23,7 +23,7 @@ use crate::{ span_with_call_site_ctxt, span_with_def_site_ctxt, span_with_mixed_site_ctxt, SyntaxContextExt as _, }, - proc_macro::{CustomProcMacroExpander, ProcMacros}, + proc_macro::{CrateProcMacros, CustomProcMacroExpander, ProcMacros}, span_map::{ExpansionSpanMap, RealSpanMap, SpanMap, SpanMapRef}, tt, AstId, BuiltinAttrExpander, BuiltinDeriveExpander, BuiltinFnLikeExpander, EagerCallInfo, EagerExpander, ExpandError, ExpandResult, ExpandTo, MacroCallKind, MacroCallLoc, MacroDefId, @@ -57,10 +57,13 @@ pub enum TokenExpander { #[query_group::query_group] pub trait ExpandDatabase: RootQueryDb { - /// The proc macros. + /// The proc macros. Do not use this! Use `proc_macros_for_crate()` instead. #[salsa::input] fn proc_macros(&self) -> Arc; + #[salsa::invoke_actual(crate::proc_macro::proc_macros_for_crate)] + fn proc_macros_for_crate(&self, krate: Crate) -> Option>; + fn ast_id_map(&self, file_id: HirFileId) -> Arc; #[salsa::transparent] @@ -120,7 +123,7 @@ pub trait ExpandDatabase: RootQueryDb { #[salsa::invoke(DeclarativeMacroExpander::expander)] fn decl_macro_expander( &self, - def_crate: CrateId, + def_crate: Crate, id: AstId, ) -> Arc; diff --git a/crates/hir-expand/src/declarative.rs b/crates/hir-expand/src/declarative.rs index 91cbbc3736..fbce320756 100644 --- a/crates/hir-expand/src/declarative.rs +++ b/crates/hir-expand/src/declarative.rs @@ -1,6 +1,6 @@ //! Compiled declarative macro expanders (`macro_rules!` and `macro`) -use base_db::CrateId; +use base_db::Crate; use intern::sym; use span::{Edition, HirFileIdRepr, MacroCallId, Span, SyntaxContextId}; use stdx::TupleExt; @@ -70,7 +70,7 @@ impl DeclarativeMacroExpander { pub(crate) fn expander( db: &dyn ExpandDatabase, - def_crate: CrateId, + def_crate: Crate, id: AstId, ) -> Arc { let (root, map) = crate::db::parse_with_map(db, id.file_id); @@ -101,14 +101,12 @@ impl DeclarativeMacroExpander { } }; let ctx_edition = |ctx: SyntaxContextId| { - let crate_graph = db.crate_graph(); - if ctx.is_root() { - crate_graph[def_crate].edition + def_crate.data(db).edition } else { // UNWRAP-SAFETY: Only the root context has no outer expansion let krate = db.lookup_intern_macro_call(ctx.outer_expn(db).unwrap()).def.krate; - crate_graph[krate].edition + krate.data(db).edition } }; let (mac, transparency) = match id.to_ptr(db).to_node(&root) { diff --git a/crates/hir-expand/src/eager.rs b/crates/hir-expand/src/eager.rs index 4a98b455ca..02dc75a4a6 100644 --- a/crates/hir-expand/src/eager.rs +++ b/crates/hir-expand/src/eager.rs @@ -18,7 +18,7 @@ //! //! //! See the full discussion : -use base_db::CrateId; +use base_db::Crate; use span::SyntaxContextId; use syntax::{ted, Parse, SyntaxElement, SyntaxNode, TextSize, WalkEvent}; use syntax_bridge::DocCommentDesugarMode; @@ -34,7 +34,7 @@ use crate::{ pub fn expand_eager_macro_input( db: &dyn ExpandDatabase, - krate: CrateId, + krate: Crate, macro_call: &ast::MacroCall, ast_id: AstId, def: MacroDefId, @@ -115,7 +115,7 @@ fn lazy_expand( def: &MacroDefId, macro_call: &ast::MacroCall, ast_id: AstId, - krate: CrateId, + krate: Crate, call_site: SyntaxContextId, ) -> ExpandResult<(InFile>, Arc)> { let expand_to = ExpandTo::from_call_site(macro_call); @@ -137,7 +137,7 @@ fn eager_macro_recur( expanded_map: &mut ExpansionSpanMap, mut offset: TextSize, curr: InFile, - krate: CrateId, + krate: Crate, call_site: SyntaxContextId, macro_resolver: &dyn Fn(&ModPath) -> Option, ) -> ExpandResult> { @@ -176,7 +176,7 @@ fn eager_macro_recur( Some(path) => match macro_resolver(&path) { Some(def) => def, None => { - let edition = db.crate_graph()[krate].edition; + let edition = krate.data(db).edition; error = Some(ExpandError::other( span_map.span_at(call.syntax().text_range().start()), format!("unresolved macro {}", path.display(db, edition)), diff --git a/crates/hir-expand/src/lib.rs b/crates/hir-expand/src/lib.rs index f8c83dce55..a1e484c08b 100644 --- a/crates/hir-expand/src/lib.rs +++ b/crates/hir-expand/src/lib.rs @@ -33,7 +33,7 @@ use triomphe::Arc; use core::fmt; use std::hash::Hash; -use base_db::CrateId; +use base_db::Crate; use either::Either; use span::{ Edition, EditionedFileId, ErasedFileAstId, FileAstId, HirFileIdRepr, Span, SpanAnchor, @@ -157,7 +157,7 @@ impl ExpandError { pub enum ExpandErrorKind { /// Attribute macro expansion is disabled. ProcMacroAttrExpansionDisabled, - MissingProcMacroExpander(CrateId), + MissingProcMacroExpander(Crate), /// The macro for this call is disabled. MacroDisabled, /// The macro definition has errors. @@ -200,7 +200,7 @@ impl ExpandErrorKind { kind: RenderedExpandError::DISABLED, }, &ExpandErrorKind::MissingProcMacroExpander(def_crate) => { - match db.proc_macros().get_error_for_crate(def_crate) { + match db.proc_macros_for_crate(def_crate).as_ref().and_then(|it| it.get_error()) { Some((e, hard_err)) => RenderedExpandError { message: e.to_owned(), error: hard_err, @@ -250,14 +250,14 @@ impl From for ExpandError { #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct MacroCallLoc { pub def: MacroDefId, - pub krate: CrateId, + pub krate: Crate, pub kind: MacroCallKind, pub ctxt: SyntaxContextId, } #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub struct MacroDefId { - pub krate: CrateId, + pub krate: Crate, pub edition: Edition, pub kind: MacroDefKind, pub local_inner: bool, @@ -525,7 +525,7 @@ impl MacroDefId { pub fn make_call( self, db: &dyn ExpandDatabase, - krate: CrateId, + krate: Crate, kind: MacroCallKind, ctxt: SyntaxContextId, ) -> MacroCallId { diff --git a/crates/hir-expand/src/mod_path.rs b/crates/hir-expand/src/mod_path.rs index 6f6f41f322..40b10cb438 100644 --- a/crates/hir-expand/src/mod_path.rs +++ b/crates/hir-expand/src/mod_path.rs @@ -11,7 +11,7 @@ use crate::{ name::{AsName, Name}, tt, }; -use base_db::CrateId; +use base_db::Crate; use intern::sym; use smallvec::SmallVec; use span::{Edition, SyntaxContextId}; @@ -33,7 +33,7 @@ pub enum PathKind { Abs, // FIXME: Can we remove this somehow? /// `$crate` from macro expansion - DollarCrate(CrateId), + DollarCrate(Crate), } impl PathKind { @@ -333,7 +333,7 @@ fn convert_path_tt(db: &dyn ExpandDatabase, tt: tt::TokenTreesView<'_>) -> Optio Some(ModPath { kind, segments }) } -pub fn resolve_crate_root(db: &dyn ExpandDatabase, mut ctxt: SyntaxContextId) -> Option { +pub fn resolve_crate_root(db: &dyn ExpandDatabase, mut ctxt: SyntaxContextId) -> Option { // When resolving `$crate` from a `macro_rules!` invoked in a `macro`, // we don't want to pretend that the `macro_rules!` definition is in the `macro` // as described in `SyntaxContextId::apply_mark`, so we ignore prepended opaque marks. diff --git a/crates/hir-expand/src/name.rs b/crates/hir-expand/src/name.rs index 0758bd4515..51721effa3 100644 --- a/crates/hir-expand/src/name.rs +++ b/crates/hir-expand/src/name.rs @@ -260,7 +260,7 @@ impl AsName for ast::FieldKind { } } -impl AsName for base_db::Dependency { +impl AsName for base_db::BuiltDependency { fn as_name(&self) -> Name { Name::new_symbol_root((*self.name).clone()) } diff --git a/crates/hir-expand/src/prettify_macro_expansion_.rs b/crates/hir-expand/src/prettify_macro_expansion_.rs index 944341ec3f..f398b070f7 100644 --- a/crates/hir-expand/src/prettify_macro_expansion_.rs +++ b/crates/hir-expand/src/prettify_macro_expansion_.rs @@ -1,6 +1,6 @@ //! Pretty printing of macros output. -use base_db::CrateId; +use base_db::Crate; use rustc_hash::FxHashMap; use syntax::NodeOrToken; use syntax::{ast::make, SyntaxNode}; @@ -13,13 +13,12 @@ pub fn prettify_macro_expansion( db: &dyn ExpandDatabase, syn: SyntaxNode, span_map: &ExpansionSpanMap, - target_crate_id: CrateId, + target_crate_id: Crate, ) -> SyntaxNode { // Because `syntax_bridge::prettify_macro_expansion::prettify_macro_expansion()` clones subtree for `syn`, // that means it will be offsetted to the beginning. let span_offset = syn.text_range().start(); - let crate_graph = db.crate_graph(); - let target_crate = &crate_graph[target_crate_id]; + let target_crate = target_crate_id.data(db); let mut syntax_ctx_id_to_dollar_crate_replacement = FxHashMap::default(); syntax_bridge::prettify_macro_expansion::prettify_macro_expansion(syn, &mut |dollar_crate| { let ctx = span_map.span_at(dollar_crate.text_range().start() + span_offset).ctx; @@ -41,7 +40,7 @@ pub fn prettify_macro_expansion( target_crate.dependencies.iter().find(|dep| dep.crate_id == macro_def_crate) { make::tokens::ident(dep.name.as_str()) - } else if let Some(crate_name) = &crate_graph[macro_def_crate].display_name { + } else if let Some(crate_name) = ¯o_def_crate.extra_data(db).display_name { make::tokens::ident(crate_name.crate_name().as_str()) } else { return dollar_crate.clone(); diff --git a/crates/hir-expand/src/proc_macro.rs b/crates/hir-expand/src/proc_macro.rs index 3dc3dcd760..cdf63e92a8 100644 --- a/crates/hir-expand/src/proc_macro.rs +++ b/crates/hir-expand/src/proc_macro.rs @@ -1,24 +1,36 @@ //! Proc Macro Expander stuff use core::fmt; +use std::any::Any; use std::{panic::RefUnwindSafe, sync}; -use base_db::{CrateId, Env}; +use base_db::{Crate, CrateBuilderId, CratesIdMap, Env}; use intern::Symbol; use rustc_hash::FxHashMap; use span::Span; +use triomphe::Arc; use crate::{db::ExpandDatabase, tt, ExpandError, ExpandErrorKind, ExpandResult}; -#[derive(Copy, Clone, Eq, PartialEq, Debug, Hash)] +#[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Debug, Hash)] pub enum ProcMacroKind { CustomDerive, Bang, Attr, } +pub trait AsAny: Any { + fn as_any(&self) -> &dyn Any; +} + +impl AsAny for T { + fn as_any(&self) -> &dyn Any { + self + } +} + /// A proc-macro expander implementation. -pub trait ProcMacroExpander: fmt::Debug + Send + Sync + RefUnwindSafe { +pub trait ProcMacroExpander: fmt::Debug + Send + Sync + RefUnwindSafe + AsAny { /// Run the expander with the given input subtree, optional attribute input subtree (for /// [`ProcMacroKind::Attr`]), environment variables, and span information. fn expand( @@ -31,8 +43,18 @@ pub trait ProcMacroExpander: fmt::Debug + Send + Sync + RefUnwindSafe { mixed_site: Span, current_dir: Option, ) -> Result; + + fn eq_dyn(&self, other: &dyn ProcMacroExpander) -> bool; } +impl PartialEq for dyn ProcMacroExpander { + fn eq(&self, other: &Self) -> bool { + self.eq_dyn(other) + } +} + +impl Eq for dyn ProcMacroExpander {} + #[derive(Debug)] pub enum ProcMacroExpansionError { /// The proc-macro panicked. @@ -45,41 +67,68 @@ pub type ProcMacroLoadResult = Result, (String, bool)>; type StoredProcMacroLoadResult = Result, (Box, bool)>; #[derive(Default, Debug)] -pub struct ProcMacrosBuilder(FxHashMap); +pub struct ProcMacrosBuilder(FxHashMap>); + impl ProcMacrosBuilder { - pub fn insert(&mut self, proc_macros_crate: CrateId, proc_macro: ProcMacroLoadResult) { + pub fn insert( + &mut self, + proc_macros_crate: CrateBuilderId, + mut proc_macro: ProcMacroLoadResult, + ) { + if let Ok(proc_macros) = &mut proc_macro { + // Sort proc macros to improve incrementality when only their order has changed (ideally the build system + // will not change their order, but just to be sure). + proc_macros + .sort_unstable_by_key(|proc_macro| (proc_macro.name.clone(), proc_macro.kind)); + } self.0.insert( proc_macros_crate, match proc_macro { - Ok(it) => Ok(it.into_boxed_slice()), - Err((e, hard_err)) => Err((e.into_boxed_str(), hard_err)), + Ok(it) => Arc::new(CrateProcMacros(Ok(it.into_boxed_slice()))), + Err((e, hard_err)) => { + Arc::new(CrateProcMacros(Err((e.into_boxed_str(), hard_err)))) + } }, ); } - pub fn build(mut self) -> ProcMacros { - self.0.shrink_to_fit(); - ProcMacros(self.0) + + pub(crate) fn build(self, crates_id_map: &CratesIdMap) -> ProcMacros { + let mut map = self + .0 + .into_iter() + .map(|(krate, proc_macro)| (crates_id_map[&krate], proc_macro)) + .collect::>(); + map.shrink_to_fit(); + ProcMacros(map) } } -#[derive(Default, Debug)] -pub struct ProcMacros(FxHashMap); - -impl FromIterator<(CrateId, ProcMacroLoadResult)> for ProcMacros { - fn from_iter>(iter: T) -> Self { +impl FromIterator<(CrateBuilderId, ProcMacroLoadResult)> for ProcMacrosBuilder { + fn from_iter>(iter: T) -> Self { let mut builder = ProcMacrosBuilder::default(); for (k, v) in iter { builder.insert(k, v); } - builder.build() + builder } } +#[derive(Debug, PartialEq, Eq)] +pub struct CrateProcMacros(StoredProcMacroLoadResult); + +#[derive(Default, Debug)] +pub struct ProcMacros(FxHashMap>); impl ProcMacros { - fn get(&self, krate: CrateId, idx: u32, err_span: Span) -> Result<&ProcMacro, ExpandError> { - let proc_macros = match self.0.get(&krate) { - Some(Ok(proc_macros)) => proc_macros, - Some(Err(_)) | None => { + fn get(&self, krate: Crate) -> Option> { + self.0.get(&krate).cloned() + } +} + +impl CrateProcMacros { + fn get(&self, idx: u32, err_span: Span) -> Result<&ProcMacro, ExpandError> { + let proc_macros = match &self.0 { + Ok(proc_macros) => proc_macros, + Err(_) => { return Err(ExpandError::other( err_span, "internal error: no proc macros for crate", @@ -98,18 +147,17 @@ impl ProcMacros { ) } - pub fn get_error_for_crate(&self, krate: CrateId) -> Option<(&str, bool)> { - self.0.get(&krate).and_then(|it| it.as_ref().err()).map(|(e, hard_err)| (&**e, *hard_err)) + pub fn get_error(&self) -> Option<(&str, bool)> { + self.0.as_ref().err().map(|(e, hard_err)| (&**e, *hard_err)) } /// Fetch the [`CustomProcMacroExpander`]s and their corresponding names for the given crate. - pub fn for_crate( + pub fn list( &self, - krate: CrateId, def_site_ctx: span::SyntaxContextId, ) -> Option> { - match self.0.get(&krate) { - Some(Ok(proc_macros)) => Some({ + match &self.0 { + Ok(proc_macros) => Some( proc_macros .iter() .enumerate() @@ -117,15 +165,15 @@ impl ProcMacros { let name = crate::name::Name::new_symbol(it.name.clone(), def_site_ctx); (name, CustomProcMacroExpander::new(idx as u32), it.disabled) }) - .collect() - }), + .collect(), + ), _ => None, } } } /// A loaded proc-macro. -#[derive(Debug, Clone)] +#[derive(Debug, Clone, Eq)] pub struct ProcMacro { /// The name of the proc macro. pub name: Symbol, @@ -137,6 +185,23 @@ pub struct ProcMacro { pub disabled: bool, } +// `#[derive(PartialEq)]` generates a strange "cannot move" error. +impl PartialEq for ProcMacro { + fn eq(&self, other: &Self) -> bool { + let Self { name, kind, expander, disabled } = self; + let Self { + name: other_name, + kind: other_kind, + expander: other_expander, + disabled: other_disabled, + } = other; + name == other_name + && kind == other_kind + && expander == other_expander + && disabled == other_disabled + } +} + /// A custom proc-macro expander handle. This handle together with its crate resolves to a [`ProcMacro`] #[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)] pub struct CustomProcMacroExpander { @@ -187,7 +252,7 @@ impl CustomProcMacroExpander { } /// The macro is explicitly disabled due to proc-macro attribute expansion being disabled. - pub fn as_expand_error(&self, def_crate: CrateId) -> Option { + pub fn as_expand_error(&self, def_crate: Crate) -> Option { match self.proc_macro_id { Self::PROC_MACRO_ATTR_DISABLED => Some(ExpandErrorKind::ProcMacroAttrExpansionDisabled), Self::DISABLED_ID => Some(ExpandErrorKind::MacroDisabled), @@ -199,8 +264,8 @@ impl CustomProcMacroExpander { pub fn expand( self, db: &dyn ExpandDatabase, - def_crate: CrateId, - calling_crate: CrateId, + def_crate: Crate, + calling_crate: Crate, tt: &tt::TopSubtree, attr_arg: Option<&tt::TopSubtree>, def_site: Span, @@ -221,8 +286,22 @@ impl CustomProcMacroExpander { ExpandError::new(call_site, ExpandErrorKind::MacroDisabled), ), id => { - let proc_macros = db.proc_macros(); - let proc_macro = match proc_macros.get(def_crate, id, call_site) { + let proc_macros = match db.proc_macros_for_crate(def_crate) { + Some(it) => it, + None => { + return ExpandResult::new( + tt::TopSubtree::empty(tt::DelimSpan { + open: call_site, + close: call_site, + }), + ExpandError::other( + call_site, + "internal error: no proc macros for crate", + ), + ) + } + }; + let proc_macro = match proc_macros.get(id, call_site) { Ok(proc_macro) => proc_macro, Err(e) => { return ExpandResult::new( @@ -235,11 +314,10 @@ impl CustomProcMacroExpander { } }; - let krate_graph = db.crate_graph(); // Proc macros have access to the environment variables of the invoking crate. - let env = &krate_graph[calling_crate].env; + let env = calling_crate.env(db); let current_dir = - krate_graph[calling_crate].proc_macro_cwd.as_deref().map(ToString::to_string); + calling_crate.data(db).proc_macro_cwd.as_deref().map(ToString::to_string); match proc_macro.expander.expand( tt, @@ -278,3 +356,10 @@ impl CustomProcMacroExpander { } } } + +pub(crate) fn proc_macros_for_crate( + db: &dyn ExpandDatabase, + krate: Crate, +) -> Option> { + db.proc_macros().get(krate) +} diff --git a/crates/hir-ty/src/chalk_db.rs b/crates/hir-ty/src/chalk_db.rs index 2be3217330..84eb964d56 100644 --- a/crates/hir-ty/src/chalk_db.rs +++ b/crates/hir-ty/src/chalk_db.rs @@ -11,7 +11,7 @@ use tracing::debug; use chalk_ir::{cast::Caster, fold::shift::Shift, CanonicalVarKinds}; use chalk_solve::rust_ir::{self, OpaqueTyDatumBound, WellKnownTrait}; -use base_db::CrateId; +use base_db::Crate; use hir_def::{ data::{adt::StructFlags, TraitFlags}, hir::Movability, @@ -523,7 +523,7 @@ impl chalk_solve::RustIrDatabase for ChalkContext<'_> { impl ChalkContext<'_> { fn edition(&self) -> Edition { - self.db.crate_graph()[self.krate].edition + self.krate.data(self.db).edition } fn for_trait_impls( @@ -593,7 +593,7 @@ impl chalk_ir::UnificationDatabase for &dyn HirDatabase { pub(crate) fn program_clauses_for_chalk_env_query( db: &dyn HirDatabase, - krate: CrateId, + krate: Crate, block: Option, environment: chalk_ir::Environment, ) -> chalk_ir::ProgramClauses { @@ -665,7 +665,7 @@ pub(crate) fn associated_ty_data_query( pub(crate) fn trait_datum_query( db: &dyn HirDatabase, - krate: CrateId, + krate: Crate, trait_id: TraitId, ) -> Arc { debug!("trait_datum {:?}", trait_id); @@ -750,7 +750,7 @@ fn lang_item_from_well_known_trait(trait_: WellKnownTrait) -> LangItem { pub(crate) fn adt_datum_query( db: &dyn HirDatabase, - krate: CrateId, + krate: Crate, chalk_ir::AdtId(adt_id): AdtId, ) -> Arc { debug!("adt_datum {:?}", adt_id); @@ -824,7 +824,7 @@ pub(crate) fn adt_datum_query( pub(crate) fn impl_datum_query( db: &dyn HirDatabase, - krate: CrateId, + krate: Crate, impl_id: ImplId, ) -> Arc { let _p = tracing::info_span!("impl_datum_query").entered(); @@ -833,11 +833,7 @@ pub(crate) fn impl_datum_query( impl_def_datum(db, krate, impl_) } -fn impl_def_datum( - db: &dyn HirDatabase, - krate: CrateId, - impl_id: hir_def::ImplId, -) -> Arc { +fn impl_def_datum(db: &dyn HirDatabase, krate: Crate, impl_id: hir_def::ImplId) -> Arc { let trait_ref = db .impl_trait(impl_id) // ImplIds for impls where the trait ref can't be resolved should never reach Chalk @@ -887,7 +883,7 @@ fn impl_def_datum( pub(crate) fn associated_ty_value_query( db: &dyn HirDatabase, - krate: CrateId, + krate: Crate, id: AssociatedTyValueId, ) -> Arc { let type_alias: TypeAliasAsValue = from_chalk(db, id); @@ -896,7 +892,7 @@ pub(crate) fn associated_ty_value_query( fn type_alias_associated_ty_value( db: &dyn HirDatabase, - _krate: CrateId, + _krate: Crate, type_alias: TypeAliasId, ) -> Arc { let type_alias_data = db.type_alias_data(type_alias); diff --git a/crates/hir-ty/src/consteval.rs b/crates/hir-ty/src/consteval.rs index b3c604015a..525672bc39 100644 --- a/crates/hir-ty/src/consteval.rs +++ b/crates/hir-ty/src/consteval.rs @@ -1,6 +1,6 @@ //! Constant evaluation details -use base_db::CrateId; +use base_db::Crate; use chalk_ir::{cast::Cast, BoundVar, DebruijnIndex}; use hir_def::{ expr_store::{Body, HygieneId}, @@ -162,7 +162,7 @@ pub fn intern_const_ref( db: &dyn HirDatabase, value: &LiteralConstRef, ty: Ty, - krate: CrateId, + krate: Crate, ) -> Const { let layout = db.layout_of_ty(ty.clone(), TraitEnvironment::empty(krate)); let bytes = match value { @@ -185,7 +185,7 @@ pub fn intern_const_ref( } /// Interns a possibly-unknown target usize -pub fn usize_const(db: &dyn HirDatabase, value: Option, krate: CrateId) -> Const { +pub fn usize_const(db: &dyn HirDatabase, value: Option, krate: Crate) -> Const { intern_const_ref( db, &value.map_or(LiteralConstRef::Unknown, LiteralConstRef::UInt), diff --git a/crates/hir-ty/src/consteval/tests.rs b/crates/hir-ty/src/consteval/tests.rs index f2673dc58f..37e7df6f4b 100644 --- a/crates/hir-ty/src/consteval/tests.rs +++ b/crates/hir-ty/src/consteval/tests.rs @@ -101,10 +101,7 @@ fn check_answer( fn pretty_print_err(e: ConstEvalError, db: TestDB) -> String { let mut err = String::new(); let span_formatter = |file, range| format!("{file:?} {range:?}"); - let display_target = DisplayTarget::from_crate( - &db, - *db.crate_graph().crates_in_topological_order().last().unwrap(), - ); + let display_target = DisplayTarget::from_crate(&db, *db.all_crates().last().unwrap()); match e { ConstEvalError::MirLowerError(e) => { e.pretty_print(&mut err, &db, span_formatter, display_target) diff --git a/crates/hir-ty/src/db.rs b/crates/hir-ty/src/db.rs index 5817ed2ef2..8f48cfc432 100644 --- a/crates/hir-ty/src/db.rs +++ b/crates/hir-ty/src/db.rs @@ -3,7 +3,7 @@ use std::sync; -use base_db::{impl_intern_key, CrateId, Upcast}; +use base_db::{impl_intern_key, Crate, Upcast}; use hir_def::{ db::DefDatabase, hir::ExprId, layout::TargetDataLayout, AdtId, BlockId, CallableDefId, ConstParamId, DefWithBodyId, EnumVariantId, FunctionId, GeneralConstId, GenericDefId, ImplId, @@ -103,8 +103,8 @@ pub trait HirDatabase: DefDatabase + Upcast + std::fmt::Debug { #[salsa::cycle(crate::layout::layout_of_ty_recover)] fn layout_of_ty(&self, ty: Ty, env: Arc) -> Result, LayoutError>; - #[salsa::invoke(crate::layout::target_data_layout_query)] - fn target_data_layout(&self, krate: CrateId) -> Result, Arc>; + #[salsa::invoke_actual(crate::layout::target_data_layout_query)] + fn target_data_layout(&self, krate: Crate) -> Result, Arc>; #[salsa::invoke_actual(crate::dyn_compatibility::dyn_compatibility_of_trait_query)] fn dyn_compatibility_of_trait(&self, trait_: TraitId) -> Option; @@ -196,8 +196,8 @@ pub trait HirDatabase: DefDatabase + Upcast + std::fmt::Debug { #[salsa::invoke_actual(crate::lower::generic_defaults_query)] fn generic_defaults(&self, def: GenericDefId) -> GenericDefaults; - #[salsa::invoke(InherentImpls::inherent_impls_in_crate_query)] - fn inherent_impls_in_crate(&self, krate: CrateId) -> Arc; + #[salsa::invoke_actual(InherentImpls::inherent_impls_in_crate_query)] + fn inherent_impls_in_crate(&self, krate: Crate) -> Arc; #[salsa::invoke_actual(InherentImpls::inherent_impls_in_block_query)] fn inherent_impls_in_block(&self, block: BlockId) -> Option>; @@ -209,18 +209,18 @@ pub trait HirDatabase: DefDatabase + Upcast + std::fmt::Debug { #[salsa::invoke(crate::method_resolution::incoherent_inherent_impl_crates)] fn incoherent_inherent_impl_crates( &self, - krate: CrateId, + krate: Crate, fp: TyFingerprint, - ) -> SmallVec<[CrateId; 2]>; + ) -> SmallVec<[Crate; 2]>; - #[salsa::invoke(TraitImpls::trait_impls_in_crate_query)] - fn trait_impls_in_crate(&self, krate: CrateId) -> Arc; + #[salsa::invoke_actual(TraitImpls::trait_impls_in_crate_query)] + fn trait_impls_in_crate(&self, krate: Crate) -> Arc; #[salsa::invoke_actual(TraitImpls::trait_impls_in_block_query)] fn trait_impls_in_block(&self, block: BlockId) -> Option>; - #[salsa::invoke(TraitImpls::trait_impls_in_deps_query)] - fn trait_impls_in_deps(&self, krate: CrateId) -> Arc<[Arc]>; + #[salsa::invoke_actual(TraitImpls::trait_impls_in_deps_query)] + fn trait_impls_in_deps(&self, krate: Crate) -> Arc<[Arc]>; // Interned IDs for Chalk integration #[salsa::interned] @@ -253,23 +253,16 @@ pub trait HirDatabase: DefDatabase + Upcast + std::fmt::Debug { #[salsa::invoke(chalk_db::trait_datum_query)] fn trait_datum( &self, - krate: CrateId, + krate: Crate, trait_id: chalk_db::TraitId, ) -> sync::Arc; #[salsa::invoke(chalk_db::adt_datum_query)] - fn adt_datum( - &self, - krate: CrateId, - struct_id: chalk_db::AdtId, - ) -> sync::Arc; + fn adt_datum(&self, krate: Crate, struct_id: chalk_db::AdtId) -> sync::Arc; #[salsa::invoke(chalk_db::impl_datum_query)] - fn impl_datum( - &self, - krate: CrateId, - impl_id: chalk_db::ImplId, - ) -> sync::Arc; + fn impl_datum(&self, krate: Crate, impl_id: chalk_db::ImplId) + -> sync::Arc; #[salsa::invoke(chalk_db::fn_def_datum_query)] fn fn_def_datum(&self, fn_def_id: FnDefId) -> sync::Arc; @@ -287,7 +280,7 @@ pub trait HirDatabase: DefDatabase + Upcast + std::fmt::Debug { #[salsa::invoke(chalk_db::associated_ty_value_query)] fn associated_ty_value( &self, - krate: CrateId, + krate: Crate, id: chalk_db::AssociatedTyValueId, ) -> sync::Arc; @@ -302,7 +295,7 @@ pub trait HirDatabase: DefDatabase + Upcast + std::fmt::Debug { #[salsa::invoke(crate::traits::trait_solve_query)] fn trait_solve( &self, - krate: CrateId, + krate: Crate, block: Option, goal: crate::Canonical>, ) -> Option; @@ -310,7 +303,7 @@ pub trait HirDatabase: DefDatabase + Upcast + std::fmt::Debug { #[salsa::invoke(chalk_db::program_clauses_for_chalk_env_query)] fn program_clauses_for_chalk_env( &self, - krate: CrateId, + krate: Crate, block: Option, env: chalk_ir::Environment, ) -> chalk_ir::ProgramClauses; diff --git a/crates/hir-ty/src/diagnostics/decl_check.rs b/crates/hir-ty/src/diagnostics/decl_check.rs index eed74e1eee..a0b1fe32ce 100644 --- a/crates/hir-ty/src/diagnostics/decl_check.rs +++ b/crates/hir-ty/src/diagnostics/decl_check.rs @@ -288,7 +288,7 @@ impl<'a> DeclValidator<'a> { fn edition(&self, id: impl HasModule) -> span::Edition { let krate = id.krate(self.db.upcast()); - self.db.crate_graph()[krate].edition + krate.data(self.db).edition } fn validate_struct(&mut self, struct_id: StructId) { diff --git a/crates/hir-ty/src/diagnostics/expr.rs b/crates/hir-ty/src/diagnostics/expr.rs index 975143b29f..053d1cd41e 100644 --- a/crates/hir-ty/src/diagnostics/expr.rs +++ b/crates/hir-ty/src/diagnostics/expr.rs @@ -4,7 +4,7 @@ use std::fmt; -use base_db::CrateId; +use base_db::Crate; use chalk_solve::rust_ir::AdtKind; use either::Either; use hir_def::{ @@ -630,7 +630,7 @@ fn missing_match_arms<'p>( scrut_ty: &Ty, witnesses: Vec>, arms_is_empty: bool, - krate: CrateId, + krate: Crate, ) -> String { struct DisplayWitness<'a, 'p>(&'a WitnessPat<'p>, &'a MatchCheckCtx<'p>, DisplayTarget); impl fmt::Display for DisplayWitness<'_, '_> { diff --git a/crates/hir-ty/src/diagnostics/unsafe_check.rs b/crates/hir-ty/src/diagnostics/unsafe_check.rs index d2b908839c..84dd4be67f 100644 --- a/crates/hir-ty/src/diagnostics/unsafe_check.rs +++ b/crates/hir-ty/src/diagnostics/unsafe_check.rs @@ -160,7 +160,7 @@ impl<'a> UnsafeVisitor<'a> { DefWithBodyId::FunctionId(func) => TargetFeatures::from_attrs(&db.attrs(func.into())), _ => TargetFeatures::default(), }; - let edition = db.crate_graph()[resolver.module().krate()].edition; + let edition = resolver.module().krate().data(db).edition; Self { db, infer, diff --git a/crates/hir-ty/src/display.rs b/crates/hir-ty/src/display.rs index 95ce36390d..2ae7e746ba 100644 --- a/crates/hir-ty/src/display.rs +++ b/crates/hir-ty/src/display.rs @@ -7,7 +7,7 @@ use std::{ mem, }; -use base_db::CrateId; +use base_db::Crate; use chalk_ir::{BoundVar, Safety, TyKind}; use either::Either; use hir_def::{ @@ -339,7 +339,7 @@ pub trait HirDisplay { } impl HirFormatter<'_> { - pub fn krate(&self) -> CrateId { + pub fn krate(&self) -> Crate { self.display_target.krate } @@ -408,13 +408,13 @@ impl HirFormatter<'_> { #[derive(Debug, Clone, Copy)] pub struct DisplayTarget { - krate: CrateId, + krate: Crate, pub edition: Edition, } impl DisplayTarget { - pub fn from_crate(db: &dyn HirDatabase, krate: CrateId) -> Self { - let edition = db.crate_graph()[krate].edition; + pub fn from_crate(db: &dyn HirDatabase, krate: Crate) -> Self { + let edition = krate.data(db).edition; Self { krate, edition } } } @@ -1711,7 +1711,7 @@ fn fn_traits(db: &dyn DefDatabase, trait_: TraitId) -> impl Iterator String { let body = db.body(owner); let krate = owner.krate(db.upcast()); - let edition = db.crate_graph()[krate].edition; + let edition = krate.data(db).edition; let mut result = body[self.place.local].name.display(db.upcast(), edition).to_string(); for proj in &self.place.projections { match proj { @@ -368,7 +368,7 @@ impl CapturedItem { pub fn display_place(&self, owner: DefWithBodyId, db: &dyn HirDatabase) -> String { let body = db.body(owner); let krate = owner.krate(db.upcast()); - let edition = db.crate_graph()[krate].edition; + let edition = krate.data(db).edition; let mut result = body[self.place.local].name.display(db.upcast(), edition).to_string(); let mut field_need_paren = false; for proj in &self.place.projections { diff --git a/crates/hir-ty/src/layout/target.rs b/crates/hir-ty/src/layout/target.rs index 7d77f6d073..e1e1c44996 100644 --- a/crates/hir-ty/src/layout/target.rs +++ b/crates/hir-ty/src/layout/target.rs @@ -1,6 +1,6 @@ //! Target dependent parameters needed for layouts -use base_db::CrateId; +use base_db::Crate; use hir_def::layout::TargetDataLayout; use rustc_abi::{AlignFromBytesError, TargetDataLayoutErrors}; use triomphe::Arc; @@ -9,9 +9,9 @@ use crate::db::HirDatabase; pub fn target_data_layout_query( db: &dyn HirDatabase, - krate: CrateId, + krate: Crate, ) -> Result, Arc> { - match &db.crate_workspace_data()[&krate].data_layout { + match &krate.workspace_data(db).data_layout { Ok(it) => match TargetDataLayout::parse_from_llvm_datalayout_string(it) { Ok(it) => Ok(Arc::new(it)), Err(e) => { diff --git a/crates/hir-ty/src/lower.rs b/crates/hir-ty/src/lower.rs index ff7f034963..29ab0251f8 100644 --- a/crates/hir-ty/src/lower.rs +++ b/crates/hir-ty/src/lower.rs @@ -14,7 +14,7 @@ use std::{ ops::{self, Not as _}, }; -use base_db::CrateId; +use base_db::Crate; use chalk_ir::{ cast::Cast, fold::{Shift, TypeFoldable}, @@ -801,7 +801,7 @@ impl<'a> TyLoweringContext<'a> { } } - fn lower_impl_trait(&mut self, bounds: &[TypeBound], krate: CrateId) -> ImplTrait { + fn lower_impl_trait(&mut self, bounds: &[TypeBound], krate: Crate) -> ImplTrait { cov_mark::hit!(lower_rpit); let self_ty = TyKind::BoundVar(BoundVar::new(DebruijnIndex::INNERMOST, 0)).intern(Interner); let predicates = self.with_shifted_in(DebruijnIndex::ONE, |ctx| { @@ -1863,8 +1863,11 @@ pub(crate) fn const_or_path_to_chalk<'g>( .unwrap_or_else(|| unknown_const(expected_ty)) } &ConstRef::Complex(it) => { - let crate_data = &db.crate_graph()[resolver.krate()]; - if crate_data.env.get("__ra_is_test_fixture").is_none() && crate_data.origin.is_local() + let krate = resolver.krate(); + // Keep the `&&` this way, because it's better to access the crate data, as we access it for + // a bunch of other things nevertheless. + if krate.data(db).origin.is_local() + && krate.env(db).get("__ra_is_test_fixture").is_none() { // FIXME: current `InTypeConstId` is very unstable, so we only use it in non local crate // that are unlikely to be edited. diff --git a/crates/hir-ty/src/method_resolution.rs b/crates/hir-ty/src/method_resolution.rs index c5ad808acc..50b0fce62f 100644 --- a/crates/hir-ty/src/method_resolution.rs +++ b/crates/hir-ty/src/method_resolution.rs @@ -5,7 +5,7 @@ use std::ops::ControlFlow; use arrayvec::ArrayVec; -use base_db::CrateId; +use base_db::Crate; use chalk_ir::{cast::Cast, UniverseIndex, WithKind}; use hir_def::{ data::{adt::StructFlags, ImplData, TraitFlags}, @@ -148,7 +148,7 @@ pub struct TraitImpls { } impl TraitImpls { - pub(crate) fn trait_impls_in_crate_query(db: &dyn HirDatabase, krate: CrateId) -> Arc { + pub(crate) fn trait_impls_in_crate_query(db: &dyn HirDatabase, krate: Crate) -> Arc { let _p = tracing::info_span!("trait_impls_in_crate_query", ?krate).entered(); let mut impls = FxHashMap::default(); @@ -175,13 +175,11 @@ impl TraitImpls { pub(crate) fn trait_impls_in_deps_query( db: &dyn HirDatabase, - krate: CrateId, + krate: Crate, ) -> Arc<[Arc]> { let _p = tracing::info_span!("trait_impls_in_deps_query", ?krate).entered(); - let crate_graph = db.crate_graph(); - Arc::from_iter( - crate_graph.transitive_deps(krate).map(|krate| db.trait_impls_in_crate(krate)), + db.transitive_deps(krate).into_iter().map(|krate| db.trait_impls_in_crate(krate)), ) } @@ -282,7 +280,7 @@ pub struct InherentImpls { } impl InherentImpls { - pub(crate) fn inherent_impls_in_crate_query(db: &dyn HirDatabase, krate: CrateId) -> Arc { + pub(crate) fn inherent_impls_in_crate_query(db: &dyn HirDatabase, krate: Crate) -> Arc { let _p = tracing::info_span!("inherent_impls_in_crate_query", ?krate).entered(); let mut impls = Self { map: FxHashMap::default(), invalid_impls: Vec::default() }; @@ -367,16 +365,15 @@ impl InherentImpls { pub(crate) fn incoherent_inherent_impl_crates( db: &dyn HirDatabase, - krate: CrateId, + krate: Crate, fp: TyFingerprint, -) -> SmallVec<[CrateId; 2]> { +) -> SmallVec<[Crate; 2]> { let _p = tracing::info_span!("incoherent_inherent_impl_crates").entered(); let mut res = SmallVec::new(); - let crate_graph = db.crate_graph(); // should pass crate for finger print and do reverse deps - for krate in crate_graph.transitive_deps(krate) { + for krate in db.transitive_deps(krate) { let impls = db.inherent_impls_in_crate(krate); if impls.map.get(&fp).is_some_and(|v| !v.is_empty()) { res.push(krate); @@ -386,11 +383,7 @@ pub(crate) fn incoherent_inherent_impl_crates( res } -pub fn def_crates( - db: &dyn HirDatabase, - ty: &Ty, - cur_crate: CrateId, -) -> Option> { +pub fn def_crates(db: &dyn HirDatabase, ty: &Ty, cur_crate: Crate) -> Option> { match ty.kind(Interner) { &TyKind::Adt(AdtId(def_id), _) => { let rustc_has_incoherent_inherent_impls = match def_id { @@ -1226,7 +1219,7 @@ fn iterate_trait_method_candidates( { // FIXME: this should really be using the edition of the method name's span, in case it // comes from a macro - if !db.crate_graph()[krate].edition.at_least_2021() { + if !krate.data(db).edition.at_least_2021() { continue; } } @@ -1239,7 +1232,7 @@ fn iterate_trait_method_candidates( { // FIXME: this should really be using the edition of the method name's span, in case it // comes from a macro - if !db.crate_graph()[krate].edition.at_least_2024() { + if !krate.data(db).edition.at_least_2024() { continue; } } diff --git a/crates/hir-ty/src/mir.rs b/crates/hir-ty/src/mir.rs index ae454fbe52..7faa23f818 100644 --- a/crates/hir-ty/src/mir.rs +++ b/crates/hir-ty/src/mir.rs @@ -12,7 +12,7 @@ use crate::{ CallableDefId, ClosureId, Const, ConstScalar, InferenceResult, Interner, MemoryMap, Substitution, TraitEnvironment, Ty, TyExt, TyKind, }; -use base_db::CrateId; +use base_db::Crate; use chalk_ir::Mutability; use either::Either; use hir_def::{ @@ -143,7 +143,7 @@ impl ProjectionElem { mut base: Ty, db: &dyn HirDatabase, closure_field: impl FnOnce(ClosureId, &Substitution, usize) -> Ty, - krate: CrateId, + krate: Crate, ) -> Ty { // we only bail on mir building when there are type mismatches // but error types may pop up resulting in us still attempting to build the mir diff --git a/crates/hir-ty/src/mir/eval.rs b/crates/hir-ty/src/mir/eval.rs index c9d62f566c..597e6a3ef0 100644 --- a/crates/hir-ty/src/mir/eval.rs +++ b/crates/hir-ty/src/mir/eval.rs @@ -2,7 +2,7 @@ use std::{borrow::Cow, cell::RefCell, fmt::Write, iter, mem, ops::Range}; -use base_db::CrateId; +use base_db::Crate; use chalk_ir::{cast::Cast, Mutability}; use either::Either; use hir_def::{ @@ -186,7 +186,7 @@ pub struct Evaluator<'a> { cached_fn_trait_func: Option, cached_fn_mut_trait_func: Option, cached_fn_once_trait_func: Option, - crate_id: CrateId, + crate_id: Crate, // FIXME: This is a workaround, see the comment on `interpret_mir` assert_placeholder_ty_is_unused: bool, /// A general limit on execution, to prevent non terminating programs from breaking r-a main process @@ -2785,7 +2785,7 @@ impl Evaluator<'_> { let db = self.db.upcast(); let loc = variant.lookup(db); let enum_loc = loc.parent.lookup(db); - let edition = self.db.crate_graph()[self.crate_id].edition; + let edition = self.crate_id.data(self.db).edition; let name = format!( "{}::{}", enum_loc.id.item_tree(db)[enum_loc.id.value].name.display(db.upcast(), edition), diff --git a/crates/hir-ty/src/mir/eval/shim.rs b/crates/hir-ty/src/mir/eval/shim.rs index f61ecabb7e..346dea8252 100644 --- a/crates/hir-ty/src/mir/eval/shim.rs +++ b/crates/hir-ty/src/mir/eval/shim.rs @@ -569,7 +569,7 @@ impl Evaluator<'_> { } String::from_utf8_lossy(&name_buf) }; - let value = self.db.crate_graph()[self.crate_id].env.get(&name); + let value = self.crate_id.env(self.db).get(&name); match value { None => { // Write null as fail diff --git a/crates/hir-ty/src/mir/lower.rs b/crates/hir-ty/src/mir/lower.rs index 17f1da0c9f..57d4baa137 100644 --- a/crates/hir-ty/src/mir/lower.rs +++ b/crates/hir-ty/src/mir/lower.rs @@ -2,7 +2,7 @@ use std::{fmt::Write, iter, mem}; -use base_db::{salsa::Cycle, CrateId}; +use base_db::{salsa::Cycle, Crate}; use chalk_ir::{BoundVar, ConstData, DebruijnIndex, TyKind}; use hir_def::{ data::adt::{StructKind, VariantData}, @@ -1920,10 +1920,10 @@ impl<'ctx> MirLowerCtx<'ctx> { } fn edition(&self) -> Edition { - self.db.crate_graph()[self.krate()].edition + self.krate().data(self.db).edition } - fn krate(&self) -> CrateId { + fn krate(&self) -> Crate { self.owner.krate(self.db.upcast()) } @@ -2121,7 +2121,7 @@ pub fn mir_body_for_closure_query( pub fn mir_body_query(db: &dyn HirDatabase, def: DefWithBodyId) -> Result> { let krate = def.krate(db.upcast()); - let edition = db.crate_graph()[krate].edition; + let edition = krate.data(db).edition; let detail = match def { DefWithBodyId::FunctionId(it) => { db.function_data(it).name.display(db.upcast(), edition).to_string() diff --git a/crates/hir-ty/src/test_db.rs b/crates/hir-ty/src/test_db.rs index b18a057ba0..68d0c8cd5a 100644 --- a/crates/hir-ty/src/test_db.rs +++ b/crates/hir-ty/src/test_db.rs @@ -3,8 +3,8 @@ use std::{fmt, panic, sync::Mutex}; use base_db::{ - FileSourceRootInput, FileText, RootQueryDb, SourceDatabase, SourceRoot, SourceRootId, - SourceRootInput, Upcast, + CrateGraphBuilder, CratesMap, FileSourceRootInput, FileText, RootQueryDb, SourceDatabase, + SourceRoot, SourceRootId, SourceRootInput, Upcast, }; use hir_def::{db::DefDatabase, ModuleId}; @@ -21,6 +21,7 @@ use triomphe::Arc; pub(crate) struct TestDB { storage: salsa::Storage, files: Arc, + crates_map: Arc, events: Arc>>>, } @@ -30,8 +31,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 } } @@ -115,6 +120,10 @@ 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 { + self.crates_map.clone() + } } #[salsa::db] @@ -151,8 +160,7 @@ impl TestDB { &self, ) -> FxHashMap> { let mut files = Vec::new(); - let crate_graph = self.crate_graph(); - for krate in crate_graph.iter() { + for &krate in self.all_crates().iter() { let crate_def_map = self.crate_def_map(krate); for (module_id, _) in crate_def_map.modules() { let file_id = crate_def_map[module_id].origin.file_id(); diff --git a/crates/hir-ty/src/tests.rs b/crates/hir-ty/src/tests.rs index 2622904058..cdb9e9edf8 100644 --- a/crates/hir-ty/src/tests.rs +++ b/crates/hir-ty/src/tests.rs @@ -15,7 +15,7 @@ mod type_alias_impl_traits; use std::env; use std::sync::LazyLock; -use base_db::{CrateId, SourceDatabase}; +use base_db::{Crate, SourceDatabase}; use expect_test::Expect; use hir_def::{ db::DefDatabase, @@ -124,7 +124,7 @@ fn check_impl( } assert!(had_annotations || allow_none, "no `//^` annotations found"); - let mut defs: Vec<(DefWithBodyId, CrateId)> = Vec::new(); + let mut defs: Vec<(DefWithBodyId, Crate)> = Vec::new(); for file_id in files { let module = db.module_for_file_opt(file_id); let module = match module { @@ -302,7 +302,7 @@ fn infer_with_mismatches(content: &str, include_mismatches: bool) -> String { let mut infer_def = |inference_result: Arc, body: Arc, body_source_map: Arc, - krate: CrateId| { + krate: Crate| { let display_target = DisplayTarget::from_crate(&db, krate); let mut types: Vec<(InFile, &Ty)> = Vec::new(); let mut mismatches: Vec<(InFile, &TypeMismatch)> = Vec::new(); @@ -391,7 +391,7 @@ fn infer_with_mismatches(content: &str, include_mismatches: bool) -> String { let module = db.module_for_file(file_id); let def_map = module.def_map(&db); - let mut defs: Vec<(DefWithBodyId, CrateId)> = Vec::new(); + let mut defs: Vec<(DefWithBodyId, Crate)> = Vec::new(); visit_module(&db, &def_map, module.local_id, &mut |it| { let def = match it { ModuleDefId::FunctionId(it) => it.into(), diff --git a/crates/hir-ty/src/traits.rs b/crates/hir-ty/src/traits.rs index 0135e0a409..f8db6a8298 100644 --- a/crates/hir-ty/src/traits.rs +++ b/crates/hir-ty/src/traits.rs @@ -7,7 +7,7 @@ use chalk_ir::{fold::TypeFoldable, DebruijnIndex, GoalData}; use chalk_recursive::Cache; use chalk_solve::{logging_db::LoggingRustIrDatabase, rust_ir, Solver}; -use base_db::CrateId; +use base_db::Crate; use hir_def::{ lang_item::{LangItem, LangItemTarget}, BlockId, TraitId, @@ -30,7 +30,7 @@ const CHALK_SOLVER_FUEL: i32 = 1000; #[derive(Debug, Copy, Clone)] pub(crate) struct ChalkContext<'a> { pub(crate) db: &'a dyn HirDatabase, - pub(crate) krate: CrateId, + pub(crate) krate: Crate, pub(crate) block: Option, } @@ -48,7 +48,7 @@ fn create_chalk_solver() -> chalk_recursive::RecursiveSolver { /// we assume that `T: Default`. #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct TraitEnvironment { - pub krate: CrateId, + pub krate: Crate, pub block: Option, // FIXME make this a BTreeMap traits_from_clauses: Box<[(Ty, TraitId)]>, @@ -56,7 +56,7 @@ pub struct TraitEnvironment { } impl TraitEnvironment { - pub fn empty(krate: CrateId) -> Arc { + pub fn empty(krate: Crate) -> Arc { Arc::new(TraitEnvironment { krate, block: None, @@ -66,7 +66,7 @@ impl TraitEnvironment { } pub fn new( - krate: CrateId, + krate: Crate, block: Option, traits_from_clauses: Box<[(Ty, TraitId)]>, env: chalk_ir::Environment, @@ -109,7 +109,7 @@ pub(crate) fn normalize_projection_query( /// Solve a trait goal using Chalk. pub(crate) fn trait_solve_query( db: &dyn HirDatabase, - krate: CrateId, + krate: Crate, block: Option, goal: Canonical>, ) -> Option { @@ -148,7 +148,7 @@ pub(crate) fn trait_solve_query( fn solve( db: &dyn HirDatabase, - krate: CrateId, + krate: Crate, block: Option, goal: &chalk_ir::UCanonical>>, ) -> Option> { @@ -294,7 +294,7 @@ impl FnTrait { } } - pub fn get_id(self, db: &dyn HirDatabase, krate: CrateId) -> Option { + pub fn get_id(self, db: &dyn HirDatabase, krate: Crate) -> Option { let target = db.lang_item(krate, self.lang_item())?; match target { LangItemTarget::Trait(t) => Some(t), diff --git a/crates/hir-ty/src/utils.rs b/crates/hir-ty/src/utils.rs index 89d89fe223..b90f4e4d7f 100644 --- a/crates/hir-ty/src/utils.rs +++ b/crates/hir-ty/src/utils.rs @@ -3,7 +3,7 @@ use std::{hash::Hash, iter}; -use base_db::CrateId; +use base_db::Crate; use chalk_ir::{ fold::{FallibleTypeFolder, Shift}, DebruijnIndex, @@ -34,10 +34,7 @@ use crate::{ TraitRefExt, Ty, WhereClause, }; -pub(crate) fn fn_traits( - db: &dyn DefDatabase, - krate: CrateId, -) -> impl Iterator + '_ { +pub(crate) fn fn_traits(db: &dyn DefDatabase, krate: Crate) -> impl Iterator + '_ { [LangItem::Fn, LangItem::FnMut, LangItem::FnOnce] .into_iter() .filter_map(move |lang| db.lang_item(krate, lang)) diff --git a/crates/hir/src/from_id.rs b/crates/hir/src/from_id.rs index 72df07ef8c..891d2fd2ba 100644 --- a/crates/hir/src/from_id.rs +++ b/crates/hir/src/from_id.rs @@ -30,7 +30,7 @@ macro_rules! from_id { } from_id![ - (base_db::CrateId, crate::Crate), + (base_db::Crate, crate::Crate), (hir_def::ModuleId, crate::Module), (hir_def::StructId, crate::Struct), (hir_def::UnionId, crate::Union), diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs index dbe743e7e2..5da2b5ed09 100644 --- a/crates/hir/src/lib.rs +++ b/crates/hir/src/lib.rs @@ -39,7 +39,7 @@ use std::{ }; use arrayvec::ArrayVec; -use base_db::{CrateDisplayName, CrateId, CrateOrigin, LangCrateOrigin}; +use base_db::{CrateDisplayName, CrateOrigin, LangCrateOrigin}; use either::Either; use hir_def::{ data::{adt::VariantData, TraitFlags}, @@ -176,7 +176,7 @@ use { /// root module. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub struct Crate { - pub(crate) id: CrateId, + pub(crate) id: base_db::Crate, } #[derive(Debug)] @@ -187,7 +187,7 @@ pub struct CrateDependency { impl Crate { pub fn origin(self, db: &dyn HirDatabase) -> CrateOrigin { - db.crate_graph()[self.id].origin.clone() + self.id.data(db).origin.clone() } pub fn is_builtin(self, db: &dyn HirDatabase) -> bool { @@ -195,7 +195,8 @@ impl Crate { } pub fn dependencies(self, db: &dyn HirDatabase) -> Vec { - db.crate_graph()[self.id] + self.id + .data(db) .dependencies .iter() .map(|dep| { @@ -207,12 +208,11 @@ impl Crate { } pub fn reverse_dependencies(self, db: &dyn HirDatabase) -> Vec { - let crate_graph = db.crate_graph(); - crate_graph + let all_crates = db.all_crates(); + all_crates .iter() - .filter(|&krate| { - crate_graph[krate].dependencies.iter().any(|it| it.crate_id == self.id) - }) + .copied() + .filter(|&krate| krate.data(db).dependencies.iter().any(|it| it.crate_id == self.id)) .map(|id| Crate { id }) .collect() } @@ -221,7 +221,7 @@ impl Crate { self, db: &dyn HirDatabase, ) -> impl Iterator { - db.crate_graph().transitive_rev_deps(self.id).map(|id| Crate { id }) + db.transitive_rev_deps(self.id).into_iter().map(|id| Crate { id }) } pub fn root_module(self) -> Module { @@ -234,19 +234,19 @@ impl Crate { } pub fn root_file(self, db: &dyn HirDatabase) -> FileId { - db.crate_graph()[self.id].root_file_id + self.id.data(db).root_file_id } pub fn edition(self, db: &dyn HirDatabase) -> Edition { - db.crate_graph()[self.id].edition + self.id.data(db).edition } pub fn version(self, db: &dyn HirDatabase) -> Option { - db.crate_graph()[self.id].version.clone() + self.id.extra_data(db).version.clone() } pub fn display_name(self, db: &dyn HirDatabase) -> Option { - db.crate_graph()[self.id].display_name.clone() + self.id.extra_data(db).display_name.clone() } pub fn query_external_importables( @@ -264,7 +264,7 @@ impl Crate { } pub fn all(db: &dyn HirDatabase) -> Vec { - db.crate_graph().iter().map(|id| Crate { id }).collect() + db.all_crates().iter().map(|&id| Crate { id }).collect() } /// Try to get the root URL of the documentation of a crate. @@ -276,12 +276,12 @@ impl Crate { } pub fn cfg(&self, db: &dyn HirDatabase) -> Arc { - db.crate_graph()[self.id].cfg_options.clone() + Arc::clone(self.id.cfg_options(db)) } - pub fn potential_cfg(&self, db: &dyn HirDatabase) -> Arc { - let data = &db.crate_graph()[self.id]; - data.potential_cfg_options.clone().unwrap_or_else(|| data.cfg_options.clone()) + pub fn potential_cfg<'db>(&self, db: &'db dyn HirDatabase) -> &'db CfgOptions { + let data = self.id.extra_data(db); + data.potential_cfg_options.as_ref().unwrap_or_else(|| self.id.cfg_options(db)) } pub fn to_display_target(self, db: &dyn HirDatabase) -> DisplayTarget { @@ -289,11 +289,12 @@ impl Crate { } fn core(db: &dyn HirDatabase) -> Option { - let crate_graph = db.crate_graph(); - let result = crate_graph + let result = db + .all_crates() .iter() + .copied() .find(|&krate| { - matches!(crate_graph[krate].origin, CrateOrigin::Lang(LangCrateOrigin::Core)) + matches!(krate.data(db).origin, CrateOrigin::Lang(LangCrateOrigin::Core)) }) .map(Crate::from); result @@ -490,9 +491,7 @@ impl HasCrate for ModuleDef { fn krate(&self, db: &dyn HirDatabase) -> Crate { match self.module(db) { Some(module) => module.krate(), - None => Crate::core(db).unwrap_or_else(|| { - (*db.crate_graph().crates_in_topological_order().last().unwrap()).into() - }), + None => Crate::core(db).unwrap_or_else(|| db.all_crates()[0].into()), } } } @@ -611,7 +610,7 @@ impl Module { style_lints: bool, ) { let _p = tracing::info_span!("diagnostics", name = ?self.name(db)).entered(); - let edition = db.crate_graph()[self.id.krate()].edition; + let edition = self.id.krate().data(db).edition; let def_map = self.id.def_map(db.upcast()); for diag in def_map.diagnostics() { if diag.in_module != self.id.local_id { @@ -970,7 +969,7 @@ fn emit_macro_def_diagnostics(db: &dyn HirDatabase, acc: &mut Vec return; }; let krate = HasModule::krate(&m.id, db.upcast()); - let edition = db.crate_graph()[krate].edition; + let edition = krate.data(db).edition; emit_def_diagnostic_( db, acc, @@ -3027,7 +3026,8 @@ impl BuiltinType { } pub fn ty(self, db: &dyn HirDatabase) -> Type { - Type::new_for_crate(db.crate_graph().iter().next().unwrap(), TyBuilder::builtin(self.inner)) + let core = Crate::core(db).map(|core| core.id).unwrap_or_else(|| db.all_crates()[0]); + Type::new_for_crate(core, TyBuilder::builtin(self.inner)) } pub fn name(self) -> Name { @@ -3968,7 +3968,7 @@ impl DeriveHelper { // FIXME: Wrong name? This is could also be a registered attribute #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] pub struct BuiltinAttr { - krate: Option, + krate: Option, idx: u32, } @@ -4014,7 +4014,7 @@ impl BuiltinAttr { #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] pub struct ToolModule { - krate: CrateId, + krate: base_db::Crate, idx: u32, } @@ -4732,7 +4732,7 @@ impl Type { Type { env: environment, ty } } - pub(crate) fn new_for_crate(krate: CrateId, ty: Ty) -> Type { + pub(crate) fn new_for_crate(krate: base_db::Crate, ty: Ty) -> Type { Type { env: TraitEnvironment::empty(krate), ty } } @@ -4794,7 +4794,7 @@ impl Type { Type { env: ty.env, ty: TyBuilder::slice(ty.ty) } } - pub fn new_tuple(krate: CrateId, tys: &[Type]) -> Type { + pub fn new_tuple(krate: base_db::Crate, tys: &[Type]) -> Type { let tys = tys.iter().map(|it| it.ty.clone()); Type { env: TraitEnvironment::empty(krate), ty: TyBuilder::tuple_with(tys) } } @@ -4826,7 +4826,7 @@ impl Type { pub fn contains_reference(&self, db: &dyn HirDatabase) -> bool { return go(db, self.env.krate, &self.ty); - fn go(db: &dyn HirDatabase, krate: CrateId, ty: &Ty) -> bool { + fn go(db: &dyn HirDatabase, krate: base_db::Crate, ty: &Ty) -> bool { match ty.kind(Interner) { // Reference itself TyKind::Ref(_, _, _) => true, @@ -6209,7 +6209,7 @@ impl HasContainer for Module { let def_map = self.id.def_map(db.upcast()); match def_map[self.id.local_id].parent { Some(parent_id) => ItemContainer::Module(Module { id: def_map.module_id(parent_id) }), - None => ItemContainer::Crate(def_map.krate()), + None => ItemContainer::Crate(def_map.krate().into()), } } } @@ -6289,7 +6289,7 @@ pub enum ItemContainer { Impl(Impl), Module(Module), ExternBlock(ExternBlock), - Crate(CrateId), + Crate(Crate), } /// Subset of `ide_db::Definition` that doc links can resolve to. diff --git a/crates/hir/src/semantics.rs b/crates/hir/src/semantics.rs index aeeb3f9790..6378eebd24 100644 --- a/crates/hir/src/semantics.rs +++ b/crates/hir/src/semantics.rs @@ -318,7 +318,7 @@ impl<'db> SemanticsImpl<'db> { pub fn first_crate_or_default(&self, file: FileId) -> Crate { match self.file_to_module_defs(file).next() { Some(module) => module.krate(), - None => (*self.db.crate_graph().crates_in_topological_order().last().unwrap()).into(), + None => (*self.db.all_crates().last().unwrap()).into(), } } diff --git a/crates/hir/src/symbols.rs b/crates/hir/src/symbols.rs index fa8153ad21..cc8aa1f1a1 100644 --- a/crates/hir/src/symbols.rs +++ b/crates/hir/src/symbols.rs @@ -77,10 +77,7 @@ impl<'a> SymbolCollector<'a> { symbols: Default::default(), work: Default::default(), current_container_name: None, - display_target: DisplayTarget::from_crate( - db, - *db.crate_graph().crates_in_topological_order().last().unwrap(), - ), + display_target: DisplayTarget::from_crate(db, *db.all_crates().last().unwrap()), } } diff --git a/crates/ide-assists/src/handlers/inline_call.rs b/crates/ide-assists/src/handlers/inline_call.rs index 9e09f198fe..5a791c58bf 100644 --- a/crates/ide-assists/src/handlers/inline_call.rs +++ b/crates/ide-assists/src/handlers/inline_call.rs @@ -7,7 +7,7 @@ use hir::{ sym, FileRange, PathResolution, Semantics, TypeInfo, }; use ide_db::{ - base_db::CrateId, + base_db::Crate, defs::Definition, imports::insert_use::remove_path_if_in_use_stmt, path_transform::PathTransform, @@ -251,11 +251,11 @@ struct CallInfo { node: ast::CallableExpr, arguments: Vec, generic_arg_list: Option, - krate: CrateId, + krate: Crate, } impl CallInfo { - fn from_name_ref(name_ref: ast::NameRef, krate: CrateId) -> Option { + fn from_name_ref(name_ref: ast::NameRef, krate: Crate) -> Option { let parent = name_ref.syntax().parent()?; if let Some(call) = ast::MethodCallExpr::cast(parent.clone()) { let receiver = call.receiver()?; diff --git a/crates/ide-db/src/apply_change.rs b/crates/ide-db/src/apply_change.rs index d8b2656782..4c8940db95 100644 --- a/crates/ide-db/src/apply_change.rs +++ b/crates/ide-db/src/apply_change.rs @@ -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 diff --git a/crates/ide-db/src/famous_defs.rs b/crates/ide-db/src/famous_defs.rs index af4c10f8ea..fe4662785a 100644 --- a/crates/ide-db/src/famous_defs.rs +++ b/crates/ide-db/src/famous_defs.rs @@ -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 { 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) } diff --git a/crates/ide-db/src/lib.rs b/crates/ide-db/src/lib.rs index 2516a9d0aa..414cc6cd18 100644 --- a/crates/ide-db/src/lib.rs +++ b/crates/ide-db/src/lib.rs @@ -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>, files: Arc, + crates_map: Arc, } 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 { + 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(), + } } } diff --git a/crates/ide-db/src/prime_caches.rs b/crates/ide-db/src/prime_caches.rs index 74d79cd695..cd3099fe93 100644 --- a/crates/ide-db/src/prime_caches.rs +++ b/crates/ide-db/src/prime_caches.rs @@ -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 diff --git a/crates/ide-db/src/search.rs b/crates/ide-db/src/search.rs index 81df0c0f0f..4f9ef05b20 100644 --- a/crates/ide-db/src/search.rs +++ b/crates/ide-db/src/search.rs @@ -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 } diff --git a/crates/ide-db/src/test_data/test_doc_alias.txt b/crates/ide-db/src/test_data/test_doc_alias.txt index 0cae7f367c..1e2d4f1ab9 100644 --- a/crates/ide-db/src/test_data/test_doc_alias.txt +++ b/crates/ide-db/src/test_data/test_doc_alias.txt @@ -2,7 +2,9 @@ ( Module { id: ModuleId { - krate: Idx::(0), + krate: Crate { + [salsa id]: Id(2c00), + }, block: None, local_id: Idx::(0), }, diff --git a/crates/ide-db/src/test_data/test_symbol_index_collection.txt b/crates/ide-db/src/test_data/test_symbol_index_collection.txt index 48de1fb837..1a77052b18 100644 --- a/crates/ide-db/src/test_data/test_symbol_index_collection.txt +++ b/crates/ide-db/src/test_data/test_symbol_index_collection.txt @@ -2,7 +2,9 @@ ( Module { id: ModuleId { - krate: Idx::(0), + krate: Crate { + [salsa id]: Id(2c00), + }, block: None, local_id: Idx::(0), }, @@ -532,7 +534,9 @@ def: Module( Module { id: ModuleId { - krate: Idx::(0), + krate: Crate { + [salsa id]: Id(2c00), + }, block: None, local_id: Idx::(1), }, @@ -565,7 +569,9 @@ def: Module( Module { id: ModuleId { - krate: Idx::(0), + krate: Crate { + [salsa id]: Id(2c00), + }, block: None, local_id: Idx::(2), }, @@ -827,7 +833,9 @@ ( Module { id: ModuleId { - krate: Idx::(0), + krate: Crate { + [salsa id]: Id(2c00), + }, block: None, local_id: Idx::(1), }, @@ -871,7 +879,9 @@ ( Module { id: ModuleId { - krate: Idx::(0), + krate: Crate { + [salsa id]: Id(2c00), + }, block: None, local_id: Idx::(2), }, diff --git a/crates/ide-diagnostics/src/lib.rs b/crates/ide-diagnostics/src/lib.rs index 5ce3336eb4..f4ced736b3 100644 --- a/crates/ide-diagnostics/src/lib.rs +++ b/crates/ide-diagnostics/src/lib.rs @@ -389,9 +389,9 @@ pub fn semantic_diagnostics( module.and_then(|m| db.toolchain_channel(m.krate().into())), Some(ReleaseChannel::Nightly) | None ); - let krate = module.map(|module| module.krate()).unwrap_or_else(|| { - (*db.crate_graph().crates_in_topological_order().last().unwrap()).into() - }); + let krate = module + .map(|module| module.krate()) + .unwrap_or_else(|| (*db.all_crates().last().unwrap()).into()); let display_target = krate.to_display_target(db); let ctx = DiagnosticsContext { config, sema, resolve, edition, is_nightly, display_target }; diff --git a/crates/ide-ssr/src/matching.rs b/crates/ide-ssr/src/matching.rs index d32ba06f1e..48d2431a11 100644 --- a/crates/ide-ssr/src/matching.rs +++ b/crates/ide-ssr/src/matching.rs @@ -626,11 +626,11 @@ impl<'db, 'sema> Matcher<'db, 'sema> { match_error!("Failed to get receiver type for `{}`", expr.syntax().text()) })? .original; - let krate = self.sema.scope(expr.syntax()).map(|it| it.krate()).unwrap_or_else(|| { - hir::Crate::from( - *self.sema.db.crate_graph().crates_in_topological_order().last().unwrap(), - ) - }); + let krate = self + .sema + .scope(expr.syntax()) + .map(|it| it.krate()) + .unwrap_or_else(|| hir::Crate::from(*self.sema.db.all_crates().last().unwrap())); let res = code_type .autoderef(self.sema.db) .enumerate() diff --git a/crates/ide/src/doc_links.rs b/crates/ide/src/doc_links.rs index 0acb129e93..9bdc2e7d13 100644 --- a/crates/ide/src/doc_links.rs +++ b/crates/ide/src/doc_links.rs @@ -504,9 +504,7 @@ fn get_doc_base_urls( let Some(krate) = krate else { return Default::default() }; let Some(display_name) = krate.display_name(db) else { return Default::default() }; - let crate_data = &db.crate_graph()[krate.into()]; - - let (web_base, local_base) = match &crate_data.origin { + let (web_base, local_base) = match krate.origin(db) { // std and co do not specify `html_root_url` any longer so we gotta handwrite this ourself. // FIXME: Use the toolchains channel instead of nightly CrateOrigin::Lang( diff --git a/crates/ide/src/expand_macro.rs b/crates/ide/src/expand_macro.rs index 2347e2e8a3..3771efc17b 100644 --- a/crates/ide/src/expand_macro.rs +++ b/crates/ide/src/expand_macro.rs @@ -1,8 +1,8 @@ use hir::db::ExpandDatabase; use hir::{ExpandResult, InFile, MacroFileIdExt, Semantics}; -use ide_db::base_db::CrateId; use ide_db::{ - helpers::pick_best_token, syntax_helpers::prettify_macro_expansion, FileId, RootDatabase, + base_db::Crate, helpers::pick_best_token, syntax_helpers::prettify_macro_expansion, FileId, + RootDatabase, }; use span::{Edition, SpanMap, SyntaxContextId, TextRange, TextSize}; use stdx::format_to; @@ -208,7 +208,7 @@ fn format( file_id: FileId, expanded: SyntaxNode, span_map: &SpanMap, - krate: CrateId, + krate: Crate, ) -> String { let expansion = prettify_macro_expansion(db, expanded, span_map, krate).to_string(); @@ -249,7 +249,7 @@ fn _format( let upcast_db = ide_db::base_db::Upcast::::upcast(db); let &crate_id = upcast_db.relevant_crates(file_id).iter().next()?; - let edition = upcast_db.crate_graph()[crate_id].edition; + let edition = crate_id.data(upcast_db).edition; #[allow(clippy::disallowed_methods)] let mut cmd = std::process::Command::new(toolchain::Tool::Rustfmt.path()); diff --git a/crates/ide/src/fetch_crates.rs b/crates/ide/src/fetch_crates.rs index 0e5bb89b6b..b682c4bc0f 100644 --- a/crates/ide/src/fetch_crates.rs +++ b/crates/ide/src/fetch_crates.rs @@ -20,21 +20,24 @@ pub struct CrateInfo { // // ![Show Dependency Tree](https://user-images.githubusercontent.com/5748995/229394139-2625beab-f4c9-484b-84ed-ad5dee0b1e1a.png) pub(crate) fn fetch_crates(db: &RootDatabase) -> FxIndexSet { - let crate_graph = db.crate_graph(); - crate_graph + db.all_crates() .iter() - .map(|crate_id| &crate_graph[crate_id]) - .filter(|&data| !matches!(data.origin, CrateOrigin::Local { .. })) - .map(crate_info) + .copied() + .map(|crate_id| (crate_id.data(db), crate_id.extra_data(db))) + .filter(|(data, _)| !matches!(data.origin, CrateOrigin::Local { .. })) + .map(|(data, extra_data)| crate_info(data, extra_data)) .collect() } -fn crate_info(data: &ide_db::base_db::CrateData) -> CrateInfo { - let crate_name = crate_name(data); - let version = data.version.clone(); +fn crate_info( + data: &ide_db::base_db::BuiltCrateData, + extra_data: &ide_db::base_db::ExtraCrateData, +) -> CrateInfo { + let crate_name = crate_name(extra_data); + let version = extra_data.version.clone(); CrateInfo { name: crate_name, version, root_file_id: data.root_file_id } } -fn crate_name(data: &ide_db::base_db::CrateData) -> Option { +fn crate_name(data: &ide_db::base_db::ExtraCrateData) -> Option { data.display_name.as_ref().map(|it| it.canonical_name().as_str().to_owned()) } diff --git a/crates/ide/src/hover/render.rs b/crates/ide/src/hover/render.rs index 5d888ceb5e..1d807fb14c 100644 --- a/crates/ide/src/hover/render.rs +++ b/crates/ide/src/hover/render.rs @@ -8,7 +8,6 @@ use hir::{ MethodViolationCode, Name, Semantics, Symbol, Trait, Type, TypeInfo, VariantDef, }; use ide_db::{ - base_db::RootQueryDb, defs::Definition, documentation::HasDocs, famous_defs::FamousDefs, @@ -466,8 +465,7 @@ pub(super) fn path( item_name: Option, edition: Edition, ) -> String { - let crate_name = - db.crate_graph()[module.krate().into()].display_name.as_ref().map(|it| it.to_string()); + let crate_name = module.krate().display_name(db).as_ref().map(|it| it.to_string()); let module_path = module .path_to_root(db) .into_iter() diff --git a/crates/ide/src/hover/tests.rs b/crates/ide/src/hover/tests.rs index 736d355ef2..afddeb6dea 100644 --- a/crates/ide/src/hover/tests.rs +++ b/crates/ide/src/hover/tests.rs @@ -9252,7 +9252,7 @@ fn main() { S ``` ___ - Implements notable traits: Notable, Future, Iterator"#]], + Implements notable traits: Future, Iterator, Notable"#]], ); } diff --git a/crates/ide/src/inlay_hints/bind_pat.rs b/crates/ide/src/inlay_hints/bind_pat.rs index 592c860396..aab8a3f873 100644 --- a/crates/ide/src/inlay_hints/bind_pat.rs +++ b/crates/ide/src/inlay_hints/bind_pat.rs @@ -868,15 +868,15 @@ fn main() { //- minicore: fn fn main() { let x = || 2; - //^ {closure#26624} + //^ {closure#25600} let y = |t: i32| x() + t; - //^ {closure#26625} + //^ {closure#25601} let mut t = 5; //^ i32 let z = |k: i32| { t += k; }; - //^ {closure#26626} + //^ {closure#25602} let p = (y, z); - //^ ({closure#26625}, {closure#26626}) + //^ ({closure#25601}, {closure#25602}) } "#, ); diff --git a/crates/ide/src/lib.rs b/crates/ide/src/lib.rs index dcb170f3f7..79863f4680 100644 --- a/crates/ide/src/lib.rs +++ b/crates/ide/src/lib.rs @@ -57,7 +57,7 @@ mod view_memory_layout; mod view_mir; mod view_syntax_tree; -use std::{iter, panic::UnwindSafe}; +use std::panic::UnwindSafe; use cfg::CfgOptions; use fetch_crates::CrateInfo; @@ -125,7 +125,7 @@ pub use ide_completion::{ }; pub use ide_db::text_edit::{Indel, TextEdit}; pub use ide_db::{ - base_db::{CrateGraph, CrateId, FileChange, SourceRoot, SourceRootId}, + base_db::{Crate, CrateGraphBuilder, FileChange, SourceRoot, SourceRootId}, documentation::Documentation, label::Label, line_index::{LineCol, LineIndex}, @@ -239,7 +239,7 @@ impl Analysis { let mut change = ChangeWithProcMacros::new(); change.set_roots(vec![source_root]); - let mut crate_graph = CrateGraph::default(); + let mut crate_graph = CrateGraphBuilder::default(); // FIXME: cfg options // Default to enable test for single file. let mut cfg_options = CfgOptions::default(); @@ -255,16 +255,13 @@ impl Analysis { CrateOrigin::Local { repo: None, name: None }, false, None, - ); - change.change_file(file_id, Some(text)); - let ws_data = crate_graph - .iter() - .zip(iter::repeat(Arc::new(CrateWorkspaceData { + Arc::new(CrateWorkspaceData { data_layout: Err("fixture has no layout".into()), toolchain: None, - }))) - .collect(); - change.set_crate_graph(crate_graph, ws_data); + }), + ); + change.change_file(file_id, Some(text)); + change.set_crate_graph(crate_graph); host.apply_change(change); (host.analysis(), file_id) @@ -372,7 +369,7 @@ impl Analysis { self.with_db(|db| test_explorer::discover_tests_in_crate_by_test_id(db, crate_id)) } - pub fn discover_tests_in_crate(&self, crate_id: CrateId) -> Cancellable> { + pub fn discover_tests_in_crate(&self, crate_id: Crate) -> Cancellable> { self.with_db(|db| test_explorer::discover_tests_in_crate(db, crate_id)) } @@ -602,17 +599,17 @@ impl Analysis { } /// Returns crates that this file belongs to. - pub fn crates_for(&self, file_id: FileId) -> Cancellable> { + pub fn crates_for(&self, file_id: FileId) -> Cancellable> { self.with_db(|db| parent_module::crates_for(db, file_id)) } /// Returns crates that this file belongs to. - pub fn transitive_rev_deps(&self, crate_id: CrateId) -> Cancellable> { - self.with_db(|db| db.crate_graph().transitive_rev_deps(crate_id).collect()) + pub fn transitive_rev_deps(&self, crate_id: Crate) -> Cancellable> { + self.with_db(|db| Vec::from_iter(db.transitive_rev_deps(crate_id))) } /// Returns crates that this file *might* belong to. - pub fn relevant_crates_for(&self, file_id: FileId) -> Cancellable> { + pub fn relevant_crates_for(&self, file_id: FileId) -> Cancellable> { self.with_db(|db| { let db = Upcast::::upcast(db); db.relevant_crates(file_id).iter().copied().collect() @@ -620,18 +617,23 @@ impl Analysis { } /// Returns the edition of the given crate. - pub fn crate_edition(&self, crate_id: CrateId) -> Cancellable { - self.with_db(|db| db.crate_graph()[crate_id].edition) + pub fn crate_edition(&self, crate_id: Crate) -> Cancellable { + self.with_db(|db| crate_id.data(db).edition) + } + + /// Returns whether the given crate is a proc macro. + pub fn is_proc_macro_crate(&self, crate_id: Crate) -> Cancellable { + self.with_db(|db| crate_id.data(db).is_proc_macro) } /// Returns true if this crate has `no_std` or `no_core` specified. - pub fn is_crate_no_std(&self, crate_id: CrateId) -> Cancellable { + pub fn is_crate_no_std(&self, crate_id: Crate) -> Cancellable { self.with_db(|db| hir::db::DefDatabase::crate_def_map(db, crate_id).is_no_std()) } /// Returns the root file of the given crate. - pub fn crate_root(&self, crate_id: CrateId) -> Cancellable { - self.with_db(|db| db.crate_graph()[crate_id].root_file_id) + pub fn crate_root(&self, crate_id: Crate) -> Cancellable { + self.with_db(|db| crate_id.data(db).root_file_id) } /// Returns the set of possible targets to run for the current file. diff --git a/crates/ide/src/parent_module.rs b/crates/ide/src/parent_module.rs index 90cccca5e8..06ab4750ac 100644 --- a/crates/ide/src/parent_module.rs +++ b/crates/ide/src/parent_module.rs @@ -1,6 +1,6 @@ use hir::{db::DefDatabase, Semantics}; use ide_db::{ - base_db::{CrateId, RootQueryDb, Upcast}, + base_db::{Crate, RootQueryDb, Upcast}, FileId, FilePosition, RootDatabase, }; use itertools::Itertools; @@ -53,7 +53,7 @@ pub(crate) fn parent_module(db: &RootDatabase, position: FilePosition) -> Vec Vec { +pub(crate) fn crates_for(db: &RootDatabase, file_id: FileId) -> Vec { let root_db = Upcast::::upcast(db); root_db .relevant_crates(file_id) diff --git a/crates/ide/src/runnables.rs b/crates/ide/src/runnables.rs index 33eef6d75c..baa7ee6897 100644 --- a/crates/ide/src/runnables.rs +++ b/crates/ide/src/runnables.rs @@ -498,9 +498,8 @@ fn module_def_doctest(db: &RootDatabase, def: Definition) -> Option { }; let krate = def.krate(db); let edition = krate.map(|it| it.edition(db)).unwrap_or(Edition::CURRENT); - let display_target = krate - .unwrap_or_else(|| (*db.crate_graph().crates_in_topological_order().last().unwrap()).into()) - .to_display_target(db); + let display_target = + krate.unwrap_or_else(|| (*db.all_crates().last().unwrap()).into()).to_display_target(db); if !has_runnable_doc_test(&attrs) { return None; } diff --git a/crates/ide/src/static_index.rs b/crates/ide/src/static_index.rs index ceea34b721..5a2b09b513 100644 --- a/crates/ide/src/static_index.rs +++ b/crates/ide/src/static_index.rs @@ -119,9 +119,7 @@ fn documentation_for_definition( sema.db, famous_defs.as_ref(), def.krate(sema.db) - .unwrap_or_else(|| { - (*sema.db.crate_graph().crates_in_topological_order().last().unwrap()).into() - }) + .unwrap_or_else(|| (*sema.db.all_crates().last().unwrap()).into()) .to_display_target(sema.db), ) } diff --git a/crates/ide/src/status.rs b/crates/ide/src/status.rs index 47ac4ebf20..52d38041ec 100644 --- a/crates/ide/src/status.rs +++ b/crates/ide/src/status.rs @@ -1,4 +1,4 @@ -use ide_db::base_db::{CrateData, RootQueryDb, Upcast}; +use ide_db::base_db::{BuiltCrateData, ExtraCrateData}; use ide_db::RootDatabase; use itertools::Itertools; use span::FileId; @@ -34,28 +34,25 @@ pub(crate) fn status(db: &RootDatabase, file_id: Option) -> String { if crates.is_empty() { format_to!(buf, "Does not belong to any crate"); } - - let crate_graph = Upcast::::upcast(db).crate_graph(); for crate_id in crates { - let CrateData { + let BuiltCrateData { root_file_id, edition, - version, - display_name, - cfg_options, - potential_cfg_options, - env, dependencies, origin, is_proc_macro, proc_macro_cwd, - } = &crate_graph[crate_id]; + } = crate_id.data(db); + let ExtraCrateData { version, display_name, potential_cfg_options } = + crate_id.extra_data(db); + let cfg_options = crate_id.cfg_options(db); + let env = crate_id.env(db); format_to!( buf, "Crate: {}\n", match display_name { - Some(it) => format!("{it}({})", crate_id.into_raw()), - None => format!("{}", crate_id.into_raw()), + Some(it) => format!("{it}({:?})", crate_id), + None => format!("{:?}", crate_id), } ); format_to!(buf, " Root module file id: {}\n", root_file_id.index()); @@ -69,7 +66,7 @@ pub(crate) fn status(db: &RootDatabase, file_id: Option) -> String { format_to!(buf, " Proc macro cwd: {:?}\n", proc_macro_cwd); let deps = dependencies .iter() - .map(|dep| format!("{}={}", dep.name, dep.crate_id.into_raw())) + .map(|dep| format!("{}={:?}", dep.name, dep.crate_id)) .format(", "); format_to!(buf, " Dependencies: {}\n", deps); } diff --git a/crates/ide/src/test_explorer.rs b/crates/ide/src/test_explorer.rs index 68f5c72d20..d22133c856 100644 --- a/crates/ide/src/test_explorer.rs +++ b/crates/ide/src/test_explorer.rs @@ -1,17 +1,15 @@ //! Discovers tests use hir::{Crate, Module, ModuleDef, Semantics}; -use ide_db::{ - base_db::{CrateGraph, CrateId, RootQueryDb}, - FileId, RootDatabase, -}; +use ide_db::base_db; +use ide_db::{base_db::RootQueryDb, FileId, RootDatabase}; use syntax::TextRange; use crate::{runnables::runnable_fn, NavigationTarget, Runnable, TryToNav}; #[derive(Debug)] pub enum TestItemKind { - Crate(CrateId), + Crate(base_db::Crate), Module, Function, } @@ -28,12 +26,12 @@ pub struct TestItem { } pub(crate) fn discover_test_roots(db: &RootDatabase) -> Vec { - let crate_graph = db.crate_graph(); - crate_graph + db.all_crates() .iter() - .filter(|&id| crate_graph[id].origin.is_local()) + .copied() + .filter(|&id| id.data(db).origin.is_local()) .filter_map(|id| { - let test_id = crate_graph[id].display_name.as_ref()?.to_string(); + let test_id = id.extra_data(db).display_name.as_ref()?.to_string(); Some(TestItem { kind: TestItemKind::Crate(id), label: test_id.clone(), @@ -47,12 +45,12 @@ pub(crate) fn discover_test_roots(db: &RootDatabase) -> Vec { .collect() } -fn find_crate_by_id(crate_graph: &CrateGraph, crate_id: &str) -> Option { +fn find_crate_by_id(db: &RootDatabase, crate_id: &str) -> Option { // here, we use display_name as the crate id. This is not super ideal, but it works since we // only show tests for the local crates. - crate_graph.iter().find(|&id| { - crate_graph[id].origin.is_local() - && crate_graph[id].display_name.as_ref().is_some_and(|x| x.to_string() == crate_id) + db.all_crates().iter().copied().find(|&id| { + id.data(db).origin.is_local() + && id.extra_data(db).display_name.as_ref().is_some_and(|x| x.to_string() == crate_id) }) } @@ -115,8 +113,7 @@ pub(crate) fn discover_tests_in_crate_by_test_id( db: &RootDatabase, crate_test_id: &str, ) -> Vec { - let crate_graph = db.crate_graph(); - let Some(crate_id) = find_crate_by_id(&crate_graph, crate_test_id) else { + let Some(crate_id) = find_crate_by_id(db, crate_test_id) else { return vec![]; }; discover_tests_in_crate(db, crate_id) @@ -171,12 +168,14 @@ fn find_module_id_and_test_parents( Some((r, id)) } -pub(crate) fn discover_tests_in_crate(db: &RootDatabase, crate_id: CrateId) -> Vec { - let crate_graph = db.crate_graph(); - if !crate_graph[crate_id].origin.is_local() { +pub(crate) fn discover_tests_in_crate( + db: &RootDatabase, + crate_id: base_db::Crate, +) -> Vec { + if !crate_id.data(db).origin.is_local() { return vec![]; } - let Some(crate_test_id) = &crate_graph[crate_id].display_name else { + let Some(crate_test_id) = &crate_id.extra_data(db).display_name else { return vec![]; }; let kind = TestItemKind::Crate(crate_id); diff --git a/crates/ide/src/view_crate_graph.rs b/crates/ide/src/view_crate_graph.rs index eeb65ac038..09f21ecfe4 100644 --- a/crates/ide/src/view_crate_graph.rs +++ b/crates/ide/src/view_crate_graph.rs @@ -1,9 +1,10 @@ use dot::{Id, LabelText}; use ide_db::{ - base_db::{CrateGraph, CrateId, Dependency, RootQueryDb, SourceDatabase, Upcast}, - FxHashSet, RootDatabase, + base_db::{ + BuiltCrateData, BuiltDependency, Crate, ExtraCrateData, RootQueryDb, SourceDatabase, + }, + FxHashMap, RootDatabase, }; -use triomphe::Arc; // Feature: View Crate Graph // @@ -16,77 +17,80 @@ use triomphe::Arc; // |---------|-------------| // | VS Code | **rust-analyzer: View Crate Graph** | pub(crate) fn view_crate_graph(db: &RootDatabase, full: bool) -> Result { - let crate_graph = Upcast::::upcast(db).crate_graph(); - let crates_to_render = crate_graph + let all_crates = db.all_crates(); + let crates_to_render = all_crates .iter() - .filter(|krate| { + .copied() + .map(|krate| (krate, (krate.data(db), krate.extra_data(db)))) + .filter(|(_, (crate_data, _))| { if full { true } else { // Only render workspace crates - let root_id = - db.file_source_root(crate_graph[*krate].root_file_id).source_root_id(db); + let root_id = db.file_source_root(crate_data.root_file_id).source_root_id(db); !db.source_root(root_id).source_root(db).is_library } }) .collect(); - let graph = DotCrateGraph { graph: crate_graph, crates_to_render }; + let graph = DotCrateGraph { crates_to_render }; let mut dot = Vec::new(); dot::render(&graph, &mut dot).unwrap(); Ok(String::from_utf8(dot).unwrap()) } -struct DotCrateGraph { - graph: Arc, - crates_to_render: FxHashSet, +struct DotCrateGraph<'db> { + crates_to_render: FxHashMap, } -type Edge<'a> = (CrateId, &'a Dependency); +type Edge<'a> = (Crate, &'a BuiltDependency); -impl<'a> dot::GraphWalk<'a, CrateId, Edge<'a>> for DotCrateGraph { - fn nodes(&'a self) -> dot::Nodes<'a, CrateId> { - self.crates_to_render.iter().copied().collect() +impl<'a> dot::GraphWalk<'a, Crate, Edge<'a>> for DotCrateGraph<'_> { + fn nodes(&'a self) -> dot::Nodes<'a, Crate> { + self.crates_to_render.keys().copied().collect() } fn edges(&'a self) -> dot::Edges<'a, Edge<'a>> { self.crates_to_render .iter() - .flat_map(|krate| { - self.graph[*krate] + .flat_map(|(krate, (crate_data, _))| { + crate_data .dependencies .iter() - .filter(|dep| self.crates_to_render.contains(&dep.crate_id)) + .filter(|dep| self.crates_to_render.contains_key(&dep.crate_id)) .map(move |dep| (*krate, dep)) }) .collect() } - fn source(&'a self, edge: &Edge<'a>) -> CrateId { + fn source(&'a self, edge: &Edge<'a>) -> Crate { edge.0 } - fn target(&'a self, edge: &Edge<'a>) -> CrateId { + fn target(&'a self, edge: &Edge<'a>) -> Crate { edge.1.crate_id } } -impl<'a> dot::Labeller<'a, CrateId, Edge<'a>> for DotCrateGraph { +impl<'a> dot::Labeller<'a, Crate, Edge<'a>> for DotCrateGraph<'_> { fn graph_id(&'a self) -> Id<'a> { Id::new("rust_analyzer_crate_graph").unwrap() } - fn node_id(&'a self, n: &CrateId) -> Id<'a> { - Id::new(format!("_{}", u32::from(n.into_raw()))).unwrap() + fn node_id(&'a self, n: &Crate) -> Id<'a> { + Id::new(format!("_{:?}", n)).unwrap() } - fn node_shape(&'a self, _node: &CrateId) -> Option> { + fn node_shape(&'a self, _node: &Crate) -> Option> { Some(LabelText::LabelStr("box".into())) } - fn node_label(&'a self, n: &CrateId) -> LabelText<'a> { - let name = - self.graph[*n].display_name.as_ref().map_or("(unnamed crate)", |name| name.as_str()); + fn node_label(&'a self, n: &Crate) -> LabelText<'a> { + let name = self.crates_to_render[n] + .1 + .display_name + .as_ref() + .map_or("(unnamed crate)", |name| name.as_str()); LabelText::LabelStr(name.into()) } } diff --git a/crates/intern/src/symbol.rs b/crates/intern/src/symbol.rs index 0fa6701ca3..f6a74d9741 100644 --- a/crates/intern/src/symbol.rs +++ b/crates/intern/src/symbol.rs @@ -42,6 +42,18 @@ struct TaggedArcPtr { unsafe impl Send for TaggedArcPtr {} unsafe impl Sync for TaggedArcPtr {} +impl Ord for TaggedArcPtr { + fn cmp(&self, other: &Self) -> std::cmp::Ordering { + self.as_str().cmp(other.as_str()) + } +} + +impl PartialOrd for TaggedArcPtr { + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } +} + impl TaggedArcPtr { const BOOL_BITS: usize = true as usize; @@ -113,7 +125,7 @@ impl TaggedArcPtr { } } -#[derive(PartialEq, Eq, Hash)] +#[derive(PartialEq, Eq, Hash, PartialOrd, Ord)] pub struct Symbol { repr: TaggedArcPtr, } diff --git a/crates/load-cargo/src/lib.rs b/crates/load-cargo/src/lib.rs index fbb0043ad2..01d29d88df 100644 --- a/crates/load-cargo/src/lib.rs +++ b/crates/load-cargo/src/lib.rs @@ -2,15 +2,15 @@ //! for incorporating changes. // Note, don't remove any public api from this. This API is consumed by external tools // to run rust-analyzer as a library. -use std::{collections::hash_map::Entry, iter, mem, path::Path, sync}; +use std::{collections::hash_map::Entry, mem, path::Path, sync}; use crossbeam_channel::{unbounded, Receiver}; use hir_expand::proc_macro::{ ProcMacro, ProcMacroExpander, ProcMacroExpansionError, ProcMacroKind, ProcMacroLoadResult, - ProcMacros, + ProcMacrosBuilder, }; use ide_db::{ - base_db::{CrateGraph, CrateWorkspaceData, Env, SourceRoot, SourceRootId}, + base_db::{CrateGraphBuilder, Env, SourceRoot, SourceRootId}, prime_caches, ChangeWithProcMacros, FxHashMap, RootDatabase, }; use itertools::Itertools; @@ -139,7 +139,6 @@ pub fn load_workspace( }); let db = load_crate_graph( - &ws, crate_graph, proc_macros, project_folders.source_root_config, @@ -418,15 +417,12 @@ pub fn load_proc_macro( } fn load_crate_graph( - ws: &ProjectWorkspace, - crate_graph: CrateGraph, - proc_macros: ProcMacros, + crate_graph: CrateGraphBuilder, + proc_macros: ProcMacrosBuilder, source_root_config: SourceRootConfig, vfs: &mut vfs::Vfs, receiver: &Receiver, ) -> RootDatabase { - let ProjectWorkspace { toolchain, target_layout, .. } = ws; - let lru_cap = std::env::var("RA_LRU_CAP").ok().and_then(|it| it.parse::().ok()); let mut db = RootDatabase::new(lru_cap); let mut analysis_change = ChangeWithProcMacros::new(); @@ -461,14 +457,7 @@ fn load_crate_graph( let source_roots = source_root_config.partition(vfs); analysis_change.set_roots(source_roots); - let ws_data = crate_graph - .iter() - .zip(iter::repeat(From::from(CrateWorkspaceData { - data_layout: target_layout.clone(), - toolchain: toolchain.clone(), - }))) - .collect(); - analysis_change.set_crate_graph(crate_graph, ws_data); + analysis_change.set_crate_graph(crate_graph); analysis_change.set_proc_macros(proc_macros); db.apply_change(analysis_change); @@ -494,7 +483,7 @@ fn expander_to_proc_macro( } } -#[derive(Debug)] +#[derive(Debug, PartialEq, Eq)] struct Expander(proc_macro_api::ProcMacro); impl ProcMacroExpander for Expander { @@ -522,6 +511,10 @@ impl ProcMacroExpander for Expander { Err(err) => Err(ProcMacroExpansionError::System(err.to_string())), } } + + fn eq_dyn(&self, other: &dyn ProcMacroExpander) -> bool { + other.as_any().downcast_ref::().is_some_and(|other| self == other) + } } #[cfg(test)] @@ -543,7 +536,7 @@ mod tests { let (db, _vfs, _proc_macro) = load_workspace_at(path, &cargo_config, &load_cargo_config, &|_| {}).unwrap(); - let n_crates = db.crate_graph().iter().count(); + let n_crates = db.all_crates().len(); // RA has quite a few crates, but the exact count doesn't matter assert!(n_crates > 20); } diff --git a/crates/proc-macro-api/src/lib.rs b/crates/proc-macro-api/src/lib.rs index dc3328ebcd..571ceaabe6 100644 --- a/crates/proc-macro-api/src/lib.rs +++ b/crates/proc-macro-api/src/lib.rs @@ -13,7 +13,7 @@ mod process; use paths::{AbsPath, AbsPathBuf}; use span::Span; -use std::{fmt, io, sync::Arc}; +use std::{fmt, io, sync::Arc, time::SystemTime}; use crate::{ legacy_protocol::msg::{ @@ -66,6 +66,7 @@ pub struct ProcMacro { dylib_path: Arc, name: Box, kind: ProcMacroKind, + dylib_last_modified: Option, } impl Eq for ProcMacro {} @@ -73,7 +74,8 @@ impl PartialEq for ProcMacro { fn eq(&self, other: &Self) -> bool { self.name == other.name && self.kind == other.kind - && Arc::ptr_eq(&self.dylib_path, &other.dylib_path) + && self.dylib_path == other.dylib_path + && self.dylib_last_modified == other.dylib_last_modified && Arc::ptr_eq(&self.process, &other.process) } } @@ -116,6 +118,9 @@ impl ProcMacroClient { let macros = self.process.find_proc_macros(&dylib.path)?; let dylib_path = Arc::new(dylib.path); + let dylib_last_modified = std::fs::metadata(dylib_path.as_path()) + .ok() + .and_then(|metadata| metadata.modified().ok()); match macros { Ok(macros) => Ok(macros .into_iter() @@ -124,6 +129,7 @@ impl ProcMacroClient { name: name.into(), kind, dylib_path: dylib_path.clone(), + dylib_last_modified, }) .collect()), Err(message) => Err(ServerError { message, io: None }), diff --git a/crates/proc-macro-srv/src/tests/mod.rs b/crates/proc-macro-srv/src/tests/mod.rs index 15de88ea65..716d351271 100644 --- a/crates/proc-macro-srv/src/tests/mod.rs +++ b/crates/proc-macro-srv/src/tests/mod.rs @@ -12,7 +12,7 @@ fn test_derive_empty() { "DeriveEmpty", r#"struct S;"#, expect!["SUBTREE $$ 1 1"], - expect!["SUBTREE $$ 42:2@0..100#2 42:2@0..100#2"], + expect!["SUBTREE $$ 42:2@0..100#4294967037 42:2@0..100#4294967037"], ); } @@ -29,12 +29,12 @@ fn test_derive_error() { LITERAL Str #[derive(DeriveError)] struct S ; 1 PUNCH ; [alone] 1"#]], expect![[r#" - SUBTREE $$ 42:2@0..100#2 42:2@0..100#2 - IDENT compile_error 42:2@0..100#2 - PUNCH ! [alone] 42:2@0..100#2 - SUBTREE () 42:2@0..100#2 42:2@0..100#2 - LITERAL Str #[derive(DeriveError)] struct S ; 42:2@0..100#2 - PUNCH ; [alone] 42:2@0..100#2"#]], + SUBTREE $$ 42:2@0..100#4294967037 42:2@0..100#4294967037 + IDENT compile_error 42:2@0..100#4294967037 + PUNCH ! [alone] 42:2@0..100#4294967037 + SUBTREE () 42:2@0..100#4294967037 42:2@0..100#4294967037 + LITERAL Str #[derive(DeriveError)] struct S ; 42:2@0..100#4294967037 + PUNCH ; [alone] 42:2@0..100#4294967037"#]], ); } @@ -53,14 +53,14 @@ fn test_fn_like_macro_noop() { PUNCH , [alone] 1 SUBTREE [] 1 1"#]], expect![[r#" - SUBTREE $$ 42:2@0..100#2 42:2@0..100#2 - IDENT ident 42:2@0..5#2 - PUNCH , [alone] 42:2@5..6#2 - LITERAL Integer 0 42:2@7..8#2 - PUNCH , [alone] 42:2@8..9#2 - LITERAL Integer 1 42:2@10..11#2 - PUNCH , [alone] 42:2@11..12#2 - SUBTREE [] 42:2@13..14#2 42:2@14..15#2"#]], + SUBTREE $$ 42:2@0..100#4294967037 42:2@0..100#4294967037 + IDENT ident 42:2@0..5#4294967037 + PUNCH , [alone] 42:2@5..6#4294967037 + LITERAL Integer 0 42:2@7..8#4294967037 + PUNCH , [alone] 42:2@8..9#4294967037 + LITERAL Integer 1 42:2@10..11#4294967037 + PUNCH , [alone] 42:2@11..12#4294967037 + SUBTREE [] 42:2@13..14#4294967037 42:2@14..15#4294967037"#]], ); } @@ -75,10 +75,10 @@ fn test_fn_like_macro_clone_ident_subtree() { PUNCH , [alone] 1 SUBTREE [] 1 1"#]], expect![[r#" - SUBTREE $$ 42:2@0..100#2 42:2@0..100#2 - IDENT ident 42:2@0..5#2 - PUNCH , [alone] 42:2@5..6#2 - SUBTREE [] 42:2@7..8#2 42:2@7..8#2"#]], + SUBTREE $$ 42:2@0..100#4294967037 42:2@0..100#4294967037 + IDENT ident 42:2@0..5#4294967037 + PUNCH , [alone] 42:2@5..6#4294967037 + SUBTREE [] 42:2@7..8#4294967037 42:2@7..8#4294967037"#]], ); } @@ -91,8 +91,8 @@ fn test_fn_like_macro_clone_raw_ident() { SUBTREE $$ 1 1 IDENT r#async 1"#]], expect![[r#" - SUBTREE $$ 42:2@0..100#2 42:2@0..100#2 - IDENT r#async 42:2@0..7#2"#]], + SUBTREE $$ 42:2@0..100#4294967037 42:2@0..100#4294967037 + IDENT r#async 42:2@0..7#4294967037"#]], ); } @@ -105,8 +105,8 @@ fn test_fn_like_fn_like_span_join() { SUBTREE $$ 1 1 IDENT r#joined 1"#]], expect![[r#" - SUBTREE $$ 42:2@0..100#2 42:2@0..100#2 - IDENT r#joined 42:2@0..11#2"#]], + SUBTREE $$ 42:2@0..100#4294967037 42:2@0..100#4294967037 + IDENT r#joined 42:2@0..11#4294967037"#]], ); } @@ -121,10 +121,10 @@ fn test_fn_like_fn_like_span_ops() { IDENT resolved_at_def_site 1 IDENT start_span 1"#]], expect![[r#" - SUBTREE $$ 42:2@0..100#2 42:2@0..100#2 - IDENT set_def_site 41:1@0..150#2 - IDENT resolved_at_def_site 42:2@13..33#2 - IDENT start_span 42:2@34..34#2"#]], + SUBTREE $$ 42:2@0..100#4294967037 42:2@0..100#4294967037 + IDENT set_def_site 41:1@0..150#4294967037 + IDENT resolved_at_def_site 42:2@13..33#4294967037 + IDENT start_span 42:2@34..34#4294967037"#]], ); } @@ -143,14 +143,14 @@ fn test_fn_like_mk_literals() { LITERAL Integer 123i64 1 LITERAL Integer 123 1"#]], expect![[r#" - SUBTREE $$ 42:2@0..100#2 42:2@0..100#2 - LITERAL ByteStr byte_string 42:2@0..100#2 - LITERAL Char c 42:2@0..100#2 - LITERAL Str string 42:2@0..100#2 - LITERAL Float 3.14f64 42:2@0..100#2 - LITERAL Float 3.14 42:2@0..100#2 - LITERAL Integer 123i64 42:2@0..100#2 - LITERAL Integer 123 42:2@0..100#2"#]], + SUBTREE $$ 42:2@0..100#4294967037 42:2@0..100#4294967037 + LITERAL ByteStr byte_string 42:2@0..100#4294967037 + LITERAL Char c 42:2@0..100#4294967037 + LITERAL Str string 42:2@0..100#4294967037 + LITERAL Float 3.14f64 42:2@0..100#4294967037 + LITERAL Float 3.14 42:2@0..100#4294967037 + LITERAL Integer 123i64 42:2@0..100#4294967037 + LITERAL Integer 123 42:2@0..100#4294967037"#]], ); } @@ -164,9 +164,9 @@ fn test_fn_like_mk_idents() { IDENT standard 1 IDENT r#raw 1"#]], expect![[r#" - SUBTREE $$ 42:2@0..100#2 42:2@0..100#2 - IDENT standard 42:2@0..100#2 - IDENT r#raw 42:2@0..100#2"#]], + SUBTREE $$ 42:2@0..100#4294967037 42:2@0..100#4294967037 + IDENT standard 42:2@0..100#4294967037 + IDENT r#raw 42:2@0..100#4294967037"#]], ); } @@ -198,27 +198,27 @@ fn test_fn_like_macro_clone_literals() { PUNCH , [alone] 1 LITERAL CStr null 1"#]], expect![[r#" - SUBTREE $$ 42:2@0..100#2 42:2@0..100#2 - LITERAL Integer 1u16 42:2@0..4#2 - PUNCH , [alone] 42:2@4..5#2 - LITERAL Integer 2_u32 42:2@6..11#2 - PUNCH , [alone] 42:2@11..12#2 - PUNCH - [alone] 42:2@13..14#2 - LITERAL Integer 4i64 42:2@14..18#2 - PUNCH , [alone] 42:2@18..19#2 - LITERAL Float 3.14f32 42:2@20..27#2 - PUNCH , [alone] 42:2@27..28#2 - LITERAL Str hello bridge 42:2@29..43#2 - PUNCH , [alone] 42:2@43..44#2 - LITERAL Str suffixedsuffix 42:2@45..61#2 - PUNCH , [alone] 42:2@61..62#2 - LITERAL StrRaw(2) raw 42:2@63..73#2 - PUNCH , [alone] 42:2@73..74#2 - LITERAL Char a 42:2@75..78#2 - PUNCH , [alone] 42:2@78..79#2 - LITERAL Byte b 42:2@80..84#2 - PUNCH , [alone] 42:2@84..85#2 - LITERAL CStr null 42:2@86..93#2"#]], + SUBTREE $$ 42:2@0..100#4294967037 42:2@0..100#4294967037 + LITERAL Integer 1u16 42:2@0..4#4294967037 + PUNCH , [alone] 42:2@4..5#4294967037 + LITERAL Integer 2_u32 42:2@6..11#4294967037 + PUNCH , [alone] 42:2@11..12#4294967037 + PUNCH - [alone] 42:2@13..14#4294967037 + LITERAL Integer 4i64 42:2@14..18#4294967037 + PUNCH , [alone] 42:2@18..19#4294967037 + LITERAL Float 3.14f32 42:2@20..27#4294967037 + PUNCH , [alone] 42:2@27..28#4294967037 + LITERAL Str hello bridge 42:2@29..43#4294967037 + PUNCH , [alone] 42:2@43..44#4294967037 + LITERAL Str suffixedsuffix 42:2@45..61#4294967037 + PUNCH , [alone] 42:2@61..62#4294967037 + LITERAL StrRaw(2) raw 42:2@63..73#4294967037 + PUNCH , [alone] 42:2@73..74#4294967037 + LITERAL Char a 42:2@75..78#4294967037 + PUNCH , [alone] 42:2@78..79#4294967037 + LITERAL Byte b 42:2@80..84#4294967037 + PUNCH , [alone] 42:2@84..85#4294967037 + LITERAL CStr null 42:2@86..93#4294967037"#]], ); } @@ -239,12 +239,12 @@ fn test_attr_macro() { LITERAL Str #[attr_error(some arguments)] mod m {} 1 PUNCH ; [alone] 1"#]], expect![[r#" - SUBTREE $$ 42:2@0..100#2 42:2@0..100#2 - IDENT compile_error 42:2@0..100#2 - PUNCH ! [alone] 42:2@0..100#2 - SUBTREE () 42:2@0..100#2 42:2@0..100#2 - LITERAL Str #[attr_error(some arguments)] mod m {} 42:2@0..100#2 - PUNCH ; [alone] 42:2@0..100#2"#]], + SUBTREE $$ 42:2@0..100#4294967037 42:2@0..100#4294967037 + IDENT compile_error 42:2@0..100#4294967037 + PUNCH ! [alone] 42:2@0..100#4294967037 + SUBTREE () 42:2@0..100#4294967037 42:2@0..100#4294967037 + LITERAL Str #[attr_error(some arguments)] mod m {} 42:2@0..100#4294967037 + PUNCH ; [alone] 42:2@0..100#4294967037"#]], ); } diff --git a/crates/project-model/src/project_json.rs b/crates/project-model/src/project_json.rs index b2df8e4703..3c14e6e627 100644 --- a/crates/project-model/src/project_json.rs +++ b/crates/project-model/src/project_json.rs @@ -452,7 +452,7 @@ pub enum TargetKindData { } /// Identifies a crate by position in the crates array. /// -/// This will differ from `CrateId` when multiple `ProjectJson` +/// This will differ from `Crate` when multiple `ProjectJson` /// workspaces are loaded. #[derive(Serialize, Deserialize, Debug, Clone, Copy, Eq, PartialEq, Hash)] #[serde(transparent)] diff --git a/crates/project-model/src/tests.rs b/crates/project-model/src/tests.rs index 8374062273..d4c93b0e9b 100644 --- a/crates/project-model/src/tests.rs +++ b/crates/project-model/src/tests.rs @@ -1,4 +1,4 @@ -use base_db::{CrateGraph, ProcMacroPaths}; +use base_db::{CrateGraphBuilder, ProcMacroPaths}; use cargo_metadata::Metadata; use cfg::{CfgAtom, CfgDiff}; use expect_test::{expect_file, ExpectFile}; @@ -15,7 +15,7 @@ use crate::{ Sysroot, WorkspaceBuildScripts, }; -fn load_cargo(file: &str) -> (CrateGraph, ProcMacroPaths) { +fn load_cargo(file: &str) -> (CrateGraphBuilder, ProcMacroPaths) { let project_workspace = load_workspace_from_metadata(file); to_crate_graph(project_workspace, &mut Default::default()) } @@ -23,7 +23,7 @@ fn load_cargo(file: &str) -> (CrateGraph, ProcMacroPaths) { fn load_cargo_with_overrides( file: &str, cfg_overrides: CfgOverrides, -) -> (CrateGraph, ProcMacroPaths) { +) -> (CrateGraphBuilder, ProcMacroPaths) { let project_workspace = ProjectWorkspace { cfg_overrides, ..load_workspace_from_metadata(file) }; to_crate_graph(project_workspace, &mut Default::default()) @@ -51,7 +51,7 @@ fn load_workspace_from_metadata(file: &str) -> ProjectWorkspace { } } -fn load_rust_project(file: &str) -> (CrateGraph, ProcMacroPaths) { +fn load_rust_project(file: &str) -> (CrateGraphBuilder, ProcMacroPaths) { let data = get_test_json_file(file); let project = rooted_project_json(data); let sysroot = get_fake_sysroot(); @@ -142,7 +142,7 @@ fn rooted_project_json(data: ProjectJsonData) -> ProjectJson { fn to_crate_graph( project_workspace: ProjectWorkspace, file_map: &mut FxHashMap, -) -> (CrateGraph, ProcMacroPaths) { +) -> (CrateGraphBuilder, ProcMacroPaths) { project_workspace.to_crate_graph( &mut { |path| { @@ -154,7 +154,7 @@ fn to_crate_graph( ) } -fn check_crate_graph(crate_graph: CrateGraph, expect: ExpectFile) { +fn check_crate_graph(crate_graph: CrateGraphBuilder, expect: ExpectFile) { let mut crate_graph = format!("{crate_graph:#?}"); replace_root(&mut crate_graph, false); diff --git a/crates/project-model/src/workspace.rs b/crates/project-model/src/workspace.rs index 62c13c7d9e..114c2551e1 100644 --- a/crates/project-model/src/workspace.rs +++ b/crates/project-model/src/workspace.rs @@ -6,8 +6,9 @@ use std::{collections::VecDeque, fmt, fs, iter, ops::Deref, sync, thread}; use anyhow::Context; use base_db::{ - CrateDisplayName, CrateGraph, CrateId, CrateName, CrateOrigin, Dependency, Env, - LangCrateOrigin, ProcMacroPaths, TargetLayoutLoadResult, + CrateBuilderId, CrateDisplayName, CrateGraphBuilder, CrateName, CrateOrigin, + CrateWorkspaceData, DependencyBuilder, Env, LangCrateOrigin, ProcMacroPaths, + TargetLayoutLoadResult, }; use cfg::{CfgAtom, CfgDiff, CfgOptions}; use intern::{sym, Symbol}; @@ -848,10 +849,14 @@ impl ProjectWorkspace { &self, load: FileLoader<'_>, extra_env: &FxHashMap, - ) -> (CrateGraph, ProcMacroPaths) { + ) -> (CrateGraphBuilder, ProcMacroPaths) { let _p = tracing::info_span!("ProjectWorkspace::to_crate_graph").entered(); let Self { kind, sysroot, cfg_overrides, rustc_cfg, .. } = self; + let crate_ws_data = Arc::new(CrateWorkspaceData { + toolchain: self.toolchain.clone(), + data_layout: self.target_layout.clone(), + }); let (crate_graph, proc_macros) = match kind { ProjectWorkspaceKind::Json(project) => project_json_to_crate_graph( rustc_cfg.clone(), @@ -861,6 +866,7 @@ impl ProjectWorkspace { extra_env, cfg_overrides, self.set_test, + crate_ws_data, ), ProjectWorkspaceKind::Cargo { cargo, rustc, build_scripts, error: _ } => { cargo_to_crate_graph( @@ -872,6 +878,7 @@ impl ProjectWorkspace { cfg_overrides, build_scripts, self.set_test, + crate_ws_data, ) } ProjectWorkspaceKind::DetachedFile { file, cargo: cargo_script, .. } => { @@ -885,6 +892,7 @@ impl ProjectWorkspace { cfg_overrides, build_scripts, self.set_test, + crate_ws_data, ) } else { detached_file_to_crate_graph( @@ -894,6 +902,7 @@ impl ProjectWorkspace { sysroot, cfg_overrides, self.set_test, + crate_ws_data, ) } } @@ -959,15 +968,22 @@ fn project_json_to_crate_graph( extra_env: &FxHashMap, override_cfg: &CfgOverrides, set_test: bool, -) -> (CrateGraph, ProcMacroPaths) { - let mut res = (CrateGraph::default(), ProcMacroPaths::default()); + crate_ws_data: Arc, +) -> (CrateGraphBuilder, ProcMacroPaths) { + let mut res = (CrateGraphBuilder::default(), ProcMacroPaths::default()); let (crate_graph, proc_macros) = &mut res; - let (public_deps, libproc_macro) = - sysroot_to_crate_graph(crate_graph, sysroot, rustc_cfg.clone(), load); + let (public_deps, libproc_macro) = sysroot_to_crate_graph( + crate_graph, + sysroot, + rustc_cfg.clone(), + load, + // FIXME: This looks incorrect but I don't think this matters. + crate_ws_data.clone(), + ); let mut cfg_cache: FxHashMap<&str, Vec> = FxHashMap::default(); - let idx_to_crate_id: FxHashMap = project + let idx_to_crate_id: FxHashMap = project .crates() .filter_map(|(idx, krate)| Some((idx, krate, load(&krate.root_module)?))) .map( @@ -1042,6 +1058,7 @@ fn project_json_to_crate_graph( }, *is_proc_macro, proc_macro_cwd.clone(), + crate_ws_data.clone(), ); debug!( ?crate_graph_crate_id, @@ -1092,12 +1109,19 @@ fn cargo_to_crate_graph( override_cfg: &CfgOverrides, build_scripts: &WorkspaceBuildScripts, set_test: bool, -) -> (CrateGraph, ProcMacroPaths) { + crate_ws_data: Arc, +) -> (CrateGraphBuilder, ProcMacroPaths) { let _p = tracing::info_span!("cargo_to_crate_graph").entered(); - let mut res = (CrateGraph::default(), ProcMacroPaths::default()); + let mut res = (CrateGraphBuilder::default(), ProcMacroPaths::default()); let (crate_graph, proc_macros) = &mut res; - let (public_deps, libproc_macro) = - sysroot_to_crate_graph(crate_graph, sysroot, rustc_cfg.clone(), load); + let (public_deps, libproc_macro) = sysroot_to_crate_graph( + crate_graph, + sysroot, + rustc_cfg.clone(), + load, + // FIXME: This looks incorrect but I don't think this causes problems. + crate_ws_data.clone(), + ); let cfg_options = CfgOptions::from_iter(rustc_cfg); @@ -1163,6 +1187,7 @@ fn cargo_to_crate_graph( name: Symbol::intern(&pkg_data.name), } }, + crate_ws_data.clone(), ); if let TargetKind::Lib { .. } = kind { lib_tgt = Some((crate_id, name.clone())); @@ -1267,6 +1292,8 @@ fn cargo_to_crate_graph( } else { rustc_build_scripts }, + // FIXME: This looks incorrect but I don't think this causes problems. + crate_ws_data, ); } } @@ -1280,11 +1307,18 @@ fn detached_file_to_crate_graph( sysroot: &Sysroot, override_cfg: &CfgOverrides, set_test: bool, -) -> (CrateGraph, ProcMacroPaths) { + crate_ws_data: Arc, +) -> (CrateGraphBuilder, ProcMacroPaths) { let _p = tracing::info_span!("detached_file_to_crate_graph").entered(); - let mut crate_graph = CrateGraph::default(); - let (public_deps, _libproc_macro) = - sysroot_to_crate_graph(&mut crate_graph, sysroot, rustc_cfg.clone(), load); + let mut crate_graph = CrateGraphBuilder::default(); + let (public_deps, _libproc_macro) = sysroot_to_crate_graph( + &mut crate_graph, + sysroot, + rustc_cfg.clone(), + load, + // FIXME: This looks incorrect but I don't think this causes problems. + crate_ws_data.clone(), + ); let mut cfg_options = CfgOptions::from_iter(rustc_cfg); if set_test { @@ -1316,6 +1350,7 @@ fn detached_file_to_crate_graph( }, false, None, + crate_ws_data, ); public_deps.add_to_crate_graph(&mut crate_graph, detached_file_crate); @@ -1323,18 +1358,19 @@ fn detached_file_to_crate_graph( } fn handle_rustc_crates( - crate_graph: &mut CrateGraph, + crate_graph: &mut CrateGraphBuilder, proc_macros: &mut ProcMacroPaths, - pkg_to_lib_crate: &mut FxHashMap, + pkg_to_lib_crate: &mut FxHashMap, load: FileLoader<'_>, rustc_workspace: &CargoWorkspace, cargo: &CargoWorkspace, public_deps: &SysrootPublicDeps, - libproc_macro: Option, - pkg_crates: &FxHashMap>, + libproc_macro: Option, + pkg_crates: &FxHashMap>, cfg_options: &CfgOptions, override_cfg: &CfgOverrides, build_scripts: &WorkspaceBuildScripts, + crate_ws_data: Arc, ) { let mut rustc_pkg_crates = FxHashMap::default(); // The root package of the rustc-dev component is rustc_driver, so we match that @@ -1377,6 +1413,7 @@ fn handle_rustc_crates( &rustc_workspace[tgt].name, kind, CrateOrigin::Rustc { name: Symbol::intern(&rustc_workspace[pkg].name) }, + crate_ws_data.clone(), ); pkg_to_lib_crate.insert(pkg, crate_id); // Add dependencies on core / std / alloc for this crate @@ -1417,7 +1454,7 @@ fn handle_rustc_crates( // This avoids the situation where `from` depends on e.g. `arrayvec`, but // `rust_analyzer` thinks that it should use the one from the `rustc_source` // instead of the one from `crates.io` - if !crate_graph[*from].dependencies.iter().any(|d| d.name == name) { + if !crate_graph[*from].basic.dependencies.iter().any(|d| d.name == name) { add_dep(crate_graph, *from, name.clone(), to); } } @@ -1427,7 +1464,7 @@ fn handle_rustc_crates( } fn add_target_crate_root( - crate_graph: &mut CrateGraph, + crate_graph: &mut CrateGraphBuilder, proc_macros: &mut ProcMacroPaths, cargo: &CargoWorkspace, pkg: &PackageData, @@ -1437,7 +1474,8 @@ fn add_target_crate_root( cargo_name: &str, kind: TargetKind, origin: CrateOrigin, -) -> CrateId { + crate_ws_data: Arc, +) -> CrateBuilderId { let edition = pkg.edition; let potential_cfg_options = if pkg.features.is_empty() { None @@ -1474,7 +1512,7 @@ fn add_target_crate_root( Some(CrateDisplayName::from_canonical_name(cargo_name)), Some(pkg.version.to_string()), Arc::new(cfg_options), - potential_cfg_options.map(Arc::new), + potential_cfg_options, env, origin, matches!(kind, TargetKind::Lib { is_proc_macro: true }), @@ -1483,6 +1521,7 @@ fn add_target_crate_root( } else { pkg.manifest.parent().to_path_buf() }), + crate_ws_data, ); if let TargetKind::Lib { is_proc_macro: true } = kind { let proc_macro = match build_data { @@ -1503,12 +1542,12 @@ fn add_target_crate_root( #[derive(Default, Debug)] struct SysrootPublicDeps { - deps: Vec<(CrateName, CrateId, bool)>, + deps: Vec<(CrateName, CrateBuilderId, bool)>, } impl SysrootPublicDeps { /// Makes `from` depend on the public sysroot crates. - fn add_to_crate_graph(&self, crate_graph: &mut CrateGraph, from: CrateId) { + fn add_to_crate_graph(&self, crate_graph: &mut CrateGraphBuilder, from: CrateBuilderId) { for (name, krate, prelude) in &self.deps { add_dep_with_prelude(crate_graph, from, name.clone(), *krate, *prelude, true); } @@ -1516,10 +1555,10 @@ impl SysrootPublicDeps { } fn extend_crate_graph_with_sysroot( - crate_graph: &mut CrateGraph, - mut sysroot_crate_graph: CrateGraph, + crate_graph: &mut CrateGraphBuilder, + mut sysroot_crate_graph: CrateGraphBuilder, mut sysroot_proc_macros: ProcMacroPaths, -) -> (SysrootPublicDeps, Option) { +) -> (SysrootPublicDeps, Option) { let mut pub_deps = vec![]; let mut libproc_macro = None; let diff = CfgDiff::new(vec![], vec![CfgAtom::Flag(sym::test.clone())]); @@ -1527,11 +1566,11 @@ fn extend_crate_graph_with_sysroot( // uninject `test` flag so `core` keeps working. Arc::make_mut(&mut c.cfg_options).apply_diff(diff.clone()); // patch the origin - if c.origin.is_local() { + if c.basic.origin.is_local() { let lang_crate = LangCrateOrigin::from( - c.display_name.as_ref().map_or("", |it| it.canonical_name().as_str()), + c.extra.display_name.as_ref().map_or("", |it| it.canonical_name().as_str()), ); - c.origin = CrateOrigin::Lang(lang_crate); + c.basic.origin = CrateOrigin::Lang(lang_crate); match lang_crate { LangCrateOrigin::Test | LangCrateOrigin::Alloc @@ -1579,11 +1618,12 @@ fn extend_crate_graph_with_sysroot( } fn sysroot_to_crate_graph( - crate_graph: &mut CrateGraph, + crate_graph: &mut CrateGraphBuilder, sysroot: &Sysroot, rustc_cfg: Vec, load: FileLoader<'_>, -) -> (SysrootPublicDeps, Option) { + crate_ws_data: Arc, +) -> (SysrootPublicDeps, Option) { let _p = tracing::info_span!("sysroot_to_crate_graph").entered(); match sysroot.workspace() { RustLibSrcWorkspace::Workspace(cargo) => { @@ -1605,6 +1645,7 @@ fn sysroot_to_crate_graph( }, &WorkspaceBuildScripts::default(), false, + crate_ws_data, ); extend_crate_graph_with_sysroot(crate_graph, cg, pm) @@ -1627,6 +1668,7 @@ fn sysroot_to_crate_graph( ..Default::default() }, false, + crate_ws_data, ); extend_crate_graph_with_sysroot(crate_graph, cg, pm) @@ -1639,29 +1681,31 @@ fn sysroot_to_crate_graph( cfg_options.insert_atom(sym::miri.clone()); cfg_options }); - let sysroot_crates: FxHashMap = - stitched - .crates() - .filter_map(|krate| { - let file_id = load(&stitched[krate].root)?; + let sysroot_crates: FxHashMap< + crate::sysroot::stitched::RustLibSrcCrate, + CrateBuilderId, + > = stitched + .crates() + .filter_map(|krate| { + let file_id = load(&stitched[krate].root)?; - let display_name = - CrateDisplayName::from_canonical_name(&stitched[krate].name); - let crate_id = crate_graph.add_crate_root( - file_id, - Edition::CURRENT_FIXME, - Some(display_name), - None, - cfg_options.clone(), - None, - Env::default(), - CrateOrigin::Lang(LangCrateOrigin::from(&*stitched[krate].name)), - false, - None, - ); - Some((krate, crate_id)) - }) - .collect(); + let display_name = CrateDisplayName::from_canonical_name(&stitched[krate].name); + let crate_id = crate_graph.add_crate_root( + file_id, + Edition::CURRENT_FIXME, + Some(display_name), + None, + cfg_options.clone(), + None, + Env::default(), + CrateOrigin::Lang(LangCrateOrigin::from(&*stitched[krate].name)), + false, + None, + crate_ws_data.clone(), + ); + Some((krate, crate_id)) + }) + .collect(); for from in stitched.crates() { for &to in stitched[from].deps.iter() { @@ -1691,22 +1735,32 @@ fn sysroot_to_crate_graph( } } -fn add_dep(graph: &mut CrateGraph, from: CrateId, name: CrateName, to: CrateId) { - add_dep_inner(graph, from, Dependency::new(name, to)) +fn add_dep( + graph: &mut CrateGraphBuilder, + from: CrateBuilderId, + name: CrateName, + to: CrateBuilderId, +) { + add_dep_inner(graph, from, DependencyBuilder::new(name, to)) } fn add_dep_with_prelude( - graph: &mut CrateGraph, - from: CrateId, + graph: &mut CrateGraphBuilder, + from: CrateBuilderId, name: CrateName, - to: CrateId, + to: CrateBuilderId, prelude: bool, sysroot: bool, ) { - add_dep_inner(graph, from, Dependency::with_prelude(name, to, prelude, sysroot)) + add_dep_inner(graph, from, DependencyBuilder::with_prelude(name, to, prelude, sysroot)) } -fn add_proc_macro_dep(crate_graph: &mut CrateGraph, from: CrateId, to: CrateId, prelude: bool) { +fn add_proc_macro_dep( + crate_graph: &mut CrateGraphBuilder, + from: CrateBuilderId, + to: CrateBuilderId, + prelude: bool, +) { add_dep_with_prelude( crate_graph, from, @@ -1717,7 +1771,7 @@ fn add_proc_macro_dep(crate_graph: &mut CrateGraph, from: CrateId, to: CrateId, ); } -fn add_dep_inner(graph: &mut CrateGraph, from: CrateId, dep: Dependency) { +fn add_dep_inner(graph: &mut CrateGraphBuilder, from: CrateBuilderId, dep: DependencyBuilder) { if let Err(err) = graph.add_dep(from, dep) { tracing::warn!("{}", err) } diff --git a/crates/project-model/test_data/output/cargo_hello_world_project_model.txt b/crates/project-model/test_data/output/cargo_hello_world_project_model.txt index fae0b6fcca..ae842bf704 100644 --- a/crates/project-model/test_data/output/cargo_hello_world_project_model.txt +++ b/crates/project-model/test_data/output/cargo_hello_world_project_model.txt @@ -1,20 +1,47 @@ { - 0: CrateData { - root_file_id: FileId( - 1, - ), - edition: Edition2018, - version: Some( - "0.1.0", - ), - display_name: Some( - CrateDisplayName { - crate_name: CrateName( - "hello_world", + 0: CrateBuilder { + basic: CrateData { + root_file_id: FileId( + 1, + ), + edition: Edition2018, + dependencies: [ + Dependency { + crate_id: Idx::(4), + name: CrateName( + "libc", + ), + prelude: true, + sysroot: false, + }, + ], + origin: Local { + repo: None, + name: Some( + "hello-world", ), - canonical_name: "hello-world", }, - ), + is_proc_macro: false, + proc_macro_cwd: Some( + AbsPathBuf( + "$ROOT$hello-world", + ), + ), + }, + extra: ExtraCrateData { + version: Some( + "0.1.0", + ), + display_name: Some( + CrateDisplayName { + crate_name: CrateName( + "hello_world", + ), + canonical_name: "hello-world", + }, + ), + potential_cfg_options: None, + }, cfg_options: CfgOptions( [ "rust_analyzer", @@ -22,7 +49,6 @@ "true", ], ), - potential_cfg_options: None, env: Env { entries: { "CARGO": "$CARGO$", @@ -44,45 +70,64 @@ "CARGO_PKG_VERSION_PRE": "", }, }, - dependencies: [ - Dependency { - crate_id: Idx::(4), - name: CrateName( - "libc", + ws_data: CrateWorkspaceData { + data_layout: Err( + "target_data_layout not loaded", + ), + toolchain: None, + }, + }, + 1: CrateBuilder { + basic: CrateData { + root_file_id: FileId( + 2, + ), + edition: Edition2018, + dependencies: [ + Dependency { + crate_id: Idx::(0), + name: CrateName( + "hello_world", + ), + prelude: true, + sysroot: false, + }, + Dependency { + crate_id: Idx::(4), + name: CrateName( + "libc", + ), + prelude: true, + sysroot: false, + }, + ], + origin: Local { + repo: None, + name: Some( + "hello-world", ), - prelude: true, - sysroot: false, }, - ], - origin: Local { - repo: None, - name: Some( - "hello-world", + is_proc_macro: false, + proc_macro_cwd: Some( + AbsPathBuf( + "$ROOT$hello-world", + ), ), }, - is_proc_macro: false, - proc_macro_cwd: Some( - AbsPathBuf( - "$ROOT$hello-world", + extra: ExtraCrateData { + version: Some( + "0.1.0", ), - ), - }, - 1: CrateData { - root_file_id: FileId( - 2, - ), - edition: Edition2018, - version: Some( - "0.1.0", - ), - display_name: Some( - CrateDisplayName { - crate_name: CrateName( - "hello_world", - ), - canonical_name: "hello-world", - }, - ), + display_name: Some( + CrateDisplayName { + crate_name: CrateName( + "hello_world", + ), + canonical_name: "hello-world", + }, + ), + potential_cfg_options: None, + }, cfg_options: CfgOptions( [ "rust_analyzer", @@ -90,7 +135,6 @@ "true", ], ), - potential_cfg_options: None, env: Env { entries: { "CARGO": "$CARGO$", @@ -112,53 +156,64 @@ "CARGO_PKG_VERSION_PRE": "", }, }, - dependencies: [ - Dependency { - crate_id: Idx::(0), - name: CrateName( - "hello_world", + ws_data: CrateWorkspaceData { + data_layout: Err( + "target_data_layout not loaded", + ), + toolchain: None, + }, + }, + 2: CrateBuilder { + basic: CrateData { + root_file_id: FileId( + 3, + ), + edition: Edition2018, + dependencies: [ + Dependency { + crate_id: Idx::(0), + name: CrateName( + "hello_world", + ), + prelude: true, + sysroot: false, + }, + Dependency { + crate_id: Idx::(4), + name: CrateName( + "libc", + ), + prelude: true, + sysroot: false, + }, + ], + origin: Local { + repo: None, + name: Some( + "hello-world", ), - prelude: true, - sysroot: false, }, - Dependency { - crate_id: Idx::(4), - name: CrateName( - "libc", + is_proc_macro: false, + proc_macro_cwd: Some( + AbsPathBuf( + "$ROOT$hello-world", ), - prelude: true, - sysroot: false, - }, - ], - origin: Local { - repo: None, - name: Some( - "hello-world", ), }, - is_proc_macro: false, - proc_macro_cwd: Some( - AbsPathBuf( - "$ROOT$hello-world", + extra: ExtraCrateData { + version: Some( + "0.1.0", ), - ), - }, - 2: CrateData { - root_file_id: FileId( - 3, - ), - edition: Edition2018, - version: Some( - "0.1.0", - ), - display_name: Some( - CrateDisplayName { - crate_name: CrateName( - "an_example", - ), - canonical_name: "an-example", - }, - ), + display_name: Some( + CrateDisplayName { + crate_name: CrateName( + "an_example", + ), + canonical_name: "an-example", + }, + ), + potential_cfg_options: None, + }, cfg_options: CfgOptions( [ "rust_analyzer", @@ -166,7 +221,6 @@ "true", ], ), - potential_cfg_options: None, env: Env { entries: { "CARGO": "$CARGO$", @@ -188,53 +242,64 @@ "CARGO_PKG_VERSION_PRE": "", }, }, - dependencies: [ - Dependency { - crate_id: Idx::(0), - name: CrateName( - "hello_world", + ws_data: CrateWorkspaceData { + data_layout: Err( + "target_data_layout not loaded", + ), + toolchain: None, + }, + }, + 3: CrateBuilder { + basic: CrateData { + root_file_id: FileId( + 4, + ), + edition: Edition2018, + dependencies: [ + Dependency { + crate_id: Idx::(0), + name: CrateName( + "hello_world", + ), + prelude: true, + sysroot: false, + }, + Dependency { + crate_id: Idx::(4), + name: CrateName( + "libc", + ), + prelude: true, + sysroot: false, + }, + ], + origin: Local { + repo: None, + name: Some( + "hello-world", ), - prelude: true, - sysroot: false, }, - Dependency { - crate_id: Idx::(4), - name: CrateName( - "libc", + is_proc_macro: false, + proc_macro_cwd: Some( + AbsPathBuf( + "$ROOT$hello-world", ), - prelude: true, - sysroot: false, - }, - ], - origin: Local { - repo: None, - name: Some( - "hello-world", ), }, - is_proc_macro: false, - proc_macro_cwd: Some( - AbsPathBuf( - "$ROOT$hello-world", + extra: ExtraCrateData { + version: Some( + "0.1.0", ), - ), - }, - 3: CrateData { - root_file_id: FileId( - 4, - ), - edition: Edition2018, - version: Some( - "0.1.0", - ), - display_name: Some( - CrateDisplayName { - crate_name: CrateName( - "it", - ), - canonical_name: "it", - }, - ), + display_name: Some( + CrateDisplayName { + crate_name: CrateName( + "it", + ), + canonical_name: "it", + }, + ), + potential_cfg_options: None, + }, cfg_options: CfgOptions( [ "rust_analyzer", @@ -242,7 +307,6 @@ "true", ], ), - potential_cfg_options: None, env: Env { entries: { "CARGO": "$CARGO$", @@ -264,53 +328,60 @@ "CARGO_PKG_VERSION_PRE": "", }, }, - dependencies: [ - Dependency { - crate_id: Idx::(0), - name: CrateName( - "hello_world", + ws_data: CrateWorkspaceData { + data_layout: Err( + "target_data_layout not loaded", + ), + toolchain: None, + }, + }, + 4: CrateBuilder { + basic: CrateData { + root_file_id: FileId( + 5, + ), + edition: Edition2015, + dependencies: [], + origin: Library { + repo: Some( + "https://github.com/rust-lang/libc", ), - prelude: true, - sysroot: false, + name: "libc", }, - Dependency { - crate_id: Idx::(4), - name: CrateName( - "libc", + is_proc_macro: false, + proc_macro_cwd: Some( + AbsPathBuf( + "$ROOT$.cargo/registry/src/github.com-1ecc6299db9ec823/libc-0.2.98", ), - prelude: true, - sysroot: false, - }, - ], - origin: Local { - repo: None, - name: Some( - "hello-world", ), }, - is_proc_macro: false, - proc_macro_cwd: Some( - AbsPathBuf( - "$ROOT$hello-world", + extra: ExtraCrateData { + version: Some( + "0.2.98", ), - ), - }, - 4: CrateData { - root_file_id: FileId( - 5, - ), - edition: Edition2015, - version: Some( - "0.2.98", - ), - display_name: Some( - CrateDisplayName { - crate_name: CrateName( - "libc", + display_name: Some( + CrateDisplayName { + crate_name: CrateName( + "libc", + ), + canonical_name: "libc", + }, + ), + potential_cfg_options: Some( + CfgOptions( + [ + "feature=align", + "feature=const-extern-fn", + "feature=default", + "feature=extra_traits", + "feature=rustc-dep-of-std", + "feature=std", + "feature=use_std", + "true", + ], ), - canonical_name: "libc", - }, - ), + ), + }, cfg_options: CfgOptions( [ "feature=default", @@ -318,20 +389,6 @@ "true", ], ), - potential_cfg_options: Some( - CfgOptions( - [ - "feature=align", - "feature=const-extern-fn", - "feature=default", - "feature=extra_traits", - "feature=rustc-dep-of-std", - "feature=std", - "feature=use_std", - "true", - ], - ), - ), env: Env { entries: { "CARGO": "$CARGO$", @@ -353,18 +410,11 @@ "CARGO_PKG_VERSION_PRE": "", }, }, - dependencies: [], - origin: Library { - repo: Some( - "https://github.com/rust-lang/libc", + ws_data: CrateWorkspaceData { + data_layout: Err( + "target_data_layout not loaded", ), - name: "libc", + toolchain: None, }, - is_proc_macro: false, - proc_macro_cwd: Some( - AbsPathBuf( - "$ROOT$.cargo/registry/src/github.com-1ecc6299db9ec823/libc-0.2.98", - ), - ), }, } \ No newline at end of file diff --git a/crates/project-model/test_data/output/cargo_hello_world_project_model_with_selective_overrides.txt b/crates/project-model/test_data/output/cargo_hello_world_project_model_with_selective_overrides.txt index fae0b6fcca..ae842bf704 100644 --- a/crates/project-model/test_data/output/cargo_hello_world_project_model_with_selective_overrides.txt +++ b/crates/project-model/test_data/output/cargo_hello_world_project_model_with_selective_overrides.txt @@ -1,20 +1,47 @@ { - 0: CrateData { - root_file_id: FileId( - 1, - ), - edition: Edition2018, - version: Some( - "0.1.0", - ), - display_name: Some( - CrateDisplayName { - crate_name: CrateName( - "hello_world", + 0: CrateBuilder { + basic: CrateData { + root_file_id: FileId( + 1, + ), + edition: Edition2018, + dependencies: [ + Dependency { + crate_id: Idx::(4), + name: CrateName( + "libc", + ), + prelude: true, + sysroot: false, + }, + ], + origin: Local { + repo: None, + name: Some( + "hello-world", ), - canonical_name: "hello-world", }, - ), + is_proc_macro: false, + proc_macro_cwd: Some( + AbsPathBuf( + "$ROOT$hello-world", + ), + ), + }, + extra: ExtraCrateData { + version: Some( + "0.1.0", + ), + display_name: Some( + CrateDisplayName { + crate_name: CrateName( + "hello_world", + ), + canonical_name: "hello-world", + }, + ), + potential_cfg_options: None, + }, cfg_options: CfgOptions( [ "rust_analyzer", @@ -22,7 +49,6 @@ "true", ], ), - potential_cfg_options: None, env: Env { entries: { "CARGO": "$CARGO$", @@ -44,45 +70,64 @@ "CARGO_PKG_VERSION_PRE": "", }, }, - dependencies: [ - Dependency { - crate_id: Idx::(4), - name: CrateName( - "libc", + ws_data: CrateWorkspaceData { + data_layout: Err( + "target_data_layout not loaded", + ), + toolchain: None, + }, + }, + 1: CrateBuilder { + basic: CrateData { + root_file_id: FileId( + 2, + ), + edition: Edition2018, + dependencies: [ + Dependency { + crate_id: Idx::(0), + name: CrateName( + "hello_world", + ), + prelude: true, + sysroot: false, + }, + Dependency { + crate_id: Idx::(4), + name: CrateName( + "libc", + ), + prelude: true, + sysroot: false, + }, + ], + origin: Local { + repo: None, + name: Some( + "hello-world", ), - prelude: true, - sysroot: false, }, - ], - origin: Local { - repo: None, - name: Some( - "hello-world", + is_proc_macro: false, + proc_macro_cwd: Some( + AbsPathBuf( + "$ROOT$hello-world", + ), ), }, - is_proc_macro: false, - proc_macro_cwd: Some( - AbsPathBuf( - "$ROOT$hello-world", + extra: ExtraCrateData { + version: Some( + "0.1.0", ), - ), - }, - 1: CrateData { - root_file_id: FileId( - 2, - ), - edition: Edition2018, - version: Some( - "0.1.0", - ), - display_name: Some( - CrateDisplayName { - crate_name: CrateName( - "hello_world", - ), - canonical_name: "hello-world", - }, - ), + display_name: Some( + CrateDisplayName { + crate_name: CrateName( + "hello_world", + ), + canonical_name: "hello-world", + }, + ), + potential_cfg_options: None, + }, cfg_options: CfgOptions( [ "rust_analyzer", @@ -90,7 +135,6 @@ "true", ], ), - potential_cfg_options: None, env: Env { entries: { "CARGO": "$CARGO$", @@ -112,53 +156,64 @@ "CARGO_PKG_VERSION_PRE": "", }, }, - dependencies: [ - Dependency { - crate_id: Idx::(0), - name: CrateName( - "hello_world", + ws_data: CrateWorkspaceData { + data_layout: Err( + "target_data_layout not loaded", + ), + toolchain: None, + }, + }, + 2: CrateBuilder { + basic: CrateData { + root_file_id: FileId( + 3, + ), + edition: Edition2018, + dependencies: [ + Dependency { + crate_id: Idx::(0), + name: CrateName( + "hello_world", + ), + prelude: true, + sysroot: false, + }, + Dependency { + crate_id: Idx::(4), + name: CrateName( + "libc", + ), + prelude: true, + sysroot: false, + }, + ], + origin: Local { + repo: None, + name: Some( + "hello-world", ), - prelude: true, - sysroot: false, }, - Dependency { - crate_id: Idx::(4), - name: CrateName( - "libc", + is_proc_macro: false, + proc_macro_cwd: Some( + AbsPathBuf( + "$ROOT$hello-world", ), - prelude: true, - sysroot: false, - }, - ], - origin: Local { - repo: None, - name: Some( - "hello-world", ), }, - is_proc_macro: false, - proc_macro_cwd: Some( - AbsPathBuf( - "$ROOT$hello-world", + extra: ExtraCrateData { + version: Some( + "0.1.0", ), - ), - }, - 2: CrateData { - root_file_id: FileId( - 3, - ), - edition: Edition2018, - version: Some( - "0.1.0", - ), - display_name: Some( - CrateDisplayName { - crate_name: CrateName( - "an_example", - ), - canonical_name: "an-example", - }, - ), + display_name: Some( + CrateDisplayName { + crate_name: CrateName( + "an_example", + ), + canonical_name: "an-example", + }, + ), + potential_cfg_options: None, + }, cfg_options: CfgOptions( [ "rust_analyzer", @@ -166,7 +221,6 @@ "true", ], ), - potential_cfg_options: None, env: Env { entries: { "CARGO": "$CARGO$", @@ -188,53 +242,64 @@ "CARGO_PKG_VERSION_PRE": "", }, }, - dependencies: [ - Dependency { - crate_id: Idx::(0), - name: CrateName( - "hello_world", + ws_data: CrateWorkspaceData { + data_layout: Err( + "target_data_layout not loaded", + ), + toolchain: None, + }, + }, + 3: CrateBuilder { + basic: CrateData { + root_file_id: FileId( + 4, + ), + edition: Edition2018, + dependencies: [ + Dependency { + crate_id: Idx::(0), + name: CrateName( + "hello_world", + ), + prelude: true, + sysroot: false, + }, + Dependency { + crate_id: Idx::(4), + name: CrateName( + "libc", + ), + prelude: true, + sysroot: false, + }, + ], + origin: Local { + repo: None, + name: Some( + "hello-world", ), - prelude: true, - sysroot: false, }, - Dependency { - crate_id: Idx::(4), - name: CrateName( - "libc", + is_proc_macro: false, + proc_macro_cwd: Some( + AbsPathBuf( + "$ROOT$hello-world", ), - prelude: true, - sysroot: false, - }, - ], - origin: Local { - repo: None, - name: Some( - "hello-world", ), }, - is_proc_macro: false, - proc_macro_cwd: Some( - AbsPathBuf( - "$ROOT$hello-world", + extra: ExtraCrateData { + version: Some( + "0.1.0", ), - ), - }, - 3: CrateData { - root_file_id: FileId( - 4, - ), - edition: Edition2018, - version: Some( - "0.1.0", - ), - display_name: Some( - CrateDisplayName { - crate_name: CrateName( - "it", - ), - canonical_name: "it", - }, - ), + display_name: Some( + CrateDisplayName { + crate_name: CrateName( + "it", + ), + canonical_name: "it", + }, + ), + potential_cfg_options: None, + }, cfg_options: CfgOptions( [ "rust_analyzer", @@ -242,7 +307,6 @@ "true", ], ), - potential_cfg_options: None, env: Env { entries: { "CARGO": "$CARGO$", @@ -264,53 +328,60 @@ "CARGO_PKG_VERSION_PRE": "", }, }, - dependencies: [ - Dependency { - crate_id: Idx::(0), - name: CrateName( - "hello_world", + ws_data: CrateWorkspaceData { + data_layout: Err( + "target_data_layout not loaded", + ), + toolchain: None, + }, + }, + 4: CrateBuilder { + basic: CrateData { + root_file_id: FileId( + 5, + ), + edition: Edition2015, + dependencies: [], + origin: Library { + repo: Some( + "https://github.com/rust-lang/libc", ), - prelude: true, - sysroot: false, + name: "libc", }, - Dependency { - crate_id: Idx::(4), - name: CrateName( - "libc", + is_proc_macro: false, + proc_macro_cwd: Some( + AbsPathBuf( + "$ROOT$.cargo/registry/src/github.com-1ecc6299db9ec823/libc-0.2.98", ), - prelude: true, - sysroot: false, - }, - ], - origin: Local { - repo: None, - name: Some( - "hello-world", ), }, - is_proc_macro: false, - proc_macro_cwd: Some( - AbsPathBuf( - "$ROOT$hello-world", + extra: ExtraCrateData { + version: Some( + "0.2.98", ), - ), - }, - 4: CrateData { - root_file_id: FileId( - 5, - ), - edition: Edition2015, - version: Some( - "0.2.98", - ), - display_name: Some( - CrateDisplayName { - crate_name: CrateName( - "libc", + display_name: Some( + CrateDisplayName { + crate_name: CrateName( + "libc", + ), + canonical_name: "libc", + }, + ), + potential_cfg_options: Some( + CfgOptions( + [ + "feature=align", + "feature=const-extern-fn", + "feature=default", + "feature=extra_traits", + "feature=rustc-dep-of-std", + "feature=std", + "feature=use_std", + "true", + ], ), - canonical_name: "libc", - }, - ), + ), + }, cfg_options: CfgOptions( [ "feature=default", @@ -318,20 +389,6 @@ "true", ], ), - potential_cfg_options: Some( - CfgOptions( - [ - "feature=align", - "feature=const-extern-fn", - "feature=default", - "feature=extra_traits", - "feature=rustc-dep-of-std", - "feature=std", - "feature=use_std", - "true", - ], - ), - ), env: Env { entries: { "CARGO": "$CARGO$", @@ -353,18 +410,11 @@ "CARGO_PKG_VERSION_PRE": "", }, }, - dependencies: [], - origin: Library { - repo: Some( - "https://github.com/rust-lang/libc", + ws_data: CrateWorkspaceData { + data_layout: Err( + "target_data_layout not loaded", ), - name: "libc", + toolchain: None, }, - is_proc_macro: false, - proc_macro_cwd: Some( - AbsPathBuf( - "$ROOT$.cargo/registry/src/github.com-1ecc6299db9ec823/libc-0.2.98", - ), - ), }, } \ No newline at end of file diff --git a/crates/project-model/test_data/output/cargo_hello_world_project_model_with_wildcard_overrides.txt b/crates/project-model/test_data/output/cargo_hello_world_project_model_with_wildcard_overrides.txt index 566174882d..272cd69cb1 100644 --- a/crates/project-model/test_data/output/cargo_hello_world_project_model_with_wildcard_overrides.txt +++ b/crates/project-model/test_data/output/cargo_hello_world_project_model_with_wildcard_overrides.txt @@ -1,27 +1,53 @@ { - 0: CrateData { - root_file_id: FileId( - 1, - ), - edition: Edition2018, - version: Some( - "0.1.0", - ), - display_name: Some( - CrateDisplayName { - crate_name: CrateName( - "hello_world", + 0: CrateBuilder { + basic: CrateData { + root_file_id: FileId( + 1, + ), + edition: Edition2018, + dependencies: [ + Dependency { + crate_id: Idx::(4), + name: CrateName( + "libc", + ), + prelude: true, + sysroot: false, + }, + ], + origin: Local { + repo: None, + name: Some( + "hello-world", ), - canonical_name: "hello-world", }, - ), + is_proc_macro: false, + proc_macro_cwd: Some( + AbsPathBuf( + "$ROOT$hello-world", + ), + ), + }, + extra: ExtraCrateData { + version: Some( + "0.1.0", + ), + display_name: Some( + CrateDisplayName { + crate_name: CrateName( + "hello_world", + ), + canonical_name: "hello-world", + }, + ), + potential_cfg_options: None, + }, cfg_options: CfgOptions( [ "rust_analyzer", "true", ], ), - potential_cfg_options: None, env: Env { entries: { "CARGO": "$CARGO$", @@ -43,52 +69,70 @@ "CARGO_PKG_VERSION_PRE": "", }, }, - dependencies: [ - Dependency { - crate_id: Idx::(4), - name: CrateName( - "libc", + ws_data: CrateWorkspaceData { + data_layout: Err( + "target_data_layout not loaded", + ), + toolchain: None, + }, + }, + 1: CrateBuilder { + basic: CrateData { + root_file_id: FileId( + 2, + ), + edition: Edition2018, + dependencies: [ + Dependency { + crate_id: Idx::(0), + name: CrateName( + "hello_world", + ), + prelude: true, + sysroot: false, + }, + Dependency { + crate_id: Idx::(4), + name: CrateName( + "libc", + ), + prelude: true, + sysroot: false, + }, + ], + origin: Local { + repo: None, + name: Some( + "hello-world", ), - prelude: true, - sysroot: false, }, - ], - origin: Local { - repo: None, - name: Some( - "hello-world", + is_proc_macro: false, + proc_macro_cwd: Some( + AbsPathBuf( + "$ROOT$hello-world", + ), ), }, - is_proc_macro: false, - proc_macro_cwd: Some( - AbsPathBuf( - "$ROOT$hello-world", + extra: ExtraCrateData { + version: Some( + "0.1.0", ), - ), - }, - 1: CrateData { - root_file_id: FileId( - 2, - ), - edition: Edition2018, - version: Some( - "0.1.0", - ), - display_name: Some( - CrateDisplayName { - crate_name: CrateName( - "hello_world", - ), - canonical_name: "hello-world", - }, - ), + display_name: Some( + CrateDisplayName { + crate_name: CrateName( + "hello_world", + ), + canonical_name: "hello-world", + }, + ), + potential_cfg_options: None, + }, cfg_options: CfgOptions( [ "rust_analyzer", "true", ], ), - potential_cfg_options: None, env: Env { entries: { "CARGO": "$CARGO$", @@ -110,60 +154,70 @@ "CARGO_PKG_VERSION_PRE": "", }, }, - dependencies: [ - Dependency { - crate_id: Idx::(0), - name: CrateName( - "hello_world", + ws_data: CrateWorkspaceData { + data_layout: Err( + "target_data_layout not loaded", + ), + toolchain: None, + }, + }, + 2: CrateBuilder { + basic: CrateData { + root_file_id: FileId( + 3, + ), + edition: Edition2018, + dependencies: [ + Dependency { + crate_id: Idx::(0), + name: CrateName( + "hello_world", + ), + prelude: true, + sysroot: false, + }, + Dependency { + crate_id: Idx::(4), + name: CrateName( + "libc", + ), + prelude: true, + sysroot: false, + }, + ], + origin: Local { + repo: None, + name: Some( + "hello-world", ), - prelude: true, - sysroot: false, }, - Dependency { - crate_id: Idx::(4), - name: CrateName( - "libc", + is_proc_macro: false, + proc_macro_cwd: Some( + AbsPathBuf( + "$ROOT$hello-world", ), - prelude: true, - sysroot: false, - }, - ], - origin: Local { - repo: None, - name: Some( - "hello-world", ), }, - is_proc_macro: false, - proc_macro_cwd: Some( - AbsPathBuf( - "$ROOT$hello-world", + extra: ExtraCrateData { + version: Some( + "0.1.0", ), - ), - }, - 2: CrateData { - root_file_id: FileId( - 3, - ), - edition: Edition2018, - version: Some( - "0.1.0", - ), - display_name: Some( - CrateDisplayName { - crate_name: CrateName( - "an_example", - ), - canonical_name: "an-example", - }, - ), + display_name: Some( + CrateDisplayName { + crate_name: CrateName( + "an_example", + ), + canonical_name: "an-example", + }, + ), + potential_cfg_options: None, + }, cfg_options: CfgOptions( [ "rust_analyzer", "true", ], ), - potential_cfg_options: None, env: Env { entries: { "CARGO": "$CARGO$", @@ -185,60 +239,70 @@ "CARGO_PKG_VERSION_PRE": "", }, }, - dependencies: [ - Dependency { - crate_id: Idx::(0), - name: CrateName( - "hello_world", + ws_data: CrateWorkspaceData { + data_layout: Err( + "target_data_layout not loaded", + ), + toolchain: None, + }, + }, + 3: CrateBuilder { + basic: CrateData { + root_file_id: FileId( + 4, + ), + edition: Edition2018, + dependencies: [ + Dependency { + crate_id: Idx::(0), + name: CrateName( + "hello_world", + ), + prelude: true, + sysroot: false, + }, + Dependency { + crate_id: Idx::(4), + name: CrateName( + "libc", + ), + prelude: true, + sysroot: false, + }, + ], + origin: Local { + repo: None, + name: Some( + "hello-world", ), - prelude: true, - sysroot: false, }, - Dependency { - crate_id: Idx::(4), - name: CrateName( - "libc", + is_proc_macro: false, + proc_macro_cwd: Some( + AbsPathBuf( + "$ROOT$hello-world", ), - prelude: true, - sysroot: false, - }, - ], - origin: Local { - repo: None, - name: Some( - "hello-world", ), }, - is_proc_macro: false, - proc_macro_cwd: Some( - AbsPathBuf( - "$ROOT$hello-world", + extra: ExtraCrateData { + version: Some( + "0.1.0", ), - ), - }, - 3: CrateData { - root_file_id: FileId( - 4, - ), - edition: Edition2018, - version: Some( - "0.1.0", - ), - display_name: Some( - CrateDisplayName { - crate_name: CrateName( - "it", - ), - canonical_name: "it", - }, - ), + display_name: Some( + CrateDisplayName { + crate_name: CrateName( + "it", + ), + canonical_name: "it", + }, + ), + potential_cfg_options: None, + }, cfg_options: CfgOptions( [ "rust_analyzer", "true", ], ), - potential_cfg_options: None, env: Env { entries: { "CARGO": "$CARGO$", @@ -260,53 +324,60 @@ "CARGO_PKG_VERSION_PRE": "", }, }, - dependencies: [ - Dependency { - crate_id: Idx::(0), - name: CrateName( - "hello_world", + ws_data: CrateWorkspaceData { + data_layout: Err( + "target_data_layout not loaded", + ), + toolchain: None, + }, + }, + 4: CrateBuilder { + basic: CrateData { + root_file_id: FileId( + 5, + ), + edition: Edition2015, + dependencies: [], + origin: Library { + repo: Some( + "https://github.com/rust-lang/libc", ), - prelude: true, - sysroot: false, + name: "libc", }, - Dependency { - crate_id: Idx::(4), - name: CrateName( - "libc", + is_proc_macro: false, + proc_macro_cwd: Some( + AbsPathBuf( + "$ROOT$.cargo/registry/src/github.com-1ecc6299db9ec823/libc-0.2.98", ), - prelude: true, - sysroot: false, - }, - ], - origin: Local { - repo: None, - name: Some( - "hello-world", ), }, - is_proc_macro: false, - proc_macro_cwd: Some( - AbsPathBuf( - "$ROOT$hello-world", + extra: ExtraCrateData { + version: Some( + "0.2.98", ), - ), - }, - 4: CrateData { - root_file_id: FileId( - 5, - ), - edition: Edition2015, - version: Some( - "0.2.98", - ), - display_name: Some( - CrateDisplayName { - crate_name: CrateName( - "libc", + display_name: Some( + CrateDisplayName { + crate_name: CrateName( + "libc", + ), + canonical_name: "libc", + }, + ), + potential_cfg_options: Some( + CfgOptions( + [ + "feature=align", + "feature=const-extern-fn", + "feature=default", + "feature=extra_traits", + "feature=rustc-dep-of-std", + "feature=std", + "feature=use_std", + "true", + ], ), - canonical_name: "libc", - }, - ), + ), + }, cfg_options: CfgOptions( [ "feature=default", @@ -314,20 +385,6 @@ "true", ], ), - potential_cfg_options: Some( - CfgOptions( - [ - "feature=align", - "feature=const-extern-fn", - "feature=default", - "feature=extra_traits", - "feature=rustc-dep-of-std", - "feature=std", - "feature=use_std", - "true", - ], - ), - ), env: Env { entries: { "CARGO": "$CARGO$", @@ -349,18 +406,11 @@ "CARGO_PKG_VERSION_PRE": "", }, }, - dependencies: [], - origin: Library { - repo: Some( - "https://github.com/rust-lang/libc", + ws_data: CrateWorkspaceData { + data_layout: Err( + "target_data_layout not loaded", ), - name: "libc", + toolchain: None, }, - is_proc_macro: false, - proc_macro_cwd: Some( - AbsPathBuf( - "$ROOT$.cargo/registry/src/github.com-1ecc6299db9ec823/libc-0.2.98", - ), - ), }, } \ No newline at end of file diff --git a/crates/project-model/test_data/output/rust_project_cfg_groups.txt b/crates/project-model/test_data/output/rust_project_cfg_groups.txt index 9b4be19c41..2b8e521f34 100644 --- a/crates/project-model/test_data/output/rust_project_cfg_groups.txt +++ b/crates/project-model/test_data/output/rust_project_cfg_groups.txt @@ -1,18 +1,38 @@ { - 0: CrateData { - root_file_id: FileId( - 1, - ), - edition: Edition2021, - version: None, - display_name: Some( - CrateDisplayName { - crate_name: CrateName( - "alloc", - ), - canonical_name: "alloc", - }, - ), + 0: CrateBuilder { + basic: CrateData { + root_file_id: FileId( + 1, + ), + edition: Edition2021, + dependencies: [ + Dependency { + crate_id: Idx::(1), + name: CrateName( + "core", + ), + prelude: true, + sysroot: false, + }, + ], + origin: Lang( + Alloc, + ), + is_proc_macro: false, + proc_macro_cwd: None, + }, + extra: ExtraCrateData { + version: None, + display_name: Some( + CrateDisplayName { + crate_name: CrateName( + "alloc", + ), + canonical_name: "alloc", + }, + ), + potential_cfg_options: None, + }, cfg_options: CfgOptions( [ "debug_assertions", @@ -20,40 +40,41 @@ "true", ], ), - potential_cfg_options: None, env: Env { entries: {}, }, - dependencies: [ - Dependency { - crate_id: Idx::(1), - name: CrateName( - "core", - ), - prelude: true, - sysroot: false, - }, - ], - origin: Lang( - Alloc, - ), - is_proc_macro: false, - proc_macro_cwd: None, + ws_data: CrateWorkspaceData { + data_layout: Err( + "test has no data layout", + ), + toolchain: None, + }, }, - 1: CrateData { - root_file_id: FileId( - 2, - ), - edition: Edition2021, - version: None, - display_name: Some( - CrateDisplayName { - crate_name: CrateName( - "core", - ), - canonical_name: "core", - }, - ), + 1: CrateBuilder { + basic: CrateData { + root_file_id: FileId( + 2, + ), + edition: Edition2021, + dependencies: [], + origin: Lang( + Core, + ), + is_proc_macro: false, + proc_macro_cwd: None, + }, + extra: ExtraCrateData { + version: None, + display_name: Some( + CrateDisplayName { + crate_name: CrateName( + "core", + ), + canonical_name: "core", + }, + ), + potential_cfg_options: None, + }, cfg_options: CfgOptions( [ "debug_assertions", @@ -61,31 +82,41 @@ "true", ], ), - potential_cfg_options: None, env: Env { entries: {}, }, - dependencies: [], - origin: Lang( - Core, - ), - is_proc_macro: false, - proc_macro_cwd: None, + ws_data: CrateWorkspaceData { + data_layout: Err( + "test has no data layout", + ), + toolchain: None, + }, }, - 2: CrateData { - root_file_id: FileId( - 3, - ), - edition: Edition2021, - version: None, - display_name: Some( - CrateDisplayName { - crate_name: CrateName( - "panic_abort", - ), - canonical_name: "panic_abort", - }, - ), + 2: CrateBuilder { + basic: CrateData { + root_file_id: FileId( + 3, + ), + edition: Edition2021, + dependencies: [], + origin: Lang( + Other, + ), + is_proc_macro: false, + proc_macro_cwd: None, + }, + extra: ExtraCrateData { + version: None, + display_name: Some( + CrateDisplayName { + crate_name: CrateName( + "panic_abort", + ), + canonical_name: "panic_abort", + }, + ), + potential_cfg_options: None, + }, cfg_options: CfgOptions( [ "debug_assertions", @@ -93,31 +124,41 @@ "true", ], ), - potential_cfg_options: None, env: Env { entries: {}, }, - dependencies: [], - origin: Lang( - Other, - ), - is_proc_macro: false, - proc_macro_cwd: None, + ws_data: CrateWorkspaceData { + data_layout: Err( + "test has no data layout", + ), + toolchain: None, + }, }, - 3: CrateData { - root_file_id: FileId( - 4, - ), - edition: Edition2021, - version: None, - display_name: Some( - CrateDisplayName { - crate_name: CrateName( - "panic_unwind", - ), - canonical_name: "panic_unwind", - }, - ), + 3: CrateBuilder { + basic: CrateData { + root_file_id: FileId( + 4, + ), + edition: Edition2021, + dependencies: [], + origin: Lang( + Other, + ), + is_proc_macro: false, + proc_macro_cwd: None, + }, + extra: ExtraCrateData { + version: None, + display_name: Some( + CrateDisplayName { + crate_name: CrateName( + "panic_unwind", + ), + canonical_name: "panic_unwind", + }, + ), + potential_cfg_options: None, + }, cfg_options: CfgOptions( [ "debug_assertions", @@ -125,31 +166,58 @@ "true", ], ), - potential_cfg_options: None, env: Env { entries: {}, }, - dependencies: [], - origin: Lang( - Other, - ), - is_proc_macro: false, - proc_macro_cwd: None, + ws_data: CrateWorkspaceData { + data_layout: Err( + "test has no data layout", + ), + toolchain: None, + }, }, - 4: CrateData { - root_file_id: FileId( - 5, - ), - edition: Edition2021, - version: None, - display_name: Some( - CrateDisplayName { - crate_name: CrateName( - "proc_macro", - ), - canonical_name: "proc_macro", - }, - ), + 4: CrateBuilder { + basic: CrateData { + root_file_id: FileId( + 5, + ), + edition: Edition2021, + dependencies: [ + Dependency { + crate_id: Idx::(6), + name: CrateName( + "std", + ), + prelude: true, + sysroot: false, + }, + Dependency { + crate_id: Idx::(1), + name: CrateName( + "core", + ), + prelude: true, + sysroot: false, + }, + ], + origin: Lang( + ProcMacro, + ), + is_proc_macro: false, + proc_macro_cwd: None, + }, + extra: ExtraCrateData { + version: None, + display_name: Some( + CrateDisplayName { + crate_name: CrateName( + "proc_macro", + ), + canonical_name: "proc_macro", + }, + ), + potential_cfg_options: None, + }, cfg_options: CfgOptions( [ "debug_assertions", @@ -157,48 +225,41 @@ "true", ], ), - potential_cfg_options: None, env: Env { entries: {}, }, - dependencies: [ - Dependency { - crate_id: Idx::(6), - name: CrateName( - "std", - ), - prelude: true, - sysroot: false, - }, - Dependency { - crate_id: Idx::(1), - name: CrateName( - "core", - ), - prelude: true, - sysroot: false, - }, - ], - origin: Lang( - ProcMacro, - ), - is_proc_macro: false, - proc_macro_cwd: None, + ws_data: CrateWorkspaceData { + data_layout: Err( + "test has no data layout", + ), + toolchain: None, + }, }, - 5: CrateData { - root_file_id: FileId( - 6, - ), - edition: Edition2021, - version: None, - display_name: Some( - CrateDisplayName { - crate_name: CrateName( - "profiler_builtins", - ), - canonical_name: "profiler_builtins", - }, - ), + 5: CrateBuilder { + basic: CrateData { + root_file_id: FileId( + 6, + ), + edition: Edition2021, + dependencies: [], + origin: Lang( + Other, + ), + is_proc_macro: false, + proc_macro_cwd: None, + }, + extra: ExtraCrateData { + version: None, + display_name: Some( + CrateDisplayName { + crate_name: CrateName( + "profiler_builtins", + ), + canonical_name: "profiler_builtins", + }, + ), + potential_cfg_options: None, + }, cfg_options: CfgOptions( [ "debug_assertions", @@ -206,31 +267,106 @@ "true", ], ), - potential_cfg_options: None, env: Env { entries: {}, }, - dependencies: [], - origin: Lang( - Other, - ), - is_proc_macro: false, - proc_macro_cwd: None, + ws_data: CrateWorkspaceData { + data_layout: Err( + "test has no data layout", + ), + toolchain: None, + }, }, - 6: CrateData { - root_file_id: FileId( - 7, - ), - edition: Edition2021, - version: None, - display_name: Some( - CrateDisplayName { - crate_name: CrateName( - "std", - ), - canonical_name: "std", - }, - ), + 6: CrateBuilder { + basic: CrateData { + root_file_id: FileId( + 7, + ), + edition: Edition2021, + dependencies: [ + Dependency { + crate_id: Idx::(0), + name: CrateName( + "alloc", + ), + prelude: true, + sysroot: false, + }, + Dependency { + crate_id: Idx::(3), + name: CrateName( + "panic_unwind", + ), + prelude: true, + sysroot: false, + }, + Dependency { + crate_id: Idx::(2), + name: CrateName( + "panic_abort", + ), + prelude: true, + sysroot: false, + }, + Dependency { + crate_id: Idx::(1), + name: CrateName( + "core", + ), + prelude: true, + sysroot: false, + }, + Dependency { + crate_id: Idx::(5), + name: CrateName( + "profiler_builtins", + ), + prelude: true, + sysroot: false, + }, + Dependency { + crate_id: Idx::(9), + name: CrateName( + "unwind", + ), + prelude: true, + sysroot: false, + }, + Dependency { + crate_id: Idx::(7), + name: CrateName( + "std_detect", + ), + prelude: true, + sysroot: false, + }, + Dependency { + crate_id: Idx::(8), + name: CrateName( + "test", + ), + prelude: true, + sysroot: false, + }, + ], + origin: Lang( + Std, + ), + is_proc_macro: false, + proc_macro_cwd: None, + }, + extra: ExtraCrateData { + version: None, + display_name: Some( + CrateDisplayName { + crate_name: CrateName( + "std", + ), + canonical_name: "std", + }, + ), + potential_cfg_options: None, + }, cfg_options: CfgOptions( [ "debug_assertions", @@ -238,96 +374,41 @@ "true", ], ), - potential_cfg_options: None, env: Env { entries: {}, }, - dependencies: [ - Dependency { - crate_id: Idx::(0), - name: CrateName( - "alloc", - ), - prelude: true, - sysroot: false, - }, - Dependency { - crate_id: Idx::(3), - name: CrateName( - "panic_unwind", - ), - prelude: true, - sysroot: false, - }, - Dependency { - crate_id: Idx::(2), - name: CrateName( - "panic_abort", - ), - prelude: true, - sysroot: false, - }, - Dependency { - crate_id: Idx::(1), - name: CrateName( - "core", - ), - prelude: true, - sysroot: false, - }, - Dependency { - crate_id: Idx::(5), - name: CrateName( - "profiler_builtins", - ), - prelude: true, - sysroot: false, - }, - Dependency { - crate_id: Idx::(9), - name: CrateName( - "unwind", - ), - prelude: true, - sysroot: false, - }, - Dependency { - crate_id: Idx::(7), - name: CrateName( - "std_detect", - ), - prelude: true, - sysroot: false, - }, - Dependency { - crate_id: Idx::(8), - name: CrateName( - "test", - ), - prelude: true, - sysroot: false, - }, - ], - origin: Lang( - Std, - ), - is_proc_macro: false, - proc_macro_cwd: None, + ws_data: CrateWorkspaceData { + data_layout: Err( + "test has no data layout", + ), + toolchain: None, + }, }, - 7: CrateData { - root_file_id: FileId( - 8, - ), - edition: Edition2021, - version: None, - display_name: Some( - CrateDisplayName { - crate_name: CrateName( - "std_detect", - ), - canonical_name: "std_detect", - }, - ), + 7: CrateBuilder { + basic: CrateData { + root_file_id: FileId( + 8, + ), + edition: Edition2021, + dependencies: [], + origin: Lang( + Other, + ), + is_proc_macro: false, + proc_macro_cwd: None, + }, + extra: ExtraCrateData { + version: None, + display_name: Some( + CrateDisplayName { + crate_name: CrateName( + "std_detect", + ), + canonical_name: "std_detect", + }, + ), + potential_cfg_options: None, + }, cfg_options: CfgOptions( [ "debug_assertions", @@ -335,31 +416,41 @@ "true", ], ), - potential_cfg_options: None, env: Env { entries: {}, }, - dependencies: [], - origin: Lang( - Other, - ), - is_proc_macro: false, - proc_macro_cwd: None, + ws_data: CrateWorkspaceData { + data_layout: Err( + "test has no data layout", + ), + toolchain: None, + }, }, - 8: CrateData { - root_file_id: FileId( - 9, - ), - edition: Edition2021, - version: None, - display_name: Some( - CrateDisplayName { - crate_name: CrateName( - "test", - ), - canonical_name: "test", - }, - ), + 8: CrateBuilder { + basic: CrateData { + root_file_id: FileId( + 9, + ), + edition: Edition2021, + dependencies: [], + origin: Lang( + Test, + ), + is_proc_macro: false, + proc_macro_cwd: None, + }, + extra: ExtraCrateData { + version: None, + display_name: Some( + CrateDisplayName { + crate_name: CrateName( + "test", + ), + canonical_name: "test", + }, + ), + potential_cfg_options: None, + }, cfg_options: CfgOptions( [ "debug_assertions", @@ -367,31 +458,41 @@ "true", ], ), - potential_cfg_options: None, env: Env { entries: {}, }, - dependencies: [], - origin: Lang( - Test, - ), - is_proc_macro: false, - proc_macro_cwd: None, + ws_data: CrateWorkspaceData { + data_layout: Err( + "test has no data layout", + ), + toolchain: None, + }, }, - 9: CrateData { - root_file_id: FileId( - 10, - ), - edition: Edition2021, - version: None, - display_name: Some( - CrateDisplayName { - crate_name: CrateName( - "unwind", - ), - canonical_name: "unwind", - }, - ), + 9: CrateBuilder { + basic: CrateData { + root_file_id: FileId( + 10, + ), + edition: Edition2021, + dependencies: [], + origin: Lang( + Other, + ), + is_proc_macro: false, + proc_macro_cwd: None, + }, + extra: ExtraCrateData { + version: None, + display_name: Some( + CrateDisplayName { + crate_name: CrateName( + "unwind", + ), + canonical_name: "unwind", + }, + ), + potential_cfg_options: None, + }, cfg_options: CfgOptions( [ "debug_assertions", @@ -399,31 +500,85 @@ "true", ], ), - potential_cfg_options: None, env: Env { entries: {}, }, - dependencies: [], - origin: Lang( - Other, - ), - is_proc_macro: false, - proc_macro_cwd: None, + ws_data: CrateWorkspaceData { + data_layout: Err( + "test has no data layout", + ), + toolchain: None, + }, }, - 10: CrateData { - root_file_id: FileId( - 11, - ), - edition: Edition2018, - version: None, - display_name: Some( - CrateDisplayName { - crate_name: CrateName( + 10: CrateBuilder { + basic: CrateData { + root_file_id: FileId( + 11, + ), + edition: Edition2018, + dependencies: [ + Dependency { + crate_id: Idx::(1), + name: CrateName( + "core", + ), + prelude: true, + sysroot: true, + }, + Dependency { + crate_id: Idx::(0), + name: CrateName( + "alloc", + ), + prelude: false, + sysroot: true, + }, + Dependency { + crate_id: Idx::(6), + name: CrateName( + "std", + ), + prelude: true, + sysroot: true, + }, + Dependency { + crate_id: Idx::(8), + name: CrateName( + "test", + ), + prelude: false, + sysroot: true, + }, + Dependency { + crate_id: Idx::(4), + name: CrateName( + "proc_macro", + ), + prelude: false, + sysroot: true, + }, + ], + origin: Local { + repo: None, + name: Some( "hello_world", ), - canonical_name: "hello_world", }, - ), + is_proc_macro: false, + proc_macro_cwd: None, + }, + extra: ExtraCrateData { + version: None, + display_name: Some( + CrateDisplayName { + crate_name: CrateName( + "hello_world", + ), + canonical_name: "hello_world", + }, + ), + potential_cfg_options: None, + }, cfg_options: CfgOptions( [ "group1_cfg=some_config", @@ -434,75 +589,85 @@ "true", ], ), - potential_cfg_options: None, env: Env { entries: {}, }, - dependencies: [ - Dependency { - crate_id: Idx::(1), - name: CrateName( - "core", - ), - prelude: true, - sysroot: true, - }, - Dependency { - crate_id: Idx::(0), - name: CrateName( - "alloc", - ), - prelude: false, - sysroot: true, - }, - Dependency { - crate_id: Idx::(6), - name: CrateName( - "std", - ), - prelude: true, - sysroot: true, - }, - Dependency { - crate_id: Idx::(8), - name: CrateName( - "test", - ), - prelude: false, - sysroot: true, - }, - Dependency { - crate_id: Idx::(4), - name: CrateName( - "proc_macro", - ), - prelude: false, - sysroot: true, - }, - ], - origin: Local { - repo: None, - name: Some( - "hello_world", + ws_data: CrateWorkspaceData { + data_layout: Err( + "test has no data layout", ), + toolchain: None, }, - is_proc_macro: false, - proc_macro_cwd: None, }, - 11: CrateData { - root_file_id: FileId( - 11, - ), - edition: Edition2018, - version: None, - display_name: Some( - CrateDisplayName { - crate_name: CrateName( + 11: CrateBuilder { + basic: CrateData { + root_file_id: FileId( + 11, + ), + edition: Edition2018, + dependencies: [ + Dependency { + crate_id: Idx::(1), + name: CrateName( + "core", + ), + prelude: true, + sysroot: true, + }, + Dependency { + crate_id: Idx::(0), + name: CrateName( + "alloc", + ), + prelude: false, + sysroot: true, + }, + Dependency { + crate_id: Idx::(6), + name: CrateName( + "std", + ), + prelude: true, + sysroot: true, + }, + Dependency { + crate_id: Idx::(8), + name: CrateName( + "test", + ), + prelude: false, + sysroot: true, + }, + Dependency { + crate_id: Idx::(4), + name: CrateName( + "proc_macro", + ), + prelude: false, + sysroot: true, + }, + ], + origin: Local { + repo: None, + name: Some( "other_crate", ), - canonical_name: "other_crate", }, - ), + is_proc_macro: false, + proc_macro_cwd: None, + }, + extra: ExtraCrateData { + version: None, + display_name: Some( + CrateDisplayName { + crate_name: CrateName( + "other_crate", + ), + canonical_name: "other_crate", + }, + ), + potential_cfg_options: None, + }, cfg_options: CfgOptions( [ "group2_cfg=fourth_config", @@ -513,59 +678,14 @@ "unrelated_cfg", ], ), - potential_cfg_options: None, env: Env { entries: {}, }, - dependencies: [ - Dependency { - crate_id: Idx::(1), - name: CrateName( - "core", - ), - prelude: true, - sysroot: true, - }, - Dependency { - crate_id: Idx::(0), - name: CrateName( - "alloc", - ), - prelude: false, - sysroot: true, - }, - Dependency { - crate_id: Idx::(6), - name: CrateName( - "std", - ), - prelude: true, - sysroot: true, - }, - Dependency { - crate_id: Idx::(8), - name: CrateName( - "test", - ), - prelude: false, - sysroot: true, - }, - Dependency { - crate_id: Idx::(4), - name: CrateName( - "proc_macro", - ), - prelude: false, - sysroot: true, - }, - ], - origin: Local { - repo: None, - name: Some( - "other_crate", + ws_data: CrateWorkspaceData { + data_layout: Err( + "test has no data layout", ), + toolchain: None, }, - is_proc_macro: false, - proc_macro_cwd: None, }, } \ No newline at end of file diff --git a/crates/project-model/test_data/output/rust_project_hello_world_project_model.txt b/crates/project-model/test_data/output/rust_project_hello_world_project_model.txt index 4c8e66e8e9..053e9473cf 100644 --- a/crates/project-model/test_data/output/rust_project_hello_world_project_model.txt +++ b/crates/project-model/test_data/output/rust_project_hello_world_project_model.txt @@ -1,18 +1,38 @@ { - 0: CrateData { - root_file_id: FileId( - 1, - ), - edition: Edition2021, - version: None, - display_name: Some( - CrateDisplayName { - crate_name: CrateName( - "alloc", - ), - canonical_name: "alloc", - }, - ), + 0: CrateBuilder { + basic: CrateData { + root_file_id: FileId( + 1, + ), + edition: Edition2021, + dependencies: [ + Dependency { + crate_id: Idx::(1), + name: CrateName( + "core", + ), + prelude: true, + sysroot: false, + }, + ], + origin: Lang( + Alloc, + ), + is_proc_macro: false, + proc_macro_cwd: None, + }, + extra: ExtraCrateData { + version: None, + display_name: Some( + CrateDisplayName { + crate_name: CrateName( + "alloc", + ), + canonical_name: "alloc", + }, + ), + potential_cfg_options: None, + }, cfg_options: CfgOptions( [ "debug_assertions", @@ -20,40 +40,41 @@ "true", ], ), - potential_cfg_options: None, env: Env { entries: {}, }, - dependencies: [ - Dependency { - crate_id: Idx::(1), - name: CrateName( - "core", - ), - prelude: true, - sysroot: false, - }, - ], - origin: Lang( - Alloc, - ), - is_proc_macro: false, - proc_macro_cwd: None, + ws_data: CrateWorkspaceData { + data_layout: Err( + "test has no data layout", + ), + toolchain: None, + }, }, - 1: CrateData { - root_file_id: FileId( - 2, - ), - edition: Edition2021, - version: None, - display_name: Some( - CrateDisplayName { - crate_name: CrateName( - "core", - ), - canonical_name: "core", - }, - ), + 1: CrateBuilder { + basic: CrateData { + root_file_id: FileId( + 2, + ), + edition: Edition2021, + dependencies: [], + origin: Lang( + Core, + ), + is_proc_macro: false, + proc_macro_cwd: None, + }, + extra: ExtraCrateData { + version: None, + display_name: Some( + CrateDisplayName { + crate_name: CrateName( + "core", + ), + canonical_name: "core", + }, + ), + potential_cfg_options: None, + }, cfg_options: CfgOptions( [ "debug_assertions", @@ -61,31 +82,41 @@ "true", ], ), - potential_cfg_options: None, env: Env { entries: {}, }, - dependencies: [], - origin: Lang( - Core, - ), - is_proc_macro: false, - proc_macro_cwd: None, + ws_data: CrateWorkspaceData { + data_layout: Err( + "test has no data layout", + ), + toolchain: None, + }, }, - 2: CrateData { - root_file_id: FileId( - 3, - ), - edition: Edition2021, - version: None, - display_name: Some( - CrateDisplayName { - crate_name: CrateName( - "panic_abort", - ), - canonical_name: "panic_abort", - }, - ), + 2: CrateBuilder { + basic: CrateData { + root_file_id: FileId( + 3, + ), + edition: Edition2021, + dependencies: [], + origin: Lang( + Other, + ), + is_proc_macro: false, + proc_macro_cwd: None, + }, + extra: ExtraCrateData { + version: None, + display_name: Some( + CrateDisplayName { + crate_name: CrateName( + "panic_abort", + ), + canonical_name: "panic_abort", + }, + ), + potential_cfg_options: None, + }, cfg_options: CfgOptions( [ "debug_assertions", @@ -93,31 +124,41 @@ "true", ], ), - potential_cfg_options: None, env: Env { entries: {}, }, - dependencies: [], - origin: Lang( - Other, - ), - is_proc_macro: false, - proc_macro_cwd: None, + ws_data: CrateWorkspaceData { + data_layout: Err( + "test has no data layout", + ), + toolchain: None, + }, }, - 3: CrateData { - root_file_id: FileId( - 4, - ), - edition: Edition2021, - version: None, - display_name: Some( - CrateDisplayName { - crate_name: CrateName( - "panic_unwind", - ), - canonical_name: "panic_unwind", - }, - ), + 3: CrateBuilder { + basic: CrateData { + root_file_id: FileId( + 4, + ), + edition: Edition2021, + dependencies: [], + origin: Lang( + Other, + ), + is_proc_macro: false, + proc_macro_cwd: None, + }, + extra: ExtraCrateData { + version: None, + display_name: Some( + CrateDisplayName { + crate_name: CrateName( + "panic_unwind", + ), + canonical_name: "panic_unwind", + }, + ), + potential_cfg_options: None, + }, cfg_options: CfgOptions( [ "debug_assertions", @@ -125,31 +166,58 @@ "true", ], ), - potential_cfg_options: None, env: Env { entries: {}, }, - dependencies: [], - origin: Lang( - Other, - ), - is_proc_macro: false, - proc_macro_cwd: None, + ws_data: CrateWorkspaceData { + data_layout: Err( + "test has no data layout", + ), + toolchain: None, + }, }, - 4: CrateData { - root_file_id: FileId( - 5, - ), - edition: Edition2021, - version: None, - display_name: Some( - CrateDisplayName { - crate_name: CrateName( - "proc_macro", - ), - canonical_name: "proc_macro", - }, - ), + 4: CrateBuilder { + basic: CrateData { + root_file_id: FileId( + 5, + ), + edition: Edition2021, + dependencies: [ + Dependency { + crate_id: Idx::(6), + name: CrateName( + "std", + ), + prelude: true, + sysroot: false, + }, + Dependency { + crate_id: Idx::(1), + name: CrateName( + "core", + ), + prelude: true, + sysroot: false, + }, + ], + origin: Lang( + ProcMacro, + ), + is_proc_macro: false, + proc_macro_cwd: None, + }, + extra: ExtraCrateData { + version: None, + display_name: Some( + CrateDisplayName { + crate_name: CrateName( + "proc_macro", + ), + canonical_name: "proc_macro", + }, + ), + potential_cfg_options: None, + }, cfg_options: CfgOptions( [ "debug_assertions", @@ -157,48 +225,41 @@ "true", ], ), - potential_cfg_options: None, env: Env { entries: {}, }, - dependencies: [ - Dependency { - crate_id: Idx::(6), - name: CrateName( - "std", - ), - prelude: true, - sysroot: false, - }, - Dependency { - crate_id: Idx::(1), - name: CrateName( - "core", - ), - prelude: true, - sysroot: false, - }, - ], - origin: Lang( - ProcMacro, - ), - is_proc_macro: false, - proc_macro_cwd: None, + ws_data: CrateWorkspaceData { + data_layout: Err( + "test has no data layout", + ), + toolchain: None, + }, }, - 5: CrateData { - root_file_id: FileId( - 6, - ), - edition: Edition2021, - version: None, - display_name: Some( - CrateDisplayName { - crate_name: CrateName( - "profiler_builtins", - ), - canonical_name: "profiler_builtins", - }, - ), + 5: CrateBuilder { + basic: CrateData { + root_file_id: FileId( + 6, + ), + edition: Edition2021, + dependencies: [], + origin: Lang( + Other, + ), + is_proc_macro: false, + proc_macro_cwd: None, + }, + extra: ExtraCrateData { + version: None, + display_name: Some( + CrateDisplayName { + crate_name: CrateName( + "profiler_builtins", + ), + canonical_name: "profiler_builtins", + }, + ), + potential_cfg_options: None, + }, cfg_options: CfgOptions( [ "debug_assertions", @@ -206,31 +267,106 @@ "true", ], ), - potential_cfg_options: None, env: Env { entries: {}, }, - dependencies: [], - origin: Lang( - Other, - ), - is_proc_macro: false, - proc_macro_cwd: None, + ws_data: CrateWorkspaceData { + data_layout: Err( + "test has no data layout", + ), + toolchain: None, + }, }, - 6: CrateData { - root_file_id: FileId( - 7, - ), - edition: Edition2021, - version: None, - display_name: Some( - CrateDisplayName { - crate_name: CrateName( - "std", - ), - canonical_name: "std", - }, - ), + 6: CrateBuilder { + basic: CrateData { + root_file_id: FileId( + 7, + ), + edition: Edition2021, + dependencies: [ + Dependency { + crate_id: Idx::(0), + name: CrateName( + "alloc", + ), + prelude: true, + sysroot: false, + }, + Dependency { + crate_id: Idx::(3), + name: CrateName( + "panic_unwind", + ), + prelude: true, + sysroot: false, + }, + Dependency { + crate_id: Idx::(2), + name: CrateName( + "panic_abort", + ), + prelude: true, + sysroot: false, + }, + Dependency { + crate_id: Idx::(1), + name: CrateName( + "core", + ), + prelude: true, + sysroot: false, + }, + Dependency { + crate_id: Idx::(5), + name: CrateName( + "profiler_builtins", + ), + prelude: true, + sysroot: false, + }, + Dependency { + crate_id: Idx::(9), + name: CrateName( + "unwind", + ), + prelude: true, + sysroot: false, + }, + Dependency { + crate_id: Idx::(7), + name: CrateName( + "std_detect", + ), + prelude: true, + sysroot: false, + }, + Dependency { + crate_id: Idx::(8), + name: CrateName( + "test", + ), + prelude: true, + sysroot: false, + }, + ], + origin: Lang( + Std, + ), + is_proc_macro: false, + proc_macro_cwd: None, + }, + extra: ExtraCrateData { + version: None, + display_name: Some( + CrateDisplayName { + crate_name: CrateName( + "std", + ), + canonical_name: "std", + }, + ), + potential_cfg_options: None, + }, cfg_options: CfgOptions( [ "debug_assertions", @@ -238,96 +374,41 @@ "true", ], ), - potential_cfg_options: None, env: Env { entries: {}, }, - dependencies: [ - Dependency { - crate_id: Idx::(0), - name: CrateName( - "alloc", - ), - prelude: true, - sysroot: false, - }, - Dependency { - crate_id: Idx::(3), - name: CrateName( - "panic_unwind", - ), - prelude: true, - sysroot: false, - }, - Dependency { - crate_id: Idx::(2), - name: CrateName( - "panic_abort", - ), - prelude: true, - sysroot: false, - }, - Dependency { - crate_id: Idx::(1), - name: CrateName( - "core", - ), - prelude: true, - sysroot: false, - }, - Dependency { - crate_id: Idx::(5), - name: CrateName( - "profiler_builtins", - ), - prelude: true, - sysroot: false, - }, - Dependency { - crate_id: Idx::(9), - name: CrateName( - "unwind", - ), - prelude: true, - sysroot: false, - }, - Dependency { - crate_id: Idx::(7), - name: CrateName( - "std_detect", - ), - prelude: true, - sysroot: false, - }, - Dependency { - crate_id: Idx::(8), - name: CrateName( - "test", - ), - prelude: true, - sysroot: false, - }, - ], - origin: Lang( - Std, - ), - is_proc_macro: false, - proc_macro_cwd: None, + ws_data: CrateWorkspaceData { + data_layout: Err( + "test has no data layout", + ), + toolchain: None, + }, }, - 7: CrateData { - root_file_id: FileId( - 8, - ), - edition: Edition2021, - version: None, - display_name: Some( - CrateDisplayName { - crate_name: CrateName( - "std_detect", - ), - canonical_name: "std_detect", - }, - ), + 7: CrateBuilder { + basic: CrateData { + root_file_id: FileId( + 8, + ), + edition: Edition2021, + dependencies: [], + origin: Lang( + Other, + ), + is_proc_macro: false, + proc_macro_cwd: None, + }, + extra: ExtraCrateData { + version: None, + display_name: Some( + CrateDisplayName { + crate_name: CrateName( + "std_detect", + ), + canonical_name: "std_detect", + }, + ), + potential_cfg_options: None, + }, cfg_options: CfgOptions( [ "debug_assertions", @@ -335,31 +416,41 @@ "true", ], ), - potential_cfg_options: None, env: Env { entries: {}, }, - dependencies: [], - origin: Lang( - Other, - ), - is_proc_macro: false, - proc_macro_cwd: None, + ws_data: CrateWorkspaceData { + data_layout: Err( + "test has no data layout", + ), + toolchain: None, + }, }, - 8: CrateData { - root_file_id: FileId( - 9, - ), - edition: Edition2021, - version: None, - display_name: Some( - CrateDisplayName { - crate_name: CrateName( - "test", - ), - canonical_name: "test", - }, - ), + 8: CrateBuilder { + basic: CrateData { + root_file_id: FileId( + 9, + ), + edition: Edition2021, + dependencies: [], + origin: Lang( + Test, + ), + is_proc_macro: false, + proc_macro_cwd: None, + }, + extra: ExtraCrateData { + version: None, + display_name: Some( + CrateDisplayName { + crate_name: CrateName( + "test", + ), + canonical_name: "test", + }, + ), + potential_cfg_options: None, + }, cfg_options: CfgOptions( [ "debug_assertions", @@ -367,31 +458,41 @@ "true", ], ), - potential_cfg_options: None, env: Env { entries: {}, }, - dependencies: [], - origin: Lang( - Test, - ), - is_proc_macro: false, - proc_macro_cwd: None, + ws_data: CrateWorkspaceData { + data_layout: Err( + "test has no data layout", + ), + toolchain: None, + }, }, - 9: CrateData { - root_file_id: FileId( - 10, - ), - edition: Edition2021, - version: None, - display_name: Some( - CrateDisplayName { - crate_name: CrateName( - "unwind", - ), - canonical_name: "unwind", - }, - ), + 9: CrateBuilder { + basic: CrateData { + root_file_id: FileId( + 10, + ), + edition: Edition2021, + dependencies: [], + origin: Lang( + Other, + ), + is_proc_macro: false, + proc_macro_cwd: None, + }, + extra: ExtraCrateData { + version: None, + display_name: Some( + CrateDisplayName { + crate_name: CrateName( + "unwind", + ), + canonical_name: "unwind", + }, + ), + potential_cfg_options: None, + }, cfg_options: CfgOptions( [ "debug_assertions", @@ -399,31 +500,85 @@ "true", ], ), - potential_cfg_options: None, env: Env { entries: {}, }, - dependencies: [], - origin: Lang( - Other, - ), - is_proc_macro: false, - proc_macro_cwd: None, + ws_data: CrateWorkspaceData { + data_layout: Err( + "test has no data layout", + ), + toolchain: None, + }, }, - 10: CrateData { - root_file_id: FileId( - 11, - ), - edition: Edition2018, - version: None, - display_name: Some( - CrateDisplayName { - crate_name: CrateName( + 10: CrateBuilder { + basic: CrateData { + root_file_id: FileId( + 11, + ), + edition: Edition2018, + dependencies: [ + Dependency { + crate_id: Idx::(1), + name: CrateName( + "core", + ), + prelude: true, + sysroot: true, + }, + Dependency { + crate_id: Idx::(0), + name: CrateName( + "alloc", + ), + prelude: false, + sysroot: true, + }, + Dependency { + crate_id: Idx::(6), + name: CrateName( + "std", + ), + prelude: true, + sysroot: true, + }, + Dependency { + crate_id: Idx::(8), + name: CrateName( + "test", + ), + prelude: false, + sysroot: true, + }, + Dependency { + crate_id: Idx::(4), + name: CrateName( + "proc_macro", + ), + prelude: false, + sysroot: true, + }, + ], + origin: Local { + repo: None, + name: Some( "hello_world", ), - canonical_name: "hello_world", }, - ), + is_proc_macro: false, + proc_macro_cwd: None, + }, + extra: ExtraCrateData { + version: None, + display_name: Some( + CrateDisplayName { + crate_name: CrateName( + "hello_world", + ), + canonical_name: "hello_world", + }, + ), + potential_cfg_options: None, + }, cfg_options: CfgOptions( [ "rust_analyzer", @@ -431,59 +586,14 @@ "true", ], ), - potential_cfg_options: None, env: Env { entries: {}, }, - dependencies: [ - Dependency { - crate_id: Idx::(1), - name: CrateName( - "core", - ), - prelude: true, - sysroot: true, - }, - Dependency { - crate_id: Idx::(0), - name: CrateName( - "alloc", - ), - prelude: false, - sysroot: true, - }, - Dependency { - crate_id: Idx::(6), - name: CrateName( - "std", - ), - prelude: true, - sysroot: true, - }, - Dependency { - crate_id: Idx::(8), - name: CrateName( - "test", - ), - prelude: false, - sysroot: true, - }, - Dependency { - crate_id: Idx::(4), - name: CrateName( - "proc_macro", - ), - prelude: false, - sysroot: true, - }, - ], - origin: Local { - repo: None, - name: Some( - "hello_world", + ws_data: CrateWorkspaceData { + data_layout: Err( + "test has no data layout", ), + toolchain: None, }, - is_proc_macro: false, - proc_macro_cwd: None, }, } \ No newline at end of file diff --git a/crates/rust-analyzer/src/global_state.rs b/crates/rust-analyzer/src/global_state.rs index f114a4454e..a6aa0376b0 100644 --- a/crates/rust-analyzer/src/global_state.rs +++ b/crates/rust-analyzer/src/global_state.rs @@ -8,7 +8,7 @@ use std::{ops::Not as _, time::Instant}; use crossbeam_channel::{unbounded, Receiver, Sender}; use hir::ChangeWithProcMacros; use ide::{Analysis, AnalysisHost, Cancellable, FileId, SourceRootId}; -use ide_db::base_db::{CrateId, ProcMacroPaths, SourceDatabase}; +use ide_db::base_db::{Crate, ProcMacroPaths, SourceDatabase}; use itertools::Itertools; use load_cargo::SourceRootConfig; use lsp_types::{SemanticTokens, Url}; @@ -158,7 +158,7 @@ pub(crate) struct GlobalState { // op queues pub(crate) fetch_workspaces_queue: OpQueue, pub(crate) fetch_build_data_queue: OpQueue<(), FetchBuildDataResponse>, - pub(crate) fetch_proc_macros_queue: OpQueue, bool>, + pub(crate) fetch_proc_macros_queue: OpQueue<(ChangeWithProcMacros, Vec), bool>, pub(crate) prime_caches_queue: OpQueue, pub(crate) discover_workspace_queue: OpQueue, @@ -714,7 +714,7 @@ impl GlobalStateSnapshot { self.vfs_read().file_path(file_id).clone() } - pub(crate) fn target_spec_for_crate(&self, crate_id: CrateId) -> Option { + pub(crate) fn target_spec_for_crate(&self, crate_id: Crate) -> Option { let file_id = self.analysis.crate_root(crate_id).ok()?; let path = self.vfs_read().file_path(file_id).clone(); let path = path.as_path()?; diff --git a/crates/rust-analyzer/src/main_loop.rs b/crates/rust-analyzer/src/main_loop.rs index b47a126424..7244fbc4aa 100644 --- a/crates/rust-analyzer/src/main_loop.rs +++ b/crates/rust-analyzer/src/main_loop.rs @@ -10,7 +10,7 @@ use std::{ use always_assert::always; use crossbeam_channel::{select, Receiver}; -use ide_db::base_db::{RootQueryDb, SourceDatabase, VfsPath}; +use ide_db::base_db::{SourceDatabase, VfsPath}; use lsp_server::{Connection, Notification, Request}; use lsp_types::{notification::Notification as _, TextDocumentIdentifier}; use stdx::thread::ThreadIntent; @@ -504,8 +504,10 @@ impl GlobalState { if !self.fetch_workspaces_queue.op_in_progress() { if let Some((cause, ())) = self.fetch_build_data_queue.should_start_op() { self.fetch_build_data(cause); - } else if let Some((cause, paths)) = self.fetch_proc_macros_queue.should_start_op() { - self.fetch_proc_macros(cause, paths); + } else if let Some((cause, (change, paths))) = + self.fetch_proc_macros_queue.should_start_op() + { + self.fetch_proc_macros(cause, change, paths); } } @@ -804,9 +806,10 @@ impl GlobalState { let (state, msg) = match progress { ProcMacroProgress::Begin => (Some(Progress::Begin), None), ProcMacroProgress::Report(msg) => (Some(Progress::Report), Some(msg)), - ProcMacroProgress::End(proc_macro_load_result) => { + ProcMacroProgress::End(change) => { self.fetch_proc_macros_queue.op_completed(true); - self.set_proc_macros(proc_macro_load_result); + self.analysis_host.apply_change(change); + self.finish_loading_crate_graph(); (Some(Progress::End), None) } }; @@ -909,16 +912,15 @@ impl GlobalState { }); } QueuedTask::CheckProcMacroSources(modified_rust_files) => { - let crate_graph = self.analysis_host.raw_database().crate_graph(); let analysis = AssertUnwindSafe(self.snapshot().analysis); self.task_pool.handle.spawn_with_sender(stdx::thread::ThreadIntent::Worker, { move |sender| { if modified_rust_files.into_iter().any(|file_id| { // FIXME: Check whether these files could be build script related match analysis.crates_for(file_id) { - Ok(crates) => { - crates.iter().any(|&krate| crate_graph[krate].is_proc_macro) - } + Ok(crates) => crates.iter().any(|&krate| { + analysis.is_proc_macro_crate(krate).is_ok_and(|it| it) + }), _ => false, } }) { diff --git a/crates/rust-analyzer/src/reload.rs b/crates/rust-analyzer/src/reload.rs index 1a60fa06c9..d6a99fbe55 100644 --- a/crates/rust-analyzer/src/reload.rs +++ b/crates/rust-analyzer/src/reload.rs @@ -15,10 +15,9 @@ // FIXME: This is a mess that needs some untangling work use std::{iter, mem}; -use hir::{db::DefDatabase, ChangeWithProcMacros, ProcMacros, ProcMacrosBuilder}; -use ide::CrateId; +use hir::{db::DefDatabase, ChangeWithProcMacros, ProcMacrosBuilder}; use ide_db::{ - base_db::{salsa::Durability, CrateGraph, CrateWorkspaceData, ProcMacroPaths}, + base_db::{salsa::Durability, CrateGraphBuilder, ProcMacroPaths, RootQueryDb}, FxHashMap, }; use itertools::Itertools; @@ -60,7 +59,7 @@ pub(crate) enum BuildDataProgress { pub(crate) enum ProcMacroProgress { Begin, Report(String), - End(ProcMacros), + End(ChangeWithProcMacros), } impl GlobalState { @@ -387,7 +386,12 @@ impl GlobalState { }); } - pub(crate) fn fetch_proc_macros(&mut self, cause: Cause, paths: Vec) { + pub(crate) fn fetch_proc_macros( + &mut self, + cause: Cause, + mut change: ChangeWithProcMacros, + paths: Vec, + ) { info!(%cause, "will load proc macros"); let ignored_proc_macros = self.config.ignored_proc_macros(None).clone(); let proc_macro_clients = self.proc_macro_clients.clone(); @@ -440,16 +444,11 @@ impl GlobalState { .for_each(|(krate, res)| builder.insert(krate, res)); } - sender.send(Task::LoadProcMacros(ProcMacroProgress::End(builder.build()))).unwrap(); + change.set_proc_macros(builder); + sender.send(Task::LoadProcMacros(ProcMacroProgress::End(change))).unwrap(); }); } - pub(crate) fn set_proc_macros(&mut self, proc_macros: ProcMacros) { - let mut change = ChangeWithProcMacros::new(); - change.set_proc_macros(proc_macros); - self.analysis_host.apply_change(change); - } - pub(crate) fn switch_workspaces(&mut self, cause: Cause) { let _p = tracing::info_span!("GlobalState::switch_workspaces").entered(); tracing::info!(%cause, "will switch workspaces"); @@ -528,6 +527,14 @@ impl GlobalState { if self.config.run_build_scripts(None) { self.build_deps_changed = false; self.fetch_build_data_queue.request_op("workspace updated".to_owned(), ()); + + let initial_build = self.analysis_host.raw_database().all_crates().is_empty(); + if !initial_build { + // `switch_workspaces()` will be called again when build scripts already run, which should + // take a short time. If we update the workspace now we will invalidate proc macros and cfgs, + // and then when build scripts complete we will invalidate them again. + return; + } } } @@ -711,7 +718,7 @@ impl GlobalState { }) .collect(); - let (crate_graph, proc_macro_paths, ws_data) = { + let (crate_graph, proc_macro_paths) = { // Create crate graph from all the workspaces let vfs = &self.vfs.read().0; let load = |path: &AbsPath| { @@ -725,24 +732,35 @@ impl GlobalState { ws_to_crate_graph(&self.workspaces, self.config.extra_env(None), load) }; let mut change = ChangeWithProcMacros::new(); - if self.config.expand_proc_macros() { - change.set_proc_macros( - crate_graph - .iter() - .map(|id| (id, Err(("proc-macro has not been built yet".to_owned(), true)))) - .collect(), - ); - self.fetch_proc_macros_queue.request_op(cause, proc_macro_paths); - } else { - change.set_proc_macros( - crate_graph - .iter() - .map(|id| (id, Err(("proc-macro expansion is disabled".to_owned(), false)))) - .collect(), - ); + let initial_build = self.analysis_host.raw_database().all_crates().is_empty(); + if initial_build || !self.config.expand_proc_macros() { + if self.config.expand_proc_macros() { + change.set_proc_macros( + crate_graph + .iter() + .map(|id| (id, Err(("proc-macro has not been built yet".to_owned(), true)))) + .collect(), + ); + } else { + change.set_proc_macros( + crate_graph + .iter() + .map(|id| (id, Err(("proc-macro expansion is disabled".to_owned(), false)))) + .collect(), + ); + } + + change.set_crate_graph(crate_graph); + self.analysis_host.apply_change(change); + + self.finish_loading_crate_graph(); + return; } - change.set_crate_graph(crate_graph, ws_data); - self.analysis_host.apply_change(change); + change.set_crate_graph(crate_graph); + self.fetch_proc_macros_queue.request_op(cause, (change, proc_macro_paths)); + } + + pub(crate) fn finish_loading_crate_graph(&mut self) { self.report_progress( "Building CrateGraph", crate::lsp::utils::Progress::End, @@ -883,26 +901,19 @@ pub fn ws_to_crate_graph( workspaces: &[ProjectWorkspace], extra_env: &FxHashMap, mut load: impl FnMut(&AbsPath) -> Option, -) -> (CrateGraph, Vec, FxHashMap>) { - let mut crate_graph = CrateGraph::default(); +) -> (CrateGraphBuilder, Vec) { + let mut crate_graph = CrateGraphBuilder::default(); let mut proc_macro_paths = Vec::default(); - let mut ws_data = FxHashMap::default(); for ws in workspaces { let (other, mut crate_proc_macros) = ws.to_crate_graph(&mut load, extra_env); - let ProjectWorkspace { toolchain, target_layout, .. } = ws; - let mapping = crate_graph.extend(other, &mut crate_proc_macros); - // Populate the side tables for the newly merged crates - ws_data.extend(mapping.values().copied().zip(iter::repeat(Arc::new(CrateWorkspaceData { - toolchain: toolchain.clone(), - data_layout: target_layout.clone(), - })))); + crate_graph.extend(other, &mut crate_proc_macros); proc_macro_paths.push(crate_proc_macros); } crate_graph.shrink_to_fit(); proc_macro_paths.shrink_to_fit(); - (crate_graph, proc_macro_paths, ws_data) + (crate_graph, proc_macro_paths) } pub(crate) fn should_refresh_for_change( diff --git a/crates/rust-analyzer/src/target_spec.rs b/crates/rust-analyzer/src/target_spec.rs index b28567fe09..abb70ebe36 100644 --- a/crates/rust-analyzer/src/target_spec.rs +++ b/crates/rust-analyzer/src/target_spec.rs @@ -4,7 +4,7 @@ use std::mem; use cfg::{CfgAtom, CfgExpr}; use hir::sym; -use ide::{Cancellable, CrateId, FileId, RunnableKind, TestId}; +use ide::{Cancellable, Crate, FileId, RunnableKind, TestId}; use project_model::project_json::Runnable; use project_model::{CargoFeatures, ManifestPath, TargetKind}; use rustc_hash::FxHashSet; @@ -54,7 +54,7 @@ pub(crate) struct CargoTargetSpec { pub(crate) package: String, pub(crate) target: String, pub(crate) target_kind: TargetKind, - pub(crate) crate_id: CrateId, + pub(crate) crate_id: Crate, pub(crate) required_features: Vec, pub(crate) features: FxHashSet, pub(crate) sysroot_root: Option, diff --git a/crates/test-fixture/Cargo.toml b/crates/test-fixture/Cargo.toml index 95f4cb9d67..2547a02a29 100644 --- a/crates/test-fixture/Cargo.toml +++ b/crates/test-fixture/Cargo.toml @@ -18,6 +18,7 @@ rustc-hash.workspace = true span.workspace = true stdx.workspace = true intern.workspace = true +triomphe.workspace = true [lints] workspace = true diff --git a/crates/test-fixture/src/lib.rs b/crates/test-fixture/src/lib.rs index 4b5c2ff4cf..51d6179a62 100644 --- a/crates/test-fixture/src/lib.rs +++ b/crates/test-fixture/src/lib.rs @@ -1,10 +1,10 @@ //! A set of high-level utility fixture methods to use in tests. -use std::{iter, mem, str::FromStr, sync}; +use std::{mem, str::FromStr, sync}; use base_db::{ - CrateDisplayName, CrateGraph, CrateId, CrateName, CrateOrigin, CrateWorkspaceData, Dependency, - Env, FileChange, FileSet, LangCrateOrigin, RootQueryDb, SourceDatabase, SourceRoot, Version, - VfsPath, + Crate, CrateDisplayName, CrateGraphBuilder, CrateName, CrateOrigin, CrateWorkspaceData, + DependencyBuilder, Env, FileChange, FileSet, LangCrateOrigin, SourceDatabase, SourceRoot, + Version, VfsPath, }; use cfg::CfgOptions; use hir_expand::{ @@ -26,6 +26,7 @@ use test_utils::{ extract_range_or_offset, Fixture, FixtureWithProjectMeta, RangeOrOffset, CURSOR_MARKER, ESCAPED_CURSOR_MARKER, }; +use triomphe::Arc; pub const WORKSPACE: base_db::SourceRootId = base_db::SourceRootId(0); @@ -101,14 +102,8 @@ pub trait WithFixture: Default + ExpandDatabase + SourceDatabase + 'static { (db, file_id, range_or_offset) } - fn test_crate(&self) -> CrateId { - let crate_graph = RootQueryDb::crate_graph(self); - let mut it = crate_graph.iter(); - let mut res = it.next().unwrap(); - while crate_graph[res].origin.is_lang() { - res = it.next().unwrap(); - } - res + fn test_crate(&self) -> Crate { + self.all_crates().iter().copied().find(|&krate| !krate.data(self).origin.is_lang()).unwrap() } } @@ -146,7 +141,7 @@ impl ChangeFixture { let mut source_change = FileChange::new(); let mut files = Vec::new(); - let mut crate_graph = CrateGraph::default(); + let mut crate_graph = CrateGraphBuilder::default(); let mut crates = FxHashMap::default(); let mut crate_deps = Vec::new(); let mut default_crate_root: Option = None; @@ -163,6 +158,9 @@ impl ChangeFixture { let mut file_position = None; + let crate_ws_data = + Arc::new(CrateWorkspaceData { data_layout: target_data_layout, toolchain }); + for entry in fixture { let mut range_or_offset = None; let text = if entry.text.contains(CURSOR_MARKER) { @@ -210,11 +208,12 @@ impl ChangeFixture { Some(crate_name.clone().into()), version, From::from(meta.cfg.clone()), - Some(From::from(meta.cfg)), + Some(meta.cfg), meta.env, origin, false, None, + crate_ws_data.clone(), ); let prev = crates.insert(crate_name.clone(), crate_id); assert!(prev.is_none(), "multiple crates with same name: {crate_name}"); @@ -249,19 +248,23 @@ impl ChangeFixture { Some(CrateName::new("ra_test_fixture").unwrap().into()), None, From::from(default_cfg.clone()), - Some(From::from(default_cfg)), + Some(default_cfg), default_env, CrateOrigin::Local { repo: None, name: None }, false, None, + crate_ws_data.clone(), ); } else { for (from, to, prelude) in crate_deps { let from_id = crates[&from]; let to_id = crates[&to]; - let sysroot = crate_graph[to_id].origin.is_lang(); + let sysroot = crate_graph[to_id].basic.origin.is_lang(); crate_graph - .add_dep(from_id, Dependency::with_prelude(to.clone(), to_id, prelude, sysroot)) + .add_dep( + from_id, + DependencyBuilder::with_prelude(to.clone(), to_id, prelude, sysroot), + ) .unwrap(); } } @@ -276,7 +279,7 @@ impl ChangeFixture { source_change.change_file(core_file, Some(mini_core.source_code())); - let all_crates = crate_graph.crates_in_topological_order(); + let all_crates = crate_graph.iter().collect::>(); let core_crate = crate_graph.add_crate_root( core_file, @@ -292,13 +295,14 @@ impl ChangeFixture { CrateOrigin::Lang(LangCrateOrigin::Core), false, None, + crate_ws_data.clone(), ); for krate in all_crates { crate_graph .add_dep( krate, - Dependency::with_prelude( + DependencyBuilder::with_prelude( CrateName::new("core").unwrap(), core_crate, true, @@ -324,7 +328,7 @@ impl ChangeFixture { source_change.change_file(proc_lib_file, Some(source)); - let all_crates = crate_graph.crates_in_topological_order(); + let all_crates = crate_graph.iter().collect::>(); let proc_macros_crate = crate_graph.add_crate_root( proc_lib_file, @@ -340,6 +344,7 @@ impl ChangeFixture { CrateOrigin::Local { repo: None, name: None }, true, None, + crate_ws_data, ); proc_macros.insert(proc_macros_crate, Ok(proc_macro)); @@ -347,7 +352,10 @@ impl ChangeFixture { crate_graph .add_dep( krate, - Dependency::new(CrateName::new("proc_macros").unwrap(), proc_macros_crate), + DependencyBuilder::new( + CrateName::new("proc_macros").unwrap(), + proc_macros_crate, + ), ) .unwrap(); } @@ -359,19 +367,9 @@ impl ChangeFixture { }; roots.push(root); - let mut change = - ChangeWithProcMacros { source_change, proc_macros: Some(proc_macros.build()) }; + let mut change = ChangeWithProcMacros { source_change, proc_macros: Some(proc_macros) }; change.source_change.set_roots(roots); - change.source_change.set_ws_data( - crate_graph - .iter() - .zip(iter::repeat(From::from(CrateWorkspaceData { - data_layout: target_data_layout, - toolchain, - }))) - .collect(), - ); change.source_change.set_crate_graph(crate_graph); ChangeFixture { file_position, files, change } @@ -654,6 +652,10 @@ impl ProcMacroExpander for IdentityProcMacroExpander { ) -> Result { Ok(subtree.clone()) } + + fn eq_dyn(&self, other: &dyn ProcMacroExpander) -> bool { + other.as_any().type_id() == std::any::TypeId::of::() + } } // Expands to a macro_rules! macro, for issue #18089. @@ -685,6 +687,10 @@ impl ProcMacroExpander for Issue18089ProcMacroExpander { #subtree }) } + + fn eq_dyn(&self, other: &dyn ProcMacroExpander) -> bool { + other.as_any().type_id() == std::any::TypeId::of::() + } } // Pastes the attribute input as its output @@ -705,6 +711,10 @@ impl ProcMacroExpander for AttributeInputReplaceProcMacroExpander { .cloned() .ok_or_else(|| ProcMacroExpansionError::Panic("Expected attribute input".into())) } + + fn eq_dyn(&self, other: &dyn ProcMacroExpander) -> bool { + other.as_any().type_id() == std::any::TypeId::of::() + } } #[derive(Debug)] @@ -736,6 +746,10 @@ impl ProcMacroExpander for Issue18840ProcMacroExpander { top_subtree_delimiter_mut.close = def_site; Ok(result) } + + fn eq_dyn(&self, other: &dyn ProcMacroExpander) -> bool { + other.as_any().type_id() == std::any::TypeId::of::() + } } #[derive(Debug)] @@ -767,6 +781,10 @@ impl ProcMacroExpander for MirrorProcMacroExpander { traverse(&mut builder, input.iter()); Ok(builder.build()) } + + fn eq_dyn(&self, other: &dyn ProcMacroExpander) -> bool { + other.as_any().type_id() == std::any::TypeId::of::() + } } // Replaces every literal with an empty string literal and every identifier with its first letter, @@ -807,6 +825,10 @@ impl ProcMacroExpander for ShortenProcMacroExpander { } } } + + fn eq_dyn(&self, other: &dyn ProcMacroExpander) -> bool { + other.as_any().type_id() == std::any::TypeId::of::() + } } // Reads ident type within string quotes, for issue #17479. @@ -832,6 +854,10 @@ impl ProcMacroExpander for Issue17479ProcMacroExpander { #symbol() }) } + + fn eq_dyn(&self, other: &dyn ProcMacroExpander) -> bool { + other.as_any().type_id() == std::any::TypeId::of::() + } } // Reads ident type within string quotes, for issue #17479. @@ -883,6 +909,10 @@ impl ProcMacroExpander for Issue18898ProcMacroExpander { } }) } + + fn eq_dyn(&self, other: &dyn ProcMacroExpander) -> bool { + other.as_any().type_id() == std::any::TypeId::of::() + } } // Reads ident type within string quotes, for issue #17479. @@ -910,4 +940,8 @@ impl ProcMacroExpander for DisallowCfgProcMacroExpander { } Ok(subtree.clone()) } + + fn eq_dyn(&self, other: &dyn ProcMacroExpander) -> bool { + other.as_any().type_id() == std::any::TypeId::of::() + } }