Repository: rust-analyzer/rust-analyzer
Pull request #5245 (2020-07-07 10:18:38)

Refactor AssistBuilder to manage a SourceChange
`AssistBuilder` now managaes a full `SourceChange` instead of a
`Vec<SourceFileEdit>`.

This prepares AssistBuilder to handle creation of new files.



Patch:
diff --git a/Cargo.lock b/Cargo.lock
index 54a95621a6..c23fea77be 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1490,8 +1490,9 @@ checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e"
 
 [[package]]
 name = "salsa"
-version = "0.14.3"
-source = "git+https://github.com/nikomatsakis/salsa?branch=dynamic-databases-rfc#fd036a4f154c46253443b3a79b6f4400c40e87b1"
+version = "0.14.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d4ca1c656054666a642affbbc86ab95ed7541125a89f032483d34ee56c0f5390"
 dependencies = [
  "crossbeam-utils",
  "indexmap",
@@ -1507,7 +1508,8 @@ dependencies = [
 [[package]]
 name = "salsa-macros"
 version = "0.14.1"
-source = "git+https://github.com/nikomatsakis/salsa?branch=dynamic-databases-rfc#fd036a4f154c46253443b3a79b6f4400c40e87b1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "038a09b6271446f1123f142fe7e5bef6d4687c4cf82e6986be574c2af3745530"
 dependencies = [
  "heck",
  "proc-macro2",
diff --git a/crates/ra_assists/src/assist_context.rs b/crates/ra_assists/src/assist_context.rs
index 3640bb4d26..c335253635 100644
--- a/crates/ra_assists/src/assist_context.rs
+++ b/crates/ra_assists/src/assist_context.rs
@@ -176,7 +176,7 @@ pub(crate) struct AssistBuilder {
     edit: TextEditBuilder,
     file_id: FileId,
     is_snippet: bool,
-    edits: Vec<SourceFileEdit>,
+    change: SourceChange,
 }
 
 impl AssistBuilder {
@@ -185,7 +185,7 @@ impl AssistBuilder {
             edit: TextEditBuilder::default(),
             file_id,
             is_snippet: false,
-            edits: Vec::new(),
+            change: SourceChange::default(),
         }
     }
 
@@ -197,8 +197,8 @@ impl AssistBuilder {
         let edit = mem::take(&mut self.edit).finish();
         if !edit.is_empty() {
             let new_edit = SourceFileEdit { file_id: self.file_id, edit };
-            assert!(!self.edits.iter().any(|it| it.file_id == new_edit.file_id));
-            self.edits.push(new_edit);
+            assert!(!self.change.source_file_edits.iter().any(|it| it.file_id == new_edit.file_id));
+            self.change.source_file_edits.push(new_edit);
         }
     }
 
@@ -265,10 +265,10 @@ impl AssistBuilder {
 
     fn finish(mut self) -> SourceChange {
         self.commit();
-        let mut res: SourceChange = mem::take(&mut self.edits).into();
+        let mut change = mem::take(&mut self.change);
         if self.is_snippet {
-            res.is_snippet = true;
+            change.is_snippet = true;
         }
-        res
+        change
     }
 }
diff --git a/crates/ra_db/Cargo.toml b/crates/ra_db/Cargo.toml
index b2d481dfb4..372fb242b1 100644
--- a/crates/ra_db/Cargo.toml
+++ b/crates/ra_db/Cargo.toml
@@ -8,7 +8,7 @@ authors = ["rust-analyzer developers"]
 doctest = false
 
 [dependencies]
-salsa = { git = "https://github.com/nikomatsakis/salsa", branch = "dynamic-databases-rfc" }
+salsa = "0.14.1"
 relative-path = "1.0.0"
 rustc-hash = "1.1.0"
 
diff --git a/crates/ra_db/src/lib.rs b/crates/ra_db/src/lib.rs
index 590efffa44..1ddacc1f6c 100644
--- a/crates/ra_db/src/lib.rs
+++ b/crates/ra_db/src/lib.rs
@@ -113,7 +113,7 @@ pub trait SourceDatabase: CheckCanceled + FileLoader + std::fmt::Debug {
     fn crate_graph(&self) -> Arc<CrateGraph>;
 }
 
-fn parse_query(db: &dyn SourceDatabase, file_id: FileId) -> Parse<ast::SourceFile> {
+fn parse_query(db: &impl SourceDatabase, file_id: FileId) -> Parse<ast::SourceFile> {
     let _p = profile("parse_query").detail(|| format!("{:?}", file_id));
     let text = db.file_text(file_id);
     SourceFile::parse(&*text)
@@ -136,7 +136,10 @@ pub trait SourceDatabaseExt: SourceDatabase {
     fn source_root_crates(&self, id: SourceRootId) -> Arc<FxHashSet<CrateId>>;
 }
 
-fn source_root_crates(db: &dyn SourceDatabaseExt, id: SourceRootId) -> Arc<FxHashSet<CrateId>> {
+fn source_root_crates(
+    db: &(impl SourceDatabaseExt + SourceDatabase),
+    id: SourceRootId,
+) -> Arc<FxHashSet<CrateId>> {
     let graph = db.crate_graph();
     let res = graph
         .iter()
diff --git a/crates/ra_hir_def/src/data.rs b/crates/ra_hir_def/src/data.rs
index aa335f1e30..282ade2a3a 100644
--- a/crates/ra_hir_def/src/data.rs
+++ b/crates/ra_hir_def/src/data.rs
@@ -31,7 +31,7 @@ pub struct FunctionData {
 }
 
 impl FunctionData {
-    pub(crate) fn fn_data_query(db: &dyn DefDatabase, func: FunctionId) -> Arc<FunctionData> {
+    pub(crate) fn fn_data_query(db: &impl DefDatabase, func: FunctionId) -> Arc<FunctionData> {
         let loc = func.lookup(db);
         let item_tree = db.item_tree(loc.id.file_id);
         let func = &item_tree[loc.id.value];
diff --git a/crates/ra_hir_ty/src/db.rs b/crates/ra_hir_ty/src/db.rs
index 84afe0484b..dc06c0ee72 100644
--- a/crates/ra_hir_ty/src/db.rs
+++ b/crates/ra_hir_ty/src/db.rs
@@ -19,6 +19,7 @@ use crate::{
 use hir_expand::name::Name;
 
 #[salsa::query_group(HirDatabaseStorage)]
+#[salsa::requires(salsa::Database)]
 pub trait HirDatabase: DefDatabase + Upcast<dyn DefDatabase> {
     #[salsa::invoke(infer_wait)]
     #[salsa::transparent]
diff --git a/crates/ra_hir_ty/src/display.rs b/crates/ra_hir_ty/src/display.rs
index ac68c5661e..23cea1a2ad 100644
--- a/crates/ra_hir_ty/src/display.rs
+++ b/crates/ra_hir_ty/src/display.rs
@@ -369,7 +369,7 @@ impl HirDisplay for ApplicationTy {
                         let data = (*datas)
                             .as_ref()
                             .map(|rpit| rpit.impl_traits[idx as usize].bounds.clone());
-                        data.subst(&self.parameters)
+                        data.clone().subst(&self.parameters)
                     }
                 };
                 write!(f, "impl ")?;
@@ -456,7 +456,7 @@ impl HirDisplay for Ty {
                         let data = (*datas)
                             .as_ref()
                             .map(|rpit| rpit.impl_traits[idx as usize].bounds.clone());
-                        data.subst(&opaque_ty.parameters)
+                        data.clone().subst(&opaque_ty.parameters)
                     }
                 };
                 write!(f, "impl ")?;
diff --git a/crates/ra_hir_ty/src/infer/expr.rs b/crates/ra_hir_ty/src/infer/expr.rs
index 06baac2a9b..22884522a8 100644
--- a/crates/ra_hir_ty/src/infer/expr.rs
+++ b/crates/ra_hir_ty/src/infer/expr.rs
@@ -85,8 +85,10 @@ impl<'a> InferenceContext<'a> {
             ctor: TypeCtor::Tuple { cardinality: num_args as u16 },
             parameters,
         });
-        let substs =
-            Substs::build_for_generics(&generic_params).push(ty.clone()).push(arg_ty).build();
+        let substs = Substs::build_for_generics(&generic_params)
+            .push(ty.clone())
+            .push(arg_ty.clone())
+            .build();
 
         let trait_env = Arc::clone(&self.trait_env);
         let implements_fn_trait =
diff --git a/crates/ra_hir_ty/src/lib.rs b/crates/ra_hir_ty/src/lib.rs
index c12bed4af3..7f3f5e7715 100644
--- a/crates/ra_hir_ty/src/lib.rs
+++ b/crates/ra_hir_ty/src/lib.rs
@@ -891,7 +891,7 @@ impl Ty {
                             let data = (*it)
                                 .as_ref()
                                 .map(|rpit| rpit.impl_traits[idx as usize].bounds.clone());
-                            data.subst(&opaque_ty.parameters)
+                            data.clone().subst(&opaque_ty.parameters)
                         })
                     }
                 };
diff --git a/crates/ra_hir_ty/src/lower.rs b/crates/ra_hir_ty/src/lower.rs
index 3af8d55a1b..3dc154e92b 100644
--- a/crates/ra_hir_ty/src/lower.rs
+++ b/crates/ra_hir_ty/src/lower.rs
@@ -720,7 +720,8 @@ fn assoc_type_bindings_from_type_bound<'a>(
                 None => return SmallVec::<[GenericPredicate; 1]>::new(),
                 Some(t) => t,
             };
-            let projection_ty = ProjectionTy { associated_ty, parameters: super_trait_ref.substs };
+            let projection_ty =
+                ProjectionTy { associated_ty, parameters: super_trait_ref.substs.clone() };
             let mut preds = SmallVec::with_capacity(
                 binding.type_ref.as_ref().map_or(0, |_| 1) + binding.bounds.len(),
             );
@@ -1215,7 +1216,7 @@ pub(crate) fn impl_trait_query(db: &dyn HirDatabase, impl_id: ImplId) -> Option<
 }
 
 pub(crate) fn return_type_impl_traits(
-    db: &dyn HirDatabase,
+    db: &impl HirDatabase,
     def: hir_def::FunctionId,
 ) -> Option<Arc<Binders<ReturnTypeImplTraits>>> {
     // FIXME unify with fn_sig_for_fn instead of doing lowering twice, maybe
diff --git a/crates/ra_hir_ty/src/traits/chalk/tls.rs b/crates/ra_hir_ty/src/traits/chalk/tls.rs
index e6a9d32116..556af70989 100644
--- a/crates/ra_hir_ty/src/traits/chalk/tls.rs
+++ b/crates/ra_hir_ty/src/traits/chalk/tls.rs
@@ -10,7 +10,7 @@ use hir_def::{AdtId, AssocContainerId, DefWithBodyId, Lookup, TypeAliasId};
 
 pub use unsafe_tls::{set_current_program, with_current_program};
 
-pub struct DebugContext<'a>(&'a dyn HirDatabase);
+pub struct DebugContext<'a>(&'a (dyn HirDatabase + 'a));
 
 impl DebugContext<'_> {
     pub fn debug_struct_id(
diff --git a/crates/ra_ide/src/status.rs b/crates/ra_ide/src/status.rs
index 08e6f69cb3..45411b357c 100644
--- a/crates/ra_ide/src/status.rs
+++ b/crates/ra_ide/src/status.rs
@@ -2,7 +2,10 @@ use std::{fmt, iter::FromIterator, sync::Arc};
 
 use hir::MacroFile;
 use ra_db::{
-    salsa::debug::{DebugQueryTable, TableEntry},
+    salsa::{
+        debug::{DebugQueryTable, TableEntry},
+        Database,
+    },
     FileTextQuery, SourceRootId,
 };
 use ra_ide_db::{
@@ -11,15 +14,15 @@ use ra_ide_db::{
 };
 use ra_prof::{memory_usage, Bytes};
 use ra_syntax::{ast, Parse, SyntaxNode};
-use rustc_hash::FxHashMap;
 
 use crate::FileId;
+use rustc_hash::FxHashMap;
 
 fn syntax_tree_stats(db: &RootDatabase) -> SyntaxTreeStats {
-    ra_db::ParseQuery.in_db(db).entries::<SyntaxTreeStats>()
+    db.query(ra_db::ParseQuery).entries::<SyntaxTreeStats>()
 }
 fn macro_syntax_tree_stats(db: &RootDatabase) -> SyntaxTreeStats {
-    hir::db::ParseMacroQuery.in_db(db).entries::<SyntaxTreeStats>()
+    db.query(hir::db::ParseMacroQuery).entries::<SyntaxTreeStats>()
 }
 
 // Feature: Status
@@ -32,10 +35,10 @@ fn macro_syntax_tree_stats(db: &RootDatabase) -> SyntaxTreeStats {
 // | VS Code | **Rust Analyzer: Status**
 // |===
 pub(crate) fn status(db: &RootDatabase) -> String {
-    let files_stats = FileTextQuery.in_db(db).entries::<FilesStats>();
+    let files_stats = db.query(FileTextQuery).entries::<FilesStats>();
     let syntax_tree_stats = syntax_tree_stats(db);
     let macro_syntax_tree_stats = macro_syntax_tree_stats(db);
-    let symbols_stats = LibrarySymbolsQuery.in_db(db).entries::<LibrarySymbolsStats>();
+    let symbols_stats = db.query(LibrarySymbolsQuery).entries::<LibrarySymbolsStats>();
     format!(
         "{}\n{}\n{}\n{} (macros)\n\n\nmemory:\n{}\ngc {:?} seconds ago",
         files_stats,
diff --git a/crates/ra_ide_db/src/change.rs b/crates/ra_ide_db/src/change.rs
index d8da3f949e..2504d7a338 100644
--- a/crates/ra_ide_db/src/change.rs
+++ b/crates/ra_ide_db/src/change.rs
@@ -147,21 +147,21 @@ impl RootDatabase {
 
         let sweep = SweepStrategy::default().discard_values().sweep_all_revisions();
 
-        ra_db::ParseQuery.in_db(self).sweep(sweep);
-        hir::db::ParseMacroQuery.in_db(self).sweep(sweep);
+        self.query(ra_db::ParseQuery).sweep(sweep);
+        self.query(hir::db::ParseMacroQuery).sweep(sweep);
 
         // Macros do take significant space, but less then the syntax trees
         // self.query(hir::db::MacroDefQuery).sweep(sweep);
         // self.query(hir::db::MacroArgQuery).sweep(sweep);
         // self.query(hir::db::MacroExpandQuery).sweep(sweep);
 
-        hir::db::AstIdMapQuery.in_db(self).sweep(sweep);
+        self.query(hir::db::AstIdMapQuery).sweep(sweep);
 
-        hir::db::BodyWithSourceMapQuery.in_db(self).sweep(sweep);
+        self.query(hir::db::BodyWithSourceMapQuery).sweep(sweep);
 
-        hir::db::ExprScopesQuery.in_db(self).sweep(sweep);
-        hir::db::InferQueryQuery.in_db(self).sweep(sweep);
-        hir::db::BodyQuery.in_db(self).sweep(sweep);
+        self.query(hir::db::ExprScopesQuery).sweep(sweep);
+        self.query(hir::db::InferQueryQuery).sweep(sweep);
+        self.query(hir::db::BodyQuery).sweep(sweep);
     }
 
     pub fn per_query_memory_usage(&mut self) -> Vec<(String, Bytes)> {
@@ -170,14 +170,14 @@ impl RootDatabase {
         macro_rules! sweep_each_query {
             ($($q:path)*) => {$(
                 let before = memory_usage().allocated;
-                $q.in_db(self).sweep(sweep);
+                self.query($q).sweep(sweep);
                 let after = memory_usage().allocated;
                 let q: $q = Default::default();
                 let name = format!("{:?}", q);
                 acc.push((name, before - after));
 
                 let before = memory_usage().allocated;
-                $q.in_db(self).sweep(sweep.discard_everything());
+                self.query($q).sweep(sweep.discard_everything());
                 let after = memory_usage().allocated;
                 let q: $q = Default::default();
                 let name = format!("{:?} (deps)", q);
@@ -252,7 +252,7 @@ impl RootDatabase {
         // write.
         // We do this after collecting the non-interned queries to correctly attribute memory used
         // by interned data.
-        self.salsa_runtime_mut().synthetic_write(Durability::HIGH);
+        self.runtime.synthetic_write(Durability::HIGH);
 
         sweep_each_query![
             // AstDatabase
diff --git a/crates/ra_ide_db/src/lib.rs b/crates/ra_ide_db/src/lib.rs
index 6900cac73e..c78071ad6e 100644
--- a/crates/ra_ide_db/src/lib.rs
+++ b/crates/ra_ide_db/src/lib.rs
@@ -11,11 +11,11 @@ pub mod imports_locator;
 pub mod source_change;
 mod wasm_shims;
 
-use std::{fmt, sync::Arc};
+use std::sync::Arc;
 
 use hir::db::{AstDatabase, DefDatabase, HirDatabase};
 use ra_db::{
-    salsa::{self, Durability},
+    salsa::{self, Database, Durability},
     Canceled, CheckCanceled, CrateId, FileId, FileLoader, FileLoaderDelegate, SourceDatabase,
     Upcast,
 };
@@ -33,18 +33,13 @@ use crate::{line_index::LineIndex, symbol_index::SymbolsDatabase};
     hir::db::DefDatabaseStorage,
     hir::db::HirDatabaseStorage
 )]
+#[derive(Debug)]
 pub struct RootDatabase {
-    storage: salsa::Storage<RootDatabase>,
+    runtime: salsa::Runtime<RootDatabase>,
     pub last_gc: crate::wasm_shims::Instant,
     pub last_gc_check: crate::wasm_shims::Instant,
 }
 
-impl fmt::Debug for RootDatabase {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        f.debug_struct("RootDatabase").finish()
-    }
-}
-
 impl Upcast<dyn AstDatabase> for RootDatabase {
     fn upcast(&self) -> &(dyn AstDatabase + 'static) {
         &*self
@@ -76,11 +71,17 @@ impl FileLoader for RootDatabase {
 }
 
 impl salsa::Database for RootDatabase {
+    fn salsa_runtime(&self) -> &salsa::Runtime<RootDatabase> {
+        &self.runtime
+    }
+    fn salsa_runtime_mut(&mut self) -> &mut salsa::Runtime<Self> {
+        &mut self.runtime
+    }
     fn on_propagated_panic(&self) -> ! {
         Canceled::throw()
     }
-    fn salsa_event(&self, event: salsa::Event) {
-        match event.kind {
+    fn salsa_event(&self, event: impl Fn() -> salsa::Event<RootDatabase>) {
+        match event().kind {
             salsa::EventKind::DidValidateMemoizedValue { .. }
             | salsa::EventKind::WillExecute { .. } => {
                 self.check_canceled();
@@ -99,7 +100,7 @@ impl Default for RootDatabase {
 impl RootDatabase {
     pub fn new(lru_capacity: Option<usize>) -> RootDatabase {
         let mut db = RootDatabase {
-            storage: salsa::Storage::default(),
+            runtime: salsa::Runtime::default(),
             last_gc: crate::wasm_shims::Instant::now(),
             last_gc_check: crate::wasm_shims::Instant::now(),
         };
@@ -112,16 +113,16 @@ impl RootDatabase {
 
     pub fn update_lru_capacity(&mut self, lru_capacity: Option<usize>) {
         let lru_capacity = lru_capacity.unwrap_or(ra_db::DEFAULT_LRU_CAP);
-        ra_db::ParseQuery.in_db_mut(self).set_lru_capacity(lru_capacity);
-        hir::db::ParseMacroQuery.in_db_mut(self).set_lru_capacity(lru_capacity);
-        hir::db::MacroExpandQuery.in_db_mut(self).set_lru_capacity(lru_capacity);
+        self.query_mut(ra_db::ParseQuery).set_lru_capacity(lru_capacity);
+        self.query_mut(hir::db::ParseMacroQuery).set_lru_capacity(lru_capacity);
+        self.query_mut(hir::db::MacroExpandQuery).set_lru_capacity(lru_capacity);
     }
 }
 
 impl salsa::ParallelDatabase for RootDatabase {
     fn snapshot(&self) -> salsa::Snapshot<RootDatabase> {
         salsa::Snapshot::new(RootDatabase {
-            storage: self.storage.snapshot(),
+            runtime: self.runtime.snapshot(self),
             last_gc: self.last_gc,
             last_gc_check: self.last_gc_check,
         })
@@ -133,7 +134,7 @@ pub trait LineIndexDatabase: ra_db::SourceDatabase + CheckCanceled {
     fn line_index(&self, file_id: FileId) -> Arc<LineIndex>;
 }
 
-fn line_index(db: &dyn LineIndexDatabase, file_id: FileId) -> Arc<LineIndex> {
+fn line_index(db: &impl LineIndexDatabase, file_id: FileId) -> Arc<LineIndex> {
     let text = db.file_text(file_id);
     Arc::new(LineIndex::new(&*text))
 }
diff --git a/crates/ra_ide_db/src/source_change.rs b/crates/ra_ide_db/src/source_change.rs
index 0bbd3c3e59..abb83f4213 100644
--- a/crates/ra_ide_db/src/source_change.rs
+++ b/crates/ra_ide_db/src/source_change.rs
@@ -6,7 +6,7 @@
 use ra_db::FileId;
 use ra_text_edit::TextEdit;
 
-#[derive(Debug, Clone)]
+#[derive(Default, Debug, Clone)]
 pub struct SourceChange {
     pub source_file_edits: Vec<SourceFileEdit>,
     pub file_system_edits: Vec<FileSystemEdit>,
diff --git a/crates/ra_ide_db/src/symbol_index.rs b/crates/ra_ide_db/src/symbol_index.rs
index 131e2a128d..5a09e7d1de 100644
--- a/crates/ra_ide_db/src/symbol_index.rs
+++ b/crates/ra_ide_db/src/symbol_index.rs
@@ -87,7 +87,7 @@ impl Query {
 }
 
 #[salsa::query_group(SymbolsDatabaseStorage)]
-pub trait SymbolsDatabase: hir::db::HirDatabase + SourceDatabaseExt {
+pub trait SymbolsDatabase: hir::db::HirDatabase + SourceDatabaseExt + ParallelDatabase {
     fn file_symbols(&self, file_id: FileId) -> Arc<SymbolIndex>;
     fn library_symbols(&self) -> Arc<FxHashMap<SourceRootId, SymbolIndex>>;
     /// The set of "local" (that is, from the current workspace) roots.
@@ -100,7 +100,9 @@ pub trait SymbolsDatabase: hir::db::HirDatabase + SourceDatabaseExt {
     fn library_roots(&self) -> Arc<FxHashSet<SourceRootId>>;
 }
 
-fn library_symbols(db: &dyn SymbolsDatabase) -> Arc<FxHashMap<SourceRootId, SymbolIndex>> {
+fn library_symbols(
+    db: &(impl SymbolsDatabase + ParallelDatabase),
+) -> Arc<FxHashMap<SourceRootId, SymbolIndex>> {
     let _p = profile("library_symbols");
 
     let roots = db.library_roots();
@@ -121,7 +123,7 @@ fn library_symbols(db: &dyn SymbolsDatabase) -> Arc<FxHashMap<SourceRootId, Symb
     Arc::new(res)
 }
 
-fn file_symbols(db: &dyn SymbolsDatabase, file_id: FileId) -> Arc<SymbolIndex> {
+fn file_symbols(db: &impl SymbolsDatabase, file_id: FileId) -> Arc<SymbolIndex> {
     db.check_canceled();
     let parse = db.parse(file_id);
 
diff --git a/crates/ra_syntax/src/ast/edit.rs b/crates/ra_syntax/src/ast/edit.rs
index 940c30c7fb..2ef173a039 100644
--- a/crates/ra_syntax/src/ast/edit.rs
+++ b/crates/ra_syntax/src/ast/edit.rs
@@ -299,8 +299,12 @@ impl ast::UseTree {
             Some(it) => it,
             None => return self.clone(),
         };
-        let use_tree =
-            make::use_tree(suffix, self.use_tree_list(), self.alias(), self.star_token().is_some());
+        let use_tree = make::use_tree(
+            suffix.clone(),
+            self.use_tree_list(),
+            self.alias(),
+            self.star_token().is_some(),
+        );
         let nested = make::use_tree_list(iter::once(use_tree));
         return make::use_tree(prefix.clone(), Some(nested), None, false);
 
diff --git a/docs/dev/README.md b/docs/dev/README.md
index 3af01cd6b7..f874624004 100644
--- a/docs/dev/README.md
+++ b/docs/dev/README.md
@@ -314,7 +314,7 @@ We don't have specific rules around git history hygiene.
 Maintaining clean git history is encouraged, but not enforced.
 We use rebase workflow, it's OK to rewrite history during PR review process.
 
-Avoid @mentioning people in commit messages and pull request descriptions (they are added to commit message by bors), as such messages create a lot of duplicate notification traffic during rebases.
+Avoid @mentioning people in commit messages, as such messages create a lot of duplicate notification traffic during rebases.
 
 # Architecture Invariants
 
diff --git a/editors/code/src/main.ts b/editors/code/src/main.ts
index 4b990afa19..5877be8b27 100644
--- a/editors/code/src/main.ts
+++ b/editors/code/src/main.ts
@@ -54,7 +54,7 @@ async function tryActivate(context: vscode.ExtensionContext) {
     const serverPath = await bootstrap(config, state).catch(err => {
         let message = "bootstrap error. ";
 
-        if (err.code === "EBUSY" || err.code === "ETXTBSY" || err.code === "EPERM") {
+        if (err.code === "EBUSY" || err.code === "ETXTBSY") {
             message += "Other vscode windows might be using rust-analyzer, ";
             message += "you should close them and reload this window to retry. ";
         }
diff --git a/editors/code/tsconfig.json b/editors/code/tsconfig.json
index c9f348241a..32d1a865f0 100644
--- a/editors/code/tsconfig.json
+++ b/editors/code/tsconfig.json
@@ -6,6 +6,8 @@
         "lib": [
             "es2019"
         ],
+        "esModuleInterop": true,
+        "allowSyntheticDefaultImports": true,
         "sourceMap": true,
         "rootDir": ".",
         "strict": true,


Test patch:
diff --git a/crates/ra_hir_def/src/test_db.rs b/crates/ra_hir_def/src/test_db.rs
index 339f819b8b..4581d87453 100644
--- a/crates/ra_hir_def/src/test_db.rs
+++ b/crates/ra_hir_def/src/test_db.rs
@@ -1,7 +1,7 @@
 //! Database used for testing `hir_def`.
 
 use std::{
-    fmt, panic,
+    panic,
     sync::{Arc, Mutex},
 };
 
@@ -18,10 +18,10 @@ use crate::db::DefDatabase;
     crate::db::InternDatabaseStorage,
     crate::db::DefDatabaseStorage
 )]
-#[derive(Default)]
+#[derive(Debug, Default)]
 pub struct TestDB {
-    storage: salsa::Storage<TestDB>,
-    events: Mutex<Option<Vec<salsa::Event>>>,
+    runtime: salsa::Runtime<TestDB>,
+    events: Mutex<Option<Vec<salsa::Event<TestDB>>>>,
 }
 
 impl Upcast<dyn AstDatabase> for TestDB {
@@ -37,20 +37,20 @@ impl Upcast<dyn DefDatabase> for TestDB {
 }
 
 impl salsa::Database for TestDB {
-    fn salsa_event(&self, event: salsa::Event) {
+    fn salsa_runtime(&self) -> &salsa::Runtime<Self> {
+        &self.runtime
+    }
+    fn salsa_runtime_mut(&mut self) -> &mut salsa::Runtime<Self> {
+        &mut self.runtime
+    }
+    fn salsa_event(&self, event: impl Fn() -> salsa::Event<TestDB>) {
         let mut events = self.events.lock().unwrap();
         if let Some(events) = &mut *events {
-            events.push(event);
+            events.push(event());
         }
     }
 }
 
-impl fmt::Debug for TestDB {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        f.debug_struct("TestDB").finish()
-    }
-}
-
 impl panic::RefUnwindSafe for TestDB {}
 
 impl FileLoader for TestDB {
@@ -78,7 +78,7 @@ impl TestDB {
         panic!("Can't find module for file")
     }
 
-    pub fn log(&self, f: impl FnOnce()) -> Vec<salsa::Event> {
+    pub fn log(&self, f: impl FnOnce()) -> Vec<salsa::Event<TestDB>> {
         *self.events.lock().unwrap() = Some(Vec::new());
         f();
         self.events.lock().unwrap().take().unwrap()
@@ -92,7 +92,7 @@ impl TestDB {
                 // This pretty horrible, but `Debug` is the only way to inspect
                 // QueryDescriptor at the moment.
                 salsa::EventKind::WillExecute { database_key } => {
-                    Some(format!("{:?}", database_key.debug(self)))
+                    Some(format!("{:?}", database_key))
                 }
                 _ => None,
             })
diff --git a/crates/ra_hir_expand/src/test_db.rs b/crates/ra_hir_expand/src/test_db.rs
index 332fa556fa..09fc18c360 100644
--- a/crates/ra_hir_expand/src/test_db.rs
+++ b/crates/ra_hir_expand/src/test_db.rs
@@ -1,7 +1,7 @@
 //! Database used for testing `hir_expand`.
 
 use std::{
-    fmt, panic,
+    panic,
     sync::{Arc, Mutex},
 };
 
@@ -13,23 +13,25 @@ use rustc_hash::FxHashSet;
     ra_db::SourceDatabaseStorage,
     crate::db::AstDatabaseStorage
 )]
-#[derive(Default)]
+#[derive(Debug, Default)]
 pub struct TestDB {
-    storage: salsa::Storage<TestDB>,
-    events: Mutex<Option<Vec<salsa::Event>>>,
+    runtime: salsa::Runtime<TestDB>,
+    events: Mutex<Option<Vec<salsa::Event<TestDB>>>>,
 }
 
-impl fmt::Debug for TestDB {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        f.debug_struct("TestDB").finish()
+impl salsa::Database for TestDB {
+    fn salsa_runtime(&self) -> &salsa::Runtime<Self> {
+        &self.runtime
     }
-}
 
-impl salsa::Database for TestDB {
-    fn salsa_event(&self, event: salsa::Event) {
+    fn salsa_runtime_mut(&mut self) -> &mut salsa::Runtime<Self> {
+        &mut self.runtime
+    }
+
+    fn salsa_event(&self, event: impl Fn() -> salsa::Event<TestDB>) {
         let mut events = self.events.lock().unwrap();
         if let Some(events) = &mut *events {
-            events.push(event);
+            events.push(event());
         }
     }
 }
diff --git a/crates/ra_hir_ty/src/test_db.rs b/crates/ra_hir_ty/src/test_db.rs
index dc447955f7..fddf0604d1 100644
--- a/crates/ra_hir_ty/src/test_db.rs
+++ b/crates/ra_hir_ty/src/test_db.rs
@@ -1,7 +1,7 @@
 //! Database used for testing `hir`.
 
 use std::{
-    fmt, panic,
+    panic,
     sync::{Arc, Mutex},
 };
 
@@ -26,15 +26,10 @@ use crate::{
     hir_def::db::DefDatabaseStorage,
     crate::db::HirDatabaseStorage
 )]
-#[derive(Default)]
+#[derive(Debug, Default)]
 pub struct TestDB {
-    storage: salsa::Storage<TestDB>,
-    events: Mutex<Option<Vec<salsa::Event>>>,
-}
-impl fmt::Debug for TestDB {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        f.debug_struct("TestDB").finish()
-    }
+    events: Mutex<Option<Vec<salsa::Event<TestDB>>>>,
+    runtime: salsa::Runtime<TestDB>,
 }
 
 impl Upcast<dyn AstDatabase> for TestDB {
@@ -50,10 +45,18 @@ impl Upcast<dyn DefDatabase> for TestDB {
 }
 
 impl salsa::Database for TestDB {
-    fn salsa_event(&self, event: salsa::Event) {
+    fn salsa_runtime(&self) -> &salsa::Runtime<TestDB> {
+        &self.runtime
+    }
+
+    fn salsa_runtime_mut(&mut self) -> &mut salsa::Runtime<Self> {
+        &mut self.runtime
+    }
+
+    fn salsa_event(&self, event: impl Fn() -> salsa::Event<TestDB>) {
         let mut events = self.events.lock().unwrap();
         if let Some(events) = &mut *events {
-            events.push(event);
+            events.push(event());
         }
     }
 }
@@ -61,8 +64,8 @@ impl salsa::Database for TestDB {
 impl salsa::ParallelDatabase for TestDB {
     fn snapshot(&self) -> salsa::Snapshot<TestDB> {
         salsa::Snapshot::new(TestDB {
-            storage: self.storage.snapshot(),
             events: Default::default(),
+            runtime: self.runtime.snapshot(self),
         })
     }
 }
@@ -179,7 +182,7 @@ impl TestDB {
 }
 
 impl TestDB {
-    pub fn log(&self, f: impl FnOnce()) -> Vec<salsa::Event> {
+    pub fn log(&self, f: impl FnOnce()) -> Vec<salsa::Event<TestDB>> {
         *self.events.lock().unwrap() = Some(Vec::new());
         f();
         self.events.lock().unwrap().take().unwrap()
@@ -193,7 +196,7 @@ impl TestDB {
                 // This pretty horrible, but `Debug` is the only way to inspect
                 // QueryDescriptor at the moment.
                 salsa::EventKind::WillExecute { database_key } => {
-                    Some(format!("{:?}", database_key.debug(self)))
+                    Some(format!("{:?}", database_key))
                 }
                 _ => None,
             })
diff --git a/crates/ra_hir_ty/src/tests.rs b/crates/ra_hir_ty/src/tests.rs
index 69f2d7667e..eeac34d140 100644
--- a/crates/ra_hir_ty/src/tests.rs
+++ b/crates/ra_hir_ty/src/tests.rs
@@ -21,7 +21,7 @@ use hir_def::{
 };
 use hir_expand::{db::AstDatabase, InFile};
 use insta::assert_snapshot;
-use ra_db::{fixture::WithFixture, FileRange, SourceDatabase, SourceDatabaseExt};
+use ra_db::{fixture::WithFixture, salsa::Database, FileRange, SourceDatabase};
 use ra_syntax::{
     algo,
     ast::{self, AstNode},
@@ -317,7 +317,7 @@ fn typing_whitespace_inside_a_function_should_not_invalidate_types() {
     "
     .to_string();
 
-    db.set_file_text(pos.file_id, Arc::new(new_text));
+    db.query_mut(ra_db::FileTextQuery).set(pos.file_id, Arc::new(new_text));
 
     {
         let events = db.log_executed(|| {
diff --git a/crates/test_utils/src/fixture.rs b/crates/test_utils/src/fixture.rs
index ed764046b6..fad8f7e2cc 100644
--- a/crates/test_utils/src/fixture.rs
+++ b/crates/test_utils/src/fixture.rs
@@ -62,7 +62,7 @@ impl Fixture {
         let components = meta.split_ascii_whitespace().collect::<Vec<_>>();
 
         let path = components[0].to_string();
-        assert!(path.starts_with('/'));
+        assert!(path.starts_with("/"));
 
         let mut krate = None;
         let mut deps = Vec::new();
diff --git a/editors/code/tests/unit/index.ts b/editors/code/tests/unit/index.ts
index b7d8d21448..5165720b45 100644
--- a/editors/code/tests/unit/index.ts
+++ b/editors/code/tests/unit/index.ts
@@ -1,6 +1,6 @@
 import * as path from 'path';
-import * as Mocha from 'mocha';
-import * as glob from 'glob';
+import Mocha from 'mocha';
+import glob from 'glob';
 
 export function run(): Promise<void> {
     // Create the mocha test