Salsify the crate graph

I.e. make it not one giant input but multiple, for incrementality and decreased memory usage for Salsa 3 reasons.
This commit is contained in:
Chayim Refael Friedman 2025-01-02 01:45:32 +02:00
parent 44f18c3d05
commit c94e9efbef
108 changed files with 3630 additions and 2512 deletions

1
Cargo.lock generated
View file

@ -2418,6 +2418,7 @@ dependencies = [
"span",
"stdx",
"test-utils",
"triomphe",
"tt",
]

View file

@ -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<Vec<SourceRoot>>,
pub files_changed: Vec<(FileId, Option<String>)>,
pub crate_graph: Option<CrateGraph>,
pub ws_data: Option<FxHashMap<CrateId, Arc<CrateWorkspaceData>>>,
pub crate_graph: Option<CrateGraphBuilder>,
}
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<CrateId, Arc<CrateWorkspaceData>>) {
self.ws_data = Some(data);
}
pub fn apply(self, db: &mut dyn RootQueryDb) {
pub fn apply(self, db: &mut dyn RootQueryDb) -> Option<CratesIdMap> {
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
}
}

View file

@ -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<CrateId, Result<(String, AbsPathBuf), String>>;
use crate::{CrateWorkspaceData, RootQueryDb};
pub type ProcMacroPaths = FxHashMap<CrateBuilderId, Result<(String, AbsPathBuf), String>>;
#[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
/// <https://github.com/rust-lang/rust-analyzer/blob/master/docs/dev/architecture.md#serialization>
#[derive(Clone, Default)]
pub struct CrateGraph {
arena: Arena<CrateData>,
#[derive(Default, Clone)]
pub struct CrateGraphBuilder {
arena: Arena<CrateBuilder>,
}
impl fmt::Debug for CrateGraph {
pub type CrateBuilderId = Idx<CrateBuilder>;
impl ops::Index<CrateBuilderId> 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<CfgOptions>,
pub env: Env,
ws_data: Arc<CrateWorkspaceData>,
}
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<CrateData>;
#[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<Box<(BuiltCrateData, HashableCfgOptions)>>,
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct CrateData<Id> {
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<Dependency<Id>>,
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<AbsPathBuf>,
}
pub type CrateDataBuilder = CrateData<CrateBuilderId>;
pub type BuiltCrateData = CrateData<Crate>;
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ExtraCrateData {
pub version: Option<String>,
/// 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<CrateDisplayName>,
pub cfg_options: Arc<CfgOptions>,
/// The cfg options that could be used by the crate
pub potential_cfg_options: Option<Arc<CfgOptions>>,
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<Dependency>,
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<AbsPathBuf>,
pub potential_cfg_options: Option<CfgOptions>,
}
#[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<Id> {
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<CrateBuilderId>;
pub type BuiltDependency = Dependency<Crate>;
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<CrateBuilderId, Crate>;
#[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<CrateWorkspaceData>,
// FIXME: Remove this `Arc`.
#[return_ref]
pub cfg_options: Arc<CfgOptions>,
#[return_ref]
pub env: Env,
}
/// The mapping from [`UniqueCrateData`] to their [`Crate`] input.
#[derive(Debug, Default)]
pub struct CratesMap(DashMap<UniqueCrateData, Crate, BuildHasherDefault<FxHasher>>);
impl CrateGraphBuilder {
pub fn add_crate_root(
&mut self,
root_file_id: FileId,
@ -361,33 +424,34 @@ impl CrateGraph {
display_name: Option<CrateDisplayName>,
version: Option<String>,
cfg_options: Arc<CfgOptions>,
potential_cfg_options: Option<Arc<CfgOptions>>,
potential_cfg_options: Option<CfgOptions>,
mut env: Env,
origin: CrateOrigin,
is_proc_macro: bool,
proc_macro_cwd: Option<AbsPathBuf>,
) -> CrateId {
ws_data: Arc<CrateWorkspaceData>,
) -> 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<CrateBuilderId, Crate>,
visited_root_files: &mut FxHashSet<FileId>,
all_crates: &mut Vec<Crate>,
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::<Vec<_>>();
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<Item = CrateId> + '_ {
pub fn iter(&self) -> impl Iterator<Item = CrateBuilderId> + '_ {
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<Item = (CrateId, &mut CrateData)> + '_ {
pub fn iter_mut(&mut self) -> impl Iterator<Item = (CrateBuilderId, &mut CrateBuilder)> + '_ {
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<Item = CrateId> {
pub fn transitive_deps(&self, of: CrateBuilderId) -> impl Iterator<Item = CrateBuilderId> {
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<Item = CrateId> {
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<CrateId> {
fn crates_in_topological_order(&self) -> Vec<CrateBuilderId> {
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<CrateId>,
res: &mut Vec<CrateId>,
source: CrateId,
graph: &CrateGraphBuilder,
visited: &mut FxHashSet<CrateBuilderId>,
res: &mut Vec<CrateBuilderId>,
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<CrateId, CrateId> {
) -> FxHashMap<CrateBuilderId, CrateBuilderId> {
// 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<CrateId, CrateId> = FxHashMap::default();
let mut id_map: FxHashMap<CrateBuilderId, CrateBuilderId> = 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<CrateId>,
from: CrateId,
to: CrateId,
) -> Option<Vec<CrateId>> {
visited: &mut FxHashSet<CrateBuilderId>,
from: CrateBuilderId,
to: CrateBuilderId,
) -> Option<Vec<CrateBuilderId>> {
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<Option<CrateId>> {
pub fn remove_crates_except(
&mut self,
to_keep: &[CrateBuilderId],
) -> Vec<Option<CrateBuilderId>> {
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<CrateId> 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<Crate> {
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<CrateDisplayName>)>,
path: Vec<(CrateBuilderId, Option<CrateDisplayName>)>,
}
impl CyclicDependenciesError {
fn from(&self) -> &(CrateId, Option<CrateDisplayName>) {
fn from(&self) -> &(CrateBuilderId, Option<CrateDisplayName>) {
self.path.first().unwrap()
}
fn to(&self) -> &(CrateId, Option<CrateDisplayName>) {
fn to(&self) -> &(CrateBuilderId, Option<CrateDisplayName>) {
self.path.last().unwrap()
}
}
impl fmt::Display for CyclicDependenciesError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let render = |(id, name): &(CrateId, Option<CrateDisplayName>)| match name {
let render = |(id, name): &(CrateBuilderId, Option<CrateDisplayName>)| 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<CrateWorkspaceData> {
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,)
]
);
}
}

View file

@ -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<Arc<[SyntaxError]>>;
/// The crate graph.
#[salsa::input]
fn crate_graph(&self) -> Arc<CrateGraph>;
#[salsa::input]
fn crate_workspace_data(&self) -> Arc<FxHashMap<CrateId, Arc<CrateWorkspaceData>>>;
#[salsa::transparent]
fn toolchain_channel(&self, krate: CrateId) -> Option<ReleaseChannel>;
fn toolchain_channel(&self, krate: Crate) -> Option<ReleaseChannel>;
/// 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<Box<[Crate]>>;
/// 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<Crate>;
/// 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<Crate>;
}
pub fn transitive_deps(db: &dyn SourceDatabase, crate_id: Crate) -> FxHashSet<Crate> {
// 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<CratesMap>;
}
/// Crate related data shared by the whole workspace.
@ -268,12 +304,8 @@ pub struct CrateWorkspaceData {
pub toolchain: Option<Version>,
}
fn toolchain_channel(db: &dyn RootQueryDb, krate: CrateId) -> Option<ReleaseChannel> {
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<ReleaseChannel> {
krate.workspace_data(db).toolchain.as_ref().and_then(|v| ReleaseChannel::from_str(&v.pre))
}
fn parse(db: &dyn RootQueryDb, file_id: EditionedFileId) -> Parse<ast::SourceFile> {
@ -291,21 +323,19 @@ fn parse_errors(db: &dyn RootQueryDb, file_id: EditionedFileId) -> Option<Arc<[S
}
}
fn source_root_crates(db: &dyn RootQueryDb, id: SourceRootId) -> 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::<Vec<_>>();
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);

View file

@ -104,6 +104,12 @@ impl CfgOptions {
_ => None,
})
}
pub fn to_hashable(&self) -> HashableCfgOptions {
let mut enabled = self.enabled.iter().cloned().collect::<Box<[_]>>();
enabled.sort_unstable();
HashableCfgOptions { _enabled: enabled }
}
}
impl Extend<CfgAtom> 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]>,
}

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -23,7 +23,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,
@ -313,8 +313,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 =
@ -413,7 +412,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,
@ -626,8 +630,8 @@ impl GenericParamsCollector {
generics_types_map: &mut TypesMap,
generics_types_source_map: &mut TypesSourceMap,
// FIXME: Change this back to `LazyCell` if https://github.com/rust-lang/libs-team/issues/429 is accepted.
exp: &mut Option<(Arc<DefMap>, Expander)>,
exp_fill: &mut dyn FnMut() -> (Arc<DefMap>, Expander),
exp: &mut Option<(Arc<DefMap>, Arc<LocalDefMap>, Expander)>,
exp_fill: &mut dyn FnMut() -> (Arc<DefMap>, Arc<LocalDefMap>, Expander),
type_ref: TypeRefId,
types_map: &TypesMap,
types_source_map: &TypesSourceMap,
@ -657,12 +661,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,
@ -690,7 +695,7 @@ impl GenericParamsCollector {
&macro_types_map,
&macro_types_source_map,
);
exp.get_or_insert_with(&mut *exp_fill).1.exit(mark);
exp.get_or_insert_with(&mut *exp_fill).2.exit(mark);
}
}
});

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -59,7 +59,7 @@ mod tests;
use std::ops::Deref;
use base_db::CrateId;
use base_db::Crate;
use hir_expand::{
name::Name, proc_macro::ProcMacroKind, ErasedAstId, HirFileId, InFile, MacroCallId, MacroDefId,
};
@ -69,7 +69,7 @@ use la_arena::Arena;
use rustc_hash::{FxHashMap, FxHashSet};
use span::{Edition, EditionedFileId, FileAstId, FileId, ROOT_ERASED_FILE_AST_ID};
use stdx::format_to;
use syntax::{ast, AstNode, SmolStr, SyntaxNode};
use syntax::{ast, AstNode, SmolStr, SyntaxNode, ToSmolStr};
use triomphe::Arc;
use tt::TextRange;
@ -95,6 +95,39 @@ const PREDEFINED_TOOLS: &[SmolStr] = &[
SmolStr::new_static("rust_analyzer"),
];
/// Parts of the def map that are only needed when analyzing code in the same crate.
///
/// There are some data in the def map (e.g. extern prelude) that is only needed when analyzing
/// things in the same crate (and maybe in the IDE layer), e.g. the extern prelude. If we put
/// it in the DefMap dependant DefMaps will be invalidated when they change (e.g. when we add
/// a dependency to the crate). Instead we split them out of the DefMap into a LocalDefMap struct.
/// `crate_local_def_map()` returns both, and `crate_def_map()` returns only the external-relevant
/// DefMap.
#[derive(Debug, PartialEq, Eq, Default)]
pub struct LocalDefMap {
// FIXME: There are probably some other things that could be here, but this is less severe and you
// need to be careful with things that block def maps also have.
/// The extern prelude which contains all root modules of external crates that are in scope.
extern_prelude: FxIndexMap<Name, (CrateRootModuleId, Option<ExternCrateId>)>,
}
impl LocalDefMap {
pub(crate) const EMPTY: &Self =
&Self { extern_prelude: FxIndexMap::with_hasher(rustc_hash::FxBuildHasher) };
fn shrink_to_fit(&mut self) {
let Self { extern_prelude } = self;
extern_prelude.shrink_to_fit();
}
pub(crate) fn extern_prelude(
&self,
) -> impl DoubleEndedIterator<Item = (&Name, (CrateRootModuleId, Option<ExternCrateId>))> + '_
{
self.extern_prelude.iter().map(|(name, &def)| (name, def))
}
}
/// Contains the results of (early) name resolution.
///
/// A `DefMap` stores the module tree and the definitions that are in scope in every module after
@ -107,7 +140,7 @@ const PREDEFINED_TOOLS: &[SmolStr] = &[
#[derive(Debug, PartialEq, Eq)]
pub struct DefMap {
/// The crate this `DefMap` belongs to.
krate: CrateId,
krate: Crate,
/// When this is a block def map, this will hold the block id of the block and module that
/// contains this block.
block: Option<BlockInfo>,
@ -141,9 +174,6 @@ pub struct DefMap {
/// Data that belongs to a crate which is shared between a crate's def map and all its block def maps.
#[derive(Clone, Debug, PartialEq, Eq)]
struct DefMapCrateData {
/// The extern prelude which contains all root modules of external crates that are in scope.
extern_prelude: FxIndexMap<Name, (CrateRootModuleId, Option<ExternCrateId>)>,
/// Side table for resolving derive helpers.
exported_derives: FxHashMap<MacroDefId, Box<[Name]>>,
fn_proc_macro_mapping: FxHashMap<FunctionId, ProcMacroId>,
@ -166,7 +196,6 @@ struct DefMapCrateData {
impl DefMapCrateData {
fn new(edition: Edition) -> Self {
Self {
extern_prelude: FxIndexMap::default(),
exported_derives: FxHashMap::default(),
fn_proc_macro_mapping: FxHashMap::default(),
registered_attrs: Vec::new(),
@ -182,7 +211,6 @@ impl DefMapCrateData {
fn shrink_to_fit(&mut self) {
let Self {
extern_prelude,
exported_derives,
fn_proc_macro_mapping,
registered_attrs,
@ -194,7 +222,6 @@ impl DefMapCrateData {
edition: _,
recursion_limit: _,
} = self;
extern_prelude.shrink_to_fit();
exported_derives.shrink_to_fit();
fn_proc_macro_mapping.shrink_to_fit();
registered_attrs.shrink_to_fit();
@ -219,11 +246,11 @@ struct BlockRelativeModuleId {
}
impl BlockRelativeModuleId {
fn def_map(self, db: &dyn DefDatabase, krate: CrateId) -> Arc<DefMap> {
fn def_map(self, db: &dyn DefDatabase, krate: Crate) -> Arc<DefMap> {
self.into_module(krate).def_map(db)
}
fn into_module(self, krate: CrateId) -> ModuleId {
fn into_module(self, krate: Crate) -> ModuleId {
ModuleId { krate, block: self.block, local_id: self.local_id }
}
@ -337,11 +364,25 @@ impl DefMap {
self.data.edition
}
pub(crate) fn crate_def_map_query(db: &dyn DefDatabase, crate_id: CrateId) -> Arc<DefMap> {
let crate_graph = db.crate_graph();
let krate = &crate_graph[crate_id];
let name = krate.display_name.as_deref().map(Symbol::as_str).unwrap_or_default();
let _p = tracing::info_span!("crate_def_map_query", ?name).entered();
pub(crate) fn crate_def_map_query(db: &dyn DefDatabase, crate_id: Crate) -> Arc<DefMap> {
db.crate_local_def_map(crate_id).0
}
pub(crate) fn crate_local_def_map_query(
db: &dyn DefDatabase,
crate_id: Crate,
) -> (Arc<DefMap>, Arc<LocalDefMap>) {
let krate = crate_id.data(db);
let _p = tracing::info_span!(
"crate_def_map_query",
name=?crate_id
.extra_data(db)
.display_name
.as_ref()
.map(|it| it.crate_name().to_smolstr())
.unwrap_or_default()
)
.entered();
let module_data = ModuleData::new(
ModuleOrigin::CrateRoot { definition: krate.root_file_id() },
@ -354,10 +395,14 @@ impl DefMap {
module_data,
None,
);
let def_map =
collector::collect_defs(db, def_map, TreeId::new(krate.root_file_id().into(), None));
let (def_map, local_def_map) = collector::collect_defs(
db,
def_map,
TreeId::new(krate.root_file_id().into(), None),
None,
);
Arc::new(def_map)
(Arc::new(def_map), Arc::new(local_def_map))
}
pub(crate) fn block_def_map_query(db: &dyn DefDatabase, block_id: BlockId) -> Arc<DefMap> {
@ -370,10 +415,10 @@ impl DefMap {
let module_data =
ModuleData::new(ModuleOrigin::BlockExpr { block: ast_id, id: block_id }, visibility);
let parent_map = module.def_map(db);
let (crate_map, crate_local_map) = db.crate_local_def_map(module.krate);
let def_map = DefMap::empty(
module.krate,
parent_map.data.clone(),
crate_map.data.clone(),
module_data,
Some(BlockInfo {
block: block_id,
@ -381,13 +426,17 @@ impl DefMap {
}),
);
let def_map =
collector::collect_defs(db, def_map, TreeId::new(ast_id.file_id, Some(block_id)));
let (def_map, _) = collector::collect_defs(
db,
def_map,
TreeId::new(ast_id.file_id, Some(block_id)),
Some(crate_local_map),
);
Arc::new(def_map)
}
fn empty(
krate: CrateId,
krate: Crate,
crate_data: Arc<DefMapCrateData>,
module_data: ModuleData,
block: Option<BlockInfo>,
@ -479,7 +528,7 @@ impl DefMap {
self.data.fn_proc_macro_mapping.get(&id).copied()
}
pub fn krate(&self) -> CrateId {
pub fn krate(&self) -> Crate {
self.krate
}
@ -590,19 +639,13 @@ impl DefMap {
self.prelude
}
pub(crate) fn extern_prelude(
&self,
) -> impl DoubleEndedIterator<Item = (&Name, (CrateRootModuleId, Option<ExternCrateId>))> + '_
{
self.data.extern_prelude.iter().map(|(name, &def)| (name, def))
}
pub(crate) fn macro_use_prelude(&self) -> &FxHashMap<Name, (MacroId, Option<ExternCrateId>)> {
&self.macro_use_prelude
}
pub(crate) fn resolve_path(
&self,
local_def_map: &LocalDefMap,
db: &dyn DefDatabase,
original_module: LocalModuleId,
path: &ModPath,
@ -610,6 +653,7 @@ impl DefMap {
expected_macro_subns: Option<MacroSubNs>,
) -> (PerNs, Option<usize>) {
let res = self.resolve_path_fp_with_macro(
local_def_map,
db,
ResolveMode::Other,
original_module,
@ -624,12 +668,14 @@ impl DefMap {
/// points at the unresolved segments.
pub(crate) fn resolve_path_locally(
&self,
local_def_map: &LocalDefMap,
db: &dyn DefDatabase,
original_module: LocalModuleId,
path: &ModPath,
shadow: BuiltinShadowMode,
) -> (PerNs, Option<usize>, ResolvePathResultPrefixInfo) {
let res = self.resolve_path_fp_with_macro_single(
local_def_map,
db,
ResolveMode::Other,
original_module,

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -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) {

View file

@ -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<tt::TopSubtree> {
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<String> {
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(

View file

@ -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<bool> {
fn check_cfg(db: &dyn ExpandDatabase, attr: &Attr, krate: Crate) -> Option<bool> {
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<bool> {
fn check_cfg_attr(db: &dyn ExpandDatabase, attr: &Attr, krate: Crate) -> Option<bool> {
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<bool> {
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<I: HasAttrs>(
db: &dyn ExpandDatabase,
items: impl Iterator<Item = I>,
krate: CrateId,
krate: Crate,
remove: &mut FxHashSet<SyntaxElement>,
) -> Option<()> {
for item in items {
@ -144,7 +144,7 @@ fn remove_possible_comma(item: &impl AstNode, res: &mut FxHashSet<SyntaxElement>
fn process_enum(
db: &dyn ExpandDatabase,
variants: VariantList,
krate: CrateId,
krate: Crate,
remove: &mut FxHashSet<SyntaxElement>,
) -> Option<()> {
'variant: for variant in variants.variants() {

View file

@ -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<ProcMacros>,
pub proc_macros: Option<ProcMacrosBuilder>,
}
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<CrateId, Arc<CrateWorkspaceData>>,
) {
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);
}

View file

@ -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<ProcMacros>;
#[salsa::invoke_actual(crate::proc_macro::proc_macros_for_crate)]
fn proc_macros_for_crate(&self, krate: Crate) -> Option<Arc<CrateProcMacros>>;
fn ast_id_map(&self, file_id: HirFileId) -> Arc<AstIdMap>;
#[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<ast::Macro>,
) -> Arc<DeclarativeMacroExpander>;

View file

@ -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<ast::Macro>,
) -> Arc<DeclarativeMacroExpander> {
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) {

View file

@ -18,7 +18,7 @@
//!
//!
//! See the full discussion : <https://rust-lang.zulipchat.com/#narrow/stream/131828-t-compiler/topic/Eager.20expansion.20of.20built-in.20macros>
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<ast::MacroCall>,
def: MacroDefId,
@ -115,7 +115,7 @@ fn lazy_expand(
def: &MacroDefId,
macro_call: &ast::MacroCall,
ast_id: AstId<ast::MacroCall>,
krate: CrateId,
krate: Crate,
call_site: SyntaxContextId,
) -> ExpandResult<(InFile<Parse<SyntaxNode>>, Arc<ExpansionSpanMap>)> {
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<SyntaxNode>,
krate: CrateId,
krate: Crate,
call_site: SyntaxContextId,
macro_resolver: &dyn Fn(&ModPath) -> Option<MacroDefId>,
) -> ExpandResult<Option<(SyntaxNode, TextSize)>> {
@ -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)),

View file

@ -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<mbe::ExpandError> 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 {

View file

@ -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<CrateId> {
pub fn resolve_crate_root(db: &dyn ExpandDatabase, mut ctxt: SyntaxContextId) -> Option<Crate> {
// 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.

View file

@ -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())
}

View file

@ -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) = &macro_def_crate.extra_data(db).display_name {
make::tokens::ident(crate_name.crate_name().as_str())
} else {
return dollar_crate.clone();

View file

@ -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<T: Any> 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<String>,
) -> Result<tt::TopSubtree, ProcMacroExpansionError>;
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<Vec<ProcMacro>, (String, bool)>;
type StoredProcMacroLoadResult = Result<Box<[ProcMacro]>, (Box<str>, bool)>;
#[derive(Default, Debug)]
pub struct ProcMacrosBuilder(FxHashMap<CrateId, StoredProcMacroLoadResult>);
pub struct ProcMacrosBuilder(FxHashMap<CrateBuilderId, Arc<CrateProcMacros>>);
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::<FxHashMap<_, _>>();
map.shrink_to_fit();
ProcMacros(map)
}
}
#[derive(Default, Debug)]
pub struct ProcMacros(FxHashMap<CrateId, StoredProcMacroLoadResult>);
impl FromIterator<(CrateId, ProcMacroLoadResult)> for ProcMacros {
fn from_iter<T: IntoIterator<Item = (CrateId, ProcMacroLoadResult)>>(iter: T) -> Self {
impl FromIterator<(CrateBuilderId, ProcMacroLoadResult)> for ProcMacrosBuilder {
fn from_iter<T: IntoIterator<Item = (CrateBuilderId, ProcMacroLoadResult)>>(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<Crate, Arc<CrateProcMacros>>);
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<Arc<CrateProcMacros>> {
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<Box<[(crate::name::Name, CustomProcMacroExpander, bool)]>> {
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<ExpandErrorKind> {
pub fn as_expand_error(&self, def_crate: Crate) -> Option<ExpandErrorKind> {
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<Arc<CrateProcMacros>> {
db.proc_macros().get(krate)
}

View file

@ -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<Interner> 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<Interner> for &dyn HirDatabase {
pub(crate) fn program_clauses_for_chalk_env_query(
db: &dyn HirDatabase,
krate: CrateId,
krate: Crate,
block: Option<BlockId>,
environment: chalk_ir::Environment<Interner>,
) -> chalk_ir::ProgramClauses<Interner> {
@ -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<TraitDatum> {
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<AdtDatum> {
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<ImplDatum> {
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<ImplDatum> {
fn impl_def_datum(db: &dyn HirDatabase, krate: Crate, impl_id: hir_def::ImplId) -> Arc<ImplDatum> {
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<AssociatedTyValue> {
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<AssociatedTyValue> {
let type_alias_data = db.type_alias_data(type_alias);

View file

@ -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<u128>, krate: CrateId) -> Const {
pub fn usize_const(db: &dyn HirDatabase, value: Option<u128>, krate: Crate) -> Const {
intern_const_ref(
db,
&value.map_or(LiteralConstRef::Unknown, LiteralConstRef::UInt),

View file

@ -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)

View file

@ -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<dyn DefDatabase> + std::fmt::Debug {
#[salsa::cycle(crate::layout::layout_of_ty_recover)]
fn layout_of_ty(&self, ty: Ty, env: Arc<TraitEnvironment>) -> Result<Arc<Layout>, LayoutError>;
#[salsa::invoke(crate::layout::target_data_layout_query)]
fn target_data_layout(&self, krate: CrateId) -> Result<Arc<TargetDataLayout>, Arc<str>>;
#[salsa::invoke_actual(crate::layout::target_data_layout_query)]
fn target_data_layout(&self, krate: Crate) -> Result<Arc<TargetDataLayout>, Arc<str>>;
#[salsa::invoke_actual(crate::dyn_compatibility::dyn_compatibility_of_trait_query)]
fn dyn_compatibility_of_trait(&self, trait_: TraitId) -> Option<DynCompatibilityViolation>;
@ -196,8 +196,8 @@ pub trait HirDatabase: DefDatabase + Upcast<dyn DefDatabase> + 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<InherentImpls>;
#[salsa::invoke_actual(InherentImpls::inherent_impls_in_crate_query)]
fn inherent_impls_in_crate(&self, krate: Crate) -> Arc<InherentImpls>;
#[salsa::invoke_actual(InherentImpls::inherent_impls_in_block_query)]
fn inherent_impls_in_block(&self, block: BlockId) -> Option<Arc<InherentImpls>>;
@ -209,18 +209,18 @@ pub trait HirDatabase: DefDatabase + Upcast<dyn DefDatabase> + 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<TraitImpls>;
#[salsa::invoke_actual(TraitImpls::trait_impls_in_crate_query)]
fn trait_impls_in_crate(&self, krate: Crate) -> Arc<TraitImpls>;
#[salsa::invoke_actual(TraitImpls::trait_impls_in_block_query)]
fn trait_impls_in_block(&self, block: BlockId) -> Option<Arc<TraitImpls>>;
#[salsa::invoke(TraitImpls::trait_impls_in_deps_query)]
fn trait_impls_in_deps(&self, krate: CrateId) -> Arc<[Arc<TraitImpls>]>;
#[salsa::invoke_actual(TraitImpls::trait_impls_in_deps_query)]
fn trait_impls_in_deps(&self, krate: Crate) -> Arc<[Arc<TraitImpls>]>;
// Interned IDs for Chalk integration
#[salsa::interned]
@ -253,23 +253,16 @@ pub trait HirDatabase: DefDatabase + Upcast<dyn DefDatabase> + 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<chalk_db::TraitDatum>;
#[salsa::invoke(chalk_db::adt_datum_query)]
fn adt_datum(
&self,
krate: CrateId,
struct_id: chalk_db::AdtId,
) -> sync::Arc<chalk_db::AdtDatum>;
fn adt_datum(&self, krate: Crate, struct_id: chalk_db::AdtId) -> sync::Arc<chalk_db::AdtDatum>;
#[salsa::invoke(chalk_db::impl_datum_query)]
fn impl_datum(
&self,
krate: CrateId,
impl_id: chalk_db::ImplId,
) -> sync::Arc<chalk_db::ImplDatum>;
fn impl_datum(&self, krate: Crate, impl_id: chalk_db::ImplId)
-> sync::Arc<chalk_db::ImplDatum>;
#[salsa::invoke(chalk_db::fn_def_datum_query)]
fn fn_def_datum(&self, fn_def_id: FnDefId) -> sync::Arc<chalk_db::FnDefDatum>;
@ -287,7 +280,7 @@ pub trait HirDatabase: DefDatabase + Upcast<dyn DefDatabase> + 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<chalk_db::AssociatedTyValue>;
@ -302,7 +295,7 @@ pub trait HirDatabase: DefDatabase + Upcast<dyn DefDatabase> + std::fmt::Debug {
#[salsa::invoke(crate::traits::trait_solve_query)]
fn trait_solve(
&self,
krate: CrateId,
krate: Crate,
block: Option<BlockId>,
goal: crate::Canonical<crate::InEnvironment<crate::Goal>>,
) -> Option<crate::Solution>;
@ -310,7 +303,7 @@ pub trait HirDatabase: DefDatabase + Upcast<dyn DefDatabase> + 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<BlockId>,
env: chalk_ir::Environment<Interner>,
) -> chalk_ir::ProgramClauses<Interner>;

View file

@ -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) {

View file

@ -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<WitnessPat<'p>>,
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<'_, '_> {

View file

@ -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,

View file

@ -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<Item = Trai
#[derive(Clone, Copy, PartialEq, Eq)]
pub enum SizedByDefault {
NotSized,
Sized { anchor: CrateId },
Sized { anchor: Crate },
}
impl SizedByDefault {
@ -2266,8 +2266,8 @@ impl HirDisplayWithTypesMap for Path {
// Resolve `$crate` to the crate's display name.
// FIXME: should use the dependency name instead if available, but that depends on
// the crate invoking `HirDisplay`
let crate_graph = f.db.crate_graph();
let name = crate_graph[*id]
let crate_data = id.extra_data(f.db);
let name = crate_data
.display_name
.as_ref()
.map(|name| name.canonical_name())

View file

@ -307,7 +307,7 @@ impl CapturedItem {
}
}
}
if is_raw_identifier(&result, db.crate_graph()[owner.module(db.upcast()).krate()].edition) {
if is_raw_identifier(&result, owner.module(db.upcast()).krate().data(db).edition) {
result.insert_str(0, "r#");
}
result
@ -316,7 +316,7 @@ impl CapturedItem {
pub fn display_place_source_code(&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();
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 {

View file

@ -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<TargetDataLayout>, Arc<str>> {
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) => {

View file

@ -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.

View file

@ -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<Self> {
pub(crate) fn trait_impls_in_crate_query(db: &dyn HirDatabase, krate: Crate) -> Arc<Self> {
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<Self>]> {
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<Self> {
pub(crate) fn inherent_impls_in_crate_query(db: &dyn HirDatabase, krate: Crate) -> Arc<Self> {
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<SmallVec<[CrateId; 2]>> {
pub fn def_crates(db: &dyn HirDatabase, ty: &Ty, cur_crate: Crate) -> Option<SmallVec<[Crate; 2]>> {
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;
}
}

View file

@ -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<V, T> ProjectionElem<V, T> {
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

View file

@ -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<FunctionId>,
cached_fn_mut_trait_func: Option<FunctionId>,
cached_fn_once_trait_func: Option<FunctionId>,
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),

View file

@ -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

View file

@ -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<Arc<MirBody>> {
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()

View file

@ -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<Self>,
files: Arc<base_db::Files>,
crates_map: Arc<CratesMap>,
events: Arc<Mutex<Option<Vec<salsa::Event>>>>,
}
@ -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<CratesMap> {
self.crates_map.clone()
}
}
#[salsa::db]
@ -151,8 +160,7 @@ impl TestDB {
&self,
) -> FxHashMap<EditionedFileId, Vec<(TextRange, String)>> {
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();

View file

@ -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<InferenceResult>,
body: Arc<Body>,
body_source_map: Arc<BodySourceMap>,
krate: CrateId| {
krate: Crate| {
let display_target = DisplayTarget::from_crate(&db, krate);
let mut types: Vec<(InFile<SyntaxNode>, &Ty)> = Vec::new();
let mut mismatches: Vec<(InFile<SyntaxNode>, &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(),

View file

@ -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<BlockId>,
}
@ -48,7 +48,7 @@ fn create_chalk_solver() -> chalk_recursive::RecursiveSolver<Interner> {
/// we assume that `T: Default`.
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct TraitEnvironment {
pub krate: CrateId,
pub krate: Crate,
pub block: Option<BlockId>,
// 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<Self> {
pub fn empty(krate: Crate) -> Arc<Self> {
Arc::new(TraitEnvironment {
krate,
block: None,
@ -66,7 +66,7 @@ impl TraitEnvironment {
}
pub fn new(
krate: CrateId,
krate: Crate,
block: Option<BlockId>,
traits_from_clauses: Box<[(Ty, TraitId)]>,
env: chalk_ir::Environment<Interner>,
@ -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<BlockId>,
goal: Canonical<InEnvironment<Goal>>,
) -> Option<Solution> {
@ -148,7 +148,7 @@ pub(crate) fn trait_solve_query(
fn solve(
db: &dyn HirDatabase,
krate: CrateId,
krate: Crate,
block: Option<BlockId>,
goal: &chalk_ir::UCanonical<chalk_ir::InEnvironment<chalk_ir::Goal<Interner>>>,
) -> Option<chalk_solve::Solution<Interner>> {
@ -294,7 +294,7 @@ impl FnTrait {
}
}
pub fn get_id(self, db: &dyn HirDatabase, krate: CrateId) -> Option<TraitId> {
pub fn get_id(self, db: &dyn HirDatabase, krate: Crate) -> Option<TraitId> {
let target = db.lang_item(krate, self.lang_item())?;
match target {
LangItemTarget::Trait(t) => Some(t),

View file

@ -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<Item = TraitId> + '_ {
pub(crate) fn fn_traits(db: &dyn DefDatabase, krate: Crate) -> impl Iterator<Item = TraitId> + '_ {
[LangItem::Fn, LangItem::FnMut, LangItem::FnOnce]
.into_iter()
.filter_map(move |lang| db.lang_item(krate, lang))

View file

@ -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),

View file

@ -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<CrateDependency> {
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<Crate> {
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<Item = Crate> {
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<String> {
db.crate_graph()[self.id].version.clone()
self.id.extra_data(db).version.clone()
}
pub fn display_name(self, db: &dyn HirDatabase) -> Option<CrateDisplayName> {
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<Crate> {
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<CfgOptions> {
db.crate_graph()[self.id].cfg_options.clone()
Arc::clone(self.id.cfg_options(db))
}
pub fn potential_cfg(&self, db: &dyn HirDatabase) -> Arc<CfgOptions> {
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<Crate> {
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<AnyDiagnostic>
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<CrateId>,
krate: Option<base_db::Crate>,
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.

View file

@ -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(),
}
}

View file

@ -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()),
}
}

View file

@ -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<ast::Expr>,
generic_arg_list: Option<ast::GenericArgList>,
krate: CrateId,
krate: Crate,
}
impl CallInfo {
fn from_name_ref(name_ref: ast::NameRef, krate: CrateId) -> Option<CallInfo> {
fn from_name_ref(name_ref: ast::NameRef, krate: Crate) -> Option<CallInfo> {
let parent = name_ref.syntax().parent()?;
if let Some(call) = ast::MethodCallExpr::cast(parent.clone()) {
let receiver = call.receiver()?;

View file

@ -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

View file

@ -1,6 +1,6 @@
//! See [`FamousDefs`].
use base_db::{CrateOrigin, LangCrateOrigin, RootQueryDb as _};
use base_db::{CrateOrigin, LangCrateOrigin};
use hir::{Crate, Enum, Function, Macro, Module, ScopeDef, Semantics, Trait};
use crate::RootDatabase;
@ -198,11 +198,10 @@ impl FamousDefs<'_, '_> {
fn find_lang_crate(&self, origin: LangCrateOrigin) -> Option<Crate> {
let krate = self.1;
let db = self.0.db;
let crate_graph = self.0.db.crate_graph();
let res = krate
.dependencies(db)
.into_iter()
.find(|dep| crate_graph[dep.krate.into()].origin == CrateOrigin::Lang(origin))?
.find(|dep| dep.krate.origin(db) == CrateOrigin::Lang(origin))?
.krate;
Some(res)
}

View file

@ -51,9 +51,8 @@ use salsa::Durability;
use std::{fmt, mem::ManuallyDrop};
use base_db::{
query_group::{self},
FileSourceRootInput, FileText, Files, RootQueryDb, SourceDatabase, SourceRoot, SourceRootId,
SourceRootInput, Upcast,
query_group, CrateGraphBuilder, CratesMap, FileSourceRootInput, FileText, Files, RootQueryDb,
SourceDatabase, SourceRoot, SourceRootId, SourceRootInput, Upcast,
};
use hir::{
db::{DefDatabase, ExpandDatabase, HirDatabase},
@ -85,6 +84,7 @@ pub struct RootDatabase {
// compile times of all `ide_*` and downstream crates suffer greatly.
storage: ManuallyDrop<salsa::Storage<Self>>,
files: Arc<Files>,
crates_map: Arc<CratesMap>,
}
impl std::panic::RefUnwindSafe for RootDatabase {}
@ -102,7 +102,11 @@ impl Drop for RootDatabase {
impl Clone for RootDatabase {
fn clone(&self) -> Self {
Self { storage: self.storage.clone(), files: self.files.clone() }
Self {
storage: self.storage.clone(),
files: self.files.clone(),
crates_map: self.crates_map.clone(),
}
}
}
@ -194,6 +198,10 @@ impl SourceDatabase for RootDatabase {
let files = Arc::clone(&self.files);
files.set_file_source_root_with_durability(self, id, source_root_id, durability);
}
fn crates_map(&self) -> Arc<CratesMap> {
self.crates_map.clone()
}
}
impl Default for RootDatabase {
@ -207,8 +215,11 @@ impl RootDatabase {
let mut db = RootDatabase {
storage: ManuallyDrop::new(salsa::Storage::default()),
files: Default::default(),
crates_map: Default::default(),
};
db.set_crate_graph_with_durability(Default::default(), Durability::HIGH);
// This needs to be here otherwise `CrateGraphBuilder` will panic.
db.set_all_crates(Arc::new(Box::new([])));
CrateGraphBuilder::default().set_in_db(&mut db);
db.set_proc_macros_with_durability(Default::default(), Durability::HIGH);
db.set_local_roots_with_durability(Default::default(), Durability::HIGH);
db.set_library_roots_with_durability(Default::default(), Durability::HIGH);
@ -258,7 +269,11 @@ impl RootDatabase {
}
pub fn snapshot(&self) -> Self {
Self { storage: self.storage.clone(), files: self.files.clone() }
Self {
storage: self.storage.clone(),
files: self.files.clone(),
crates_map: self.crates_map.clone(),
}
}
}

View file

@ -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

View file

@ -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 }

View file

@ -2,7 +2,9 @@
(
Module {
id: ModuleId {
krate: Idx::<CrateData>(0),
krate: Crate {
[salsa id]: Id(2c00),
},
block: None,
local_id: Idx::<ModuleData>(0),
},

View file

@ -2,7 +2,9 @@
(
Module {
id: ModuleId {
krate: Idx::<CrateData>(0),
krate: Crate {
[salsa id]: Id(2c00),
},
block: None,
local_id: Idx::<ModuleData>(0),
},
@ -532,7 +534,9 @@
def: Module(
Module {
id: ModuleId {
krate: Idx::<CrateData>(0),
krate: Crate {
[salsa id]: Id(2c00),
},
block: None,
local_id: Idx::<ModuleData>(1),
},
@ -565,7 +569,9 @@
def: Module(
Module {
id: ModuleId {
krate: Idx::<CrateData>(0),
krate: Crate {
[salsa id]: Id(2c00),
},
block: None,
local_id: Idx::<ModuleData>(2),
},
@ -827,7 +833,9 @@
(
Module {
id: ModuleId {
krate: Idx::<CrateData>(0),
krate: Crate {
[salsa id]: Id(2c00),
},
block: None,
local_id: Idx::<ModuleData>(1),
},
@ -871,7 +879,9 @@
(
Module {
id: ModuleId {
krate: Idx::<CrateData>(0),
krate: Crate {
[salsa id]: Id(2c00),
},
block: None,
local_id: Idx::<ModuleData>(2),
},

View file

@ -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 };

View file

@ -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()

View file

@ -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(

View file

@ -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<SyntaxContextId>,
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::<dyn ide_db::base_db::RootQueryDb>::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());

View file

@ -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<CrateInfo> {
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<String> {
fn crate_name(data: &ide_db::base_db::ExtraCrateData) -> Option<String> {
data.display_name.as_ref().map(|it| it.canonical_name().as_str().to_owned())
}

View file

@ -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<String>,
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()

View file

@ -9252,7 +9252,7 @@ fn main() {
S
```
___
Implements notable traits: Notable, Future<Output = u32>, Iterator<Item = S>"#]],
Implements notable traits: Future<Output = u32>, Iterator<Item = S>, Notable"#]],
);
}

View file

@ -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})
}
"#,
);

View file

@ -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<Vec<TestItem>> {
pub fn discover_tests_in_crate(&self, crate_id: Crate) -> Cancellable<Vec<TestItem>> {
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<Vec<CrateId>> {
pub fn crates_for(&self, file_id: FileId) -> Cancellable<Vec<Crate>> {
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<Vec<CrateId>> {
self.with_db(|db| db.crate_graph().transitive_rev_deps(crate_id).collect())
pub fn transitive_rev_deps(&self, crate_id: Crate) -> Cancellable<Vec<Crate>> {
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<Vec<CrateId>> {
pub fn relevant_crates_for(&self, file_id: FileId) -> Cancellable<Vec<Crate>> {
self.with_db(|db| {
let db = Upcast::<dyn RootQueryDb>::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<Edition> {
self.with_db(|db| db.crate_graph()[crate_id].edition)
pub fn crate_edition(&self, crate_id: Crate) -> Cancellable<Edition> {
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<bool> {
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<bool> {
pub fn is_crate_no_std(&self, crate_id: Crate) -> Cancellable<bool> {
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<FileId> {
self.with_db(|db| db.crate_graph()[crate_id].root_file_id)
pub fn crate_root(&self, crate_id: Crate) -> Cancellable<FileId> {
self.with_db(|db| crate_id.data(db).root_file_id)
}
/// Returns the set of possible targets to run for the current file.

View file

@ -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<Na
}
/// This returns `Vec` because a module may be included from several places.
pub(crate) fn crates_for(db: &RootDatabase, file_id: FileId) -> Vec<CrateId> {
pub(crate) fn crates_for(db: &RootDatabase, file_id: FileId) -> Vec<Crate> {
let root_db = Upcast::<dyn RootQueryDb>::upcast(db);
root_db
.relevant_crates(file_id)

View file

@ -498,9 +498,8 @@ fn module_def_doctest(db: &RootDatabase, def: Definition) -> Option<Runnable> {
};
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;
}

View file

@ -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),
)
}

View file

@ -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<FileId>) -> String {
if crates.is_empty() {
format_to!(buf, "Does not belong to any crate");
}
let crate_graph = Upcast::<dyn RootQueryDb>::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<FileId>) -> 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);
}

View file

@ -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<TestItem> {
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<TestItem> {
.collect()
}
fn find_crate_by_id(crate_graph: &CrateGraph, crate_id: &str) -> Option<CrateId> {
fn find_crate_by_id(db: &RootDatabase, crate_id: &str) -> Option<base_db::Crate> {
// 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<TestItem> {
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<TestItem> {
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<TestItem> {
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);

View file

@ -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<String, String> {
let crate_graph = Upcast::<dyn RootQueryDb>::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<CrateGraph>,
crates_to_render: FxHashSet<CrateId>,
struct DotCrateGraph<'db> {
crates_to_render: FxHashMap<Crate, (&'db BuiltCrateData, &'db ExtraCrateData)>,
}
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<LabelText<'a>> {
fn node_shape(&'a self, _node: &Crate) -> Option<LabelText<'a>> {
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())
}
}

View file

@ -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<std::cmp::Ordering> {
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,
}

View file

@ -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<vfs::loader::Message>,
) -> RootDatabase {
let ProjectWorkspace { toolchain, target_layout, .. } = ws;
let lru_cap = std::env::var("RA_LRU_CAP").ok().and_then(|it| it.parse::<u16>().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::<Self>().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);
}

View file

@ -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<AbsPathBuf>,
name: Box<str>,
kind: ProcMacroKind,
dylib_last_modified: Option<SystemTime>,
}
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 }),

View file

@ -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"#]],
);
}

View file

@ -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)]

View file

@ -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<AbsPathBuf, FileId>,
) -> (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);

View file

@ -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<String, String>,
) -> (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<String, String>,
override_cfg: &CfgOverrides,
set_test: bool,
) -> (CrateGraph, ProcMacroPaths) {
let mut res = (CrateGraph::default(), ProcMacroPaths::default());
crate_ws_data: Arc<CrateWorkspaceData>,
) -> (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<CfgAtom>> = FxHashMap::default();
let idx_to_crate_id: FxHashMap<CrateArrayIdx, CrateId> = project
let idx_to_crate_id: FxHashMap<CrateArrayIdx, _> = 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<CrateWorkspaceData>,
) -> (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<CrateWorkspaceData>,
) -> (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<Package, CrateId>,
pkg_to_lib_crate: &mut FxHashMap<Package, CrateBuilderId>,
load: FileLoader<'_>,
rustc_workspace: &CargoWorkspace,
cargo: &CargoWorkspace,
public_deps: &SysrootPublicDeps,
libproc_macro: Option<CrateId>,
pkg_crates: &FxHashMap<Package, Vec<(CrateId, TargetKind)>>,
libproc_macro: Option<CrateBuilderId>,
pkg_crates: &FxHashMap<Package, Vec<(CrateBuilderId, TargetKind)>>,
cfg_options: &CfgOptions,
override_cfg: &CfgOverrides,
build_scripts: &WorkspaceBuildScripts,
crate_ws_data: Arc<CrateWorkspaceData>,
) {
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<CrateWorkspaceData>,
) -> 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<CrateId>) {
) -> (SysrootPublicDeps, Option<CrateBuilderId>) {
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<CfgAtom>,
load: FileLoader<'_>,
) -> (SysrootPublicDeps, Option<CrateId>) {
crate_ws_data: Arc<CrateWorkspaceData>,
) -> (SysrootPublicDeps, Option<CrateBuilderId>) {
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<crate::sysroot::stitched::RustLibSrcCrate, CrateId> =
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)
}

View file

@ -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::<CrateBuilder>(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::<CrateData>(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::<CrateBuilder>(0),
name: CrateName(
"hello_world",
),
prelude: true,
sysroot: false,
},
Dependency {
crate_id: Idx::<CrateBuilder>(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::<CrateData>(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::<CrateBuilder>(0),
name: CrateName(
"hello_world",
),
prelude: true,
sysroot: false,
},
Dependency {
crate_id: Idx::<CrateBuilder>(4),
name: CrateName(
"libc",
),
prelude: true,
sysroot: false,
},
],
origin: Local {
repo: None,
name: Some(
"hello-world",
),
prelude: true,
sysroot: false,
},
Dependency {
crate_id: Idx::<CrateData>(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::<CrateData>(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::<CrateBuilder>(0),
name: CrateName(
"hello_world",
),
prelude: true,
sysroot: false,
},
Dependency {
crate_id: Idx::<CrateBuilder>(4),
name: CrateName(
"libc",
),
prelude: true,
sysroot: false,
},
],
origin: Local {
repo: None,
name: Some(
"hello-world",
),
prelude: true,
sysroot: false,
},
Dependency {
crate_id: Idx::<CrateData>(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::<CrateData>(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::<CrateData>(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",
),
),
},
}

View file

@ -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::<CrateBuilder>(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::<CrateData>(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::<CrateBuilder>(0),
name: CrateName(
"hello_world",
),
prelude: true,
sysroot: false,
},
Dependency {
crate_id: Idx::<CrateBuilder>(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::<CrateData>(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::<CrateBuilder>(0),
name: CrateName(
"hello_world",
),
prelude: true,
sysroot: false,
},
Dependency {
crate_id: Idx::<CrateBuilder>(4),
name: CrateName(
"libc",
),
prelude: true,
sysroot: false,
},
],
origin: Local {
repo: None,
name: Some(
"hello-world",
),
prelude: true,
sysroot: false,
},
Dependency {
crate_id: Idx::<CrateData>(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::<CrateData>(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::<CrateBuilder>(0),
name: CrateName(
"hello_world",
),
prelude: true,
sysroot: false,
},
Dependency {
crate_id: Idx::<CrateBuilder>(4),
name: CrateName(
"libc",
),
prelude: true,
sysroot: false,
},
],
origin: Local {
repo: None,
name: Some(
"hello-world",
),
prelude: true,
sysroot: false,
},
Dependency {
crate_id: Idx::<CrateData>(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::<CrateData>(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::<CrateData>(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",
),
),
},
}

View file

@ -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::<CrateBuilder>(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::<CrateData>(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::<CrateBuilder>(0),
name: CrateName(
"hello_world",
),
prelude: true,
sysroot: false,
},
Dependency {
crate_id: Idx::<CrateBuilder>(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::<CrateData>(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::<CrateBuilder>(0),
name: CrateName(
"hello_world",
),
prelude: true,
sysroot: false,
},
Dependency {
crate_id: Idx::<CrateBuilder>(4),
name: CrateName(
"libc",
),
prelude: true,
sysroot: false,
},
],
origin: Local {
repo: None,
name: Some(
"hello-world",
),
prelude: true,
sysroot: false,
},
Dependency {
crate_id: Idx::<CrateData>(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::<CrateData>(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::<CrateBuilder>(0),
name: CrateName(
"hello_world",
),
prelude: true,
sysroot: false,
},
Dependency {
crate_id: Idx::<CrateBuilder>(4),
name: CrateName(
"libc",
),
prelude: true,
sysroot: false,
},
],
origin: Local {
repo: None,
name: Some(
"hello-world",
),
prelude: true,
sysroot: false,
},
Dependency {
crate_id: Idx::<CrateData>(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::<CrateData>(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::<CrateData>(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",
),
),
},
}

Some files were not shown because too many files have changed in this diff Show more