Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 16 additions & 18 deletions crates/base-db/src/change.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,14 @@ use vfs::FileId;

use crate::{
CrateGraphBuilder, CratesIdMap, LibraryRoots, LocalRoots, SourceDatabase, SourceRoot,
SourceRootId,
SourceRootId, SourceRootKind,
};

/// 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 roots: Option<Vec<(SourceRootId, SourceRoot)>>,
pub files_changed: Vec<(FileId, Option<String>, SourceRootKind)>,
pub crate_graph: Option<CrateGraphBuilder>,
}

Expand All @@ -38,12 +38,12 @@ impl fmt::Debug for FileChange {
}

impl FileChange {
pub fn set_roots(&mut self, roots: Vec<SourceRoot>) {
pub fn set_roots(&mut self, roots: Vec<(SourceRootId, SourceRoot)>) {
self.roots = Some(roots);
}

pub fn change_file(&mut self, file_id: FileId, new_text: Option<String>) {
self.files_changed.push((file_id, new_text))
pub fn change_file(&mut self, file_id: FileId, new_text: Option<String>, kind: SourceRootKind) {
self.files_changed.push((file_id, new_text, kind))
}

pub fn set_crate_graph(&mut self, graph: CrateGraphBuilder) {
Expand All @@ -55,13 +55,18 @@ impl FileChange {
if let Some(roots) = self.roots {
let mut local_roots = FxHashSet::default();
let mut library_roots = FxHashSet::default();
for (idx, root) in roots.into_iter().enumerate() {
let root_id = SourceRootId(idx as u32);
for (root_id, root) in roots {
if root.is_library {
library_roots.insert(root_id);
} else {
local_roots.insert(root_id);
}
// Library source roots (and their file mappings) are stored with `NEVER_CHANGE`
// durability and are assumed immutable, so we emit them only once. Repartitioning
// re-produces them on every structural change; re-setting them would panic.
if root.is_library && db.is_source_root_initialized(root_id) {
continue;
}
let durability = source_root_durability(&root);
for file_id in root.iter() {
db.set_file_source_root_with_durability(file_id, root_id, durability);
Expand All @@ -73,11 +78,8 @@ impl FileChange {
LibraryRoots::get(db).set_roots(db).to(library_roots);
}

for (file_id, text) in self.files_changed {
let source_root_id = db.file_source_root(file_id);
let source_root = db.source_root(source_root_id.source_root_id(db));

let durability = file_text_durability(&source_root.source_root(db));
for (file_id, text, kind) in self.files_changed {
let durability = kind.file_text_durability();
// XXX: can't actually remove the file, just reset the text
let text = text.unwrap_or_default();
db.set_file_text_with_durability(file_id, &text, durability)
Expand All @@ -91,9 +93,5 @@ impl FileChange {
}

fn source_root_durability(source_root: &SourceRoot) -> Durability {
if source_root.is_library { Durability::MEDIUM } else { Durability::LOW }
}

fn file_text_durability(source_root: &SourceRoot) -> Durability {
if source_root.is_library { Durability::HIGH } else { Durability::LOW }
if source_root.is_library { Durability::NEVER_CHANGE } else { Durability::MEDIUM }
}
23 changes: 22 additions & 1 deletion crates/base-db/src/input.rs
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,27 @@ impl SourceRoot {
}
}

/// Whether a file or source root belongs to immutable library sources (sysroot,
/// crates.io) or to the mutable local workspace.
///
/// Library sources are assumed to never change over the lifetime of the program,
/// which lets us store their file text with [`salsa::Durability::NEVER_CHANGE`].
#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)]
pub enum SourceRootKind {
Local,
Library,
}

impl SourceRootKind {
/// Durability to use for the text of files belonging to a source root of this kind.
pub fn file_text_durability(self) -> Durability {
match self {
SourceRootKind::Local => Durability::LOW,
SourceRootKind::Library => Durability::NEVER_CHANGE,
}
}
}

#[derive(Default, Clone)]
pub struct CrateGraphBuilder {
arena: Arena<CrateBuilder>,
Expand Down Expand Up @@ -447,7 +468,7 @@ impl BuiltDependency {

pub type CratesIdMap = FxHashMap<CrateBuilderId, Crate>;

#[salsa_macros::input]
#[salsa::input]
#[derive(Debug, PartialOrd, Ord)]
pub struct Crate {
#[returns(ref)]
Expand Down
18 changes: 14 additions & 4 deletions crates/base-db/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ pub use crate::{
BuiltCrateData, BuiltDependency, Crate, CrateBuilder, CrateBuilderId, CrateDataBuilder,
CrateDisplayName, CrateGraphBuilder, CrateName, CrateOrigin, CratesIdMap, CratesMap,
DependencyBuilder, Env, ExtraCrateData, LangCrateOrigin, ProcMacroLoadingError,
ProcMacroPaths, ReleaseChannel, SourceRoot, SourceRootId, UniqueCrateData,
ProcMacroPaths, ReleaseChannel, SourceRoot, SourceRootId, SourceRootKind, UniqueCrateData,
},
};
use dashmap::{DashMap, mapref::entry::Entry};
Expand Down Expand Up @@ -151,6 +151,11 @@ impl Files {
*source_root
}

/// Whether a source root with the given id has already been set.
pub fn is_source_root_initialized(&self, source_root_id: SourceRootId) -> bool {
self.source_roots.contains_key(&source_root_id)
}

pub fn set_source_root_with_durability(
&self,
db: &mut dyn SourceDatabase,
Expand Down Expand Up @@ -236,19 +241,19 @@ pub struct LocalRoots {
pub roots: FxHashSet<SourceRootId>,
}

#[salsa_macros::input(debug)]
#[salsa::input(debug)]
pub struct FileText {
#[returns(ref)]
pub text: Arc<str>,
pub file_id: vfs::FileId,
}

#[salsa_macros::input(debug)]
#[salsa::input(debug)]
pub struct FileSourceRootInput {
pub source_root_id: SourceRootId,
}

#[salsa_macros::input(debug)]
#[salsa::input(debug)]
pub struct SourceRootInput {
pub source_root: Arc<SourceRoot>,
}
Expand All @@ -270,6 +275,11 @@ pub trait SourceDatabase: salsa::Database {
/// Contents of the source root.
fn source_root(&self, id: SourceRootId) -> SourceRootInput;

/// Whether a source root with the given id has already been set.
///
/// Unlike [`SourceDatabase::source_root`], this does not panic for unknown ids.
fn is_source_root_initialized(&self, id: SourceRootId) -> bool;

fn file_source_root(&self, id: vfs::FileId) -> FileSourceRootInput;

fn set_file_source_root_with_durability(
Expand Down
4 changes: 4 additions & 0 deletions crates/hir-def/src/test_db.rs
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,10 @@ impl SourceDatabase for TestDB {
self.files.source_root(source_root_id)
}

fn is_source_root_initialized(&self, source_root_id: SourceRootId) -> bool {
self.files.is_source_root_initialized(source_root_id)
}

fn set_source_root_with_durability(
&mut self,
source_root_id: SourceRootId,
Expand Down
10 changes: 6 additions & 4 deletions crates/hir-expand/src/change.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
//! Defines a unit of change that can applied to the database to get the next
//! state. Changes are transactional.
use base_db::{CrateGraphBuilder, FileChange, SourceRoot, salsa::Durability};
use base_db::{
CrateGraphBuilder, FileChange, SourceRoot, SourceRootId, SourceRootKind, salsa::Durability,
};
use span::FileId;
use triomphe::Arc;

Expand All @@ -25,8 +27,8 @@ impl ChangeWithProcMacros {
}
}

pub fn change_file(&mut self, file_id: FileId, new_text: Option<String>) {
self.source_change.change_file(file_id, new_text)
pub fn change_file(&mut self, file_id: FileId, new_text: Option<String>, kind: SourceRootKind) {
self.source_change.change_file(file_id, new_text, kind)
}

pub fn set_crate_graph(&mut self, graph: CrateGraphBuilder) {
Expand All @@ -37,7 +39,7 @@ impl ChangeWithProcMacros {
self.proc_macros = Some(proc_macros);
}

pub fn set_roots(&mut self, roots: Vec<SourceRoot>) {
pub fn set_roots(&mut self, roots: Vec<(SourceRootId, SourceRoot)>) {
self.source_change.set_roots(roots)
}
}
4 changes: 4 additions & 0 deletions crates/hir-ty/src/test_db.rs
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,10 @@ impl SourceDatabase for TestDB {
self.files.source_root(source_root_id)
}

fn is_source_root_initialized(&self, source_root_id: SourceRootId) -> bool {
self.files.is_source_root_initialized(source_root_id)
}

fn set_source_root_with_durability(
&mut self,
source_root_id: SourceRootId,
Expand Down
4 changes: 4 additions & 0 deletions crates/ide-db/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,10 @@ impl SourceDatabase for RootDatabase {
self.files.source_root(source_root_id)
}

fn is_source_root_initialized(&self, source_root_id: SourceRootId) -> bool {
self.files.is_source_root_initialized(source_root_id)
}

fn set_source_root_with_durability(
&mut self,
source_root_id: SourceRootId,
Expand Down
6 changes: 3 additions & 3 deletions crates/ide/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,7 @@ pub use ide_completion::{
pub use ide_db::{
FileId, FilePosition, FileRange, RootDatabase, Severity, SymbolKind,
assists::ExprFillDefaultMode,
base_db::{Crate, CrateGraphBuilder, FileChange, SourceRoot, SourceRootId},
base_db::{Crate, CrateGraphBuilder, FileChange, SourceRoot, SourceRootId, SourceRootKind},
documentation::Documentation,
label::Label,
line_index::{LineCol, LineIndex},
Expand Down Expand Up @@ -263,7 +263,7 @@ impl Analysis {
let source_root = SourceRoot::new_local(file_set);

let mut change = ChangeWithProcMacros::default();
change.set_roots(vec![source_root]);
change.set_roots(vec![(SourceRootId(0), source_root)]);
let mut crate_graph = CrateGraphBuilder::default();
// FIXME: cfg options
// Default to enable test for single file.
Expand All @@ -288,7 +288,7 @@ impl Analysis {
toolchain: None,
}),
);
change.change_file(file_id, Some(text));
change.change_file(file_id, Some(text), SourceRootKind::Local);
change.set_crate_graph(crate_graph);

host.apply_change(change);
Expand Down
Loading
Loading