Repository: rust-analyzer/rust-analyzer
Pull request #2012 (2019-10-14 15:41:37)

#1435 postfix completion for integer literals
Fix for #1435 Incorrect postfix completion for integer literals


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_batch/src/lib.rs b/crates/ra_batch/src/lib.rs
index df49eb13d1..602beb4394 100644
--- a/crates/ra_batch/src/lib.rs
+++ b/crates/ra_batch/src/lib.rs
@@ -141,8 +141,14 @@ mod tests {
     #[test]
     fn test_loading_rust_analyzer() {
         let path = Path::new(env!("CARGO_MANIFEST_DIR")).parent().unwrap().parent().unwrap();
-        let (host, _roots) = load_cargo(path).unwrap();
-        let n_crates = Crate::all(host.raw_database()).len();
+        let (host, roots) = load_cargo(path).unwrap();
+        let mut n_crates = 0;
+        for (root, _) in roots {
+            for _krate in Crate::source_root_crates(host.raw_database(), root) {
+                n_crates += 1;
+            }
+        }
+
         // RA has quite a few crates, but the exact count doesn't matter
         assert!(n_crates > 20);
     }
diff --git a/crates/ra_cli/src/analysis_bench.rs b/crates/ra_cli/src/analysis_bench.rs
index 8bbe5d9e83..727f1e62b8 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, SourceDatabaseExt,
+    FileId, SourceDatabase,
 };
 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 35c867dce9..a8a110bd93 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::SourceDatabaseExt;
+use ra_db::SourceDatabase;
 use ra_hir::{AssocItem, Crate, HasBodySource, HasSource, HirDisplay, ModuleDef, Ty, TypeWalk};
 use ra_syntax::AstNode;
 
@@ -22,29 +22,16 @@ pub fn run(
     let mut num_crates = 0;
     let mut visited_modules = HashSet::new();
     let mut visit_queue = Vec::new();
-
-    let members = roots
-        .into_iter()
-        .filter_map(
-            |(source_root_id, project_root)| {
-                if project_root.is_member() {
-                    Some(source_root_id)
-                } else {
-                    None
-                }
-            },
-        )
-        .collect::<HashSet<_>>();
-
-    for krate in Crate::all(db) {
-        let module = krate.root_module(db).expect("crate without root module");
-        let file_id = module.definition_source(db).file_id;
-        if members.contains(&db.file_source_root(file_id.original_file(db))) {
-            num_crates += 1;
-            visit_queue.push(module);
+    for (source_root_id, project_root) in roots {
+        if project_root.is_member() {
+            for krate in Crate::source_root_crates(db, source_root_id) {
+                num_crates += 1;
+                let module =
+                    krate.root_module(db).expect("crate in source root without root module");
+                visit_queue.push(module);
+            }
         }
     }
-
     println!("Crates in this dir: {}", num_crates);
     let mut num_decls = 0;
     let mut funcs = Vec::new();
diff --git a/crates/ra_db/src/input.rs b/crates/ra_db/src/input.rs
index eafa95921c..cae51b02c3 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 fn file_by_relative_path(&self, path: &RelativePath) -> Option<FileId> {
+    pub(crate) 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 fc5d6d3965..4d3a9c0362 100644
--- a/crates/ra_db/src/lib.rs
+++ b/crates/ra_db/src/lib.rs
@@ -64,39 +64,21 @@ pub struct FileRange {
 
 pub const DEFAULT_LRU_CAP: usize = 128;
 
-pub trait FileLoader {
+/// 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 {
     /// 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;
@@ -106,48 +88,40 @@ pub trait SourceDatabaseExt: SourceDatabase {
     /// 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(
-    db: &(impl SourceDatabaseExt + SourceDatabase),
-    id: SourceRootId,
-) -> Arc<Vec<CrateId>> {
+fn source_root_crates(db: &impl 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)
 }
 
-/// 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)
-    }
+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)
 }
diff --git a/crates/ra_hir/src/code_model.rs b/crates/ra_hir/src/code_model.rs
index 8eb3c577d6..8055a07dbe 100644
--- a/crates/ra_hir/src/code_model.rs
+++ b/crates/ra_hir/src/code_model.rs
@@ -5,7 +5,7 @@ pub(crate) mod docs;
 
 use std::sync::Arc;
 
-use ra_db::{CrateId, Edition, FileId};
+use ra_db::{CrateId, Edition, FileId, SourceRootId};
 use ra_syntax::ast::{self, NameOwner, TypeAscriptionOwner};
 
 use crate::{
@@ -76,8 +76,10 @@ impl Crate {
         crate_graph.edition(self.crate_id)
     }
 
-    pub fn all(db: &impl DefDatabase) -> Vec<Crate> {
-        db.crate_graph().iter().map(|crate_id| Crate { crate_id }).collect()
+    // FIXME: should this be in source_binder?
+    pub fn source_root_crates(db: &impl DefDatabase, source_root: SourceRootId) -> Vec<Crate> {
+        let crate_ids = db.source_root_crates(source_root);
+        crate_ids.iter().map(|&crate_id| Crate { crate_id }).collect()
     }
 }
 
diff --git a/crates/ra_hir/src/from_source.rs b/crates/ra_hir/src/from_source.rs
index f80d8eb5f1..a012f33f7b 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,
         };
 
-        db.relevant_crates(src.file_id.original_file(db))
-            .iter()
-            .map(|&crate_id| Crate { crate_id })
-            .find_map(|krate| {
+        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| {
                 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 499dcafea2..85b0227446 100644
--- a/crates/ra_hir/src/ids.rs
+++ b/crates/ra_hir/src/ids.rs
@@ -85,7 +85,11 @@ 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,);
+                log::warn!(
+                    "fail on macro_parse: (reason: {}) {}",
+                    err,
+                    macro_call_id.debug_dump(db)
+                );
             })
             .ok()?;
         match macro_file.macro_file_kind {
@@ -363,6 +367,35 @@ 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 0b278deb3a..8274249835 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, FileLoader, FileLoaderDelegate, FilePosition,
-    SourceDatabase, SourceDatabaseExt, SourceRoot, SourceRootId,
+    salsa, CrateGraph, CrateId, Edition, FileId, FilePosition, SourceDatabase, SourceRoot,
+    SourceRootId,
 };
-use relative_path::{RelativePath, RelativePathBuf};
+use relative_path::RelativePathBuf;
 use rustc_hash::FxHashMap;
 use test_utils::{extract_offset, parse_fixture, CURSOR_MARKER};
 
@@ -17,7 +17,6 @@ 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,
@@ -35,22 +34,6 @@ 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 050249c0e6..09913787b7 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, SourceDatabaseExt, SourceRoot, SourceRootId,
+    CrateGraph, CrateId, FileId, SourceDatabase, SourceRoot, SourceRootId,
 };
 use ra_prof::{memory_usage, profile, Bytes};
 use ra_syntax::SourceFile;
diff --git a/crates/ra_ide_api/src/completion/complete_postfix.rs b/crates/ra_ide_api/src/completion/complete_postfix.rs
index 445a026768..555cecb73a 100644
--- a/crates/ra_ide_api/src/completion/complete_postfix.rs
+++ b/crates/ra_ide_api/src/completion/complete_postfix.rs
@@ -8,7 +8,7 @@ use crate::{
     CompletionItem,
 };
 use hir::{Ty, TypeCtor};
-use ra_syntax::{ast::AstNode, TextRange};
+use ra_syntax::{ast::AstNode, TextRange, TextUnit};
 use ra_text_edit::TextEditBuilder;
 
 fn postfix_snippet(ctx: &CompletionContext, label: &str, detail: &str, snippet: &str) -> Builder {
@@ -42,7 +42,13 @@ fn is_bool_or_unknown(ty: Option<Ty>) -> bool {
 
 pub(super) fn complete_postfix(acc: &mut Completions, ctx: &CompletionContext) {
     if let Some(dot_receiver) = &ctx.dot_receiver {
-        let receiver_text = dot_receiver.syntax().text().to_string();
+        let receiver_text = if ctx.dot_receiver_is_ambiguous_float_literal {
+            let text = dot_receiver.syntax().text();
+            let without_dot = ..text.len() - TextUnit::of_char('.');
+            text.slice(without_dot).to_string()
+        } else {
+            dot_receiver.syntax().text().to_string()
+        };
         let receiver_ty = ctx.analyzer.type_of(ctx.db, &dot_receiver);
         if is_bool_or_unknown(receiver_ty) {
             postfix_snippet(ctx, "if", "if expr {}", &format!("if {} {{$0}}", receiver_text))
@@ -206,6 +212,63 @@ mod tests {
         insert: "&mut bar",
         detail: "&mut expr",
     },
+]"###
+        );
+    }
+
+    #[test]
+    fn postfix_completion_works_for_ambiguous_float_literal() {
+        assert_debug_snapshot!(
+            do_postfix_completion(
+                r#"
+                fn main() {
+                    42.<|>
+                }
+                "#,
+            ),
+            @r###"[
+    CompletionItem {
+        label: "box",
+        source_range: [52; 52),
+        delete: [49; 52),
+        insert: "Box::new(42)",
+        detail: "Box::new(expr)",
+    },
+    CompletionItem {
+        label: "dbg",
+        source_range: [52; 52),
+        delete: [49; 52),
+        insert: "dbg!(42)",
+        detail: "dbg!(expr)",
+    },
+    CompletionItem {
+        label: "match",
+        source_range: [52; 52),
+        delete: [49; 52),
+        insert: "match 42 {\n    ${1:_} => {$0\\},\n}",
+        detail: "match expr {}",
+    },
+    CompletionItem {
+        label: "not",
+        source_range: [52; 52),
+        delete: [49; 52),
+        insert: "!42",
+        detail: "!expr",
+    },
+    CompletionItem {
+        label: "ref",
+        source_range: [52; 52),
+        delete: [49; 52),
+        insert: "&42",
+        detail: "&expr",
+    },
+    CompletionItem {
+        label: "refm",
+        source_range: [52; 52),
+        delete: [49; 52),
+        insert: "&mut 42",
+        detail: "&mut expr",
+    },
 ]"###
         );
     }
diff --git a/crates/ra_ide_api/src/completion/completion_context.rs b/crates/ra_ide_api/src/completion/completion_context.rs
index 73f3f3960c..64cbc0f982 100644
--- a/crates/ra_ide_api/src/completion/completion_context.rs
+++ b/crates/ra_ide_api/src/completion/completion_context.rs
@@ -38,6 +38,7 @@ pub(crate) struct CompletionContext<'a> {
     pub(super) is_new_item: bool,
     /// The receiver if this is a field or method access, i.e. writing something.<|>
     pub(super) dot_receiver: Option<ast::Expr>,
+    pub(super) dot_receiver_is_ambiguous_float_literal: bool,
     /// If this is a call (method or function) in particular, i.e. the () are already there.
     pub(super) is_call: bool,
     pub(super) is_path_type: bool,
@@ -80,6 +81,7 @@ impl<'a> CompletionContext<'a> {
             is_call: false,
             is_path_type: false,
             has_type_args: false,
+            dot_receiver_is_ambiguous_float_literal: false,
         };
         ctx.fill(&original_parse, position.offset);
         Some(ctx)
@@ -235,6 +237,16 @@ impl<'a> CompletionContext<'a> {
                 .expr()
                 .map(|e| e.syntax().text_range())
                 .and_then(|r| find_node_with_range(original_file.syntax(), r));
+            self.dot_receiver_is_ambiguous_float_literal = if let Some(ast::Expr::Literal(l)) =
+                &self.dot_receiver
+            {
+                match l.kind() {
+                    ast::LiteralKind::FloatNumber { suffix: _ } => l.token().text().ends_with('.'),
+                    _ => false,
+                }
+            } else {
+                false
+            }
         }
         if let Some(method_call_expr) = ast::MethodCallExpr::cast(parent) {
             // As above
diff --git a/crates/ra_ide_api/src/db.rs b/crates/ra_ide_api/src/db.rs
index bbf04bcf70..ea0714addb 100644
--- a/crates/ra_ide_api/src/db.rs
+++ b/crates/ra_ide_api/src/db.rs
@@ -4,10 +4,8 @@ use std::sync::Arc;
 
 use ra_db::{
     salsa::{self, Database, Durability},
-    Canceled, CheckCanceled, CrateId, FileId, FileLoader, FileLoaderDelegate, SourceDatabase,
-    SourceDatabaseExt, SourceRootId,
+    Canceled, CheckCanceled, CrateId, FileId, SourceDatabase, SourceRootId,
 };
-use relative_path::RelativePath;
 use rustc_hash::FxHashMap;
 
 use crate::{
@@ -17,7 +15,6 @@ use crate::{
 
 #[salsa::database(
     ra_db::SourceDatabaseStorage,
-    ra_db::SourceDatabaseExtStorage,
     LineIndexDatabaseStorage,
     symbol_index::SymbolsDatabaseStorage,
     hir::db::InternDatabaseStorage,
@@ -34,22 +31,6 @@ 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()
@@ -123,7 +104,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 8743a3a798..65f061443a 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, SourceDatabaseExt};
+use ra_db::SourceDatabase;
 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 f7fd42f652..2d92fe1c50 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, FileLoader, SourceDatabase,
+    CheckCanceled, SourceDatabase,
 };
 use ra_syntax::{SourceFile, TextRange, TextUnit};
 use ra_text_edit::TextEdit;
@@ -289,14 +289,10 @@ 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 + ra_db::SourceDatabaseExt) {
+    pub fn raw_database(&self) -> &(impl hir::db::HirDatabase + salsa::Database) {
         &self.db
     }
-    pub fn raw_database_mut(
-        &mut self,
-    ) -> &mut (impl hir::db::HirDatabase + salsa::Database + ra_db::SourceDatabaseExt) {
+    pub fn raw_database_mut(&mut self) -> &mut (impl hir::db::HirDatabase + salsa::Database) {
         &mut self.db
     }
 }
diff --git a/crates/ra_ide_api/src/references.rs b/crates/ra_ide_api/src/references.rs
index 4247c6d908..c95c47bf1e 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, SourceDatabaseExt};
+use ra_db::SourceDatabase;
 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 5729eb5b3d..797e9926f0 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},
-    SourceDatabaseExt, SourceRootId,
+    SourceDatabase, 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 af9c397602..c41862a0bd 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, SourceDatabaseExt};
+use ra_db::SourceDatabase;
 
 fn check_def_map_is_not_recomputed(initial: &str, file_change: &str) {
     let (mut db, pos) = MockDatabase::with_position(initial);