Repository: rust-analyzer/rust-analyzer
Pull request #5188 (2020-07-02 10:38:46)

Implement StatusBar

kjeremy: Could we use `window/showMessage` instead and capture it on the ts side for custom display?

Patch:
diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml
index 7f4e753410..ed9191c49c 100644
--- a/.github/workflows/ci.yaml
+++ b/.github/workflows/ci.yaml
@@ -116,9 +116,9 @@ jobs:
     - run: npm ci
       working-directory: ./editors/code
 
-#    - run: npm audit || { sleep 10 && npm audit; } || { sleep 30 && npm audit; }
-#      if: runner.os == 'Linux'
-#      working-directory: ./editors/code
+    - run: npm audit || { sleep 10 && npm audit; } || { sleep 30 && npm audit; }
+      if: runner.os == 'Linux'
+      working-directory: ./editors/code
 
     - run: npm run lint
       working-directory: ./editors/code
diff --git a/Cargo.lock b/Cargo.lock
index 61ae8157a7..e1d2475e22 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1248,7 +1248,6 @@ dependencies = [
  "ra_syntax",
  "ra_text_edit",
  "rustc-hash",
- "test_utils",
 ]
 
 [[package]]
diff --git a/Cargo.toml b/Cargo.toml
index 189f4ea2bd..5278b5a167 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -24,8 +24,6 @@ opt-level = 0
 opt-level = 0
 [profile.release.package.salsa-macros]
 opt-level = 0
-[profile.release.package.tracing-attributes]
-opt-level = 0
 [profile.release.package.xtask]
 opt-level = 0
 
diff --git a/crates/flycheck/src/lib.rs b/crates/flycheck/src/lib.rs
index 844b093d46..1023d3040f 100644
--- a/crates/flycheck/src/lib.rs
+++ b/crates/flycheck/src/lib.rs
@@ -132,7 +132,6 @@ impl FlycheckActor {
                     self.cancel_check_process();
 
                     let mut command = self.check_command();
-                    log::info!("restart flycheck {:?}", command);
                     command.stdout(Stdio::piped()).stderr(Stdio::null()).stdin(Stdio::null());
                     if let Ok(child) = command.spawn().map(JodChild) {
                         self.cargo_handle = Some(CargoHandle::spawn(child));
diff --git a/crates/ra_assists/src/handlers/extract_struct_from_enum_variant.rs b/crates/ra_assists/src/handlers/extract_struct_from_enum_variant.rs
index ca19cf1988..bdf9d7ae26 100644
--- a/crates/ra_assists/src/handlers/extract_struct_from_enum_variant.rs
+++ b/crates/ra_assists/src/handlers/extract_struct_from_enum_variant.rs
@@ -53,7 +53,7 @@ pub(crate) fn extract_struct_from_enum_variant(
         target,
         |builder| {
             let definition = Definition::ModuleDef(ModuleDef::EnumVariant(variant_hir));
-            let res = definition.find_usages(&ctx.sema, None);
+            let res = definition.find_usages(&ctx.db(), None);
             let start_offset = variant.parent_enum().syntax().text_range().start();
             let mut visited_modules_set = FxHashSet::default();
             visited_modules_set.insert(current_module);
diff --git a/crates/ra_assists/src/handlers/inline_local_variable.rs b/crates/ra_assists/src/handlers/inline_local_variable.rs
index 259839535c..f4fb0056bc 100644
--- a/crates/ra_assists/src/handlers/inline_local_variable.rs
+++ b/crates/ra_assists/src/handlers/inline_local_variable.rs
@@ -44,7 +44,7 @@ pub(crate) fn inline_local_variable(acc: &mut Assists, ctx: &AssistContext) -> O
 
     let def = ctx.sema.to_def(&bind_pat)?;
     let def = Definition::Local(def);
-    let refs = def.find_usages(&ctx.sema, None);
+    let refs = def.find_usages(ctx.db(), None);
     if refs.is_empty() {
         mark::hit!(test_not_applicable_if_variable_unused);
         return None;
diff --git a/crates/ra_db/src/input.rs b/crates/ra_db/src/input.rs
index aaa4927596..445a1ee48e 100644
--- a/crates/ra_db/src/input.rs
+++ b/crates/ra_db/src/input.rs
@@ -197,23 +197,6 @@ impl CrateGraph {
         self.arena.keys().copied()
     }
 
-    /// Returns an iterator over all transitive dependencies of the given crate.
-    pub fn transitive_deps(&self, of: CrateId) -> impl Iterator<Item = CrateId> + '_ {
-        let mut worklist = vec![of];
-        let mut deps = FxHashSet::default();
-
-        while let Some(krate) = worklist.pop() {
-            if !deps.insert(krate) {
-                continue;
-            }
-
-            worklist.extend(self[krate].dependencies.iter().map(|dep| dep.crate_id));
-        }
-
-        deps.remove(&of);
-        deps.into_iter()
-    }
-
     // FIXME: this only finds one crate with the given root; we could have multiple
     pub fn crate_id_for_crate_root(&self, file_id: FileId) -> Option<CrateId> {
         let (&crate_id, _) =
diff --git a/crates/ra_hir/src/code_model.rs b/crates/ra_hir/src/code_model.rs
index 1b3525011d..e09eb77c2c 100644
--- a/crates/ra_hir/src/code_model.rs
+++ b/crates/ra_hir/src/code_model.rs
@@ -1053,14 +1053,12 @@ pub struct ImplDef {
 
 impl ImplDef {
     pub fn all_in_crate(db: &dyn HirDatabase, krate: Crate) -> Vec<ImplDef> {
-        let inherent = db.inherent_impls_in_crate(krate.id);
-        let trait_ = db.trait_impls_in_crate(krate.id);
-
-        inherent.all_impls().chain(trait_.all_impls()).map(Self::from).collect()
+        let impls = db.impls_in_crate(krate.id);
+        impls.all_impls().map(Self::from).collect()
     }
     pub fn for_trait(db: &dyn HirDatabase, krate: Crate, trait_: Trait) -> Vec<ImplDef> {
-        let impls = db.trait_impls_in_crate(krate.id);
-        impls.for_trait(trait_.id).map(Self::from).collect()
+        let impls = db.impls_in_crate(krate.id);
+        impls.lookup_impl_defs_for_trait(trait_.id).map(Self::from).collect()
     }
 
     pub fn target_trait(self, db: &dyn HirDatabase) -> Option<TypeRef> {
@@ -1189,7 +1187,7 @@ impl Type {
             None => return false,
         };
 
-        let canonical_ty = Canonical { value: self.ty.value.clone(), kinds: Arc::new([]) };
+        let canonical_ty = Canonical { value: self.ty.value.clone(), num_vars: 0 };
         method_resolution::implements_trait(
             &canonical_ty,
             db,
@@ -1213,7 +1211,7 @@ impl Type {
                 self.ty.environment.clone(),
                 hir_ty::Obligation::Trait(trait_ref),
             ),
-            kinds: Arc::new([]),
+            num_vars: 0,
         };
 
         db.trait_solve(self.krate, goal).is_some()
@@ -1288,7 +1286,7 @@ impl Type {
     pub fn autoderef<'a>(&'a self, db: &'a dyn HirDatabase) -> impl Iterator<Item = Type> + 'a {
         // There should be no inference vars in types passed here
         // FIXME check that?
-        let canonical = Canonical { value: self.ty.value.clone(), kinds: Arc::new([]) };
+        let canonical = Canonical { value: self.ty.value.clone(), num_vars: 0 };
         let environment = self.ty.environment.clone();
         let ty = InEnvironment { value: canonical, environment };
         autoderef(db, Some(self.krate), ty)
@@ -1305,10 +1303,10 @@ impl Type {
         mut callback: impl FnMut(AssocItem) -> Option<T>,
     ) -> Option<T> {
         for krate in self.ty.value.def_crates(db, krate.id)? {
-            let impls = db.inherent_impls_in_crate(krate);
+            let impls = db.impls_in_crate(krate);
 
-            for impl_def in impls.for_self_ty(&self.ty.value) {
-                for &item in db.impl_data(*impl_def).items.iter() {
+            for impl_def in impls.lookup_impl_defs(&self.ty.value) {
+                for &item in db.impl_data(impl_def).items.iter() {
                     if let Some(result) = callback(item.into()) {
                         return Some(result);
                     }
@@ -1329,7 +1327,7 @@ impl Type {
         // There should be no inference vars in types passed here
         // FIXME check that?
         // FIXME replace Unknown by bound vars here
-        let canonical = Canonical { value: self.ty.value.clone(), kinds: Arc::new([]) };
+        let canonical = Canonical { value: self.ty.value.clone(), num_vars: 0 };
 
         let env = self.ty.environment.clone();
         let krate = krate.id;
@@ -1360,7 +1358,7 @@ impl Type {
         // There should be no inference vars in types passed here
         // FIXME check that?
         // FIXME replace Unknown by bound vars here
-        let canonical = Canonical { value: self.ty.value.clone(), kinds: Arc::new([]) };
+        let canonical = Canonical { value: self.ty.value.clone(), num_vars: 0 };
 
         let env = self.ty.environment.clone();
         let krate = krate.id;
diff --git a/crates/ra_hir/src/db.rs b/crates/ra_hir/src/db.rs
index cb48ca0656..bb67952de2 100644
--- a/crates/ra_hir/src/db.rs
+++ b/crates/ra_hir/src/db.rs
@@ -16,10 +16,10 @@ pub use hir_expand::db::{
 pub use hir_ty::db::{
     AssociatedTyDataQuery, AssociatedTyValueQuery, CallableItemSignatureQuery, FieldTypesQuery,
     GenericDefaultsQuery, GenericPredicatesForParamQuery, GenericPredicatesQuery, HirDatabase,
-    HirDatabaseStorage, ImplDatumQuery, ImplSelfTyQuery, ImplTraitQuery, InferQueryQuery,
-    InherentImplsInCrateQuery, InternAssocTyValueQuery, InternChalkImplQuery, InternTypeCtorQuery,
-    InternTypeParamIdQuery, ReturnTypeImplTraitsQuery, StructDatumQuery, TraitDatumQuery,
-    TraitImplsInCrateQuery, TraitImplsInDepsQuery, TraitSolveQuery, TyQuery, ValueTyQuery,
+    HirDatabaseStorage, ImplDatumQuery, ImplSelfTyQuery, ImplTraitQuery, ImplsFromDepsQuery,
+    ImplsInCrateQuery, InferQueryQuery, InternAssocTyValueQuery, InternChalkImplQuery,
+    InternTypeCtorQuery, InternTypeParamIdQuery, ReturnTypeImplTraitsQuery, StructDatumQuery,
+    TraitDatumQuery, TraitSolveQuery, TyQuery, ValueTyQuery,
 };
 
 #[test]
diff --git a/crates/ra_hir_def/src/item_tree/lower.rs b/crates/ra_hir_def/src/item_tree/lower.rs
index 06743d7fce..5149dd141f 100644
--- a/crates/ra_hir_def/src/item_tree/lower.rs
+++ b/crates/ra_hir_def/src/item_tree/lower.rs
@@ -211,7 +211,7 @@ impl Ctx {
     fn lower_record_field(&mut self, field: &ast::RecordFieldDef) -> Option<Field> {
         let name = field.name()?.as_name();
         let visibility = self.lower_visibility(field);
-        let type_ref = self.lower_type_ref_opt(field.ascribed_type());
+        let type_ref = self.lower_type_ref(&field.ascribed_type()?);
         let res = Field { name, type_ref, visibility };
         Some(res)
     }
diff --git a/crates/ra_hir_ty/src/autoderef.rs b/crates/ra_hir_ty/src/autoderef.rs
index c727012c69..1b0f84c5c7 100644
--- a/crates/ra_hir_ty/src/autoderef.rs
+++ b/crates/ra_hir_ty/src/autoderef.rs
@@ -37,7 +37,7 @@ pub(crate) fn deref(
     ty: InEnvironment<&Canonical<Ty>>,
 ) -> Option<Canonical<Ty>> {
     if let Some(derefed) = ty.value.value.builtin_deref() {
-        Some(Canonical { value: derefed, kinds: ty.value.kinds.clone() })
+        Some(Canonical { value: derefed, num_vars: ty.value.num_vars })
     } else {
         deref_by_trait(db, krate, ty)
     }
@@ -68,8 +68,8 @@ fn deref_by_trait(
 
     // Check that the type implements Deref at all
     let trait_ref = TraitRef { trait_: deref_trait, substs: parameters.clone() };
-    let implements_goal = Canonical {
-        kinds: ty.value.kinds.clone(),
+    let implements_goal = super::Canonical {
+        num_vars: ty.value.num_vars,
         value: InEnvironment {
             value: Obligation::Trait(trait_ref),
             environment: ty.environment.clone(),
@@ -81,7 +81,7 @@ fn deref_by_trait(
 
     // Now do the assoc type projection
     let projection = super::traits::ProjectionPredicate {
-        ty: Ty::Bound(BoundVar::new(DebruijnIndex::INNERMOST, ty.value.kinds.len())),
+        ty: Ty::Bound(BoundVar::new(DebruijnIndex::INNERMOST, ty.value.num_vars)),
         projection_ty: super::ProjectionTy { associated_ty: target, parameters },
     };
 
@@ -89,8 +89,7 @@ fn deref_by_trait(
 
     let in_env = InEnvironment { value: obligation, environment: ty.environment };
 
-    let canonical =
-        Canonical::new(in_env, ty.value.kinds.iter().copied().chain(Some(super::TyKind::General)));
+    let canonical = super::Canonical { num_vars: 1 + ty.value.num_vars, value: in_env };
 
     let solution = db.trait_solve(krate, canonical)?;
 
@@ -111,7 +110,7 @@ fn deref_by_trait(
             // assumptions will be broken. We would need to properly introduce
             // new variables in that case
 
-            for i in 1..vars.0.kinds.len() {
+            for i in 1..vars.0.num_vars {
                 if vars.0.value[i - 1] != Ty::Bound(BoundVar::new(DebruijnIndex::INNERMOST, i - 1))
                 {
                     warn!("complex solution for derefing {:?}: {:?}, ignoring", ty.value, solution);
@@ -120,7 +119,7 @@ fn deref_by_trait(
             }
             Some(Canonical {
                 value: vars.0.value[vars.0.value.len() - 1].clone(),
-                kinds: vars.0.kinds.clone(),
+                num_vars: vars.0.num_vars,
             })
         }
         Solution::Ambig(_) => {
diff --git a/crates/ra_hir_ty/src/db.rs b/crates/ra_hir_ty/src/db.rs
index dc06c0ee72..cad5532739 100644
--- a/crates/ra_hir_ty/src/db.rs
+++ b/crates/ra_hir_ty/src/db.rs
@@ -11,7 +11,7 @@ use ra_db::{impl_intern_key, salsa, CrateId, Upcast};
 use ra_prof::profile;
 
 use crate::{
-    method_resolution::{InherentImpls, TraitImpls},
+    method_resolution::CrateImplDefs,
     traits::{chalk, AssocTyValue, Impl},
     Binders, CallableDef, GenericPredicate, InferenceResult, OpaqueTyId, PolyFnSig,
     ReturnTypeImplTraits, TraitRef, Ty, TyDefId, TypeCtor, ValueTyDefId,
@@ -67,14 +67,11 @@ pub trait HirDatabase: DefDatabase + Upcast<dyn DefDatabase> {
     #[salsa::invoke(crate::lower::generic_defaults_query)]
     fn generic_defaults(&self, def: GenericDefId) -> Arc<[Binders<Ty>]>;
 
-    #[salsa::invoke(InherentImpls::inherent_impls_in_crate_query)]
-    fn inherent_impls_in_crate(&self, krate: CrateId) -> Arc<InherentImpls>;
+    #[salsa::invoke(crate::method_resolution::CrateImplDefs::impls_in_crate_query)]
+    fn impls_in_crate(&self, krate: CrateId) -> Arc<CrateImplDefs>;
 
-    #[salsa::invoke(TraitImpls::trait_impls_in_crate_query)]
-    fn trait_impls_in_crate(&self, krate: CrateId) -> Arc<TraitImpls>;
-
-    #[salsa::invoke(TraitImpls::trait_impls_in_deps_query)]
-    fn trait_impls_in_deps(&self, krate: CrateId) -> Arc<TraitImpls>;
+    #[salsa::invoke(crate::method_resolution::CrateImplDefs::impls_from_deps_query)]
+    fn impls_from_deps(&self, krate: CrateId) -> Arc<CrateImplDefs>;
 
     // Interned IDs for Chalk integration
     #[salsa::interned]
diff --git a/crates/ra_hir_ty/src/infer/unify.rs b/crates/ra_hir_ty/src/infer/unify.rs
index 2e895d9116..269495ca0b 100644
--- a/crates/ra_hir_ty/src/infer/unify.rs
+++ b/crates/ra_hir_ty/src/infer/unify.rs
@@ -9,7 +9,7 @@ use test_utils::mark;
 use super::{InferenceContext, Obligation};
 use crate::{
     BoundVar, Canonical, DebruijnIndex, GenericPredicate, InEnvironment, InferTy, Substs, Ty,
-    TyKind, TypeCtor, TypeWalk,
+    TypeCtor, TypeWalk,
 };
 
 impl<'a> InferenceContext<'a> {
@@ -86,20 +86,10 @@ where
     }
 
     fn into_canonicalized<T>(self, result: T) -> Canonicalized<T> {
-        let kinds = self
-            .free_vars
-            .iter()
-            .map(|v| match v {
-                // mapping MaybeNeverTypeVar to the same kind as general ones
-                // should be fine, because as opposed to int or float type vars,
-                // they don't restrict what kind of type can go into them, they
-                // just affect fallback.
-                InferTy::TypeVar(_) | InferTy::MaybeNeverTypeVar(_) => TyKind::General,
-                InferTy::IntVar(_) => TyKind::Integer,
-                InferTy::FloatVar(_) => TyKind::Float,
-            })
-            .collect();
-        Canonicalized { value: Canonical { value: result, kinds }, free_vars: self.free_vars }
+        Canonicalized {
+            value: Canonical { value: result, num_vars: self.free_vars.len() },
+            free_vars: self.free_vars,
+        }
     }
 
     pub(crate) fn canonicalize_ty(mut self, ty: Ty) -> Canonicalized<Ty> {
@@ -141,41 +131,26 @@ impl<T> Canonicalized<T> {
         ty
     }
 
-    pub fn apply_solution(&self, ctx: &mut InferenceContext<'_>, solution: Canonical<Substs>) {
+    pub fn apply_solution(&self, ctx: &mut InferenceContext<'_>, solution: Canonical<Vec<Ty>>) {
         // the solution may contain new variables, which we need to convert to new inference vars
-        let new_vars = Substs(
-            solution
-                .kinds
-                .iter()
-                .map(|k| match k {
-                    TyKind::General => ctx.table.new_type_var(),
-                    TyKind::Integer => ctx.table.new_integer_var(),
-                    TyKind::Float => ctx.table.new_float_var(),
-                })
-                .collect(),
-        );
+        let new_vars = Substs((0..solution.num_vars).map(|_| ctx.table.new_type_var()).collect());
         for (i, ty) in solution.value.into_iter().enumerate() {
             let var = self.free_vars[i];
             // eagerly replace projections in the type; we may be getting types
             // e.g. from where clauses where this hasn't happened yet
-            let ty = ctx.normalize_associated_types_in(ty.clone().subst_bound_vars(&new_vars));
+            let ty = ctx.normalize_associated_types_in(ty.subst_bound_vars(&new_vars));
             ctx.table.unify(&Ty::Infer(var), &ty);
         }
     }
 }
 
-pub fn unify(tys: &Canonical<(Ty, Ty)>) -> Option<Substs> {
+pub fn unify(ty1: &Canonical<Ty>, ty2: &Canonical<Ty>) -> Option<Substs> {
     let mut table = InferenceTable::new();
-    let vars = Substs(
-        tys.kinds
-            .iter()
-            // we always use type vars here because we want everything to
-            // fallback to Unknown in the end (kind of hacky, as below)
-            .map(|_| table.new_type_var())
-            .collect(),
-    );
-    let ty1_with_vars = tys.value.0.clone().subst_bound_vars(&vars);
-    let ty2_with_vars = tys.value.1.clone().subst_bound_vars(&vars);
+    let num_vars = ty1.num_vars.max(ty2.num_vars);
+    let vars =
+        Substs::builder(num_vars).fill(std::iter::repeat_with(|| table.new_type_var())).build();
+    let ty1_with_vars = ty1.value.clone().subst_bound_vars(&vars);
+    let ty2_with_vars = ty2.value.clone().subst_bound_vars(&vars);
     if !table.unify(&ty1_with_vars, &ty2_with_vars) {
         return None;
     }
@@ -187,7 +162,7 @@ pub fn unify(tys: &Canonical<(Ty, Ty)>) -> Option<Substs> {
         }
     }
     Some(
-        Substs::builder(tys.kinds.len())
+        Substs::builder(ty1.num_vars)
             .fill(vars.iter().map(|v| table.resolve_ty_completely(v.clone())))
             .build(),
     )
diff --git a/crates/ra_hir_ty/src/lib.rs b/crates/ra_hir_ty/src/lib.rs
index 7f3f5e7715..c9513b752a 100644
--- a/crates/ra_hir_ty/src/lib.rs
+++ b/crates/ra_hir_ty/src/lib.rs
@@ -662,27 +662,13 @@ impl TypeWalk for GenericPredicate {
 
 /// Basically a claim (currently not validated / checked) that the contained
 /// type / trait ref contains no inference variables; any inference variables it
-/// contained have been replaced by bound variables, and `kinds` tells us how
-/// many there are and whether they were normal or float/int variables. This is
-/// used to erase irrelevant differences between types before using them in
-/// queries.
+/// contained have been replaced by bound variables, and `num_vars` tells us how
+/// many there are. This is used to erase irrelevant differences between types
+/// before using them in queries.
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
 pub struct Canonical<T> {
     pub value: T,
-    pub kinds: Arc<[TyKind]>,
-}
-
-impl<T> Canonical<T> {
-    pub fn new(value: T, kinds: impl IntoIterator<Item = TyKind>) -> Self {
-        Self { value, kinds: kinds.into_iter().collect() }
-    }
-}
-
-#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
-pub enum TyKind {
-    General,
-    Integer,
-    Float,
+    pub num_vars: usize,
 }
 
 /// A function signature as seen by type inference: Several parameter types and
diff --git a/crates/ra_hir_ty/src/method_resolution.rs b/crates/ra_hir_ty/src/method_resolution.rs
index a45febbf74..c19519cf11 100644
--- a/crates/ra_hir_ty/src/method_resolution.rs
+++ b/crates/ra_hir_ty/src/method_resolution.rs
@@ -2,7 +2,7 @@
 //! For details about how this works in rustc, see the method lookup page in the
 //! [rustc guide](https://rust-lang.github.io/rustc-guide/method-lookup.html)
 //! and the corresponding code mostly in librustc_typeck/check/method/probe.rs.
-use std::{iter, sync::Arc};
+use std::sync::Arc;
 
 use arrayvec::ArrayVec;
 use hir_def::{
@@ -17,8 +17,7 @@ use rustc_hash::{FxHashMap, FxHashSet};
 use super::Substs;
 use crate::{
     autoderef, db::HirDatabase, primitive::FloatBitness, utils::all_super_traits, ApplicationTy,
-    Canonical, DebruijnIndex, InEnvironment, TraitEnvironment, TraitRef, Ty, TyKind, TypeCtor,
-    TypeWalk,
+    Canonical, DebruijnIndex, InEnvironment, TraitEnvironment, TraitRef, Ty, TypeCtor, TypeWalk,
 };
 
 /// This is used as a key for indexing impls.
@@ -39,131 +38,136 @@ impl TyFingerprint {
     }
 }
 
-/// Trait impls defined or available in some crate.
-#[derive(Debug, Eq, PartialEq)]
-pub struct TraitImpls {
-    // If the `Option<TyFingerprint>` is `None`, the impl may apply to any self type.
-    map: FxHashMap<TraitId, FxHashMap<Option<TyFingerprint>, Vec<ImplId>>>,
+/// A queryable and mergeable collection of impls.
+#[derive(Debug, PartialEq, Eq)]
+pub struct CrateImplDefs {
+    inherent_impls: FxHashMap<TyFingerprint, Vec<ImplId>>,
+    impls_by_trait: FxHashMap<TraitId, FxHashMap<Option<TyFingerprint>, Vec<ImplId>>>,
 }
 
-impl TraitImpls {
-    pub(crate) fn trait_impls_in_crate_query(db: &dyn HirDatabase, krate: CrateId) -> Arc<Self> {
-        let _p = profile("trait_impls_in_crate_query");
-        let mut impls = Self { map: FxHashMap::default() };
-
-        let crate_def_map = db.crate_def_map(krate);
-        for (_module_id, module_data) in crate_def_map.modules.iter() {
-            for impl_id in module_data.scope.impls() {
-                let target_trait = match db.impl_trait(impl_id) {
-                    Some(tr) => tr.value.trait_,
-                    None => continue,
-                };
-                let self_ty = db.impl_self_ty(impl_id);
-                let self_ty_fp = TyFingerprint::for_impl(&self_ty.value);
-                impls
-                    .map
-                    .entry(target_trait)
-                    .or_default()
-                    .entry(self_ty_fp)
-                    .or_default()
-                    .push(impl_id);
-            }
-        }
+impl CrateImplDefs {
+    pub(crate) fn impls_in_crate_query(db: &dyn HirDatabase, krate: CrateId) -> Arc<CrateImplDefs> {
+        let _p = profile("impls_in_crate_query");
+        let mut res = CrateImplDefs {
+            inherent_impls: FxHashMap::default(),
+            impls_by_trait: FxHashMap::default(),
+        };
+        res.fill(db, krate);
 
-        Arc::new(impls)
+        Arc::new(res)
     }
 
-    pub(crate) fn trait_impls_in_deps_query(db: &dyn HirDatabase, krate: CrateId) -> Arc<Self> {
-        let _p = profile("trait_impls_in_deps_query");
+    /// Collects all impls from transitive dependencies of `krate` that may be used by `krate`.
+    ///
+    /// The full set of impls that can be used by `krate` is the returned map plus all the impls
+    /// from `krate` itself.
+    pub(crate) fn impls_from_deps_query(
+        db: &dyn HirDatabase,
+        krate: CrateId,
+    ) -> Arc<CrateImplDefs> {
+        let _p = profile("impls_from_deps_query");
         let crate_graph = db.crate_graph();
-        let mut res = Self { map: FxHashMap::default() };
+        let mut res = CrateImplDefs {
+            inherent_impls: FxHashMap::default(),
+            impls_by_trait: FxHashMap::default(),
+        };
 
-        for krate in crate_graph.transitive_deps(krate) {
-            res.merge(&db.trait_impls_in_crate(krate));
+        // For each dependency, calculate `impls_from_deps` recursively, then add its own
+        // `impls_in_crate`.
+        // As we might visit crates multiple times, `merge` has to deduplicate impls to avoid
+        // wasting memory.
+        for dep in &crate_graph[krate].dependencies {
+            res.merge(&db.impls_from_deps(dep.crate_id));
+            res.merge(&db.impls_in_crate(dep.crate_id));
         }
 
         Arc::new(res)
     }
 
+    fn fill(&mut self, db: &dyn HirDatabase, krate: CrateId) {
+        let crate_def_map = db.crate_def_map(krate);
+        for (_module_id, module_data) in crate_def_map.modules.iter() {
+            for impl_id in module_data.scope.impls() {
+                match db.impl_trait(impl_id) {
+                    Some(tr) => {
+                        let self_ty = db.impl_self_ty(impl_id);
+                        let self_ty_fp = TyFingerprint::for_impl(&self_ty.value);
+                        self.impls_by_trait
+                            .entry(tr.value.trait_)
+                            .or_default()
+                            .entry(self_ty_fp)
+                            .or_default()
+                            .push(impl_id);
+                    }
+                    None => {
+                        let self_ty = db.impl_self_ty(impl_id);
+                        if let Some(self_ty_fp) = TyFingerprint::for_impl(&self_ty.value) {
+                            self.inherent_impls.entry(self_ty_fp).or_default().push(impl_id);
+                        }
+                    }
+                }
+            }
+        }
+    }
+
     fn merge(&mut self, other: &Self) {
-        for (trait_, other_map) in &other.map {
-            let map = self.map.entry(*trait_).or_default();
+        for (fp, impls) in &other.inherent_impls {
+            let vec = self.inherent_impls.entry(*fp).or_default();
+            vec.extend(impls);
+            vec.sort();
+            vec.dedup();
+        }
+
+        for (trait_, other_map) in &other.impls_by_trait {
+            let map = self.impls_by_trait.entry(*trait_).or_default();
             for (fp, impls) in other_map {
                 let vec = map.entry(*fp).or_default();
                 vec.extend(impls);
+                vec.sort();
+                vec.dedup();
             }
         }
     }
 
-    /// Queries all impls of the given trait.
-    pub fn for_trait(&self, trait_: TraitId) -> impl Iterator<Item = ImplId> + '_ {
-        self.map
-            .get(&trait_)
+    pub fn lookup_impl_defs(&self, ty: &Ty) -> impl Iterator<Item = ImplId> + '_ {
+        let fingerprint = TyFingerprint::for_impl(ty);
+        fingerprint.and_then(|f| self.inherent_impls.get(&f)).into_iter().flatten().copied()
+    }
+
+    pub fn lookup_impl_defs_for_trait(&self, tr: TraitId) -> impl Iterator<Item = ImplId> + '_ {
+        self.impls_by_trait
+            .get(&tr)
             .into_iter()
-            .flat_map(|map| map.values().flat_map(|v| v.iter().copied()))
+            .flat_map(|m| m.values().flat_map(|v| v.iter().copied()))
     }
 
-    /// Queries all impls of `trait_` that may apply to `self_ty`.
-    pub fn for_trait_and_self_ty(
+    pub fn lookup_impl_defs_for_trait_and_ty(
         &self,
-        trait_: TraitId,
-        self_ty: TyFingerprint,
+        tr: TraitId,
+        fp: TyFingerprint,
     ) -> impl Iterator<Item = ImplId> + '_ {
-        self.map
-            .get(&trait_)
+        self.impls_by_trait
+            .get(&tr)
+            .and_then(|m| m.get(&Some(fp)))
             .into_iter()
-            .flat_map(move |map| map.get(&None).into_iter().chain(map.get(&Some(self_ty))))
-            .flat_map(|v| v.iter().copied())
-    }
-
-    pub fn all_impls(&self) -> impl Iterator<Item = ImplId> + '_ {
-        self.map.values().flat_map(|map| map.values().flat_map(|v| v.iter().copied()))
-    }
-}
-
-/// Inherent impls defined in some crate.
-///
-/// Inherent impls can only be defined in the crate that also defines the self type of the impl
-/// (note that some primitives are considered to be defined by both libcore and liballoc).
-///
-/// This makes inherent impl lookup easier than trait impl lookup since we only have to consider a
-/// single crate.
-#[derive(Debug, Eq, PartialEq)]
-pub struct InherentImpls {
-    map: FxHashMap<TyFingerprint, Vec<ImplId>>,
-}
-
-impl InherentImpls {
-    pub(crate) fn inherent_impls_in_crate_query(db: &dyn HirDatabase, krate: CrateId) -> Arc<Self> {
-        let mut map: FxHashMap<_, Vec<_>> = FxHashMap::default();
-
-        let crate_def_map = db.crate_def_map(krate);
-        for (_module_id, module_data) in crate_def_map.modules.iter() {
-            for impl_id in module_data.scope.impls() {
-                let data = db.impl_data(impl_id);
-                if data.target_trait.is_some() {
-                    continue;
-                }
-
-                let self_ty = db.impl_self_ty(impl_id);
-                if let Some(fp) = TyFingerprint::for_impl(&self_ty.value) {
-                    map.entry(fp).or_default().push(impl_id);
-                }
-            }
-        }
-
-        Arc::new(Self { map })
-    }
-
-    pub fn for_self_ty(&self, self_ty: &Ty) -> &[ImplId] {
-        match TyFingerprint::for_impl(self_ty) {
-            Some(fp) => self.map.get(&fp).map(|vec| vec.as_ref()).unwrap_or(&[]),
-            None => &[],
-        }
+            .flatten()
+            .copied()
+            .chain(
+                self.impls_by_trait
+                    .get(&tr)
+                    .and_then(|m| m.get(&None))
+                    .into_iter()
+                    .flatten()
+                    .copied(),
+            )
     }
 
-    pub fn all_impls(&self) -> impl Iterator<Item = ImplId> + '_ {
-        self.map.values().flat_map(|v| v.iter().copied())
+    pub fn all_impls<'a>(&'a self) -> impl Iterator<Item = ImplId> + 'a {
+        self.inherent_impls
+            .values()
+            .chain(self.impls_by_trait.values().flat_map(|m| m.values()))
+            .flatten()
+            .copied()
     }
 }
 
@@ -373,7 +377,7 @@ fn iterate_method_candidates_with_autoref(
         return true;
     }
     let refed = Canonical {
-        kinds: deref_chain[0].kinds.clone(),
+        num_vars: deref_chain[0].num_vars,
         value: Ty::apply_one(TypeCtor::Ref(Mutability::Shared), deref_chain[0].value.clone()),
     };
     if iterate_method_candidates_by_receiver(
@@ -389,7 +393,7 @@ fn iterate_method_candidates_with_autoref(
         return true;
     }
     let ref_muted = Canonical {
-        kinds: deref_chain[0].kinds.clone(),
+        num_vars: deref_chain[0].num_vars,
         value: Ty::apply_one(TypeCtor::Ref(Mutability::Mut), deref_chain[0].value.clone()),
     };
     if iterate_method_candidates_by_receiver(
@@ -520,9 +524,9 @@ fn iterate_inherent_methods(
         None => return false,
     };
     for krate in def_crates {
-        let impls = db.inherent_impls_in_crate(krate);
+        let impls = db.impls_in_crate(krate);
 
-        for &impl_def in impls.for_self_ty(&self_ty.value) {
+        for impl_def in impls.lookup_impl_defs(&self_ty.value) {
             for &item in db.impl_data(impl_def).items.iter() {
                 if !is_valid_candidate(db, name, receiver_ty, item, self_ty) {
                     continue;
@@ -608,19 +612,18 @@ pub(crate) fn inherent_impl_substs(
     // we create a var for each type parameter of the impl; we need to keep in
     // mind here that `self_ty` might have vars of its own
     let vars = Substs::build_for_def(db, impl_id)
-        .fill_with_bound_vars(DebruijnIndex::INNERMOST, self_ty.kinds.len())
+        .fill_with_bound_vars(DebruijnIndex::INNERMOST, self_ty.num_vars)
         .build();
     let self_ty_with_vars = db.impl_self_ty(impl_id).subst(&vars);
-    let mut kinds = self_ty.kinds.to_vec();
-    kinds.extend(iter::repeat(TyKind::General).take(vars.len()));
-    let tys = Canonical { kinds: kinds.into(), value: (self_ty_with_vars, self_ty.value.clone()) };
-    let substs = super::infer::unify(&tys);
+    let self_ty_with_vars =
+        Canonical { num_vars: vars.len() + self_ty.num_vars, value: self_ty_with_vars };
+    let substs = super::infer::unify(&self_ty_with_vars, self_ty);
     // We only want the substs for the vars we added, not the ones from self_ty.
     // Also, if any of the vars we added are still in there, we replace them by
     // Unknown. I think this can only really happen if self_ty contained
     // Unknown, and in that case we want the result to contain Unknown in those
     // places again.
-    substs.map(|s| fallback_bound_vars(s.suffix(vars.len()), self_ty.kinds.len()))
+    substs.map(|s| fallback_bound_vars(s.suffix(vars.len()), self_ty.num_vars))
 }
 
 /// This replaces any 'free' Bound vars in `s` (i.e. those with indices past
@@ -680,15 +683,15 @@ fn generic_implements_goal(
     trait_: TraitId,
     self_ty: Canonical<Ty>,
 ) -> Canonical<InEnvironment<super::Obligation>> {
-    let mut kinds = self_ty.kinds.to_vec();
+    let num_vars = self_ty.num_vars;
     let substs = super::Substs::build_for_def(db, trait_)
         .push(self_ty.value)
-        .fill_with_bound_vars(DebruijnIndex::INNERMOST, kinds.len())
+        .fill_with_bound_vars(DebruijnIndex::INNERMOST, num_vars)
         .build();
-    kinds.extend(iter::repeat(TyKind::General).take(substs.len() - 1));
+    let num_vars = substs.len() - 1 + self_ty.num_vars;
     let trait_ref = TraitRef { trait_, substs };
     let obligation = super::Obligation::Trait(trait_ref);
-    Canonical { kinds: kinds.into(), value: InEnvironment::new(env, obligation) }
+    Canonical { num_vars, value: InEnvironment::new(env, obligation) }
 }
 
 fn autoderef_method_receiver(
@@ -701,9 +704,9 @@ fn autoderef_method_receiver(
     if let Some(Ty::Apply(ApplicationTy { ctor: TypeCtor::Array, parameters })) =
         deref_chain.last().map(|ty| &ty.value)
     {
-        let kinds = deref_chain.last().unwrap().kinds.clone();
+        let num_vars = deref_chain.last().unwrap().num_vars;
         let unsized_ty = Ty::apply(TypeCtor::Slice, parameters.clone());
-        deref_chain.push(Canonical { value: unsized_ty, kinds })
+        deref_chain.push(Canonical { value: unsized_ty, num_vars })
     }
     deref_chain
 }
diff --git a/crates/ra_hir_ty/src/traits.rs b/crates/ra_hir_ty/src/traits.rs
index 2a6d7faefe..6f43c3a22e 100644
--- a/crates/ra_hir_ty/src/traits.rs
+++ b/crates/ra_hir_ty/src/traits.rs
@@ -1,5 +1,5 @@
 //! Trait solving using Chalk.
-use std::sync::Arc;
+use std::{panic, sync::Arc};
 
 use chalk_ir::cast::Cast;
 use hir_def::{
@@ -8,7 +8,7 @@ use hir_def::{
 use ra_db::{impl_intern_key, salsa, CrateId};
 use ra_prof::profile;
 
-use crate::{db::HirDatabase, DebruijnIndex, Substs};
+use crate::{db::HirDatabase, DebruijnIndex};
 
 use super::{Canonical, GenericPredicate, HirDisplay, ProjectionTy, TraitRef, Ty, TypeWalk};
 
@@ -190,7 +190,15 @@ fn solution_from_chalk(
     solution: chalk_solve::Solution<Interner>,
 ) -> Solution {
     let convert_subst = |subst: chalk_ir::Canonical<chalk_ir::Substitution<Interner>>| {
-        let result = from_chalk(db, subst);
+        let value = subst
+            .value
+            .iter(&Interner)
+            .map(|p| match p.ty(&Interner) {
+                Some(ty) => from_chalk(db, ty.clone()),
+                None => unimplemented!(),
+            })
+            .collect();
+        let result = Canonical { value, num_vars: subst.binders.len(&Interner) };
         SolutionVariables(result)
     };
     match solution {
@@ -214,7 +222,7 @@ fn solution_from_chalk(
 }
 
 #[derive(Clone, Debug, PartialEq, Eq)]
-pub struct SolutionVariables(pub Canonical<Substs>);
+pub struct SolutionVariables(pub Canonical<Vec<Ty>>);
 
 #[derive(Clone, Debug, PartialEq, Eq)]
 /// A (possible) solution for a proposed goal.
diff --git a/crates/ra_hir_ty/src/traits/chalk.rs b/crates/ra_hir_ty/src/traits/chalk.rs
index c97b81d579..8ef4941c0a 100644
--- a/crates/ra_hir_ty/src/traits/chalk.rs
+++ b/crates/ra_hir_ty/src/traits/chalk.rs
@@ -77,8 +77,8 @@ impl<'a> chalk_solve::RustIrDatabase<Interner> for ChalkContext<'a> {
         // Note: Since we're using impls_for_trait, only impls where the trait
         // can be resolved should ever reach Chalk. `impl_datum` relies on that
         // and will panic if the trait can't be resolved.
-        let in_deps = self.db.trait_impls_in_deps(self.krate);
-        let in_self = self.db.trait_impls_in_crate(self.krate);
+        let in_deps = self.db.impls_from_deps(self.krate);
+        let in_self = self.db.impls_in_crate(self.krate);
         let impl_maps = [in_deps, in_self];
 
         let id_to_chalk = |id: hir_def::ImplId| Impl::ImplDef(id).to_chalk(self.db);
@@ -87,12 +87,14 @@ impl<'a> chalk_solve::RustIrDatabase<Interner> for ChalkContext<'a> {
             Some(fp) => impl_maps
                 .iter()
                 .flat_map(|crate_impl_defs| {
-                    crate_impl_defs.for_trait_and_self_ty(trait_, fp).map(id_to_chalk)
+                    crate_impl_defs.lookup_impl_defs_for_trait_and_ty(trait_, fp).map(id_to_chalk)
                 })
                 .collect(),
             None => impl_maps
                 .iter()
-                .flat_map(|crate_impl_defs| crate_impl_defs.for_trait(trait_).map(id_to_chalk))
+                .flat_map(|crate_impl_defs| {
+                    crate_impl_defs.lookup_impl_defs_for_trait(trait_).map(id_to_chalk)
+                })
                 .collect(),
         };
 
diff --git a/crates/ra_hir_ty/src/traits/chalk/mapping.rs b/crates/ra_hir_ty/src/traits/chalk/mapping.rs
index 433d6aa03d..ac82ea8310 100644
--- a/crates/ra_hir_ty/src/traits/chalk/mapping.rs
+++ b/crates/ra_hir_ty/src/traits/chalk/mapping.rs
@@ -17,7 +17,7 @@ use crate::{
     primitive::{FloatBitness, FloatTy, IntBitness, IntTy, Signedness},
     traits::{builtin, AssocTyValue, Canonical, Impl, Obligation},
     ApplicationTy, CallableDef, GenericPredicate, InEnvironment, OpaqueTy, OpaqueTyId,
-    ProjectionPredicate, ProjectionTy, Substs, TraitEnvironment, TraitRef, Ty, TyKind, TypeCtor,
+    ProjectionPredicate, ProjectionTy, Substs, TraitEnvironment, TraitRef, Ty, TypeCtor,
 };
 
 use super::interner::*;
@@ -555,39 +555,22 @@ where
     type Chalk = chalk_ir::Canonical<T::Chalk>;
 
     fn to_chalk(self, db: &dyn HirDatabase) -> chalk_ir::Canonical<T::Chalk> {
-        let kinds = self
-            .kinds
-            .iter()
-            .map(|k| match k {
-                TyKind::General => chalk_ir::TyKind::General,
-                TyKind::Integer => chalk_ir::TyKind::Integer,
-                TyKind::Float => chalk_ir::TyKind::Float,
-            })
-            .map(|tk| {
-                chalk_ir::CanonicalVarKind::new(
-                    chalk_ir::VariableKind::Ty(tk),
-                    chalk_ir::UniverseIndex::ROOT,
-                )
-            });
+        let parameter = chalk_ir::CanonicalVarKind::new(
+            chalk_ir::VariableKind::Ty(chalk_ir::TyKind::General),
+            chalk_ir::UniverseIndex::ROOT,
+        );
         let value = self.value.to_chalk(db);
-        chalk_ir::Canonical { value, binders: chalk_ir::CanonicalVarKinds::from(&Interner, kinds) }
+        chalk_ir::Canonical {
+            value,
+            binders: chalk_ir::CanonicalVarKinds::from(&Interner, vec![parameter; self.num_vars]),
+        }
     }
 
     fn from_chalk(db: &dyn HirDatabase, canonical: chalk_ir::Canonical<T::Chalk>) -> Canonical<T> {
-        let kinds = canonical
-            .binders
-            .iter(&Interner)
-            .map(|k| match k.kind {
-                chalk_ir::VariableKind::Ty(tk) => match tk {
-                    chalk_ir::TyKind::General => TyKind::General,
-                    chalk_ir::TyKind::Integer => TyKind::Integer,
-                    chalk_ir::TyKind::Float => TyKind::Float,
-                },
-                chalk_ir::VariableKind::Lifetime => panic!("unexpected lifetime from Chalk"),
-                chalk_ir::VariableKind::Const(_) => panic!("unexpected const from Chalk"),
-            })
-            .collect();
-        Canonical { kinds, value: from_chalk(db, canonical.value) }
+        Canonical {
+            num_vars: canonical.binders.len(&Interner),
+            value: from_chalk(db, canonical.value),
+        }
     }
 }
 
diff --git a/crates/ra_ide/src/call_hierarchy.rs b/crates/ra_ide/src/call_hierarchy.rs
index 884353808e..bd0e488340 100644
--- a/crates/ra_ide/src/call_hierarchy.rs
+++ b/crates/ra_ide/src/call_hierarchy.rs
@@ -39,11 +39,10 @@ pub(crate) fn call_hierarchy(
 
 pub(crate) fn incoming_calls(db: &RootDatabase, position: FilePosition) -> Option<Vec<CallItem>> {
     let sema = Semantics::new(db);
-
     // 1. Find all refs
     // 2. Loop through refs and determine unique fndef. This will become our `from: CallHierarchyItem,` in the reply.
     // 3. Add ranges relative to the start of the fndef.
-    let refs = references::find_all_refs(&sema, position, None)?;
+    let refs = references::find_all_refs(db, position, None)?;
 
     let mut calls = CallLocations::default();
 
diff --git a/crates/ra_ide/src/completion.rs b/crates/ra_ide/src/completion.rs
index 9ebb8ebb7c..e1fcf379d7 100644
--- a/crates/ra_ide/src/completion.rs
+++ b/crates/ra_ide/src/completion.rs
@@ -63,11 +63,11 @@ pub use crate::completion::{
 // There also snippet completions:
 //
 // .Expressions
-// - `pd` -> `eprintln!(" = {:?}", );")`
-// - `ppd` -> `eprintln!(" = {:#?}", );`
+// - `pd` -> `println!("{:?}")`
+// - `ppd` -> `println!("{:#?}")`
 //
 // .Items
-// - `tfn` -> `#[test] fn feature(){}`
+// - `tfn` -> `#[test] fn f(){}`
 // - `tmod` ->
 // ```rust
 // #[cfg(test)]
@@ -75,7 +75,7 @@ pub use crate::completion::{
 //     use super::*;
 //
 //     #[test]
-//     fn test_name() {}
+//     fn test_fn() {}
 // }
 // ```
 
@@ -137,8 +137,8 @@ mod tests {
         documentation: &'a str,
     }
 
-    fn check_detail_and_documentation(ra_fixture: &str, expected: DetailAndDocumentation) {
-        let (analysis, position) = analysis_and_position(ra_fixture);
+    fn check_detail_and_documentation(fixture: &str, expected: DetailAndDocumentation) {
+        let (analysis, position) = analysis_and_position(fixture);
         let config = CompletionConfig::default();
         let completions = analysis.completions(&config, position).unwrap().unwrap();
         for item in completions {
diff --git a/crates/ra_ide/src/completion/complete_keyword.rs b/crates/ra_ide/src/completion/complete_keyword.rs
index e599cc3d16..3b174f9161 100644
--- a/crates/ra_ide/src/completion/complete_keyword.rs
+++ b/crates/ra_ide/src/completion/complete_keyword.rs
@@ -1,6 +1,6 @@
 //! FIXME: write short doc here
 
-use ra_syntax::{ast, SyntaxKind};
+use ra_syntax::ast;
 
 use crate::completion::{
     CompletionContext, CompletionItem, CompletionItemKind, CompletionKind, Completions,
@@ -37,10 +37,6 @@ pub(super) fn complete_use_tree_keyword(acc: &mut Completions, ctx: &CompletionC
 }
 
 pub(super) fn complete_expr_keyword(acc: &mut Completions, ctx: &CompletionContext) {
-    if ctx.token.kind() == SyntaxKind::COMMENT {
-        return;
-    }
-
     let has_trait_or_impl_parent = ctx.has_impl_parent || ctx.has_trait_parent;
     if ctx.trait_as_prev_sibling || ctx.impl_as_prev_sibling {
         add_keyword(ctx, acc, "where", "where ");
diff --git a/crates/ra_ide/src/completion/presentation.rs b/crates/ra_ide/src/completion/presentation.rs
index b18279746e..4fdc2f0bbc 100644
--- a/crates/ra_ide/src/completion/presentation.rs
+++ b/crates/ra_ide/src/completion/presentation.rs
@@ -1516,54 +1516,4 @@ mod tests {
         "###
         );
     }
-
-    #[test]
-    fn no_keyword_autocompletion_on_line_comments() {
-        assert_debug_snapshot!(
-        do_completion(
-                r"
-                    fn test() {
-                        let x = 2; // A comment<|>
-                    }
-                    ",
-                CompletionKind::Keyword
-        ),
-            @r###"
-            []
-            "###
-        );
-    }
-
-    #[test]
-    fn no_keyword_autocompletion_on_multi_line_comments() {
-        assert_debug_snapshot!(
-        do_completion(
-                r"
-                    /*
-                    Some multi-line comment<|>
-                    */
-                    ",
-                CompletionKind::Keyword
-        ),
-            @r###"
-            []
-            "###
-        );
-    }
-
-    #[test]
-    fn no_keyword_autocompletion_on_doc_comments() {
-        assert_debug_snapshot!(
-        do_completion(
-                r"
-                    /// Some doc comment
-                    /// let test<|> = 1
-                    ",
-                CompletionKind::Keyword
-        ),
-            @r###"
-            []
-            "###
-        );
-    }
 }
diff --git a/crates/ra_ide/src/diagnostics.rs b/crates/ra_ide/src/diagnostics.rs
index 46f8c31c7a..05fb799d60 100644
--- a/crates/ra_ide/src/diagnostics.rs
+++ b/crates/ra_ide/src/diagnostics.rs
@@ -324,10 +324,10 @@ mod tests {
     ///  * a diagnostic is produced
     ///  * this diagnostic touches the input cursor position
     ///  * that the contents of the file containing the cursor match `after` after the diagnostic fix is applied
-    fn check_apply_diagnostic_fix_from_position(ra_fixture: &str, after: &str) {
+    fn check_apply_diagnostic_fix_from_position(fixture: &str, after: &str) {
         let after = trim_indent(after);
 
-        let (analysis, file_position) = analysis_and_position(ra_fixture);
+        let (analysis, file_position) = analysis_and_position(fixture);
         let diagnostic = analysis.diagnostics(file_position.file_id).unwrap().pop().unwrap();
         let mut fix = diagnostic.fix.unwrap();
         let edit = fix.source_change.source_file_edits.pop().unwrap().edit;
@@ -365,14 +365,14 @@ mod tests {
 
     /// Takes a multi-file input fixture with annotated cursor position and checks that no diagnostics
     /// apply to the file containing the cursor.
-    fn check_no_diagnostic_for_target_file(ra_fixture: &str) {
-        let (analysis, file_position) = analysis_and_position(ra_fixture);
+    fn check_no_diagnostic_for_target_file(fixture: &str) {
+        let (analysis, file_position) = analysis_and_position(fixture);
         let diagnostics = analysis.diagnostics(file_position.file_id).unwrap();
         assert_eq!(diagnostics.len(), 0);
     }
 
-    fn check_no_diagnostic(ra_fixture: &str) {
-        let (analysis, file_id) = single_file(ra_fixture);
+    fn check_no_diagnostic(content: &str) {
+        let (analysis, file_id) = single_file(content);
         let diagnostics = analysis.diagnostics(file_id).unwrap();
         assert_eq!(diagnostics.len(), 0, "expected no diagnostic, found one");
     }
@@ -473,8 +473,7 @@ mod tests {
 
     #[test]
     fn test_wrap_return_type_not_applicable_when_expr_type_does_not_match_ok_type() {
-        check_no_diagnostic_for_target_file(
-            r"
+        let content = r#"
             //- /main.rs
             use core::result::Result::{self, Ok, Err};
 
@@ -486,14 +485,13 @@ mod tests {
             pub mod result {
                 pub enum Result<T, E> { Ok(T), Err(E) }
             }
-        ",
-        );
+        "#;
+        check_no_diagnostic_for_target_file(content);
     }
 
     #[test]
     fn test_wrap_return_type_not_applicable_when_return_type_is_not_result() {
-        check_no_diagnostic_for_target_file(
-            r"
+        let content = r#"
             //- /main.rs
             use core::result::Result::{self, Ok, Err};
 
@@ -510,8 +508,8 @@ mod tests {
             pub mod result {
                 pub enum Result<T, E> { Ok(T), Err(E) }
             }
-        ",
-        );
+        "#;
+        check_no_diagnostic_for_target_file(content);
     }
 
     #[test]
@@ -620,8 +618,7 @@ mod tests {
 
     #[test]
     fn test_fill_struct_fields_no_diagnostic() {
-        check_no_diagnostic(
-            r"
+        let content = r"
             struct TestStruct {
                 one: i32,
                 two: i64,
@@ -631,14 +628,14 @@ mod tests {
                 let one = 1;
                 let s = TestStruct{ one, two: 2 };
             }
-        ",
-        );
+        ";
+
+        check_no_diagnostic(content);
     }
 
     #[test]
     fn test_fill_struct_fields_no_diagnostic_on_spread() {
-        check_no_diagnostic(
-            r"
+        let content = r"
             struct TestStruct {
                 one: i32,
                 two: i64,
@@ -648,8 +645,9 @@ mod tests {
                 let one = 1;
                 let s = TestStruct{ ..a };
             }
-        ",
-        );
+        ";
+
+        check_no_diagnostic(content);
     }
 
     #[test]
diff --git a/crates/ra_ide/src/display/structure.rs b/crates/ra_ide/src/display/structure.rs
index c22a5d17b3..aad5a8e4db 100644
--- a/crates/ra_ide/src/display/structure.rs
+++ b/crates/ra_ide/src/display/structure.rs
@@ -173,19 +173,12 @@ fn structure_node(node: &SyntaxNode) -> Option<StructureNode> {
 
 #[cfg(test)]
 mod tests {
-    use expect::{expect, Expect};
-
     use super::*;
-
-    fn check(ra_fixture: &str, expect: Expect) {
-        let file = SourceFile::parse(ra_fixture).ok().unwrap();
-        let structure = file_structure(&file);
-        expect.assert_debug_eq(&structure)
-    }
+    use insta::assert_debug_snapshot;
 
     #[test]
     fn test_file_structure() {
-        check(
+        let file = SourceFile::parse(
             r#"
 struct Foo {
     x: i32
@@ -230,211 +223,216 @@ fn obsolete() {}
 #[deprecated(note = "for awhile")]
 fn very_obsolete() {}
 "#,
-            expect![[r#"
-                [
-                    StructureNode {
-                        parent: None,
-                        label: "Foo",
-                        navigation_range: 8..11,
-                        node_range: 1..26,
-                        kind: STRUCT_DEF,
-                        detail: None,
-                        deprecated: false,
-                    },
-                    StructureNode {
-                        parent: Some(
-                            0,
-                        ),
-                        label: "x",
-                        navigation_range: 18..19,
-                        node_range: 18..24,
-                        kind: RECORD_FIELD_DEF,
-                        detail: Some(
-                            "i32",
-                        ),
-                        deprecated: false,
-                    },
-                    StructureNode {
-                        parent: None,
-                        label: "m",
-                        navigation_range: 32..33,
-                        node_range: 28..158,
-                        kind: MODULE,
-                        detail: None,
-                        deprecated: false,
-                    },
-                    StructureNode {
-                        parent: Some(
-                            2,
-                        ),
-                        label: "bar1",
-                        navigation_range: 43..47,
-                        node_range: 40..52,
-                        kind: FN_DEF,
-                        detail: Some(
-                            "fn()",
-                        ),
-                        deprecated: false,
-                    },
-                    StructureNode {
-                        parent: Some(
-                            2,
-                        ),
-                        label: "bar2",
-                        navigation_range: 60..64,
-                        node_range: 57..81,
-                        kind: FN_DEF,
-                        detail: Some(
-                            "fn<T>(t: T) -> T",
-                        ),
-                        deprecated: false,
-                    },
-                    StructureNode {
-                        parent: Some(
-                            2,
-                        ),
-                        label: "bar3",
-                        navigation_range: 89..93,
-                        node_range: 86..156,
-                        kind: FN_DEF,
-                        detail: Some(
-                            "fn<A, B>(a: A, b: B) -> Vec< u32 >",
-                        ),
-                        deprecated: false,
-                    },
-                    StructureNode {
-                        parent: None,
-                        label: "E",
-                        navigation_range: 165..166,
-                        node_range: 160..180,
-                        kind: ENUM_DEF,
-                        detail: None,
-                        deprecated: false,
-                    },
-                    StructureNode {
-                        parent: Some(
-                            6,
-                        ),
-                        label: "X",
-                        navigation_range: 169..170,
-                        node_range: 169..170,
-                        kind: ENUM_VARIANT,
-                        detail: None,
-                        deprecated: false,
-                    },
-                    StructureNode {
-                        parent: Some(
-                            6,
-                        ),
-                        label: "Y",
-                        navigation_range: 172..173,
-                        node_range: 172..178,
-                        kind: ENUM_VARIANT,
-                        detail: None,
-                        deprecated: false,
-                    },
-                    StructureNode {
-                        parent: None,
-                        label: "T",
-                        navigation_range: 186..187,
-                        node_range: 181..193,
-                        kind: TYPE_ALIAS_DEF,
-                        detail: Some(
-                            "()",
-                        ),
-                        deprecated: false,
-                    },
-                    StructureNode {
-                        parent: None,
-                        label: "S",
-                        navigation_range: 201..202,
-                        node_range: 194..213,
-                        kind: STATIC_DEF,
-                        detail: Some(
-                            "i32",
-                        ),
-                        deprecated: false,
-                    },
-                    StructureNode {
-                        parent: None,
-                        label: "C",
-                        navigation_range: 220..221,
-                        node_range: 214..232,
-                        kind: CONST_DEF,
-                        detail: Some(
-                            "i32",
-                        ),
-                        deprecated: false,
-                    },
-                    StructureNode {
-                        parent: None,
-                        label: "impl E",
-                        navigation_range: 239..240,
-                        node_range: 234..243,
-                        kind: IMPL_DEF,
-                        detail: None,
-                        deprecated: false,
-                    },
-                    StructureNode {
-                        parent: None,
-                        label: "impl fmt::Debug for E",
-                        navigation_range: 265..266,
-                        node_range: 245..269,
-                        kind: IMPL_DEF,
-                        detail: None,
-                        deprecated: false,
-                    },
-                    StructureNode {
-                        parent: None,
-                        label: "mc",
-                        navigation_range: 284..286,
-                        node_range: 271..303,
-                        kind: MACRO_CALL,
-                        detail: None,
-                        deprecated: false,
-                    },
-                    StructureNode {
-                        parent: None,
-                        label: "mcexp",
-                        navigation_range: 334..339,
-                        node_range: 305..356,
-                        kind: MACRO_CALL,
-                        detail: None,
-                        deprecated: false,
-                    },
-                    StructureNode {
-                        parent: None,
-                        label: "mcexp",
-                        navigation_range: 387..392,
-                        node_range: 358..409,
-                        kind: MACRO_CALL,
-                        detail: None,
-                        deprecated: false,
-                    },
-                    StructureNode {
-                        parent: None,
-                        label: "obsolete",
-                        navigation_range: 428..436,
-                        node_range: 411..441,
-                        kind: FN_DEF,
-                        detail: Some(
-                            "fn()",
-                        ),
-                        deprecated: true,
-                    },
-                    StructureNode {
-                        parent: None,
-                        label: "very_obsolete",
-                        navigation_range: 481..494,
-                        node_range: 443..499,
-                        kind: FN_DEF,
-                        detail: Some(
-                            "fn()",
-                        ),
-                        deprecated: true,
-                    },
-                ]
-            "#]],
-        );
+        )
+        .ok()
+        .unwrap();
+        let structure = file_structure(&file);
+        assert_debug_snapshot!(structure,
+        @r###"
+        [
+            StructureNode {
+                parent: None,
+                label: "Foo",
+                navigation_range: 8..11,
+                node_range: 1..26,
+                kind: STRUCT_DEF,
+                detail: None,
+                deprecated: false,
+            },
+            StructureNode {
+                parent: Some(
+                    0,
+                ),
+                label: "x",
+                navigation_range: 18..19,
+                node_range: 18..24,
+                kind: RECORD_FIELD_DEF,
+                detail: Some(
+                    "i32",
+                ),
+                deprecated: false,
+            },
+            StructureNode {
+                parent: None,
+                label: "m",
+                navigation_range: 32..33,
+                node_range: 28..158,
+                kind: MODULE,
+                detail: None,
+                deprecated: false,
+            },
+            StructureNode {
+                parent: Some(
+                    2,
+                ),
+                label: "bar1",
+                navigation_range: 43..47,
+                node_range: 40..52,
+                kind: FN_DEF,
+                detail: Some(
+                    "fn()",
+                ),
+                deprecated: false,
+            },
+            StructureNode {
+                parent: Some(
+                    2,
+                ),
+                label: "bar2",
+                navigation_range: 60..64,
+                node_range: 57..81,
+                kind: FN_DEF,
+                detail: Some(
+                    "fn<T>(t: T) -> T",
+                ),
+                deprecated: false,
+            },
+            StructureNode {
+                parent: Some(
+                    2,
+                ),
+                label: "bar3",
+                navigation_range: 89..93,
+                node_range: 86..156,
+                kind: FN_DEF,
+                detail: Some(
+                    "fn<A, B>(a: A, b: B) -> Vec< u32 >",
+                ),
+                deprecated: false,
+            },
+            StructureNode {
+                parent: None,
+                label: "E",
+                navigation_range: 165..166,
+                node_range: 160..180,
+                kind: ENUM_DEF,
+                detail: None,
+                deprecated: false,
+            },
+            StructureNode {
+                parent: Some(
+                    6,
+                ),
+                label: "X",
+                navigation_range: 169..170,
+                node_range: 169..170,
+                kind: ENUM_VARIANT,
+                detail: None,
+                deprecated: false,
+            },
+            StructureNode {
+                parent: Some(
+                    6,
+                ),
+                label: "Y",
+                navigation_range: 172..173,
+                node_range: 172..178,
+                kind: ENUM_VARIANT,
+                detail: None,
+                deprecated: false,
+            },
+            StructureNode {
+                parent: None,
+                label: "T",
+                navigation_range: 186..187,
+                node_range: 181..193,
+                kind: TYPE_ALIAS_DEF,
+                detail: Some(
+                    "()",
+                ),
+                deprecated: false,
+            },
+            StructureNode {
+                parent: None,
+                label: "S",
+                navigation_range: 201..202,
+                node_range: 194..213,
+                kind: STATIC_DEF,
+                detail: Some(
+                    "i32",
+                ),
+                deprecated: false,
+            },
+            StructureNode {
+                parent: None,
+                label: "C",
+                navigation_range: 220..221,
+                node_range: 214..232,
+                kind: CONST_DEF,
+                detail: Some(
+                    "i32",
+                ),
+                deprecated: false,
+            },
+            StructureNode {
+                parent: None,
+                label: "impl E",
+                navigation_range: 239..240,
+                node_range: 234..243,
+                kind: IMPL_DEF,
+                detail: None,
+                deprecated: false,
+            },
+            StructureNode {
+                parent: None,
+                label: "impl fmt::Debug for E",
+                navigation_range: 265..266,
+                node_range: 245..269,
+                kind: IMPL_DEF,
+                detail: None,
+                deprecated: false,
+            },
+            StructureNode {
+                parent: None,
+                label: "mc",
+                navigation_range: 284..286,
+                node_range: 271..303,
+                kind: MACRO_CALL,
+                detail: None,
+                deprecated: false,
+            },
+            StructureNode {
+                parent: None,
+                label: "mcexp",
+                navigation_range: 334..339,
+                node_range: 305..356,
+                kind: MACRO_CALL,
+                detail: None,
+                deprecated: false,
+            },
+            StructureNode {
+                parent: None,
+                label: "mcexp",
+                navigation_range: 387..392,
+                node_range: 358..409,
+                kind: MACRO_CALL,
+                detail: None,
+                deprecated: false,
+            },
+            StructureNode {
+                parent: None,
+                label: "obsolete",
+                navigation_range: 428..436,
+                node_range: 411..441,
+                kind: FN_DEF,
+                detail: Some(
+                    "fn()",
+                ),
+                deprecated: true,
+            },
+            StructureNode {
+                parent: None,
+                label: "very_obsolete",
+                navigation_range: 481..494,
+                node_range: 443..499,
+                kind: FN_DEF,
+                detail: Some(
+                    "fn()",
+                ),
+                deprecated: true,
+            },
+        ]
+        "###
+                );
     }
 }
diff --git a/crates/ra_ide/src/expand_macro.rs b/crates/ra_ide/src/expand_macro.rs
index 043515f541..54a47aac06 100644
--- a/crates/ra_ide/src/expand_macro.rs
+++ b/crates/ra_ide/src/expand_macro.rs
@@ -2,9 +2,7 @@ use hir::Semantics;
 use ra_ide_db::RootDatabase;
 use ra_syntax::{
     algo::{find_node_at_offset, SyntaxRewriter},
-    ast, AstNode, NodeOrToken, SyntaxKind,
-    SyntaxKind::*,
-    SyntaxNode, WalkEvent, T,
+    ast, AstNode, NodeOrToken, SyntaxKind, SyntaxNode, WalkEvent, T,
 };
 
 use crate::FilePosition;
@@ -67,6 +65,8 @@ fn expand_macro_recur(
 // FIXME: It would also be cool to share logic here and in the mbe tests,
 // which are pretty unreadable at the moment.
 fn insert_whitespaces(syn: SyntaxNode) -> String {
+    use SyntaxKind::*;
+
     let mut res = String::new();
     let mut token_iter = syn
         .preorder_with_tokens()
@@ -120,164 +120,175 @@ fn insert_whitespaces(syn: SyntaxNode) -> String {
 
 #[cfg(test)]
 mod tests {
-    use expect::{expect, Expect};
+    use insta::assert_snapshot;
 
     use crate::mock_analysis::analysis_and_position;
 
-    fn check(ra_fixture: &str, expect: Expect) {
-        let (analysis, pos) = analysis_and_position(ra_fixture);
-        let expansion = analysis.expand_macro(pos).unwrap().unwrap();
-        let actual = format!("{}\n{}", expansion.name, expansion.expansion);
-        expect.assert_eq(&actual);
+    use super::*;
+
+    fn check_expand_macro(fixture: &str) -> ExpandedMacro {
+        let (analysis, pos) = analysis_and_position(fixture);
+        analysis.expand_macro(pos).unwrap().unwrap()
     }
 
     #[test]
     fn macro_expand_recursive_expansion() {
-        check(
+        let res = check_expand_macro(
             r#"
-macro_rules! bar {
-    () => { fn  b() {} }
-}
-macro_rules! foo {
-    () => { bar!(); }
-}
-macro_rules! baz {
-    () => { foo!(); }
-}
-f<|>oo!();
-"#,
-            expect![[r#"
-                foo
-                fn b(){}
-            "#]],
+        //- /lib.rs
+        macro_rules! bar {
+            () => { fn  b() {} }
+        }
+        macro_rules! foo {
+            () => { bar!(); }
+        }
+        macro_rules! baz {
+            () => { foo!(); }
+        }
+        f<|>oo!();
+        "#,
         );
+
+        assert_eq!(res.name, "foo");
+        assert_snapshot!(res.expansion, @r###"
+fn b(){}
+"###);
     }
 
     #[test]
     fn macro_expand_multiple_lines() {
-        check(
+        let res = check_expand_macro(
             r#"
-macro_rules! foo {
-    () => {
-        fn some_thing() -> u32 {
-            let a = 0;
-            a + 10
+        //- /lib.rs
+        macro_rules! foo {
+            () => {
+                fn some_thing() -> u32 {
+                    let a = 0;
+                    a + 10
+                }
+            }
         }
-    }
-}
-f<|>oo!();
+        f<|>oo!();
         "#,
-            expect![[r#"
-            foo
-            fn some_thing() -> u32 {
-              let a = 0;
-              a+10
-            }"#]],
         );
+
+        assert_eq!(res.name, "foo");
+        assert_snapshot!(res.expansion, @r###"
+fn some_thing() -> u32 {
+  let a = 0;
+  a+10
+}
+"###);
     }
 
     #[test]
     fn macro_expand_match_ast() {
-        check(
+        let res = check_expand_macro(
             r#"
-macro_rules! match_ast {
-    (match $node:ident { $($tt:tt)* }) => { match_ast!(match ($node) { $($tt)* }) };
-    (match ($node:expr) {
-        $( ast::$ast:ident($it:ident) => $res:block, )*
-        _ => $catch_all:expr $(,)?
-    }) => {{
-        $( if let Some($it) = ast::$ast::cast($node.clone()) $res else )*
-        { $catch_all }
-    }};
-}
+        //- /lib.rs
+        macro_rules! match_ast {
+            (match $node:ident { $($tt:tt)* }) => { match_ast!(match ($node) { $($tt)* }) };
 
-fn main() {
-    mat<|>ch_ast! {
-        match container {
-            ast::TraitDef(it) => {},
-            ast::ImplDef(it) => {},
-            _ => { continue },
+            (match ($node:expr) {
+                $( ast::$ast:ident($it:ident) => $res:block, )*
+                _ => $catch_all:expr $(,)?
+            }) => {{
+                $( if let Some($it) = ast::$ast::cast($node.clone()) $res else )*
+                { $catch_all }
+            }};
         }
+
+        fn main() {
+            mat<|>ch_ast! {
+                match container {
+                    ast::TraitDef(it) => {},
+                    ast::ImplDef(it) => {},
+                    _ => { continue },
+                }
+            }
+        }
+        "#,
+        );
+
+        assert_eq!(res.name, "match_ast");
+        assert_snapshot!(res.expansion, @r###"
+{
+  if let Some(it) = ast::TraitDef::cast(container.clone()){}
+  else if let Some(it) = ast::ImplDef::cast(container.clone()){}
+  else {
+    {
+      continue
     }
+  }
 }
-"#,
-            expect![[r#"
-       match_ast
-       {
-         if let Some(it) = ast::TraitDef::cast(container.clone()){}
-         else if let Some(it) = ast::ImplDef::cast(container.clone()){}
-         else {
-           {
-             continue
-           }
-         }
-       }"#]],
-        );
+"###);
     }
 
     #[test]
     fn macro_expand_match_ast_inside_let_statement() {
-        check(
+        let res = check_expand_macro(
             r#"
-macro_rules! match_ast {
-    (match $node:ident { $($tt:tt)* }) => { match_ast!(match ($node) { $($tt)* }) };
-    (match ($node:expr) {}) => {{}};
-}
+        //- /lib.rs
+        macro_rules! match_ast {
+            (match $node:ident { $($tt:tt)* }) => { match_ast!(match ($node) { $($tt)* }) };
+            (match ($node:expr) {}) => {{}};
+        }
 
-fn main() {
-    let p = f(|it| {
-        let res = mat<|>ch_ast! { match c {}};
-        Some(res)
-    })?;
-}
-"#,
-            expect![[r#"
-                match_ast
-                {}
-            "#]],
+        fn main() {
+            let p = f(|it| {
+                let res = mat<|>ch_ast! { match c {}};
+                Some(res)
+            })?;
+        }
+        "#,
         );
+
+        assert_eq!(res.name, "match_ast");
+        assert_snapshot!(res.expansion, @r###"{}"###);
     }
 
     #[test]
     fn macro_expand_inner_macro_fail_to_expand() {
-        check(
+        let res = check_expand_macro(
             r#"
-macro_rules! bar {
-    (BAD) => {};
-}
-macro_rules! foo {
-    () => {bar!()};
-}
+        //- /lib.rs
+        macro_rules! bar {
+            (BAD) => {};
+        }
+        macro_rules! foo {
+            () => {bar!()};
+        }
 
-fn main() {
-    let res = fo<|>o!();
-}
-"#,
-            expect![[r#"
-                foo
-            "#]],
+        fn main() {
+            let res = fo<|>o!();
+        }
+        "#,
         );
+
+        assert_eq!(res.name, "foo");
+        assert_snapshot!(res.expansion, @r###""###);
     }
 
     #[test]
     fn macro_expand_with_dollar_crate() {
-        check(
+        let res = check_expand_macro(
             r#"
-#[macro_export]
-macro_rules! bar {
-    () => {0};
-}
-macro_rules! foo {
-    () => {$crate::bar!()};
-}
+        //- /lib.rs
+        #[macro_export]
+        macro_rules! bar {
+            () => {0};
+        }
+        macro_rules! foo {
+            () => {$crate::bar!()};
+        }
 
-fn main() {
-    let res = fo<|>o!();
-}
-"#,
-            expect![[r#"
-                foo
-                0 "#]],
+        fn main() {
+            let res = fo<|>o!();
+        }
+        "#,
         );
+
+        assert_eq!(res.name, "foo");
+        assert_snapshot!(res.expansion, @r###"0"###);
     }
 }
diff --git a/crates/ra_ide/src/folding_ranges.rs b/crates/ra_ide/src/folding_ranges.rs
index 5cec689f8b..8657377ded 100644
--- a/crates/ra_ide/src/folding_ranges.rs
+++ b/crates/ra_ide/src/folding_ranges.rs
@@ -15,7 +15,6 @@ pub enum FoldKind {
     Imports,
     Mods,
     Block,
-    ArgList,
 }
 
 #[derive(Debug)]
@@ -84,7 +83,6 @@ fn fold_kind(kind: SyntaxKind) -> Option<FoldKind> {
     match kind {
         COMMENT => Some(FoldKind::Comment),
         USE_ITEM => Some(FoldKind::Imports),
-        ARG_LIST => Some(FoldKind::ArgList),
         RECORD_FIELD_DEF_LIST
         | RECORD_FIELD_PAT_LIST
         | ITEM_LIST
@@ -198,85 +196,89 @@ fn contiguous_range_for_comment(
 
 #[cfg(test)]
 mod tests {
-    use test_utils::extract_tags;
-
     use super::*;
+    use test_utils::extract_ranges;
 
-    fn check(ra_fixture: &str) {
-        let (ranges, text) = extract_tags(ra_fixture, "fold");
-
+    fn do_check(text: &str, fold_kinds: &[FoldKind]) {
+        let (ranges, text) = extract_ranges(text, "fold");
         let parse = SourceFile::parse(&text);
         let folds = folding_ranges(&parse.tree());
+
         assert_eq!(
             folds.len(),
             ranges.len(),
             "The amount of folds is different than the expected amount"
         );
-
-        for (fold, (range, attr)) in folds.iter().zip(ranges.into_iter()) {
+        assert_eq!(
+            folds.len(),
+            fold_kinds.len(),
+            "The amount of fold kinds is different than the expected amount"
+        );
+        for ((fold, range), fold_kind) in
+            folds.iter().zip(ranges.into_iter()).zip(fold_kinds.iter())
+        {
             assert_eq!(fold.range.start(), range.start());
             assert_eq!(fold.range.end(), range.end());
-
-            let kind = match fold.kind {
-                FoldKind::Comment => "comment",
-                FoldKind::Imports => "imports",
-                FoldKind::Mods => "mods",
-                FoldKind::Block => "block",
-                FoldKind::ArgList => "arglist",
-            };
-            assert_eq!(kind, &attr.unwrap());
+            assert_eq!(&fold.kind, fold_kind);
         }
     }
 
     #[test]
     fn test_fold_comments() {
-        check(
-            r#"
-<fold comment>// Hello
+        let text = r#"
+<fold>// Hello
 // this is a multiline
 // comment
 //</fold>
 
 // But this is not
 
-fn main() <fold block>{
-    <fold comment>// We should
+fn main() <fold>{
+    <fold>// We should
     // also
     // fold
     // this one.</fold>
-    <fold comment>//! But this one is different
+    <fold>//! But this one is different
     //! because it has another flavor</fold>
-    <fold comment>/* As does this
+    <fold>/* As does this
     multiline comment */</fold>
-}</fold>"#,
-        );
+}</fold>"#;
+
+        let fold_kinds = &[
+            FoldKind::Comment,
+            FoldKind::Block,
+            FoldKind::Comment,
+            FoldKind::Comment,
+            FoldKind::Comment,
+        ];
+        do_check(text, fold_kinds);
     }
 
     #[test]
     fn test_fold_imports() {
-        check(
-            r#"
-<fold imports>use std::<fold block>{
+        let text = r#"
+<fold>use std::<fold>{
     str,
     vec,
     io as iop
 }</fold>;</fold>
 
-fn main() <fold block>{
-}</fold>"#,
-        );
+fn main() <fold>{
+}</fold>"#;
+
+        let folds = &[FoldKind::Imports, FoldKind::Block, FoldKind::Block];
+        do_check(text, folds);
     }
 
     #[test]
     fn test_fold_mods() {
-        check(
-            r#"
+        let text = r#"
 
 pub mod foo;
-<fold mods>mod after_pub;
+<fold>mod after_pub;
 mod after_pub_next;</fold>
 
-<fold mods>mod before_pub;
+<fold>mod before_pub;
 mod before_pub_next;</fold>
 pub mod bar;
 
@@ -284,93 +286,90 @@ mod not_folding_single;
 pub mod foobar;
 pub not_folding_single_next;
 
-<fold mods>#[cfg(test)]
+<fold>#[cfg(test)]
 mod with_attribute;
 mod with_attribute_next;</fold>
 
-fn main() <fold block>{
-}</fold>"#,
-        );
+fn main() <fold>{
+}</fold>"#;
+
+        let folds = &[FoldKind::Mods, FoldKind::Mods, FoldKind::Mods, FoldKind::Block];
+        do_check(text, folds);
     }
 
     #[test]
     fn test_fold_import_groups() {
-        check(
-            r#"
-<fold imports>use std::str;
+        let text = r#"
+<fold>use std::str;
 use std::vec;
 use std::io as iop;</fold>
 
-<fold imports>use std::mem;
+<fold>use std::mem;
 use std::f64;</fold>
 
 use std::collections::HashMap;
 // Some random comment
 use std::collections::VecDeque;
 
-fn main() <fold block>{
-}</fold>"#,
-        );
+fn main() <fold>{
+}</fold>"#;
+
+        let folds = &[FoldKind::Imports, FoldKind::Imports, FoldKind::Block];
+        do_check(text, folds);
     }
 
     #[test]
     fn test_fold_import_and_groups() {
-        check(
-            r#"
-<fold imports>use std::str;
+        let text = r#"
+<fold>use std::str;
 use std::vec;
 use std::io as iop;</fold>
 
-<fold imports>use std::mem;
+<fold>use std::mem;
 use std::f64;</fold>
 
-<fold imports>use std::collections::<fold block>{
+<fold>use std::collections::<fold>{
     HashMap,
     VecDeque,
 }</fold>;</fold>
 // Some random comment
 
-fn main() <fold block>{
-}</fold>"#,
-        );
+fn main() <fold>{
+}</fold>"#;
+
+        let folds = &[
+            FoldKind::Imports,
+            FoldKind::Imports,
+            FoldKind::Imports,
+            FoldKind::Block,
+            FoldKind::Block,
+        ];
+        do_check(text, folds);
     }
 
     #[test]
     fn test_folds_macros() {
-        check(
-            r#"
-macro_rules! foo <fold block>{
+        let text = r#"
+macro_rules! foo <fold>{
     ($($tt:tt)*) => { $($tt)* }
 }</fold>
-"#,
-        );
+"#;
+
+        let folds = &[FoldKind::Block];
+        do_check(text, folds);
     }
 
     #[test]
     fn test_fold_match_arms() {
-        check(
-            r#"
-fn main() <fold block>{
-    match 0 <fold block>{
+        let text = r#"
+fn main() <fold>{
+    match 0 <fold>{
         0 => 0,
         _ => 1,
     }</fold>
-}</fold>"#,
-        );
-    }
+}</fold>"#;
 
-    #[test]
-    fn fold_big_calls() {
-        check(
-            r#"
-fn main() <fold block>{
-    frobnicate<fold arglist>(
-        1,
-        2,
-        3,
-    )</fold>
-}</fold>
-        "#,
-        )
+        let folds = &[FoldKind::Block, FoldKind::Block];
+        do_check(text, folds);
     }
 }
diff --git a/crates/ra_ide/src/goto_implementation.rs b/crates/ra_ide/src/goto_implementation.rs
index 9acc960fc2..99a7022a48 100644
--- a/crates/ra_ide/src/goto_implementation.rs
+++ b/crates/ra_ide/src/goto_implementation.rs
@@ -219,10 +219,6 @@ impl T for &Foo {}
   #[derive(Copy)]
 //^^^^^^^^^^^^^^^
 struct Foo<|>;
-
-mod marker {
-    trait Copy {}
-}
 "#,
         );
     }
diff --git a/crates/ra_ide/src/goto_type_definition.rs b/crates/ra_ide/src/goto_type_definition.rs
index 7eb40d637a..91a3097fbb 100644
--- a/crates/ra_ide/src/goto_type_definition.rs
+++ b/crates/ra_ide/src/goto_type_definition.rs
@@ -55,8 +55,8 @@ fn pick_best(tokens: TokenAtOffset<SyntaxToken>) -> Option<SyntaxToken> {
 mod tests {
     use crate::mock_analysis::analysis_and_position;
 
-    fn check_goto(ra_fixture: &str, expected: &str) {
-        let (analysis, pos) = analysis_and_position(ra_fixture);
+    fn check_goto(fixture: &str, expected: &str) {
+        let (analysis, pos) = analysis_and_position(fixture);
 
         let mut navs = analysis.goto_type_definition(pos).unwrap().unwrap().info;
         assert_eq!(navs.len(), 1);
@@ -67,7 +67,7 @@ mod tests {
     #[test]
     fn goto_type_definition_works_simple() {
         check_goto(
-            r"
+            "
             //- /lib.rs
             struct Foo;
             fn foo() {
@@ -82,7 +82,7 @@ mod tests {
     #[test]
     fn goto_type_definition_works_simple_ref() {
         check_goto(
-            r"
+            "
             //- /lib.rs
             struct Foo;
             fn foo() {
@@ -97,7 +97,7 @@ mod tests {
     #[test]
     fn goto_type_definition_works_through_macro() {
         check_goto(
-            r"
+            "
             //- /lib.rs
             macro_rules! id {
                 ($($tt:tt)*) => { $($tt)* }
@@ -116,7 +116,7 @@ mod tests {
     #[test]
     fn goto_type_definition_for_param() {
         check_goto(
-            r"
+            "
             //- /lib.rs
             struct Foo;
             fn foo(<|>f: Foo) {}
@@ -128,7 +128,7 @@ mod tests {
     #[test]
     fn goto_type_definition_for_tuple_field() {
         check_goto(
-            r"
+            "
             //- /lib.rs
             struct Foo;
             struct Bar(Foo);
diff --git a/crates/ra_ide/src/hover.rs b/crates/ra_ide/src/hover.rs
index eaba2b61ed..c3e36a387a 100644
--- a/crates/ra_ide/src/hover.rs
+++ b/crates/ra_ide/src/hover.rs
@@ -417,8 +417,8 @@ mod tests {
         assert_eq!(offset, position.into());
     }
 
-    fn check_hover_result(ra_fixture: &str, expected: &[&str]) -> (String, Vec<HoverAction>) {
-        let (analysis, position) = analysis_and_position(ra_fixture);
+    fn check_hover_result(fixture: &str, expected: &[&str]) -> (String, Vec<HoverAction>) {
+        let (analysis, position) = analysis_and_position(fixture);
         let hover = analysis.hover(position).unwrap().unwrap();
         let mut results = Vec::from(hover.info.results());
         results.sort();
@@ -435,8 +435,8 @@ mod tests {
         (content[hover.range].to_string(), hover.info.actions().to_vec())
     }
 
-    fn check_hover_no_result(ra_fixture: &str) {
-        let (analysis, position) = analysis_and_position(ra_fixture);
+    fn check_hover_no_result(fixture: &str) {
+        let (analysis, position) = analysis_and_position(fixture);
         assert!(analysis.hover(position).unwrap().is_none());
     }
 
@@ -923,7 +923,7 @@ fn func(foo: i32) { if true { <|>foo; }; }
     #[test]
     fn test_hover_through_macro() {
         let (hover_on, _) = check_hover_result(
-            r"
+            "
             //- /lib.rs
             macro_rules! id {
                 ($($tt:tt)*) => { $($tt)* }
@@ -944,7 +944,7 @@ fn func(foo: i32) { if true { <|>foo; }; }
     #[test]
     fn test_hover_through_expr_in_macro() {
         let (hover_on, _) = check_hover_result(
-            r"
+            "
             //- /lib.rs
             macro_rules! id {
                 ($($tt:tt)*) => { $($tt)* }
@@ -962,7 +962,7 @@ fn func(foo: i32) { if true { <|>foo; }; }
     #[test]
     fn test_hover_through_expr_in_macro_recursive() {
         let (hover_on, _) = check_hover_result(
-            r"
+            "
             //- /lib.rs
             macro_rules! id_deep {
                 ($($tt:tt)*) => { $($tt)* }
@@ -983,7 +983,7 @@ fn func(foo: i32) { if true { <|>foo; }; }
     #[test]
     fn test_hover_through_func_in_macro_recursive() {
         let (hover_on, _) = check_hover_result(
-            r"
+            "
             //- /lib.rs
             macro_rules! id_deep {
                 ($($tt:tt)*) => { $($tt)* }
@@ -1026,7 +1026,7 @@ fn func(foo: i32) { if true { <|>foo; }; }
     #[test]
     fn test_hover_through_assert_macro() {
         let (hover_on, _) = check_hover_result(
-            r"
+            r#"
             //- /lib.rs
             #[rustc_builtin_macro]
             macro_rules! assert {}
@@ -1035,7 +1035,7 @@ fn func(foo: i32) { if true { <|>foo; }; }
             fn foo() {
                 assert!(ba<|>r());
             }
-            ",
+            "#,
             &["fn bar() -> bool"],
         );
 
@@ -1077,14 +1077,14 @@ fn func(foo: i32) { if true { <|>foo; }; }
     #[test]
     fn test_hover_function_show_qualifiers() {
         check_hover_result(
-            r"
+            "
             //- /lib.rs
             async fn foo<|>() {}
             ",
             &["async fn foo()"],
         );
         check_hover_result(
-            r"
+            "
             //- /lib.rs
             pub const unsafe fn foo<|>() {}
             ",
@@ -1102,7 +1102,7 @@ fn func(foo: i32) { if true { <|>foo; }; }
     #[test]
     fn test_hover_trait_show_qualifiers() {
         let (_, actions) = check_hover_result(
-            r"
+            "
             //- /lib.rs
             unsafe trait foo<|>() {}
             ",
@@ -1114,7 +1114,7 @@ fn func(foo: i32) { if true { <|>foo; }; }
     #[test]
     fn test_hover_mod_with_same_name_as_function() {
         check_hover_result(
-            r"
+            "
             //- /lib.rs
             use self::m<|>y::Bar;
 
@@ -1237,7 +1237,7 @@ fn func(foo: i32) { if true { <|>foo; }; }
     #[test]
     fn test_hover_trait_has_impl_action() {
         let (_, actions) = check_hover_result(
-            r"
+            "
             //- /lib.rs
             trait foo<|>() {}
             ",
@@ -1249,7 +1249,7 @@ fn func(foo: i32) { if true { <|>foo; }; }
     #[test]
     fn test_hover_struct_has_impl_action() {
         let (_, actions) = check_hover_result(
-            r"
+            "
             //- /lib.rs
             struct foo<|>() {}
             ",
@@ -1261,7 +1261,7 @@ fn func(foo: i32) { if true { <|>foo; }; }
     #[test]
     fn test_hover_union_has_impl_action() {
         let (_, actions) = check_hover_result(
-            r"
+            "
             //- /lib.rs
             union foo<|>() {}
             ",
@@ -1273,7 +1273,7 @@ fn func(foo: i32) { if true { <|>foo; }; }
     #[test]
     fn test_hover_enum_has_impl_action() {
         let (_, actions) = check_hover_result(
-            r"
+            "
             //- /lib.rs
             enum foo<|>() {
                 A,
@@ -1288,7 +1288,7 @@ fn func(foo: i32) { if true { <|>foo; }; }
     #[test]
     fn test_hover_test_has_action() {
         let (_, actions) = check_hover_result(
-            r"
+            "
             //- /lib.rs
             #[test]
             fn foo_<|>test() {}
@@ -1332,7 +1332,7 @@ fn func(foo: i32) { if true { <|>foo; }; }
     #[test]
     fn test_hover_test_mod_has_action() {
         let (_, actions) = check_hover_result(
-            r"
+            "
             //- /lib.rs
             mod tests<|> {
                 #[test]
@@ -1373,7 +1373,7 @@ fn func(foo: i32) { if true { <|>foo; }; }
     #[test]
     fn test_hover_struct_has_goto_type_action() {
         let (_, actions) = check_hover_result(
-            r"
+            "
             //- /main.rs
             struct S{ f1: u32 }
 
@@ -1416,7 +1416,7 @@ fn func(foo: i32) { if true { <|>foo; }; }
     #[test]
     fn test_hover_generic_struct_has_goto_type_actions() {
         let (_, actions) = check_hover_result(
-            r"
+            "
             //- /main.rs
             struct Arg(u32);
             struct S<T>{ f1: T }
@@ -1479,7 +1479,7 @@ fn func(foo: i32) { if true { <|>foo; }; }
     #[test]
     fn test_hover_generic_struct_has_flattened_goto_type_actions() {
         let (_, actions) = check_hover_result(
-            r"
+            "
             //- /main.rs
             struct Arg(u32);
             struct S<T>{ f1: T }
@@ -1542,7 +1542,7 @@ fn func(foo: i32) { if true { <|>foo; }; }
     #[test]
     fn test_hover_tuple_has_goto_type_actions() {
         let (_, actions) = check_hover_result(
-            r"
+            "
             //- /main.rs
             struct A(u32);
             struct B(u32);
@@ -1627,7 +1627,7 @@ fn func(foo: i32) { if true { <|>foo; }; }
     #[test]
     fn test_hover_return_impl_trait_has_goto_type_action() {
         let (_, actions) = check_hover_result(
-            r"
+            "
             //- /main.rs
             trait Foo {}
 
@@ -1672,7 +1672,7 @@ fn func(foo: i32) { if true { <|>foo; }; }
     #[test]
     fn test_hover_generic_return_impl_trait_has_goto_type_action() {
         let (_, actions) = check_hover_result(
-            r"
+            "
             //- /main.rs
             trait Foo<T> {}
             struct S;
@@ -1737,7 +1737,7 @@ fn func(foo: i32) { if true { <|>foo; }; }
     #[test]
     fn test_hover_return_impl_traits_has_goto_type_action() {
         let (_, actions) = check_hover_result(
-            r"
+            "
             //- /main.rs
             trait Foo {}
             trait Bar {}
@@ -1802,7 +1802,7 @@ fn func(foo: i32) { if true { <|>foo; }; }
     #[test]
     fn test_hover_generic_return_impl_traits_has_goto_type_action() {
         let (_, actions) = check_hover_result(
-            r"
+            "
             //- /main.rs
             trait Foo<T> {}
             trait Bar<T> {}
@@ -1907,7 +1907,7 @@ fn func(foo: i32) { if true { <|>foo; }; }
     #[test]
     fn test_hover_arg_impl_trait_has_goto_type_action() {
         let (_, actions) = check_hover_result(
-            r"
+            "
             //- /lib.rs
             trait Foo {}
             fn foo(ar<|>g: &impl Foo) {}
@@ -1947,7 +1947,7 @@ fn func(foo: i32) { if true { <|>foo; }; }
     #[test]
     fn test_hover_arg_impl_traits_has_goto_type_action() {
         let (_, actions) = check_hover_result(
-            r"
+            "
             //- /lib.rs
             trait Foo {}
             trait Bar<T> {}
@@ -2028,7 +2028,7 @@ fn func(foo: i32) { if true { <|>foo; }; }
     #[test]
     fn test_hover_arg_generic_impl_trait_has_goto_type_action() {
         let (_, actions) = check_hover_result(
-            r"
+            "
             //- /lib.rs
             trait Foo<T> {}
             struct S {}
@@ -2088,7 +2088,7 @@ fn func(foo: i32) { if true { <|>foo; }; }
     #[test]
     fn test_hover_dyn_return_has_goto_type_action() {
         let (_, actions) = check_hover_result(
-            r"
+            "
             //- /main.rs
             trait Foo {}
             struct S;
@@ -2156,7 +2156,7 @@ fn func(foo: i32) { if true { <|>foo; }; }
     #[test]
     fn test_hover_dyn_arg_has_goto_type_action() {
         let (_, actions) = check_hover_result(
-            r"
+            "
             //- /lib.rs
             trait Foo {}
             fn foo(ar<|>g: &dyn Foo) {}
@@ -2196,7 +2196,7 @@ fn func(foo: i32) { if true { <|>foo; }; }
     #[test]
     fn test_hover_generic_dyn_arg_has_goto_type_action() {
         let (_, actions) = check_hover_result(
-            r"
+            "
             //- /lib.rs
             trait Foo<T> {}
             struct S {}
@@ -2256,7 +2256,7 @@ fn func(foo: i32) { if true { <|>foo; }; }
     #[test]
     fn test_hover_goto_type_action_links_order() {
         let (_, actions) = check_hover_result(
-            r"
+            "
             //- /lib.rs
             trait ImplTrait<T> {}
             trait DynTrait<T> {}
@@ -2357,7 +2357,7 @@ fn func(foo: i32) { if true { <|>foo; }; }
     #[test]
     fn test_hover_associated_type_has_goto_type_action() {
         let (_, actions) = check_hover_result(
-            r"
+            "
             //- /main.rs
             trait Foo {
                 type Item;
diff --git a/crates/ra_ide/src/lib.rs b/crates/ra_ide/src/lib.rs
index 8660278f15..ecac5134e6 100644
--- a/crates/ra_ide/src/lib.rs
+++ b/crates/ra_ide/src/lib.rs
@@ -75,7 +75,7 @@ pub use crate::{
     },
 };
 
-pub use hir::{Documentation, Semantics};
+pub use hir::Documentation;
 pub use ra_assists::{Assist, AssistConfig, AssistId, ResolvedAssist};
 pub use ra_db::{
     Canceled, CrateGraph, CrateId, Edition, FileId, FilePosition, FileRange, SourceRoot,
@@ -385,9 +385,7 @@ impl Analysis {
         position: FilePosition,
         search_scope: Option<SearchScope>,
     ) -> Cancelable<Option<ReferenceSearchResult>> {
-        self.with_db(|db| {
-            references::find_all_refs(&Semantics::new(db), position, search_scope).map(|it| it.info)
-        })
+        self.with_db(|db| references::find_all_refs(db, position, search_scope).map(|it| it.info))
     }
 
     /// Returns a short text describing element at position.
diff --git a/crates/ra_ide/src/references.rs b/crates/ra_ide/src/references.rs
index c2b0d5efea..3433fdae39 100644
--- a/crates/ra_ide/src/references.rs
+++ b/crates/ra_ide/src/references.rs
@@ -86,11 +86,12 @@ impl IntoIterator for ReferenceSearchResult {
 }
 
 pub(crate) fn find_all_refs(
-    sema: &Semantics<RootDatabase>,
+    db: &RootDatabase,
     position: FilePosition,
     search_scope: Option<SearchScope>,
 ) -> Option<RangeInfo<ReferenceSearchResult>> {
     let _p = profile("find_all_refs");
+    let sema = Semantics::new(db);
     let syntax = sema.parse(position.file_id).syntax().clone();
 
     let (opt_name, search_kind) = if let Some(name) =
@@ -107,15 +108,15 @@ pub(crate) fn find_all_refs(
     let RangeInfo { range, info: def } = find_name(&sema, &syntax, position, opt_name)?;
 
     let references = def
-        .find_usages(sema, search_scope)
+        .find_usages(db, search_scope)
         .into_iter()
         .filter(|r| search_kind == ReferenceKind::Other || search_kind == r.kind)
         .collect();
 
-    let decl_range = def.try_to_nav(sema.db)?.range();
+    let decl_range = def.try_to_nav(db)?.range();
 
     let declaration = Declaration {
-        nav: def.try_to_nav(sema.db)?,
+        nav: def.try_to_nav(db)?,
         kind: ReferenceKind::Other,
         access: decl_access(&def, &syntax, decl_range),
     };
diff --git a/crates/ra_ide/src/references/rename.rs b/crates/ra_ide/src/references/rename.rs
index b6a2266b4b..7ebc0adcf9 100644
--- a/crates/ra_ide/src/references/rename.rs
+++ b/crates/ra_ide/src/references/rename.rs
@@ -24,24 +24,23 @@ pub(crate) fn rename(
     position: FilePosition,
     new_name: &str,
 ) -> Option<RangeInfo<SourceChange>> {
-    let sema = Semantics::new(db);
-
     match lex_single_valid_syntax_kind(new_name)? {
         SyntaxKind::IDENT | SyntaxKind::UNDERSCORE => (),
-        SyntaxKind::SELF_KW => return rename_to_self(&sema, position),
+        SyntaxKind::SELF_KW => return rename_to_self(db, position),
         _ => return None,
     }
 
+    let sema = Semantics::new(db);
     let source_file = sema.parse(position.file_id);
     let syntax = source_file.syntax();
     if let Some(module) = find_module_at_offset(&sema, position, syntax) {
-        rename_mod(&sema, position, module, new_name)
+        rename_mod(db, position, module, new_name)
     } else if let Some(self_token) =
         syntax.token_at_offset(position.offset).find(|t| t.kind() == SyntaxKind::SELF_KW)
     {
-        rename_self_to_param(&sema, position, self_token, new_name)
+        rename_self_to_param(db, position, self_token, new_name)
     } else {
-        rename_reference(&sema, position, new_name)
+        rename_reference(sema.db, position, new_name)
     }
 }
 
@@ -98,7 +97,7 @@ fn source_edit_from_reference(reference: Reference, new_name: &str) -> SourceFil
 }
 
 fn rename_mod(
-    sema: &Semantics<RootDatabase>,
+    db: &RootDatabase,
     position: FilePosition,
     module: Module,
     new_name: &str,
@@ -106,12 +105,12 @@ fn rename_mod(
     let mut source_file_edits = Vec::new();
     let mut file_system_edits = Vec::new();
 
-    let src = module.definition_source(sema.db);
-    let file_id = src.file_id.original_file(sema.db);
+    let src = module.definition_source(db);
+    let file_id = src.file_id.original_file(db);
     match src.value {
         ModuleSource::SourceFile(..) => {
             // mod is defined in path/to/dir/mod.rs
-            let dst = if module.is_mod_rs(sema.db) {
+            let dst = if module.is_mod_rs(db) {
                 format!("../{}/mod.rs", new_name)
             } else {
                 format!("{}.rs", new_name)
@@ -123,17 +122,17 @@ fn rename_mod(
         ModuleSource::Module(..) => {}
     }
 
-    if let Some(src) = module.declaration_source(sema.db) {
-        let file_id = src.file_id.original_file(sema.db);
+    if let Some(src) = module.declaration_source(db) {
+        let file_id = src.file_id.original_file(db);
         let name = src.value.name()?;
         let edit = SourceFileEdit {
-            file_id,
+            file_id: file_id,
             edit: TextEdit::replace(name.syntax().text_range(), new_name.into()),
         };
         source_file_edits.push(edit);
     }
 
-    let RangeInfo { range, info: refs } = find_all_refs(sema, position, None)?;
+    let RangeInfo { range, info: refs } = find_all_refs(db, position, None)?;
     let ref_edits = refs
         .references
         .into_iter()
@@ -143,10 +142,8 @@ fn rename_mod(
     Some(RangeInfo::new(range, SourceChange::from_edits(source_file_edits, file_system_edits)))
 }
 
-fn rename_to_self(
-    sema: &Semantics<RootDatabase>,
-    position: FilePosition,
-) -> Option<RangeInfo<SourceChange>> {
+fn rename_to_self(db: &RootDatabase, position: FilePosition) -> Option<RangeInfo<SourceChange>> {
+    let sema = Semantics::new(db);
     let source_file = sema.parse(position.file_id);
     let syn = source_file.syntax();
 
@@ -161,7 +158,7 @@ fn rename_to_self(
         _ => return None, // not renaming other types
     };
 
-    let RangeInfo { range, info: refs } = find_all_refs(sema, position, None)?;
+    let RangeInfo { range, info: refs } = find_all_refs(db, position, None)?;
 
     let param_range = first_param.syntax().text_range();
     let (param_ref, usages): (Vec<Reference>, Vec<Reference>) = refs
@@ -213,15 +210,16 @@ fn text_edit_from_self_param(
 }
 
 fn rename_self_to_param(
-    sema: &Semantics<RootDatabase>,
+    db: &RootDatabase,
     position: FilePosition,
     self_token: SyntaxToken,
     new_name: &str,
 ) -> Option<RangeInfo<SourceChange>> {
+    let sema = Semantics::new(db);
     let source_file = sema.parse(position.file_id);
     let syn = source_file.syntax();
 
-    let text = sema.db.file_text(position.file_id);
+    let text = db.file_text(position.file_id);
     let fn_def = find_node_at_offset::<ast::FnDef>(syn, position.offset)?;
     let search_range = fn_def.syntax().text_range();
 
@@ -251,11 +249,11 @@ fn rename_self_to_param(
 }
 
 fn rename_reference(
-    sema: &Semantics<RootDatabase>,
+    db: &RootDatabase,
     position: FilePosition,
     new_name: &str,
 ) -> Option<RangeInfo<SourceChange>> {
-    let RangeInfo { range, info: refs } = find_all_refs(sema, position, None)?;
+    let RangeInfo { range, info: refs } = find_all_refs(db, position, None)?;
 
     let edit = refs
         .into_iter()
diff --git a/crates/ra_ide/src/ssr.rs b/crates/ra_ide/src/ssr.rs
index b3e9e5dfe1..9f8e540c02 100644
--- a/crates/ra_ide/src/ssr.rs
+++ b/crates/ra_ide/src/ssr.rs
@@ -10,18 +10,6 @@ use ra_ssr::{MatchFinder, SsrError, SsrRule};
 // The syntax for a structural search replace command is `<search_pattern> ==>> <replace_pattern>`.
 // A `$<name>` placeholder in the search pattern will match any AST node and `$<name>` will reference it in the replacement.
 // Within a macro call, a placeholder will match up until whatever token follows the placeholder.
-//
-// Placeholders may be given constraints by writing them as `${<name>:<constraint1>:<constraint2>...}`.
-//
-// Supported constraints:
-//
-// |===
-// | Constraint    | Restricts placeholder
-//
-// | kind(literal) | Is a literal (e.g. `42` or `"forty two"`)
-// | not(a)        | Negates the constraint `a`
-// |===
-//
 // Available via the command `rust-analyzer.ssr`.
 //
 // ```rust
diff --git a/crates/ra_ide_db/src/change.rs b/crates/ra_ide_db/src/change.rs
index dbe6eacc59..b507000f22 100644
--- a/crates/ra_ide_db/src/change.rs
+++ b/crates/ra_ide_db/src/change.rs
@@ -243,9 +243,8 @@ impl RootDatabase {
             hir::db::GenericPredicatesForParamQuery
             hir::db::GenericPredicatesQuery
             hir::db::GenericDefaultsQuery
-            hir::db::InherentImplsInCrateQuery
-            hir::db::TraitImplsInCrateQuery
-            hir::db::TraitImplsInDepsQuery
+            hir::db::ImplsInCrateQuery
+            hir::db::ImplsFromDepsQuery
             hir::db::InternTypeCtorQuery
             hir::db::InternTypeParamIdQuery
             hir::db::InternChalkImplQuery
diff --git a/crates/ra_ide_db/src/search.rs b/crates/ra_ide_db/src/search.rs
index 81553150b5..44d5c35e68 100644
--- a/crates/ra_ide_db/src/search.rs
+++ b/crates/ra_ide_db/src/search.rs
@@ -180,20 +180,20 @@ impl Definition {
 
     pub fn find_usages(
         &self,
-        sema: &Semantics<RootDatabase>,
+        db: &RootDatabase,
         search_scope: Option<SearchScope>,
     ) -> Vec<Reference> {
         let _p = profile("Definition::find_usages");
 
         let search_scope = {
-            let base = self.search_scope(sema.db);
+            let base = self.search_scope(db);
             match search_scope {
                 None => base,
                 Some(scope) => base.intersection(&scope),
             }
         };
 
-        let name = match self.name(sema.db) {
+        let name = match self.name(db) {
             None => return Vec::new(),
             Some(it) => it.to_string(),
         };
@@ -202,10 +202,11 @@ impl Definition {
         let mut refs = vec![];
 
         for (file_id, search_range) in search_scope {
-            let text = sema.db.file_text(file_id);
+            let text = db.file_text(file_id);
             let search_range =
                 search_range.unwrap_or(TextRange::up_to(TextSize::of(text.as_str())));
 
+            let sema = Semantics::new(db);
             let tree = Lazy::new(|| sema.parse(file_id).syntax().clone());
 
             for (idx, _) in text.match_indices(pat) {
@@ -221,6 +222,9 @@ impl Definition {
                         continue;
                     };
 
+                // FIXME: reuse sb
+                // See https://github.com/rust-lang/rust/pull/68198#issuecomment-574269098
+
                 match classify_name_ref(&sema, &name_ref) {
                     Some(NameRefClass::Definition(def)) if &def == self => {
                         let kind = if is_record_lit_name_ref(&name_ref)
diff --git a/crates/ra_ssr/Cargo.toml b/crates/ra_ssr/Cargo.toml
index fe098aaee3..3c2f15a833 100644
--- a/crates/ra_ssr/Cargo.toml
+++ b/crates/ra_ssr/Cargo.toml
@@ -17,4 +17,3 @@ ra_db = { path = "../ra_db" }
 ra_ide_db = { path = "../ra_ide_db" }
 hir = { path = "../ra_hir", package = "ra_hir" }
 rustc-hash = "1.1.0"
-test_utils = { path = "../test_utils" }
diff --git a/crates/ra_ssr/src/matching.rs b/crates/ra_ssr/src/matching.rs
index ce53d46d29..53d802e775 100644
--- a/crates/ra_ssr/src/matching.rs
+++ b/crates/ra_ssr/src/matching.rs
@@ -2,7 +2,7 @@
 //! process of matching, placeholder values are recorded.
 
 use crate::{
-    parsing::{Constraint, NodeKind, Placeholder, SsrTemplate},
+    parsing::{Placeholder, SsrTemplate},
     SsrMatches, SsrPattern, SsrRule,
 };
 use hir::Semantics;
@@ -11,7 +11,6 @@ use ra_syntax::ast::{AstNode, AstToken};
 use ra_syntax::{ast, SyntaxElement, SyntaxElementChildren, SyntaxKind, SyntaxNode, SyntaxToken};
 use rustc_hash::FxHashMap;
 use std::{cell::Cell, iter::Peekable};
-use test_utils::mark;
 
 // Creates a match error. If we're currently attempting to match some code that we thought we were
 // going to match, as indicated by the --debug-snippet flag, then populate the reason field.
@@ -170,9 +169,6 @@ impl<'db, 'sema> MatchState<'db, 'sema> {
         if let Some(placeholder) =
             match_inputs.get_placeholder(&SyntaxElement::Node(pattern.clone()))
         {
-            for constraint in &placeholder.constraints {
-                self.check_constraint(constraint, code)?;
-            }
             if self.match_out.is_none() {
                 return Ok(());
             }
@@ -296,24 +292,6 @@ impl<'db, 'sema> MatchState<'db, 'sema> {
         Ok(())
     }
 
-    fn check_constraint(
-        &self,
-        constraint: &Constraint,
-        code: &SyntaxNode,
-    ) -> Result<(), MatchFailed> {
-        match constraint {
-            Constraint::Kind(kind) => {
-                kind.matches(code)?;
-            }
-            Constraint::Not(sub) => {
-                if self.check_constraint(&*sub, code).is_ok() {
-                    fail_match!("Constraint {:?} failed for '{}'", constraint, code.text());
-                }
-            }
-        }
-        Ok(())
-    }
-
     /// We want to allow the records to match in any order, so we have special matching logic for
     /// them.
     fn attempt_match_record_field_list(
@@ -537,21 +515,6 @@ impl SsrPattern {
     }
 }
 
-impl NodeKind {
-    fn matches(&self, node: &SyntaxNode) -> Result<(), MatchFailed> {
-        let ok = match self {
-            Self::Literal => {
-                mark::hit!(literal_constraint);
-                ast::Literal::can_cast(node.kind())
-            }
-        };
-        if !ok {
-            fail_match!("Code '{}' isn't of kind {:?}", node.text(), self);
-        }
-        Ok(())
-    }
-}
-
 // If `node` contains nothing but an ident then return it, otherwise return None.
 fn only_ident(element: SyntaxElement) -> Option<SyntaxToken> {
     match element {
diff --git a/crates/ra_ssr/src/parsing.rs b/crates/ra_ssr/src/parsing.rs
index 5ea1256165..04d46bd326 100644
--- a/crates/ra_ssr/src/parsing.rs
+++ b/crates/ra_ssr/src/parsing.rs
@@ -6,7 +6,7 @@
 //! e.g. expressions, type references etc.
 
 use crate::{SsrError, SsrPattern, SsrRule};
-use ra_syntax::{ast, AstNode, SmolStr, SyntaxKind, T};
+use ra_syntax::{ast, AstNode, SmolStr, SyntaxKind};
 use rustc_hash::{FxHashMap, FxHashSet};
 use std::str::FromStr;
 
@@ -39,18 +39,6 @@ pub(crate) struct Placeholder {
     pub(crate) ident: SmolStr,
     /// A unique name used in place of this placeholder when we parse the pattern as Rust code.
     stand_in_name: String,
-    pub(crate) constraints: Vec<Constraint>,
-}
-
-#[derive(Clone, Debug, PartialEq, Eq)]
-pub(crate) enum Constraint {
-    Kind(NodeKind),
-    Not(Box<Constraint>),
-}
-
-#[derive(Clone, Debug, PartialEq, Eq)]
-pub(crate) enum NodeKind {
-    Literal,
 }
 
 #[derive(Debug, Clone, PartialEq, Eq)]
@@ -161,7 +149,7 @@ fn parse_pattern(pattern_str: &str) -> Result<Vec<PatternElement>, SsrError> {
     let mut placeholder_names = FxHashSet::default();
     let mut tokens = tokenize(pattern_str)?.into_iter();
     while let Some(token) = tokens.next() {
-        if token.kind == T![$] {
+        if token.kind == SyntaxKind::DOLLAR {
             let placeholder = parse_placeholder(&mut tokens)?;
             if !placeholder_names.insert(placeholder.ident.clone()) {
                 bail!("Name `{}` repeats more than once", placeholder.ident);
@@ -189,9 +177,6 @@ fn validate_rule(rule: &SsrRule) -> Result<(), SsrError> {
             if !defined_placeholders.contains(&placeholder.ident) {
                 undefined.push(format!("${}", placeholder.ident));
             }
-            if !placeholder.constraints.is_empty() {
-                bail!("Replacement placeholders cannot have constraints");
-            }
         }
     }
     if !undefined.is_empty() {
@@ -220,90 +205,23 @@ fn tokenize(source: &str) -> Result<Vec<Token>, SsrError> {
 
 fn parse_placeholder(tokens: &mut std::vec::IntoIter<Token>) -> Result<Placeholder, SsrError> {
     let mut name = None;
-    let mut constraints = Vec::new();
     if let Some(token) = tokens.next() {
         match token.kind {
             SyntaxKind::IDENT => {
                 name = Some(token.text);
             }
-            T!['{'] => {
-                let token =
-                    tokens.next().ok_or_else(|| SsrError::new("Unexpected end of placeholder"))?;
-                if token.kind == SyntaxKind::IDENT {
-                    name = Some(token.text);
-                }
-                loop {
-                    let token = tokens
-                        .next()
-                        .ok_or_else(|| SsrError::new("Placeholder is missing closing brace '}'"))?;
-                    match token.kind {
-                        T![:] => {
-                            constraints.push(parse_constraint(tokens)?);
-                        }
-                        T!['}'] => break,
-                        _ => bail!("Unexpected token while parsing placeholder: '{}'", token.text),
-                    }
-                }
-            }
             _ => {
-                bail!("Placeholders should either be $name or ${name:constraints}");
+                bail!("Placeholders should be $name");
             }
         }
     }
     let name = name.ok_or_else(|| SsrError::new("Placeholder ($) with no name"))?;
-    Ok(Placeholder::new(name, constraints))
-}
-
-fn parse_constraint(tokens: &mut std::vec::IntoIter<Token>) -> Result<Constraint, SsrError> {
-    let constraint_type = tokens
-        .next()
-        .ok_or_else(|| SsrError::new("Found end of placeholder while looking for a constraint"))?
-        .text
-        .to_string();
-    match constraint_type.as_str() {
-        "kind" => {
-            expect_token(tokens, "(")?;
-            let t = tokens.next().ok_or_else(|| {
-                SsrError::new("Unexpected end of constraint while looking for kind")
-            })?;
-            if t.kind != SyntaxKind::IDENT {
-                bail!("Expected ident, found {:?} while parsing kind constraint", t.kind);
-            }
-            expect_token(tokens, ")")?;
-            Ok(Constraint::Kind(NodeKind::from(&t.text)?))
-        }
-        "not" => {
-            expect_token(tokens, "(")?;
-            let sub = parse_constraint(tokens)?;
-            expect_token(tokens, ")")?;
-            Ok(Constraint::Not(Box::new(sub)))
-        }
-        x => bail!("Unsupported constraint type '{}'", x),
-    }
-}
-
-fn expect_token(tokens: &mut std::vec::IntoIter<Token>, expected: &str) -> Result<(), SsrError> {
-    if let Some(t) = tokens.next() {
-        if t.text == expected {
-            return Ok(());
-        }
-        bail!("Expected {} found {}", expected, t.text);
-    }
-    bail!("Expected {} found end of stream");
-}
-
-impl NodeKind {
-    fn from(name: &SmolStr) -> Result<NodeKind, SsrError> {
-        Ok(match name.as_str() {
-            "literal" => NodeKind::Literal,
-            _ => bail!("Unknown node kind '{}'", name),
-        })
-    }
+    Ok(Placeholder::new(name))
 }
 
 impl Placeholder {
-    fn new(name: SmolStr, constraints: Vec<Constraint>) -> Self {
-        Self { stand_in_name: format!("__placeholder_{}", name), constraints, ident: name }
+    fn new(name: SmolStr) -> Self {
+        Self { stand_in_name: format!("__placeholder_{}", name), ident: name }
     }
 }
 
@@ -323,31 +241,31 @@ mod tests {
             PatternElement::Token(Token { kind, text: SmolStr::new(text) })
         }
         fn placeholder(name: &str) -> PatternElement {
-            PatternElement::Placeholder(Placeholder::new(SmolStr::new(name), Vec::new()))
+            PatternElement::Placeholder(Placeholder::new(SmolStr::new(name)))
         }
         let result: SsrRule = "foo($a, $b) ==>> bar($b, $a)".parse().unwrap();
         assert_eq!(
             result.pattern.raw.tokens,
             vec![
                 token(SyntaxKind::IDENT, "foo"),
-                token(T!['('], "("),
+                token(SyntaxKind::L_PAREN, "("),
                 placeholder("a"),
-                token(T![,], ","),
+                token(SyntaxKind::COMMA, ","),
                 token(SyntaxKind::WHITESPACE, " "),
                 placeholder("b"),
-                token(T![')'], ")"),
+                token(SyntaxKind::R_PAREN, ")"),
             ]
         );
         assert_eq!(
             result.template.tokens,
             vec![
                 token(SyntaxKind::IDENT, "bar"),
-                token(T!['('], "("),
+                token(SyntaxKind::L_PAREN, "("),
                 placeholder("b"),
-                token(T![,], ","),
+                token(SyntaxKind::COMMA, ","),
                 token(SyntaxKind::WHITESPACE, " "),
                 placeholder("a"),
-                token(T![')'], ")"),
+                token(SyntaxKind::R_PAREN, ")"),
             ]
         );
     }
diff --git a/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs
index 6c311648a9..21acfe6445 100644
--- a/crates/rust-analyzer/src/config.rs
+++ b/crates/rust-analyzer/src/config.rs
@@ -130,6 +130,7 @@ pub struct ClientCapsConfig {
     pub code_action_group: bool,
     pub resolve_code_action: bool,
     pub hover_actions: bool,
+    pub status_notification: bool,
 }
 
 impl Config {
@@ -365,6 +366,7 @@ impl Config {
             self.client_caps.code_action_group = get_bool("codeActionGroup");
             self.client_caps.resolve_code_action = get_bool("resolveCodeAction");
             self.client_caps.hover_actions = get_bool("hoverActions");
+            self.client_caps.status_notification = get_bool("statusNotification");
         }
     }
 }
diff --git a/crates/rust-analyzer/src/global_state.rs b/crates/rust-analyzer/src/global_state.rs
index b7b4edf661..640b3959df 100644
--- a/crates/rust-analyzer/src/global_state.rs
+++ b/crates/rust-analyzer/src/global_state.rs
@@ -31,6 +31,8 @@ use crate::{
 pub(crate) enum Status {
     Loading,
     Ready,
+    Invalid,
+    NeedsReload,
 }
 
 impl Default for Status {
diff --git a/crates/rust-analyzer/src/lsp_ext.rs b/crates/rust-analyzer/src/lsp_ext.rs
index 82207bbb8b..d225ad5ff3 100644
--- a/crates/rust-analyzer/src/lsp_ext.rs
+++ b/crates/rust-analyzer/src/lsp_ext.rs
@@ -3,7 +3,7 @@
 use std::{collections::HashMap, path::PathBuf};
 
 use lsp_types::request::Request;
-use lsp_types::{Position, Range, TextDocumentIdentifier};
+use lsp_types::{notification::Notification, Position, Range, TextDocumentIdentifier};
 use serde::{Deserialize, Serialize};
 
 pub enum AnalyzerStatus {}
@@ -208,6 +208,22 @@ pub struct SsrParams {
     pub parse_only: bool,
 }
 
+pub enum StatusNotification {}
+
+#[serde(rename_all = "camelCase")]
+#[derive(Serialize, Deserialize)]
+pub enum Status {
+    Loading,
+    Ready,
+    NeedsReload,
+    Invalid,
+}
+
+impl Notification for StatusNotification {
+    type Params = Status;
+    const METHOD: &'static str = "rust-analyzer/status";
+}
+
 pub enum CodeActionRequest {}
 
 impl Request for CodeActionRequest {
diff --git a/crates/rust-analyzer/src/main_loop.rs b/crates/rust-analyzer/src/main_loop.rs
index e03038b258..d4d18a8082 100644
--- a/crates/rust-analyzer/src/main_loop.rs
+++ b/crates/rust-analyzer/src/main_loop.rs
@@ -111,6 +111,35 @@ impl GlobalState {
     }
 
     fn run(mut self, inbox: Receiver<lsp_server::Message>) -> Result<()> {
+        let registration_options = lsp_types::TextDocumentRegistrationOptions {
+            document_selector: Some(vec![
+                lsp_types::DocumentFilter {
+                    language: None,
+                    scheme: None,
+                    pattern: Some("**/*.rs".into()),
+                },
+                lsp_types::DocumentFilter {
+                    language: None,
+                    scheme: None,
+                    pattern: Some("**/Cargo.toml".into()),
+                },
+                lsp_types::DocumentFilter {
+                    language: None,
+                    scheme: None,
+                    pattern: Some("**/Cargo.lock".into()),
+                },
+            ]),
+        };
+        let registration = lsp_types::Registration {
+            id: "textDocument/didSave".to_string(),
+            method: "textDocument/didSave".to_string(),
+            register_options: Some(serde_json::to_value(registration_options).unwrap()),
+        };
+        self.send_request::<lsp_types::request::RegisterCapability>(
+            lsp_types::RegistrationParams { registrations: vec![registration] },
+            |_, _| (),
+        );
+
         self.reload();
 
         while let Some(event) = self.next_event(&inbox) {
@@ -169,16 +198,16 @@ impl GlobalState {
                 }
                 vfs::loader::Message::Progress { n_total, n_done } => {
                     if n_total == 0 {
-                        self.status = Status::Ready;
+                        self.transition(Status::Invalid);
                     } else {
                         let state = if n_done == 0 {
-                            self.status = Status::Loading;
+                            self.transition(Status::Loading);
                             Progress::Begin
                         } else if n_done < n_total {
                             Progress::Report
                         } else {
                             assert_eq!(n_done, n_total);
-                            self.status = Status::Ready;
+                            self.transition(Status::Ready);
                             Progress::End
                         };
                         self.report_progress(
@@ -274,6 +303,19 @@ impl GlobalState {
         Ok(())
     }
 
+    fn transition(&mut self, new_status: Status) {
+        self.status = Status::Ready;
+        if self.config.client_caps.status_notification {
+            let lsp_status = match new_status {
+                Status::Loading => lsp_ext::Status::Loading,
+                Status::Ready => lsp_ext::Status::Ready,
+                Status::Invalid => lsp_ext::Status::Invalid,
+                Status::NeedsReload => lsp_ext::Status::NeedsReload,
+            };
+            self.send_notification::<lsp_ext::StatusNotification>(lsp_status);
+        }
+    }
+
     fn on_request(&mut self, request_received: Instant, req: Request) -> Result<()> {
         self.register_request(&req, request_received);
 
@@ -383,10 +425,16 @@ impl GlobalState {
                 );
                 Ok(())
             })?
-            .on::<lsp_types::notification::DidSaveTextDocument>(|this, _params| {
+            .on::<lsp_types::notification::DidSaveTextDocument>(|this, params| {
                 if let Some(flycheck) = &this.flycheck {
                     flycheck.handle.update();
                 }
+                let uri = params.text_document.uri.as_str();
+                if uri.ends_with("Cargo.toml") || uri.ends_with("Cargo.lock") {
+                    if matches!(this.status, Status::Ready | Status::Invalid) {
+                        this.transition(Status::NeedsReload);
+                    }
+                }
                 Ok(())
             })?
             .on::<lsp_types::notification::DidChangeConfiguration>(|this, _params| {
diff --git a/crates/rust-analyzer/src/reload.rs b/crates/rust-analyzer/src/reload.rs
index 0c1fd1b8b5..523b04b97a 100644
--- a/crates/rust-analyzer/src/reload.rs
+++ b/crates/rust-analyzer/src/reload.rs
@@ -78,7 +78,7 @@ impl GlobalState {
                     .collect(),
             };
             let registration = lsp_types::Registration {
-                id: "file-watcher".to_string(),
+                id: "workspace/didChangeWatchedFiles".to_string(),
                 method: "workspace/didChangeWatchedFiles".to_string(),
                 register_options: Some(serde_json::to_value(registration_options).unwrap()),
             };
diff --git a/crates/rust-analyzer/src/to_proto.rs b/crates/rust-analyzer/src/to_proto.rs
index 95dd8e408d..a0a58f689d 100644
--- a/crates/rust-analyzer/src/to_proto.rs
+++ b/crates/rust-analyzer/src/to_proto.rs
@@ -352,7 +352,7 @@ pub(crate) fn folding_range(
     let kind = match fold.kind {
         FoldKind::Comment => Some(lsp_types::FoldingRangeKind::Comment),
         FoldKind::Imports => Some(lsp_types::FoldingRangeKind::Imports),
-        FoldKind::Mods | FoldKind::Block | FoldKind::ArgList => None,
+        FoldKind::Mods | FoldKind::Block => None,
     };
 
     let range = range(line_index, fold.range);
@@ -685,27 +685,32 @@ pub(crate) fn runnable(
 
 #[cfg(test)]
 mod tests {
-    use ra_ide::Analysis;
+    use test_utils::extract_ranges;
 
     use super::*;
 
     #[test]
     fn conv_fold_line_folding_only_fixup() {
-        let text = r#"mod a;
+        let text = r#"<fold>mod a;
 mod b;
-mod c;
+mod c;</fold>
 
-fn main() {
-    if cond {
+fn main() <fold>{
+    if cond <fold>{
         a::do_a();
-    } else {
+    }</fold> else <fold>{
         b::do_b();
-    }
-}"#;
-
-        let (analysis, file_id) = Analysis::from_single_file(text.to_string());
-        let folds = analysis.folding_ranges(file_id).unwrap();
-        assert_eq!(folds.len(), 4);
+    }</fold>
+}</fold>"#;
+
+        let (ranges, text) = extract_ranges(text, "fold");
+        assert_eq!(ranges.len(), 4);
+        let folds = vec![
+            Fold { range: ranges[0], kind: FoldKind::Mods },
+            Fold { range: ranges[1], kind: FoldKind::Block },
+            Fold { range: ranges[2], kind: FoldKind::Block },
+            Fold { range: ranges[3], kind: FoldKind::Block },
+        ];
 
         let line_index = LineIndex::new(&text);
         let converted: Vec<lsp_types::FoldingRange> =
diff --git a/docs/dev/lsp-extensions.md b/docs/dev/lsp-extensions.md
index c0afb16d3b..6d6bbac7ca 100644
--- a/docs/dev/lsp-extensions.md
+++ b/docs/dev/lsp-extensions.md
@@ -399,6 +399,18 @@ Returns internal status message, mostly for debugging purposes.
 
 Reloads project information (that is, re-executes `cargo metadata`).
 
+## Status Notification
+
+**Client Capability:** `{ "statusNotification": boolean }`
+
+**Method:** `rust-analyzer/status`
+
+**Notification:** `"loading" | "ready" | "invalid" | "needsReload"`
+
+This notification is sent from server to client.
+The client can use it to display persistent status to the user (in modline).
+For `needsReload` state, the client can provide a context-menu action to run `rust-analyzer/reloadWorkspace` request.
+
 ## Syntax Tree
 
 **Method:** `rust-analyzer/syntaxTree`
diff --git a/editors/code/src/client.ts b/editors/code/src/client.ts
index 65ad573d8c..3e5915c28d 100644
--- a/editors/code/src/client.ts
+++ b/editors/code/src/client.ts
@@ -161,6 +161,7 @@ class ExperimentalFeatures implements lc.StaticFeature {
         caps.codeActionGroup = true;
         caps.resolveCodeAction = true;
         caps.hoverActions = true;
+        caps.statusNotification = true;
         capabilities.experimental = caps;
     }
     initialize(_capabilities: lc.ServerCapabilities<any>, _documentSelector: lc.DocumentSelector | undefined): void {
diff --git a/editors/code/src/ctx.ts b/editors/code/src/ctx.ts
index 41df119910..6e767babf4 100644
--- a/editors/code/src/ctx.ts
+++ b/editors/code/src/ctx.ts
@@ -1,9 +1,11 @@
 import * as vscode from 'vscode';
 import * as lc from 'vscode-languageclient';
+import * as ra from './lsp_ext';
 
 import { Config } from './config';
 import { createClient } from './client';
 import { isRustEditor, RustEditor } from './util';
+import { Status } from './lsp_ext';
 
 export class Ctx {
     private constructor(
@@ -11,6 +13,7 @@ export class Ctx {
         private readonly extCtx: vscode.ExtensionContext,
         readonly client: lc.LanguageClient,
         readonly serverPath: string,
+        readonly statusBar: vscode.StatusBarItem,
     ) {
 
     }
@@ -22,9 +25,18 @@ export class Ctx {
         cwd: string,
     ): Promise<Ctx> {
         const client = createClient(serverPath, cwd);
-        const res = new Ctx(config, extCtx, client, serverPath);
+
+        const statusBar = vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Left);
+        extCtx.subscriptions.push(statusBar);
+        statusBar.text = "rust-analyzer";
+        statusBar.tooltip = "ready";
+        statusBar.show();
+
+        const res = new Ctx(config, extCtx, client, serverPath, statusBar);
+
         res.pushCleanup(client.start());
         await client.onReady();
+        client.onNotification(ra.status, (status) => res.setStatus(status));
         return res;
     }
 
@@ -54,6 +66,35 @@ export class Ctx {
         return this.extCtx.subscriptions;
     }
 
+    setStatus(status: Status) {
+        switch (status) {
+            case "loading":
+                this.statusBar.text = "$(sync~spin) rust-analyzer";
+                this.statusBar.tooltip = "Loading the project";
+                this.statusBar.command = undefined;
+                this.statusBar.color = undefined;
+                break;
+            case "ready":
+                this.statusBar.text = "rust-analyzer";
+                this.statusBar.tooltip = "Ready";
+                this.statusBar.command = undefined;
+                this.statusBar.color = undefined;
+                break;
+            case "invalid":
+                this.statusBar.text = "$(error) rust-analyzer";
+                this.statusBar.tooltip = "Failed to load the project";
+                this.statusBar.command = undefined;
+                this.statusBar.color = new vscode.ThemeColor("notificationsErrorIcon.foreground");
+                break;
+            case "needsReload":
+                this.statusBar.text = "$(warning) rust-analyzer";
+                this.statusBar.tooltip = "Click to reload";
+                this.statusBar.command = "rust-analyzer.reloadWorkspace";
+                this.statusBar.color = new vscode.ThemeColor("notificationsWarningIcon.foreground");
+                break;
+        }
+    }
+
     pushCleanup(d: Disposable) {
         this.extCtx.subscriptions.push(d);
     }
diff --git a/editors/code/src/lsp_ext.ts b/editors/code/src/lsp_ext.ts
index 981b6f40ec..bf4703239d 100644
--- a/editors/code/src/lsp_ext.ts
+++ b/editors/code/src/lsp_ext.ts
@@ -6,6 +6,9 @@ import * as lc from "vscode-languageclient";
 
 export const analyzerStatus = new lc.RequestType<null, string, void>("rust-analyzer/analyzerStatus");
 
+export type Status = "loading" | "ready" | "invalid" | "needsReload";
+export const status = new lc.NotificationType<Status>("rust-analyzer/status");
+
 export const reloadWorkspace = new lc.RequestType<null, null, void>("rust-analyzer/reloadWorkspace");
 
 export interface SyntaxTreeParams {
diff --git a/editors/code/src/main.ts b/editors/code/src/main.ts
index a1521a93be..2982b9cbf6 100644
--- a/editors/code/src/main.ts
+++ b/editors/code/src/main.ts
@@ -19,16 +19,6 @@ let ctx: Ctx | undefined;
 const RUST_PROJECT_CONTEXT_NAME = "inRustProject";
 
 export async function activate(context: vscode.ExtensionContext) {
-    // For some reason vscode not always shows pop-up error notifications
-    // when an extension fails to activate, so we do it explicitly by ourselves.
-    // FIXME: remove this bit of code once vscode fixes this issue: https://github.com/microsoft/vscode/issues/101242
-    await tryActivate(context).catch(err => {
-        void vscode.window.showErrorMessage(`Cannot activate rust-analyzer: ${err.message}`);
-        throw err;
-    });
-}
-
-async function tryActivate(context: vscode.ExtensionContext) {
     // Register a "dumb" onEnter command for the case where server fails to
     // start.
     //
@@ -68,7 +58,9 @@ async function tryActivate(context: vscode.ExtensionContext) {
 
     const workspaceFolder = vscode.workspace.workspaceFolders?.[0];
     if (workspaceFolder === undefined) {
-        throw new Error("no folder is opened");
+        const err = "Cannot activate rust-analyzer when no folder is opened";
+        void vscode.window.showErrorMessage(err);
+        throw new Error(err);
     }
 
     // Note: we try to start the server before we activate type hints so that it
@@ -160,17 +152,13 @@ async function bootstrapExtension(config: Config, state: PersistentState): Promi
         return;
     };
 
+    const lastCheck = state.lastCheck;
     const now = Date.now();
-    if (config.package.releaseTag === NIGHTLY_TAG) {
-        // Check if we should poll github api for the new nightly version
-        // if we haven't done it during the past hour
-        const lastCheck = state.lastCheck;
 
-        const anHour = 60 * 60 * 1000;
-        const shouldCheckForNewNightly = state.releaseId === undefined || (now - (lastCheck ?? 0)) > anHour;
+    const anHour = 60 * 60 * 1000;
+    const shouldDownloadNightly = state.releaseId === undefined || (now - (lastCheck ?? 0)) > anHour;
 
-        if (!shouldCheckForNewNightly) return;
-    }
+    if (!shouldDownloadNightly) return;
 
     const release = await fetchRelease("nightly").catch((e) => {
         log.error(e);


Test patch:
diff --git a/crates/ra_hir_ty/src/tests.rs b/crates/ra_hir_ty/src/tests.rs
index eeac34d140..9084c3bed2 100644
--- a/crates/ra_hir_ty/src/tests.rs
+++ b/crates/ra_hir_ty/src/tests.rs
@@ -507,30 +507,6 @@ fn no_such_field_with_feature_flag_diagnostics_on_struct_fields() {
     assert_snapshot!(diagnostics, @r###""###);
 }
 
-#[test]
-fn no_such_field_with_type_macro() {
-    let diagnostics = TestDB::with_files(
-        r"
-        macro_rules! Type {
-            () => { u32 };
-        }
-
-        struct Foo {
-            bar: Type![],
-        }
-        impl Foo {
-            fn new() -> Self {
-                Foo { bar: 0 }
-            }
-        }
-        ",
-    )
-    .diagnostics()
-    .0;
-
-    assert_snapshot!(diagnostics, @r###""###);
-}
-
 #[test]
 fn missing_record_pat_field_diagnostic() {
     let diagnostics = TestDB::with_files(
diff --git a/crates/ra_hir_ty/src/tests/traits.rs b/crates/ra_hir_ty/src/tests/traits.rs
index 766790576d..01c919a7ec 100644
--- a/crates/ra_hir_ty/src/tests/traits.rs
+++ b/crates/ra_hir_ty/src/tests/traits.rs
@@ -3029,21 +3029,3 @@ fn infer_dyn_fn_output() {
     "###
     );
 }
-
-#[test]
-fn variable_kinds() {
-    check_types(
-        r#"
-trait Trait<T> { fn get(self, t: T) -> T; }
-struct S;
-impl Trait<u128> for S {}
-impl Trait<f32> for S {}
-fn test() {
-    S.get(1);
-  //^^^^^^^^ u128
-    S.get(1.);
-  //^^^^^^^^ f32
-}
-        "#,
-    );
-}
diff --git a/crates/ra_proc_macro_srv/src/tests/mod.rs b/crates/ra_proc_macro_srv/src/tests/mod.rs
index 8e6f28abdf..82cefbb29a 100644
--- a/crates/ra_proc_macro_srv/src/tests/mod.rs
+++ b/crates/ra_proc_macro_srv/src/tests/mod.rs
@@ -11,7 +11,7 @@ fn test_derive_serialize_proc_macro() {
         "serde_derive",
         "Serialize",
         "1.0",
-        r"struct Foo {}",
+        r##"struct Foo {}"##,
         include_str!("fixtures/test_serialize_proc_macro.txt"),
     );
 }
@@ -22,7 +22,9 @@ fn test_derive_serialize_proc_macro_failed() {
         "serde_derive",
         "Serialize",
         "1.0",
-        r"struct {}",
+        r##"
+    struct {}
+"##,
         r##"
 SUBTREE $
   IDENT   compile_error 4294967295
diff --git a/crates/ra_proc_macro_srv/src/tests/utils.rs b/crates/ra_proc_macro_srv/src/tests/utils.rs
index dcb00671ff..8d85f2d8a7 100644
--- a/crates/ra_proc_macro_srv/src/tests/utils.rs
+++ b/crates/ra_proc_macro_srv/src/tests/utils.rs
@@ -44,12 +44,12 @@ pub fn assert_expand(
     crate_name: &str,
     macro_name: &str,
     version: &str,
-    ra_fixture: &str,
+    fixture: &str,
     expect: &str,
 ) {
     let path = fixtures::dylib_path(crate_name, version);
     let expander = dylib::Expander::new(&path).unwrap();
-    let fixture = parse_string(ra_fixture).unwrap();
+    let fixture = parse_string(fixture).unwrap();
 
     let res = expander.expand(macro_name, &fixture.subtree, None).unwrap();
     assert_eq_text!(&format!("{:?}", res), &expect.trim());
diff --git a/crates/ra_ssr/src/tests.rs b/crates/ra_ssr/src/tests.rs
index 9568d44322..c692c97e2e 100644
--- a/crates/ra_ssr/src/tests.rs
+++ b/crates/ra_ssr/src/tests.rs
@@ -1,6 +1,5 @@
 use crate::{MatchFinder, SsrRule};
 use ra_db::{FileId, SourceDatabaseExt};
-use test_utils::mark;
 
 fn parse_error_text(query: &str) -> String {
     format!("{}", query.parse::<SsrRule>().unwrap_err())
@@ -302,22 +301,6 @@ fn match_pattern() {
     assert_matches("Some($a)", "fn f() {if let Some(x) = foo() {}}", &["Some(x)"]);
 }
 
-#[test]
-fn literal_constraint() {
-    mark::check!(literal_constraint);
-    let code = r#"
-        fn f1() {
-            let x1 = Some(42);
-            let x2 = Some("foo");
-            let x3 = Some(x1);
-            let x4 = Some(40 + 2);
-            let x5 = Some(true);
-        }
-        "#;
-    assert_matches("Some(${a:kind(literal)})", code, &["Some(42)", "Some(\"foo\")", "Some(true)"]);
-    assert_matches("Some(${a:not(kind(literal))})", code, &["Some(x1)", "Some(40 + 2)"]);
-}
-
 #[test]
 fn match_reordered_struct_instantiation() {
     assert_matches(
diff --git a/crates/rust-analyzer/tests/heavy_tests/support.rs b/crates/rust-analyzer/tests/heavy_tests/support.rs
index 49f194f7ef..7bf687794c 100644
--- a/crates/rust-analyzer/tests/heavy_tests/support.rs
+++ b/crates/rust-analyzer/tests/heavy_tests/support.rs
@@ -176,12 +176,19 @@ impl Server {
         while let Some(msg) = self.recv() {
             match msg {
                 Message::Request(req) => {
-                    if req.method != "window/workDoneProgress/create"
-                        && !(req.method == "client/registerCapability"
-                            && req.params.to_string().contains("workspace/didChangeWatchedFiles"))
-                    {
-                        panic!("unexpected request: {:?}", req)
+                    if req.method == "window/workDoneProgress/create" {
+                        continue;
                     }
+                    if req.method == "client/registerCapability" {
+                        let params = req.params.to_string();
+                        if ["workspace/didChangeWatchedFiles", "textDocument/didSave"]
+                            .iter()
+                            .any(|&it| params.contains(it))
+                        {
+                            continue;
+                        }
+                    }
+                    panic!("unexpected request: {:?}", req)
                 }
                 Message::Notification(_) => (),
                 Message::Response(res) => {
diff --git a/crates/test_utils/src/lib.rs b/crates/test_utils/src/lib.rs
index e4aa894ace..fba5f42810 100644
--- a/crates/test_utils/src/lib.rs
+++ b/crates/test_utils/src/lib.rs
@@ -118,8 +118,8 @@ pub fn extract_range_or_offset(text: &str) -> (RangeOrOffset, String) {
 }
 
 /// Extracts ranges, marked with `<tag> </tag>` pairs from the `text`
-pub fn extract_tags(mut text: &str, tag: &str) -> (Vec<(TextRange, Option<String>)>, String) {
-    let open = format!("<{}", tag);
+pub fn extract_ranges(mut text: &str, tag: &str) -> (Vec<TextRange>, String) {
+    let open = format!("<{}>", tag);
     let close = format!("</{}>", tag);
     let mut ranges = Vec::new();
     let mut res = String::new();
@@ -134,35 +134,22 @@ pub fn extract_tags(mut text: &str, tag: &str) -> (Vec<(TextRange, Option<String
                 res.push_str(&text[..i]);
                 text = &text[i..];
                 if text.starts_with(&open) {
-                    let close_open = text.find('>').unwrap();
-                    let attr = text[open.len()..close_open].trim();
-                    let attr = if attr.is_empty() { None } else { Some(attr.to_string()) };
-                    text = &text[close_open + '>'.len_utf8()..];
+                    text = &text[open.len()..];
                     let from = TextSize::of(&res);
-                    stack.push((from, attr));
+                    stack.push(from);
                 } else if text.starts_with(&close) {
                     text = &text[close.len()..];
-                    let (from, attr) =
-                        stack.pop().unwrap_or_else(|| panic!("unmatched </{}>", tag));
+                    let from = stack.pop().unwrap_or_else(|| panic!("unmatched </{}>", tag));
                     let to = TextSize::of(&res);
-                    ranges.push((TextRange::new(from, to), attr));
-                } else {
-                    res.push('<');
-                    text = &text['<'.len_utf8()..];
+                    ranges.push(TextRange::new(from, to));
                 }
             }
         }
     }
     assert!(stack.is_empty(), "unmatched <{}>", tag);
-    ranges.sort_by_key(|r| (r.0.start(), r.0.end()));
+    ranges.sort_by_key(|r| (r.start(), r.end()));
     (ranges, res)
 }
-#[test]
-fn test_extract_tags() {
-    let (tags, text) = extract_tags(r#"<tag fn>fn <tag>main</tag>() {}</tag>"#, "tag");
-    let actual = tags.into_iter().map(|(range, attr)| (&text[range], attr)).collect::<Vec<_>>();
-    assert_eq!(actual, vec![("fn main() {}", Some("fn".into())), ("main", None),]);
-}
 
 /// Inserts `<|>` marker into the `text` at `offset`.
 pub fn add_cursor(text: &str, offset: TextSize) -> String {