Repository: rust-analyzer/rust-analyzer
Pull request #11792 (2022-03-22 16:42:29)

minor: Bump dependencies


Patch:
diff --git a/Cargo.lock b/Cargo.lock
index 5351da334a..0aa8adbdb5 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -171,9 +171,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
 
 [[package]]
 name = "chalk-derive"
-version = "0.79.0"
+version = "0.80.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0b14364774396379d5c488e73d88e0a6d2b51acd0dac9c8359e2f84c58cf3a16"
+checksum = "d0001adf0cf12361e08b65e1898ea138f8f77d8f5177cbf29b6b3b3532252bd6"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -183,9 +183,9 @@ dependencies = [
 
 [[package]]
 name = "chalk-ir"
-version = "0.79.0"
+version = "0.80.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cd571e8931d3075f562a2d460bfe3028a9c7b343876765cce95b6143a76b882e"
+checksum = "92d8a95548f23618fda86426e4304e563ec2bb7ba0216139f0748d63c107b5f1"
 dependencies = [
  "bitflags",
  "chalk-derive",
@@ -194,9 +194,9 @@ dependencies = [
 
 [[package]]
 name = "chalk-recursive"
-version = "0.79.0"
+version = "0.80.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "54ceedab35607f4680d02de80f8be005af0ad5c1dcfec56cfd849d33da5fe736"
+checksum = "759a811f4706f02304353db1b8b525fe6ec25648e004bf7e348139c86865240f"
 dependencies = [
  "chalk-derive",
  "chalk-ir",
@@ -207,9 +207,9 @@ dependencies = [
 
 [[package]]
 name = "chalk-solve"
-version = "0.79.0"
+version = "0.80.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9e31bb853cf921365759346db05d833f969e330462432bf38c9c2be1e78a9abd"
+checksum = "f37f492dacfafe2e21319b80827da2779932909bb392f0cc86b2bd5c07c1b4e1"
 dependencies = [
  "chalk-derive",
  "chalk-ir",
@@ -249,9 +249,9 @@ dependencies = [
 
 [[package]]
 name = "crossbeam-channel"
-version = "0.5.3"
+version = "0.5.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fdbfe11fe19ff083c48923cf179540e8cd0535903dc35e178a1fdeeb59aef51f"
+checksum = "5aaa7bd5fb665c6864b5f963dd9097905c54125909c7aa94c9e18507cdbe6c53"
 dependencies = [
  "cfg-if",
  "crossbeam-utils",
@@ -821,9 +821,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
 
 [[package]]
 name = "libc"
-version = "0.2.120"
+version = "0.2.121"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ad5c14e80759d0939d013e6ca49930e59fc53dd8e5009132f76240c179380c09"
+checksum = "efaa7b300f3b5fe8eb6bf21ce3895e1751d9665086af2d64b42f19701015ff4f"
 
 [[package]]
 name = "libloading"
@@ -880,9 +880,9 @@ dependencies = [
 
 [[package]]
 name = "lsp-types"
-version = "0.92.0"
+version = "0.92.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e8a69d4142d51b208c9fc3cea68b1a7fcef30354e7aa6ccad07250fd8430fc76"
+checksum = "c79d4897790e8fd2550afa6d6125821edb5716e60e0e285046e070f0f6a06e0e"
 dependencies = [
  "bitflags",
  "serde",
@@ -1283,9 +1283,9 @@ dependencies = [
 
 [[package]]
 name = "quote"
-version = "1.0.15"
+version = "1.0.16"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "864d3e96a899863136fc6e99f3d7cae289dafe43bf2c5ac19b70df7210c0a145"
+checksum = "b4af2ec4714533fcdf07e886f17025ace8b997b9ce51204ee69b6da831c3da57"
 dependencies = [
  "proc-macro2",
 ]
diff --git a/crates/cfg/Cargo.toml b/crates/cfg/Cargo.toml
index 8f9437d8e7..5c510db83b 100644
--- a/crates/cfg/Cargo.toml
+++ b/crates/cfg/Cargo.toml
@@ -17,10 +17,10 @@ tt = { path = "../tt", version = "0.0.0" }
 [dev-dependencies]
 mbe = { path = "../mbe" }
 syntax = { path = "../syntax" }
-expect-test = "1.2.0-pre.1"
-oorandom = "11"
+expect-test = "1.2.2"
+oorandom = "11.1.3"
 # We depend on both individually instead of using `features = ["derive"]` to microoptimize the
 # build graph: if the feature was enabled, syn would be built early on in the graph if `smolstr`
 # supports `arbitrary`. This way, we avoid feature unification.
-arbitrary = "1"
-derive_arbitrary = "1"
+arbitrary = "1.1.0"
+derive_arbitrary = "1.1.0"
diff --git a/crates/flycheck/Cargo.toml b/crates/flycheck/Cargo.toml
index 6284ebfc82..c33d893744 100644
--- a/crates/flycheck/Cargo.toml
+++ b/crates/flycheck/Cargo.toml
@@ -10,12 +10,12 @@ rust-version = "1.57"
 doctest = false
 
 [dependencies]
-crossbeam-channel = "0.5.0"
-tracing = "0.1"
-cargo_metadata = "0.14"
-serde = { version = "1.0.106", features = ["derive"] }
-serde_json = "1.0.48"
-jod-thread = "0.1.1"
+crossbeam-channel = "0.5.4"
+tracing = "0.1.32"
+cargo_metadata = "0.14.2"
+serde = { version = "1.0.136", features = ["derive"] }
+serde_json = "1.0.79"
+jod-thread = "0.1.2"
 
 toolchain = { path = "../toolchain", version = "0.0.0" }
 stdx = { path = "../stdx", version = "0.0.0" }
diff --git a/crates/hir/Cargo.toml b/crates/hir/Cargo.toml
index 68cfb5d324..2b9a52d36f 100644
--- a/crates/hir/Cargo.toml
+++ b/crates/hir/Cargo.toml
@@ -11,11 +11,11 @@ doctest = false
 
 [dependencies]
 rustc-hash = "1.1.0"
-either = "1.5.3"
-arrayvec = "0.7"
-itertools = "0.10.0"
-smallvec = "1.4.0"
-once_cell = "1"
+either = "1.6.1"
+arrayvec = "0.7.2"
+itertools = "0.10.3"
+smallvec = "1.8.0"
+once_cell = "1.10.0"
 
 stdx = { path = "../stdx", version = "0.0.0" }
 syntax = { path = "../syntax", version = "0.0.0" }
diff --git a/crates/hir/src/diagnostics.rs b/crates/hir/src/diagnostics.rs
index bc43fb15ee..b5e7d5db63 100644
--- a/crates/hir/src/diagnostics.rs
+++ b/crates/hir/src/diagnostics.rs
@@ -5,7 +5,7 @@
 //! be expressed in terms of hir types themselves.
 use cfg::{CfgExpr, CfgOptions};
 use either::Either;
-use hir_def::path::ModPath;
+use hir_def::{path::ModPath, type_ref::Mutability};
 use hir_expand::{name::Name, HirFileId, InFile};
 use syntax::{ast, AstPtr, SyntaxNodePtr, TextRange};
 
@@ -28,6 +28,7 @@ macro_rules! diagnostics {
 }
 
 diagnostics![
+    AddReferenceHere,
     BreakOutsideOfLoop,
     InactiveCode,
     IncorrectCase,
@@ -37,10 +38,11 @@ diagnostics![
     MismatchedArgCount,
     MissingFields,
     MissingMatchArms,
+    MissingOkOrSomeInTailExpr,
     MissingUnsafe,
     NoSuchField,
+    RemoveThisSemicolon,
     ReplaceFilterMapNextWithFindMap,
-    TypeMismatch,
     UnimplementedBuiltinMacro,
     UnresolvedExternCrate,
     UnresolvedImport,
@@ -145,6 +147,19 @@ pub struct MismatchedArgCount {
     pub found: usize,
 }
 
+#[derive(Debug)]
+pub struct RemoveThisSemicolon {
+    pub expr: InFile<AstPtr<ast::Expr>>,
+}
+
+#[derive(Debug)]
+pub struct MissingOkOrSomeInTailExpr {
+    pub expr: InFile<AstPtr<ast::Expr>>,
+    // `Some` or `Ok` depending on whether the return type is Result or Option
+    pub required: String,
+    pub expected: Type,
+}
+
 #[derive(Debug)]
 pub struct MissingMatchArms {
     pub file: HirFileId,
@@ -152,11 +167,9 @@ pub struct MissingMatchArms {
 }
 
 #[derive(Debug)]
-pub struct TypeMismatch {
-    // FIXME: add mismatches in patterns as well
+pub struct AddReferenceHere {
     pub expr: InFile<AstPtr<ast::Expr>>,
-    pub expected: Type,
-    pub actual: Type,
+    pub mutability: Mutability,
 }
 
 pub use hir_ty::diagnostics::IncorrectCase;
diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs
index f4e58d88ed..3c12907b82 100644
--- a/crates/hir/src/lib.rs
+++ b/crates/hir/src/lib.rs
@@ -58,6 +58,7 @@ use hir_ty::{
     consteval::{
         eval_const, unknown_const_as_generic, ComputedExpr, ConstEvalCtx, ConstEvalError, ConstExt,
     },
+    could_unify,
     diagnostics::BodyValidationDiagnostic,
     method_resolution::{self, TyFingerprint},
     primitive::UintTy,
@@ -84,11 +85,12 @@ use crate::db::{DefDatabase, HirDatabase};
 pub use crate::{
     attrs::{HasAttrs, Namespace},
     diagnostics::{
-        AnyDiagnostic, BreakOutsideOfLoop, InactiveCode, IncorrectCase, InvalidDeriveTarget,
-        MacroError, MalformedDerive, MismatchedArgCount, MissingFields, MissingMatchArms,
-        MissingUnsafe, NoSuchField, ReplaceFilterMapNextWithFindMap, TypeMismatch,
-        UnimplementedBuiltinMacro, UnresolvedExternCrate, UnresolvedImport, UnresolvedMacroCall,
-        UnresolvedModule, UnresolvedProcMacro,
+        AddReferenceHere, AnyDiagnostic, BreakOutsideOfLoop, InactiveCode, IncorrectCase,
+        InvalidDeriveTarget, MacroError, MalformedDerive, MismatchedArgCount, MissingFields,
+        MissingMatchArms, MissingOkOrSomeInTailExpr, MissingUnsafe, NoSuchField,
+        RemoveThisSemicolon, ReplaceFilterMapNextWithFindMap, UnimplementedBuiltinMacro,
+        UnresolvedExternCrate, UnresolvedImport, UnresolvedMacroCall, UnresolvedModule,
+        UnresolvedProcMacro,
     },
     has_source::HasSource,
     semantics::{PathResolution, Semantics, SemanticsScope, TypeInfo},
@@ -1003,24 +1005,6 @@ impl Adt {
         Type::from_def(db, id.module(db.upcast()).krate(), id)
     }
 
-    /// Turns this ADT into a type with the given type parameters. This isn't
-    /// the greatest API, FIXME find a better one.
-    pub fn ty_with_args(self, db: &dyn HirDatabase, args: &[Type]) -> Type {
-        let id = AdtId::from(self);
-        let mut it = args.iter().map(|t| t.ty.clone());
-        let ty = TyBuilder::def_ty(db, id.into())
-            .fill(|x| {
-                let r = it.next().unwrap_or_else(|| TyKind::Error.intern(Interner));
-                match x {
-                    ParamKind::Type => GenericArgData::Ty(r).intern(Interner),
-                    ParamKind::Const(ty) => unknown_const_as_generic(ty.clone()),
-                }
-            })
-            .build();
-        let krate = id.module(db.upcast()).krate();
-        Type::new(db, krate, id, ty)
-    }
-
     pub fn module(self, db: &dyn HirDatabase) -> Module {
         match self {
             Adt::Struct(s) => s.module(db),
@@ -1036,14 +1020,6 @@ impl Adt {
             Adt::Enum(e) => e.name(db),
         }
     }
-
-    pub fn as_enum(&self) -> Option<Enum> {
-        if let Self::Enum(v) = self {
-            Some(*v)
-        } else {
-            None
-        }
-    }
 }
 
 impl HasVisibility for Adt {
@@ -1187,30 +1163,6 @@ impl DefWithBody {
                 }
             }
         }
-        for (expr, mismatch) in infer.expr_type_mismatches() {
-            let expr = match source_map.expr_syntax(expr) {
-                Ok(expr) => expr,
-                Err(SyntheticSyntax) => continue,
-            };
-            acc.push(
-                TypeMismatch {
-                    expr,
-                    expected: Type::new(
-                        db,
-                        krate,
-                        DefWithBodyId::from(self),
-                        mismatch.expected.clone(),
-                    ),
-                    actual: Type::new(
-                        db,
-                        krate,
-                        DefWithBodyId::from(self),
-                        mismatch.actual.clone(),
-                    ),
-                }
-                .into(),
-            );
-        }
 
         for expr in hir_ty::diagnostics::missing_unsafe(db, self.into()) {
             match source_map.expr_syntax(expr) {
@@ -1307,6 +1259,25 @@ impl DefWithBody {
                         Err(SyntheticSyntax) => (),
                     }
                 }
+                BodyValidationDiagnostic::RemoveThisSemicolon { expr } => {
+                    match source_map.expr_syntax(expr) {
+                        Ok(expr) => acc.push(RemoveThisSemicolon { expr }.into()),
+                        Err(SyntheticSyntax) => (),
+                    }
+                }
+                BodyValidationDiagnostic::MissingOkOrSomeInTailExpr { expr, required } => {
+                    match source_map.expr_syntax(expr) {
+                        Ok(expr) => acc.push(
+                            MissingOkOrSomeInTailExpr {
+                                expr,
+                                required,
+                                expected: self.body_type(db),
+                            }
+                            .into(),
+                        ),
+                        Err(SyntheticSyntax) => (),
+                    }
+                }
                 BodyValidationDiagnostic::MissingMatchArms { match_expr } => {
                     match source_map.expr_syntax(match_expr) {
                         Ok(source_ptr) => {
@@ -1328,6 +1299,12 @@ impl DefWithBody {
                         Err(SyntheticSyntax) => (),
                     }
                 }
+                BodyValidationDiagnostic::AddReferenceHere { arg_expr, mutability } => {
+                    match source_map.expr_syntax(arg_expr) {
+                        Ok(expr) => acc.push(AddReferenceHere { expr, mutability }.into()),
+                        Err(SyntheticSyntax) => (),
+                    }
+                }
             }
         }
 
@@ -2641,17 +2618,6 @@ impl Type {
         Type { krate, env: environment, ty }
     }
 
-    pub fn reference(inner: &Type, m: Mutability) -> Type {
-        inner.derived(
-            TyKind::Ref(
-                if m.is_mut() { hir_ty::Mutability::Mut } else { hir_ty::Mutability::Not },
-                hir_ty::static_lifetime(),
-                inner.ty.clone(),
-            )
-            .intern(Interner),
-        )
-    }
-
     fn new(db: &dyn HirDatabase, krate: CrateId, lexical_env: impl HasResolver, ty: Ty) -> Type {
         let resolver = lexical_env.resolver(db.upcast());
         let environment = resolver
@@ -2693,12 +2659,6 @@ impl Type {
         matches!(self.ty.kind(Interner), TyKind::Ref(..))
     }
 
-    pub fn as_reference(&self) -> Option<(Type, Mutability)> {
-        let (ty, _lt, m) = self.ty.as_reference()?;
-        let m = Mutability::from_mutable(matches!(m, hir_ty::Mutability::Mut));
-        Some((self.derived(ty.clone()), m))
-    }
-
     pub fn is_slice(&self) -> bool {
         matches!(self.ty.kind(Interner), TyKind::Slice(..))
     }
@@ -2940,7 +2900,7 @@ impl Type {
         self.autoderef_(db).map(move |ty| self.derived(ty))
     }
 
-    fn autoderef_<'a>(&'a self, db: &'a dyn HirDatabase) -> impl Iterator<Item = Ty> + 'a {
+    pub fn autoderef_<'a>(&'a self, db: &'a dyn HirDatabase) -> impl Iterator<Item = Ty> + 'a {
         // There should be no inference vars in types passed here
         let canonical = hir_ty::replace_errors_with_variables(&self.ty);
         let environment = self.env.clone();
@@ -3278,12 +3238,7 @@ impl Type {
 
     pub fn could_unify_with(&self, db: &dyn HirDatabase, other: &Type) -> bool {
         let tys = hir_ty::replace_errors_with_variables(&(self.ty.clone(), other.ty.clone()));
-        hir_ty::could_unify(db, self.env.clone(), &tys)
-    }
-
-    pub fn could_coerce_to(&self, db: &dyn HirDatabase, to: &Type) -> bool {
-        let tys = hir_ty::replace_errors_with_variables(&(self.ty.clone(), to.ty.clone()));
-        hir_ty::could_coerce(db, self.env.clone(), &tys)
+        could_unify(db, self.env.clone(), &tys)
     }
 }
 
diff --git a/crates/hir_def/Cargo.toml b/crates/hir_def/Cargo.toml
index 8a886f4a96..5087e18bc3 100644
--- a/crates/hir_def/Cargo.toml
+++ b/crates/hir_def/Cargo.toml
@@ -11,19 +11,19 @@ doctest = false
 
 [dependencies]
 cov-mark = "2.0.0-pre.1"
-dashmap = { version = "5.0", features = ["raw-api"] }
-lock_api = "0.4"
-parking_lot = "0.12"
-tracing = "0.1"
-once_cell = "1.3.1"
+dashmap = { version = "5.2.0", features = ["raw-api"] }
+lock_api = "0.4.6"
+parking_lot = "0.12.0"
+tracing = "0.1.32"
+once_cell = "1.10.0"
 rustc-hash = "1.1.0"
-either = "1.5.3"
+either = "1.6.1"
 anymap = "0.12.1"
-drop_bomb = "0.1.4"
-fst = { version = "0.4", default-features = false }
-itertools = "0.10.0"
-indexmap = "1.7.0"
-smallvec = "1.4.0"
+drop_bomb = "0.1.5"
+fst = { version = "0.4.7", default-features = false }
+itertools = "0.10.3"
+indexmap = "1.8.0"
+smallvec = "1.8.0"
 arrayvec = "0.7.2"
 la-arena = { version = "0.3.0", path = "../../lib/arena" }
 
@@ -39,4 +39,4 @@ limit = { path = "../limit", version = "0.0.0" }
 
 [dev-dependencies]
 test_utils = { path = "../test_utils" }
-expect-test = "1.2.0-pre.1"
+expect-test = "1.2.2"
diff --git a/crates/hir_def/src/type_ref.rs b/crates/hir_def/src/type_ref.rs
index 8e9336a0cc..c6c521f733 100644
--- a/crates/hir_def/src/type_ref.rs
+++ b/crates/hir_def/src/type_ref.rs
@@ -38,22 +38,6 @@ impl Mutability {
             Mutability::Mut => "mut ",
         }
     }
-
-    /// Returns `true` if the mutability is [`Mut`].
-    ///
-    /// [`Mut`]: Mutability::Mut
-    #[must_use]
-    pub fn is_mut(&self) -> bool {
-        matches!(self, Self::Mut)
-    }
-
-    /// Returns `true` if the mutability is [`Shared`].
-    ///
-    /// [`Shared`]: Mutability::Shared
-    #[must_use]
-    pub fn is_shared(&self) -> bool {
-        matches!(self, Self::Shared)
-    }
 }
 
 #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
diff --git a/crates/hir_expand/Cargo.toml b/crates/hir_expand/Cargo.toml
index d7b4cbf82e..9d8772d129 100644
--- a/crates/hir_expand/Cargo.toml
+++ b/crates/hir_expand/Cargo.toml
@@ -11,12 +11,12 @@ doctest = false
 
 [dependencies]
 cov-mark = "2.0.0-pre.1"
-tracing = "0.1"
-either = "1.5.3"
-rustc-hash = "1.0.0"
+tracing = "0.1.32"
+either = "1.6.1"
+rustc-hash = "1.1.0"
 la-arena = { version = "0.3.0", path = "../../lib/arena" }
-itertools = "0.10.0"
-hashbrown = { version = "0.12", features = [
+itertools = "0.10.3"
+hashbrown = { version = "0.12.0", features = [
     "inline-more",
 ], default-features = false }
 
@@ -29,4 +29,4 @@ mbe = { path = "../mbe", version = "0.0.0" }
 limit = { path = "../limit", version = "0.0.0" }
 
 [dev-dependencies]
-expect-test = "1.2.0-pre.1"
+expect-test = "1.2.2"
diff --git a/crates/hir_ty/Cargo.toml b/crates/hir_ty/Cargo.toml
index d2bfca53ad..699fd86c9d 100644
--- a/crates/hir_ty/Cargo.toml
+++ b/crates/hir_ty/Cargo.toml
@@ -11,18 +11,18 @@ doctest = false
 
 [dependencies]
 cov-mark = "2.0.0-pre.1"
-itertools = "0.10.0"
-arrayvec = "0.7"
-smallvec = "1.2.0"
+itertools = "0.10.3"
+arrayvec = "0.7.2"
+smallvec = "1.8.0"
 ena = "0.14.0"
-tracing = "0.1"
+tracing = "0.1.32"
 rustc-hash = "1.1.0"
-scoped-tls = "1"
-chalk-solve = { version = "0.79", default-features = false }
-chalk-ir = "0.79"
-chalk-recursive = { version = "0.79", default-features = false }
+scoped-tls = "1.0.0"
+chalk-solve = { version = "0.80.0", default-features = false }
+chalk-ir = "0.80.0"
+chalk-recursive = { version = "0.80.0", default-features = false }
 la-arena = { version = "0.3.0", path = "../../lib/arena" }
-once_cell = { version = "1.5.0" }
+once_cell = "1.10.0"
 typed-arena = "2.0.1"
 
 stdx = { path = "../stdx", version = "0.0.0" }
@@ -35,10 +35,10 @@ limit = { path = "../limit", version = "0.0.0" }
 
 [dev-dependencies]
 test_utils = { path = "../test_utils" }
-expect-test = "1.2.0-pre.1"
-tracing = "0.1"
-tracing-subscriber = { version = "0.3", default-features = false, features = [
+expect-test = "1.2.2"
+tracing = "0.1.32"
+tracing-subscriber = { version = "0.3.9", default-features = false, features = [
     "env-filter",
     "registry",
 ] }
-tracing-tree = "0.2"
+tracing-tree = "0.2.0"
diff --git a/crates/hir_ty/src/chalk_db.rs b/crates/hir_ty/src/chalk_db.rs
index 1b67e5a86b..451245b5d2 100644
--- a/crates/hir_ty/src/chalk_db.rs
+++ b/crates/hir_ty/src/chalk_db.rs
@@ -337,6 +337,10 @@ impl<'a> chalk_solve::RustIrDatabase<Interner> for ChalkContext<'a> {
             hir_def::AdtId::UnionId(id) => self.db.union_data(id).name.to_string(),
         }
     }
+    fn adt_size_align(&self, _id: chalk_ir::AdtId<Interner>) -> Arc<rust_ir::AdtSizeAlign> {
+        // FIXME
+        Arc::new(rust_ir::AdtSizeAlign::from_one_zst(false))
+    }
     fn assoc_type_name(&self, assoc_ty_id: chalk_ir::AssocTypeId<Interner>) -> String {
         let id = self.db.associated_ty_data(assoc_ty_id).name;
         self.db.type_alias_data(id).name.to_string()
@@ -480,34 +484,38 @@ pub(crate) fn trait_datum_query(
 
 fn well_known_trait_from_lang_attr(name: &str) -> Option<WellKnownTrait> {
     Some(match name {
-        "sized" => WellKnownTrait::Sized,
-        "copy" => WellKnownTrait::Copy,
         "clone" => WellKnownTrait::Clone,
+        "coerce_unsized" => WellKnownTrait::CoerceUnsized,
+        "copy" => WellKnownTrait::Copy,
+        "discriminant_kind" => WellKnownTrait::DiscriminantKind,
+        "dispatch_from_dyn" => WellKnownTrait::DispatchFromDyn,
         "drop" => WellKnownTrait::Drop,
-        "fn_once" => WellKnownTrait::FnOnce,
-        "fn_mut" => WellKnownTrait::FnMut,
         "fn" => WellKnownTrait::Fn,
+        "fn_mut" => WellKnownTrait::FnMut,
+        "fn_once" => WellKnownTrait::FnOnce,
+        "generator" => WellKnownTrait::Generator,
+        "sized" => WellKnownTrait::Sized,
+        "unpin" => WellKnownTrait::Unpin,
         "unsize" => WellKnownTrait::Unsize,
-        "coerce_unsized" => WellKnownTrait::CoerceUnsized,
-        "discriminant_kind" => WellKnownTrait::DiscriminantKind,
         _ => return None,
     })
 }
 
 fn lang_attr_from_well_known_trait(attr: WellKnownTrait) -> &'static str {
     match attr {
-        WellKnownTrait::Sized => "sized",
-        WellKnownTrait::Copy => "copy",
         WellKnownTrait::Clone => "clone",
-        WellKnownTrait::Drop => "drop",
-        WellKnownTrait::FnOnce => "fn_once",
-        WellKnownTrait::FnMut => "fn_mut",
-        WellKnownTrait::Fn => "fn",
-        WellKnownTrait::Unsize => "unsize",
-        WellKnownTrait::Unpin => "unpin",
         WellKnownTrait::CoerceUnsized => "coerce_unsized",
+        WellKnownTrait::Copy => "copy",
         WellKnownTrait::DiscriminantKind => "discriminant_kind",
+        WellKnownTrait::DispatchFromDyn => "dispatch_from_dyn",
+        WellKnownTrait::Drop => "drop",
+        WellKnownTrait::Fn => "fn",
+        WellKnownTrait::FnMut => "fn_mut",
+        WellKnownTrait::FnOnce => "fn_once",
         WellKnownTrait::Generator => "generator",
+        WellKnownTrait::Sized => "sized",
+        WellKnownTrait::Unpin => "unpin",
+        WellKnownTrait::Unsize => "unsize",
     }
 }
 
diff --git a/crates/hir_ty/src/diagnostics/expr.rs b/crates/hir_ty/src/diagnostics/expr.rs
index 71eb7e3995..b7d765c59b 100644
--- a/crates/hir_ty/src/diagnostics/expr.rs
+++ b/crates/hir_ty/src/diagnostics/expr.rs
@@ -4,7 +4,10 @@
 
 use std::sync::Arc;
 
-use hir_def::{path::path, resolver::HasResolver, AssocItemId, DefWithBodyId, HasModule};
+use hir_def::{
+    expr::Statement, path::path, resolver::HasResolver, type_ref::Mutability, AssocItemId,
+    DefWithBodyId, HasModule,
+};
 use hir_expand::name;
 use itertools::Either;
 use rustc_hash::FxHashSet;
@@ -17,7 +20,7 @@ use crate::{
         deconstruct_pat::DeconstructedPat,
         usefulness::{compute_match_usefulness, MatchCheckCtx},
     },
-    InferenceResult, Interner, TyExt,
+    AdtId, InferenceResult, Interner, Ty, TyExt, TyKind,
 };
 
 pub(crate) use hir_def::{
@@ -40,9 +43,20 @@ pub enum BodyValidationDiagnostic {
         expected: usize,
         found: usize,
     },
+    RemoveThisSemicolon {
+        expr: ExprId,
+    },
+    MissingOkOrSomeInTailExpr {
+        expr: ExprId,
+        required: String,
+    },
     MissingMatchArms {
         match_expr: ExprId,
     },
+    AddReferenceHere {
+        arg_expr: ExprId,
+        mutability: Mutability,
+    },
 }
 
 impl BodyValidationDiagnostic {
@@ -102,6 +116,30 @@ impl ExprValidator {
                 });
             }
         }
+        let body_expr = &body[body.body_expr];
+        if let Expr::Block { statements, tail, .. } = body_expr {
+            if let Some(t) = tail {
+                self.validate_results_in_tail_expr(body.body_expr, *t, db);
+            } else if let Some(Statement::Expr { expr: id, .. }) = statements.last() {
+                self.validate_missing_tail_expr(body.body_expr, *id);
+            }
+        }
+
+        let infer = &self.infer;
+        let diagnostics = &mut self.diagnostics;
+
+        infer
+            .expr_type_mismatches()
+            .filter_map(|(expr, mismatch)| {
+                let (expr_without_ref, mutability) =
+                    check_missing_refs(infer, expr, &mismatch.expected)?;
+
+                Some((expr_without_ref, mutability))
+            })
+            .for_each(|(arg_expr, mutability)| {
+                diagnostics
+                    .push(BodyValidationDiagnostic::AddReferenceHere { arg_expr, mutability });
+            });
     }
 
     fn validate_call(
@@ -292,6 +330,66 @@ impl ExprValidator {
         }
         pattern
     }
+
+    fn validate_results_in_tail_expr(&mut self, body_id: ExprId, id: ExprId, db: &dyn HirDatabase) {
+        // the mismatch will be on the whole block currently
+        let mismatch = match self.infer.type_mismatch_for_expr(body_id) {
+            Some(m) => m,
+            None => return,
+        };
+
+        let core_result_path = path![core::result::Result];
+        let core_option_path = path![core::option::Option];
+
+        let resolver = self.owner.resolver(db.upcast());
+        let core_result_enum = match resolver.resolve_known_enum(db.upcast(), &core_result_path) {
+            Some(it) => it,
+            _ => return,
+        };
+        let core_option_enum = match resolver.resolve_known_enum(db.upcast(), &core_option_path) {
+            Some(it) => it,
+            _ => return,
+        };
+
+        let (params, required) = match mismatch.expected.kind(Interner) {
+            TyKind::Adt(AdtId(hir_def::AdtId::EnumId(enum_id)), parameters)
+                if *enum_id == core_result_enum =>
+            {
+                (parameters, "Ok".to_string())
+            }
+            TyKind::Adt(AdtId(hir_def::AdtId::EnumId(enum_id)), parameters)
+                if *enum_id == core_option_enum =>
+            {
+                (parameters, "Some".to_string())
+            }
+            _ => return,
+        };
+
+        if params.len(Interner) > 0 && params.at(Interner, 0).ty(Interner) == Some(&mismatch.actual)
+        {
+            self.diagnostics
+                .push(BodyValidationDiagnostic::MissingOkOrSomeInTailExpr { expr: id, required });
+        }
+    }
+
+    fn validate_missing_tail_expr(&mut self, body_id: ExprId, possible_tail_id: ExprId) {
+        let mismatch = match self.infer.type_mismatch_for_expr(body_id) {
+            Some(m) => m,
+            None => return,
+        };
+
+        let possible_tail_ty = match self.infer.type_of_expr.get(possible_tail_id) {
+            Some(ty) => ty,
+            None => return,
+        };
+
+        if !mismatch.actual.is_unit() || mismatch.expected != *possible_tail_ty {
+            return;
+        }
+
+        self.diagnostics
+            .push(BodyValidationDiagnostic::RemoveThisSemicolon { expr: possible_tail_id });
+    }
 }
 
 struct FilterMapNextChecker {
@@ -425,3 +523,30 @@ fn types_of_subpatterns_do_match(pat: PatId, body: &Body, infer: &InferenceResul
     walk(pat, body, infer, &mut has_type_mismatches);
     !has_type_mismatches
 }
+
+fn check_missing_refs(
+    infer: &InferenceResult,
+    arg: ExprId,
+    param: &Ty,
+) -> Option<(ExprId, Mutability)> {
+    let arg_ty = infer.type_of_expr.get(arg)?;
+
+    let reference_one = arg_ty.as_reference();
+    let reference_two = param.as_reference();
+
+    match (reference_one, reference_two) {
+        (None, Some((referenced_ty, _, mutability))) if referenced_ty == arg_ty => {
+            Some((arg, Mutability::from_mutable(matches!(mutability, chalk_ir::Mutability::Mut))))
+        }
+        (None, Some((referenced_ty, _, mutability))) => match referenced_ty.kind(Interner) {
+            TyKind::Slice(subst) if matches!(arg_ty.kind(Interner), TyKind::Array(arr_subst, _) if arr_subst == subst) => {
+                Some((
+                    arg,
+                    Mutability::from_mutable(matches!(mutability, chalk_ir::Mutability::Mut)),
+                ))
+            }
+            _ => None,
+        },
+        _ => None,
+    }
+}
diff --git a/crates/hir_ty/src/infer.rs b/crates/hir_ty/src/infer.rs
index c91cdec183..442774d0be 100644
--- a/crates/hir_ty/src/infer.rs
+++ b/crates/hir_ty/src/infer.rs
@@ -44,8 +44,6 @@ use crate::{
 //
 // https://github.com/rust-lang/rust/issues/57411
 #[allow(unreachable_pub)]
-pub use coerce::could_coerce;
-#[allow(unreachable_pub)]
 pub use unify::could_unify;
 
 pub(crate) mod unify;
diff --git a/crates/hir_ty/src/infer/coerce.rs b/crates/hir_ty/src/infer/coerce.rs
index f54440bf5b..528e3ba882 100644
--- a/crates/hir_ty/src/infer/coerce.rs
+++ b/crates/hir_ty/src/infer/coerce.rs
@@ -5,26 +5,23 @@
 //! See <https://doc.rust-lang.org/nomicon/coercions.html> and
 //! `librustc_typeck/check/coercion.rs`.
 
-use std::{iter, sync::Arc};
+use std::iter;
 
-use chalk_ir::{cast::Cast, BoundVar, Goal, Mutability, TyVariableKind};
+use chalk_ir::{cast::Cast, Goal, Mutability, TyVariableKind};
 use hir_def::{expr::ExprId, lang_item::LangItemTarget};
 use stdx::always;
 use syntax::SmolStr;
 
 use crate::{
     autoderef::{Autoderef, AutoderefKind},
-    db::HirDatabase,
     infer::{
-        Adjust, Adjustment, AutoBorrow, InferOk, InferenceContext, OverloadedDeref, PointerCast,
-        TypeError, TypeMismatch,
+        Adjust, Adjustment, AutoBorrow, InferOk, InferResult, InferenceContext, OverloadedDeref,
+        PointerCast, TypeError, TypeMismatch,
     },
     static_lifetime, Canonical, DomainGoal, FnPointer, FnSig, Guidance, InEnvironment, Interner,
-    Solution, Substitution, TraitEnvironment, Ty, TyBuilder, TyExt, TyKind,
+    Solution, Substitution, Ty, TyBuilder, TyExt, TyKind,
 };
 
-use super::unify::InferenceTable;
-
 pub(crate) type CoerceResult = Result<InferOk<(Vec<Adjustment>, Ty)>, TypeError>;
 
 /// Do not require any adjustments, i.e. coerce `x -> x`.
@@ -87,8 +84,8 @@ impl CoerceMany {
         };
         if let Some(sig) = sig {
             let target_ty = TyKind::Function(sig.to_fn_ptr()).intern(Interner);
-            let result1 = ctx.table.coerce_inner(self.expected_ty.clone(), &target_ty);
-            let result2 = ctx.table.coerce_inner(expr_ty.clone(), &target_ty);
+            let result1 = ctx.coerce_inner(self.expected_ty.clone(), &target_ty);
+            let result2 = ctx.coerce_inner(expr_ty.clone(), &target_ty);
             if let (Ok(result1), Ok(result2)) = (result1, result2) {
                 ctx.table.register_infer_ok(result1);
                 ctx.table.register_infer_ok(result2);
@@ -121,45 +118,6 @@ impl CoerceMany {
     }
 }
 
-pub fn could_coerce(
-    db: &dyn HirDatabase,
-    env: Arc<TraitEnvironment>,
-    tys: &Canonical<(Ty, Ty)>,
-) -> bool {
-    coerce(db, env, tys).is_ok()
-}
-
-pub(crate) fn coerce(
-    db: &dyn HirDatabase,
-    env: Arc<TraitEnvironment>,
-    tys: &Canonical<(Ty, Ty)>,
-) -> Result<(Vec<Adjustment>, Ty), TypeError> {
-    let mut table = InferenceTable::new(db, env);
-    let vars = table.fresh_subst(tys.binders.as_slice(Interner));
-    let ty1_with_vars = vars.apply(tys.value.0.clone(), Interner);
-    let ty2_with_vars = vars.apply(tys.value.1.clone(), Interner);
-    let (adjustments, ty) = table.coerce(&ty1_with_vars, &ty2_with_vars)?;
-    // default any type vars that weren't unified back to their original bound vars
-    // (kind of hacky)
-    let find_var = |iv| {
-        vars.iter(Interner).position(|v| match v.interned() {
-            chalk_ir::GenericArgData::Ty(ty) => ty.inference_var(Interner),
-            chalk_ir::GenericArgData::Lifetime(lt) => lt.inference_var(Interner),
-            chalk_ir::GenericArgData::Const(c) => c.inference_var(Interner),
-        } == Some(iv))
-    };
-    let fallback = |iv, kind, default, binder| match kind {
-        chalk_ir::VariableKind::Ty(_ty_kind) => find_var(iv)
-            .map_or(default, |i| BoundVar::new(binder, i).to_ty(Interner).cast(Interner)),
-        chalk_ir::VariableKind::Lifetime => find_var(iv)
-            .map_or(default, |i| BoundVar::new(binder, i).to_lifetime(Interner).cast(Interner)),
-        chalk_ir::VariableKind::Const(ty) => find_var(iv)
-            .map_or(default, |i| BoundVar::new(binder, i).to_const(Interner, ty).cast(Interner)),
-    };
-    // FIXME also map the types in the adjustments
-    Ok((adjustments, table.resolve_with_fallback(ty, &fallback)))
-}
-
 impl<'a> InferenceContext<'a> {
     /// Unify two types, but may coerce the first one to the second one
     /// using "implicit coercion rules" if needed.
@@ -168,31 +126,16 @@ impl<'a> InferenceContext<'a> {
         expr: Option<ExprId>,
         from_ty: &Ty,
         to_ty: &Ty,
-    ) -> Result<Ty, TypeError> {
-        let from_ty = self.resolve_ty_shallow(from_ty);
-        let to_ty = self.resolve_ty_shallow(to_ty);
-        let (adjustments, ty) = self.table.coerce(&from_ty, &to_ty)?;
-        if let Some(expr) = expr {
-            self.write_expr_adj(expr, adjustments);
-        }
-        Ok(ty)
-    }
-}
-
-impl<'a> InferenceTable<'a> {
-    /// Unify two types, but may coerce the first one to the second one
-    /// using "implicit coercion rules" if needed.
-    pub(crate) fn coerce(
-        &mut self,
-        from_ty: &Ty,
-        to_ty: &Ty,
-    ) -> Result<(Vec<Adjustment>, Ty), TypeError> {
+    ) -> InferResult<Ty> {
         let from_ty = self.resolve_ty_shallow(from_ty);
         let to_ty = self.resolve_ty_shallow(to_ty);
         match self.coerce_inner(from_ty, &to_ty) {
             Ok(InferOk { value: (adjustments, ty), goals }) => {
-                self.register_infer_ok(InferOk { value: (), goals });
-                Ok((adjustments, ty))
+                if let Some(expr) = expr {
+                    self.write_expr_adj(expr, adjustments);
+                }
+                self.table.register_infer_ok(InferOk { value: (), goals });
+                Ok(InferOk { value: ty, goals: Vec::new() })
             }
             Err(e) => {
                 // FIXME deal with error
@@ -211,7 +154,7 @@ impl<'a> InferenceTable<'a> {
             //
             // here, we would coerce from `!` to `?T`.
             if let TyKind::InferenceVar(tv, TyVariableKind::General) = to_ty.kind(Interner) {
-                self.set_diverging(*tv, true);
+                self.table.set_diverging(*tv, true);
             }
             return success(simple(Adjust::NeverToAny)(to_ty.clone()), to_ty.clone(), vec![]);
         }
@@ -260,7 +203,8 @@ impl<'a> InferenceTable<'a> {
     where
         F: FnOnce(Ty) -> Vec<Adjustment>,
     {
-        self.try_unify(t1, t2)
+        self.table
+            .try_unify(t1, t2)
             .and_then(|InferOk { goals, .. }| success(f(t1.clone()), t1.clone(), goals))
     }
 
@@ -315,9 +259,9 @@ impl<'a> InferenceTable<'a> {
         // details of coercion errors though, so I think it's useful to leave
         // the structure like it is.
 
-        let snapshot = self.snapshot();
+        let snapshot = self.table.snapshot();
 
-        let mut autoderef = Autoderef::new(self, from_ty.clone());
+        let mut autoderef = Autoderef::new(&mut self.table, from_ty.clone());
         let mut first_error = None;
         let mut found = None;
 
@@ -373,7 +317,7 @@ impl<'a> InferenceTable<'a> {
         let InferOk { value: ty, goals } = match found {
             Some(d) => d,
             None => {
-                self.rollback_to(snapshot);
+                self.table.rollback_to(snapshot);
                 let err = first_error.expect("coerce_borrowed_pointer had no error");
                 return Err(err);
             }
@@ -569,7 +513,7 @@ impl<'a> InferenceTable<'a> {
         let coerce_from =
             reborrow.as_ref().map_or_else(|| from_ty.clone(), |(_, adj)| adj.target.clone());
 
-        let krate = self.trait_env.krate;
+        let krate = self.resolver.krate().unwrap();
         let coerce_unsized_trait =
             match self.db.lang_item(krate, SmolStr::new_inline("coerce_unsized")) {
                 Some(LangItemTarget::TraitId(trait_)) => trait_,
@@ -602,7 +546,7 @@ impl<'a> InferenceTable<'a> {
         match solution {
             Solution::Unique(v) => {
                 canonicalized.apply_solution(
-                    self,
+                    &mut self.table,
                     Canonical {
                         binders: v.binders,
                         // FIXME handle constraints
@@ -612,7 +556,7 @@ impl<'a> InferenceTable<'a> {
             }
             Solution::Ambig(Guidance::Definite(subst)) => {
                 // FIXME need to record an obligation here
-                canonicalized.apply_solution(self, subst)
+                canonicalized.apply_solution(&mut self.table, subst)
             }
             // FIXME actually we maybe should also accept unknown guidance here
             _ => return Err(TypeError),
diff --git a/crates/hir_ty/src/infer/expr.rs b/crates/hir_ty/src/infer/expr.rs
index 43cff92f23..ebbce33e01 100644
--- a/crates/hir_ty/src/infer/expr.rs
+++ b/crates/hir_ty/src/infer/expr.rs
@@ -28,7 +28,7 @@ use crate::{
     lower::{
         const_or_path_to_chalk, generic_arg_to_chalk, lower_to_chalk_mutability, ParamLoweringMode,
     },
-    mapping::{from_chalk, ToChalk},
+    mapping::from_chalk,
     method_resolution,
     primitive::{self, UintTy},
     static_lifetime, to_chalk_trait_id,
@@ -67,7 +67,7 @@ impl<'a> InferenceContext<'a> {
         let ty = self.infer_expr_inner(expr, expected);
         if let Some(target) = expected.only_has_type(&mut self.table) {
             match self.coerce(Some(expr), &ty, &target) {
-                Ok(res) => res,
+                Ok(res) => res.value,
                 Err(_) => {
                     self.result
                         .type_mismatches
@@ -279,16 +279,14 @@ impl<'a> InferenceContext<'a> {
                 let callee_ty = self.infer_expr(*callee, &Expectation::none());
                 let mut derefs = Autoderef::new(&mut self.table, callee_ty.clone());
                 let mut res = None;
-                let mut derefed_callee = callee_ty.clone();
                 // manual loop to be able to access `derefs.table`
                 while let Some((callee_deref_ty, _)) = derefs.next() {
                     res = derefs.table.callable_sig(&callee_deref_ty, args.len());
                     if res.is_some() {
-                        derefed_callee = callee_deref_ty;
                         break;
                     }
                 }
-                let (param_tys, ret_ty) = match res {
+                let (param_tys, ret_ty): (Vec<Ty>, Ty) = match res {
                     Some(res) => {
                         let adjustments = auto_deref_adjust_steps(&derefs);
                         self.write_expr_adj(*callee, adjustments);
@@ -296,7 +294,6 @@ impl<'a> InferenceContext<'a> {
                     }
                     None => (Vec::new(), self.err_ty()),
                 };
-                let indices_to_skip = self.check_legacy_const_generics(derefed_callee, args);
                 self.register_obligations_for_call(&callee_ty);
 
                 let expected_inputs = self.expected_inputs_for_expected_output(
@@ -305,7 +302,7 @@ impl<'a> InferenceContext<'a> {
                     param_tys.clone(),
                 );
 
-                self.check_call_arguments(args, &expected_inputs, &param_tys, &indices_to_skip);
+                self.check_call_arguments(args, &expected_inputs, &param_tys);
                 self.normalize_associated_types_in(ret_ty)
             }
             Expr::MethodCall { receiver, args, method_name, generic_args } => self
@@ -955,7 +952,7 @@ impl<'a> InferenceContext<'a> {
         let expected_inputs =
             self.expected_inputs_for_expected_output(expected, ret_ty.clone(), param_tys.clone());
 
-        self.check_call_arguments(args, &expected_inputs, &param_tys, &[]);
+        self.check_call_arguments(args, &expected_inputs, &param_tys);
         self.normalize_associated_types_in(ret_ty)
     }
 
@@ -986,40 +983,24 @@ impl<'a> InferenceContext<'a> {
         }
     }
 
-    fn check_call_arguments(
-        &mut self,
-        args: &[ExprId],
-        expected_inputs: &[Ty],
-        param_tys: &[Ty],
-        skip_indices: &[u32],
-    ) {
+    fn check_call_arguments(&mut self, args: &[ExprId], expected_inputs: &[Ty], param_tys: &[Ty]) {
         // Quoting https://github.com/rust-lang/rust/blob/6ef275e6c3cb1384ec78128eceeb4963ff788dca/src/librustc_typeck/check/mod.rs#L3325 --
         // We do this in a pretty awful way: first we type-check any arguments
         // that are not closures, then we type-check the closures. This is so
         // that we have more information about the types of arguments when we
         // type-check the functions. This isn't really the right way to do this.
         for &check_closures in &[false, true] {
-            let mut skip_indices = skip_indices.into_iter().copied().fuse().peekable();
             let param_iter = param_tys.iter().cloned().chain(repeat(self.err_ty()));
             let expected_iter = expected_inputs
                 .iter()
                 .cloned()
                 .chain(param_iter.clone().skip(expected_inputs.len()));
-            for (idx, ((&arg, param_ty), expected_ty)) in
-                args.iter().zip(param_iter).zip(expected_iter).enumerate()
-            {
+            for ((&arg, param_ty), expected_ty) in args.iter().zip(param_iter).zip(expected_iter) {
                 let is_closure = matches!(&self.body[arg], Expr::Lambda { .. });
                 if is_closure != check_closures {
                     continue;
                 }
 
-                while skip_indices.peek().map_or(false, |i| *i < idx as u32) {
-                    skip_indices.next();
-                }
-                if skip_indices.peek().copied() == Some(idx as u32) {
-                    continue;
-                }
-
                 // the difference between param_ty and expected here is that
                 // expected is the parameter when the expected *return* type is
                 // taken into account. So in `let _: &[i32] = identity(&[1, 2])`
@@ -1159,49 +1140,6 @@ impl<'a> InferenceContext<'a> {
         }
     }
 
-    /// Returns the argument indices to skip.
-    fn check_legacy_const_generics(&mut self, callee: Ty, args: &[ExprId]) -> Vec<u32> {
-        let (func, subst) = match callee.kind(Interner) {
-            TyKind::FnDef(fn_id, subst) => {
-                let callable = CallableDefId::from_chalk(self.db, *fn_id);
-                let func = match callable {
-                    CallableDefId::FunctionId(f) => f,
-                    _ => return Vec::new(),
-                };
-                (func, subst)
-            }
-            _ => return Vec::new(),
-        };
-
-        let data = self.db.function_data(func);
-        if data.legacy_const_generics_indices.is_empty() {
-            return Vec::new();
-        }
-
-        // only use legacy const generics if the param count matches with them
-        if data.params.len() + data.legacy_const_generics_indices.len() != args.len() {
-            return Vec::new();
-        }
-
-        // check legacy const parameters
-        for (subst_idx, arg_idx) in data.legacy_const_generics_indices.iter().copied().enumerate() {
-            let arg = match subst.at(Interner, subst_idx).constant(Interner) {
-                Some(c) => c,
-                None => continue, // not a const parameter?
-            };
-            if arg_idx >= args.len() as u32 {
-                continue;
-            }
-            let _ty = arg.data(Interner).ty.clone();
-            let expected = Expectation::none(); // FIXME use actual const ty, when that is lowered correctly
-            self.infer_expr(args[arg_idx as usize], &expected);
-            // FIXME: evaluate and unify with the const
-        }
-        let mut indices = data.legacy_const_generics_indices.clone();
-        indices.sort();
-        indices
-    }
-
     fn builtin_binary_op_return_ty(&mut self, op: BinaryOp, lhs_ty: Ty, rhs_ty: Ty) -> Option<Ty> {
         let lhs_ty = self.resolve_ty_shallow(&lhs_ty);
         let rhs_ty = self.resolve_ty_shallow(&rhs_ty);
diff --git a/crates/hir_ty/src/infer/unify.rs b/crates/hir_ty/src/infer/unify.rs
index 84ca1660af..ef0675d59f 100644
--- a/crates/hir_ty/src/infer/unify.rs
+++ b/crates/hir_ty/src/infer/unify.rs
@@ -3,8 +3,8 @@
 use std::{fmt, mem, sync::Arc};
 
 use chalk_ir::{
-    cast::Cast, fold::Fold, interner::HasInterner, zip::Zip, CanonicalVarKind, FloatTy, IntTy,
-    NoSolution, TyVariableKind, UniverseIndex,
+    cast::Cast, fold::Fold, interner::HasInterner, zip::Zip, FloatTy, IntTy, NoSolution,
+    TyVariableKind, UniverseIndex,
 };
 use chalk_solve::infer::ParameterEnaVariableExt;
 use ena::unify::UnifyKey;
@@ -299,23 +299,11 @@ impl<'a> InferenceTable<'a> {
         self.resolve_with_fallback_inner(&mut Vec::new(), t, &fallback)
     }
 
-    pub(crate) fn fresh_subst(&mut self, binders: &[CanonicalVarKind<Interner>]) -> Substitution {
-        Substitution::from_iter(
-            Interner,
-            binders.iter().map(|kind| {
-                let param_infer_var =
-                    kind.map_ref(|&ui| self.var_unification_table.new_variable(ui));
-                param_infer_var.to_generic_arg(Interner)
-            }),
-        )
-    }
-
     pub(crate) fn instantiate_canonical<T>(&mut self, canonical: Canonical<T>) -> T::Result
     where
         T: HasInterner<Interner = Interner> + Fold<Interner> + std::fmt::Debug,
     {
-        let subst = self.fresh_subst(canonical.binders.as_slice(Interner));
-        subst.apply(canonical.value, Interner)
+        self.var_unification_table.instantiate_canonical(Interner, canonical)
     }
 
     fn resolve_with_fallback_inner<T>(
diff --git a/crates/hir_ty/src/lib.rs b/crates/hir_ty/src/lib.rs
index 945b4b0e4a..59e6fe2a04 100644
--- a/crates/hir_ty/src/lib.rs
+++ b/crates/hir_ty/src/lib.rs
@@ -51,7 +51,7 @@ pub use autoderef::autoderef;
 pub use builder::{ParamKind, TyBuilder};
 pub use chalk_ext::*;
 pub use infer::{
-    could_coerce, could_unify, Adjust, Adjustment, AutoBorrow, InferenceDiagnostic, InferenceResult,
+    could_unify, Adjust, Adjustment, AutoBorrow, InferenceDiagnostic, InferenceResult,
 };
 pub use interner::Interner;
 pub use lower::{
diff --git a/crates/ide/Cargo.toml b/crates/ide/Cargo.toml
index 1df2942bdc..cd11b2801d 100644
--- a/crates/ide/Cargo.toml
+++ b/crates/ide/Cargo.toml
@@ -11,15 +11,15 @@ doctest = false
 
 [dependencies]
 cov-mark = "2.0.0-pre.1"
-crossbeam-channel = "0.5.0"
-either = "1.5.3"
-itertools = "0.10.0"
-tracing = "0.1"
+crossbeam-channel = "0.5.4"
+either = "1.6.1"
+itertools = "0.10.3"
+tracing = "0.1.32"
 rustc-hash = "1.1.0"
-oorandom = "11.1.2"
-pulldown-cmark-to-cmark = "10.0.0"
-pulldown-cmark = { version = "0.9", default-features = false }
-url = "2.1.1"
+oorandom = "11.1.3"
+pulldown-cmark-to-cmark = "10.0.1"
+pulldown-cmark = { version = "0.9.1", default-features = false }
+url = "2.2.2"
 dot = "0.1.4"
 
 stdx = { path = "../stdx", version = "0.0.0" }
@@ -39,4 +39,4 @@ hir = { path = "../hir", version = "0.0.0" }
 
 [dev-dependencies]
 test_utils = { path = "../test_utils" }
-expect-test = "1.2.0-pre.1"
+expect-test = "1.2.2"
diff --git a/crates/ide_assists/Cargo.toml b/crates/ide_assists/Cargo.toml
index 09242e0aaf..4caa9285b4 100644
--- a/crates/ide_assists/Cargo.toml
+++ b/crates/ide_assists/Cargo.toml
@@ -12,7 +12,7 @@ doctest = false
 [dependencies]
 cov-mark = "2.0.0-pre.1"
 rustc-hash = "1.1.0"
-itertools = "0.10.0"
+itertools = "0.10.3"
 either = "1.6.1"
 
 stdx = { path = "../stdx", version = "0.0.0" }
@@ -25,4 +25,4 @@ hir = { path = "../hir", version = "0.0.0" }
 [dev-dependencies]
 test_utils = { path = "../test_utils" }
 sourcegen = { path = "../sourcegen" }
-expect-test = "1.2.0-pre.1"
+expect-test = "1.2.2"
diff --git a/crates/ide_assists/src/handlers/add_missing_match_arms.rs b/crates/ide_assists/src/handlers/add_missing_match_arms.rs
index 0dc67ede36..2070cca142 100644
--- a/crates/ide_assists/src/handlers/add_missing_match_arms.rs
+++ b/crates/ide_assists/src/handlers/add_missing_match_arms.rs
@@ -78,7 +78,7 @@ pub(crate) fn add_missing_match_arms(acc: &mut Assists, ctx: &AssistContext) ->
         Peekable<Box<dyn Iterator<Item = (ast::Pat, bool)>>>,
         bool,
     ) = if let Some(enum_def) = resolve_enum_def(&ctx.sema, &expr) {
-        let is_non_exhaustive = enum_def.is_non_exhaustive(ctx.db(), module.krate());
+        let is_non_exhaustive = enum_def.is_non_exhaustive(ctx.db());
 
         let variants = enum_def.variants(ctx.db());
 
@@ -104,7 +104,7 @@ pub(crate) fn add_missing_match_arms(acc: &mut Assists, ctx: &AssistContext) ->
         (missing_pats.peekable(), is_non_exhaustive)
     } else if let Some(enum_defs) = resolve_tuple_of_enum_def(&ctx.sema, &expr) {
         let is_non_exhaustive =
-            enum_defs.iter().any(|enum_def| enum_def.is_non_exhaustive(ctx.db(), module.krate()));
+            enum_defs.iter().any(|enum_def| enum_def.is_non_exhaustive(ctx.db()));
 
         let mut n_arms = 1;
         let variants_of_enums: Vec<Vec<ExtendedVariant>> = enum_defs
@@ -301,11 +301,9 @@ fn lift_enum(e: hir::Enum) -> ExtendedEnum {
 }
 
 impl ExtendedEnum {
-    fn is_non_exhaustive(self, db: &RootDatabase, krate: Crate) -> bool {
+    fn is_non_exhaustive(self, db: &RootDatabase) -> bool {
         match self {
-            ExtendedEnum::Enum(e) => {
-                e.attrs(db).by_key("non_exhaustive").exists() && e.module(db).krate() != krate
-            }
+            ExtendedEnum::Enum(e) => e.attrs(db).by_key("non_exhaustive").exists(),
             _ => false,
         }
     }
@@ -1659,32 +1657,8 @@ fn foo(t: E) {
     }
 
     #[test]
-    fn ignores_non_exhaustive_for_crate_local_enums() {
-        check_assist(
-            add_missing_match_arms,
-            r#"
-#[non_exhaustive]
-enum E { A, B, }
-
-fn foo(t: E) {
-    match $0t {
-    }
-}"#,
-            r#"
-#[non_exhaustive]
-enum E { A, B, }
-
-fn foo(t: E) {
-    match t {
-        $0E::A => todo!(),
-        E::B => todo!(),
-    }
-}"#,
-        );
-    }
-
-    #[test]
-    fn ignores_doc_hidden_and_non_exhaustive_for_crate_local_enums() {
+    fn ignores_doc_hidden_for_crate_local_enums_but_not_non_exhaustive() {
+        cov_mark::check!(added_wildcard_pattern);
         check_assist(
             add_missing_match_arms,
             r#"
@@ -1703,6 +1677,7 @@ fn foo(t: E) {
     match t {
         $0E::A => todo!(),
         E::B => todo!(),
+        _ => todo!(),
     }
 }"#,
         );
diff --git a/crates/ide_completion/Cargo.toml b/crates/ide_completion/Cargo.toml
index 5d8cad4389..e088e3815a 100644
--- a/crates/ide_completion/Cargo.toml
+++ b/crates/ide_completion/Cargo.toml
@@ -11,11 +11,11 @@ doctest = false
 
 [dependencies]
 cov-mark = "2.0.0-pre.1"
-itertools = "0.10.0"
+itertools = "0.10.3"
 rustc-hash = "1.1.0"
 either = "1.6.1"
-once_cell = "1.7"
-smallvec = "1.4"
+once_cell = "1.10.0"
+smallvec = "1.8.0"
 
 stdx = { path = "../stdx", version = "0.0.0" }
 syntax = { path = "../syntax", version = "0.0.0" }
@@ -29,6 +29,6 @@ profile = { path = "../profile", version = "0.0.0" }
 hir = { path = "../hir", version = "0.0.0" }
 
 [dev-dependencies]
-expect-test = "1.2.0-pre.1"
+expect-test = "1.2.2"
 
 test_utils = { path = "../test_utils" }
diff --git a/crates/ide_db/Cargo.toml b/crates/ide_db/Cargo.toml
index 26b51739cf..8c4fe95de1 100644
--- a/crates/ide_db/Cargo.toml
+++ b/crates/ide_db/Cargo.toml
@@ -11,15 +11,15 @@ doctest = false
 
 [dependencies]
 cov-mark = "2.0.0-pre.1"
-tracing = "0.1"
-rayon = "1.5.0"
-fst = { version = "0.4", default-features = false }
+tracing = "0.1.32"
+rayon = "1.5.1"
+fst = { version = "0.4.7", default-features = false }
 rustc-hash = "1.1.0"
-once_cell = "1.3.1"
+once_cell = "1.10.0"
 either = "1.6.1"
-itertools = "0.10.0"
-arrayvec = "0.7"
-indexmap = "1.7"
+itertools = "0.10.3"
+arrayvec = "0.7.2"
+indexmap = "1.8.0"
 
 stdx = { path = "../stdx", version = "0.0.0" }
 parser = { path = "../parser", version = "0.0.0" }
@@ -36,4 +36,4 @@ limit = { path = "../limit", version = "0.0.0" }
 test_utils = { path = "../test_utils" }
 sourcegen = { path = "../sourcegen" }
 xshell = "0.2.1"
-expect-test = "1.2.0-pre.1"
+expect-test = "1.2.2"
diff --git a/crates/ide_diagnostics/Cargo.toml b/crates/ide_diagnostics/Cargo.toml
index ba926c3719..3d3eba3ba4 100644
--- a/crates/ide_diagnostics/Cargo.toml
+++ b/crates/ide_diagnostics/Cargo.toml
@@ -11,9 +11,9 @@ doctest = false
 
 [dependencies]
 cov-mark = "2.0.0-pre.1"
-itertools = "0.10.0"
+itertools = "0.10.3"
 rustc-hash = "1.1.0"
-either = "1.5.3"
+either = "1.6.1"
 
 profile = { path = "../profile", version = "0.0.0" }
 stdx = { path = "../stdx", version = "0.0.0" }
@@ -24,7 +24,7 @@ hir = { path = "../hir", version = "0.0.0" }
 ide_db = { path = "../ide_db", version = "0.0.0" }
 
 [dev-dependencies]
-expect-test = "1.2.0-pre.1"
+expect-test = "1.2.2"
 
 test_utils = { path = "../test_utils" }
 sourcegen = { path = "../sourcegen" }
diff --git a/crates/ide_diagnostics/src/handlers/add_reference_here.rs b/crates/ide_diagnostics/src/handlers/add_reference_here.rs
new file mode 100644
index 0000000000..db24fd6cce
--- /dev/null
+++ b/crates/ide_diagnostics/src/handlers/add_reference_here.rs
@@ -0,0 +1,163 @@
+use hir::db::AstDatabase;
+use ide_db::source_change::SourceChange;
+use syntax::AstNode;
+use text_edit::TextEdit;
+
+use crate::{fix, Assist, Diagnostic, DiagnosticsContext};
+
+// Diagnostic: add-reference-here
+//
+// This diagnostic is triggered when there's a missing referencing of expression.
+pub(crate) fn add_reference_here(
+    ctx: &DiagnosticsContext<'_>,
+    d: &hir::AddReferenceHere,
+) -> Diagnostic {
+    Diagnostic::new(
+        "add-reference-here",
+        "add reference here",
+        ctx.sema.diagnostics_display_range(d.expr.clone().map(|it| it.into())).range,
+    )
+    .with_fixes(fixes(ctx, d))
+}
+
+fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::AddReferenceHere) -> Option<Vec<Assist>> {
+    let root = ctx.sema.db.parse_or_expand(d.expr.file_id)?;
+    let arg_expr = d.expr.value.to_node(&root);
+
+    let arg_with_ref = format!("&{}{}", d.mutability.as_keyword_for_ref(), arg_expr.syntax());
+
+    let arg_range = arg_expr.syntax().text_range();
+    let edit = TextEdit::replace(arg_range, arg_with_ref);
+    let source_change =
+        SourceChange::from_text_edit(d.expr.file_id.original_file(ctx.sema.db), edit);
+
+    Some(vec![fix("add_reference_here", "Add reference here", source_change, arg_range)])
+}
+
+#[cfg(test)]
+mod tests {
+    use crate::tests::{check_diagnostics, check_fix};
+
+    #[test]
+    fn missing_reference() {
+        check_diagnostics(
+            r#"
+fn main() {
+    test(123);
+       //^^^ 💡 error: add reference here
+}
+fn test(arg: &i32) {}
+"#,
+        );
+    }
+
+    #[test]
+    fn test_add_reference_to_int() {
+        check_fix(
+            r#"
+fn main() {
+    test(123$0);
+}
+fn test(arg: &i32) {}
+            "#,
+            r#"
+fn main() {
+    test(&123);
+}
+fn test(arg: &i32) {}
+            "#,
+        );
+    }
+
+    #[test]
+    fn test_add_mutable_reference_to_int() {
+        check_fix(
+            r#"
+fn main() {
+    test($0123);
+}
+fn test(arg: &mut i32) {}
+            "#,
+            r#"
+fn main() {
+    test(&mut 123);
+}
+fn test(arg: &mut i32) {}
+            "#,
+        );
+    }
+
+    #[test]
+    fn test_add_reference_to_array() {
+        check_fix(
+            r#"
+fn main() {
+    test($0[1, 2, 3]);
+}
+fn test(arg: &[i32]) {}
+            "#,
+            r#"
+fn main() {
+    test(&[1, 2, 3]);
+}
+fn test(arg: &[i32]) {}
+            "#,
+        );
+    }
+
+    #[test]
+    fn test_add_reference_to_method_call() {
+        check_fix(
+            r#"
+fn main() {
+    Test.call_by_ref($0123);
+}
+struct Test;
+impl Test {
+    fn call_by_ref(&self, arg: &i32) {}
+}
+            "#,
+            r#"
+fn main() {
+    Test.call_by_ref(&123);
+}
+struct Test;
+impl Test {
+    fn call_by_ref(&self, arg: &i32) {}
+}
+            "#,
+        );
+    }
+
+    #[test]
+    fn test_add_reference_to_let_stmt() {
+        check_fix(
+            r#"
+fn main() {
+    let test: &i32 = $0123;
+}
+            "#,
+            r#"
+fn main() {
+    let test: &i32 = &123;
+}
+            "#,
+        );
+    }
+
+    #[test]
+    fn test_add_mutable_reference_to_let_stmt() {
+        check_fix(
+            r#"
+fn main() {
+    let test: &mut i32 = $0123;
+}
+            "#,
+            r#"
+fn main() {
+    let test: &mut i32 = &mut 123;
+}
+            "#,
+        );
+    }
+}
diff --git a/crates/ide_diagnostics/src/handlers/field_shorthand.rs b/crates/ide_diagnostics/src/handlers/field_shorthand.rs
index 2b71053625..33152e2845 100644
--- a/crates/ide_diagnostics/src/handlers/field_shorthand.rs
+++ b/crates/ide_diagnostics/src/handlers/field_shorthand.rs
@@ -108,13 +108,13 @@ mod tests {
         check_diagnostics(
             r#"
 struct A { a: &'static str }
-fn main() { A { a: "hello" }; }
+fn main() { A { a: "hello" } }
 "#,
         );
         check_diagnostics(
             r#"
 struct A(usize);
-fn main() { A { 0: 0 }; }
+fn main() { A { 0: 0 } }
 "#,
         );
 
@@ -123,14 +123,14 @@ fn main() { A { 0: 0 }; }
 struct A { a: &'static str }
 fn main() {
     let a = "haha";
-    A { a$0: a };
+    A { a$0: a }
 }
 "#,
             r#"
 struct A { a: &'static str }
 fn main() {
     let a = "haha";
-    A { a };
+    A { a }
 }
 "#,
         );
@@ -141,7 +141,7 @@ struct A { a: &'static str, b: &'static str }
 fn main() {
     let a = "haha";
     let b = "bb";
-    A { a$0: a, b };
+    A { a$0: a, b }
 }
 "#,
             r#"
@@ -149,7 +149,7 @@ struct A { a: &'static str, b: &'static str }
 fn main() {
     let a = "haha";
     let b = "bb";
-    A { a, b };
+    A { a, b }
 }
 "#,
         );
diff --git a/crates/ide_diagnostics/src/handlers/missing_match_arms.rs b/crates/ide_diagnostics/src/handlers/missing_match_arms.rs
index fe6a8683c1..6bdcd41a79 100644
--- a/crates/ide_diagnostics/src/handlers/missing_match_arms.rs
+++ b/crates/ide_diagnostics/src/handlers/missing_match_arms.rs
@@ -278,7 +278,6 @@ fn main() {
     match (true, false) {
         (true, false, true) => (),
         (true) => (),
-      // ^^^^  error: expected (bool, bool), found bool
     }
     match (true, false) { (true,) => {} }
     match (0) { () => () }
diff --git a/crates/ide_diagnostics/src/handlers/missing_ok_or_some_in_tail_expr.rs b/crates/ide_diagnostics/src/handlers/missing_ok_or_some_in_tail_expr.rs
new file mode 100644
index 0000000000..d5635ba8ba
--- /dev/null
+++ b/crates/ide_diagnostics/src/handlers/missing_ok_or_some_in_tail_expr.rs
@@ -0,0 +1,223 @@
+use hir::{db::AstDatabase, TypeInfo};
+use ide_db::{
+    assists::Assist, source_change::SourceChange, syntax_helpers::node_ext::for_each_tail_expr,
+};
+use syntax::AstNode;
+use text_edit::TextEdit;
+
+use crate::{fix, Diagnostic, DiagnosticsContext};
+
+// Diagnostic: missing-ok-or-some-in-tail-expr
+//
+// This diagnostic is triggered if a block that should return `Result` returns a value not wrapped in `Ok`,
+// or if a block that should return `Option` returns a value not wrapped in `Some`.
+//
+// Example:
+//
+// ```rust
+// fn foo() -> Result<u8, ()> {
+//     10
+// }
+// ```
+pub(crate) fn missing_ok_or_some_in_tail_expr(
+    ctx: &DiagnosticsContext<'_>,
+    d: &hir::MissingOkOrSomeInTailExpr,
+) -> Diagnostic {
+    Diagnostic::new(
+        "missing-ok-or-some-in-tail-expr",
+        format!("wrap return expression in {}", d.required),
+        ctx.sema.diagnostics_display_range(d.expr.clone().map(|it| it.into())).range,
+    )
+    .with_fixes(fixes(ctx, d))
+}
+
+fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::MissingOkOrSomeInTailExpr) -> Option<Vec<Assist>> {
+    let root = ctx.sema.db.parse_or_expand(d.expr.file_id)?;
+    let tail_expr = d.expr.value.to_node(&root);
+    let tail_expr_range = tail_expr.syntax().text_range();
+    let mut builder = TextEdit::builder();
+    for_each_tail_expr(&tail_expr, &mut |expr| {
+        if ctx.sema.type_of_expr(expr).map(TypeInfo::original).as_ref() != Some(&d.expected) {
+            builder.insert(expr.syntax().text_range().start(), format!("{}(", d.required));
+            builder.insert(expr.syntax().text_range().end(), ")".to_string());
+        }
+    });
+    let source_change =
+        SourceChange::from_text_edit(d.expr.file_id.original_file(ctx.sema.db), builder.finish());
+    let name = if d.required == "Ok" { "Wrap with Ok" } else { "Wrap with Some" };
+    Some(vec![fix("wrap_tail_expr", name, source_change, tail_expr_range)])
+}
+
+#[cfg(test)]
+mod tests {
+    use crate::tests::{check_diagnostics, check_fix};
+
+    #[test]
+    fn test_wrap_return_type_option() {
+        check_fix(
+            r#"
+//- minicore: option, result
+fn div(x: i32, y: i32) -> Option<i32> {
+    if y == 0 {
+        return None;
+    }
+    x / y$0
+}
+"#,
+            r#"
+fn div(x: i32, y: i32) -> Option<i32> {
+    if y == 0 {
+        return None;
+    }
+    Some(x / y)
+}
+"#,
+        );
+    }
+
+    #[test]
+    fn test_wrap_return_type_option_tails() {
+        check_fix(
+            r#"
+//- minicore: option, result
+fn div(x: i32, y: i32) -> Option<i32> {
+    if y == 0 {
+        0
+    } else if true {
+        100
+    } else {
+        None
+    }$0
+}
+"#,
+            r#"
+fn div(x: i32, y: i32) -> Option<i32> {
+    if y == 0 {
+        Some(0)
+    } else if true {
+        Some(100)
+    } else {
+        None
+    }
+}
+"#,
+        );
+    }
+
+    #[test]
+    fn test_wrap_return_type() {
+        check_fix(
+            r#"
+//- minicore: option, result
+fn div(x: i32, y: i32) -> Result<i32, ()> {
+    if y == 0 {
+        return Err(());
+    }
+    x / y$0
+}
+"#,
+            r#"
+fn div(x: i32, y: i32) -> Result<i32, ()> {
+    if y == 0 {
+        return Err(());
+    }
+    Ok(x / y)
+}
+"#,
+        );
+    }
+
+    #[test]
+    fn test_wrap_return_type_handles_generic_functions() {
+        check_fix(
+            r#"
+//- minicore: option, result
+fn div<T>(x: T) -> Result<T, i32> {
+    if x == 0 {
+        return Err(7);
+    }
+    $0x
+}
+"#,
+            r#"
+fn div<T>(x: T) -> Result<T, i32> {
+    if x == 0 {
+        return Err(7);
+    }
+    Ok(x)
+}
+"#,
+        );
+    }
+
+    #[test]
+    fn test_wrap_return_type_handles_type_aliases() {
+        check_fix(
+            r#"
+//- minicore: option, result
+type MyResult<T> = Result<T, ()>;
+
+fn div(x: i32, y: i32) -> MyResult<i32> {
+    if y == 0 {
+        return Err(());
+    }
+    x $0/ y
+}
+"#,
+            r#"
+type MyResult<T> = Result<T, ()>;
+
+fn div(x: i32, y: i32) -> MyResult<i32> {
+    if y == 0 {
+        return Err(());
+    }
+    Ok(x / y)
+}
+"#,
+        );
+    }
+
+    #[test]
+    fn test_in_const_and_static() {
+        check_fix(
+            r#"
+//- minicore: option, result
+static A: Option<()> = {($0)};
+            "#,
+            r#"
+static A: Option<()> = {Some(())};
+            "#,
+        );
+        check_fix(
+            r#"
+//- minicore: option, result
+const _: Option<()> = {($0)};
+            "#,
+            r#"
+const _: Option<()> = {Some(())};
+            "#,
+        );
+    }
+
+    #[test]
+    fn test_wrap_return_type_not_applicable_when_expr_type_does_not_match_ok_type() {
+        check_diagnostics(
+            r#"
+//- minicore: option, result
+fn foo() -> Result<(), i32> { 0 }
+"#,
+        );
+    }
+
+    #[test]
+    fn test_wrap_return_type_not_applicable_when_return_type_is_not_result_or_option() {
+        check_diagnostics(
+            r#"
+//- minicore: option, result
+enum SomeOtherEnum { Ok(i32), Err(String) }
+
+fn foo() -> SomeOtherEnum { 0 }
+"#,
+        );
+    }
+}
diff --git a/crates/ide_diagnostics/src/handlers/remove_this_semicolon.rs b/crates/ide_diagnostics/src/handlers/remove_this_semicolon.rs
new file mode 100644
index 0000000000..141fbc42fa
--- /dev/null
+++ b/crates/ide_diagnostics/src/handlers/remove_this_semicolon.rs
@@ -0,0 +1,76 @@
+use ide_db::{
+    base_db::{FileLoader, FileRange},
+    source_change::SourceChange,
+};
+use syntax::{TextRange, TextSize};
+use text_edit::TextEdit;
+
+use crate::{fix, Assist, Diagnostic, DiagnosticsContext};
+
+// Diagnostic: remove-this-semicolon
+//
+// This diagnostic is triggered when there's an erroneous `;` at the end of the block.
+pub(crate) fn remove_this_semicolon(
+    ctx: &DiagnosticsContext<'_>,
+    d: &hir::RemoveThisSemicolon,
+) -> Diagnostic {
+    Diagnostic::new(
+        "remove-this-semicolon",
+        "remove this semicolon",
+        semicolon_range(ctx, d).unwrap_or_else(|it| it).range,
+    )
+    .with_fixes(fixes(ctx, d))
+}
+
+fn semicolon_range(
+    ctx: &DiagnosticsContext<'_>,
+    d: &hir::RemoveThisSemicolon,
+) -> Result<FileRange, FileRange> {
+    let expr_range = ctx.sema.diagnostics_display_range(d.expr.clone().map(|it| it.into()));
+    let file_text = ctx.sema.db.file_text(expr_range.file_id);
+    let range_end: usize = expr_range.range.end().into();
+    // FIXME: This doesn't handle whitespace and comments, but handling those in
+    // the presence of macros might prove tricky...
+    if file_text[range_end..].starts_with(';') {
+        Ok(FileRange {
+            file_id: expr_range.file_id,
+            range: TextRange::at(expr_range.range.end(), TextSize::of(';')),
+        })
+    } else {
+        Err(expr_range)
+    }
+}
+
+fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::RemoveThisSemicolon) -> Option<Vec<Assist>> {
+    let semicolon_range = semicolon_range(ctx, d).ok()?;
+
+    let edit = TextEdit::delete(semicolon_range.range);
+    let source_change = SourceChange::from_text_edit(semicolon_range.file_id, edit);
+
+    Some(vec![fix(
+        "remove_semicolon",
+        "Remove this semicolon",
+        source_change,
+        semicolon_range.range,
+    )])
+}
+
+#[cfg(test)]
+mod tests {
+    use crate::tests::{check_diagnostics, check_fix};
+
+    #[test]
+    fn missing_semicolon() {
+        check_diagnostics(
+            r#"
+fn test() -> i32 { 123; }
+                    //^ 💡 error: remove this semicolon
+"#,
+        );
+    }
+
+    #[test]
+    fn remove_semicolon() {
+        check_fix(r#"fn f() -> i32 { 92$0; }"#, r#"fn f() -> i32 { 92 }"#);
+    }
+}
diff --git a/crates/ide_diagnostics/src/handlers/type_mismatch.rs b/crates/ide_diagnostics/src/handlers/type_mismatch.rs
deleted file mode 100644
index 040dcbd1d9..0000000000
--- a/crates/ide_diagnostics/src/handlers/type_mismatch.rs
+++ /dev/null
@@ -1,476 +0,0 @@
-use hir::{db::AstDatabase, HirDisplay, Type, TypeInfo};
-use ide_db::{
-    famous_defs::FamousDefs, source_change::SourceChange,
-    syntax_helpers::node_ext::for_each_tail_expr,
-};
-use syntax::{
-    ast::{BlockExpr, ExprStmt},
-    AstNode,
-};
-use text_edit::TextEdit;
-
-use crate::{fix, Assist, Diagnostic, DiagnosticsContext};
-
-// Diagnostic: type-mismatch
-//
-// This diagnostic is triggered when the type of an expression does not match
-// the expected type.
-pub(crate) fn type_mismatch(ctx: &DiagnosticsContext<'_>, d: &hir::TypeMismatch) -> Diagnostic {
-    let mut diag = Diagnostic::new(
-        "type-mismatch",
-        format!(
-            "expected {}, found {}",
-            d.expected.display(ctx.sema.db),
-            d.actual.display(ctx.sema.db)
-        ),
-        ctx.sema.diagnostics_display_range(d.expr.clone().map(|it| it.into())).range,
-    )
-    .with_fixes(fixes(ctx, d));
-    if diag.fixes.is_none() {
-        diag.experimental = true;
-    }
-    diag
-}
-
-fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::TypeMismatch) -> Option<Vec<Assist>> {
-    let mut fixes = Vec::new();
-
-    add_reference(ctx, d, &mut fixes);
-    add_missing_ok_or_some(ctx, d, &mut fixes);
-    remove_semicolon(ctx, d, &mut fixes);
-
-    if fixes.is_empty() {
-        None
-    } else {
-        Some(fixes)
-    }
-}
-
-fn add_reference(
-    ctx: &DiagnosticsContext<'_>,
-    d: &hir::TypeMismatch,
-    acc: &mut Vec<Assist>,
-) -> Option<()> {
-    let root = ctx.sema.db.parse_or_expand(d.expr.file_id)?;
-    let expr_node = d.expr.value.to_node(&root);
-
-    let range = ctx.sema.diagnostics_display_range(d.expr.clone().map(|it| it.into())).range;
-
-    let (_, mutability) = d.expected.as_reference()?;
-    let actual_with_ref = Type::reference(&d.actual, mutability);
-    if !actual_with_ref.could_coerce_to(ctx.sema.db, &d.expected) {
-        return None;
-    }
-
-    let ampersands = format!("&{}", mutability.as_keyword_for_ref());
-
-    let edit = TextEdit::insert(expr_node.syntax().text_range().start(), ampersands);
-    let source_change =
-        SourceChange::from_text_edit(d.expr.file_id.original_file(ctx.sema.db), edit);
-    acc.push(fix("add_reference_here", "Add reference here", source_change, range));
-    Some(())
-}
-
-fn add_missing_ok_or_some(
-    ctx: &DiagnosticsContext<'_>,
-    d: &hir::TypeMismatch,
-    acc: &mut Vec<Assist>,
-) -> Option<()> {
-    let root = ctx.sema.db.parse_or_expand(d.expr.file_id)?;
-    let tail_expr = d.expr.value.to_node(&root);
-    let tail_expr_range = tail_expr.syntax().text_range();
-    let scope = ctx.sema.scope(tail_expr.syntax());
-
-    let expected_adt = d.expected.as_adt()?;
-    let expected_enum = expected_adt.as_enum()?;
-
-    let famous_defs = FamousDefs(&ctx.sema, scope.krate());
-    let core_result = famous_defs.core_result_Result();
-    let core_option = famous_defs.core_option_Option();
-
-    if Some(expected_enum) != core_result && Some(expected_enum) != core_option {
-        return None;
-    }
-
-    let variant_name = if Some(expected_enum) == core_result { "Ok" } else { "Some" };
-
-    let wrapped_actual_ty = expected_adt.ty_with_args(ctx.sema.db, &[d.actual.clone()]);
-
-    if !d.expected.could_unify_with(ctx.sema.db, &wrapped_actual_ty) {
-        return None;
-    }
-
-    let mut builder = TextEdit::builder();
-    for_each_tail_expr(&tail_expr, &mut |expr| {
-        if ctx.sema.type_of_expr(expr).map(TypeInfo::adjusted).as_ref() != Some(&d.expected) {
-            builder.insert(expr.syntax().text_range().start(), format!("{}(", variant_name));
-            builder.insert(expr.syntax().text_range().end(), ")".to_string());
-        }
-    });
-    let source_change =
-        SourceChange::from_text_edit(d.expr.file_id.original_file(ctx.sema.db), builder.finish());
-    let name = format!("Wrap in {}", variant_name);
-    acc.push(fix("wrap_tail_expr", &name, source_change, tail_expr_range));
-    Some(())
-}
-
-fn remove_semicolon(
-    ctx: &DiagnosticsContext<'_>,
-    d: &hir::TypeMismatch,
-    acc: &mut Vec<Assist>,
-) -> Option<()> {
-    let root = ctx.sema.db.parse_or_expand(d.expr.file_id)?;
-    let expr = d.expr.value.to_node(&root);
-    if !d.actual.is_unit() {
-        return None;
-    }
-    let block = BlockExpr::cast(expr.syntax().clone())?;
-    let expr_before_semi =
-        block.statements().last().and_then(|s| ExprStmt::cast(s.syntax().clone()))?;
-    let type_before_semi = ctx.sema.type_of_expr(&expr_before_semi.expr()?)?.original();
-    if !type_before_semi.could_coerce_to(ctx.sema.db, &d.expected) {
-        return None;
-    }
-    let semicolon_range = expr_before_semi.semicolon_token()?.text_range();
-
-    let edit = TextEdit::delete(semicolon_range);
-    let source_change =
-        SourceChange::from_text_edit(d.expr.file_id.original_file(ctx.sema.db), edit);
-
-    acc.push(fix("remove_semicolon", "Remove this semicolon", source_change, semicolon_range));
-    Some(())
-}
-
-#[cfg(test)]
-mod tests {
-    use crate::tests::{check_diagnostics, check_fix, check_no_fix};
-
-    #[test]
-    fn missing_reference() {
-        check_diagnostics(
-            r#"
-fn main() {
-    test(123);
-       //^^^ 💡 error: expected &i32, found i32
-}
-fn test(arg: &i32) {}
-"#,
-        );
-    }
-
-    #[test]
-    fn test_add_reference_to_int() {
-        check_fix(
-            r#"
-fn main() {
-    test(123$0);
-}
-fn test(arg: &i32) {}
-            "#,
-            r#"
-fn main() {
-    test(&123);
-}
-fn test(arg: &i32) {}
-            "#,
-        );
-    }
-
-    #[test]
-    fn test_add_mutable_reference_to_int() {
-        check_fix(
-            r#"
-fn main() {
-    test($0123);
-}
-fn test(arg: &mut i32) {}
-            "#,
-            r#"
-fn main() {
-    test(&mut 123);
-}
-fn test(arg: &mut i32) {}
-            "#,
-        );
-    }
-
-    #[test]
-    fn test_add_reference_to_array() {
-        check_fix(
-            r#"
-//- minicore: coerce_unsized
-fn main() {
-    test($0[1, 2, 3]);
-}
-fn test(arg: &[i32]) {}
-            "#,
-            r#"
-fn main() {
-    test(&[1, 2, 3]);
-}
-fn test(arg: &[i32]) {}
-            "#,
-        );
-    }
-
-    #[test]
-    fn test_add_reference_with_autoderef() {
-        check_fix(
-            r#"
-//- minicore: coerce_unsized, deref
-struct Foo;
-struct Bar;
-impl core::ops::Deref for Foo {
-    type Target = Bar;
-}
-
-fn main() {
-    test($0Foo);
-}
-fn test(arg: &Bar) {}
-            "#,
-            r#"
-struct Foo;
-struct Bar;
-impl core::ops::Deref for Foo {
-    type Target = Bar;
-}
-
-fn main() {
-    test(&Foo);
-}
-fn test(arg: &Bar) {}
-            "#,
-        );
-    }
-
-    #[test]
-    fn test_add_reference_to_method_call() {
-        check_fix(
-            r#"
-fn main() {
-    Test.call_by_ref($0123);
-}
-struct Test;
-impl Test {
-    fn call_by_ref(&self, arg: &i32) {}
-}
-            "#,
-            r#"
-fn main() {
-    Test.call_by_ref(&123);
-}
-struct Test;
-impl Test {
-    fn call_by_ref(&self, arg: &i32) {}
-}
-            "#,
-        );
-    }
-
-    #[test]
-    fn test_add_reference_to_let_stmt() {
-        check_fix(
-            r#"
-fn main() {
-    let test: &i32 = $0123;
-}
-            "#,
-            r#"
-fn main() {
-    let test: &i32 = &123;
-}
-            "#,
-        );
-    }
-
-    #[test]
-    fn test_add_mutable_reference_to_let_stmt() {
-        check_fix(
-            r#"
-fn main() {
-    let test: &mut i32 = $0123;
-}
-            "#,
-            r#"
-fn main() {
-    let test: &mut i32 = &mut 123;
-}
-            "#,
-        );
-    }
-
-    #[test]
-    fn test_wrap_return_type_option() {
-        check_fix(
-            r#"
-//- minicore: option, result
-fn div(x: i32, y: i32) -> Option<i32> {
-    if y == 0 {
-        return None;
-    }
-    x / y$0
-}
-"#,
-            r#"
-fn div(x: i32, y: i32) -> Option<i32> {
-    if y == 0 {
-        return None;
-    }
-    Some(x / y)
-}
-"#,
-        );
-    }
-
-    #[test]
-    fn test_wrap_return_type_option_tails() {
-        check_fix(
-            r#"
-//- minicore: option, result
-fn div(x: i32, y: i32) -> Option<i32> {
-    if y == 0 {
-        0
-    } else if true {
-        100
-    } else {
-        None
-    }$0
-}
-"#,
-            r#"
-fn div(x: i32, y: i32) -> Option<i32> {
-    if y == 0 {
-        Some(0)
-    } else if true {
-        Some(100)
-    } else {
-        None
-    }
-}
-"#,
-        );
-    }
-
-    #[test]
-    fn test_wrap_return_type() {
-        check_fix(
-            r#"
-//- minicore: option, result
-fn div(x: i32, y: i32) -> Result<i32, ()> {
-    if y == 0 {
-        return Err(());
-    }
-    x / y$0
-}
-"#,
-            r#"
-fn div(x: i32, y: i32) -> Result<i32, ()> {
-    if y == 0 {
-        return Err(());
-    }
-    Ok(x / y)
-}
-"#,
-        );
-    }
-
-    #[test]
-    fn test_wrap_return_type_handles_generic_functions() {
-        check_fix(
-            r#"
-//- minicore: option, result
-fn div<T>(x: T) -> Result<T, i32> {
-    if x == 0 {
-        return Err(7);
-    }
-    $0x
-}
-"#,
-            r#"
-fn div<T>(x: T) -> Result<T, i32> {
-    if x == 0 {
-        return Err(7);
-    }
-    Ok(x)
-}
-"#,
-        );
-    }
-
-    #[test]
-    fn test_wrap_return_type_handles_type_aliases() {
-        check_fix(
-            r#"
-//- minicore: option, result
-type MyResult<T> = Result<T, ()>;
-
-fn div(x: i32, y: i32) -> MyResult<i32> {
-    if y == 0 {
-        return Err(());
-    }
-    x $0/ y
-}
-"#,
-            r#"
-type MyResult<T> = Result<T, ()>;
-
-fn div(x: i32, y: i32) -> MyResult<i32> {
-    if y == 0 {
-        return Err(());
-    }
-    Ok(x / y)
-}
-"#,
-        );
-    }
-
-    #[test]
-    fn test_in_const_and_static() {
-        check_fix(
-            r#"
-//- minicore: option, result
-static A: Option<()> = {($0)};
-            "#,
-            r#"
-static A: Option<()> = {Some(())};
-            "#,
-        );
-        check_fix(
-            r#"
-//- minicore: option, result
-const _: Option<()> = {($0)};
-            "#,
-            r#"
-const _: Option<()> = {Some(())};
-            "#,
-        );
-    }
-
-    #[test]
-    fn test_wrap_return_type_not_applicable_when_expr_type_does_not_match_ok_type() {
-        check_no_fix(
-            r#"
-//- minicore: option, result
-fn foo() -> Result<(), i32> { 0$0 }
-"#,
-        );
-    }
-
-    #[test]
-    fn test_wrap_return_type_not_applicable_when_return_type_is_not_result_or_option() {
-        check_no_fix(
-            r#"
-//- minicore: option, result
-enum SomeOtherEnum { Ok(i32), Err(String) }
-
-fn foo() -> SomeOtherEnum { 0$0 }
-"#,
-        );
-    }
-
-    #[test]
-    fn remove_semicolon() {
-        check_fix(r#"fn f() -> i32 { 92$0; }"#, r#"fn f() -> i32 { 92 }"#);
-    }
-}
diff --git a/crates/ide_diagnostics/src/lib.rs b/crates/ide_diagnostics/src/lib.rs
index 13ac0a2450..86d76751ad 100644
--- a/crates/ide_diagnostics/src/lib.rs
+++ b/crates/ide_diagnostics/src/lib.rs
@@ -24,6 +24,7 @@
 //! don't yet have a great pattern for how to do them properly.
 
 mod handlers {
+    pub(crate) mod add_reference_here;
     pub(crate) mod break_outside_of_loop;
     pub(crate) mod inactive_code;
     pub(crate) mod incorrect_case;
@@ -33,10 +34,11 @@ mod handlers {
     pub(crate) mod mismatched_arg_count;
     pub(crate) mod missing_fields;
     pub(crate) mod missing_match_arms;
+    pub(crate) mod missing_ok_or_some_in_tail_expr;
     pub(crate) mod missing_unsafe;
     pub(crate) mod no_such_field;
+    pub(crate) mod remove_this_semicolon;
     pub(crate) mod replace_filter_map_next_with_find_map;
-    pub(crate) mod type_mismatch;
     pub(crate) mod unimplemented_builtin_macro;
     pub(crate) mod unresolved_extern_crate;
     pub(crate) mod unresolved_import;
@@ -189,6 +191,7 @@ pub fn diagnostics(
     for diag in diags {
         #[rustfmt::skip]
         let d = match diag {
+            AnyDiagnostic::AddReferenceHere(d) => handlers::add_reference_here::add_reference_here(&ctx, &d),
             AnyDiagnostic::BreakOutsideOfLoop(d) => handlers::break_outside_of_loop::break_outside_of_loop(&ctx, &d),
             AnyDiagnostic::IncorrectCase(d) => handlers::incorrect_case::incorrect_case(&ctx, &d),
             AnyDiagnostic::MacroError(d) => handlers::macro_error::macro_error(&ctx, &d),
@@ -196,10 +199,11 @@ pub fn diagnostics(
             AnyDiagnostic::MismatchedArgCount(d) => handlers::mismatched_arg_count::mismatched_arg_count(&ctx, &d),
             AnyDiagnostic::MissingFields(d) => handlers::missing_fields::missing_fields(&ctx, &d),
             AnyDiagnostic::MissingMatchArms(d) => handlers::missing_match_arms::missing_match_arms(&ctx, &d),
+            AnyDiagnostic::MissingOkOrSomeInTailExpr(d) => handlers::missing_ok_or_some_in_tail_expr::missing_ok_or_some_in_tail_expr(&ctx, &d),
             AnyDiagnostic::MissingUnsafe(d) => handlers::missing_unsafe::missing_unsafe(&ctx, &d),
             AnyDiagnostic::NoSuchField(d) => handlers::no_such_field::no_such_field(&ctx, &d),
+            AnyDiagnostic::RemoveThisSemicolon(d) => handlers::remove_this_semicolon::remove_this_semicolon(&ctx, &d),
             AnyDiagnostic::ReplaceFilterMapNextWithFindMap(d) => handlers::replace_filter_map_next_with_find_map::replace_filter_map_next_with_find_map(&ctx, &d),
-            AnyDiagnostic::TypeMismatch(d) => handlers::type_mismatch::type_mismatch(&ctx, &d),
             AnyDiagnostic::UnimplementedBuiltinMacro(d) => handlers::unimplemented_builtin_macro::unimplemented_builtin_macro(&ctx, &d),
             AnyDiagnostic::UnresolvedExternCrate(d) => handlers::unresolved_extern_crate::unresolved_extern_crate(&ctx, &d),
             AnyDiagnostic::UnresolvedImport(d) => handlers::unresolved_import::unresolved_import(&ctx, &d),
diff --git a/crates/ide_ssr/Cargo.toml b/crates/ide_ssr/Cargo.toml
index a725f7847c..9135857c38 100644
--- a/crates/ide_ssr/Cargo.toml
+++ b/crates/ide_ssr/Cargo.toml
@@ -13,7 +13,7 @@ doctest = false
 [dependencies]
 cov-mark = "2.0.0-pre.1"
 rustc-hash = "1.1.0"
-itertools = "0.10.0"
+itertools = "0.10.3"
 
 text_edit = { path = "../text_edit", version = "0.0.0" }
 parser = { path = "../parser", version = "0.0.0" }
@@ -23,4 +23,4 @@ hir = { path = "../hir", version = "0.0.0" }
 
 [dev-dependencies]
 test_utils = { path = "../test_utils" }
-expect-test = "1.2.0-pre.1"
+expect-test = "1.2.2"
diff --git a/crates/mbe/Cargo.toml b/crates/mbe/Cargo.toml
index c29c570bf5..1453ec4c69 100644
--- a/crates/mbe/Cargo.toml
+++ b/crates/mbe/Cargo.toml
@@ -12,8 +12,8 @@ doctest = false
 [dependencies]
 cov-mark = "2.0.0-pre.1"
 rustc-hash = "1.1.0"
-smallvec = "1.2.0"
-tracing = "0.1"
+smallvec = "1.8.0"
+tracing = "0.1.32"
 
 syntax = { path = "../syntax", version = "0.0.0" }
 parser = { path = "../parser", version = "0.0.0" }
diff --git a/crates/parser/Cargo.toml b/crates/parser/Cargo.toml
index 0a5f923305..8105b536b7 100644
--- a/crates/parser/Cargo.toml
+++ b/crates/parser/Cargo.toml
@@ -10,11 +10,10 @@ rust-version = "1.57"
 doctest = false
 
 [dependencies]
-drop_bomb = "0.1.4"
+drop_bomb = "0.1.5"
 rustc_lexer = { version = "725.0.0", package = "rustc-ap-rustc_lexer" }
 limit = { path = "../limit", version = "0.0.0" }
 
 [dev-dependencies]
-expect-test = "1.2"
+expect-test = "1.2.2"
 sourcegen = { path = "../sourcegen" }
-
diff --git a/crates/proc_macro_api/Cargo.toml b/crates/proc_macro_api/Cargo.toml
index fde5b80141..000c23dab6 100644
--- a/crates/proc_macro_api/Cargo.toml
+++ b/crates/proc_macro_api/Cargo.toml
@@ -10,18 +10,18 @@ rust-version = "1.57"
 doctest = false
 
 [dependencies]
-object = { version = "0.28", default-features = false, features = [
+object = { version = "0.28.3", default-features = false, features = [
     "std",
     "read_core",
     "elf",
     "macho",
     "pe",
 ] }
-serde = { version = "1.0", features = ["derive"] }
-serde_json = { version = "1.0", features = ["unbounded_depth"] }
-tracing = "0.1"
-memmap2 = "0.5"
-snap = "1.0"
+serde = { version = "1.0.136", features = ["derive"] }
+serde_json = { version = "1.0.79", features = ["unbounded_depth"] }
+tracing = "0.1.32"
+memmap2 = "0.5.3"
+snap = "1.0.5"
 
 paths = { path = "../paths", version = "0.0.0" }
 tt = { path = "../tt", version = "0.0.0" }
diff --git a/crates/proc_macro_srv/Cargo.toml b/crates/proc_macro_srv/Cargo.toml
index 28e759cd87..381d241b86 100644
--- a/crates/proc_macro_srv/Cargo.toml
+++ b/crates/proc_macro_srv/Cargo.toml
@@ -10,15 +10,15 @@ rust-version = "1.57"
 doctest = false
 
 [dependencies]
-object = { version = "0.28", default-features = false, features = [
+object = { version = "0.28.3", default-features = false, features = [
     "std",
     "read_core",
     "elf",
     "macho",
     "pe",
 ] }
-libloading = "0.7.0"
-memmap2 = "0.5"
+libloading = "0.7.3"
+memmap2 = "0.5.3"
 
 tt = { path = "../tt", version = "0.0.0" }
 mbe = { path = "../mbe", version = "0.0.0" }
@@ -26,7 +26,7 @@ paths = { path = "../paths", version = "0.0.0" }
 proc_macro_api = { path = "../proc_macro_api", version = "0.0.0" }
 
 [dev-dependencies]
-expect-test = "1.2.0-pre.1"
+expect-test = "1.2.2"
 
 # used as proc macro test targets
 proc_macro_test = { path = "../proc_macro_test" }
diff --git a/crates/profile/Cargo.toml b/crates/profile/Cargo.toml
index 51eeea30d2..8324f48de9 100644
--- a/crates/profile/Cargo.toml
+++ b/crates/profile/Cargo.toml
@@ -10,18 +10,18 @@ rust-version = "1.57"
 doctest = false
 
 [dependencies]
-once_cell = "1.3.1"
-cfg-if = "1"
-libc = "0.2"
+once_cell = "1.10.0"
+cfg-if = "1.0.0"
+libc = "0.2.121"
 la-arena = { version = "0.3.0", path = "../../lib/arena" }
-countme = { version = "3.0", features = ["enable"] }
-jemalloc-ctl = { version = "0.4.1", package = "tikv-jemalloc-ctl", optional = true }
+countme = { version = "3.0.1", features = ["enable"] }
+jemalloc-ctl = { version = "0.4.2", package = "tikv-jemalloc-ctl", optional = true }
 
 [target.'cfg(target_os = "linux")'.dependencies]
-perf-event = "0.4"
+perf-event = "0.4.7"
 
 [target.'cfg(windows)'.dependencies]
-winapi = { version = "0.3.8", features = ["processthreadsapi", "psapi"] }
+winapi = { version = "0.3.9", features = ["processthreadsapi", "psapi"] }
 
 [features]
 cpu_profiler = []
diff --git a/crates/project_model/Cargo.toml b/crates/project_model/Cargo.toml
index 4932e7d012..abb21586da 100644
--- a/crates/project_model/Cargo.toml
+++ b/crates/project_model/Cargo.toml
@@ -10,14 +10,14 @@ rust-version = "1.57"
 doctest = false
 
 [dependencies]
-tracing = "0.1"
+tracing = "0.1.32"
 rustc-hash = "1.1.0"
-cargo_metadata = "0.14"
-semver = "1"
-serde = { version = "1.0.106", features = ["derive"] }
-serde_json = "1.0.48"
-anyhow = "1.0.26"
-expect-test = "1.2.0-pre.1"
+cargo_metadata = "0.14.2"
+semver = "1.0.6"
+serde = { version = "1.0.136", features = ["derive"] }
+serde_json = "1.0.79"
+anyhow = "1.0.56"
+expect-test = "1.2.2"
 la-arena = { version = "0.3.0", path = "../../lib/arena" }
 
 cfg = { path = "../cfg", version = "0.0.0" }
diff --git a/crates/rust-analyzer/Cargo.toml b/crates/rust-analyzer/Cargo.toml
index 079e56c9fa..87b4203e51 100644
--- a/crates/rust-analyzer/Cargo.toml
+++ b/crates/rust-analyzer/Cargo.toml
@@ -18,32 +18,32 @@ name = "rust-analyzer"
 path = "src/bin/main.rs"
 
 [dependencies]
-anyhow = "1.0.26"
-crossbeam-channel = "0.5.0"
-dissimilar = "1.0.2"
-itertools = "0.10.0"
-lsp-types = { version = "0.92", features = ["proposed"] }
-parking_lot = "0.12"
-xflags = "0.2.1"
-oorandom = "11.1.2"
+anyhow = "1.0.56"
+crossbeam-channel = "0.5.4"
+dissimilar = "1.0.3"
+itertools = "0.10.3"
+lsp-types = { version = "0.92.1", features = ["proposed"] }
+parking_lot = "0.12.0"
+xflags = "0.2.4"
+oorandom = "11.1.3"
 rustc-hash = "1.1.0"
-serde = { version = "1.0.106", features = ["derive"] }
-serde_json = { version = "1.0.48", features = ["preserve_order"] }
-threadpool = "1.7.1"
-rayon = "1.5"
+serde = { version = "1.0.136", features = ["derive"] }
+serde_json = { version = "1.0.79", features = ["preserve_order"] }
+threadpool = "1.8.1"
+rayon = "1.5.1"
 num_cpus = "1.13.1"
-mimalloc = { version = "0.1.19", default-features = false, optional = true }
-lsp-server = "0.5.1"
-tracing = "0.1"
-tracing-subscriber = { version = "0.3", default-features = false, features = [
+mimalloc = { version = "0.1.28", default-features = false, optional = true }
+lsp-server = "0.5.2"
+tracing = "0.1.32"
+tracing-subscriber = { version = "0.3.9", default-features = false, features = [
     "env-filter",
     "registry",
     "fmt",
     "tracing-log",
 ] }
 tracing-log = "0.1.2"
-tracing-tree = "0.2"
-always-assert = "0.1"
+tracing-tree = "0.2.0"
+always-assert = "0.1.2"
 
 stdx = { path = "../stdx", version = "0.0.0" }
 flycheck = { path = "../flycheck", version = "0.0.0" }
@@ -67,14 +67,14 @@ hir_ty = { path = "../hir_ty", version = "0.0.0" }
 proc_macro_srv = { path = "../proc_macro_srv", version = "0.0.0" }
 
 [target.'cfg(windows)'.dependencies]
-winapi = "0.3.8"
+winapi = "0.3.9"
 
 [target.'cfg(not(target_env = "msvc"))'.dependencies]
-jemallocator = { version = "0.4.1", package = "tikv-jemallocator", optional = true }
+jemallocator = { version = "0.4.3", package = "tikv-jemallocator", optional = true }
 
 [dev-dependencies]
-expect-test = "1.2.0-pre.1"
-jod-thread = "0.1.0"
+expect-test = "1.2.2"
+jod-thread = "0.1.2"
 xshell = "0.2.1"
 
 test_utils = { path = "../test_utils" }
diff --git a/crates/rust-analyzer/src/caps.rs b/crates/rust-analyzer/src/caps.rs
index d83af2a48a..8c19f584f0 100644
--- a/crates/rust-analyzer/src/caps.rs
+++ b/crates/rust-analyzer/src/caps.rs
@@ -112,6 +112,7 @@ pub fn server_capabilities(config: &Config) -> ServerCapabilities {
             .into(),
         ),
         moniker_provider: None,
+        inlay_hint_provider: None,
         experimental: Some(json!({
             "externalDocs": true,
             "hoverRange": true,
diff --git a/crates/stdx/Cargo.toml b/crates/stdx/Cargo.toml
index bfce91b1d3..d3dfdf7eb6 100644
--- a/crates/stdx/Cargo.toml
+++ b/crates/stdx/Cargo.toml
@@ -10,8 +10,8 @@ rust-version = "1.57"
 doctest = false
 
 [dependencies]
-libc = "0.2"
-backtrace = { version = "0.3.44", optional = true }
+libc = "0.2.121"
+backtrace = { version = "0.3.64", optional = true }
 always-assert = { version = "0.1.2", features = ["log"] }
 # Think twice before adding anything here
 
diff --git a/crates/syntax/Cargo.toml b/crates/syntax/Cargo.toml
index d8f8290745..4a454cb8b7 100644
--- a/crates/syntax/Cargo.toml
+++ b/crates/syntax/Cargo.toml
@@ -12,12 +12,12 @@ doctest = false
 
 [dependencies]
 cov-mark = "2.0.0-pre.1"
-itertools = "0.10.0"
-rowan = "0.15.0"
+itertools = "0.10.3"
+rowan = "0.15.4"
 rustc_lexer = { version = "725.0.0", package = "rustc-ap-rustc_lexer" }
 rustc-hash = "1.1.0"
-once_cell = "1.3.1"
-indexmap = "1.7.0"
+once_cell = "1.10.0"
+indexmap = "1.8.0"
 smol_str = "0.1.21"
 
 stdx = { path = "../stdx", version = "0.0.0" }
@@ -26,10 +26,10 @@ parser = { path = "../parser", version = "0.0.0" }
 profile = { path = "../profile", version = "0.0.0" }
 
 [dev-dependencies]
-rayon = "1"
-expect-test = "1.2.0-pre.1"
-proc-macro2 = "1.0.8"
-quote = "1.0.2"
+rayon = "1.5.1"
+expect-test = "1.2.2"
+proc-macro2 = "1.0.36"
+quote = "1.0.16"
 ungrammar = "=1.16.1"
 
 test_utils = { path = "../test_utils" }
diff --git a/crates/text_edit/Cargo.toml b/crates/text_edit/Cargo.toml
index dae69e265d..fde19f1363 100644
--- a/crates/text_edit/Cargo.toml
+++ b/crates/text_edit/Cargo.toml
@@ -10,5 +10,5 @@ rust-version = "1.57"
 doctest = false
 
 [dependencies]
-itertools = "0.10.0"
-text-size = "1.0.0"
+itertools = "0.10.3"
+text-size = "1.1.0"
diff --git a/crates/tt/Cargo.toml b/crates/tt/Cargo.toml
index 3fb39355fe..f97c59ea53 100644
--- a/crates/tt/Cargo.toml
+++ b/crates/tt/Cargo.toml
@@ -10,6 +10,6 @@ rust-version = "1.57"
 doctest = false
 
 [dependencies]
-smol_str = "0.1"
+smol_str = "0.1.21"
 
 stdx = { path = "../stdx", version = "0.0.0" }
diff --git a/crates/vfs-notify/Cargo.toml b/crates/vfs-notify/Cargo.toml
index 10addab1e4..a13a85f92f 100644
--- a/crates/vfs-notify/Cargo.toml
+++ b/crates/vfs-notify/Cargo.toml
@@ -10,10 +10,10 @@ rust-version = "1.57"
 doctest = false
 
 [dependencies]
-tracing = "0.1"
-jod-thread = "0.1.0"
-walkdir = "2.3.1"
-crossbeam-channel = "0.5.0"
+tracing = "0.1.32"
+jod-thread = "0.1.2"
+walkdir = "2.3.2"
+crossbeam-channel = "0.5.4"
 notify = "=5.0.0-pre.14"
 
 vfs = { path = "../vfs", version = "0.0.0" }
diff --git a/crates/vfs/Cargo.toml b/crates/vfs/Cargo.toml
index 24f380e25f..a690535bea 100644
--- a/crates/vfs/Cargo.toml
+++ b/crates/vfs/Cargo.toml
@@ -10,8 +10,8 @@ rust-version = "1.57"
 doctest = false
 
 [dependencies]
-rustc-hash = "1.0"
-fst = "0.4"
+rustc-hash = "1.1.0"
+fst = "0.4.7"
 
 paths = { path = "../paths", version = "0.0.0" }
-indexmap = "1.7"
+indexmap = "1.8.0"
diff --git a/xtask/Cargo.toml b/xtask/Cargo.toml
index de6a102427..417a58556b 100644
--- a/xtask/Cargo.toml
+++ b/xtask/Cargo.toml
@@ -7,9 +7,9 @@ edition = "2021"
 rust-version = "1.57"
 
 [dependencies]
-anyhow = "1.0.26"
-flate2 = "1.0"
-write-json = "0.1.0"
+anyhow = "1.0.56"
+flate2 = "1.0.22"
+write-json = "0.1.2"
 xshell = "0.2.1"
-xflags = "0.2.1"
+xflags = "0.2.4"
 # Avoid adding more dependencies to this crate


Test patch:
diff --git a/crates/hir_ty/src/tests/simple.rs b/crates/hir_ty/src/tests/simple.rs
index de27c294f6..0d050f7461 100644
--- a/crates/hir_ty/src/tests/simple.rs
+++ b/crates/hir_ty/src/tests/simple.rs
@@ -1,6 +1,6 @@
 use expect_test::expect;
 
-use super::{check_infer, check_no_mismatches, check_types};
+use super::{check_infer, check_types};
 
 #[test]
 fn infer_box() {
@@ -2624,21 +2624,3 @@ pub mod prelude {
     "#,
     );
 }
-
-#[test]
-fn legacy_const_generics() {
-    check_no_mismatches(
-        r#"
-#[rustc_legacy_const_generics(1, 3)]
-fn mixed<const N1: &'static str, const N2: bool>(
-    a: u8,
-    b: i8,
-) {}
-
-fn f() {
-    mixed(0, "", -1, true);
-    mixed::<"", true>(0, -1);
-}
-    "#,
-    );
-}
diff --git a/crates/proc_macro_test/Cargo.toml b/crates/proc_macro_test/Cargo.toml
index 85c6de390a..d0ddbd6d59 100644
--- a/crates/proc_macro_test/Cargo.toml
+++ b/crates/proc_macro_test/Cargo.toml
@@ -12,4 +12,4 @@ doctest = false
 [build-dependencies]
 proc_macro_test_impl = { path = "imp", version = "0.0.0" }
 toolchain = { path = "../toolchain", version = "0.0.0" }
-cargo_metadata = "0.14"
+cargo_metadata = "0.14.2"
diff --git a/crates/test_utils/Cargo.toml b/crates/test_utils/Cargo.toml
index 36293155f2..e8a8ef04b4 100644
--- a/crates/test_utils/Cargo.toml
+++ b/crates/test_utils/Cargo.toml
@@ -11,8 +11,8 @@ doctest = false
 
 [dependencies]
 # Avoid adding deps here, this crate is widely used in tests it should compile fast!
-dissimilar = "1.0.2"
-text-size = "1.0.0"
+dissimilar = "1.0.3"
+text-size = "1.1.0"
 rustc-hash = "1.1.0"
 
 stdx = { path = "../stdx", version = "0.0.0" }