Repository: rust-analyzer/rust-analyzer
Pull request #2008 (2019-10-14 13:26:26)

Prepare SourceDatabase API for lazy file loading


Patch:
diff --git a/Cargo.lock b/Cargo.lock
index 0826b056a2..965d5aaa03 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -891,14 +891,17 @@ version = "0.1.0"
 name = "ra_assists"
 version = "0.1.0"
 dependencies = [
+ "arrayvec 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)",
  "format-buf 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "join_to_string 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "once_cell 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "ra_db 0.1.0",
  "ra_fmt 0.1.0",
  "ra_hir 0.1.0",
  "ra_syntax 0.1.0",
  "ra_text_edit 0.1.0",
+ "rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "rustc_lexer 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "test_utils 0.1.0",
 ]
@@ -1028,6 +1031,8 @@ dependencies = [
  "lsp-server 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "lsp-types 0.61.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "parking_lot 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "ra_cfg 0.1.0",
+ "ra_db 0.1.0",
  "ra_ide_api 0.1.0",
  "ra_prof 0.1.0",
  "ra_project_model 0.1.0",
@@ -1048,6 +1053,7 @@ dependencies = [
 name = "ra_mbe"
 version = "0.1.0"
 dependencies = [
+ "itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
  "ra_parser 0.1.0",
  "ra_syntax 0.1.0",
diff --git a/crates/ra_assists/Cargo.toml b/crates/ra_assists/Cargo.toml
index beebccbd9c..d3b6aeb36a 100644
--- a/crates/ra_assists/Cargo.toml
+++ b/crates/ra_assists/Cargo.toml
@@ -6,8 +6,11 @@ authors = ["rust-analyzer developers"]
 
 [dependencies]
 format-buf = "1.0.0"
+once_cell = "1.0.1"
 join_to_string = "0.1.3"
 itertools = "0.8.0"
+arrayvec = "0.4.10"
+rustc-hash = "1.0.1"
 rustc_lexer = "0.1.0"
 
 ra_syntax = { path = "../ra_syntax" }
diff --git a/crates/ra_assists/src/assists/move_bounds.rs b/crates/ra_assists/src/assists/move_bounds.rs
index d2444b6b9c..f791d22b0b 100644
--- a/crates/ra_assists/src/assists/move_bounds.rs
+++ b/crates/ra_assists/src/assists/move_bounds.rs
@@ -18,7 +18,7 @@ pub(crate) fn move_bounds_to_where_clause(mut ctx: AssistCtx<impl HirDatabase>)
     }
 
     let parent = type_param_list.syntax().parent()?;
-    if parent.children_with_tokens().any(|it| it.kind() == WHERE_CLAUSE) {
+    if parent.children_with_tokens().find(|it| it.kind() == WHERE_CLAUSE).is_some() {
         return None;
     }
 
diff --git a/crates/ra_cli/src/analysis_bench.rs b/crates/ra_cli/src/analysis_bench.rs
index 727f1e62b8..8bbe5d9e83 100644
--- a/crates/ra_cli/src/analysis_bench.rs
+++ b/crates/ra_cli/src/analysis_bench.rs
@@ -8,7 +8,7 @@ use std::{
 
 use ra_db::{
     salsa::{Database, Durability},
-    FileId, SourceDatabase,
+    FileId, SourceDatabaseExt,
 };
 use ra_ide_api::{Analysis, AnalysisChange, AnalysisHost, FilePosition, LineCol};
 
diff --git a/crates/ra_cli/src/analysis_stats.rs b/crates/ra_cli/src/analysis_stats.rs
index fe4f57dcde..35c867dce9 100644
--- a/crates/ra_cli/src/analysis_stats.rs
+++ b/crates/ra_cli/src/analysis_stats.rs
@@ -2,7 +2,7 @@
 
 use std::{collections::HashSet, fmt::Write, path::Path, time::Instant};
 
-use ra_db::SourceDatabase;
+use ra_db::SourceDatabaseExt;
 use ra_hir::{AssocItem, Crate, HasBodySource, HasSource, HirDisplay, ModuleDef, Ty, TypeWalk};
 use ra_syntax::AstNode;
 
diff --git a/crates/ra_db/src/input.rs b/crates/ra_db/src/input.rs
index cae51b02c3..eafa95921c 100644
--- a/crates/ra_db/src/input.rs
+++ b/crates/ra_db/src/input.rs
@@ -57,7 +57,7 @@ impl SourceRoot {
     pub fn walk(&self) -> impl Iterator<Item = FileId> + '_ {
         self.files.values().copied()
     }
-    pub(crate) fn file_by_relative_path(&self, path: &RelativePath) -> Option<FileId> {
+    pub fn file_by_relative_path(&self, path: &RelativePath) -> Option<FileId> {
         self.files.get(path).copied()
     }
 }
diff --git a/crates/ra_db/src/lib.rs b/crates/ra_db/src/lib.rs
index 4d3a9c0362..fc5d6d3965 100644
--- a/crates/ra_db/src/lib.rs
+++ b/crates/ra_db/src/lib.rs
@@ -64,21 +64,39 @@ pub struct FileRange {
 
 pub const DEFAULT_LRU_CAP: usize = 128;
 
-/// Database which stores all significant input facts: source code and project
-/// model. Everything else in rust-analyzer is derived from these queries.
-#[salsa::query_group(SourceDatabaseStorage)]
-pub trait SourceDatabase: CheckCanceled + std::fmt::Debug {
+pub trait FileLoader {
     /// Text of the file.
-    #[salsa::input]
     fn file_text(&self, file_id: FileId) -> Arc<String>;
-
-    #[salsa::transparent]
     fn resolve_relative_path(&self, anchor: FileId, relative_path: &RelativePath)
         -> Option<FileId>;
+    fn relevant_crates(&self, file_id: FileId) -> Arc<Vec<CrateId>>;
+}
 
+/// Database which stores all significant input facts: source code and project
+/// model. Everything else in rust-analyzer is derived from these queries.
+#[salsa::query_group(SourceDatabaseStorage)]
+pub trait SourceDatabase: CheckCanceled + FileLoader + std::fmt::Debug {
     // Parses the file into the syntax tree.
     #[salsa::invoke(parse_query)]
     fn parse(&self, file_id: FileId) -> Parse<ast::SourceFile>;
+
+    /// The crate graph.
+    #[salsa::input]
+    fn crate_graph(&self) -> Arc<CrateGraph>;
+}
+
+fn parse_query(db: &impl SourceDatabase, file_id: FileId) -> Parse<ast::SourceFile> {
+    let _p = profile("parse_query");
+    let text = db.file_text(file_id);
+    SourceFile::parse(&*text)
+}
+
+/// We don't want to give HIR knowledge of source roots, hence we extract these
+/// methods into a separate DB.
+#[salsa::query_group(SourceDatabaseExtStorage)]
+pub trait SourceDatabaseExt: SourceDatabase {
+    #[salsa::input]
+    fn file_text(&self, file_id: FileId) -> Arc<String>;
     /// Path to a file, relative to the root of its source root.
     #[salsa::input]
     fn file_relative_path(&self, file_id: FileId) -> RelativePathBuf;
@@ -88,40 +106,48 @@ pub trait SourceDatabase: CheckCanceled + std::fmt::Debug {
     /// Contents of the source root.
     #[salsa::input]
     fn source_root(&self, id: SourceRootId) -> Arc<SourceRoot>;
-    fn source_root_crates(&self, id: SourceRootId) -> Arc<Vec<CrateId>>;
-    /// The crate graph.
-    #[salsa::input]
-    fn crate_graph(&self) -> Arc<CrateGraph>;
-}
 
-fn resolve_relative_path(
-    db: &impl SourceDatabase,
-    anchor: FileId,
-    relative_path: &RelativePath,
-) -> Option<FileId> {
-    let path = {
-        let mut path = db.file_relative_path(anchor);
-        // Workaround for relative path API: turn `lib.rs` into ``.
-        if !path.pop() {
-            path = RelativePathBuf::default();
-        }
-        path.push(relative_path);
-        path.normalize()
-    };
-    let source_root = db.file_source_root(anchor);
-    let source_root = db.source_root(source_root);
-    source_root.file_by_relative_path(&path)
+    fn source_root_crates(&self, id: SourceRootId) -> Arc<Vec<CrateId>>;
 }
 
-fn source_root_crates(db: &impl SourceDatabase, id: SourceRootId) -> Arc<Vec<CrateId>> {
+fn source_root_crates(
+    db: &(impl SourceDatabaseExt + SourceDatabase),
+    id: SourceRootId,
+) -> Arc<Vec<CrateId>> {
     let root = db.source_root(id);
     let graph = db.crate_graph();
     let res = root.walk().filter_map(|it| graph.crate_id_for_crate_root(it)).collect::<Vec<_>>();
     Arc::new(res)
 }
 
-fn parse_query(db: &impl SourceDatabase, file_id: FileId) -> Parse<ast::SourceFile> {
-    let _p = profile("parse_query");
-    let text = db.file_text(file_id);
-    SourceFile::parse(&*text)
+/// Silly workaround for cyclic deps between the traits
+pub struct FileLoaderDelegate<T>(pub T);
+
+impl<T: SourceDatabaseExt> FileLoader for FileLoaderDelegate<&'_ T> {
+    fn file_text(&self, file_id: FileId) -> Arc<String> {
+        SourceDatabaseExt::file_text(self.0, file_id)
+    }
+    fn resolve_relative_path(
+        &self,
+        anchor: FileId,
+        relative_path: &RelativePath,
+    ) -> Option<FileId> {
+        let path = {
+            let mut path = self.0.file_relative_path(anchor);
+            // Workaround for relative path API: turn `lib.rs` into ``.
+            if !path.pop() {
+                path = RelativePathBuf::default();
+            }
+            path.push(relative_path);
+            path.normalize()
+        };
+        let source_root = self.0.file_source_root(anchor);
+        let source_root = self.0.source_root(source_root);
+        source_root.file_by_relative_path(&path)
+    }
+
+    fn relevant_crates(&self, file_id: FileId) -> Arc<Vec<CrateId>> {
+        let source_root = self.0.file_source_root(file_id);
+        self.0.source_root_crates(source_root)
+    }
 }
diff --git a/crates/ra_hir/src/from_source.rs b/crates/ra_hir/src/from_source.rs
index a012f33f7b..f80d8eb5f1 100644
--- a/crates/ra_hir/src/from_source.rs
+++ b/crates/ra_hir/src/from_source.rs
@@ -189,14 +189,14 @@ impl Module {
             ModuleSource::SourceFile(_) => None,
         };
 
-        let source_root_id = db.file_source_root(src.file_id.original_file(db));
-        db.source_root_crates(source_root_id).iter().map(|&crate_id| Crate { crate_id }).find_map(
-            |krate| {
+        db.relevant_crates(src.file_id.original_file(db))
+            .iter()
+            .map(|&crate_id| Crate { crate_id })
+            .find_map(|krate| {
                 let def_map = db.crate_def_map(krate);
                 let module_id = def_map.find_module_by_source(src.file_id, decl_id)?;
                 Some(Module { krate, module_id })
-            },
-        )
+            })
     }
 }
 
diff --git a/crates/ra_hir/src/ids.rs b/crates/ra_hir/src/ids.rs
index 85b0227446..499dcafea2 100644
--- a/crates/ra_hir/src/ids.rs
+++ b/crates/ra_hir/src/ids.rs
@@ -85,11 +85,7 @@ impl HirFileId {
                 // Note:
                 // The final goal we would like to make all parse_macro success,
                 // such that the following log will not call anyway.
-                log::warn!(
-                    "fail on macro_parse: (reason: {}) {}",
-                    err,
-                    macro_call_id.debug_dump(db)
-                );
+                log::warn!("fail on macro_parse: (reason: {})", err,);
             })
             .ok()?;
         match macro_file.macro_file_kind {
@@ -367,35 +363,6 @@ impl AstItemDef<ast::TypeAliasDef> for TypeAliasId {
     }
 }
 
-impl MacroCallId {
-    pub fn debug_dump(self, db: &impl AstDatabase) -> String {
-        let loc = self.loc(db);
-        let node = loc.ast_id.to_node(db);
-        let syntax_str = {
-            let mut res = String::new();
-            node.syntax().text().for_each_chunk(|chunk| {
-                if !res.is_empty() {
-                    res.push(' ')
-                }
-                res.push_str(chunk)
-            });
-            res
-        };
-
-        // dump the file name
-        let file_id: HirFileId = self.loc(db).ast_id.file_id();
-        let original = file_id.original_file(db);
-        let macro_rules = db.macro_def(loc.def);
-
-        format!(
-            "macro call [file: {:?}] : {}\nhas rules: {}",
-            db.file_relative_path(original),
-            syntax_str,
-            macro_rules.is_some()
-        )
-    }
-}
-
 /// This exists just for Chalk, because Chalk just has a single `StructId` where
 /// we have different kinds of ADTs, primitive types and special type
 /// constructors like tuples and function pointers.
diff --git a/crates/ra_hir/src/lib.rs b/crates/ra_hir/src/lib.rs
index ca261e8f54..9cbd9a8aef 100644
--- a/crates/ra_hir/src/lib.rs
+++ b/crates/ra_hir/src/lib.rs
@@ -51,7 +51,6 @@ mod lang_item;
 mod generics;
 mod resolve;
 pub mod diagnostics;
-mod util;
 
 mod code_model;
 
diff --git a/crates/ra_hir/src/mock.rs b/crates/ra_hir/src/mock.rs
index 8274249835..0b278deb3a 100644
--- a/crates/ra_hir/src/mock.rs
+++ b/crates/ra_hir/src/mock.rs
@@ -5,10 +5,10 @@ use std::{panic, sync::Arc};
 use parking_lot::Mutex;
 use ra_cfg::CfgOptions;
 use ra_db::{
-    salsa, CrateGraph, CrateId, Edition, FileId, FilePosition, SourceDatabase, SourceRoot,
-    SourceRootId,
+    salsa, CrateGraph, CrateId, Edition, FileId, FileLoader, FileLoaderDelegate, FilePosition,
+    SourceDatabase, SourceDatabaseExt, SourceRoot, SourceRootId,
 };
-use relative_path::RelativePathBuf;
+use relative_path::{RelativePath, RelativePathBuf};
 use rustc_hash::FxHashMap;
 use test_utils::{extract_offset, parse_fixture, CURSOR_MARKER};
 
@@ -17,6 +17,7 @@ use crate::{db, debug::HirDebugHelper, diagnostics::DiagnosticSink};
 pub const WORKSPACE: SourceRootId = SourceRootId(0);
 
 #[salsa::database(
+    ra_db::SourceDatabaseExtStorage,
     ra_db::SourceDatabaseStorage,
     db::InternDatabaseStorage,
     db::AstDatabaseStorage,
@@ -34,6 +35,22 @@ pub struct MockDatabase {
 
 impl panic::RefUnwindSafe for MockDatabase {}
 
+impl FileLoader for MockDatabase {
+    fn file_text(&self, file_id: FileId) -> Arc<String> {
+        FileLoaderDelegate(self).file_text(file_id)
+    }
+    fn resolve_relative_path(
+        &self,
+        anchor: FileId,
+        relative_path: &RelativePath,
+    ) -> Option<FileId> {
+        FileLoaderDelegate(self).resolve_relative_path(anchor, relative_path)
+    }
+    fn relevant_crates(&self, file_id: FileId) -> Arc<Vec<CrateId>> {
+        FileLoaderDelegate(self).relevant_crates(file_id)
+    }
+}
+
 impl HirDebugHelper for MockDatabase {
     fn crate_name(&self, krate: CrateId) -> Option<String> {
         self.crate_names.get(&krate).cloned()
diff --git a/crates/ra_hir/src/ty.rs b/crates/ra_hir/src/ty.rs
index cc9746f6d7..d161735e8f 100644
--- a/crates/ra_hir/src/ty.rs
+++ b/crates/ra_hir/src/ty.rs
@@ -17,8 +17,8 @@ use std::sync::Arc;
 use std::{fmt, iter, mem};
 
 use crate::{
-    db::HirDatabase, expr::ExprId, type_ref::Mutability, util::make_mut_slice, Adt, Crate,
-    DefWithBody, GenericParams, HasGenericParams, Name, Trait, TypeAlias,
+    db::HirDatabase, expr::ExprId, type_ref::Mutability, Adt, Crate, DefWithBody, GenericParams,
+    HasGenericParams, Name, Trait, TypeAlias,
 };
 use display::{HirDisplay, HirFormatter};
 
@@ -308,9 +308,12 @@ impl Substs {
     }
 
     pub fn walk_mut(&mut self, f: &mut impl FnMut(&mut Ty)) {
-        for t in make_mut_slice(&mut self.0) {
+        // Without an Arc::make_mut_slice, we can't avoid the clone here:
+        let mut v: Vec<_> = self.0.iter().cloned().collect();
+        for t in &mut v {
             t.walk_mut(f);
         }
+        self.0 = v.into();
     }
 
     pub fn as_single(&self) -> &Ty {
@@ -327,7 +330,8 @@ impl Substs {
                 .params_including_parent()
                 .into_iter()
                 .map(|p| Ty::Param { idx: p.idx, name: p.name.clone() })
-                .collect(),
+                .collect::<Vec<_>>()
+                .into(),
         )
     }
 
@@ -338,7 +342,8 @@ impl Substs {
                 .params_including_parent()
                 .into_iter()
                 .map(|p| Ty::Bound(p.idx))
-                .collect(),
+                .collect::<Vec<_>>()
+                .into(),
         )
     }
 
@@ -536,9 +541,12 @@ impl TypeWalk for FnSig {
     }
 
     fn walk_mut(&mut self, f: &mut impl FnMut(&mut Ty)) {
-        for t in make_mut_slice(&mut self.params_and_return) {
+        // Without an Arc::make_mut_slice, we can't avoid the clone here:
+        let mut v: Vec<_> = self.params_and_return.iter().cloned().collect();
+        for t in &mut v {
             t.walk_mut(f);
         }
+        self.params_and_return = v.into();
     }
 }
 
@@ -748,9 +756,11 @@ impl TypeWalk for Ty {
                 p_ty.parameters.walk_mut(f);
             }
             Ty::Dyn(predicates) | Ty::Opaque(predicates) => {
-                for p in make_mut_slice(predicates) {
+                let mut v: Vec<_> = predicates.iter().cloned().collect();
+                for p in &mut v {
                     p.walk_mut(f);
                 }
+                *predicates = v.into();
             }
             Ty::Param { .. } | Ty::Bound(_) | Ty::Infer(_) | Ty::Unknown => {}
         }
diff --git a/crates/ra_hir/src/ty/infer/unify.rs b/crates/ra_hir/src/ty/infer/unify.rs
index 014c7981fe..d161aa6b39 100644
--- a/crates/ra_hir/src/ty/infer/unify.rs
+++ b/crates/ra_hir/src/ty/infer/unify.rs
@@ -6,7 +6,6 @@ use crate::ty::{
     Canonical, InEnvironment, InferTy, ProjectionPredicate, ProjectionTy, Substs, TraitRef, Ty,
     TypeWalk,
 };
-use crate::util::make_mut_slice;
 
 impl<'a, D: HirDatabase> InferenceContext<'a, D> {
     pub(super) fn canonicalizer<'b>(&'b mut self) -> Canonicalizer<'a, 'b, D>
@@ -75,11 +74,10 @@ where
         })
     }
 
-    fn do_canonicalize_trait_ref(&mut self, mut trait_ref: TraitRef) -> TraitRef {
-        for ty in make_mut_slice(&mut trait_ref.substs.0) {
-            *ty = self.do_canonicalize_ty(ty.clone());
-        }
-        trait_ref
+    fn do_canonicalize_trait_ref(&mut self, trait_ref: TraitRef) -> TraitRef {
+        let substs =
+            trait_ref.substs.iter().map(|ty| self.do_canonicalize_ty(ty.clone())).collect();
+        TraitRef { trait_: trait_ref.trait_, substs: Substs(substs) }
     }
 
     fn into_canonicalized<T>(self, result: T) -> Canonicalized<T> {
@@ -89,11 +87,10 @@ where
         }
     }
 
-    fn do_canonicalize_projection_ty(&mut self, mut projection_ty: ProjectionTy) -> ProjectionTy {
-        for ty in make_mut_slice(&mut projection_ty.parameters.0) {
-            *ty = self.do_canonicalize_ty(ty.clone());
-        }
-        projection_ty
+    fn do_canonicalize_projection_ty(&mut self, projection_ty: ProjectionTy) -> ProjectionTy {
+        let params =
+            projection_ty.parameters.iter().map(|ty| self.do_canonicalize_ty(ty.clone())).collect();
+        ProjectionTy { associated_ty: projection_ty.associated_ty, parameters: Substs(params) }
     }
 
     fn do_canonicalize_projection_predicate(
diff --git a/crates/ra_hir/src/ty/lower.rs b/crates/ra_hir/src/ty/lower.rs
index 366556134b..a604c02e2d 100644
--- a/crates/ra_hir/src/ty/lower.rs
+++ b/crates/ra_hir/src/ty/lower.rs
@@ -22,7 +22,6 @@ use crate::{
     resolve::{Resolver, TypeNs},
     ty::Adt,
     type_ref::{TypeBound, TypeRef},
-    util::make_mut_slice,
     BuiltinType, Const, Enum, EnumVariant, Function, ModuleDef, Path, Static, Struct, StructField,
     Trait, TypeAlias, Union,
 };
@@ -32,11 +31,11 @@ impl Ty {
         match type_ref {
             TypeRef::Never => Ty::simple(TypeCtor::Never),
             TypeRef::Tuple(inner) => {
-                let inner_tys: Arc<[Ty]> =
-                    inner.iter().map(|tr| Ty::from_hir(db, resolver, tr)).collect();
+                let inner_tys =
+                    inner.iter().map(|tr| Ty::from_hir(db, resolver, tr)).collect::<Vec<_>>();
                 Ty::apply(
                     TypeCtor::Tuple { cardinality: inner_tys.len() as u16 },
-                    Substs(inner_tys),
+                    Substs(inner_tys.into()),
                 )
             }
             TypeRef::Path(path) => Ty::from_hir_path(db, resolver, path),
@@ -58,7 +57,9 @@ impl Ty {
             }
             TypeRef::Placeholder => Ty::Unknown,
             TypeRef::Fn(params) => {
-                let sig = Substs(params.iter().map(|tr| Ty::from_hir(db, resolver, tr)).collect());
+                let inner_tys =
+                    params.iter().map(|tr| Ty::from_hir(db, resolver, tr)).collect::<Vec<_>>();
+                let sig = Substs(inner_tys.into());
                 Ty::apply(TypeCtor::FnPtr { num_args: sig.len() as u16 - 1 }, sig)
             }
             TypeRef::DynTrait(bounds) => {
@@ -68,8 +69,8 @@ impl Ty {
                     .flat_map(|b| {
                         GenericPredicate::from_type_bound(db, resolver, b, self_ty.clone())
                     })
-                    .collect();
-                Ty::Dyn(predicates)
+                    .collect::<Vec<_>>();
+                Ty::Dyn(predicates.into())
             }
             TypeRef::ImplTrait(bounds) => {
                 let self_ty = Ty::Bound(0);
@@ -78,8 +79,8 @@ impl Ty {
                     .flat_map(|b| {
                         GenericPredicate::from_type_bound(db, resolver, b, self_ty.clone())
                     })
-                    .collect();
-                Ty::Opaque(predicates)
+                    .collect::<Vec<_>>();
+                Ty::Opaque(predicates.into())
             }
             TypeRef::Error => Ty::Unknown,
         }
@@ -391,7 +392,10 @@ impl TraitRef {
     ) -> Self {
         let mut substs = TraitRef::substs_from_path(db, resolver, segment, resolved);
         if let Some(self_ty) = explicit_self_ty {
-            make_mut_slice(&mut substs.0)[0] = self_ty;
+            // FIXME this could be nicer
+            let mut substs_vec = substs.0.to_vec();
+            substs_vec[0] = self_ty;
+            substs.0 = substs_vec.into();
         }
         TraitRef { trait_: resolved, substs }
     }
@@ -554,12 +558,13 @@ pub(crate) fn generic_predicates_for_param_query(
     param_idx: u32,
 ) -> Arc<[GenericPredicate]> {
     let resolver = def.resolver(db);
-    resolver
+    let predicates = resolver
         .where_predicates_in_scope()
         // we have to filter out all other predicates *first*, before attempting to lower them
         .filter(|pred| Ty::from_hir_only_param(db, &resolver, &pred.type_ref) == Some(param_idx))
         .flat_map(|pred| GenericPredicate::from_where_predicate(db, &resolver, pred))
-        .collect()
+        .collect::<Vec<_>>();
+    predicates.into()
 }
 
 pub(crate) fn trait_env(
@@ -580,10 +585,11 @@ pub(crate) fn generic_predicates_query(
     def: GenericDef,
 ) -> Arc<[GenericPredicate]> {
     let resolver = def.resolver(db);
-    resolver
+    let predicates = resolver
         .where_predicates_in_scope()
         .flat_map(|pred| GenericPredicate::from_where_predicate(db, &resolver, pred))
-        .collect()
+        .collect::<Vec<_>>();
+    predicates.into()
 }
 
 /// Resolve the default type params from generics
@@ -597,9 +603,9 @@ pub(crate) fn generic_defaults_query(db: &impl HirDatabase, def: GenericDef) ->
         .map(|p| {
             p.default.as_ref().map_or(Ty::Unknown, |path| Ty::from_hir_path(db, &resolver, path))
         })
-        .collect();
+        .collect::<Vec<_>>();
 
-    Substs(defaults)
+    Substs(defaults.into())
 }
 
 fn fn_sig_for_fn(db: &impl HirDatabase, def: Function) -> FnSig {
diff --git a/crates/ra_hir/src/ty/traits.rs b/crates/ra_hir/src/ty/traits.rs
index 0cb5c37984..b0f67ae501 100644
--- a/crates/ra_hir/src/ty/traits.rs
+++ b/crates/ra_hir/src/ty/traits.rs
@@ -89,7 +89,7 @@ pub(crate) fn impls_for_trait_query(
     }
     let crate_impl_blocks = db.impls_in_crate(krate);
     impls.extend(crate_impl_blocks.lookup_impl_blocks_for_trait(trait_));
-    impls.into_iter().collect()
+    impls.into_iter().collect::<Vec<_>>().into()
 }
 
 /// A set of clauses that we assume to be true. E.g. if we are inside this function:
diff --git a/crates/ra_hir/src/ty/traits/chalk.rs b/crates/ra_hir/src/ty/traits/chalk.rs
index 00aaf65d92..9168de7092 100644
--- a/crates/ra_hir/src/ty/traits/chalk.rs
+++ b/crates/ra_hir/src/ty/traits/chalk.rs
@@ -126,7 +126,8 @@ impl ToChalk for Substs {
                 chalk_ir::Parameter(chalk_ir::ParameterKind::Ty(ty)) => from_chalk(db, ty),
                 chalk_ir::Parameter(chalk_ir::ParameterKind::Lifetime(_)) => unimplemented!(),
             })
-            .collect();
+            .collect::<Vec<_>>()
+            .into();
         Substs(tys)
     }
 }
diff --git a/crates/ra_hir/src/util.rs b/crates/ra_hir/src/util.rs
deleted file mode 100644
index 0095ee45d3..0000000000
--- a/crates/ra_hir/src/util.rs
+++ /dev/null
@@ -1,12 +0,0 @@
-//! Internal utility functions.
-
-use std::sync::Arc;
-
-/// Helper for mutating `Arc<[T]>` (i.e. `Arc::make_mut` for Arc slices).
-/// The underlying values are cloned if there are other strong references.
-pub(crate) fn make_mut_slice<T: Clone>(a: &mut Arc<[T]>) -> &mut [T] {
-    if Arc::get_mut(a).is_none() {
-        *a = a.iter().cloned().collect();
-    }
-    Arc::get_mut(a).unwrap()
-}
diff --git a/crates/ra_ide_api/src/change.rs b/crates/ra_ide_api/src/change.rs
index 09913787b7..050249c0e6 100644
--- a/crates/ra_ide_api/src/change.rs
+++ b/crates/ra_ide_api/src/change.rs
@@ -4,7 +4,7 @@ use std::{fmt, sync::Arc, time};
 
 use ra_db::{
     salsa::{Database, Durability, SweepStrategy},
-    CrateGraph, CrateId, FileId, SourceDatabase, SourceRoot, SourceRootId,
+    CrateGraph, CrateId, FileId, SourceDatabase, SourceDatabaseExt, SourceRoot, SourceRootId,
 };
 use ra_prof::{memory_usage, profile, Bytes};
 use ra_syntax::SourceFile;
diff --git a/crates/ra_ide_api/src/db.rs b/crates/ra_ide_api/src/db.rs
index f9ee135733..b9321464b4 100644
--- a/crates/ra_ide_api/src/db.rs
+++ b/crates/ra_ide_api/src/db.rs
@@ -4,8 +4,10 @@ use std::sync::Arc;
 
 use ra_db::{
     salsa::{self, Database, Durability},
-    Canceled, CheckCanceled, CrateId, FileId, SourceDatabase, SourceRootId,
+    Canceled, CheckCanceled, CrateId, FileId, FileLoader, FileLoaderDelegate, SourceDatabase,
+    SourceDatabaseExt, SourceRootId,
 };
+use relative_path::RelativePath;
 use rustc_hash::FxHashMap;
 
 use crate::{
@@ -15,6 +17,7 @@ use crate::{
 
 #[salsa::database(
     ra_db::SourceDatabaseStorage,
+    ra_db::SourceDatabaseExtStorage,
     LineIndexDatabaseStorage,
     symbol_index::SymbolsDatabaseStorage,
     hir::db::InternDatabaseStorage,
@@ -31,6 +34,22 @@ pub(crate) struct RootDatabase {
     pub(crate) last_gc_check: crate::wasm_shims::Instant,
 }
 
+impl FileLoader for RootDatabase {
+    fn file_text(&self, file_id: FileId) -> Arc<String> {
+        FileLoaderDelegate(self).file_text(file_id)
+    }
+    fn resolve_relative_path(
+        &self,
+        anchor: FileId,
+        relative_path: &RelativePath,
+    ) -> Option<FileId> {
+        FileLoaderDelegate(self).resolve_relative_path(anchor, relative_path)
+    }
+    fn relevant_crates(&self, file_id: FileId) -> Arc<Vec<CrateId>> {
+        FileLoaderDelegate(self).relevant_crates(file_id)
+    }
+}
+
 impl hir::debug::HirDebugHelper for RootDatabase {
     fn crate_name(&self, krate: CrateId) -> Option<String> {
         self.debug_data.crate_names.get(&krate).cloned()
@@ -104,7 +123,7 @@ pub(crate) trait LineIndexDatabase: ra_db::SourceDatabase + CheckCanceled {
     fn line_index(&self, file_id: FileId) -> Arc<LineIndex>;
 }
 
-fn line_index(db: &impl LineIndexDatabase, file_id: FileId) -> Arc<LineIndex> {
+fn line_index(db: &impl ra_db::SourceDatabase, file_id: FileId) -> Arc<LineIndex> {
     let text = db.file_text(file_id);
     Arc::new(LineIndex::new(&*text))
 }
diff --git a/crates/ra_ide_api/src/diagnostics.rs b/crates/ra_ide_api/src/diagnostics.rs
index 65f061443a..8743a3a798 100644
--- a/crates/ra_ide_api/src/diagnostics.rs
+++ b/crates/ra_ide_api/src/diagnostics.rs
@@ -4,7 +4,7 @@ use std::cell::RefCell;
 
 use hir::diagnostics::{AstDiagnostic, Diagnostic as _, DiagnosticSink};
 use itertools::Itertools;
-use ra_db::SourceDatabase;
+use ra_db::{SourceDatabase, SourceDatabaseExt};
 use ra_prof::profile;
 use ra_syntax::{
     algo,
diff --git a/crates/ra_ide_api/src/lib.rs b/crates/ra_ide_api/src/lib.rs
index 2d92fe1c50..f7fd42f652 100644
--- a/crates/ra_ide_api/src/lib.rs
+++ b/crates/ra_ide_api/src/lib.rs
@@ -52,7 +52,7 @@ use std::sync::Arc;
 use ra_cfg::CfgOptions;
 use ra_db::{
     salsa::{self, ParallelDatabase},
-    CheckCanceled, SourceDatabase,
+    CheckCanceled, FileLoader, SourceDatabase,
 };
 use ra_syntax::{SourceFile, TextRange, TextUnit};
 use ra_text_edit::TextEdit;
@@ -289,10 +289,14 @@ impl AnalysisHost {
     pub fn per_query_memory_usage(&mut self) -> Vec<(String, ra_prof::Bytes)> {
         self.db.per_query_memory_usage()
     }
-    pub fn raw_database(&self) -> &(impl hir::db::HirDatabase + salsa::Database) {
+    pub fn raw_database(
+        &self,
+    ) -> &(impl hir::db::HirDatabase + salsa::Database + ra_db::SourceDatabaseExt) {
         &self.db
     }
-    pub fn raw_database_mut(&mut self) -> &mut (impl hir::db::HirDatabase + salsa::Database) {
+    pub fn raw_database_mut(
+        &mut self,
+    ) -> &mut (impl hir::db::HirDatabase + salsa::Database + ra_db::SourceDatabaseExt) {
         &mut self.db
     }
 }
diff --git a/crates/ra_ide_api/src/references.rs b/crates/ra_ide_api/src/references.rs
index c95c47bf1e..4247c6d908 100644
--- a/crates/ra_ide_api/src/references.rs
+++ b/crates/ra_ide_api/src/references.rs
@@ -1,7 +1,7 @@
 //! FIXME: write short doc here
 
 use hir::{Either, ModuleSource};
-use ra_db::SourceDatabase;
+use ra_db::{SourceDatabase, SourceDatabaseExt};
 use ra_syntax::{algo::find_node_at_offset, ast, AstNode, SourceFile, SyntaxNode};
 use relative_path::{RelativePath, RelativePathBuf};
 
diff --git a/crates/ra_ide_api/src/symbol_index.rs b/crates/ra_ide_api/src/symbol_index.rs
index 797e9926f0..5729eb5b3d 100644
--- a/crates/ra_ide_api/src/symbol_index.rs
+++ b/crates/ra_ide_api/src/symbol_index.rs
@@ -29,7 +29,7 @@ use std::{
 use fst::{self, Streamer};
 use ra_db::{
     salsa::{self, ParallelDatabase},
-    SourceDatabase, SourceRootId,
+    SourceDatabaseExt, SourceRootId,
 };
 use ra_syntax::{
     ast::{self, NameOwner},
diff --git a/crates/ra_lsp_server/Cargo.toml b/crates/ra_lsp_server/Cargo.toml
index 46a0f958c0..aedc55a95c 100644
--- a/crates/ra_lsp_server/Cargo.toml
+++ b/crates/ra_lsp_server/Cargo.toml
@@ -18,6 +18,8 @@ parking_lot = "0.9.0"
 jod-thread = "0.1.0"
 ra_vfs = "0.4.0"
 ra_syntax = { path = "../ra_syntax" }
+ra_db = { path = "../ra_db" }
+ra_cfg = { path = "../ra_cfg" }
 ra_text_edit = { path = "../ra_text_edit" }
 ra_ide_api = { path = "../ra_ide_api" }
 lsp-server = "0.2.0"
diff --git a/crates/ra_mbe/Cargo.toml b/crates/ra_mbe/Cargo.toml
index e8ef2457bb..b058dde91c 100644
--- a/crates/ra_mbe/Cargo.toml
+++ b/crates/ra_mbe/Cargo.toml
@@ -8,6 +8,7 @@ authors = ["rust-analyzer developers"]
 ra_syntax = { path = "../ra_syntax" }
 ra_parser = { path = "../ra_parser" }
 tt = { path = "../ra_tt", package = "ra_tt" }
+itertools = "0.8.0"
 rustc-hash = "1.0.0"
 smallvec = "0.6.9"
 log = "0.4.5"
diff --git a/crates/ra_syntax/Cargo.toml b/crates/ra_syntax/Cargo.toml
index 68c594202f..9bc85404a0 100644
--- a/crates/ra_syntax/Cargo.toml
+++ b/crates/ra_syntax/Cargo.toml
@@ -15,7 +15,6 @@ rustc-hash = "1.0.1"
 arrayvec = "0.4.10"
 once_cell = "1.2.0"
 
-# This crate transitively depends on `smol_str` via `rowan`.
 # ideally, `serde` should be enabled by `ra_lsp_server`, but we enable it here
 # to reduce number of compilations
 smol_str = { version = "0.1.12", features = ["serde"] }
diff --git a/crates/ra_tt/Cargo.toml b/crates/ra_tt/Cargo.toml
index 3fcc7f0855..3328d312fa 100644
--- a/crates/ra_tt/Cargo.toml
+++ b/crates/ra_tt/Cargo.toml
@@ -5,6 +5,4 @@ version = "0.1.0"
 authors = ["rust-analyzer developers"]
 
 [dependencies]
-# ideally, `serde` should be enabled by `ra_lsp_server`, but we enable it here
-# to reduce number of compilations
-smol_str = { version = "0.1.12", features = ["serde"] }
+smol_str = "0.1.9"


Test patch:
diff --git a/crates/ra_hir/src/nameres/tests/incremental.rs b/crates/ra_hir/src/nameres/tests/incremental.rs
index c41862a0bd..af9c397602 100644
--- a/crates/ra_hir/src/nameres/tests/incremental.rs
+++ b/crates/ra_hir/src/nameres/tests/incremental.rs
@@ -2,7 +2,7 @@ use super::*;
 
 use std::sync::Arc;
 
-use ra_db::SourceDatabase;
+use ra_db::{SourceDatabase, SourceDatabaseExt};
 
 fn check_def_map_is_not_recomputed(initial: &str, file_change: &str) {
     let (mut db, pos) = MockDatabase::with_position(initial);