Auto merge of #148944 - theemathas:rm_inherit_overflow, r=joboet

Remove `rustc_inherit_overflow_checks` from `position()` in slice iterators

This method implementation can never cause an overflow, since `i` can never go over the slice's length.
diff --git a/.typos.toml b/.typos.toml
index 9946415..e954b08 100644
--- a/.typos.toml
+++ b/.typos.toml
@@ -33,6 +33,7 @@
 thir = "thir"
 jod = "jod"
 tructure = "tructure"
+taits = "taits"
 
 [default.extend-identifiers]
 anc = "anc"
diff --git a/Cargo.lock b/Cargo.lock
index 535833d..12b5f8a 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -419,6 +419,22 @@
 ]
 
 [[package]]
+name = "dhat"
+version = "0.3.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "98cd11d84628e233de0ce467de10b8633f4ddaecafadefc86e13b84b8739b827"
+dependencies = [
+ "backtrace",
+ "lazy_static",
+ "mintex",
+ "parking_lot",
+ "rustc-hash 1.1.0",
+ "serde",
+ "serde_json",
+ "thousands",
+]
+
+[[package]]
 name = "dirs"
 version = "6.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1384,6 +1400,12 @@
 ]
 
 [[package]]
+name = "mintex"
+version = "0.1.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c505b3e17ed6b70a7ed2e67fbb2c560ee327353556120d6e72f5232b6880d536"
+
+[[package]]
 name = "mio"
 version = "1.1.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1452,7 +1474,7 @@
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "7957b9740744892f114936ab4a57b3f487491bbeafaf8083688b16841a4240e5"
 dependencies = [
- "windows-sys 0.60.2",
+ "windows-sys 0.61.0",
 ]
 
 [[package]]
@@ -2011,6 +2033,7 @@
  "cargo_metadata 0.21.0",
  "cfg",
  "crossbeam-channel",
+ "dhat",
  "dirs",
  "dissimilar",
  "expect-test",
@@ -2047,6 +2070,7 @@
  "serde",
  "serde_derive",
  "serde_json",
+ "smallvec",
  "stdx",
  "syntax",
  "syntax-bridge",
@@ -2529,6 +2553,12 @@
 ]
 
 [[package]]
+name = "thousands"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3bf63baf9f5039dadc247375c29eb13706706cfde997d0330d05aa63a77d8820"
+
+[[package]]
 name = "thread_local"
 version = "1.1.9"
 source = "registry+https://github.com/rust-lang/crates.io-index"
diff --git a/crates/hir-def/src/item_tree/lower.rs b/crates/hir-def/src/item_tree/lower.rs
index 454e063..db50e65 100644
--- a/crates/hir-def/src/item_tree/lower.rs
+++ b/crates/hir-def/src/item_tree/lower.rs
@@ -370,18 +370,13 @@
         });
         match &vis {
             RawVisibility::Public => RawVisibilityId::PUB,
-            RawVisibility::Module(path, explicitness) if path.segments().is_empty() => {
-                match (path.kind, explicitness) {
-                    (PathKind::SELF, VisibilityExplicitness::Explicit) => {
-                        RawVisibilityId::PRIV_EXPLICIT
-                    }
-                    (PathKind::SELF, VisibilityExplicitness::Implicit) => {
-                        RawVisibilityId::PRIV_IMPLICIT
-                    }
-                    (PathKind::Crate, _) => RawVisibilityId::PUB_CRATE,
-                    _ => RawVisibilityId(self.visibilities.insert_full(vis).0 as u32),
-                }
+            RawVisibility::PubSelf(VisibilityExplicitness::Explicit) => {
+                RawVisibilityId::PRIV_EXPLICIT
             }
+            RawVisibility::PubSelf(VisibilityExplicitness::Implicit) => {
+                RawVisibilityId::PRIV_IMPLICIT
+            }
+            RawVisibility::PubCrate => RawVisibilityId::PUB_CRATE,
             _ => RawVisibilityId(self.visibilities.insert_full(vis).0 as u32),
         }
     }
@@ -466,10 +461,7 @@
 }
 
 fn private_vis() -> RawVisibility {
-    RawVisibility::Module(
-        Interned::new(ModPath::from_kind(PathKind::SELF)),
-        VisibilityExplicitness::Implicit,
-    )
+    RawVisibility::PubSelf(VisibilityExplicitness::Implicit)
 }
 
 pub(crate) fn visibility_from_ast(
@@ -486,9 +478,11 @@
                 Some(path) => path,
             }
         }
-        ast::VisibilityKind::PubCrate => ModPath::from_kind(PathKind::Crate),
+        ast::VisibilityKind::PubCrate => return RawVisibility::PubCrate,
         ast::VisibilityKind::PubSuper => ModPath::from_kind(PathKind::Super(1)),
-        ast::VisibilityKind::PubSelf => ModPath::from_kind(PathKind::SELF),
+        ast::VisibilityKind::PubSelf => {
+            return RawVisibility::PubSelf(VisibilityExplicitness::Explicit);
+        }
         ast::VisibilityKind::Pub => return RawVisibility::Public,
     };
     RawVisibility::Module(Interned::new(path), VisibilityExplicitness::Explicit)
diff --git a/crates/hir-def/src/macro_expansion_tests/mbe/meta_syntax.rs b/crates/hir-def/src/macro_expansion_tests/mbe/meta_syntax.rs
index 2c94f0e..311fdc3 100644
--- a/crates/hir-def/src/macro_expansion_tests/mbe/meta_syntax.rs
+++ b/crates/hir-def/src/macro_expansion_tests/mbe/meta_syntax.rs
@@ -98,7 +98,7 @@
 
 #[test]
 fn test_rustc_issue_57597() {
-    // <https://github.com/rust-lang/rust/blob/master/tests/ui/issues/issue-57597.rs>
+    // <https://github.com/rust-lang/rust/blob/ec2cc76/tests/ui/macros/issue-57597.rs>
     check(
         r#"
 macro_rules! m0 { ($($($i:ident)?)+) => {}; }
diff --git a/crates/hir-def/src/resolver.rs b/crates/hir-def/src/resolver.rs
index 698292c..abcf0a3 100644
--- a/crates/hir-def/src/resolver.rs
+++ b/crates/hir-def/src/resolver.rs
@@ -1075,7 +1075,9 @@
         if let Some(block) = scopes.block(scope) {
             let def_map = block_def_map(db, block);
             let local_def_map = block.lookup(db).module.only_local_def_map(db);
-            r = r.push_block_scope(def_map, local_def_map);
+            // Using `DefMap::ROOT` is okay here since inside modules other than the root,
+            // there can't directly be expressions.
+            r = r.push_block_scope(def_map, local_def_map, DefMap::ROOT);
             // FIXME: This adds as many module scopes as there are blocks, but resolving in each
             // already traverses all parents, so this is O(n²). I think we could only store the
             // innermost module scope instead?
@@ -1108,12 +1110,9 @@
         self,
         def_map: &'db DefMap,
         local_def_map: &'db LocalDefMap,
+        module_id: LocalModuleId,
     ) -> Resolver<'db> {
-        self.push_scope(Scope::BlockScope(ModuleItemMap {
-            def_map,
-            local_def_map,
-            module_id: DefMap::ROOT,
-        }))
+        self.push_scope(Scope::BlockScope(ModuleItemMap { def_map, local_def_map, module_id }))
     }
 
     fn push_expr_scope(
@@ -1273,7 +1272,7 @@
         let (mut def_map, local_def_map) = self.local_def_map(db);
         let mut module_id = self.local_id;
 
-        if !self.is_block_module() {
+        if !self.is_within_block() {
             return Resolver {
                 scopes: vec![],
                 module_scope: ModuleItemMap { def_map, local_def_map, module_id },
@@ -1283,9 +1282,9 @@
         let mut modules: SmallVec<[_; 1]> = smallvec![];
         while let Some(parent) = def_map.parent() {
             let block_def_map = mem::replace(&mut def_map, parent.def_map(db));
-            modules.push(block_def_map);
-            if !parent.is_block_module() {
-                module_id = parent.local_id;
+            let block_module_id = mem::replace(&mut module_id, parent.local_id);
+            modules.push((block_def_map, block_module_id));
+            if !parent.is_within_block() {
                 break;
             }
         }
@@ -1293,8 +1292,8 @@
             scopes: Vec::with_capacity(modules.len()),
             module_scope: ModuleItemMap { def_map, local_def_map, module_id },
         };
-        for def_map in modules.into_iter().rev() {
-            resolver = resolver.push_block_scope(def_map, local_def_map);
+        for (def_map, module_id) in modules.into_iter().rev() {
+            resolver = resolver.push_block_scope(def_map, local_def_map, module_id);
         }
         resolver
     }
diff --git a/crates/hir-def/src/visibility.rs b/crates/hir-def/src/visibility.rs
index b5eb84c..948f6ed 100644
--- a/crates/hir-def/src/visibility.rs
+++ b/crates/hir-def/src/visibility.rs
@@ -289,18 +289,21 @@
 
 pub fn visibility_from_ast(
     db: &dyn DefDatabase,
-    has_resolver: impl HasResolver,
+    has_resolver: impl HasResolver + HasModule,
     ast_vis: InFile<Option<ast::Visibility>>,
 ) -> Visibility {
     let mut span_map = None;
     let raw_vis = crate::item_tree::visibility_from_ast(db, ast_vis.value, &mut |range| {
         span_map.get_or_insert_with(|| db.span_map(ast_vis.file_id)).span_for_range(range).ctx
     });
-    if raw_vis == RawVisibility::Public {
-        return Visibility::Public;
+    match raw_vis {
+        RawVisibility::PubSelf(explicitness) => {
+            Visibility::Module(has_resolver.module(db), explicitness)
+        }
+        RawVisibility::PubCrate => Visibility::PubCrate(has_resolver.krate(db)),
+        RawVisibility::Public => Visibility::Public,
+        RawVisibility::Module(..) => Visibility::resolve(db, &has_resolver.resolver(db), &raw_vis),
     }
-
-    Visibility::resolve(db, &has_resolver.resolver(db), &raw_vis)
 }
 
 /// Resolve visibility of a type alias.
diff --git a/crates/hir-ty/src/autoderef.rs b/crates/hir-ty/src/autoderef.rs
index 6dd3cdb..392b0b0 100644
--- a/crates/hir-ty/src/autoderef.rs
+++ b/crates/hir-ty/src/autoderef.rs
@@ -38,7 +38,7 @@
     env: Arc<TraitEnvironment<'db>>,
     ty: Canonical<'db, Ty<'db>>,
 ) -> impl Iterator<Item = Ty<'db>> + use<'db> {
-    let mut table = InferenceTable::new(db, env);
+    let mut table = InferenceTable::new(db, env, None);
     let ty = table.instantiate_canonical(ty);
     let mut autoderef = Autoderef::new_no_tracking(&mut table, ty);
     let mut v = Vec::new();
diff --git a/crates/hir-ty/src/display.rs b/crates/hir-ty/src/display.rs
index dd1b212..0a37966 100644
--- a/crates/hir-ty/src/display.rs
+++ b/crates/hir-ty/src/display.rs
@@ -2078,9 +2078,10 @@
             if vis_id == module_id {
                 // pub(self) or omitted
                 Ok(())
-            } else if root_module_id == vis_id {
+            } else if root_module_id == vis_id && !root_module_id.is_within_block() {
                 write!(f, "pub(crate) ")
-            } else if module_id.containing_module(f.db) == Some(vis_id) {
+            } else if module_id.containing_module(f.db) == Some(vis_id) && !vis_id.is_block_module()
+            {
                 write!(f, "pub(super) ")
             } else {
                 write!(f, "pub(in ...) ")
diff --git a/crates/hir-ty/src/infer.rs b/crates/hir-ty/src/infer.rs
index 361e665..016edb2 100644
--- a/crates/hir-ty/src/infer.rs
+++ b/crates/hir-ty/src/infer.rs
@@ -21,6 +21,7 @@
 mod expr;
 mod fallback;
 mod mutability;
+mod opaques;
 mod pat;
 mod path;
 pub(crate) mod unify;
@@ -31,8 +32,7 @@
 use either::Either;
 use hir_def::{
     AdtId, AssocItemId, ConstId, DefWithBodyId, FieldId, FunctionId, GenericDefId, GenericParamId,
-    ImplId, ItemContainerId, LocalFieldId, Lookup, TraitId, TupleFieldId, TupleId, TypeAliasId,
-    VariantId,
+    ItemContainerId, LocalFieldId, Lookup, TraitId, TupleFieldId, TupleId, TypeAliasId, VariantId,
     expr_store::{Body, ExpressionStore, HygieneId, path::Path},
     hir::{BindingAnnotation, BindingId, ExprId, ExprOrPatId, LabelId, PatId},
     lang_item::{LangItem, LangItemTarget, lang_item},
@@ -44,11 +44,11 @@
 use hir_expand::{mod_path::ModPath, name::Name};
 use indexmap::IndexSet;
 use intern::sym;
-use la_arena::{ArenaMap, Entry};
+use la_arena::ArenaMap;
 use rustc_ast_ir::Mutability;
 use rustc_hash::{FxHashMap, FxHashSet};
 use rustc_type_ir::{
-    AliasTyKind, Flags, TypeFlags, TypeFoldable, TypeSuperVisitable, TypeVisitable, TypeVisitor,
+    AliasTyKind, TypeFoldable,
     inherent::{AdtDef, IntoKind, Region as _, SliceLike, Ty as _},
 };
 use stdx::never;
@@ -61,7 +61,6 @@
         coerce::{CoerceMany, DynamicCoerceMany},
         diagnostics::{Diagnostics, InferenceTyLoweringContext as TyLoweringContext},
         expr::ExprIsRead,
-        unify::InferenceTable,
     },
     lower::{
         ImplTraitIdx, ImplTraitLoweringMode, LifetimeElisionKind, diagnostics::TyLoweringDiagnostic,
@@ -69,10 +68,7 @@
     mir::MirSpan,
     next_solver::{
         AliasTy, Const, DbInterner, ErrorGuaranteed, GenericArg, GenericArgs, Region, Ty, TyKind,
-        Tys,
-        abi::Safety,
-        fold::fold_tys,
-        infer::traits::{Obligation, ObligationCause},
+        Tys, abi::Safety, infer::traits::ObligationCause,
     },
     traits::FnTrait,
     utils::TargetFeatureIsSafeInTarget,
@@ -132,6 +128,8 @@
 
     ctx.infer_mut_body();
 
+    ctx.handle_opaque_type_uses();
+
     ctx.type_inference_fallback();
 
     // Comment from rustc:
@@ -148,6 +146,10 @@
 
     ctx.infer_closures();
 
+    ctx.table.select_obligations_where_possible();
+
+    ctx.handle_opaque_type_uses();
+
     Arc::new(ctx.resolve_all())
 }
 
@@ -454,7 +456,7 @@
     /// unresolved or missing subpatterns or subpatterns of mismatched types.
     pub(crate) type_of_pat: ArenaMap<PatId, Ty<'db>>,
     pub(crate) type_of_binding: ArenaMap<BindingId, Ty<'db>>,
-    pub(crate) type_of_rpit: ArenaMap<ImplTraitIdx<'db>, Ty<'db>>,
+    pub(crate) type_of_opaque: FxHashMap<InternedOpaqueTyId, Ty<'db>>,
     type_mismatches: FxHashMap<ExprOrPatId, TypeMismatch<'db>>,
     /// Whether there are any type-mismatching errors in the result.
     // FIXME: This isn't as useful as initially thought due to us falling back placeholders to
@@ -499,7 +501,7 @@
             type_of_expr: Default::default(),
             type_of_pat: Default::default(),
             type_of_binding: Default::default(),
-            type_of_rpit: Default::default(),
+            type_of_opaque: Default::default(),
             type_mismatches: Default::default(),
             has_errors: Default::default(),
             error_ty,
@@ -640,8 +642,14 @@
     // This method is consumed by external tools to run rust-analyzer as a library. Don't remove, please.
     pub fn return_position_impl_trait_types(
         &self,
+        db: &'db dyn HirDatabase,
     ) -> impl Iterator<Item = (ImplTraitIdx<'db>, Ty<'db>)> {
-        self.type_of_rpit.iter().map(|(k, v)| (k, *v))
+        self.type_of_opaque.iter().filter_map(move |(&id, &ty)| {
+            let ImplTraitId::ReturnTypeImplTrait(_, rpit_idx) = id.loc(db) else {
+                return None;
+            };
+            Some((rpit_idx, ty))
+        })
     }
 }
 
@@ -707,6 +715,7 @@
 
     re_static: Region<'db>,
     re_error: Region<'db>,
+    re_erased: Region<'db>,
 
     empty_args: GenericArgs<'db>,
     empty_tys: Tys<'db>,
@@ -742,6 +751,7 @@
 
             re_static,
             re_error: Region::error(interner),
+            re_erased: Region::new_erased(interner),
 
             empty_args: GenericArgs::new_from_iter(interner, []),
             empty_tys: Tys::new_from_iter(interner, []),
@@ -848,11 +858,6 @@
     }
 }
 
-enum ImplTraitReplacingMode<'db> {
-    ReturnPosition(FxHashSet<Ty<'db>>),
-    TypeAlias,
-}
-
 impl<'body, 'db> InferenceContext<'body, 'db> {
     fn new(
         db: &'db dyn HirDatabase,
@@ -861,7 +866,7 @@
         resolver: Resolver<'db>,
     ) -> Self {
         let trait_env = db.trait_environment_for_body(owner);
-        let table = unify::InferenceTable::new(db, trait_env);
+        let table = unify::InferenceTable::new(db, trait_env, Some(owner));
         let types = InternedStandardTypes::new(table.interner());
         InferenceContext {
             result: InferenceResult::new(types.error),
@@ -952,7 +957,7 @@
     // `InferenceResult` in the middle of inference. See the fixme comment in `consteval::eval_to_const`. If you
     // used this function for another workaround, mention it here. If you really need this function and believe that
     // there is no problem in it being `pub(crate)`, remove this comment.
-    pub(crate) fn resolve_all(self) -> InferenceResult<'db> {
+    fn resolve_all(self) -> InferenceResult<'db> {
         let InferenceContext {
             mut table, mut result, tuple_field_accesses_rev, diagnostics, ..
         } = self;
@@ -967,7 +972,7 @@
             type_of_expr,
             type_of_pat,
             type_of_binding,
-            type_of_rpit,
+            type_of_opaque,
             type_mismatches,
             has_errors,
             error_ty: _,
@@ -999,11 +1004,7 @@
             *has_errors = *has_errors || ty.references_non_lt_error();
         }
         type_of_binding.shrink_to_fit();
-        for ty in type_of_rpit.values_mut() {
-            *ty = table.resolve_completely(*ty);
-            *has_errors = *has_errors || ty.references_non_lt_error();
-        }
-        type_of_rpit.shrink_to_fit();
+        type_of_opaque.shrink_to_fit();
 
         *has_errors |= !type_mismatches.is_empty();
 
@@ -1084,9 +1085,6 @@
             LifetimeElisionKind::for_const(self.interner(), id.loc(self.db).container),
         );
 
-        // Constants might be defining usage sites of TAITs.
-        self.make_tait_coercion_table(iter::once(return_ty));
-
         self.return_ty = return_ty;
     }
 
@@ -1098,9 +1096,6 @@
             LifetimeElisionKind::Elided(self.types.re_static),
         );
 
-        // Statics might be defining usage sites of TAITs.
-        self.make_tait_coercion_table(iter::once(return_ty));
-
         self.return_ty = return_ty;
     }
 
@@ -1138,16 +1133,12 @@
             let ty = self.process_user_written_ty(ty);
             self.write_binding_ty(self_param, ty);
         }
-        let mut tait_candidates = FxHashSet::default();
         for (ty, pat) in param_tys.zip(&*self.body.params) {
             let ty = self.process_user_written_ty(ty);
 
             self.infer_top_pat(*pat, ty, None);
-            if ty.flags().intersects(TypeFlags::HAS_TY_OPAQUE.union(TypeFlags::HAS_TY_INFER)) {
-                tait_candidates.insert(ty);
-            }
         }
-        let return_ty = match data.ret_type {
+        self.return_ty = match data.ret_type {
             Some(return_ty) => {
                 let return_ty = self.with_ty_lowering(
                     &data.store,
@@ -1158,45 +1149,12 @@
                         ctx.lower_ty(return_ty)
                     },
                 );
-                let return_ty = self.insert_type_vars(return_ty);
-                if let Some(rpits) = self.db.return_type_impl_traits(func) {
-                    let mut mode = ImplTraitReplacingMode::ReturnPosition(FxHashSet::default());
-                    let result = self.insert_inference_vars_for_impl_trait(return_ty, &mut mode);
-                    if let ImplTraitReplacingMode::ReturnPosition(taits) = mode {
-                        tait_candidates.extend(taits);
-                    }
-                    let rpits = (*rpits).as_ref().skip_binder();
-                    for (id, _) in rpits.impl_traits.iter() {
-                        if let Entry::Vacant(e) = self.result.type_of_rpit.entry(id) {
-                            never!("Missed RPIT in `insert_inference_vars_for_rpit`");
-                            e.insert(self.types.error);
-                        }
-                    }
-                    result
-                } else {
-                    return_ty
-                }
+                self.process_user_written_ty(return_ty)
             }
             None => self.types.unit,
         };
 
-        self.return_ty = self.process_user_written_ty(return_ty);
         self.return_coercion = Some(CoerceMany::new(self.return_ty));
-
-        // Functions might be defining usage sites of TAITs.
-        // To define an TAITs, that TAIT must appear in the function's signatures.
-        // So, it suffices to check for params and return types.
-        fold_tys(self.interner(), self.return_ty, |ty| {
-            match ty.kind() {
-                TyKind::Alias(AliasTyKind::Opaque, _) | TyKind::Infer(..) => {
-                    tait_candidates.insert(self.return_ty);
-                }
-                _ => {}
-            }
-            ty
-        });
-
-        self.make_tait_coercion_table(tait_candidates.iter().copied());
     }
 
     #[inline]
@@ -1204,193 +1162,6 @@
         self.table.interner()
     }
 
-    fn insert_inference_vars_for_impl_trait<T>(
-        &mut self,
-        t: T,
-        mode: &mut ImplTraitReplacingMode<'db>,
-    ) -> T
-    where
-        T: TypeFoldable<DbInterner<'db>>,
-    {
-        fold_tys(self.interner(), t, |ty| {
-            let ty = self.table.try_structurally_resolve_type(ty);
-            let opaque_ty_id = match ty.kind() {
-                TyKind::Alias(AliasTyKind::Opaque, alias_ty) => alias_ty.def_id.expect_opaque_ty(),
-                _ => return ty,
-            };
-            let (impl_traits, idx) = match self.db.lookup_intern_impl_trait_id(opaque_ty_id) {
-                // We don't replace opaque types from other kind with inference vars
-                // because `insert_inference_vars_for_impl_traits` for each kinds
-                // and unreplaced opaque types of other kind are resolved while
-                // inferencing because of `tait_coercion_table`.
-                ImplTraitId::ReturnTypeImplTrait(def, idx) => {
-                    if matches!(mode, ImplTraitReplacingMode::TypeAlias) {
-                        // RPITs don't have `tait_coercion_table`, so use inserted inference
-                        // vars for them.
-                        if let Some(ty) = self.result.type_of_rpit.get(idx) {
-                            return *ty;
-                        }
-                        return ty;
-                    }
-                    (self.db.return_type_impl_traits(def), idx)
-                }
-                ImplTraitId::TypeAliasImplTrait(def, idx) => {
-                    if let ImplTraitReplacingMode::ReturnPosition(taits) = mode {
-                        // Gather TAITs while replacing RPITs because TAITs inside RPITs
-                        // may not visited while replacing TAITs
-                        taits.insert(ty);
-                        return ty;
-                    }
-                    (self.db.type_alias_impl_traits(def), idx)
-                }
-            };
-            let Some(impl_traits) = impl_traits else {
-                return ty;
-            };
-            let bounds =
-                (*impl_traits).as_ref().map_bound(|its| its.impl_traits[idx].predicates.as_slice());
-            let var = match self.result.type_of_rpit.entry(idx) {
-                Entry::Occupied(entry) => return *entry.get(),
-                Entry::Vacant(entry) => *entry.insert(self.table.next_ty_var()),
-            };
-            for clause in bounds.iter_identity_copied() {
-                let clause = self.insert_inference_vars_for_impl_trait(clause, mode);
-                self.table.register_predicate(Obligation::new(
-                    self.interner(),
-                    ObligationCause::new(),
-                    self.table.trait_env.env,
-                    clause,
-                ));
-            }
-            var
-        })
-    }
-
-    /// The coercion of a non-inference var into an opaque type should fail,
-    /// but not in the defining sites of the TAITs.
-    /// In such cases, we insert an proxy inference var for each TAIT,
-    /// and coerce into it instead of TAIT itself.
-    ///
-    /// The inference var stretagy is effective because;
-    ///
-    /// - It can still unify types that coerced into TAITs
-    /// - We are pushing `impl Trait` bounds into it
-    ///
-    /// This function inserts a map that maps the opaque type to that proxy inference var.
-    fn make_tait_coercion_table(&mut self, tait_candidates: impl Iterator<Item = Ty<'db>>) {
-        struct TypeAliasImplTraitCollector<'a, 'db> {
-            db: &'a dyn HirDatabase,
-            table: &'a mut InferenceTable<'db>,
-            assocs: FxHashMap<InternedOpaqueTyId, (ImplId, Ty<'db>)>,
-            non_assocs: FxHashMap<InternedOpaqueTyId, Ty<'db>>,
-        }
-
-        impl<'db> TypeVisitor<DbInterner<'db>> for TypeAliasImplTraitCollector<'_, 'db> {
-            type Result = ();
-
-            fn visit_ty(&mut self, ty: Ty<'db>) {
-                let ty = self.table.try_structurally_resolve_type(ty);
-
-                if let TyKind::Alias(AliasTyKind::Opaque, alias_ty) = ty.kind()
-                    && let id = alias_ty.def_id.expect_opaque_ty()
-                    && let ImplTraitId::TypeAliasImplTrait(alias_id, _) =
-                        self.db.lookup_intern_impl_trait_id(id)
-                {
-                    let loc = self.db.lookup_intern_type_alias(alias_id);
-                    match loc.container {
-                        ItemContainerId::ImplId(impl_id) => {
-                            self.assocs.insert(id, (impl_id, ty));
-                        }
-                        ItemContainerId::ModuleId(..) | ItemContainerId::ExternBlockId(..) => {
-                            self.non_assocs.insert(id, ty);
-                        }
-                        _ => {}
-                    }
-                }
-
-                ty.super_visit_with(self)
-            }
-        }
-
-        let mut collector = TypeAliasImplTraitCollector {
-            db: self.db,
-            table: &mut self.table,
-            assocs: FxHashMap::default(),
-            non_assocs: FxHashMap::default(),
-        };
-        for ty in tait_candidates {
-            ty.visit_with(&mut collector);
-        }
-
-        // Non-assoc TAITs can be define-used everywhere as long as they are
-        // in function signatures or const types, etc
-        let mut taits = collector.non_assocs;
-
-        // assoc TAITs(ATPITs) can be only define-used inside their impl block.
-        // They cannot be define-used in inner items like in the following;
-        //
-        // ```
-        // impl Trait for Struct {
-        //     type Assoc = impl Default;
-        //
-        //     fn assoc_fn() -> Self::Assoc {
-        //         let foo: Self::Assoc = true; // Allowed here
-        //
-        //         fn inner() -> Self::Assoc {
-        //              false                   // Not allowed here
-        //         }
-        //
-        //         foo
-        //     }
-        // }
-        // ```
-        let impl_id = match self.owner {
-            DefWithBodyId::FunctionId(it) => {
-                let loc = self.db.lookup_intern_function(it);
-                if let ItemContainerId::ImplId(impl_id) = loc.container {
-                    Some(impl_id)
-                } else {
-                    None
-                }
-            }
-            DefWithBodyId::ConstId(it) => {
-                let loc = self.db.lookup_intern_const(it);
-                if let ItemContainerId::ImplId(impl_id) = loc.container {
-                    Some(impl_id)
-                } else {
-                    None
-                }
-            }
-            _ => None,
-        };
-
-        if let Some(impl_id) = impl_id {
-            taits.extend(collector.assocs.into_iter().filter_map(|(id, (impl_, ty))| {
-                if impl_ == impl_id { Some((id, ty)) } else { None }
-            }));
-        }
-
-        let tait_coercion_table: FxHashMap<_, _> = taits
-            .into_iter()
-            .filter_map(|(id, ty)| {
-                if let ImplTraitId::TypeAliasImplTrait(..) = self.db.lookup_intern_impl_trait_id(id)
-                {
-                    let ty = self.insert_inference_vars_for_impl_trait(
-                        ty,
-                        &mut ImplTraitReplacingMode::TypeAlias,
-                    );
-                    Some((id, ty))
-                } else {
-                    None
-                }
-            })
-            .collect();
-
-        if !tait_coercion_table.is_empty() {
-            self.table.tait_coercion_table = Some(tait_coercion_table);
-        }
-    }
-
     fn infer_body(&mut self) {
         match self.return_coercion {
             Some(_) => self.infer_return(self.body.body_expr),
@@ -2006,12 +1777,15 @@
         Some(struct_.into())
     }
 
-    fn get_traits_in_scope(&self) -> Either<FxHashSet<TraitId>, &FxHashSet<TraitId>> {
-        let mut b_traits = self.resolver.traits_in_scope_from_block_scopes().peekable();
+    fn get_traits_in_scope<'a>(
+        resolver: &Resolver<'db>,
+        traits_in_scope: &'a FxHashSet<TraitId>,
+    ) -> Either<FxHashSet<TraitId>, &'a FxHashSet<TraitId>> {
+        let mut b_traits = resolver.traits_in_scope_from_block_scopes().peekable();
         if b_traits.peek().is_some() {
-            Either::Left(self.traits_in_scope.iter().copied().chain(b_traits).collect())
+            Either::Left(traits_in_scope.iter().copied().chain(b_traits).collect())
         } else {
-            Either::Right(&self.traits_in_scope)
+            Either::Right(traits_in_scope)
         }
     }
 }
diff --git a/crates/hir-ty/src/infer/coerce.rs b/crates/hir-ty/src/infer/coerce.rs
index 78889cc..40de923 100644
--- a/crates/hir-ty/src/infer/coerce.rs
+++ b/crates/hir-ty/src/infer/coerce.rs
@@ -60,8 +60,7 @@
     next_solver::{
         Binder, BoundConst, BoundRegion, BoundRegionKind, BoundTy, BoundTyKind, CallableIdWrapper,
         Canonical, ClauseKind, CoercePredicate, Const, ConstKind, DbInterner, ErrorGuaranteed,
-        GenericArgs, PolyFnSig, PredicateKind, Region, RegionKind, SolverDefId, TraitRef, Ty,
-        TyKind,
+        GenericArgs, PolyFnSig, PredicateKind, Region, RegionKind, TraitRef, Ty, TyKind,
         infer::{
             InferCtxt, InferOk, InferResult,
             relate::RelateResult,
@@ -223,24 +222,6 @@
             }
         }
 
-        // If we are coercing into a TAIT, coerce into its proxy inference var, instead.
-        // FIXME(next-solver): This should not be here. This is not how rustc does thing, and it also not allows us
-        // to normalize opaques defined in our scopes. Instead, we should properly register
-        // `TypingMode::Analysis::defining_opaque_types_and_generators`, and rely on the solver to reveal
-        // them for us (we'll also need some global-like registry for the values, something we cannot
-        // really implement, therefore we can really support only RPITs and ITIAT or the new `#[define_opaque]`
-        // TAIT, not the old global TAIT).
-        let mut b = b;
-        if let Some(tait_table) = &self.table.tait_coercion_table
-            && let TyKind::Alias(rustc_type_ir::Opaque, opaque_ty) = b.kind()
-            && let SolverDefId::InternedOpaqueTyId(opaque_ty_id) = opaque_ty.def_id
-            && !matches!(a.kind(), TyKind::Infer(..) | TyKind::Alias(rustc_type_ir::Opaque, _))
-            && let Some(ty) = tait_table.get(&opaque_ty_id)
-        {
-            b = self.table.shallow_resolve(*ty);
-        }
-        let b = b;
-
         // Coercing *from* an unresolved inference variable means that
         // we have no information about the source type. This will always
         // ultimately fall back to some form of subtyping.
@@ -1528,7 +1509,7 @@
     env: Arc<TraitEnvironment<'db>>,
     tys: &Canonical<'db, (Ty<'db>, Ty<'db>)>,
 ) -> Result<(Vec<Adjustment<'db>>, Ty<'db>), TypeError<DbInterner<'db>>> {
-    let mut table = InferenceTable::new(db, env);
+    let mut table = InferenceTable::new(db, env, None);
     let interner = table.interner();
     let ((ty1_with_vars, ty2_with_vars), vars) = table.infer_ctxt.instantiate_canonical(tys);
 
diff --git a/crates/hir-ty/src/infer/expr.rs b/crates/hir-ty/src/infer/expr.rs
index fd4e374..b7ab109 100644
--- a/crates/hir-ty/src/infer/expr.rs
+++ b/crates/hir-ty/src/infer/expr.rs
@@ -1458,10 +1458,11 @@
     ) -> Ty<'db> {
         let coerce_ty = expected.coercion_target_type(&mut self.table);
         let g = self.resolver.update_to_inner_scope(self.db, self.owner, expr);
-        let prev_env = block_id.map(|block_id| {
+        let prev_state = block_id.map(|block_id| {
             let prev_env = self.table.trait_env.clone();
             TraitEnvironment::with_block(&mut self.table.trait_env, block_id);
-            prev_env
+            let prev_block = self.table.infer_ctxt.interner.block.replace(block_id);
+            (prev_env, prev_block)
         });
 
         let (break_ty, ty) =
@@ -1576,8 +1577,9 @@
                 }
             });
         self.resolver.reset_to_guard(g);
-        if let Some(prev_env) = prev_env {
+        if let Some((prev_env, prev_block)) = prev_state {
             self.table.trait_env = prev_env;
+            self.table.infer_ctxt.interner.block = prev_block;
         }
 
         break_ty.unwrap_or(ty)
@@ -1689,10 +1691,11 @@
                 // work out while people are typing
                 let canonicalized_receiver = self.canonicalize(receiver_ty);
                 let resolved = method_resolution::lookup_method(
-                    self.db,
                     &canonicalized_receiver,
-                    self.table.trait_env.clone(),
-                    self.get_traits_in_scope().as_ref().left_or_else(|&it| it),
+                    &mut self.table,
+                    Self::get_traits_in_scope(&self.resolver, &self.traits_in_scope)
+                        .as_ref()
+                        .left_or_else(|&it| it),
                     VisibleFromModule::Filter(self.resolver.module()),
                     name,
                 );
@@ -1844,10 +1847,11 @@
         let canonicalized_receiver = self.canonicalize(receiver_ty);
 
         let resolved = method_resolution::lookup_method(
-            self.db,
             &canonicalized_receiver,
-            self.table.trait_env.clone(),
-            self.get_traits_in_scope().as_ref().left_or_else(|&it| it),
+            &mut self.table,
+            Self::get_traits_in_scope(&self.resolver, &self.traits_in_scope)
+                .as_ref()
+                .left_or_else(|&it| it),
             VisibleFromModule::Filter(self.resolver.module()),
             method_name,
         );
@@ -1892,9 +1896,10 @@
 
                 let assoc_func_with_same_name = method_resolution::iterate_method_candidates(
                     &canonicalized_receiver,
-                    self.db,
-                    self.table.trait_env.clone(),
-                    self.get_traits_in_scope().as_ref().left_or_else(|&it| it),
+                    &mut self.table,
+                    Self::get_traits_in_scope(&self.resolver, &self.traits_in_scope)
+                        .as_ref()
+                        .left_or_else(|&it| it),
                     VisibleFromModule::Filter(self.resolver.module()),
                     Some(method_name),
                     method_resolution::LookupMode::Path,
diff --git a/crates/hir-ty/src/infer/opaques.rs b/crates/hir-ty/src/infer/opaques.rs
new file mode 100644
index 0000000..f7719f5
--- /dev/null
+++ b/crates/hir-ty/src/infer/opaques.rs
@@ -0,0 +1,147 @@
+//! Defining opaque types via inference.
+
+use rustc_type_ir::{TypeVisitableExt, fold_regions};
+use tracing::{debug, instrument};
+
+use crate::{
+    infer::InferenceContext,
+    next_solver::{
+        EarlyBinder, OpaqueTypeKey, SolverDefId, TypingMode,
+        infer::{opaque_types::OpaqueHiddenType, traits::ObligationCause},
+    },
+};
+
+impl<'db> InferenceContext<'_, 'db> {
+    /// This takes all the opaque type uses during HIR typeck. It first computes
+    /// the concrete hidden type by iterating over all defining uses.
+    ///
+    /// A use during HIR typeck is defining if all non-lifetime arguments are
+    /// unique generic parameters and the hidden type does not reference any
+    /// inference variables.
+    ///
+    /// It then uses these defining uses to guide inference for all other uses.
+    #[instrument(level = "debug", skip(self))]
+    pub(super) fn handle_opaque_type_uses(&mut self) {
+        // We clone the opaques instead of stealing them here as they are still used for
+        // normalization in the next generation trait solver.
+        let opaque_types: Vec<_> = self.table.infer_ctxt.clone_opaque_types();
+
+        self.compute_definition_site_hidden_types(opaque_types);
+    }
+}
+
+#[expect(unused, reason = "rustc has this")]
+#[derive(Copy, Clone, Debug)]
+enum UsageKind<'db> {
+    None,
+    NonDefiningUse(OpaqueTypeKey<'db>, OpaqueHiddenType<'db>),
+    UnconstrainedHiddenType(OpaqueHiddenType<'db>),
+    HasDefiningUse(OpaqueHiddenType<'db>),
+}
+
+impl<'db> UsageKind<'db> {
+    fn merge(&mut self, other: UsageKind<'db>) {
+        match (&*self, &other) {
+            (UsageKind::HasDefiningUse(_), _) | (_, UsageKind::None) => unreachable!(),
+            (UsageKind::None, _) => *self = other,
+            // When mergining non-defining uses, prefer earlier ones. This means
+            // the error happens as early as possible.
+            (
+                UsageKind::NonDefiningUse(..) | UsageKind::UnconstrainedHiddenType(..),
+                UsageKind::NonDefiningUse(..),
+            ) => {}
+            // When merging unconstrained hidden types, we prefer later ones. This is
+            // used as in most cases, the defining use is the final return statement
+            // of our function, and other uses with defining arguments are likely not
+            // intended to be defining.
+            (
+                UsageKind::NonDefiningUse(..) | UsageKind::UnconstrainedHiddenType(..),
+                UsageKind::UnconstrainedHiddenType(..) | UsageKind::HasDefiningUse(_),
+            ) => *self = other,
+        }
+    }
+}
+
+impl<'db> InferenceContext<'_, 'db> {
+    fn compute_definition_site_hidden_types(
+        &mut self,
+        mut opaque_types: Vec<(OpaqueTypeKey<'db>, OpaqueHiddenType<'db>)>,
+    ) {
+        for entry in opaque_types.iter_mut() {
+            *entry = self.table.infer_ctxt.resolve_vars_if_possible(*entry);
+        }
+        debug!(?opaque_types);
+
+        let interner = self.interner();
+        let TypingMode::Analysis { defining_opaque_types_and_generators } =
+            self.table.infer_ctxt.typing_mode()
+        else {
+            unreachable!();
+        };
+
+        for def_id in defining_opaque_types_and_generators {
+            let def_id = match def_id {
+                SolverDefId::InternedOpaqueTyId(it) => it,
+                _ => continue,
+            };
+
+            // We do actually need to check this the second pass (we can't just
+            // store this), because we can go from `UnconstrainedHiddenType` to
+            // `HasDefiningUse` (because of fallback)
+            let mut usage_kind = UsageKind::None;
+            for &(opaque_type_key, hidden_type) in &opaque_types {
+                if opaque_type_key.def_id != def_id.into() {
+                    continue;
+                }
+
+                usage_kind.merge(self.consider_opaque_type_use(opaque_type_key, hidden_type));
+
+                if let UsageKind::HasDefiningUse(..) = usage_kind {
+                    break;
+                }
+            }
+
+            if let UsageKind::HasDefiningUse(ty) = usage_kind {
+                for &(opaque_type_key, hidden_type) in &opaque_types {
+                    if opaque_type_key.def_id != def_id.into() {
+                        continue;
+                    }
+
+                    let expected =
+                        EarlyBinder::bind(ty.ty).instantiate(interner, opaque_type_key.args);
+                    self.demand_eqtype(expected, hidden_type.ty);
+                }
+
+                self.result.type_of_opaque.insert(def_id, ty.ty);
+
+                continue;
+            }
+
+            self.result.type_of_opaque.insert(def_id, self.types.error);
+        }
+    }
+
+    #[tracing::instrument(skip(self), ret)]
+    fn consider_opaque_type_use(
+        &self,
+        opaque_type_key: OpaqueTypeKey<'db>,
+        hidden_type: OpaqueHiddenType<'db>,
+    ) -> UsageKind<'db> {
+        // We ignore uses of the opaque if they have any inference variables
+        // as this can frequently happen with recursive calls.
+        //
+        // See `tests/ui/traits/next-solver/opaques/universal-args-non-defining.rs`.
+        if hidden_type.ty.has_non_region_infer() {
+            return UsageKind::UnconstrainedHiddenType(hidden_type);
+        }
+
+        let cause = ObligationCause::new();
+        let at = self.table.infer_ctxt.at(&cause, self.table.trait_env.env);
+        let hidden_type = match at.deeply_normalize(hidden_type) {
+            Ok(hidden_type) => hidden_type,
+            Err(_errors) => OpaqueHiddenType { ty: self.types.error },
+        };
+        let hidden_type = fold_regions(self.interner(), hidden_type, |_, _| self.types.re_erased);
+        UsageKind::HasDefiningUse(hidden_type)
+    }
+}
diff --git a/crates/hir-ty/src/infer/path.rs b/crates/hir-ty/src/infer/path.rs
index 2dae7cb..9ade842 100644
--- a/crates/hir-ty/src/infer/path.rs
+++ b/crates/hir-ty/src/infer/path.rs
@@ -310,9 +310,10 @@
         let mut not_visible = None;
         let res = method_resolution::iterate_method_candidates(
             &canonical_ty,
-            self.db,
-            self.table.trait_env.clone(),
-            self.get_traits_in_scope().as_ref().left_or_else(|&it| it),
+            &mut self.table,
+            Self::get_traits_in_scope(&self.resolver, &self.traits_in_scope)
+                .as_ref()
+                .left_or_else(|&it| it),
             VisibleFromModule::Filter(self.resolver.module()),
             Some(name),
             method_resolution::LookupMode::Path,
diff --git a/crates/hir-ty/src/infer/unify.rs b/crates/hir-ty/src/infer/unify.rs
index a18cdda..0f582a1 100644
--- a/crates/hir-ty/src/infer/unify.rs
+++ b/crates/hir-ty/src/infer/unify.rs
@@ -2,10 +2,10 @@
 
 use std::fmt;
 
-use hir_def::{AdtId, GenericParamId, lang_item::LangItem};
+use hir_def::{AdtId, DefWithBodyId, GenericParamId, lang_item::LangItem};
 use hir_expand::name::Name;
 use intern::sym;
-use rustc_hash::{FxHashMap, FxHashSet};
+use rustc_hash::FxHashSet;
 use rustc_type_ir::{
     DebruijnIndex, InferConst, InferTy, RegionVid, TyVid, TypeFoldable, TypeFolder,
     TypeSuperFoldable, TypeVisitableExt, UpcastFrom,
@@ -17,12 +17,12 @@
 
 use crate::{
     TraitEnvironment,
-    db::{HirDatabase, InternedOpaqueTyId},
+    db::HirDatabase,
     infer::InferenceContext,
     next_solver::{
         self, AliasTy, Binder, Canonical, ClauseKind, Const, ConstKind, DbInterner,
         ErrorGuaranteed, GenericArg, GenericArgs, Predicate, PredicateKind, Region, RegionKind,
-        SolverDefId, SolverDefIds, TraitRef, Ty, TyKind, TypingMode,
+        SolverDefId, TraitRef, Ty, TyKind, TypingMode,
         fulfill::{FulfillmentCtxt, NextSolverError},
         infer::{
             DbInternerInferExt, InferCtxt, InferOk, InferResult,
@@ -139,10 +139,7 @@
     select: for<'a> fn(&mut ObligationCtxt<'a, 'db>) -> Vec<NextSolverError<'db>>,
 ) -> bool {
     let interner = DbInterner::new_with(db, Some(env.krate), env.block);
-    // FIXME(next-solver): I believe this should use `PostAnalysis` (this is only used for IDE things),
-    // but this causes some bug because of our incorrect impl of `type_of_opaque_hir_typeck()` for TAIT
-    // and async blocks.
-    let infcx = interner.infer_ctxt().build(TypingMode::non_body_analysis());
+    let infcx = interner.infer_ctxt().build(TypingMode::PostAnalysis);
     let cause = ObligationCause::dummy();
     let at = infcx.at(&cause, env.env);
     let ((ty1_with_vars, ty2_with_vars), _) = infcx.instantiate_canonical(tys);
@@ -158,7 +155,6 @@
 pub(crate) struct InferenceTable<'db> {
     pub(crate) db: &'db dyn HirDatabase,
     pub(crate) trait_env: Arc<TraitEnvironment<'db>>,
-    pub(crate) tait_coercion_table: Option<FxHashMap<InternedOpaqueTyId, Ty<'db>>>,
     pub(crate) infer_ctxt: InferCtxt<'db>,
     pub(super) fulfillment_cx: FulfillmentCtxt<'db>,
     pub(super) diverging_type_vars: FxHashSet<Ty<'db>>,
@@ -170,15 +166,23 @@
 }
 
 impl<'db> InferenceTable<'db> {
-    pub(crate) fn new(db: &'db dyn HirDatabase, trait_env: Arc<TraitEnvironment<'db>>) -> Self {
+    /// Inside hir-ty you should use this for inference only, and always pass `owner`.
+    /// Outside it, always pass `owner = None`.
+    pub(crate) fn new(
+        db: &'db dyn HirDatabase,
+        trait_env: Arc<TraitEnvironment<'db>>,
+        owner: Option<DefWithBodyId>,
+    ) -> Self {
         let interner = DbInterner::new_with(db, Some(trait_env.krate), trait_env.block);
-        let infer_ctxt = interner.infer_ctxt().build(rustc_type_ir::TypingMode::Analysis {
-            defining_opaque_types_and_generators: SolverDefIds::new_from_iter(interner, []),
-        });
+        let typing_mode = match owner {
+            Some(owner) => TypingMode::typeck_for_body(interner, owner.into()),
+            // IDE things wants to reveal opaque types.
+            None => TypingMode::PostAnalysis,
+        };
+        let infer_ctxt = interner.infer_ctxt().build(typing_mode);
         InferenceTable {
             db,
             trait_env,
-            tait_coercion_table: None,
             fulfillment_cx: FulfillmentCtxt::new(&infer_ctxt),
             infer_ctxt,
             diverging_type_vars: FxHashSet::default(),
@@ -698,40 +702,7 @@
     where
         T: TypeFoldable<DbInterner<'db>>,
     {
-        struct Folder<'a, 'db> {
-            table: &'a mut InferenceTable<'db>,
-        }
-        impl<'db> TypeFolder<DbInterner<'db>> for Folder<'_, 'db> {
-            fn cx(&self) -> DbInterner<'db> {
-                self.table.interner()
-            }
-
-            fn fold_ty(&mut self, ty: Ty<'db>) -> Ty<'db> {
-                if !ty.references_error() {
-                    return ty;
-                }
-
-                if ty.is_ty_error() { self.table.next_ty_var() } else { ty.super_fold_with(self) }
-            }
-
-            fn fold_const(&mut self, ct: Const<'db>) -> Const<'db> {
-                if !ct.references_error() {
-                    return ct;
-                }
-
-                if ct.is_ct_error() {
-                    self.table.next_const_var()
-                } else {
-                    ct.super_fold_with(self)
-                }
-            }
-
-            fn fold_region(&mut self, r: Region<'db>) -> Region<'db> {
-                if r.is_error() { self.table.next_region_var() } else { r }
-            }
-        }
-
-        ty.fold_with(&mut Folder { table: self })
+        self.infer_ctxt.insert_type_vars(ty)
     }
 
     /// Replaces `Ty::Error` by a new type var, so we can maybe still infer it.
diff --git a/crates/hir-ty/src/lib.rs b/crates/hir-ty/src/lib.rs
index 25579e0..fdacc1d 100644
--- a/crates/hir-ty/src/lib.rs
+++ b/crates/hir-ty/src/lib.rs
@@ -27,9 +27,11 @@
 mod inhabitedness;
 mod lower;
 pub mod next_solver;
+mod opaques;
 mod specialization;
 mod target_feature;
 mod utils;
+mod variance;
 
 pub mod autoderef;
 pub mod consteval;
@@ -50,7 +52,6 @@
 mod test_db;
 #[cfg(test)]
 mod tests;
-mod variance;
 
 use std::hash::Hash;
 
@@ -471,6 +472,7 @@
     }
 }
 
+/// To be used from `hir` only.
 pub fn callable_sig_from_fn_trait<'db>(
     self_ty: Ty<'db>,
     trait_env: Arc<TraitEnvironment<'db>>,
@@ -482,7 +484,7 @@
         .trait_items(db)
         .associated_type_by_name(&Name::new_symbol_root(sym::Output))?;
 
-    let mut table = InferenceTable::new(db, trait_env.clone());
+    let mut table = InferenceTable::new(db, trait_env.clone(), None);
 
     // Register two obligations:
     // - Self: FnOnce<?args_ty>
diff --git a/crates/hir-ty/src/method_resolution.rs b/crates/hir-ty/src/method_resolution.rs
index cec6356..1e30897 100644
--- a/crates/hir-ty/src/method_resolution.rs
+++ b/crates/hir-ty/src/method_resolution.rs
@@ -489,9 +489,8 @@
 
 /// Look up the method with the given name.
 pub(crate) fn lookup_method<'db>(
-    db: &'db dyn HirDatabase,
     ty: &Canonical<'db, Ty<'db>>,
-    env: Arc<TraitEnvironment<'db>>,
+    table: &mut InferenceTable<'db>,
     traits_in_scope: &FxHashSet<TraitId>,
     visible_from_module: VisibleFromModule,
     name: &Name,
@@ -499,8 +498,7 @@
     let mut not_visible = None;
     let res = iterate_method_candidates(
         ty,
-        db,
-        env,
+        table,
         traits_in_scope,
         visible_from_module,
         Some(name),
@@ -656,8 +654,7 @@
 // FIXME add a context type here?
 pub(crate) fn iterate_method_candidates<'db, T>(
     ty: &Canonical<'db, Ty<'db>>,
-    db: &'db dyn HirDatabase,
-    env: Arc<TraitEnvironment<'db>>,
+    table: &mut InferenceTable<'db>,
     traits_in_scope: &FxHashSet<TraitId>,
     visible_from_module: VisibleFromModule,
     name: Option<&Name>,
@@ -665,10 +662,9 @@
     mut callback: impl FnMut(ReceiverAdjustments, AssocItemId, bool) -> Option<T>,
 ) -> Option<T> {
     let mut slot = None;
-    _ = iterate_method_candidates_dyn(
+    _ = iterate_method_candidates_dyn_impl(
         ty,
-        db,
-        env,
+        table,
         traits_in_scope,
         visible_from_module,
         name,
@@ -985,6 +981,7 @@
     is_not_orphan
 }
 
+/// To be used from `hir` only.
 pub fn iterate_path_candidates<'db>(
     ty: &Canonical<'db, Ty<'db>>,
     db: &'db dyn HirDatabase,
@@ -1007,6 +1004,7 @@
     )
 }
 
+/// To be used from `hir` only.
 pub fn iterate_method_candidates_dyn<'db>(
     ty: &Canonical<'db, Ty<'db>>,
     db: &'db dyn HirDatabase,
@@ -1017,6 +1015,26 @@
     mode: LookupMode,
     callback: &mut dyn MethodCandidateCallback,
 ) -> ControlFlow<()> {
+    iterate_method_candidates_dyn_impl(
+        ty,
+        &mut InferenceTable::new(db, env, None),
+        traits_in_scope,
+        visible_from_module,
+        name,
+        mode,
+        callback,
+    )
+}
+
+fn iterate_method_candidates_dyn_impl<'db>(
+    ty: &Canonical<'db, Ty<'db>>,
+    table: &mut InferenceTable<'db>,
+    traits_in_scope: &FxHashSet<TraitId>,
+    visible_from_module: VisibleFromModule,
+    name: Option<&Name>,
+    mode: LookupMode,
+    callback: &mut dyn MethodCandidateCallback,
+) -> ControlFlow<()> {
     let _p = tracing::info_span!(
         "iterate_method_candidates_dyn",
         ?mode,
@@ -1046,28 +1064,28 @@
             // the methods by autoderef order of *receiver types*, not *self
             // types*.
 
-            let mut table = InferenceTable::new(db, env);
-            let ty = table.instantiate_canonical(*ty);
-            let deref_chain = autoderef_method_receiver(&mut table, ty);
+            table.run_in_snapshot(|table| {
+                let ty = table.instantiate_canonical(*ty);
+                let deref_chain = autoderef_method_receiver(table, ty);
 
-            deref_chain.into_iter().try_for_each(|(receiver_ty, adj)| {
-                iterate_method_candidates_with_autoref(
-                    &mut table,
-                    receiver_ty,
-                    adj,
-                    traits_in_scope,
-                    visible_from_module,
-                    name,
-                    callback,
-                )
+                deref_chain.into_iter().try_for_each(|(receiver_ty, adj)| {
+                    iterate_method_candidates_with_autoref(
+                        table,
+                        receiver_ty,
+                        adj,
+                        traits_in_scope,
+                        visible_from_module,
+                        name,
+                        callback,
+                    )
+                })
             })
         }
         LookupMode::Path => {
             // No autoderef for path lookups
             iterate_method_candidates_for_self_ty(
                 ty,
-                db,
-                env,
+                table,
                 traits_in_scope,
                 visible_from_module,
                 name,
@@ -1250,39 +1268,39 @@
 #[tracing::instrument(skip_all, fields(name = ?name))]
 fn iterate_method_candidates_for_self_ty<'db>(
     self_ty: &Canonical<'db, Ty<'db>>,
-    db: &'db dyn HirDatabase,
-    env: Arc<TraitEnvironment<'db>>,
+    table: &mut InferenceTable<'db>,
     traits_in_scope: &FxHashSet<TraitId>,
     visible_from_module: VisibleFromModule,
     name: Option<&Name>,
     callback: &mut dyn MethodCandidateCallback,
 ) -> ControlFlow<()> {
-    let mut table = InferenceTable::new(db, env);
-    let self_ty = table.instantiate_canonical(*self_ty);
-    iterate_inherent_methods(
-        self_ty,
-        &mut table,
-        name,
-        None,
-        None,
-        visible_from_module,
-        LookupMode::Path,
-        &mut |adjustments, item, is_visible| {
-            callback.on_inherent_method(adjustments, item, is_visible)
-        },
-    )?;
-    iterate_trait_method_candidates(
-        self_ty,
-        &mut table,
-        traits_in_scope,
-        name,
-        None,
-        None,
-        LookupMode::Path,
-        &mut |adjustments, item, is_visible| {
-            callback.on_trait_method(adjustments, item, is_visible)
-        },
-    )
+    table.run_in_snapshot(|table| {
+        let self_ty = table.instantiate_canonical(*self_ty);
+        iterate_inherent_methods(
+            self_ty,
+            table,
+            name,
+            None,
+            None,
+            visible_from_module,
+            LookupMode::Path,
+            &mut |adjustments, item, is_visible| {
+                callback.on_inherent_method(adjustments, item, is_visible)
+            },
+        )?;
+        iterate_trait_method_candidates(
+            self_ty,
+            table,
+            traits_in_scope,
+            name,
+            None,
+            None,
+            LookupMode::Path,
+            &mut |adjustments, item, is_visible| {
+                callback.on_trait_method(adjustments, item, is_visible)
+            },
+        )
+    })
 }
 
 #[tracing::instrument(skip_all, fields(name = ?name, visible_from_module, receiver_ty))]
diff --git a/crates/hir-ty/src/mir/borrowck.rs b/crates/hir-ty/src/mir/borrowck.rs
index db16c94..0189265 100644
--- a/crates/hir-ty/src/mir/borrowck.rs
+++ b/crates/hir-ty/src/mir/borrowck.rs
@@ -17,7 +17,7 @@
     display::DisplayTarget,
     mir::OperandKind,
     next_solver::{
-        DbInterner, GenericArgs, SolverDefIds, Ty, TypingMode,
+        DbInterner, GenericArgs, Ty, TypingMode,
         infer::{DbInternerInferExt, InferCtxt},
     },
 };
@@ -100,11 +100,11 @@
     let interner = DbInterner::new_with(db, Some(module.krate()), module.containing_block());
     let env = db.trait_environment_for_body(def);
     let mut res = vec![];
+    // This calculates opaques defining scope which is a bit costly therefore is put outside `all_mir_bodies()`.
+    let typing_mode = TypingMode::borrowck(interner, def.into());
     all_mir_bodies(db, def, |body| {
         // FIXME(next-solver): Opaques.
-        let infcx = interner.infer_ctxt().build(TypingMode::Borrowck {
-            defining_opaque_types: SolverDefIds::new_from_iter(interner, []),
-        });
+        let infcx = interner.infer_ctxt().build(typing_mode);
         res.push(BorrowckResult {
             mutability_of_locals: mutability_of_locals(&infcx, &body),
             moved_out_of_ref: moved_out_of_ref(&infcx, &env, &body),
diff --git a/crates/hir-ty/src/next_solver/def_id.rs b/crates/hir-ty/src/next_solver/def_id.rs
index 0ff0b08..77f2106 100644
--- a/crates/hir-ty/src/next_solver/def_id.rs
+++ b/crates/hir-ty/src/next_solver/def_id.rs
@@ -154,6 +154,29 @@
     }
 }
 
+impl TryFrom<SolverDefId> for DefWithBodyId {
+    type Error = ();
+
+    #[inline]
+    fn try_from(value: SolverDefId) -> Result<Self, Self::Error> {
+        let id = match value {
+            SolverDefId::ConstId(id) => id.into(),
+            SolverDefId::FunctionId(id) => id.into(),
+            SolverDefId::StaticId(id) => id.into(),
+            SolverDefId::EnumVariantId(id) | SolverDefId::Ctor(Ctor::Enum(id)) => id.into(),
+            SolverDefId::InternedOpaqueTyId(_)
+            | SolverDefId::TraitId(_)
+            | SolverDefId::TypeAliasId(_)
+            | SolverDefId::ImplId(_)
+            | SolverDefId::InternedClosureId(_)
+            | SolverDefId::InternedCoroutineId(_)
+            | SolverDefId::Ctor(Ctor::Struct(_))
+            | SolverDefId::AdtId(_) => return Err(()),
+        };
+        Ok(id)
+    }
+}
+
 impl TryFrom<SolverDefId> for GenericDefId {
     type Error = ();
 
diff --git a/crates/hir-ty/src/next_solver/generic_arg.rs b/crates/hir-ty/src/next_solver/generic_arg.rs
index 90bd44a..dedd6a1 100644
--- a/crates/hir-ty/src/next_solver/generic_arg.rs
+++ b/crates/hir-ty/src/next_solver/generic_arg.rs
@@ -63,6 +63,14 @@
         }
     }
 
+    #[inline]
+    pub(crate) fn expect_region(self) -> Region<'db> {
+        match self {
+            GenericArg::Lifetime(region) => region,
+            _ => panic!("expected a region, got {self:?}"),
+        }
+    }
+
     pub fn error_from_id(interner: DbInterner<'db>, id: GenericParamId) -> GenericArg<'db> {
         match id {
             GenericParamId::TypeParamId(_) => Ty::new_error(interner, ErrorGuaranteed).into(),
diff --git a/crates/hir-ty/src/next_solver/infer/mod.rs b/crates/hir-ty/src/next_solver/infer/mod.rs
index 36c6c48..7b8f52b 100644
--- a/crates/hir-ty/src/next_solver/infer/mod.rs
+++ b/crates/hir-ty/src/next_solver/infer/mod.rs
@@ -13,27 +13,27 @@
 use region_constraints::{RegionConstraintCollector, RegionConstraintStorage};
 use rustc_next_trait_solver::solve::SolverDelegateEvalExt;
 use rustc_pattern_analysis::Captures;
-use rustc_type_ir::TypeFoldable;
-use rustc_type_ir::error::{ExpectedFound, TypeError};
-use rustc_type_ir::inherent::{
-    Const as _, GenericArg as _, GenericArgs as _, IntoKind, SliceLike, Term as _, Ty as _,
-};
 use rustc_type_ir::{
     ClosureKind, ConstVid, FloatVarValue, FloatVid, GenericArgKind, InferConst, InferTy,
-    IntVarValue, IntVid, OutlivesPredicate, RegionVid, TyVid, UniverseIndex,
+    IntVarValue, IntVid, OutlivesPredicate, RegionVid, TermKind, TyVid, TypeFoldable, TypeFolder,
+    TypeSuperFoldable, TypeVisitableExt, UniverseIndex,
+    error::{ExpectedFound, TypeError},
+    inherent::{
+        Const as _, GenericArg as _, GenericArgs as _, IntoKind, SliceLike, Term as _, Ty as _,
+    },
 };
-use rustc_type_ir::{TermKind, TypeVisitableExt};
 use snapshot::undo_log::InferCtxtUndoLogs;
 use tracing::{debug, instrument};
 use traits::{ObligationCause, PredicateObligations};
 use type_variable::TypeVariableOrigin;
 use unify_key::{ConstVariableOrigin, ConstVariableValue, ConstVidKey};
 
-use crate::next_solver::fold::BoundVarReplacerDelegate;
-use crate::next_solver::infer::select::EvaluationResult;
-use crate::next_solver::infer::traits::PredicateObligation;
-use crate::next_solver::obligation_ctxt::ObligationCtxt;
-use crate::next_solver::{BoundConst, BoundRegion, BoundTy, BoundVarKind, Goal, SolverContext};
+use crate::next_solver::{
+    BoundConst, BoundRegion, BoundTy, BoundVarKind, Goal, SolverContext,
+    fold::BoundVarReplacerDelegate,
+    infer::{select::EvaluationResult, traits::PredicateObligation},
+    obligation_ctxt::ObligationCtxt,
+};
 
 use super::{
     AliasTerm, Binder, CanonicalQueryInput, CanonicalVarValues, Const, ConstKind, DbInterner,
@@ -46,7 +46,7 @@
 pub mod at;
 pub mod canonical;
 mod context;
-mod opaque_types;
+pub mod opaque_types;
 pub mod region_constraints;
 pub mod relate;
 pub mod resolve;
@@ -400,6 +400,46 @@
         ))
     }
 
+    pub(crate) fn insert_type_vars<T>(&self, ty: T) -> T
+    where
+        T: TypeFoldable<DbInterner<'db>>,
+    {
+        struct Folder<'a, 'db> {
+            infcx: &'a InferCtxt<'db>,
+        }
+        impl<'db> TypeFolder<DbInterner<'db>> for Folder<'_, 'db> {
+            fn cx(&self) -> DbInterner<'db> {
+                self.infcx.interner
+            }
+
+            fn fold_ty(&mut self, ty: Ty<'db>) -> Ty<'db> {
+                if !ty.references_error() {
+                    return ty;
+                }
+
+                if ty.is_ty_error() { self.infcx.next_ty_var() } else { ty.super_fold_with(self) }
+            }
+
+            fn fold_const(&mut self, ct: Const<'db>) -> Const<'db> {
+                if !ct.references_error() {
+                    return ct;
+                }
+
+                if ct.is_ct_error() {
+                    self.infcx.next_const_var()
+                } else {
+                    ct.super_fold_with(self)
+                }
+            }
+
+            fn fold_region(&mut self, r: Region<'db>) -> Region<'db> {
+                if r.is_error() { self.infcx.next_region_var() } else { r }
+            }
+        }
+
+        ty.fold_with(&mut Folder { infcx: self })
+    }
+
     /// Evaluates whether the predicate can be satisfied in the given
     /// `ParamEnv`, and returns `false` if not certain. However, this is
     /// not entirely accurate if inference variables are involved.
diff --git a/crates/hir-ty/src/next_solver/infer/opaque_types/mod.rs b/crates/hir-ty/src/next_solver/infer/opaque_types/mod.rs
index 06d9984..6b6104b 100644
--- a/crates/hir-ty/src/next_solver/infer/opaque_types/mod.rs
+++ b/crates/hir-ty/src/next_solver/infer/opaque_types/mod.rs
@@ -4,9 +4,11 @@
 
 pub(crate) use table::{OpaqueTypeStorage, OpaqueTypeTable};
 
+use macros::{TypeFoldable, TypeVisitable};
+
 use crate::next_solver::{OpaqueTypeKey, Ty, infer::InferCtxt};
 
-#[derive(Copy, Clone, Debug)]
+#[derive(Copy, Clone, Debug, TypeVisitable, TypeFoldable)]
 pub struct OpaqueHiddenType<'db> {
     pub ty: Ty<'db>,
 }
diff --git a/crates/hir-ty/src/next_solver/infer/opaque_types/table.rs b/crates/hir-ty/src/next_solver/infer/opaque_types/table.rs
index 0f8b238..00177d2 100644
--- a/crates/hir-ty/src/next_solver/infer/opaque_types/table.rs
+++ b/crates/hir-ty/src/next_solver/infer/opaque_types/table.rs
@@ -122,14 +122,6 @@
     }
 }
 
-impl<'db> Drop for OpaqueTypeStorage<'db> {
-    fn drop(&mut self) {
-        if !self.opaque_types.is_empty() {
-            panic!("{:?}", self.opaque_types)
-        }
-    }
-}
-
 pub(crate) struct OpaqueTypeTable<'a, 'db> {
     storage: &'a mut OpaqueTypeStorage<'db>,
 
diff --git a/crates/hir-ty/src/next_solver/interner.rs b/crates/hir-ty/src/next_solver/interner.rs
index c1ccbaf..b18e08b 100644
--- a/crates/hir-ty/src/next_solver/interner.rs
+++ b/crates/hir-ty/src/next_solver/interner.rs
@@ -7,8 +7,8 @@
 
 use base_db::Crate;
 use hir_def::{
-    AdtId, AttrDefId, BlockId, CallableDefId, EnumVariantId, ItemContainerId, StructId, UnionId,
-    VariantId,
+    AdtId, AttrDefId, BlockId, CallableDefId, DefWithBodyId, EnumVariantId, ItemContainerId,
+    StructId, UnionId, VariantId,
     lang_item::LangItem,
     signatures::{FieldData, FnFlags, ImplFlags, StructFlags, TraitFlags},
 };
@@ -29,7 +29,7 @@
 
 use crate::{
     FnAbi,
-    db::{HirDatabase, InternedCoroutine},
+    db::{HirDatabase, InternedCoroutine, InternedCoroutineId},
     method_resolution::{ALL_FLOAT_FPS, ALL_INT_FPS, TyFingerprint},
     next_solver::{
         AdtIdWrapper, BoundConst, CallableIdWrapper, CanonicalVarKind, ClosureIdWrapper,
@@ -96,7 +96,7 @@
         }
     };
     ($name:ident, $ty:ty, nofold) => {
-        #[salsa::interned(constructor = new_, debug)]
+        #[salsa::interned(constructor = new_)]
         pub struct $name {
             #[returns(ref)]
             inner_: smallvec::SmallVec<[$ty; 2]>,
@@ -119,6 +119,12 @@
             }
         }
 
+        impl<'db> std::fmt::Debug for $name<'db> {
+            fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+                self.as_slice().fmt(fmt)
+            }
+        }
+
         impl<'db> rustc_type_ir::inherent::SliceLike for $name<'db> {
             type Item = $ty;
 
@@ -1866,9 +1872,42 @@
         Binder::bind_with_vars(inner, bound_vars)
     }
 
-    fn opaque_types_defined_by(self, _defining_anchor: Self::LocalDefId) -> Self::LocalDefIds {
-        // FIXME(next-solver)
-        SolverDefIds::new_from_iter(self, [])
+    fn opaque_types_defined_by(self, def_id: Self::LocalDefId) -> Self::LocalDefIds {
+        let Ok(def_id) = DefWithBodyId::try_from(def_id) else {
+            return SolverDefIds::default();
+        };
+        let mut result = Vec::new();
+        crate::opaques::opaque_types_defined_by(self.db, def_id, &mut result);
+        SolverDefIds::new_from_iter(self, result)
+    }
+
+    fn opaque_types_and_coroutines_defined_by(self, def_id: Self::LocalDefId) -> Self::LocalDefIds {
+        let Ok(def_id) = DefWithBodyId::try_from(def_id) else {
+            return SolverDefIds::default();
+        };
+        let mut result = Vec::new();
+
+        crate::opaques::opaque_types_defined_by(self.db, def_id, &mut result);
+
+        // Collect coroutines.
+        let body = self.db.body(def_id);
+        body.exprs().for_each(|(expr_id, expr)| {
+            if matches!(
+                expr,
+                hir_def::hir::Expr::Async { .. }
+                    | hir_def::hir::Expr::Closure {
+                        closure_kind: hir_def::hir::ClosureKind::Async
+                            | hir_def::hir::ClosureKind::Coroutine(_),
+                        ..
+                    }
+            ) {
+                let coroutine =
+                    InternedCoroutineId::new(self.db, InternedCoroutine(def_id, expr_id));
+                result.push(coroutine.into());
+            }
+        });
+
+        SolverDefIds::new_from_iter(self, result)
     }
 
     fn alias_has_const_conditions(self, _def_id: Self::DefId) -> bool {
@@ -1913,12 +1952,10 @@
                 let impl_trait_id = self.db().lookup_intern_impl_trait_id(opaque);
                 match impl_trait_id {
                     crate::ImplTraitId::ReturnTypeImplTrait(func, idx) => {
-                        let infer = self.db().infer(func.into());
-                        EarlyBinder::bind(infer.type_of_rpit[idx])
+                        crate::opaques::rpit_hidden_types(self.db, func)[idx]
                     }
-                    crate::ImplTraitId::TypeAliasImplTrait(..) => {
-                        // FIXME(next-solver)
-                        EarlyBinder::bind(Ty::new_error(self, ErrorGuaranteed))
+                    crate::ImplTraitId::TypeAliasImplTrait(type_alias, idx) => {
+                        crate::opaques::tait_hidden_types(self.db, type_alias)[idx]
                     }
                 }
             }
@@ -1969,13 +2006,6 @@
         true
     }
 
-    fn opaque_types_and_coroutines_defined_by(
-        self,
-        _defining_anchor: Self::LocalDefId,
-    ) -> Self::LocalDefIds {
-        Default::default()
-    }
-
     type Probe = rustc_type_ir::solve::inspect::Probe<DbInterner<'db>>;
     fn mk_probe(self, probe: rustc_type_ir::solve::inspect::Probe<Self>) -> Self::Probe {
         probe
diff --git a/crates/hir-ty/src/next_solver/solver.rs b/crates/hir-ty/src/next_solver/solver.rs
index 487d164..7b96b40 100644
--- a/crates/hir-ty/src/next_solver/solver.rs
+++ b/crates/hir-ty/src/next_solver/solver.rs
@@ -2,17 +2,22 @@
 
 use hir_def::{AssocItemId, GeneralConstId};
 use rustc_next_trait_solver::delegate::SolverDelegate;
-use rustc_type_ir::GenericArgKind;
-use rustc_type_ir::lang_items::SolverTraitLangItem;
 use rustc_type_ir::{
-    InferCtxtLike, Interner, PredicatePolarity, TypeFlags, TypeVisitableExt,
-    inherent::{IntoKind, Term as _, Ty as _},
+    AliasTyKind, GenericArgKind, InferCtxtLike, Interner, PredicatePolarity, TypeFlags,
+    TypeVisitableExt,
+    inherent::{IntoKind, SliceLike, Term as _, Ty as _},
+    lang_items::SolverTraitLangItem,
     solve::{Certainty, NoSolution},
 };
+use tracing::debug;
 
-use crate::next_solver::{CanonicalVarKind, ImplIdWrapper};
-use crate::next_solver::{
-    ClauseKind, CoercePredicate, PredicateKind, SubtypePredicate, util::sizedness_fast_path,
+use crate::{
+    ImplTraitId,
+    next_solver::{
+        AliasTy, CanonicalVarKind, Clause, ClauseKind, CoercePredicate, GenericArgs, ImplIdWrapper,
+        ParamEnv, Predicate, PredicateKind, SubtypePredicate, Ty, TyKind, fold::fold_tys,
+        util::sizedness_fast_path,
+    },
 };
 
 use super::{
@@ -76,7 +81,7 @@
 
     fn well_formed_goals(
         &self,
-        _param_env: <Self::Interner as rustc_type_ir::Interner>::ParamEnv,
+        _param_env: ParamEnv<'db>,
         _arg: <Self::Interner as rustc_type_ir::Interner>::Term,
     ) -> Option<
         Vec<
@@ -125,18 +130,60 @@
 
     fn add_item_bounds_for_hidden_type(
         &self,
-        _def_id: <Self::Interner as rustc_type_ir::Interner>::DefId,
-        _args: <Self::Interner as rustc_type_ir::Interner>::GenericArgs,
-        _param_env: <Self::Interner as rustc_type_ir::Interner>::ParamEnv,
-        _hidden_ty: <Self::Interner as rustc_type_ir::Interner>::Ty,
-        _goals: &mut Vec<
-            rustc_type_ir::solve::Goal<
-                Self::Interner,
-                <Self::Interner as rustc_type_ir::Interner>::Predicate,
-            >,
-        >,
+        def_id: SolverDefId,
+        args: GenericArgs<'db>,
+        param_env: ParamEnv<'db>,
+        hidden_ty: Ty<'db>,
+        goals: &mut Vec<Goal<'db, Predicate<'db>>>,
     ) {
-        unimplemented!()
+        let interner = self.interner;
+        let opaque_id = def_id.expect_opaque_ty();
+        // Require that the hidden type is well-formed. We have to
+        // make sure we wf-check the hidden type to fix #114728.
+        //
+        // However, we don't check that all types are well-formed.
+        // We only do so for types provided by the user or if they are
+        // "used", e.g. for method selection.
+        //
+        // This means we never check the wf requirements of the hidden
+        // type during MIR borrowck, causing us to infer the wrong
+        // lifetime for its member constraints which then results in
+        // unexpected region errors.
+        goals.push(Goal::new(interner, param_env, ClauseKind::WellFormed(hidden_ty.into())));
+
+        let replace_opaques_in = |clause: Clause<'db>| {
+            fold_tys(interner, clause, |ty| match ty.kind() {
+                // Replace all other mentions of the same opaque type with the hidden type,
+                // as the bounds must hold on the hidden type after all.
+                TyKind::Alias(
+                    AliasTyKind::Opaque,
+                    AliasTy { def_id: def_id2, args: args2, .. },
+                ) if def_id == def_id2 && args == args2 => hidden_ty,
+                _ => ty,
+            })
+        };
+
+        let db = interner.db;
+        let (opaques_table, opaque_idx) = match opaque_id.loc(db) {
+            ImplTraitId::ReturnTypeImplTrait(func, opaque_idx) => {
+                (db.return_type_impl_traits(func), opaque_idx)
+            }
+            ImplTraitId::TypeAliasImplTrait(type_alias, opaque_idx) => {
+                (db.type_alias_impl_traits(type_alias), opaque_idx)
+            }
+        };
+        let item_bounds = opaques_table
+            .as_deref()
+            .unwrap()
+            .as_ref()
+            .map_bound(|table| &table.impl_traits[opaque_idx].predicates);
+        for predicate in item_bounds.iter_instantiated_copied(interner, args.as_slice()) {
+            let predicate = replace_opaques_in(predicate);
+
+            // Require that the predicate holds for the concrete type.
+            debug!(?predicate);
+            goals.push(Goal::new(interner, param_env, predicate));
+        }
     }
 
     fn fetch_eligible_assoc_item(
@@ -190,8 +237,8 @@
 
     fn is_transmutable(
         &self,
-        _dst: <Self::Interner as rustc_type_ir::Interner>::Ty,
-        _src: <Self::Interner as rustc_type_ir::Interner>::Ty,
+        _dst: Ty<'db>,
+        _src: Ty<'db>,
         _assume: <Self::Interner as rustc_type_ir::Interner>::Const,
     ) -> Result<Certainty, NoSolution> {
         unimplemented!()
@@ -199,7 +246,7 @@
 
     fn evaluate_const(
         &self,
-        _param_env: <Self::Interner as rustc_type_ir::Interner>::ParamEnv,
+        _param_env: ParamEnv<'db>,
         uv: rustc_type_ir::UnevaluatedConst<Self::Interner>,
     ) -> Option<<Self::Interner as rustc_type_ir::Interner>::Const> {
         let c = match uv.def {
diff --git a/crates/hir-ty/src/opaques.rs b/crates/hir-ty/src/opaques.rs
new file mode 100644
index 0000000..8531f24
--- /dev/null
+++ b/crates/hir-ty/src/opaques.rs
@@ -0,0 +1,199 @@
+//! Handling of opaque types, detection of defining scope and hidden type.
+
+use hir_def::{
+    AssocItemId, AssocItemLoc, DefWithBodyId, FunctionId, HasModule, ItemContainerId, TypeAliasId,
+};
+use hir_expand::name::Name;
+use la_arena::ArenaMap;
+use rustc_type_ir::inherent::Ty as _;
+use syntax::ast;
+use triomphe::Arc;
+
+use crate::{
+    ImplTraitId,
+    db::{HirDatabase, InternedOpaqueTyId},
+    lower::{ImplTraitIdx, ImplTraits},
+    next_solver::{
+        DbInterner, EarlyBinder, ErrorGuaranteed, SolverDefId, Ty, TypingMode,
+        infer::{DbInternerInferExt, traits::ObligationCause},
+        obligation_ctxt::ObligationCtxt,
+    },
+};
+
+pub(crate) fn opaque_types_defined_by(
+    db: &dyn HirDatabase,
+    def_id: DefWithBodyId,
+    result: &mut Vec<SolverDefId>,
+) {
+    if let DefWithBodyId::FunctionId(func) = def_id {
+        // A function may define its own RPITs.
+        extend_with_opaques(
+            db,
+            db.return_type_impl_traits(func),
+            |opaque_idx| ImplTraitId::ReturnTypeImplTrait(func, opaque_idx),
+            result,
+        );
+    }
+
+    let extend_with_taits = |type_alias| {
+        extend_with_opaques(
+            db,
+            db.type_alias_impl_traits(type_alias),
+            |opaque_idx| ImplTraitId::TypeAliasImplTrait(type_alias, opaque_idx),
+            result,
+        );
+    };
+
+    // Collect opaques from assoc items.
+    let extend_with_atpit_from_assoc_items = |assoc_items: &[(Name, AssocItemId)]| {
+        assoc_items
+            .iter()
+            .filter_map(|&(_, assoc_id)| match assoc_id {
+                AssocItemId::TypeAliasId(it) => Some(it),
+                AssocItemId::FunctionId(_) | AssocItemId::ConstId(_) => None,
+            })
+            .for_each(extend_with_taits);
+    };
+    let extend_with_atpit_from_container = |container| match container {
+        ItemContainerId::ImplId(impl_id) => {
+            if db.impl_signature(impl_id).target_trait.is_some() {
+                extend_with_atpit_from_assoc_items(&impl_id.impl_items(db).items);
+            }
+        }
+        ItemContainerId::TraitId(trait_id) => {
+            extend_with_atpit_from_assoc_items(&trait_id.trait_items(db).items);
+        }
+        _ => {}
+    };
+    match def_id {
+        DefWithBodyId::ConstId(id) => extend_with_atpit_from_container(id.loc(db).container),
+        DefWithBodyId::FunctionId(id) => extend_with_atpit_from_container(id.loc(db).container),
+        DefWithBodyId::StaticId(_) | DefWithBodyId::VariantId(_) => {}
+    }
+
+    // FIXME: Collect opaques from `#[define_opaque]`.
+
+    fn extend_with_opaques<'db>(
+        db: &'db dyn HirDatabase,
+        opaques: Option<Arc<EarlyBinder<'db, ImplTraits<'db>>>>,
+        mut make_impl_trait: impl FnMut(ImplTraitIdx<'db>) -> ImplTraitId<'db>,
+        result: &mut Vec<SolverDefId>,
+    ) {
+        if let Some(opaques) = opaques {
+            for (opaque_idx, _) in (*opaques).as_ref().skip_binder().impl_traits.iter() {
+                let opaque_id = InternedOpaqueTyId::new(db, make_impl_trait(opaque_idx));
+                result.push(opaque_id.into());
+            }
+        }
+    }
+}
+
+// These are firewall queries to prevent drawing dependencies between infers:
+
+#[salsa::tracked(returns(ref), unsafe(non_update_return_type))]
+pub(crate) fn rpit_hidden_types<'db>(
+    db: &'db dyn HirDatabase,
+    function: FunctionId,
+) -> ArenaMap<ImplTraitIdx<'db>, EarlyBinder<'db, Ty<'db>>> {
+    let infer = db.infer(function.into());
+    let mut result = ArenaMap::new();
+    for (opaque, hidden_type) in infer.return_position_impl_trait_types(db) {
+        result.insert(opaque, EarlyBinder::bind(hidden_type));
+    }
+    result.shrink_to_fit();
+    result
+}
+
+#[salsa::tracked(returns(ref), unsafe(non_update_return_type))]
+pub(crate) fn tait_hidden_types<'db>(
+    db: &'db dyn HirDatabase,
+    type_alias: TypeAliasId,
+) -> ArenaMap<ImplTraitIdx<'db>, EarlyBinder<'db, Ty<'db>>> {
+    let loc = type_alias.loc(db);
+    let module = loc.module(db);
+    let interner = DbInterner::new_with(db, Some(module.krate()), module.containing_block());
+    let infcx = interner.infer_ctxt().build(TypingMode::non_body_analysis());
+    let mut ocx = ObligationCtxt::new(&infcx);
+    let cause = ObligationCause::dummy();
+    let param_env = db.trait_environment(type_alias.into()).env;
+
+    let defining_bodies = tait_defining_bodies(db, &loc);
+
+    let taits_count = db
+        .type_alias_impl_traits(type_alias)
+        .map_or(0, |taits| (*taits).as_ref().skip_binder().impl_traits.len());
+
+    let mut result = ArenaMap::with_capacity(taits_count);
+    for defining_body in defining_bodies {
+        let infer = db.infer(defining_body);
+        for (&opaque, &hidden_type) in &infer.type_of_opaque {
+            let ImplTraitId::TypeAliasImplTrait(opaque_owner, opaque_idx) = opaque.loc(db) else {
+                continue;
+            };
+            if opaque_owner != type_alias {
+                continue;
+            }
+            // In the presence of errors, we attempt to create a unified type from all
+            // types. rustc doesn't do that, but this should improve the experience.
+            let hidden_type = infcx.insert_type_vars(hidden_type);
+            match result.entry(opaque_idx) {
+                la_arena::Entry::Vacant(entry) => {
+                    entry.insert(EarlyBinder::bind(hidden_type));
+                }
+                la_arena::Entry::Occupied(entry) => {
+                    _ = ocx.eq(&cause, param_env, entry.get().instantiate_identity(), hidden_type);
+                }
+            }
+        }
+    }
+
+    _ = ocx.try_evaluate_obligations();
+
+    // Fill missing entries.
+    for idx in 0..taits_count {
+        let idx = la_arena::Idx::from_raw(la_arena::RawIdx::from_u32(idx as u32));
+        match result.entry(idx) {
+            la_arena::Entry::Vacant(entry) => {
+                entry.insert(EarlyBinder::bind(Ty::new_error(interner, ErrorGuaranteed)));
+            }
+            la_arena::Entry::Occupied(mut entry) => {
+                *entry.get_mut() = entry.get().map_bound(|hidden_type| {
+                    infcx.resolve_vars_if_possible(hidden_type).replace_infer_with_error(interner)
+                });
+            }
+        }
+    }
+
+    result
+}
+
+fn tait_defining_bodies(
+    db: &dyn HirDatabase,
+    loc: &AssocItemLoc<ast::TypeAlias>,
+) -> Vec<DefWithBodyId> {
+    let from_assoc_items = |assoc_items: &[(Name, AssocItemId)]| {
+        // Associated Type Position Impl Trait.
+        assoc_items
+            .iter()
+            .filter_map(|&(_, assoc_id)| match assoc_id {
+                AssocItemId::FunctionId(it) => Some(it.into()),
+                AssocItemId::ConstId(it) => Some(it.into()),
+                AssocItemId::TypeAliasId(_) => None,
+            })
+            .collect()
+    };
+    match loc.container {
+        ItemContainerId::ImplId(impl_id) => {
+            if db.impl_signature(impl_id).target_trait.is_some() {
+                return from_assoc_items(&impl_id.impl_items(db).items);
+            }
+        }
+        ItemContainerId::TraitId(trait_id) => {
+            return from_assoc_items(&trait_id.trait_items(db).items);
+        }
+        _ => {}
+    }
+
+    // FIXME: Support general TAITs, or decisively decide not to.
+    Vec::new()
+}
diff --git a/crates/hir-ty/src/specialization.rs b/crates/hir-ty/src/specialization.rs
index 611947b..f4ee4de 100644
--- a/crates/hir-ty/src/specialization.rs
+++ b/crates/hir-ty/src/specialization.rs
@@ -20,7 +20,7 @@
 // and indeed I was unable to cause cycles even with erroneous code. However, in r-a we can
 // create a cycle if there is an error in the impl's where clauses. I believe well formed code
 // cannot create a cycle, but a cycle handler is required nevertheless.
-fn specializes_cycle(
+fn specializes_query_cycle(
     _db: &dyn HirDatabase,
     _specializing_impl_def_id: ImplId,
     _parent_impl_def_id: ImplId,
@@ -39,31 +39,14 @@
 /// `parent_impl_def_id` is a const impl (conditionally based off of some `[const]`
 /// bounds), then `specializing_impl_def_id` must also be const for the same
 /// set of types.
-#[salsa::tracked(cycle_result = specializes_cycle)]
-pub(crate) fn specializes(
+#[salsa::tracked(cycle_result = specializes_query_cycle)]
+fn specializes_query(
     db: &dyn HirDatabase,
     specializing_impl_def_id: ImplId,
     parent_impl_def_id: ImplId,
 ) -> bool {
-    let module = specializing_impl_def_id.loc(db).container;
-
-    // We check that the specializing impl comes from a crate that has specialization enabled.
-    //
-    // We don't really care if the specialized impl (the parent) is in a crate that has
-    // specialization enabled, since it's not being specialized.
-    //
-    // rustc also checks whether the specializing impls comes from a macro marked
-    // `#[allow_internal_unstable(specialization)]`, but `#[allow_internal_unstable]`
-    // is an internal feature, std is not using it for specialization nor is likely to
-    // ever use it, and we don't have the span information necessary to replicate that.
-    let def_map = crate_def_map(db, module.krate());
-    if !def_map.is_unstable_feature_enabled(&sym::specialization)
-        && !def_map.is_unstable_feature_enabled(&sym::min_specialization)
-    {
-        return false;
-    }
-
-    let interner = DbInterner::new_with(db, Some(module.krate()), module.containing_block());
+    let trait_env = db.trait_environment(specializing_impl_def_id.into());
+    let interner = DbInterner::new_with(db, Some(trait_env.krate), trait_env.block);
 
     let specializing_impl_signature = db.impl_signature(specializing_impl_def_id);
     let parent_impl_signature = db.impl_signature(parent_impl_def_id);
@@ -87,7 +70,7 @@
 
     // create a parameter environment corresponding to an identity instantiation of the specializing impl,
     // i.e. the most generic instantiation of the specializing impl.
-    let param_env = db.trait_environment(specializing_impl_def_id.into()).env;
+    let param_env = trait_env.env;
 
     // Create an infcx, taking the predicates of the specializing impl as assumptions:
     let infcx = interner.infer_ctxt().build(TypingMode::non_body_analysis());
@@ -148,3 +131,31 @@
 
     true
 }
+
+// This function is used to avoid creating the query for crates that does not define `#![feature(specialization)]`,
+// as the solver is calling this a lot, and creating the query consumes a lot of memory.
+pub(crate) fn specializes(
+    db: &dyn HirDatabase,
+    specializing_impl_def_id: ImplId,
+    parent_impl_def_id: ImplId,
+) -> bool {
+    let module = specializing_impl_def_id.loc(db).container;
+
+    // We check that the specializing impl comes from a crate that has specialization enabled.
+    //
+    // We don't really care if the specialized impl (the parent) is in a crate that has
+    // specialization enabled, since it's not being specialized.
+    //
+    // rustc also checks whether the specializing impls comes from a macro marked
+    // `#[allow_internal_unstable(specialization)]`, but `#[allow_internal_unstable]`
+    // is an internal feature, std is not using it for specialization nor is likely to
+    // ever use it, and we don't have the span information necessary to replicate that.
+    let def_map = crate_def_map(db, module.krate());
+    if !def_map.is_unstable_feature_enabled(&sym::specialization)
+        && !def_map.is_unstable_feature_enabled(&sym::min_specialization)
+    {
+        return false;
+    }
+
+    specializes_query(db, specializing_impl_def_id, parent_impl_def_id)
+}
diff --git a/crates/hir-ty/src/tests/incremental.rs b/crates/hir-ty/src/tests/incremental.rs
index bc47019..14ec161 100644
--- a/crates/hir-ty/src/tests/incremental.rs
+++ b/crates/hir-ty/src/tests/incremental.rs
@@ -591,6 +591,7 @@
                 "function_signature_shim",
                 "function_signature_with_source_map_shim",
                 "trait_environment_shim",
+                "return_type_impl_traits_shim",
                 "expr_scopes_shim",
                 "struct_signature_shim",
                 "struct_signature_with_source_map_shim",
@@ -686,6 +687,7 @@
                 "return_type_impl_traits_shim",
                 "infer_shim",
                 "function_signature_with_source_map_shim",
+                "return_type_impl_traits_shim",
                 "expr_scopes_shim",
                 "struct_signature_with_source_map_shim",
                 "generic_predicates_shim",
diff --git a/crates/hir-ty/src/tests/opaque_types.rs b/crates/hir-ty/src/tests/opaque_types.rs
index 5cdd170..ca98633 100644
--- a/crates/hir-ty/src/tests/opaque_types.rs
+++ b/crates/hir-ty/src/tests/opaque_types.rs
@@ -31,7 +31,6 @@
 }
 
 #[test]
-#[ignore = "FIXME(next-solver): This currently generates a type mismatch, need to switch opaque type handling to the solver"]
 fn associated_type_impl_traits_complex() {
     check_types(
         r#"
@@ -116,6 +115,7 @@
     );
 }
 
+#[ignore = "FIXME(next-solver): TAIT support was removed, need to rework it to work with `#[define_opaque]`"]
 #[test]
 fn type_alias_impl_trait_simple() {
     check_no_mismatches(
@@ -135,9 +135,6 @@
 "#,
     );
 
-    // FIXME(next-solver): This should emit type mismatch error but leaving it for now
-    // as we should fully migrate into next-solver without chalk-ir and TAIT should be
-    // reworked on r-a to handle `#[define_opaque(T)]`
     check_infer_with_mismatches(
         r#"
 trait Trait {}
diff --git a/crates/hir-ty/src/tests/regression.rs b/crates/hir-ty/src/tests/regression.rs
index 7c79393..75d3203 100644
--- a/crates/hir-ty/src/tests/regression.rs
+++ b/crates/hir-ty/src/tests/regression.rs
@@ -725,7 +725,7 @@
             138..146 'bar(key)': impl Future<Output = <K as Foo<R>>::Bar>
             142..145 'key': &'? K
             162..165 'key': &'? K
-            224..227 '{ }': ()
+            224..227 '{ }': impl Future<Output = <K as Foo<R>>::Bar>
         "#]],
     );
 }
@@ -2506,3 +2506,19 @@
 "#,
     );
 }
+
+#[test]
+fn module_inside_block() {
+    check_types(
+        r#"
+fn foo() {
+    mod my_mod {
+        pub type Bool = bool;
+    }
+
+    let _: my_mod::Bool;
+     // ^ bool
+}
+    "#,
+    );
+}
diff --git a/crates/hir-ty/src/tests/regression/new_solver.rs b/crates/hir-ty/src/tests/regression/new_solver.rs
index f8b73cd..64c69af 100644
--- a/crates/hir-ty/src/tests/regression/new_solver.rs
+++ b/crates/hir-ty/src/tests/regression/new_solver.rs
@@ -180,7 +180,7 @@
     "#,
         expect![[r#"
             150..154 'self': &'a Grid
-            174..181 '{     }': impl Iterator<Item = &'a ()>
+            174..181 '{     }': <&'a Grid as IntoIterator>::IntoIter
         "#]],
     );
 }
diff --git a/crates/hir-ty/src/tests/traits.rs b/crates/hir-ty/src/tests/traits.rs
index f72ca22..c0e4393 100644
--- a/crates/hir-ty/src/tests/traits.rs
+++ b/crates/hir-ty/src/tests/traits.rs
@@ -1211,7 +1211,7 @@
         expect![[r#"
             29..33 'self': &'? Self
             54..58 'self': &'? Self
-            98..100 '{}': ()
+            98..100 '{}': impl Trait<u64>
             110..111 'x': impl Trait<u64>
             130..131 'y': &'? impl Trait<u64>
             151..268 '{     ...2(); }': ()
@@ -1373,11 +1373,11 @@
         expect![[r#"
             49..53 'self': &'? mut Self
             101..105 'self': &'? Self
-            184..195 '{ loop {} }': ({unknown}, {unknown})
+            184..195 '{ loop {} }': (impl Iterator<Item = impl Trait<u32>>, impl Trait<u64>)
             186..193 'loop {}': !
             191..193 '{}': ()
             206..207 't': T
-            268..279 '{ loop {} }': ({unknown}, {unknown})
+            268..279 '{ loop {} }': (impl Iterator<Item = impl Trait<T>>, impl Trait<T>)
             270..277 'loop {}': !
             275..277 '{}': ()
             291..413 '{     ...o(); }': ()
@@ -1419,7 +1419,7 @@
 }
 "#,
         expect![[r#"
-            134..165 '{     ...(C)) }': (impl FnOnce(&'? str, T), Bar<u8>)
+            134..165 '{     ...(C)) }': (impl FnOnce(&'? str, T), impl Trait<u8>)
             140..163 '(|inpu...ar(C))': (impl FnOnce(&'? str, T), Bar<u8>)
             141..154 '|input, t| {}': impl FnOnce(&'? str, T)
             142..147 'input': &'? str
@@ -1441,7 +1441,7 @@
 trait Future { type Output; }
 impl Future for () { type Output = i32; }
 type Foo<F> = (<F as Future>::Output, F);
-fn foo<X>() -> Foo<impl Future<Output = ()>> {
+fn foo<X>() -> Foo<impl Future<Output = i32>> {
     (0, ())
 }
 "#,
diff --git a/crates/hir-ty/src/traits.rs b/crates/hir-ty/src/traits.rs
index 7f6d4ff..00c8eb7 100644
--- a/crates/hir-ty/src/traits.rs
+++ b/crates/hir-ty/src/traits.rs
@@ -107,24 +107,26 @@
     infer_ctxt: &InferCtxt<'db>,
     goal: Canonical<'db, Goal<'db, Predicate<'db>>>,
 ) -> NextTraitSolveResult {
-    let context = SolverContext(infer_ctxt.clone());
+    infer_ctxt.probe(|_| {
+        let context = <&SolverContext<'db>>::from(infer_ctxt);
 
-    tracing::info!(?goal);
+        tracing::info!(?goal);
 
-    let (goal, var_values) = context.instantiate_canonical(&goal);
-    tracing::info!(?var_values);
+        let (goal, var_values) = context.instantiate_canonical(&goal);
+        tracing::info!(?var_values);
 
-    let res = context.evaluate_root_goal(goal, Span::dummy(), None);
+        let res = context.evaluate_root_goal(goal, Span::dummy(), None);
 
-    let res = res.map(|r| (r.has_changed, r.certainty));
+        let res = res.map(|r| (r.has_changed, r.certainty));
 
-    tracing::debug!("solve_nextsolver({:?}) => {:?}", goal, res);
+        tracing::debug!("solve_nextsolver({:?}) => {:?}", goal, res);
 
-    match res {
-        Err(_) => NextTraitSolveResult::NoSolution,
-        Ok((_, Certainty::Yes)) => NextTraitSolveResult::Certain,
-        Ok((_, Certainty::Maybe { .. })) => NextTraitSolveResult::Uncertain,
-    }
+        match res {
+            Err(_) => NextTraitSolveResult::NoSolution,
+            Ok((_, Certainty::Yes)) => NextTraitSolveResult::Certain,
+            Ok((_, Certainty::Maybe { .. })) => NextTraitSolveResult::Uncertain,
+        }
+    })
 }
 
 /// Solve a trait goal using next trait solver.
diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs
index 2bb2f80..f2faf99 100644
--- a/crates/hir/src/lib.rs
+++ b/crates/hir/src/lib.rs
@@ -5136,10 +5136,7 @@
             AliasTy::new(interner, alias.id.into(), args),
         );
 
-        // FIXME(next-solver): This needs to be `PostAnalysis`, but this currently causes errors due to our incorrect
-        // handling of opaques. `non_body_analysis()` will also cause errors (from not revealing opaques inside their
-        // defining places), so we choose between two bad options.
-        let infcx = interner.infer_ctxt().build(TypingMode::non_body_analysis());
+        let infcx = interner.infer_ctxt().build(TypingMode::PostAnalysis);
         let ty = structurally_normalize_ty(&infcx, projection, self.env.clone());
         if ty.is_ty_error() { None } else { Some(self.derived(ty)) }
     }
@@ -5758,8 +5755,7 @@
 
     pub fn drop_glue(&self, db: &'db dyn HirDatabase) -> DropGlue {
         let interner = DbInterner::new_with(db, Some(self.env.krate), self.env.block);
-        // FIXME: This should be `PostAnalysis` I believe.
-        let infcx = interner.infer_ctxt().build(TypingMode::non_body_analysis());
+        let infcx = interner.infer_ctxt().build(TypingMode::PostAnalysis);
         hir_ty::drop::has_drop_glue(&infcx, self.ty, self.env.clone())
     }
 }
diff --git a/crates/hir/src/semantics.rs b/crates/hir/src/semantics.rs
index 62ce3da..ec43442 100644
--- a/crates/hir/src/semantics.rs
+++ b/crates/hir/src/semantics.rs
@@ -2105,6 +2105,22 @@
             parent = parent_;
         }
     }
+
+    pub fn impl_generated_from_derive(&self, impl_: Impl) -> Option<Adt> {
+        let source = hir_def::src::HasSource::ast_ptr(&impl_.id.loc(self.db), self.db);
+        let mut file_id = source.file_id;
+        let adt_ast_id = loop {
+            let macro_call = file_id.macro_file()?;
+            match macro_call.loc(self.db).kind {
+                hir_expand::MacroCallKind::Derive { ast_id, .. } => break ast_id,
+                hir_expand::MacroCallKind::FnLike { ast_id, .. } => file_id = ast_id.file_id,
+                hir_expand::MacroCallKind::Attr { ast_id, .. } => file_id = ast_id.file_id,
+            }
+        };
+        let adt_source = adt_ast_id.to_in_file_node(self.db);
+        self.cache(adt_source.value.syntax().ancestors().last().unwrap(), adt_source.file_id);
+        ToDef::to_def(self, adt_source.as_ref())
+    }
 }
 
 // FIXME This can't be the best way to do this
diff --git a/crates/hir/src/source_analyzer.rs b/crates/hir/src/source_analyzer.rs
index 15eab14..f994ed2 100644
--- a/crates/hir/src/source_analyzer.rs
+++ b/crates/hir/src/source_analyzer.rs
@@ -1594,14 +1594,12 @@
             Some(unresolved) => resolver
                 .generic_def()
                 .and_then(|def| {
-                    hir_ty::attach_db(db, || {
-                        hir_ty::associated_type_shorthand_candidates(
-                            db,
-                            def,
-                            res.in_type_ns()?,
-                            |name, _| name == unresolved.name,
-                        )
-                    })
+                    hir_ty::associated_type_shorthand_candidates(
+                        db,
+                        def,
+                        res.in_type_ns()?,
+                        |name, _| name == unresolved.name,
+                    )
                 })
                 .map(TypeAlias::from)
                 .map(Into::into)
diff --git a/crates/ide-assists/src/handlers/convert_range_for_to_while.rs b/crates/ide-assists/src/handlers/convert_range_for_to_while.rs
new file mode 100644
index 0000000..68cb764
--- /dev/null
+++ b/crates/ide-assists/src/handlers/convert_range_for_to_while.rs
@@ -0,0 +1,259 @@
+use ide_db::assists::AssistId;
+use itertools::Itertools;
+use syntax::{
+    AstNode, T,
+    algo::previous_non_trivia_token,
+    ast::{
+        self, HasArgList, HasLoopBody, HasName, RangeItem, edit::AstNodeEdit, make,
+        syntax_factory::SyntaxFactory,
+    },
+    syntax_editor::{Element, Position},
+};
+
+use crate::assist_context::{AssistContext, Assists};
+
+// Assist: convert_range_for_to_while
+//
+// Convert for each range into while loop.
+//
+// ```
+// fn foo() {
+//     $0for i in 3..7 {
+//         foo(i);
+//     }
+// }
+// ```
+// ->
+// ```
+// fn foo() {
+//     let mut i = 3;
+//     while i < 7 {
+//         foo(i);
+//         i += 1;
+//     }
+// }
+// ```
+pub(crate) fn convert_range_for_to_while(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> {
+    let for_kw = ctx.find_token_syntax_at_offset(T![for])?;
+    let for_ = ast::ForExpr::cast(for_kw.parent()?)?;
+    let ast::Pat::IdentPat(pat) = for_.pat()? else { return None };
+    let iterable = for_.iterable()?;
+    let (start, end, step, inclusive) = extract_range(&iterable)?;
+    let name = pat.name()?;
+    let body = for_.loop_body()?;
+    let last = previous_non_trivia_token(body.stmt_list()?.r_curly_token()?)?;
+
+    let description = if end.is_some() {
+        "Replace with while expression"
+    } else {
+        "Replace with loop expression"
+    };
+    acc.add(
+        AssistId::refactor("convert_range_for_to_while"),
+        description,
+        for_.syntax().text_range(),
+        |builder| {
+            let mut edit = builder.make_editor(for_.syntax());
+            let make = SyntaxFactory::with_mappings();
+
+            let indent = for_.indent_level();
+            let pat = make.ident_pat(pat.ref_token().is_some(), true, name.clone());
+            let let_stmt = make.let_stmt(pat.into(), None, Some(start));
+            edit.insert_all(
+                Position::before(for_.syntax()),
+                vec![
+                    let_stmt.syntax().syntax_element(),
+                    make.whitespace(&format!("\n{}", indent)).syntax_element(),
+                ],
+            );
+
+            let mut elements = vec![];
+
+            let var_expr = make.expr_path(make.ident_path(&name.text()));
+            let op = ast::BinaryOp::CmpOp(ast::CmpOp::Ord {
+                ordering: ast::Ordering::Less,
+                strict: !inclusive,
+            });
+            if let Some(end) = end {
+                elements.extend([
+                    make.token(T![while]).syntax_element(),
+                    make.whitespace(" ").syntax_element(),
+                    make.expr_bin(var_expr.clone(), op, end).syntax().syntax_element(),
+                ]);
+            } else {
+                elements.push(make.token(T![loop]).syntax_element());
+            }
+
+            edit.replace_all(
+                for_kw.syntax_element()..=iterable.syntax().syntax_element(),
+                elements,
+            );
+
+            let op = ast::BinaryOp::Assignment { op: Some(ast::ArithOp::Add) };
+            edit.insert_all(
+                Position::after(last),
+                vec![
+                    make.whitespace(&format!("\n{}", indent + 1)).syntax_element(),
+                    make.expr_bin(var_expr, op, step).syntax().syntax_element(),
+                    make.token(T![;]).syntax_element(),
+                ],
+            );
+
+            edit.add_mappings(make.finish_with_mappings());
+            builder.add_file_edits(ctx.vfs_file_id(), edit);
+        },
+    )
+}
+
+fn extract_range(iterable: &ast::Expr) -> Option<(ast::Expr, Option<ast::Expr>, ast::Expr, bool)> {
+    Some(match iterable {
+        ast::Expr::ParenExpr(expr) => extract_range(&expr.expr()?)?,
+        ast::Expr::RangeExpr(range) => {
+            let inclusive = range.op_kind()? == ast::RangeOp::Inclusive;
+            (range.start()?, range.end(), make::expr_literal("1").into(), inclusive)
+        }
+        ast::Expr::MethodCallExpr(call) if call.name_ref()?.text() == "step_by" => {
+            let [step] = call.arg_list()?.args().collect_array()?;
+            let (start, end, _, inclusive) = extract_range(&call.receiver()?)?;
+            (start, end, step, inclusive)
+        }
+        _ => return None,
+    })
+}
+
+#[cfg(test)]
+mod tests {
+    use crate::tests::{check_assist, check_assist_not_applicable};
+
+    use super::*;
+
+    #[test]
+    fn test_convert_range_for_to_while() {
+        check_assist(
+            convert_range_for_to_while,
+            "
+fn foo() {
+    $0for i in 3..7 {
+        foo(i);
+    }
+}
+            ",
+            "
+fn foo() {
+    let mut i = 3;
+    while i < 7 {
+        foo(i);
+        i += 1;
+    }
+}
+            ",
+        );
+    }
+
+    #[test]
+    fn test_convert_range_for_to_while_no_end_bound() {
+        check_assist(
+            convert_range_for_to_while,
+            "
+fn foo() {
+    $0for i in 3.. {
+        foo(i);
+    }
+}
+            ",
+            "
+fn foo() {
+    let mut i = 3;
+    loop {
+        foo(i);
+        i += 1;
+    }
+}
+            ",
+        );
+    }
+
+    #[test]
+    fn test_convert_range_for_to_while_with_mut_binding() {
+        check_assist(
+            convert_range_for_to_while,
+            "
+fn foo() {
+    $0for mut i in 3..7 {
+        foo(i);
+    }
+}
+            ",
+            "
+fn foo() {
+    let mut i = 3;
+    while i < 7 {
+        foo(i);
+        i += 1;
+    }
+}
+            ",
+        );
+    }
+
+    #[test]
+    fn test_convert_range_for_to_while_with_label() {
+        check_assist(
+            convert_range_for_to_while,
+            "
+fn foo() {
+    'a: $0for mut i in 3..7 {
+        foo(i);
+    }
+}
+            ",
+            "
+fn foo() {
+    let mut i = 3;
+    'a: while i < 7 {
+        foo(i);
+        i += 1;
+    }
+}
+            ",
+        );
+    }
+
+    #[test]
+    fn test_convert_range_for_to_while_step_by() {
+        check_assist(
+            convert_range_for_to_while,
+            "
+fn foo() {
+    $0for mut i in (3..7).step_by(2) {
+        foo(i);
+    }
+}
+            ",
+            "
+fn foo() {
+    let mut i = 3;
+    while i < 7 {
+        foo(i);
+        i += 2;
+    }
+}
+            ",
+        );
+    }
+
+    #[test]
+    fn test_convert_range_for_to_while_not_applicable_non_range() {
+        check_assist_not_applicable(
+            convert_range_for_to_while,
+            "
+fn foo() {
+    let ident = 3..7;
+    $0for mut i in ident {
+        foo(i);
+    }
+}
+            ",
+        );
+    }
+}
diff --git a/crates/ide-assists/src/handlers/generate_blanket_trait_impl.rs b/crates/ide-assists/src/handlers/generate_blanket_trait_impl.rs
index c25b0bb..b0fa9e6 100644
--- a/crates/ide-assists/src/handlers/generate_blanket_trait_impl.rs
+++ b/crates/ide-assists/src/handlers/generate_blanket_trait_impl.rs
@@ -13,7 +13,7 @@
     AstNode,
     ast::{
         self, AssocItem, BlockExpr, GenericParam, HasAttrs, HasGenericParams, HasName,
-        HasTypeBounds, HasVisibility, edit_in_place::Indent, make,
+        HasTypeBounds, HasVisibility, edit::AstNodeEdit, make,
     },
     syntax_editor::Position,
 };
@@ -75,7 +75,7 @@
         |builder| {
             let mut edit = builder.make_editor(traitd.syntax());
             let namety = make::ty_path(make::path_from_text(&name.text()));
-            let trait_where_clause = traitd.where_clause().map(|it| it.clone_for_update());
+            let trait_where_clause = traitd.where_clause().map(|it| it.reset_indent());
             let bounds = traitd.type_bound_list().and_then(exlucde_sized);
             let is_unsafe = traitd.unsafe_token().is_some();
             let thisname = this_name(&traitd);
@@ -90,10 +90,6 @@
             let trait_gen_args =
                 traitd.generic_param_list().map(|param_list| param_list.to_generic_args());
 
-            if let Some(ref where_clause) = trait_where_clause {
-                where_clause.reindent_to(0.into());
-            }
-
             let impl_ = make::impl_trait(
                 cfg_attrs(&traitd),
                 is_unsafe,
@@ -112,20 +108,19 @@
 
             if let Some(trait_assoc_list) = traitd.assoc_item_list() {
                 let assoc_item_list = impl_.get_or_create_assoc_item_list();
-                for method in trait_assoc_list.assoc_items() {
-                    let AssocItem::Fn(method) = method else {
-                        continue;
+                for item in trait_assoc_list.assoc_items() {
+                    let item = match item {
+                        ast::AssocItem::Fn(method) if method.body().is_none() => {
+                            todo_fn(&method, ctx.config).into()
+                        }
+                        ast::AssocItem::Const(_) | ast::AssocItem::TypeAlias(_) => item,
+                        _ => continue,
                     };
-                    if method.body().is_some() {
-                        continue;
-                    }
-                    let f = todo_fn(&method, ctx.config).clone_for_update();
-                    f.indent(1.into());
-                    assoc_item_list.add_item(AssocItem::Fn(f));
+                    assoc_item_list.add_item(item.reset_indent().indent(1.into()));
                 }
             }
 
-            impl_.indent(indent);
+            let impl_ = impl_.indent(indent);
 
             edit.insert_all(
                 Position::after(traitd.syntax()),
@@ -507,6 +502,41 @@
     }
 
     #[test]
+    fn test_gen_blanket_other_assoc_items() {
+        check_assist(
+            generate_blanket_trait_impl,
+            r#"
+trait $0Foo {
+    type Item;
+
+    const N: usize;
+
+    fn foo(&self);
+}
+"#,
+            r#"
+trait Foo {
+    type Item;
+
+    const N: usize;
+
+    fn foo(&self);
+}
+
+impl<T: ?Sized> Foo for $0T {
+    type Item;
+
+    const N: usize;
+
+    fn foo(&self) {
+        todo!()
+    }
+}
+"#,
+        );
+    }
+
+    #[test]
     fn test_gen_blanket_indent() {
         check_assist(
             generate_blanket_trait_impl,
@@ -742,6 +772,49 @@
 }
         "#,
         );
+        check_assist(
+            generate_blanket_trait_impl,
+            r#"
+mod foo {
+    mod bar {
+        trait $0Foo {
+            type Item: Bar<
+                Self,
+            >;
+
+            const N: Baz<
+                Self,
+            >;
+        }
+    }
+}
+        "#,
+            r#"
+mod foo {
+    mod bar {
+        trait Foo {
+            type Item: Bar<
+                Self,
+            >;
+
+            const N: Baz<
+                Self,
+            >;
+        }
+
+        impl<T: ?Sized> Foo for $0T {
+            type Item: Bar<
+                Self,
+            >;
+
+            const N: Baz<
+                Self,
+            >;
+        }
+    }
+}
+        "#,
+        );
     }
 
     #[test]
@@ -824,6 +897,8 @@
 where
     Self::Owned: Default,
 {
+    type X: Sync;
+
     fn foo(&self, x: Self::X) -> T {
         todo!()
     }
@@ -871,6 +946,8 @@
     Self: ToOwned,
     Self::Owned: Default,
 {
+    type X: Sync;
+
     fn foo(&self, x: Self::X) -> T {
         todo!()
     }
@@ -906,6 +983,8 @@
 }
 
 impl<T: Send, T1: ?Sized> Foo<T> for $0T1 {
+    type X: Sync;
+
     fn foo(&self, x: Self::X) -> T {
         todo!()
     }
@@ -941,6 +1020,8 @@
 }
 
 impl<T: ?Sized> Foo for $0T {
+    type X: Sync;
+
     fn foo(&self, x: Self::X) -> i32 {
         todo!()
     }
diff --git a/crates/ide-assists/src/handlers/replace_is_method_with_if_let_method.rs b/crates/ide-assists/src/handlers/replace_is_method_with_if_let_method.rs
index c57fd4d..5a23077 100644
--- a/crates/ide-assists/src/handlers/replace_is_method_with_if_let_method.rs
+++ b/crates/ide-assists/src/handlers/replace_is_method_with_if_let_method.rs
@@ -1,3 +1,4 @@
+use either::Either;
 use ide_db::syntax_helpers::suggest_name;
 use syntax::ast::{self, AstNode, syntax_factory::SyntaxFactory};
 
@@ -24,9 +25,9 @@
     acc: &mut Assists,
     ctx: &AssistContext<'_>,
 ) -> Option<()> {
-    let if_expr = ctx.find_node_at_offset::<ast::IfExpr>()?;
+    let has_cond = ctx.find_node_at_offset::<Either<ast::IfExpr, ast::WhileExpr>>()?;
 
-    let cond = if_expr.condition()?;
+    let cond = either::for_both!(&has_cond, it => it.condition())?;
     let cond = cover_let_chain(cond, ctx.selection_trimmed())?;
     let call_expr = match cond {
         ast::Expr::MethodCallExpr(call) => call,
@@ -39,7 +40,7 @@
             let receiver = call_expr.receiver()?;
 
             let mut name_generator = suggest_name::NameGenerator::new_from_scope_locals(
-                ctx.sema.scope(if_expr.syntax()),
+                ctx.sema.scope(has_cond.syntax()),
             );
             let var_name = if let ast::Expr::PathExpr(path_expr) = receiver.clone() {
                 name_generator.suggest_name(&path_expr.path()?.to_string())
@@ -48,9 +49,9 @@
             };
 
             let (assist_id, message, text) = if name_ref.text() == "is_some" {
-                ("replace_is_some_with_if_let_some", "Replace `is_some` with `if let Some`", "Some")
+                ("replace_is_some_with_if_let_some", "Replace `is_some` with `let Some`", "Some")
             } else {
-                ("replace_is_ok_with_if_let_ok", "Replace `is_ok` with `if let Ok`", "Ok")
+                ("replace_is_ok_with_if_let_ok", "Replace `is_ok` with `let Ok`", "Ok")
             };
 
             acc.add(
@@ -251,6 +252,25 @@
     }
 
     #[test]
+    fn replace_is_some_with_while_let_some() {
+        check_assist(
+            replace_is_method_with_if_let_method,
+            r#"
+fn main() {
+    let mut x = Some(1);
+    while x.is_som$0e() { x = None }
+}
+"#,
+            r#"
+fn main() {
+    let mut x = Some(1);
+    while let Some(${0:x1}) = x { x = None }
+}
+"#,
+        );
+    }
+
+    #[test]
     fn replace_is_some_with_if_let_some_not_applicable_after_l_curly() {
         check_assist_not_applicable(
             replace_is_method_with_if_let_method,
diff --git a/crates/ide-assists/src/lib.rs b/crates/ide-assists/src/lib.rs
index e9f2d68..4b4aa94 100644
--- a/crates/ide-assists/src/lib.rs
+++ b/crates/ide-assists/src/lib.rs
@@ -131,6 +131,7 @@
     mod convert_match_to_let_else;
     mod convert_named_struct_to_tuple_struct;
     mod convert_nested_function_to_closure;
+    mod convert_range_for_to_while;
     mod convert_to_guarded_return;
     mod convert_tuple_return_type_to_struct;
     mod convert_tuple_struct_to_named_struct;
@@ -268,6 +269,7 @@
             convert_match_to_let_else::convert_match_to_let_else,
             convert_named_struct_to_tuple_struct::convert_named_struct_to_tuple_struct,
             convert_nested_function_to_closure::convert_nested_function_to_closure,
+            convert_range_for_to_while::convert_range_for_to_while,
             convert_to_guarded_return::convert_to_guarded_return,
             convert_tuple_return_type_to_struct::convert_tuple_return_type_to_struct,
             convert_tuple_struct_to_named_struct::convert_tuple_struct_to_named_struct,
diff --git a/crates/ide-assists/src/tests/generated.rs b/crates/ide-assists/src/tests/generated.rs
index a99fe8d..7f0836a 100644
--- a/crates/ide-assists/src/tests/generated.rs
+++ b/crates/ide-assists/src/tests/generated.rs
@@ -732,6 +732,29 @@
 }
 
 #[test]
+fn doctest_convert_range_for_to_while() {
+    check_doc_test(
+        "convert_range_for_to_while",
+        r#####"
+fn foo() {
+    $0for i in 3..7 {
+        foo(i);
+    }
+}
+"#####,
+        r#####"
+fn foo() {
+    let mut i = 3;
+    while i < 7 {
+        foo(i);
+        i += 1;
+    }
+}
+"#####,
+    )
+}
+
+#[test]
 fn doctest_convert_to_guarded_return() {
     check_doc_test(
         "convert_to_guarded_return",
diff --git a/crates/ide-completion/src/completions/keyword.rs b/crates/ide-completion/src/completions/keyword.rs
index 6162d98..eab2b90 100644
--- a/crates/ide-completion/src/completions/keyword.rs
+++ b/crates/ide-completion/src/completions/keyword.rs
@@ -532,6 +532,146 @@
     }
 
     #[test]
+    fn if_completion_in_format() {
+        check_edit(
+            "if",
+            r#"
+//- minicore: fmt
+fn main() {
+    format_args!("{}", $0);
+}
+"#,
+            r#"
+fn main() {
+    format_args!("{}", if $1 {
+    $2
+} else {
+    $0
+});
+}
+"#,
+        );
+
+        check_edit(
+            "if",
+            r#"
+//- minicore: fmt
+fn main() {
+    format_args!("{}", if$0);
+}
+"#,
+            r#"
+fn main() {
+    format_args!("{}", if $1 {
+    $2
+} else {
+    $0
+});
+}
+"#,
+        );
+    }
+
+    #[test]
+    fn if_completion_in_value_expected_expressions() {
+        check_edit(
+            "if",
+            r#"
+fn main() {
+    2 + $0;
+}
+"#,
+            r#"
+fn main() {
+    2 + if $1 {
+    $2
+} else {
+    $0
+};
+}
+"#,
+        );
+
+        check_edit(
+            "if",
+            r#"
+fn main() {
+    -$0;
+}
+"#,
+            r#"
+fn main() {
+    -if $1 {
+    $2
+} else {
+    $0
+};
+}
+"#,
+        );
+
+        check_edit(
+            "if",
+            r#"
+fn main() {
+    return $0;
+}
+"#,
+            r#"
+fn main() {
+    return if $1 {
+    $2
+} else {
+    $0
+};
+}
+"#,
+        );
+
+        check_edit(
+            "if",
+            r#"
+fn main() {
+    loop {
+        break $0;
+    }
+}
+"#,
+            r#"
+fn main() {
+    loop {
+        break if $1 {
+    $2
+} else {
+    $0
+};
+    }
+}
+"#,
+        );
+
+        check_edit(
+            "if",
+            r#"
+struct Foo { x: i32 }
+fn main() {
+    Foo { x: $0 }
+}
+"#,
+            r#"
+struct Foo { x: i32 }
+fn main() {
+    Foo { x: if $1 {
+    $2
+} else {
+    $0
+} }
+}
+"#,
+        );
+    }
+
+    #[test]
     fn completes_let_in_block() {
         check_edit(
             "let",
diff --git a/crates/ide-completion/src/context/analysis.rs b/crates/ide-completion/src/context/analysis.rs
index b3d9ff0..d6d3978 100644
--- a/crates/ide-completion/src/context/analysis.rs
+++ b/crates/ide-completion/src/context/analysis.rs
@@ -1012,6 +1012,25 @@
             .and_then(|next| next.first_token())
             .is_some_and(|token| token.kind() == SyntaxKind::ELSE_KW)
     };
+    let is_in_value = |it: &SyntaxNode| {
+        let Some(node) = it.parent() else { return false };
+        let kind = node.kind();
+        ast::LetStmt::can_cast(kind)
+            || ast::ArgList::can_cast(kind)
+            || ast::ArrayExpr::can_cast(kind)
+            || ast::ParenExpr::can_cast(kind)
+            || ast::BreakExpr::can_cast(kind)
+            || ast::ReturnExpr::can_cast(kind)
+            || ast::PrefixExpr::can_cast(kind)
+            || ast::FormatArgsArg::can_cast(kind)
+            || ast::RecordExprField::can_cast(kind)
+            || ast::BinExpr::cast(node.clone())
+                .and_then(|expr| expr.rhs())
+                .is_some_and(|expr| expr.syntax() == it)
+            || ast::IndexExpr::cast(node)
+                .and_then(|expr| expr.index())
+                .is_some_and(|expr| expr.syntax() == it)
+    };
 
     // We do not want to generate path completions when we are sandwiched between an item decl signature and its body.
     // ex. trait Foo $0 {}
@@ -1307,7 +1326,7 @@
             .and_then(ast::LetStmt::cast)
             .is_some_and(|it| it.semicolon_token().is_none())
             || after_incomplete_let && incomplete_expr_stmt.unwrap_or(true) && !before_else_kw;
-        let in_value = it.parent().and_then(Either::<ast::LetStmt, ast::ArgList>::cast).is_some();
+        let in_value = is_in_value(it);
         let impl_ = fetch_immediate_impl_or_trait(sema, original_file, expr.syntax())
             .and_then(Either::left);
 
diff --git a/crates/ide-completion/src/tests/flyimport.rs b/crates/ide-completion/src/tests/flyimport.rs
index 0cd4208..e139a5e 100644
--- a/crates/ide-completion/src/tests/flyimport.rs
+++ b/crates/ide-completion/src/tests/flyimport.rs
@@ -1953,3 +1953,25 @@
         expect![""],
     );
 }
+
+#[test]
+fn multiple_matches_with_qualifier() {
+    check(
+        r#"
+//- /foo.rs crate:foo
+pub mod env {
+    pub fn var() {}
+    pub fn _var() {}
+}
+
+//- /bar.rs crate:bar deps:foo
+fn main() {
+    env::var$0
+}
+    "#,
+        expect![[r#"
+            fn _var() (use foo::env) fn()
+            fn var() (use foo::env)  fn()
+        "#]],
+    );
+}
diff --git a/crates/ide-db/src/generated/lints.rs b/crates/ide-db/src/generated/lints.rs
index 14bc380..5eb7e92 100644
--- a/crates/ide-db/src/generated/lints.rs
+++ b/crates/ide-db/src/generated/lints.rs
@@ -7511,7 +7511,7 @@
 an executable without the `std` crate, you might run into the need
 for lang item definitions.
 
-[personality]: https://github.com/rust-lang/rust/blob/master/library/std/src/sys/personality/gcc.rs
+[personality]: https://github.com/rust-lang/rust/blob/HEAD/library/std/src/sys/personality/gcc.rs
 
 ## Example: Implementing a `Box`
 
@@ -7586,7 +7586,7 @@
 
 An up-to-date list of all language items can be found [here] in the compiler code.
 
-[here]: https://github.com/rust-lang/rust/blob/master/compiler/rustc_hir/src/lang_items.rs
+[here]: https://github.com/rust-lang/rust/blob/HEAD/compiler/rustc_hir/src/lang_items.rs
 "##,
         default_severity: Severity::Allow,
         warn_since: None,
diff --git a/crates/ide-db/src/imports/import_assets.rs b/crates/ide-db/src/imports/import_assets.rs
index 0c235c8..50edfca 100644
--- a/crates/ide-db/src/imports/import_assets.rs
+++ b/crates/ide-db/src/imports/import_assets.rs
@@ -1,6 +1,6 @@
 //! Look up accessible paths for items.
 
-use std::ops::ControlFlow;
+use std::{convert::Infallible, ops::ControlFlow};
 
 use hir::{
     AsAssocItem, AssocItem, AssocItemContainer, Complete, Crate, FindPathConfig, HasCrate,
@@ -9,6 +9,7 @@
 };
 use itertools::Itertools;
 use rustc_hash::{FxHashMap, FxHashSet};
+use smallvec::SmallVec;
 use syntax::{
     AstNode, SyntaxNode,
     ast::{self, HasName, make},
@@ -416,7 +417,7 @@
             NameToImport::Exact(first_qsegment.as_str().to_owned(), true),
             AssocSearchMode::Exclude,
         )
-        .filter_map(|(item, do_not_complete)| {
+        .flat_map(|(item, do_not_complete)| {
             // we found imports for `first_qsegment`, now we need to filter these imports by whether
             // they result in resolving the rest of the path successfully
             validate_resolvable(
@@ -446,10 +447,10 @@
     resolved_qualifier: ItemInNs,
     unresolved_qualifier: &[Name],
     complete_in_flyimport: CompleteInFlyimport,
-) -> Option<LocatedImport> {
+) -> SmallVec<[LocatedImport; 1]> {
     let _p = tracing::info_span!("ImportAssets::import_for_item").entered();
 
-    let qualifier = {
+    let qualifier = (|| {
         let mut adjusted_resolved_qualifier = resolved_qualifier;
         if !unresolved_qualifier.is_empty() {
             match resolved_qualifier {
@@ -464,69 +465,80 @@
         }
 
         match adjusted_resolved_qualifier {
-            ItemInNs::Types(def) => def,
-            _ => return None,
+            ItemInNs::Types(def) => Some(def),
+            _ => None,
         }
-    };
-    let import_path_candidate = mod_path(resolved_qualifier)?;
+    })();
+    let Some(qualifier) = qualifier else { return SmallVec::new() };
+    let Some(import_path_candidate) = mod_path(resolved_qualifier) else { return SmallVec::new() };
+    let mut result = SmallVec::new();
     let ty = match qualifier {
         ModuleDef::Module(module) => {
-            return items_locator::items_with_name_in_module(
+            items_locator::items_with_name_in_module::<Infallible>(
                 db,
                 module,
                 candidate.clone(),
                 AssocSearchMode::Exclude,
-                |it| match scope_filter(it) {
-                    true => ControlFlow::Break(it),
-                    false => ControlFlow::Continue(()),
+                |item| {
+                    if scope_filter(item) {
+                        result.push(LocatedImport::new(
+                            import_path_candidate.clone(),
+                            resolved_qualifier,
+                            item,
+                            complete_in_flyimport,
+                        ));
+                    }
+                    ControlFlow::Continue(())
                 },
-            )
-            .map(|item| {
-                LocatedImport::new(
-                    import_path_candidate,
-                    resolved_qualifier,
-                    item,
-                    complete_in_flyimport,
-                )
-            });
+            );
+            return result;
         }
         // FIXME
-        ModuleDef::Trait(_) => return None,
+        ModuleDef::Trait(_) => return SmallVec::new(),
         ModuleDef::TypeAlias(alias) => alias.ty(db),
         ModuleDef::BuiltinType(builtin) => builtin.ty(db),
         ModuleDef::Adt(adt) => adt.ty(db),
-        _ => return None,
+        _ => return SmallVec::new(),
     };
-    ty.iterate_path_candidates(db, scope, &FxHashSet::default(), None, None, |assoc| {
-        // FIXME: Support extra trait imports
-        if assoc.container_or_implemented_trait(db).is_some() {
-            return None;
-        }
-        let name = assoc.name(db)?;
-        let is_match = match candidate {
-            NameToImport::Prefix(text, true) => name.as_str().starts_with(text),
-            NameToImport::Prefix(text, false) => {
-                name.as_str().chars().zip(text.chars()).all(|(name_char, candidate_char)| {
-                    name_char.eq_ignore_ascii_case(&candidate_char)
-                })
+    ty.iterate_path_candidates::<Infallible>(
+        db,
+        scope,
+        &FxHashSet::default(),
+        None,
+        None,
+        |assoc| {
+            // FIXME: Support extra trait imports
+            if assoc.container_or_implemented_trait(db).is_some() {
+                return None;
             }
-            NameToImport::Exact(text, true) => name.as_str() == text,
-            NameToImport::Exact(text, false) => name.as_str().eq_ignore_ascii_case(text),
-            NameToImport::Fuzzy(text, true) => text.chars().all(|c| name.as_str().contains(c)),
-            NameToImport::Fuzzy(text, false) => text
-                .chars()
-                .all(|c| name.as_str().chars().any(|name_char| name_char.eq_ignore_ascii_case(&c))),
-        };
-        if !is_match {
-            return None;
-        }
-        Some(LocatedImport::new(
-            import_path_candidate.clone(),
-            resolved_qualifier,
-            assoc_to_item(assoc),
-            complete_in_flyimport,
-        ))
-    })
+            let name = assoc.name(db)?;
+            let is_match = match candidate {
+                NameToImport::Prefix(text, true) => name.as_str().starts_with(text),
+                NameToImport::Prefix(text, false) => {
+                    name.as_str().chars().zip(text.chars()).all(|(name_char, candidate_char)| {
+                        name_char.eq_ignore_ascii_case(&candidate_char)
+                    })
+                }
+                NameToImport::Exact(text, true) => name.as_str() == text,
+                NameToImport::Exact(text, false) => name.as_str().eq_ignore_ascii_case(text),
+                NameToImport::Fuzzy(text, true) => text.chars().all(|c| name.as_str().contains(c)),
+                NameToImport::Fuzzy(text, false) => text.chars().all(|c| {
+                    name.as_str().chars().any(|name_char| name_char.eq_ignore_ascii_case(&c))
+                }),
+            };
+            if !is_match {
+                return None;
+            }
+            result.push(LocatedImport::new(
+                import_path_candidate.clone(),
+                resolved_qualifier,
+                assoc_to_item(assoc),
+                complete_in_flyimport,
+            ));
+            None
+        },
+    );
+    result
 }
 
 pub fn item_for_path_search(db: &RootDatabase, item: ItemInNs) -> Option<ItemInNs> {
diff --git a/crates/ide-db/src/search.rs b/crates/ide-db/src/search.rs
index f1d076e..018c841 100644
--- a/crates/ide-db/src/search.rs
+++ b/crates/ide-db/src/search.rs
@@ -387,12 +387,14 @@
             return SearchScope::reverse_dependencies(db, module.krate());
         }
 
-        let vis = self.visibility(db);
-        if let Some(Visibility::Public) = vis {
-            return SearchScope::reverse_dependencies(db, module.krate());
-        }
-        if let Some(Visibility::Module(module, _)) = vis {
-            return SearchScope::module_and_children(db, module.into());
+        if let Some(vis) = self.visibility(db) {
+            return match vis {
+                Visibility::Module(module, _) => {
+                    SearchScope::module_and_children(db, module.into())
+                }
+                Visibility::PubCrate(krate) => SearchScope::krate(db, krate.into()),
+                Visibility::Public => SearchScope::reverse_dependencies(db, module.krate()),
+            };
         }
 
         let range = match module_source {
diff --git a/crates/ide/src/annotations.rs b/crates/ide/src/annotations.rs
index 36c4404..6fb8ded 100644
--- a/crates/ide/src/annotations.rs
+++ b/crates/ide/src/annotations.rs
@@ -9,7 +9,7 @@
 use crate::{
     NavigationTarget, RunnableKind,
     annotations::fn_references::find_all_methods,
-    goto_implementation::goto_implementation,
+    goto_implementation::{GotoImplementationConfig, goto_implementation},
     navigation_target,
     references::{FindAllRefsConfig, find_all_refs},
     runnables::{Runnable, runnables},
@@ -44,6 +44,7 @@
     pub annotate_method_references: bool,
     pub annotate_enum_variant_references: bool,
     pub location: AnnotationLocation,
+    pub filter_adjacent_derive_implementations: bool,
     pub minicore: MiniCore<'a>,
 }
 
@@ -204,7 +205,12 @@
 ) -> Annotation {
     match annotation.kind {
         AnnotationKind::HasImpls { pos, ref mut data } => {
-            *data = goto_implementation(db, pos).map(|range| range.info);
+            let goto_implementation_config = GotoImplementationConfig {
+                filter_adjacent_derive_implementations: config
+                    .filter_adjacent_derive_implementations,
+            };
+            *data =
+                goto_implementation(db, &goto_implementation_config, pos).map(|range| range.info);
         }
         AnnotationKind::HasReferences { pos, ref mut data } => {
             *data = find_all_refs(
@@ -253,6 +259,7 @@
         annotate_enum_variant_references: true,
         location: AnnotationLocation::AboveName,
         minicore: MiniCore::default(),
+        filter_adjacent_derive_implementations: false,
     };
 
     fn check_with_config(
diff --git a/crates/ide/src/goto_implementation.rs b/crates/ide/src/goto_implementation.rs
index 875403c..0572bca 100644
--- a/crates/ide/src/goto_implementation.rs
+++ b/crates/ide/src/goto_implementation.rs
@@ -8,6 +8,10 @@
 
 use crate::{FilePosition, NavigationTarget, RangeInfo, TryToNav};
 
+pub struct GotoImplementationConfig {
+    pub filter_adjacent_derive_implementations: bool,
+}
+
 // Feature: Go to Implementation
 //
 // Navigates to the impl items of types.
@@ -19,6 +23,7 @@
 // ![Go to Implementation](https://user-images.githubusercontent.com/48062697/113065566-02f85480-91b1-11eb-9288-aaad8abd8841.gif)
 pub(crate) fn goto_implementation(
     db: &RootDatabase,
+    config: &GotoImplementationConfig,
     FilePosition { file_id, offset }: FilePosition,
 ) -> Option<RangeInfo<Vec<NavigationTarget>>> {
     let sema = Semantics::new(db);
@@ -55,7 +60,19 @@
                 .and_then(|def| {
                     let navs = match def {
                         Definition::Trait(trait_) => impls_for_trait(&sema, trait_),
-                        Definition::Adt(adt) => impls_for_ty(&sema, adt.ty(sema.db)),
+                        Definition::Adt(adt) => {
+                            let mut impls = Impl::all_for_type(db, adt.ty(sema.db));
+                            if config.filter_adjacent_derive_implementations {
+                                impls.retain(|impl_| {
+                                    sema.impl_generated_from_derive(*impl_) != Some(adt)
+                                });
+                            }
+                            impls
+                                .into_iter()
+                                .filter_map(|imp| imp.try_to_nav(&sema))
+                                .flatten()
+                                .collect()
+                        }
                         Definition::TypeAlias(alias) => impls_for_ty(&sema, alias.ty(sema.db)),
                         Definition::BuiltinType(builtin) => {
                             impls_for_ty(&sema, builtin.ty(sema.db))
@@ -125,12 +142,24 @@
     use ide_db::FileRange;
     use itertools::Itertools;
 
-    use crate::fixture;
+    use crate::{GotoImplementationConfig, fixture};
 
+    const TEST_CONFIG: &GotoImplementationConfig =
+        &GotoImplementationConfig { filter_adjacent_derive_implementations: false };
+
+    #[track_caller]
     fn check(#[rust_analyzer::rust_fixture] ra_fixture: &str) {
+        check_with_config(TEST_CONFIG, ra_fixture);
+    }
+
+    #[track_caller]
+    fn check_with_config(
+        config: &GotoImplementationConfig,
+        #[rust_analyzer::rust_fixture] ra_fixture: &str,
+    ) {
         let (analysis, position, expected) = fixture::annotations(ra_fixture);
 
-        let navs = analysis.goto_implementation(position).unwrap().unwrap().info;
+        let navs = analysis.goto_implementation(config, position).unwrap().unwrap().info;
 
         let cmp = |frange: &FileRange| (frange.file_id, frange.range.start());
 
@@ -416,4 +445,22 @@
 "#,
         );
     }
+
+    #[test]
+    fn filter_adjacent_derives() {
+        check_with_config(
+            &GotoImplementationConfig { filter_adjacent_derive_implementations: true },
+            r#"
+//- minicore: clone, copy, derive
+
+#[derive(Clone, Copy)]
+struct Foo$0;
+
+trait Bar {}
+
+impl Bar for Foo {}
+          // ^^^
+            "#,
+        );
+    }
 }
diff --git a/crates/ide/src/hover/tests.rs b/crates/ide/src/hover/tests.rs
index 91fb4d0..3a19531 100644
--- a/crates/ide/src/hover/tests.rs
+++ b/crates/ide/src/hover/tests.rs
@@ -10809,7 +10809,7 @@
 
             ---
 
-            needs Drop
+            no Drop
         "#]],
     );
     check(
diff --git a/crates/ide/src/lib.rs b/crates/ide/src/lib.rs
index 8572528..2609457 100644
--- a/crates/ide/src/lib.rs
+++ b/crates/ide/src/lib.rs
@@ -86,6 +86,7 @@
     file_structure::{FileStructureConfig, StructureNode, StructureNodeKind},
     folding_ranges::{Fold, FoldKind},
     goto_definition::GotoDefinitionConfig,
+    goto_implementation::GotoImplementationConfig,
     highlight_related::{HighlightRelatedConfig, HighlightedRange},
     hover::{
         HoverAction, HoverConfig, HoverDocFormat, HoverGotoTypeData, HoverResult,
@@ -106,7 +107,7 @@
     move_item::Direction,
     navigation_target::{NavigationTarget, TryToNav, UpmappingResult},
     references::{FindAllRefsConfig, ReferenceSearchResult},
-    rename::RenameError,
+    rename::{RenameConfig, RenameError},
     runnables::{Runnable, RunnableKind, TestId, UpdateTest},
     signature_help::SignatureHelp,
     static_index::{
@@ -537,9 +538,10 @@
     /// Returns the impls from the symbol at `position`.
     pub fn goto_implementation(
         &self,
+        config: &GotoImplementationConfig,
         position: FilePosition,
     ) -> Cancellable<Option<RangeInfo<Vec<NavigationTarget>>>> {
-        self.with_db(|db| goto_implementation::goto_implementation(db, position))
+        self.with_db(|db| goto_implementation::goto_implementation(db, config, position))
     }
 
     /// Returns the type definitions for the symbol at `position`.
@@ -830,8 +832,9 @@
         &self,
         position: FilePosition,
         new_name: &str,
+        config: &RenameConfig,
     ) -> Cancellable<Result<SourceChange, RenameError>> {
-        self.with_db(|db| rename::rename(db, position, new_name))
+        self.with_db(|db| rename::rename(db, position, new_name, config))
     }
 
     pub fn prepare_rename(
diff --git a/crates/ide/src/rename.rs b/crates/ide/src/rename.rs
index 8922a8e..ce59639 100644
--- a/crates/ide/src/rename.rs
+++ b/crates/ide/src/rename.rs
@@ -4,7 +4,7 @@
 //! tests. This module also implements a couple of magic tricks, like renaming
 //! `self` and to `self` (to switch between associated function and method).
 
-use hir::{AsAssocItem, InFile, Name, Semantics, sym};
+use hir::{AsAssocItem, FindPathConfig, HasContainer, HirDisplay, InFile, Name, Semantics, sym};
 use ide_db::{
     FileId, FileRange, RootDatabase,
     defs::{Definition, NameClass, NameRefClass},
@@ -27,6 +27,23 @@
 
 type RenameResult<T> = Result<T, RenameError>;
 
+pub struct RenameConfig {
+    pub prefer_no_std: bool,
+    pub prefer_prelude: bool,
+    pub prefer_absolute: bool,
+}
+
+impl RenameConfig {
+    fn find_path_config(&self) -> FindPathConfig {
+        FindPathConfig {
+            prefer_no_std: self.prefer_no_std,
+            prefer_prelude: self.prefer_prelude,
+            prefer_absolute: self.prefer_absolute,
+            allow_unstable: true,
+        }
+    }
+}
+
 /// This is similar to `collect::<Result<Vec<_>, _>>`, but unlike it, it succeeds if there is *any* `Ok` item.
 fn ok_if_any<T, E>(iter: impl Iterator<Item = Result<T, E>>) -> Result<Vec<T>, E> {
     let mut err = None;
@@ -100,6 +117,7 @@
     db: &RootDatabase,
     position: FilePosition,
     new_name: &str,
+    config: &RenameConfig,
 ) -> RenameResult<SourceChange> {
     let sema = Semantics::new(db);
     let file_id = sema
@@ -158,7 +176,14 @@
             if let Definition::Local(local) = def {
                 if let Some(self_param) = local.as_self_param(sema.db) {
                     cov_mark::hit!(rename_self_to_param);
-                    return rename_self_to_param(&sema, local, self_param, &new_name, kind);
+                    return rename_self_to_param(
+                        &sema,
+                        local,
+                        self_param,
+                        &new_name,
+                        kind,
+                        config.find_path_config(),
+                    );
                 }
                 if kind == IdentifierKind::LowercaseSelf {
                     cov_mark::hit!(rename_to_self);
@@ -360,7 +385,7 @@
     f: hir::Function,
 ) {
     let calls = Definition::Function(f).usages(sema).all();
-    for (file_id, calls) in calls {
+    for (_file_id, calls) in calls {
         for call in calls {
             let Some(fn_name) = call.name.as_name_ref() else { continue };
             let Some(path) = fn_name.syntax().parent().and_then(ast::PathSegment::cast) else {
@@ -409,6 +434,12 @@
                     .unwrap_or_else(|| arg_list.syntax().text_range().end()),
             };
             let replace_range = TextRange::new(replace_start, replace_end);
+            let macro_file = sema.hir_file_for(fn_name.syntax());
+            let Some((replace_range, _)) =
+                InFile::new(macro_file, replace_range).original_node_file_range_opt(sema.db)
+            else {
+                continue;
+            };
 
             let Some(macro_mapped_self) = sema.original_range_opt(self_arg.syntax()) else {
                 continue;
@@ -426,8 +457,8 @@
             replacement.push('(');
 
             source_change.insert_source_edit(
-                file_id.file_id(sema.db),
-                TextEdit::replace(replace_range, replacement),
+                replace_range.file_id.file_id(sema.db),
+                TextEdit::replace(replace_range.range, replacement),
             );
         }
     }
@@ -514,12 +545,189 @@
     Ok(source_change)
 }
 
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+enum CallReceiverAdjust {
+    Deref,
+    Ref,
+    RefMut,
+    None,
+}
+
+fn method_to_assoc_fn_call_self_adjust(
+    sema: &Semantics<'_, RootDatabase>,
+    self_arg: &ast::Expr,
+) -> CallReceiverAdjust {
+    let mut result = CallReceiverAdjust::None;
+    let self_adjust = sema.expr_adjustments(self_arg);
+    if let Some(self_adjust) = self_adjust {
+        let mut i = 0;
+        while i < self_adjust.len() {
+            if matches!(self_adjust[i].kind, hir::Adjust::Deref(..))
+                && matches!(
+                    self_adjust.get(i + 1),
+                    Some(hir::Adjustment { kind: hir::Adjust::Borrow(..), .. })
+                )
+            {
+                // Deref then ref (reborrow), skip them.
+                i += 2;
+                continue;
+            }
+
+            match self_adjust[i].kind {
+                hir::Adjust::Deref(_) if result == CallReceiverAdjust::None => {
+                    // Autoref takes precedence over deref, because if given a `&Type` the compiler will deref
+                    // it automatically.
+                    result = CallReceiverAdjust::Deref;
+                }
+                hir::Adjust::Borrow(hir::AutoBorrow::Ref(mutability)) => {
+                    match (result, mutability) {
+                        (CallReceiverAdjust::RefMut, hir::Mutability::Shared) => {}
+                        (_, hir::Mutability::Mut) => result = CallReceiverAdjust::RefMut,
+                        (_, hir::Mutability::Shared) => result = CallReceiverAdjust::Ref,
+                    }
+                }
+                _ => {}
+            }
+
+            i += 1;
+        }
+    }
+    result
+}
+
+fn transform_method_call_into_assoc_fn(
+    sema: &Semantics<'_, RootDatabase>,
+    source_change: &mut SourceChange,
+    f: hir::Function,
+    find_path_config: FindPathConfig,
+) {
+    let calls = Definition::Function(f).usages(sema).all();
+    for (_file_id, calls) in calls {
+        for call in calls {
+            let Some(fn_name) = call.name.as_name_ref() else { continue };
+            let Some(method_call) = fn_name.syntax().parent().and_then(ast::MethodCallExpr::cast)
+            else {
+                continue;
+            };
+            let Some(mut self_arg) = method_call.receiver() else {
+                continue;
+            };
+
+            let Some(scope) = sema.scope(fn_name.syntax()) else {
+                continue;
+            };
+            let self_adjust = method_to_assoc_fn_call_self_adjust(sema, &self_arg);
+
+            // Strip parentheses, function arguments have higher precedence than any operator.
+            while let ast::Expr::ParenExpr(it) = &self_arg {
+                self_arg = match it.expr() {
+                    Some(it) => it,
+                    None => break,
+                };
+            }
+
+            let needs_comma = method_call.arg_list().is_some_and(|it| it.args().next().is_some());
+
+            let self_needs_parens = self_adjust != CallReceiverAdjust::None
+                && self_arg.precedence().needs_parentheses_in(ExprPrecedence::Prefix);
+
+            let replace_start = method_call.syntax().text_range().start();
+            let replace_end = method_call
+                .arg_list()
+                .and_then(|it| it.l_paren_token())
+                .map(|it| it.text_range().end())
+                .unwrap_or_else(|| method_call.syntax().text_range().end());
+            let replace_range = TextRange::new(replace_start, replace_end);
+            let macro_file = sema.hir_file_for(fn_name.syntax());
+            let Some((replace_range, _)) =
+                InFile::new(macro_file, replace_range).original_node_file_range_opt(sema.db)
+            else {
+                continue;
+            };
+
+            let fn_container_path = match f.container(sema.db) {
+                hir::ItemContainer::Trait(trait_) => {
+                    // FIXME: We always put it as `Trait::function`. Is it better to use `Type::function` (but
+                    // that could conflict with an inherent method)? Or maybe `<Type as Trait>::function`?
+                    // Or let the user decide?
+                    let Some(path) = scope.module().find_path(
+                        sema.db,
+                        hir::ItemInNs::Types(trait_.into()),
+                        find_path_config,
+                    ) else {
+                        continue;
+                    };
+                    path.display(sema.db, replace_range.file_id.edition(sema.db)).to_string()
+                }
+                hir::ItemContainer::Impl(impl_) => {
+                    let ty = impl_.self_ty(sema.db);
+                    match ty.as_adt() {
+                        Some(adt) => {
+                            let Some(path) = scope.module().find_path(
+                                sema.db,
+                                hir::ItemInNs::Types(adt.into()),
+                                find_path_config,
+                            ) else {
+                                continue;
+                            };
+                            path.display(sema.db, replace_range.file_id.edition(sema.db))
+                                .to_string()
+                        }
+                        None => {
+                            let Ok(mut ty) =
+                                ty.display_source_code(sema.db, scope.module().into(), false)
+                            else {
+                                continue;
+                            };
+                            ty.insert(0, '<');
+                            ty.push('>');
+                            ty
+                        }
+                    }
+                }
+                _ => continue,
+            };
+
+            let Some(macro_mapped_self) = sema.original_range_opt(self_arg.syntax()) else {
+                continue;
+            };
+            let mut replacement = String::new();
+            replacement.push_str(&fn_container_path);
+            replacement.push_str("::");
+            format_to!(replacement, "{fn_name}");
+            replacement.push('(');
+            replacement.push_str(match self_adjust {
+                CallReceiverAdjust::Deref => "*",
+                CallReceiverAdjust::Ref => "&",
+                CallReceiverAdjust::RefMut => "&mut ",
+                CallReceiverAdjust::None => "",
+            });
+            if self_needs_parens {
+                replacement.push('(');
+            }
+            replacement.push_str(macro_mapped_self.text(sema.db));
+            if self_needs_parens {
+                replacement.push(')');
+            }
+            if needs_comma {
+                replacement.push_str(", ");
+            }
+
+            source_change.insert_source_edit(
+                replace_range.file_id.file_id(sema.db),
+                TextEdit::replace(replace_range.range, replacement),
+            );
+        }
+    }
+}
+
 fn rename_self_to_param(
     sema: &Semantics<'_, RootDatabase>,
     local: hir::Local,
     self_param: hir::SelfParam,
     new_name: &Name,
     identifier_kind: IdentifierKind,
+    find_path_config: FindPathConfig,
 ) -> RenameResult<SourceChange> {
     if identifier_kind == IdentifierKind::LowercaseSelf {
         // Let's do nothing rather than complain.
@@ -527,6 +735,11 @@
         return Ok(SourceChange::default());
     }
 
+    let fn_def = match local.parent(sema.db) {
+        hir::DefWithBody::Function(func) => func,
+        _ => bail!("Cannot rename local to self outside of function"),
+    };
+
     let InFile { file_id, value: self_param } =
         sema.source(self_param).ok_or_else(|| format_err!("cannot find function source"))?;
 
@@ -554,6 +767,7 @@
             ),
         )
     }));
+    transform_method_call_into_assoc_fn(sema, &mut source_change, fn_def, find_path_config);
     Ok(source_change)
 }
 
@@ -587,7 +801,10 @@
 
     use crate::fixture;
 
-    use super::{RangeInfo, RenameError};
+    use super::{RangeInfo, RenameConfig, RenameError};
+
+    const TEST_CONFIG: RenameConfig =
+        RenameConfig { prefer_no_std: false, prefer_prelude: true, prefer_absolute: false };
 
     #[track_caller]
     fn check(
@@ -603,7 +820,7 @@
             panic!("Prepare rename to '{new_name}' was failed: {err}")
         }
         let rename_result = analysis
-            .rename(position, new_name)
+            .rename(position, new_name, &TEST_CONFIG)
             .unwrap_or_else(|err| panic!("Rename to '{new_name}' was cancelled: {err}"));
         match rename_result {
             Ok(source_change) => {
@@ -635,7 +852,7 @@
     #[track_caller]
     fn check_conflicts(new_name: &str, #[rust_analyzer::rust_fixture] ra_fixture: &str) {
         let (analysis, position, conflicts) = fixture::annotations(ra_fixture);
-        let source_change = analysis.rename(position, new_name).unwrap().unwrap();
+        let source_change = analysis.rename(position, new_name, &TEST_CONFIG).unwrap().unwrap();
         let expected_conflicts = conflicts
             .into_iter()
             .map(|(file_range, _)| (file_range.file_id, file_range.range))
@@ -662,8 +879,10 @@
         expect: Expect,
     ) {
         let (analysis, position) = fixture::position(ra_fixture);
-        let source_change =
-            analysis.rename(position, new_name).unwrap().expect("Expect returned a RenameError");
+        let source_change = analysis
+            .rename(position, new_name, &TEST_CONFIG)
+            .unwrap()
+            .expect("Expect returned a RenameError");
         expect.assert_eq(&filter_expect(source_change))
     }
 
@@ -3589,4 +3808,115 @@
         "#,
         );
     }
+
+    #[test]
+    fn rename_to_self_callers_in_macro() {
+        check(
+            "self",
+            r#"
+struct Foo;
+
+impl Foo {
+    fn foo(th$0is: &Self, v: i32) {}
+}
+
+macro_rules! m { ($it:expr) => { $it } }
+fn bar(v: Foo) {
+    m!(Foo::foo(&v, 123));
+}
+        "#,
+            r#"
+struct Foo;
+
+impl Foo {
+    fn foo(&self, v: i32) {}
+}
+
+macro_rules! m { ($it:expr) => { $it } }
+fn bar(v: Foo) {
+    m!(v.foo( 123));
+}
+        "#,
+        );
+    }
+
+    #[test]
+    fn rename_from_self_callers() {
+        check(
+            "this",
+            r#"
+//- minicore: add
+struct Foo;
+impl Foo {
+    fn foo(&sel$0f) {}
+}
+impl core::ops::Add for Foo {
+    type Output = Foo;
+
+    fn add(self, _rhs: Self) -> Self::Output {
+        Foo
+    }
+}
+
+fn bar(v: &Foo) {
+    v.foo();
+    (Foo + Foo).foo();
+}
+
+mod baz {
+    fn baz(v: super::Foo) {
+        v.foo();
+    }
+}
+        "#,
+            r#"
+struct Foo;
+impl Foo {
+    fn foo(this: &Self) {}
+}
+impl core::ops::Add for Foo {
+    type Output = Foo;
+
+    fn add(self, _rhs: Self) -> Self::Output {
+        Foo
+    }
+}
+
+fn bar(v: &Foo) {
+    Foo::foo(v);
+    Foo::foo(&(Foo + Foo));
+}
+
+mod baz {
+    fn baz(v: super::Foo) {
+        crate::Foo::foo(&v);
+    }
+}
+        "#,
+        );
+        // Multiple args:
+        check(
+            "this",
+            r#"
+struct Foo;
+impl Foo {
+    fn foo(&sel$0f, _v: i32) {}
+}
+
+fn bar() {
+    Foo.foo(1);
+}
+        "#,
+            r#"
+struct Foo;
+impl Foo {
+    fn foo(this: &Self, _v: i32) {}
+}
+
+fn bar() {
+    Foo::foo(&Foo, 1);
+}
+        "#,
+        );
+    }
 }
diff --git a/crates/ide/src/signature_help.rs b/crates/ide/src/signature_help.rs
index 5f7e12c..f9ec448 100644
--- a/crates/ide/src/signature_help.rs
+++ b/crates/ide/src/signature_help.rs
@@ -175,6 +175,9 @@
     match callable.kind() {
         hir::CallableKind::Function(func) => {
             res.doc = func.docs(db);
+            if func.is_async(db) {
+                format_to!(res.signature, "async ");
+            }
             format_to!(res.signature, "fn {}", func.name(db).display(db, edition));
 
             let generic_params = GenericDef::Function(func)
@@ -283,13 +286,16 @@
         }
     };
     match callable.kind() {
-        hir::CallableKind::Function(func) if callable.return_type().contains_unknown() => {
-            render(func.ret_type(db))
+        hir::CallableKind::Function(func) => render(func.async_ret_type(db).unwrap_or_else(|| {
+            if callable.return_type().contains_unknown() {
+                func.ret_type(db)
+            } else {
+                callable.return_type()
+            }
+        })),
+        hir::CallableKind::Closure(_) | hir::CallableKind::FnPtr | hir::CallableKind::FnImpl(_) => {
+            render(callable.return_type())
         }
-        hir::CallableKind::Function(_)
-        | hir::CallableKind::Closure(_)
-        | hir::CallableKind::FnPtr
-        | hir::CallableKind::FnImpl(_) => render(callable.return_type()),
         hir::CallableKind::TupleStruct(_) | hir::CallableKind::TupleEnumVariant(_) => {}
     }
     Some(res)
@@ -751,13 +757,7 @@
 
     #[track_caller]
     fn check(#[rust_analyzer::rust_fixture] ra_fixture: &str, expect: Expect) {
-        let fixture = format!(
-            r#"
-//- minicore: sized, fn
-{ra_fixture}
-            "#
-        );
-        let (db, position) = position(&fixture);
+        let (db, position) = position(ra_fixture);
         let sig_help = hir::attach_db(&db, || crate::signature_help::signature_help(&db, position));
         let actual = match sig_help {
             Some(sig_help) => {
@@ -795,6 +795,7 @@
     fn test_fn_signature_two_args() {
         check(
             r#"
+//- minicore: sized, fn
 fn foo(x: u32, y: u32) -> u32 {x + y}
 fn bar() { foo($03, ); }
 "#,
@@ -805,6 +806,7 @@
         );
         check(
             r#"
+//- minicore: sized, fn
 fn foo(x: u32, y: u32) -> u32 {x + y}
 fn bar() { foo(3$0, ); }
 "#,
@@ -815,6 +817,7 @@
         );
         check(
             r#"
+//- minicore: sized, fn
 fn foo(x: u32, y: u32) -> u32 {x + y}
 fn bar() { foo(3,$0 ); }
 "#,
@@ -825,6 +828,7 @@
         );
         check(
             r#"
+//- minicore: sized, fn
 fn foo(x: u32, y: u32) -> u32 {x + y}
 fn bar() { foo(3, $0); }
 "#,
@@ -839,6 +843,7 @@
     fn test_fn_signature_two_args_empty() {
         check(
             r#"
+//- minicore: sized, fn
 fn foo(x: u32, y: u32) -> u32 {x + y}
 fn bar() { foo($0); }
 "#,
@@ -853,6 +858,7 @@
     fn test_fn_signature_two_args_first_generics() {
         check(
             r#"
+//- minicore: sized, fn
 fn foo<T, U: Copy + Display>(x: T, y: U) -> u32
     where T: Copy + Display, U: Debug
 { x + y }
@@ -870,6 +876,7 @@
     fn test_fn_signature_no_params() {
         check(
             r#"
+//- minicore: sized, fn
 fn foo<T>() -> T where T: Copy + Display {}
 fn bar() { foo($0); }
 "#,
@@ -883,6 +890,7 @@
     fn test_fn_signature_for_impl() {
         check(
             r#"
+//- minicore: sized, fn
 struct F;
 impl F { pub fn new() { } }
 fn bar() {
@@ -899,6 +907,7 @@
     fn test_fn_signature_for_method_self() {
         check(
             r#"
+//- minicore: sized, fn
 struct S;
 impl S { pub fn do_it(&self) {} }
 
@@ -917,6 +926,7 @@
     fn test_fn_signature_for_method_with_arg() {
         check(
             r#"
+//- minicore: sized, fn
 struct S;
 impl S {
     fn foo(&self, x: i32) {}
@@ -935,6 +945,7 @@
     fn test_fn_signature_for_generic_method() {
         check(
             r#"
+//- minicore: sized, fn
 struct S<T>(T);
 impl<T> S<T> {
     fn foo(&self, x: T) {}
@@ -953,6 +964,7 @@
     fn test_fn_signature_for_method_with_arg_as_assoc_fn() {
         check(
             r#"
+//- minicore: sized, fn
 struct S;
 impl S {
     fn foo(&self, x: i32) {}
@@ -971,6 +983,7 @@
     fn test_fn_signature_with_docs_simple() {
         check(
             r#"
+//- minicore: sized, fn
 /// test
 // non-doc-comment
 fn foo(j: u32) -> u32 {
@@ -994,6 +1007,7 @@
     fn test_fn_signature_with_docs() {
         check(
             r#"
+//- minicore: sized, fn
 /// Adds one to the number given.
 ///
 /// # Examples
@@ -1031,6 +1045,7 @@
     fn test_fn_signature_with_docs_impl() {
         check(
             r#"
+//- minicore: sized, fn
 struct addr;
 impl addr {
     /// Adds one to the number given.
@@ -1073,6 +1088,7 @@
     fn test_fn_signature_with_docs_from_actix() {
         check(
             r#"
+//- minicore: sized, fn
 trait Actor {
     /// Actor execution context type
     type Context;
@@ -1106,6 +1122,7 @@
     fn call_info_bad_offset() {
         check(
             r#"
+//- minicore: sized, fn
 fn foo(x: u32, y: u32) -> u32 {x + y}
 fn bar() { foo $0 (3, ); }
 "#,
@@ -1117,6 +1134,7 @@
     fn outside_of_arg_list() {
         check(
             r#"
+//- minicore: sized, fn
 fn foo(a: u8) {}
 fn f() {
     foo(123)$0
@@ -1126,6 +1144,7 @@
         );
         check(
             r#"
+//- minicore: sized, fn
 fn foo<T>(a: u8) {}
 fn f() {
     foo::<u32>$0()
@@ -1135,6 +1154,7 @@
         );
         check(
             r#"
+//- minicore: sized, fn
 fn foo(a: u8) -> u8 {a}
 fn bar(a: u8) -> u8 {a}
 fn f() {
@@ -1148,6 +1168,7 @@
         );
         check(
             r#"
+//- minicore: sized, fn
 struct Vec<T>(T);
 struct Vec2<T>(T);
 fn f() {
@@ -1165,6 +1186,7 @@
     fn test_nested_method_in_lambda() {
         check(
             r#"
+//- minicore: sized, fn
 struct Foo;
 impl Foo { fn bar(&self, _: u32) { } }
 
@@ -1186,6 +1208,7 @@
     fn works_for_tuple_structs() {
         check(
             r#"
+//- minicore: sized, fn
 /// A cool tuple struct
 struct S(u32, i32);
 fn main() {
@@ -1205,6 +1228,7 @@
     fn tuple_struct_pat() {
         check(
             r#"
+//- minicore: sized, fn
 /// A cool tuple struct
 struct S(u32, i32);
 fn main() {
@@ -1224,6 +1248,7 @@
     fn tuple_struct_pat_rest() {
         check(
             r#"
+//- minicore: sized, fn
 /// A cool tuple struct
 struct S(u32, i32, f32, u16);
 fn main() {
@@ -1239,6 +1264,7 @@
         );
         check(
             r#"
+//- minicore: sized, fn
 /// A cool tuple struct
 struct S(u32, i32, f32, u16, u8);
 fn main() {
@@ -1254,6 +1280,7 @@
         );
         check(
             r#"
+//- minicore: sized, fn
 /// A cool tuple struct
 struct S(u32, i32, f32, u16);
 fn main() {
@@ -1269,6 +1296,7 @@
         );
         check(
             r#"
+//- minicore: sized, fn
 /// A cool tuple struct
 struct S(u32, i32, f32, u16, u8);
 fn main() {
@@ -1284,6 +1312,7 @@
         );
         check(
             r#"
+//- minicore: sized, fn
 /// A cool tuple struct
 struct S(u32, i32, f32, u16);
 fn main() {
@@ -1299,6 +1328,7 @@
         );
         check(
             r#"
+//- minicore: sized, fn
 /// A cool tuple struct
 struct S(u32, i32, f32, u16);
 fn main() {
@@ -1318,6 +1348,7 @@
     fn generic_struct() {
         check(
             r#"
+//- minicore: sized, fn
 struct S<T>(T);
 fn main() {
     let s = S($0);
@@ -1334,6 +1365,7 @@
     fn works_for_enum_variants() {
         check(
             r#"
+//- minicore: sized, fn
 enum E {
     /// A Variant
     A(i32),
@@ -1360,6 +1392,7 @@
     fn cant_call_struct_record() {
         check(
             r#"
+//- minicore: sized, fn
 struct S { x: u32, y: i32 }
 fn main() {
     let s = S($0);
@@ -1373,6 +1406,7 @@
     fn cant_call_enum_record() {
         check(
             r#"
+//- minicore: sized, fn
 enum E {
     /// A Variant
     A(i32),
@@ -1394,6 +1428,7 @@
     fn fn_signature_for_call_in_macro() {
         check(
             r#"
+//- minicore: sized, fn
 macro_rules! id { ($($tt:tt)*) => { $($tt)* } }
 fn foo() { }
 id! {
@@ -1410,6 +1445,7 @@
     fn fn_signature_for_method_call_defined_in_macro() {
         check(
             r#"
+//- minicore: sized, fn
 macro_rules! id { ($($tt:tt)*) => { $($tt)* } }
 struct S;
 id! {
@@ -1429,6 +1465,7 @@
     fn call_info_for_lambdas() {
         check(
             r#"
+//- minicore: sized, fn
 struct S;
 fn foo(s: S) -> i32 { 92 }
 fn main() {
@@ -1443,6 +1480,7 @@
         );
         check(
             r#"
+//- minicore: sized, fn
 struct S;
 fn foo(s: S) -> i32 { 92 }
 fn main() {
@@ -1456,6 +1494,7 @@
         );
         check(
             r#"
+//- minicore: sized, fn
 struct S;
 fn foo(s: S) -> i32 { 92 }
 fn main() {
@@ -1474,6 +1513,7 @@
     fn call_info_for_fn_def_over_reference() {
         check(
             r#"
+//- minicore: sized, fn
 struct S;
 fn foo(s: S) -> i32 { 92 }
 fn main() {
@@ -1492,6 +1532,7 @@
     fn call_info_for_fn_ptr() {
         check(
             r#"
+//- minicore: sized, fn
 fn main(f: fn(i32, f64) -> char) {
     f(0, $0)
 }
@@ -1507,6 +1548,7 @@
     fn call_info_for_fn_impl() {
         check(
             r#"
+//- minicore: sized, fn
 struct S;
 impl core::ops::FnOnce<(i32, f64)> for S {
     type Output = char;
@@ -1524,6 +1566,7 @@
         );
         check(
             r#"
+//- minicore: sized, fn
 struct S;
 impl core::ops::FnOnce<(i32, f64)> for S {
     type Output = char;
@@ -1541,6 +1584,7 @@
         );
         check(
             r#"
+//- minicore: sized, fn
 struct S;
 impl core::ops::FnOnce<(i32, f64)> for S {
     type Output = char;
@@ -1556,6 +1600,7 @@
         );
         check(
             r#"
+//- minicore: sized, fn
 struct S;
 impl core::ops::FnOnce<(i32, f64)> for S {
     type Output = char;
@@ -1576,6 +1621,7 @@
     fn call_info_for_unclosed_call() {
         check(
             r#"
+//- minicore: sized, fn
 fn foo(foo: u32, bar: u32) {}
 fn main() {
     foo($0
@@ -1588,6 +1634,7 @@
         // check with surrounding space
         check(
             r#"
+//- minicore: sized, fn
 fn foo(foo: u32, bar: u32) {}
 fn main() {
     foo( $0
@@ -1603,6 +1650,7 @@
     fn test_multiline_argument() {
         check(
             r#"
+//- minicore: sized, fn
 fn callee(a: u8, b: u8) {}
 fn main() {
     callee(match 0 {
@@ -1613,6 +1661,7 @@
         );
         check(
             r#"
+//- minicore: sized, fn
 fn callee(a: u8, b: u8) {}
 fn main() {
     callee(match 0 {
@@ -1626,6 +1675,7 @@
         );
         check(
             r#"
+//- minicore: sized, fn
 fn callee(a: u8, b: u8) {}
 fn main() {
     callee($0match 0 {
@@ -1643,6 +1693,7 @@
     fn test_generics_simple() {
         check(
             r#"
+//- minicore: sized, fn
 /// Option docs.
 enum Option<T> {
     Some(T),
@@ -1666,6 +1717,7 @@
     fn test_generics_on_variant() {
         check(
             r#"
+//- minicore: sized, fn
 /// Option docs.
 enum Option<T> {
     /// Some docs.
@@ -1693,6 +1745,7 @@
     fn test_lots_of_generics() {
         check(
             r#"
+//- minicore: sized, fn
 trait Tr<T> {}
 
 struct S<T>(T);
@@ -1716,6 +1769,7 @@
     fn test_generics_in_trait_ufcs() {
         check(
             r#"
+//- minicore: sized, fn
 trait Tr {
     fn f<T: Tr, U>() {}
 }
@@ -1739,6 +1793,7 @@
     fn test_generics_in_method_call() {
         check(
             r#"
+//- minicore: sized, fn
 struct S;
 
 impl S {
@@ -1760,6 +1815,7 @@
     fn test_generic_param_in_method_call() {
         check(
             r#"
+//- minicore: sized, fn
 struct Foo;
 impl Foo {
     fn test<V>(&mut self, val: V) {}
@@ -1779,6 +1835,7 @@
     fn test_generic_kinds() {
         check(
             r#"
+//- minicore: sized, fn
 fn callee<'a, const A: u8, T, const C: u8>() {}
 
 fn f() {
@@ -1792,6 +1849,7 @@
         );
         check(
             r#"
+//- minicore: sized, fn
 fn callee<'a, const A: u8, T, const C: u8>() {}
 
 fn f() {
@@ -1809,6 +1867,7 @@
     fn test_trait_assoc_types() {
         check(
             r#"
+//- minicore: sized, fn
 trait Trait<'a, T> {
     type Assoc;
 }
@@ -1821,6 +1880,7 @@
         );
         check(
             r#"
+//- minicore: sized, fn
 trait Iterator {
     type Item;
 }
@@ -1833,6 +1893,7 @@
         );
         check(
             r#"
+//- minicore: sized, fn
 trait Iterator {
     type Item;
 }
@@ -1845,6 +1906,7 @@
         );
         check(
             r#"
+//- minicore: sized, fn
 trait Tr {
     type A;
     type B;
@@ -1858,6 +1920,7 @@
         );
         check(
             r#"
+//- minicore: sized, fn
 trait Tr {
     type A;
     type B;
@@ -1871,6 +1934,7 @@
         );
         check(
             r#"
+//- minicore: sized, fn
 trait Tr {
     type A;
     type B;
@@ -1884,6 +1948,7 @@
         );
         check(
             r#"
+//- minicore: sized, fn
 trait Tr {
     type A;
     type B;
@@ -1901,6 +1966,7 @@
     fn test_supertrait_assoc() {
         check(
             r#"
+//- minicore: sized, fn
 trait Super {
     type SuperTy;
 }
@@ -1920,6 +1986,7 @@
     fn no_assoc_types_outside_type_bounds() {
         check(
             r#"
+//- minicore: sized, fn
 trait Tr<T> {
     type Assoc;
 }
@@ -1938,6 +2005,7 @@
         // FIXME: Substitute type vars in impl trait (`U` -> `i8`)
         check(
             r#"
+//- minicore: sized, fn
 trait Trait<T> {}
 struct Wrap<T>(T);
 fn foo<U>(x: Wrap<impl Trait<U>>) {}
@@ -1956,6 +2024,7 @@
     fn fully_qualified_syntax() {
         check(
             r#"
+//- minicore: sized, fn
 fn f() {
     trait A { fn foo(&self, other: Self); }
     A::foo(&self$0, other);
@@ -1972,6 +2041,7 @@
     fn help_for_generic_call() {
         check(
             r#"
+//- minicore: sized, fn
 fn f<F: FnOnce(u8, u16) -> i32>(f: F) {
     f($0)
 }
@@ -1983,6 +2053,7 @@
         );
         check(
             r#"
+//- minicore: sized, fn
 fn f<T, F: FnMut(&T, u16) -> &T>(f: F) {
     f($0)
 }
@@ -1996,8 +2067,15 @@
 
     #[test]
     fn regression_13579() {
+        // FIXME(next-solver): There should be signature help available here.
+        // The reason it is not is because of a trait solver bug. Since `Error` is not provided
+        // nor it can be inferred, it becomes an error type. The bug is that the solver ignores
+        // predicates on error types, and they do not guide infer vars, not allowing us to infer
+        // that `take`'s return type is callable.
+        // https://github.com/rust-lang/rust/pull/146602 should fix the solver bug.
         check(
             r#"
+//- minicore: sized, fn
 fn f() {
     take(2)($0);
 }
@@ -2008,9 +2086,7 @@
     move || count
 }
 "#,
-            expect![[r#"
-                impl Fn() -> i32
-            "#]],
+            expect![""],
         );
     }
 
@@ -2018,6 +2094,7 @@
     fn record_literal() {
         check(
             r#"
+//- minicore: sized, fn
 struct Strukt<T, U = ()> {
     t: T,
     u: U,
@@ -2041,6 +2118,7 @@
     fn record_literal_nonexistent_field() {
         check(
             r#"
+//- minicore: sized, fn
 struct Strukt {
     a: u8,
 }
@@ -2062,6 +2140,7 @@
     fn tuple_variant_record_literal() {
         check(
             r#"
+//- minicore: sized, fn
 enum Opt {
     Some(u8),
 }
@@ -2076,6 +2155,7 @@
         );
         check(
             r#"
+//- minicore: sized, fn
 enum Opt {
     Some(u8),
 }
@@ -2094,6 +2174,7 @@
     fn record_literal_self() {
         check(
             r#"
+//- minicore: sized, fn
 struct S { t: u8 }
 impl S {
     fn new() -> Self {
@@ -2112,6 +2193,7 @@
     fn record_pat() {
         check(
             r#"
+//- minicore: sized, fn
 struct Strukt<T, U = ()> {
     t: T,
     u: U,
@@ -2135,6 +2217,7 @@
     fn test_enum_in_nested_method_in_lambda() {
         check(
             r#"
+//- minicore: sized, fn
 enum A {
     A,
     B
@@ -2158,6 +2241,7 @@
     fn test_tuple_expr_free() {
         check(
             r#"
+//- minicore: sized, fn
 fn main() {
     (0$0, 1, 3);
 }
@@ -2169,6 +2253,7 @@
         );
         check(
             r#"
+//- minicore: sized, fn
 fn main() {
     ($0 1, 3);
 }
@@ -2180,6 +2265,7 @@
         );
         check(
             r#"
+//- minicore: sized, fn
 fn main() {
     (1, 3 $0);
 }
@@ -2191,6 +2277,7 @@
         );
         check(
             r#"
+//- minicore: sized, fn
 fn main() {
     (1, 3 $0,);
 }
@@ -2206,6 +2293,7 @@
     fn test_tuple_expr_expected() {
         check(
             r#"
+//- minicore: sized, fn
 fn main() {
     let _: (&str, u32, u32)= ($0, 1, 3);
 }
@@ -2218,6 +2306,7 @@
         // FIXME: Should typeck report a 4-ary tuple for the expression here?
         check(
             r#"
+//- minicore: sized, fn
 fn main() {
     let _: (&str, u32, u32, u32) = ($0, 1, 3);
 }
@@ -2229,6 +2318,7 @@
         );
         check(
             r#"
+//- minicore: sized, fn
 fn main() {
     let _: (&str, u32, u32)= ($0, 1, 3, 5);
 }
@@ -2244,6 +2334,7 @@
     fn test_tuple_pat_free() {
         check(
             r#"
+//- minicore: sized, fn
 fn main() {
     let ($0, 1, 3);
 }
@@ -2255,6 +2346,7 @@
         );
         check(
             r#"
+//- minicore: sized, fn
 fn main() {
     let (0$0, 1, 3);
 }
@@ -2266,6 +2358,7 @@
         );
         check(
             r#"
+//- minicore: sized, fn
 fn main() {
     let ($0 1, 3);
 }
@@ -2277,6 +2370,7 @@
         );
         check(
             r#"
+//- minicore: sized, fn
 fn main() {
     let (1, 3 $0);
 }
@@ -2288,6 +2382,7 @@
         );
         check(
             r#"
+//- minicore: sized, fn
 fn main() {
     let (1, 3 $0,);
 }
@@ -2299,6 +2394,7 @@
         );
         check(
             r#"
+//- minicore: sized, fn
 fn main() {
     let (1, 3 $0, ..);
 }
@@ -2310,6 +2406,7 @@
         );
         check(
             r#"
+//- minicore: sized, fn
 fn main() {
     let (1, 3, .., $0);
 }
@@ -2326,6 +2423,7 @@
     fn test_tuple_pat_expected() {
         check(
             r#"
+//- minicore: sized, fn
 fn main() {
     let (0$0, 1, 3): (i32, i32, i32);
 }
@@ -2337,6 +2435,7 @@
         );
         check(
             r#"
+//- minicore: sized, fn
 fn main() {
     let ($0, 1, 3): (i32, i32, i32);
 }
@@ -2348,6 +2447,7 @@
         );
         check(
             r#"
+//- minicore: sized, fn
 fn main() {
     let (1, 3 $0): (i32,);
 }
@@ -2359,6 +2459,7 @@
         );
         check(
             r#"
+//- minicore: sized, fn
 fn main() {
     let (1, 3 $0, ..): (i32, i32, i32, i32);
 }
@@ -2370,6 +2471,7 @@
         );
         check(
             r#"
+//- minicore: sized, fn
 fn main() {
     let (1, 3, .., $0): (i32, i32, i32);
 }
@@ -2384,6 +2486,7 @@
     fn test_tuple_pat_expected_inferred() {
         check(
             r#"
+//- minicore: sized, fn
 fn main() {
     let (0$0, 1, 3) = (1, 2 ,3);
 }
@@ -2395,6 +2498,7 @@
         );
         check(
             r#"
+//- minicore: sized, fn
 fn main() {
     let ($0 1, 3) = (1, 2, 3);
 }
@@ -2407,6 +2511,7 @@
         );
         check(
             r#"
+//- minicore: sized, fn
 fn main() {
     let (1, 3 $0) = (1,);
 }
@@ -2418,6 +2523,7 @@
         );
         check(
             r#"
+//- minicore: sized, fn
 fn main() {
     let (1, 3 $0, ..) = (1, 2, 3, 4);
 }
@@ -2429,6 +2535,7 @@
         );
         check(
             r#"
+//- minicore: sized, fn
 fn main() {
     let (1, 3, .., $0) = (1, 2, 3);
 }
@@ -2444,6 +2551,7 @@
     fn test_tuple_generic_param() {
         check(
             r#"
+//- minicore: sized, fn
 struct S<T>(T);
 
 fn main() {
@@ -2461,6 +2569,7 @@
     fn test_enum_generic_param() {
         check(
             r#"
+//- minicore: sized, fn
 enum Option<T> {
     Some(T),
     None,
@@ -2481,6 +2590,7 @@
     fn test_enum_variant_generic_param() {
         check(
             r#"
+//- minicore: sized, fn
 enum Option<T> {
     Some(T),
     None,
@@ -2501,6 +2611,7 @@
     fn test_generic_arg_with_default() {
         check(
             r#"
+//- minicore: sized, fn
 struct S<T = u8> {
     field: T,
 }
@@ -2517,6 +2628,7 @@
 
         check(
             r#"
+//- minicore: sized, fn
 struct S<const C: u8 = 5> {
     field: C,
 }
@@ -2531,4 +2643,27 @@
             "#]],
         );
     }
+
+    #[test]
+    fn test_async_function() {
+        check(
+            r#"
+//- minicore: sized, fn, future, result
+pub async fn conn_mut<F, T>(f: F) -> Result<T, i32>
+where
+    F: FnOnce() -> T,
+{
+    Ok(f())
+}
+
+fn main() {
+    conn_mut($0)
+}
+            "#,
+            expect![[r#"
+                async fn conn_mut<F: FnOnce() -> T, T>(f: F) -> Result<T, i32>
+                                                       ^^^^
+            "#]],
+        );
+    }
 }
diff --git a/crates/ide/src/syntax_highlighting.rs b/crates/ide/src/syntax_highlighting.rs
index 66895cb..531c7e1 100644
--- a/crates/ide/src/syntax_highlighting.rs
+++ b/crates/ide/src/syntax_highlighting.rs
@@ -114,9 +114,9 @@
 // |-----------|--------------------------------|
 // |operator| Emitted for general operators.|
 // |arithmetic| Emitted for the arithmetic operators `+`, `-`, `*`, `/`, `+=`, `-=`, `*=`, `/=`.|
-// |bitwise| Emitted for the bitwise operators `|`, `&`, `!`, `^`, `|=`, `&=`, `^=`.|
+// |bitwise| Emitted for the bitwise operators `\|`, `&`, `!`, `^`, `\|=`, `&=`, `^=`.|
 // |comparison| Emitted for the comparison oerators `>`, `<`, `==`, `>=`, `<=`, `!=`.|
-// |logical| Emitted for the logical operators `||`, `&&`, `!`.|
+// |logical| Emitted for the logical operators `\|\|`, `&&`, `!`.|
 //
 // - For punctuation:
 //
@@ -172,20 +172,20 @@
 // |constant| Emitted for const.|
 // |consuming| Emitted for locals that are being consumed when use in a function call.|
 // |controlFlow| Emitted for control-flow related tokens, this includes th `?` operator.|
-// |crateRoot| Emitted for crate names, like `serde` and `crate.|
+// |crateRoot| Emitted for crate names, like `serde` and `crate`.|
 // |declaration| Emitted for names of definitions, like `foo` in `fn foo(){}`.|
-// |defaultLibrary| Emitted for items from built-in crates (std, core, allc, test and proc_macro).|
+// |defaultLibrary| Emitted for items from built-in crates (std, core, alloc, test and proc_macro).|
 // |documentation| Emitted for documentation comment.|
 // |injected| Emitted for doc-string injected highlighting like rust source blocks in documentation.|
 // |intraDocLink| Emitted for intra doc links in doc-string.|
-// |library| Emitted for items that are defined outside of the current crae.|
+// |library| Emitted for items that are defined outside of the current crate.|
 // |macro|  Emitted for tokens inside macro call.|
 // |mutable| Emitted for mutable locals and statics as well as functions taking `&mut self`.|
-// |public| Emitted for items that are from the current crate and are `pub.|
-// |reference| Emitted for locals behind a reference and functions taking self` by reference.|
-// |static| Emitted for "static" functions, also known as functions that d not take a `self` param, as well as statics and consts.|
+// |public| Emitted for items that are from the current crate and are `pub`.|
+// |reference| Emitted for locals behind a reference and functions taking `self` by reference.|
+// |static| Emitted for "static" functions, also known as functions that do not take a `self` param, as well as statics and consts.|
 // |trait| Emitted for associated trait item.|
-// |unsafe| Emitted for unsafe operations, like unsafe function calls, as ell as the `unsafe` token.|
+// |unsafe| Emitted for unsafe operations, like unsafe function calls, as well as the `unsafe` token.|
 //
 // ![Semantic Syntax Highlighting](https://user-images.githubusercontent.com/48062697/113164457-06cfb980-9239-11eb-819b-0f93e646acf8.png)
 // ![Semantic Syntax Highlighting](https://user-images.githubusercontent.com/48062697/113187625-f7f50100-9250-11eb-825e-91c58f236071.png)
diff --git a/crates/ide/src/syntax_highlighting/test_data/highlight_block_mod_items.html b/crates/ide/src/syntax_highlighting/test_data/highlight_block_mod_items.html
index 3beda39..711f534 100644
--- a/crates/ide/src/syntax_highlighting/test_data/highlight_block_mod_items.html
+++ b/crates/ide/src/syntax_highlighting/test_data/highlight_block_mod_items.html
@@ -53,7 +53,7 @@
         <span class="macro public">foo</span><span class="macro_bang">!</span><span class="parenthesis">(</span><span class="struct declaration macro public">Bar</span><span class="parenthesis">)</span><span class="semicolon">;</span>
         <span class="keyword">fn</span> <span class="function declaration">func</span><span class="parenthesis">(</span><span class="punctuation">_</span><span class="colon">:</span> <span class="module">y</span><span class="operator">::</span><span class="struct public">Bar</span><span class="parenthesis">)</span> <span class="brace">{</span>
             <span class="keyword">mod</span> <span class="module declaration">inner</span> <span class="brace">{</span>
-                <span class="keyword">struct</span> <span class="struct declaration">Innerest</span><span class="angle">&lt;</span><span class="keyword const">const</span> <span class="const_param const declaration">C</span><span class="colon">:</span> <span class="unresolved_reference">usize</span><span class="angle">&gt;</span> <span class="brace">{</span> <span class="field declaration">field</span><span class="colon">:</span> <span class="bracket">[</span><span class="parenthesis">(</span><span class="parenthesis">)</span><span class="semicolon">;</span> <span class="brace">{</span><span class="const_param const">C</span><span class="brace">}</span><span class="bracket">]</span> <span class="brace">}</span>
+                <span class="keyword">struct</span> <span class="struct declaration">Innerest</span><span class="angle">&lt;</span><span class="keyword const">const</span> <span class="const_param const declaration">C</span><span class="colon">:</span> <span class="builtin_type">usize</span><span class="angle">&gt;</span> <span class="brace">{</span> <span class="field declaration">field</span><span class="colon">:</span> <span class="bracket">[</span><span class="parenthesis">(</span><span class="parenthesis">)</span><span class="semicolon">;</span> <span class="brace">{</span><span class="const_param const">C</span><span class="brace">}</span><span class="bracket">]</span> <span class="brace">}</span>
             <span class="brace">}</span>
         <span class="brace">}</span>
     <span class="brace">}</span>
diff --git a/crates/ide/src/syntax_highlighting/test_data/regression_20952.html b/crates/ide/src/syntax_highlighting/test_data/regression_20952.html
new file mode 100644
index 0000000..2c0250c
--- /dev/null
+++ b/crates/ide/src/syntax_highlighting/test_data/regression_20952.html
@@ -0,0 +1,45 @@
+
+<style>
+body                { margin: 0; }
+pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padding: 0.4em; }
+
+.lifetime           { color: #DFAF8F; font-style: italic; }
+.label              { color: #DFAF8F; font-style: italic; }
+.comment            { color: #7F9F7F; }
+.documentation      { color: #629755; }
+.intra_doc_link     { font-style: italic; }
+.injected           { opacity: 0.65 ; }
+.struct, .enum      { color: #7CB8BB; }
+.enum_variant       { color: #BDE0F3; }
+.string_literal     { color: #CC9393; }
+.field              { color: #94BFF3; }
+.function           { color: #93E0E3; }
+.parameter          { color: #94BFF3; }
+.text               { color: #DCDCCC; }
+.type               { color: #7CB8BB; }
+.builtin_type       { color: #8CD0D3; }
+.type_param         { color: #DFAF8F; }
+.attribute          { color: #94BFF3; }
+.numeric_literal    { color: #BFEBBF; }
+.bool_literal       { color: #BFE6EB; }
+.macro              { color: #94BFF3; }
+.proc_macro         { color: #94BFF3; text-decoration: underline; }
+.derive             { color: #94BFF3; font-style: italic; }
+.module             { color: #AFD8AF; }
+.value_param        { color: #DCDCCC; }
+.variable           { color: #DCDCCC; }
+.format_specifier   { color: #CC696B; }
+.mutable            { text-decoration: underline; }
+.escape_sequence    { color: #94BFF3; }
+.keyword            { color: #F0DFAF; font-weight: bold; }
+.control            { font-style: italic; }
+.reference          { font-style: italic; font-weight: bold; }
+.const              { font-weight: bolder; }
+.unsafe             { color: #BC8383; }
+
+.invalid_escape_sequence { color: #FC5555; text-decoration: wavy underline; }
+.unresolved_reference    { color: #FC5555; text-decoration: wavy underline; }
+</style>
+<pre><code><span class="keyword">fn</span> <span class="function declaration">main</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span>
+    <span class="macro default_library library">format_args</span><span class="macro_bang">!</span><span class="parenthesis">(</span>"{} {}, {} (подозрение на спам: {:.2}%)"б<span class="parenthesis">)</span><span class="semicolon">;</span>
+<span class="brace">}</span></code></pre>
\ No newline at end of file
diff --git a/crates/ide/src/syntax_highlighting/tests.rs b/crates/ide/src/syntax_highlighting/tests.rs
index 4e84127..58c613e 100644
--- a/crates/ide/src/syntax_highlighting/tests.rs
+++ b/crates/ide/src/syntax_highlighting/tests.rs
@@ -1497,3 +1497,17 @@
         false,
     );
 }
+
+#[test]
+fn regression_20952() {
+    check_highlighting(
+        r#"
+//- minicore: fmt
+fn main() {
+    format_args!("{} {}, {} (подозрение на спам: {:.2}%)"б);
+}
+"#,
+        expect_file!["./test_data/regression_20952.html"],
+        false,
+    );
+}
diff --git a/crates/parser/src/grammar.rs b/crates/parser/src/grammar.rs
index 8ddf50d..bf84302 100644
--- a/crates/parser/src/grammar.rs
+++ b/crates/parser/src/grammar.rs
@@ -94,7 +94,17 @@
 
         pub(crate) fn source_file(p: &mut Parser<'_>) {
             let m = p.start();
+            // test frontmatter
+            // #!/usr/bin/env cargo
+            //
+            // ---
+            // [dependencies]
+            // clap = { version = "4.2", features = ["derive"] }
+            // ---
+            //
+            // fn main() {}
             p.eat(SHEBANG);
+            p.eat(FRONTMATTER);
             items::mod_contents(p, false);
             m.complete(p, SOURCE_FILE);
         }
diff --git a/crates/parser/src/grammar/expressions/atom.rs b/crates/parser/src/grammar/expressions/atom.rs
index ed8a91c..cde62e0 100644
--- a/crates/parser/src/grammar/expressions/atom.rs
+++ b/crates/parser/src/grammar/expressions/atom.rs
@@ -588,6 +588,12 @@
     }
     params::param_list_closure(p);
     if opt_ret_type(p) {
+        // test_err closure_ret_recovery
+        // fn foo() { || -> A> { let x = 1; } }
+        while p.at(T![>]) {
+            // recover from unbalanced return type brackets
+            p.err_and_bump("expected a curly brace");
+        }
         // test lambda_ret_block
         // fn main() { || -> i32 { 92 }(); }
         block_expr(p);
diff --git a/crates/parser/src/grammar/items.rs b/crates/parser/src/grammar/items.rs
index 8e551b0..c609f93 100644
--- a/crates/parser/src/grammar/items.rs
+++ b/crates/parser/src/grammar/items.rs
@@ -424,6 +424,14 @@
     // fn bar() -> () {}
     opt_ret_type(p);
 
+    // test_err fn_ret_recovery
+    // fn foo() -> A>]) { let x = 1; }
+    // fn foo() -> A>]) where T: Copy { let x = 1; }
+    while p.at(T![')']) | p.at(T![']']) | p.at(T![>]) {
+        // recover from unbalanced return type brackets
+        p.err_and_bump("expected a curly brace");
+    }
+
     // test function_where_clause
     // fn foo<T>() where T: Copy {}
     generic_params::opt_where_clause(p);
diff --git a/crates/parser/test_data/generated/runner.rs b/crates/parser/test_data/generated/runner.rs
index 9bdbe56..7f5ff0e 100644
--- a/crates/parser/test_data/generated/runner.rs
+++ b/crates/parser/test_data/generated/runner.rs
@@ -265,6 +265,8 @@
     #[test]
     fn for_type() { run_and_expect_no_errors("test_data/parser/inline/ok/for_type.rs"); }
     #[test]
+    fn frontmatter() { run_and_expect_no_errors("test_data/parser/inline/ok/frontmatter.rs"); }
+    #[test]
     fn full_range_expr() {
         run_and_expect_no_errors("test_data/parser/inline/ok/full_range_expr.rs");
     }
@@ -749,6 +751,10 @@
     #[test]
     fn bad_asm_expr() { run_and_expect_errors("test_data/parser/inline/err/bad_asm_expr.rs"); }
     #[test]
+    fn closure_ret_recovery() {
+        run_and_expect_errors("test_data/parser/inline/err/closure_ret_recovery.rs");
+    }
+    #[test]
     fn comma_after_default_values_syntax() {
         run_and_expect_errors("test_data/parser/inline/err/comma_after_default_values_syntax.rs");
     }
@@ -773,6 +779,10 @@
         run_and_expect_errors("test_data/parser/inline/err/fn_pointer_type_missing_fn.rs");
     }
     #[test]
+    fn fn_ret_recovery() {
+        run_and_expect_errors("test_data/parser/inline/err/fn_ret_recovery.rs");
+    }
+    #[test]
     fn gen_fn() {
         run_and_expect_errors_with_edition(
             "test_data/parser/inline/err/gen_fn.rs",
diff --git a/crates/parser/test_data/parser/inline/err/closure_ret_recovery.rast b/crates/parser/test_data/parser/inline/err/closure_ret_recovery.rast
new file mode 100644
index 0000000..f626651
--- /dev/null
+++ b/crates/parser/test_data/parser/inline/err/closure_ret_recovery.rast
@@ -0,0 +1,52 @@
+SOURCE_FILE
+  FN
+    FN_KW "fn"
+    WHITESPACE " "
+    NAME
+      IDENT "foo"
+    PARAM_LIST
+      L_PAREN "("
+      R_PAREN ")"
+    WHITESPACE " "
+    BLOCK_EXPR
+      STMT_LIST
+        L_CURLY "{"
+        WHITESPACE " "
+        CLOSURE_EXPR
+          PARAM_LIST
+            PIPE "|"
+            PIPE "|"
+          WHITESPACE " "
+          RET_TYPE
+            THIN_ARROW "->"
+            WHITESPACE " "
+            PATH_TYPE
+              PATH
+                PATH_SEGMENT
+                  NAME_REF
+                    IDENT "A"
+          ERROR
+            R_ANGLE ">"
+          WHITESPACE " "
+          BLOCK_EXPR
+            STMT_LIST
+              L_CURLY "{"
+              WHITESPACE " "
+              LET_STMT
+                LET_KW "let"
+                WHITESPACE " "
+                IDENT_PAT
+                  NAME
+                    IDENT "x"
+                WHITESPACE " "
+                EQ "="
+                WHITESPACE " "
+                LITERAL
+                  INT_NUMBER "1"
+                SEMICOLON ";"
+              WHITESPACE " "
+              R_CURLY "}"
+        WHITESPACE " "
+        R_CURLY "}"
+  WHITESPACE "\n"
+error 18: expected a curly brace
diff --git a/crates/parser/test_data/parser/inline/err/closure_ret_recovery.rs b/crates/parser/test_data/parser/inline/err/closure_ret_recovery.rs
new file mode 100644
index 0000000..7a758ec
--- /dev/null
+++ b/crates/parser/test_data/parser/inline/err/closure_ret_recovery.rs
@@ -0,0 +1 @@
+fn foo() { || -> A> { let x = 1; } }
diff --git a/crates/parser/test_data/parser/inline/err/fn_ret_recovery.rast b/crates/parser/test_data/parser/inline/err/fn_ret_recovery.rast
new file mode 100644
index 0000000..0323df8
--- /dev/null
+++ b/crates/parser/test_data/parser/inline/err/fn_ret_recovery.rast
@@ -0,0 +1,112 @@
+SOURCE_FILE
+  FN
+    FN_KW "fn"
+    WHITESPACE " "
+    NAME
+      IDENT "foo"
+    PARAM_LIST
+      L_PAREN "("
+      R_PAREN ")"
+    WHITESPACE " "
+    RET_TYPE
+      THIN_ARROW "->"
+      WHITESPACE " "
+      PATH_TYPE
+        PATH
+          PATH_SEGMENT
+            NAME_REF
+              IDENT "A"
+    ERROR
+      R_ANGLE ">"
+    ERROR
+      R_BRACK "]"
+    ERROR
+      R_PAREN ")"
+    WHITESPACE " "
+    BLOCK_EXPR
+      STMT_LIST
+        L_CURLY "{"
+        WHITESPACE " "
+        LET_STMT
+          LET_KW "let"
+          WHITESPACE " "
+          IDENT_PAT
+            NAME
+              IDENT "x"
+          WHITESPACE " "
+          EQ "="
+          WHITESPACE " "
+          LITERAL
+            INT_NUMBER "1"
+          SEMICOLON ";"
+        WHITESPACE " "
+        R_CURLY "}"
+  WHITESPACE "\n"
+  FN
+    FN_KW "fn"
+    WHITESPACE " "
+    NAME
+      IDENT "foo"
+    PARAM_LIST
+      L_PAREN "("
+      R_PAREN ")"
+    WHITESPACE " "
+    RET_TYPE
+      THIN_ARROW "->"
+      WHITESPACE " "
+      PATH_TYPE
+        PATH
+          PATH_SEGMENT
+            NAME_REF
+              IDENT "A"
+    ERROR
+      R_ANGLE ">"
+    ERROR
+      R_BRACK "]"
+    ERROR
+      R_PAREN ")"
+    WHITESPACE " "
+    WHERE_CLAUSE
+      WHERE_KW "where"
+      WHITESPACE " "
+      WHERE_PRED
+        PATH_TYPE
+          PATH
+            PATH_SEGMENT
+              NAME_REF
+                IDENT "T"
+        COLON ":"
+        WHITESPACE " "
+        TYPE_BOUND_LIST
+          TYPE_BOUND
+            PATH_TYPE
+              PATH
+                PATH_SEGMENT
+                  NAME_REF
+                    IDENT "Copy"
+    WHITESPACE " "
+    BLOCK_EXPR
+      STMT_LIST
+        L_CURLY "{"
+        WHITESPACE " "
+        LET_STMT
+          LET_KW "let"
+          WHITESPACE " "
+          IDENT_PAT
+            NAME
+              IDENT "x"
+          WHITESPACE " "
+          EQ "="
+          WHITESPACE " "
+          LITERAL
+            INT_NUMBER "1"
+          SEMICOLON ";"
+        WHITESPACE " "
+        R_CURLY "}"
+  WHITESPACE "\n"
+error 13: expected a curly brace
+error 14: expected a curly brace
+error 15: expected a curly brace
+error 45: expected a curly brace
+error 46: expected a curly brace
+error 47: expected a curly brace
diff --git a/crates/parser/test_data/parser/inline/err/fn_ret_recovery.rs b/crates/parser/test_data/parser/inline/err/fn_ret_recovery.rs
new file mode 100644
index 0000000..73e3d84
--- /dev/null
+++ b/crates/parser/test_data/parser/inline/err/fn_ret_recovery.rs
@@ -0,0 +1,2 @@
+fn foo() -> A>]) { let x = 1; }
+fn foo() -> A>]) where T: Copy { let x = 1; }
diff --git a/crates/parser/test_data/parser/inline/ok/frontmatter.rast b/crates/parser/test_data/parser/inline/ok/frontmatter.rast
new file mode 100644
index 0000000..bad8959
--- /dev/null
+++ b/crates/parser/test_data/parser/inline/ok/frontmatter.rast
@@ -0,0 +1,18 @@
+SOURCE_FILE
+  SHEBANG "#!/usr/bin/env cargo\n"
+  FRONTMATTER "\n---\n[dependencies]\nclap = { version = \"4.2\", features = [\"derive\"] }\n---\n"
+  WHITESPACE "\n"
+  FN
+    FN_KW "fn"
+    WHITESPACE " "
+    NAME
+      IDENT "main"
+    PARAM_LIST
+      L_PAREN "("
+      R_PAREN ")"
+    WHITESPACE " "
+    BLOCK_EXPR
+      STMT_LIST
+        L_CURLY "{"
+        R_CURLY "}"
+  WHITESPACE "\n"
diff --git a/crates/parser/test_data/parser/inline/ok/frontmatter.rs b/crates/parser/test_data/parser/inline/ok/frontmatter.rs
new file mode 100644
index 0000000..1f9f7a7
--- /dev/null
+++ b/crates/parser/test_data/parser/inline/ok/frontmatter.rs
@@ -0,0 +1,8 @@
+#!/usr/bin/env cargo
+
+---
+[dependencies]
+clap = { version = "4.2", features = ["derive"] }
+---
+
+fn main() {}
diff --git a/crates/proc-macro-srv/src/tests/mod.rs b/crates/proc-macro-srv/src/tests/mod.rs
index 08495f5..d4f9976 100644
--- a/crates/proc-macro-srv/src/tests/mod.rs
+++ b/crates/proc-macro-srv/src/tests/mod.rs
@@ -326,7 +326,7 @@
               PUNCH   , [alone] 1
               LITERAL Str hello bridge 1
               PUNCH   , [alone] 1
-              LITERAL Str suffixedsuffix 1
+              LITERAL Err(()) "suffixed"suffix 1
               PUNCH   , [alone] 1
               LITERAL StrRaw(2) raw 1
               PUNCH   , [alone] 1
@@ -372,7 +372,7 @@
               PUNCH   , [alone] 42:Root[0000, 0]@27..28#ROOT2024
               LITERAL Str hello bridge 42:Root[0000, 0]@29..43#ROOT2024
               PUNCH   , [alone] 42:Root[0000, 0]@43..44#ROOT2024
-              LITERAL Str suffixedsuffix 42:Root[0000, 0]@45..61#ROOT2024
+              LITERAL Err(()) "suffixed"suffix 42:Root[0000, 0]@45..61#ROOT2024
               PUNCH   , [alone] 42:Root[0000, 0]@61..62#ROOT2024
               LITERAL StrRaw(2) raw 42:Root[0000, 0]@63..73#ROOT2024
               PUNCH   , [alone] 42:Root[0000, 0]@73..74#ROOT2024
diff --git a/crates/project-model/src/build_dependencies.rs b/crates/project-model/src/build_dependencies.rs
index 3a682d5..fedc694 100644
--- a/crates/project-model/src/build_dependencies.rs
+++ b/crates/project-model/src/build_dependencies.rs
@@ -86,6 +86,7 @@
             config,
             &allowed_features,
             workspace.manifest_path(),
+            workspace.target_directory().as_ref(),
             current_dir,
             sysroot,
             toolchain,
@@ -106,8 +107,9 @@
         let (_guard, cmd) = Self::build_command(
             config,
             &Default::default(),
-            // This is not gonna be used anyways, so just construct a dummy here
+            // These are not gonna be used anyways, so just construct a dummy here
             &ManifestPath::try_from(working_directory.clone()).unwrap(),
+            working_directory.as_ref(),
             working_directory,
             &Sysroot::empty(),
             None,
@@ -430,6 +432,7 @@
         config: &CargoConfig,
         allowed_features: &FxHashSet<String>,
         manifest_path: &ManifestPath,
+        target_dir: &Utf8Path,
         current_dir: &AbsPath,
         sysroot: &Sysroot,
         toolchain: Option<&semver::Version>,
@@ -450,8 +453,9 @@
                 cmd.arg("--manifest-path");
                 cmd.arg(manifest_path);
 
-                if let Some(target_dir) = &config.target_dir {
-                    cmd.arg("--target-dir").arg(target_dir);
+                if let Some(target_dir) = config.target_dir_config.target_dir(Some(target_dir)) {
+                    cmd.arg("--target-dir");
+                    cmd.arg(target_dir.as_ref());
                 }
 
                 if let Some(target) = &config.target {
diff --git a/crates/project-model/src/cargo_workspace.rs b/crates/project-model/src/cargo_workspace.rs
index 76ba01f..7311049 100644
--- a/crates/project-model/src/cargo_workspace.rs
+++ b/crates/project-model/src/cargo_workspace.rs
@@ -1,7 +1,6 @@
 //! See [`CargoWorkspace`].
 
-use std::ops;
-use std::str::from_utf8;
+use std::{borrow::Cow, ops, str::from_utf8};
 
 use anyhow::Context;
 use base_db::Env;
@@ -95,6 +94,29 @@
     }
 }
 
+#[derive(Clone, Debug, Default, PartialEq, Eq)]
+pub enum TargetDirectoryConfig {
+    #[default]
+    None,
+    UseSubdirectory,
+    Directory(Utf8PathBuf),
+}
+
+impl TargetDirectoryConfig {
+    pub fn target_dir<'a>(
+        &'a self,
+        ws_target_dir: Option<&'a Utf8Path>,
+    ) -> Option<Cow<'a, Utf8Path>> {
+        match self {
+            TargetDirectoryConfig::None => None,
+            TargetDirectoryConfig::UseSubdirectory => {
+                Some(Cow::Owned(ws_target_dir?.join("rust-analyzer")))
+            }
+            TargetDirectoryConfig::Directory(dir) => Some(Cow::Borrowed(dir)),
+        }
+    }
+}
+
 #[derive(Default, Clone, Debug, PartialEq, Eq)]
 pub struct CargoConfig {
     /// Whether to pass `--all-targets` to cargo invocations.
@@ -121,7 +143,7 @@
     pub extra_env: FxHashMap<String, Option<String>>,
     pub invocation_strategy: InvocationStrategy,
     /// Optional path to use instead of `target` when building
-    pub target_dir: Option<Utf8PathBuf>,
+    pub target_dir_config: TargetDirectoryConfig,
     /// Gate `#[test]` behind `#[cfg(test)]`
     pub set_test: bool,
     /// Load the project without any dependencies
@@ -715,21 +737,15 @@
         }
     }
 
-    pub(crate) fn no_deps_metadata(&self) -> Option<&cargo_metadata::Metadata> {
-        self.no_deps_result.as_ref().ok()
-    }
-
     /// Executes the metadata-fetching command.
     ///
     /// A successful result may still contain a metadata error if the full fetch failed,
     /// but the fallback `--no-deps` pre-fetch succeeded during command construction.
     pub(crate) fn exec(
         self,
-        target_dir: &Utf8Path,
         locked: bool,
         progress: &dyn Fn(String),
     ) -> anyhow::Result<(cargo_metadata::Metadata, Option<anyhow::Error>)> {
-        _ = target_dir;
         let Self {
             mut command,
             manifest_path: _,
diff --git a/crates/project-model/src/lib.rs b/crates/project-model/src/lib.rs
index e36b904..910bc0a 100644
--- a/crates/project-model/src/lib.rs
+++ b/crates/project-model/src/lib.rs
@@ -62,7 +62,7 @@
     build_dependencies::{ProcMacroDylibPath, WorkspaceBuildScripts},
     cargo_workspace::{
         CargoConfig, CargoFeatures, CargoMetadataConfig, CargoWorkspace, Package, PackageData,
-        PackageDependency, RustLibSource, Target, TargetData, TargetKind,
+        PackageDependency, RustLibSource, Target, TargetData, TargetDirectoryConfig, TargetKind,
     },
     manifest_path::ManifestPath,
     project_json::{ProjectJson, ProjectJsonData},
diff --git a/crates/project-model/src/sysroot.rs b/crates/project-model/src/sysroot.rs
index 5cc399b..920afe6 100644
--- a/crates/project-model/src/sysroot.rs
+++ b/crates/project-model/src/sysroot.rs
@@ -9,7 +9,7 @@
 
 use anyhow::{Result, format_err};
 use itertools::Itertools;
-use paths::{AbsPath, AbsPathBuf, Utf8Path, Utf8PathBuf};
+use paths::{AbsPath, AbsPathBuf, Utf8PathBuf};
 use rustc_hash::FxHashMap;
 use stdx::format_to;
 use toolchain::{Tool, probe_for_binary};
@@ -219,7 +219,6 @@
         &self,
         sysroot_source_config: &RustSourceWorkspaceConfig,
         no_deps: bool,
-        target_dir: &Utf8Path,
         progress: &dyn Fn(String),
     ) -> Option<RustLibSrcWorkspace> {
         assert!(matches!(self.workspace, RustLibSrcWorkspace::Empty), "workspace already loaded");
@@ -233,7 +232,6 @@
                 match self.load_library_via_cargo(
                     &library_manifest,
                     src_root,
-                    target_dir,
                     cargo_config,
                     no_deps,
                     progress,
@@ -328,7 +326,6 @@
         &self,
         library_manifest: &ManifestPath,
         current_dir: &AbsPath,
-        target_dir: &Utf8Path,
         cargo_config: &CargoMetadataConfig,
         no_deps: bool,
         progress: &dyn Fn(String),
@@ -345,7 +342,7 @@
         let locked = true;
         let (mut res, err) =
             FetchMetadata::new(library_manifest, current_dir, &cargo_config, self, no_deps)
-                .exec(target_dir, locked, progress)?;
+                .exec(locked, progress)?;
 
         // Patch out `rustc-std-workspace-*` crates to point to the real crates.
         // This is done prior to `CrateGraph` construction to prevent de-duplication logic from failing.
diff --git a/crates/project-model/src/tests.rs b/crates/project-model/src/tests.rs
index 711cdd1..1908fc0 100644
--- a/crates/project-model/src/tests.rs
+++ b/crates/project-model/src/tests.rs
@@ -238,12 +238,8 @@
     );
     let cwd = AbsPathBuf::assert_utf8(temp_dir().join("smoke_test_real_sysroot_cargo"));
     std::fs::create_dir_all(&cwd).unwrap();
-    let loaded_sysroot = sysroot.load_workspace(
-        &RustSourceWorkspaceConfig::default_cargo(),
-        false,
-        &Utf8PathBuf::default(),
-        &|_| (),
-    );
+    let loaded_sysroot =
+        sysroot.load_workspace(&RustSourceWorkspaceConfig::default_cargo(), false, &|_| ());
     if let Some(loaded_sysroot) = loaded_sysroot {
         sysroot.set_workspace(loaded_sysroot);
     }
diff --git a/crates/project-model/src/workspace.rs b/crates/project-model/src/workspace.rs
index b88db41..aa2e159 100644
--- a/crates/project-model/src/workspace.rs
+++ b/crates/project-model/src/workspace.rs
@@ -16,7 +16,7 @@
 use rustc_hash::{FxHashMap, FxHashSet};
 use semver::Version;
 use span::{Edition, FileId};
-use toolchain::{NO_RUSTUP_AUTO_INSTALL_ENV, Tool};
+use toolchain::Tool;
 use tracing::instrument;
 use tracing::{debug, error, info};
 use triomphe::Arc;
@@ -295,11 +295,6 @@
             &sysroot,
             *no_deps,
         );
-        let target_dir = config
-            .target_dir
-            .clone()
-            .or_else(|| fetch_metadata.no_deps_metadata().map(|m| m.target_directory.clone()))
-            .unwrap_or_else(|| workspace_dir.join("target").into());
 
         // We spawn a bunch of processes to query various information about the workspace's
         // toolchain and sysroot
@@ -345,7 +340,7 @@
                         },
                         &sysroot,
                         *no_deps,
-                    ).exec(&target_dir, true, progress) {
+                    ).exec(true, progress) {
                         Ok((meta, _error)) => {
                             let workspace = CargoWorkspace::new(
                                 meta,
@@ -374,16 +369,16 @@
                 })
             });
 
-            let cargo_metadata = s.spawn(|| fetch_metadata.exec(&target_dir, false, progress));
+            let cargo_metadata = s.spawn(|| fetch_metadata.exec(false, progress));
             let loaded_sysroot = s.spawn(|| {
                 sysroot.load_workspace(
                     &RustSourceWorkspaceConfig::CargoMetadata(sysroot_metadata_config(
                         config,
+                        workspace_dir,
                         &targets,
                         toolchain.clone(),
                     )),
                     config.no_deps,
-                    &target_dir,
                     progress,
                 )
             });
@@ -463,12 +458,6 @@
         let targets = target_tuple::get(query_config, config.target.as_deref(), &config.extra_env)
             .unwrap_or_default();
         let toolchain = version::get(query_config, &config.extra_env).ok().flatten();
-        let project_root = project_json.project_root();
-        let target_dir = config
-            .target_dir
-            .clone()
-            .or_else(|| cargo_target_dir(project_json.manifest()?, &config.extra_env, &sysroot))
-            .unwrap_or_else(|| project_root.join("target").into());
 
         // We spawn a bunch of processes to query various information about the workspace's
         // toolchain and sysroot
@@ -486,18 +475,17 @@
                     sysroot.load_workspace(
                         &RustSourceWorkspaceConfig::Json(*sysroot_project),
                         config.no_deps,
-                        &target_dir,
                         progress,
                     )
                 } else {
                     sysroot.load_workspace(
                         &RustSourceWorkspaceConfig::CargoMetadata(sysroot_metadata_config(
                             config,
+                            project_json.project_root(),
                             &targets,
                             toolchain.clone(),
                         )),
                         config.no_deps,
-                        &target_dir,
                         progress,
                     )
                 }
@@ -545,20 +533,15 @@
             .unwrap_or_default();
         let rustc_cfg = rustc_cfg::get(query_config, None, &config.extra_env);
         let target_data = target_data::get(query_config, None, &config.extra_env);
-        let target_dir = config
-            .target_dir
-            .clone()
-            .or_else(|| cargo_target_dir(detached_file, &config.extra_env, &sysroot))
-            .unwrap_or_else(|| dir.join("target").into());
 
         let loaded_sysroot = sysroot.load_workspace(
             &RustSourceWorkspaceConfig::CargoMetadata(sysroot_metadata_config(
                 config,
+                dir,
                 &targets,
                 toolchain.clone(),
             )),
             config.no_deps,
-            &target_dir,
             &|_| (),
         );
         if let Some(loaded_sysroot) = loaded_sysroot {
@@ -579,21 +562,15 @@
             &sysroot,
             config.no_deps,
         );
-        let target_dir = config
-            .target_dir
-            .clone()
-            .or_else(|| fetch_metadata.no_deps_metadata().map(|m| m.target_directory.clone()))
-            .unwrap_or_else(|| dir.join("target").into());
-        let cargo_script =
-            fetch_metadata.exec(&target_dir, false, &|_| ()).ok().map(|(ws, error)| {
-                let cargo_config_extra_env =
-                    cargo_config_env(detached_file, &config_file, &config.extra_env);
-                (
-                    CargoWorkspace::new(ws, detached_file.clone(), cargo_config_extra_env, false),
-                    WorkspaceBuildScripts::default(),
-                    error.map(Arc::new),
-                )
-            });
+        let cargo_script = fetch_metadata.exec(false, &|_| ()).ok().map(|(ws, error)| {
+            let cargo_config_extra_env =
+                cargo_config_env(detached_file, &config_file, &config.extra_env);
+            (
+                CargoWorkspace::new(ws, detached_file.clone(), cargo_config_extra_env, false),
+                WorkspaceBuildScripts::default(),
+                error.map(Arc::new),
+            )
+        });
 
         Ok(ProjectWorkspace {
             kind: ProjectWorkspaceKind::DetachedFile {
@@ -1890,37 +1867,32 @@
 
 fn sysroot_metadata_config(
     config: &CargoConfig,
+    current_dir: &AbsPath,
     targets: &[String],
     toolchain_version: Option<Version>,
 ) -> CargoMetadataConfig {
+    // We run `cargo metadata` on sysroot with sysroot dir as a working directory, but still pass
+    // the `targets` from the cargo config evaluated from the workspace's `current_dir`.
+    // So, we need to *canonicalize* those *might-be-relative-paths-to-custom-target-json-files*.
+    //
+    // See https://github.com/rust-lang/cargo/blob/f7acf448fc127df9a77c52cc2bba027790ac4931/src/cargo/core/compiler/compile_kind.rs#L171-L192
+    let targets = targets
+        .iter()
+        .map(|target| {
+            if target.ends_with(".json") {
+                current_dir.join(target).to_string()
+            } else {
+                target.to_owned()
+            }
+        })
+        .collect();
+
     CargoMetadataConfig {
         features: Default::default(),
-        targets: targets.to_vec(),
+        targets,
         extra_args: Default::default(),
         extra_env: config.extra_env.clone(),
         toolchain_version,
         kind: "sysroot",
     }
 }
-
-fn cargo_target_dir(
-    manifest: &ManifestPath,
-    extra_env: &FxHashMap<String, Option<String>>,
-    sysroot: &Sysroot,
-) -> Option<Utf8PathBuf> {
-    let cargo = sysroot.tool(Tool::Cargo, manifest.parent(), extra_env);
-    let mut meta = cargo_metadata::MetadataCommand::new();
-    meta.env(NO_RUSTUP_AUTO_INSTALL_ENV.0, NO_RUSTUP_AUTO_INSTALL_ENV.1);
-    meta.cargo_path(cargo.get_program());
-    meta.manifest_path(manifest);
-    // `--no-deps` doesn't (over)write lockfiles as it doesn't do any package resolve.
-    // So we can use it to get `target_directory` before copying lockfiles
-    meta.no_deps();
-    let mut other_options = vec![];
-    if manifest.is_rust_manifest() {
-        meta.env("RUSTC_BOOTSTRAP", "1");
-        other_options.push("-Zscript".to_owned());
-    }
-    meta.other_options(other_options);
-    meta.exec().map(|m| m.target_directory).ok()
-}
diff --git a/crates/rust-analyzer/Cargo.toml b/crates/rust-analyzer/Cargo.toml
index c746f84..b9dfe1f 100644
--- a/crates/rust-analyzer/Cargo.toml
+++ b/crates/rust-analyzer/Cargo.toml
@@ -42,6 +42,7 @@
 num_cpus = "1.17.0"
 mimalloc = { version = "0.1.46", default-features = false, optional = true }
 lsp-server.workspace = true
+smallvec.workspace = true
 tracing.workspace = true
 tracing-subscriber.workspace = true
 tracing-tree.workspace = true
@@ -53,6 +54,7 @@
 memchr = "2.7.5"
 cargo_metadata.workspace = true
 process-wrap.workspace = true
+dhat = { version = "0.3.3", optional = true }
 
 cfg.workspace = true
 hir-def.workspace = true
@@ -105,6 +107,7 @@
   "hir-ty/in-rust-tree",
   "load-cargo/in-rust-tree",
 ]
+dhat = ["dep:dhat"]
 
 [lints]
 workspace = true
diff --git a/crates/rust-analyzer/src/cli/analysis_stats.rs b/crates/rust-analyzer/src/cli/analysis_stats.rs
index de24bc0..5e4a277 100644
--- a/crates/rust-analyzer/src/cli/analysis_stats.rs
+++ b/crates/rust-analyzer/src/cli/analysis_stats.rs
@@ -1214,6 +1214,7 @@
             annotate_method_references: false,
             annotate_enum_variant_references: false,
             location: ide::AnnotationLocation::AboveName,
+            filter_adjacent_derive_implementations: false,
             minicore: MiniCore::default(),
         };
         for &file_id in file_ids {
diff --git a/crates/rust-analyzer/src/cli/rustc_tests.rs b/crates/rust-analyzer/src/cli/rustc_tests.rs
index 2056714..eb28a47 100644
--- a/crates/rust-analyzer/src/cli/rustc_tests.rs
+++ b/crates/rust-analyzer/src/cli/rustc_tests.rs
@@ -9,7 +9,6 @@
 use ide::{AnalysisHost, DiagnosticCode, DiagnosticsConfig};
 use ide_db::base_db;
 use itertools::Either;
-use paths::Utf8PathBuf;
 use profile::StopWatch;
 use project_model::toolchain_info::{QueryConfig, target_data};
 use project_model::{
@@ -75,12 +74,8 @@
         };
 
         let mut sysroot = Sysroot::discover(tmp_file.parent().unwrap(), &cargo_config.extra_env);
-        let loaded_sysroot = sysroot.load_workspace(
-            &RustSourceWorkspaceConfig::default_cargo(),
-            false,
-            &Utf8PathBuf::default(),
-            &|_| (),
-        );
+        let loaded_sysroot =
+            sysroot.load_workspace(&RustSourceWorkspaceConfig::default_cargo(), false, &|_| ());
         if let Some(loaded_sysroot) = loaded_sysroot {
             sysroot.set_workspace(loaded_sysroot);
         }
diff --git a/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs
index 652c2e3..b8c4b9f 100644
--- a/crates/rust-analyzer/src/config.rs
+++ b/crates/rust-analyzer/src/config.rs
@@ -10,9 +10,9 @@
 use ide::{
     AnnotationConfig, AssistConfig, CallHierarchyConfig, CallableSnippets, CompletionConfig,
     CompletionFieldsToResolve, DiagnosticsConfig, GenericParameterHints, GotoDefinitionConfig,
-    HighlightConfig, HighlightRelatedConfig, HoverConfig, HoverDocFormat, InlayFieldsToResolve,
-    InlayHintsConfig, JoinLinesConfig, MemoryLayoutHoverConfig, MemoryLayoutHoverRenderKind,
-    Snippet, SnippetScope, SourceRootId,
+    GotoImplementationConfig, HighlightConfig, HighlightRelatedConfig, HoverConfig, HoverDocFormat,
+    InlayFieldsToResolve, InlayHintsConfig, JoinLinesConfig, MemoryLayoutHoverConfig,
+    MemoryLayoutHoverRenderKind, RenameConfig, Snippet, SnippetScope, SourceRootId,
 };
 use ide_db::{
     MiniCore, SnippetCap,
@@ -23,7 +23,7 @@
 use paths::{Utf8Path, Utf8PathBuf};
 use project_model::{
     CargoConfig, CargoFeatures, ProjectJson, ProjectJsonData, ProjectJsonFromCommand,
-    ProjectManifest, RustLibSource,
+    ProjectManifest, RustLibSource, TargetDirectoryConfig,
 };
 use rustc_hash::{FxHashMap, FxHashSet};
 use semver::Version;
@@ -98,6 +98,9 @@
         /// Code's `files.watcherExclude`.
         files_exclude | files_excludeDirs: Vec<Utf8PathBuf> = vec![],
 
+        /// If this is `true`, when "Goto Implementations" and in "Implementations" lens, are triggered on a `struct` or `enum` or `union`, we filter out trait implementations that originate from `derive`s above the type.
+        gotoImplementations_filterAdjacentDerives: bool = false,
+
         /// Highlight related return values while the cursor is on any `match`, `if`, or match arm
         /// arrow (`=>`).
         highlightRelated_branchExitPoints_enable: bool = true,
@@ -378,6 +381,12 @@
         /// Internal config, path to proc-macro server executable.
         procMacro_server: Option<Utf8PathBuf> = None,
 
+        /// The path where to save memory profiling output.
+        ///
+        /// **Note:** Memory profiling is not enabled by default in rust-analyzer builds, you need to build
+        /// from source for it.
+        profiling_memoryProfile: Option<Utf8PathBuf> = None,
+
         /// Exclude imports from find-all-references.
         references_excludeImports: bool = false,
 
@@ -1413,6 +1422,7 @@
 
     // annotations
     pub location: AnnotationLocation,
+    pub filter_adjacent_derive_implementations: bool,
 }
 
 #[derive(Copy, Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
@@ -1469,6 +1479,7 @@
             annotate_enum_variant_references: self.enum_variant_refs,
             location: self.location.into(),
             minicore,
+            filter_adjacent_derive_implementations: self.filter_adjacent_derive_implementations,
         }
     }
 }
@@ -1705,6 +1716,14 @@
         }
     }
 
+    pub fn rename(&self, source_root: Option<SourceRootId>) -> RenameConfig {
+        RenameConfig {
+            prefer_no_std: self.imports_preferNoStd(source_root).to_owned(),
+            prefer_prelude: self.imports_preferPrelude(source_root).to_owned(),
+            prefer_absolute: self.imports_prefixExternPrelude(source_root).to_owned(),
+        }
+    }
+
     pub fn call_hierarchy<'a>(&self, minicore: MiniCore<'a>) -> CallHierarchyConfig<'a> {
         CallHierarchyConfig { exclude_tests: self.references_excludeTests().to_owned(), minicore }
     }
@@ -2157,6 +2176,11 @@
         Some(AbsPathBuf::try_from(path).unwrap_or_else(|path| self.root_path.join(path)))
     }
 
+    pub fn dhat_output_file(&self) -> Option<AbsPathBuf> {
+        let path = self.profiling_memoryProfile().clone()?;
+        Some(AbsPathBuf::try_from(path).unwrap_or_else(|path| self.root_path.join(path)))
+    }
+
     pub fn ignored_proc_macros(
         &self,
         source_root: Option<SourceRootId>,
@@ -2277,7 +2301,7 @@
             run_build_script_command: self.cargo_buildScripts_overrideCommand(source_root).clone(),
             extra_args: self.cargo_extraArgs(source_root).clone(),
             extra_env: self.cargo_extraEnv(source_root).clone(),
-            target_dir: self.target_dir_from_config(source_root),
+            target_dir_config: self.target_dir_from_config(source_root),
             set_test: *self.cfg_setTest(source_root),
             no_deps: *self.cargo_noDeps(source_root),
         }
@@ -2365,7 +2389,7 @@
             extra_args: self.extra_args(source_root).clone(),
             extra_test_bin_args: self.runnables_extraTestBinaryArgs(source_root).clone(),
             extra_env: self.extra_env(source_root).clone(),
-            target_dir: self.target_dir_from_config(source_root),
+            target_dir_config: self.target_dir_from_config(source_root),
             set_test: true,
         }
     }
@@ -2423,7 +2447,7 @@
                     extra_args: self.check_extra_args(source_root),
                     extra_test_bin_args: self.runnables_extraTestBinaryArgs(source_root).clone(),
                     extra_env: self.check_extra_env(source_root),
-                    target_dir: self.target_dir_from_config(source_root),
+                    target_dir_config: self.target_dir_from_config(source_root),
                     set_test: *self.cfg_setTest(source_root),
                 },
                 ansi_color_output: self.color_diagnostic_output(),
@@ -2431,17 +2455,12 @@
         }
     }
 
-    fn target_dir_from_config(&self, source_root: Option<SourceRootId>) -> Option<Utf8PathBuf> {
-        self.cargo_targetDir(source_root).as_ref().and_then(|target_dir| match target_dir {
-            TargetDirectory::UseSubdirectory(true) => {
-                let env_var = env::var("CARGO_TARGET_DIR").ok();
-                let mut path = Utf8PathBuf::from(env_var.as_deref().unwrap_or("target"));
-                path.push("rust-analyzer");
-                Some(path)
-            }
-            TargetDirectory::UseSubdirectory(false) => None,
-            TargetDirectory::Directory(dir) => Some(dir.clone()),
-        })
+    fn target_dir_from_config(&self, source_root: Option<SourceRootId>) -> TargetDirectoryConfig {
+        match &self.cargo_targetDir(source_root) {
+            Some(TargetDirectory::UseSubdirectory(true)) => TargetDirectoryConfig::UseSubdirectory,
+            Some(TargetDirectory::UseSubdirectory(false)) | None => TargetDirectoryConfig::None,
+            Some(TargetDirectory::Directory(dir)) => TargetDirectoryConfig::Directory(dir.clone()),
+        }
     }
 
     pub fn check_on_save(&self, source_root: Option<SourceRootId>) -> bool {
@@ -2495,6 +2514,15 @@
             refs_trait: *self.lens_enable() && *self.lens_references_trait_enable(),
             enum_variant_refs: *self.lens_enable() && *self.lens_references_enumVariant_enable(),
             location: *self.lens_location(),
+            filter_adjacent_derive_implementations: *self
+                .gotoImplementations_filterAdjacentDerives(),
+        }
+    }
+
+    pub fn goto_implementation(&self) -> GotoImplementationConfig {
+        GotoImplementationConfig {
+            filter_adjacent_derive_implementations: *self
+                .gotoImplementations_filterAdjacentDerives(),
         }
     }
 
@@ -3958,7 +3986,7 @@
 
 #[cfg(test)]
 mod tests {
-    use std::fs;
+    use std::{borrow::Cow, fs};
 
     use test_utils::{ensure_file_contents, project_root};
 
@@ -4093,9 +4121,13 @@
 
         (config, _, _) = config.apply_change(change);
         assert_eq!(config.cargo_targetDir(None), &None);
-        assert!(
-            matches!(config.flycheck(None), FlycheckConfig::CargoCommand { options, .. } if options.target_dir.is_none())
-        );
+        assert!(matches!(
+            config.flycheck(None),
+            FlycheckConfig::CargoCommand {
+                options: CargoOptions { target_dir_config: TargetDirectoryConfig::None, .. },
+                ..
+            }
+        ));
     }
 
     #[test]
@@ -4111,11 +4143,16 @@
         (config, _, _) = config.apply_change(change);
 
         assert_eq!(config.cargo_targetDir(None), &Some(TargetDirectory::UseSubdirectory(true)));
-        let target =
+        let ws_target_dir =
             Utf8PathBuf::from(std::env::var("CARGO_TARGET_DIR").unwrap_or("target".to_owned()));
-        assert!(
-            matches!(config.flycheck(None), FlycheckConfig::CargoCommand { options, .. } if options.target_dir == Some(target.join("rust-analyzer")))
-        );
+        assert!(matches!(
+            config.flycheck(None),
+            FlycheckConfig::CargoCommand {
+                options: CargoOptions { target_dir_config, .. },
+                ..
+            } if target_dir_config.target_dir(Some(&ws_target_dir)).map(Cow::into_owned)
+                == Some(ws_target_dir.join("rust-analyzer"))
+        ));
     }
 
     #[test]
@@ -4134,8 +4171,13 @@
             config.cargo_targetDir(None),
             &Some(TargetDirectory::Directory(Utf8PathBuf::from("other_folder")))
         );
-        assert!(
-            matches!(config.flycheck(None), FlycheckConfig::CargoCommand { options, .. } if options.target_dir == Some(Utf8PathBuf::from("other_folder")))
-        );
+        assert!(matches!(
+            config.flycheck(None),
+            FlycheckConfig::CargoCommand {
+                options: CargoOptions { target_dir_config, .. },
+                ..
+            } if target_dir_config.target_dir(None).map(Cow::into_owned)
+                == Some(Utf8PathBuf::from("other_folder"))
+        ));
     }
 }
diff --git a/crates/rust-analyzer/src/diagnostics.rs b/crates/rust-analyzer/src/diagnostics.rs
index 4bfad98..4a24780 100644
--- a/crates/rust-analyzer/src/diagnostics.rs
+++ b/crates/rust-analyzer/src/diagnostics.rs
@@ -1,5 +1,5 @@
 //! Book keeping for keeping diagnostics easily in sync with the client.
-pub(crate) mod to_proto;
+pub(crate) mod flycheck_to_proto;
 
 use std::mem;
 
@@ -8,6 +8,7 @@
 use ide_db::{FxHashMap, base_db::DbPanicContext};
 use itertools::Itertools;
 use rustc_hash::FxHashSet;
+use smallvec::SmallVec;
 use stdx::iter_eq_by;
 use triomphe::Arc;
 
@@ -57,7 +58,7 @@
 #[derive(Debug, Clone)]
 pub(crate) struct Fix {
     // Fixes may be triggerable from multiple ranges.
-    pub(crate) ranges: Vec<lsp_types::Range>,
+    pub(crate) ranges: SmallVec<[lsp_types::Range; 1]>,
     pub(crate) action: lsp_ext::CodeAction,
 }
 
diff --git a/crates/rust-analyzer/src/diagnostics/to_proto.rs b/crates/rust-analyzer/src/diagnostics/flycheck_to_proto.rs
similarity index 88%
rename from crates/rust-analyzer/src/diagnostics/to_proto.rs
rename to crates/rust-analyzer/src/diagnostics/flycheck_to_proto.rs
index 3f64628..a6d7bcb 100644
--- a/crates/rust-analyzer/src/diagnostics/to_proto.rs
+++ b/crates/rust-analyzer/src/diagnostics/flycheck_to_proto.rs
@@ -4,6 +4,7 @@
 use crate::flycheck::{Applicability, DiagnosticLevel, DiagnosticSpan};
 use itertools::Itertools;
 use rustc_hash::FxHashMap;
+use smallvec::SmallVec;
 use stdx::format_to;
 use vfs::{AbsPath, AbsPathBuf};
 
@@ -18,12 +19,12 @@
 fn diagnostic_severity(
     config: &DiagnosticsMapConfig,
     level: crate::flycheck::DiagnosticLevel,
-    code: Option<crate::flycheck::DiagnosticCode>,
+    code: Option<&crate::flycheck::DiagnosticCode>,
 ) -> Option<lsp_types::DiagnosticSeverity> {
     let res = match level {
         DiagnosticLevel::Ice => lsp_types::DiagnosticSeverity::ERROR,
         DiagnosticLevel::Error => lsp_types::DiagnosticSeverity::ERROR,
-        DiagnosticLevel::Warning => match &code {
+        DiagnosticLevel::Warning => match code {
             // HACK: special case for `warnings` rustc lint.
             Some(code)
                 if config.warnings_as_hint.iter().any(|lint| {
@@ -143,11 +144,11 @@
 fn diagnostic_related_information(
     config: &DiagnosticsMapConfig,
     workspace_root: &AbsPath,
-    span: &DiagnosticSpan,
+    span: DiagnosticSpan,
     snap: &GlobalStateSnapshot,
 ) -> Option<lsp_types::DiagnosticRelatedInformation> {
-    let message = span.label.clone()?;
-    let location = location(config, workspace_root, span, snap);
+    let location = location(config, workspace_root, &span, snap);
+    let message = span.label?;
     Some(lsp_types::DiagnosticRelatedInformation { location, message })
 }
 
@@ -184,7 +185,7 @@
     rd: &crate::flycheck::Diagnostic,
     snap: &GlobalStateSnapshot,
 ) -> MappedRustChildDiagnostic {
-    let spans: Vec<&DiagnosticSpan> = rd.spans.iter().filter(|s| s.is_primary).collect();
+    let spans: SmallVec<[&DiagnosticSpan; 1]> = rd.spans.iter().filter(|s| s.is_primary).collect();
     if spans.is_empty() {
         // `rustc` uses these spanless children as a way to print multi-line
         // messages
@@ -227,42 +228,37 @@
         message.push_str(&suggestions);
     }
 
-    if edit_map.is_empty() {
-        MappedRustChildDiagnostic::SubDiagnostic(SubDiagnostic {
-            related: lsp_types::DiagnosticRelatedInformation {
-                location: location(config, workspace_root, spans[0], snap),
-                message,
-            },
-            suggested_fix: None,
-        })
+    let suggested_fix = if edit_map.is_empty() {
+        None
     } else {
-        MappedRustChildDiagnostic::SubDiagnostic(SubDiagnostic {
-            related: lsp_types::DiagnosticRelatedInformation {
-                location: location(config, workspace_root, spans[0], snap),
-                message: message.clone(),
+        Some(Box::new(Fix {
+            ranges: spans
+                .iter()
+                .map(|&span| location(config, workspace_root, span, snap).range)
+                .collect(),
+            action: lsp_ext::CodeAction {
+                title: message.clone(),
+                group: None,
+                kind: Some(lsp_types::CodeActionKind::QUICKFIX),
+                edit: Some(lsp_ext::SnippetWorkspaceEdit {
+                    // FIXME: there's no good reason to use edit_map here....
+                    changes: Some(edit_map),
+                    document_changes: None,
+                    change_annotations: None,
+                }),
+                is_preferred: Some(is_preferred),
+                data: None,
+                command: None,
             },
-            suggested_fix: Some(Box::new(Fix {
-                ranges: spans
-                    .iter()
-                    .map(|&span| location(config, workspace_root, span, snap).range)
-                    .collect(),
-                action: lsp_ext::CodeAction {
-                    title: message,
-                    group: None,
-                    kind: Some(lsp_types::CodeActionKind::QUICKFIX),
-                    edit: Some(lsp_ext::SnippetWorkspaceEdit {
-                        // FIXME: there's no good reason to use edit_map here....
-                        changes: Some(edit_map),
-                        document_changes: None,
-                        change_annotations: None,
-                    }),
-                    is_preferred: Some(is_preferred),
-                    data: None,
-                    command: None,
-                },
-            })),
-        })
-    }
+        }))
+    };
+    MappedRustChildDiagnostic::SubDiagnostic(SubDiagnostic {
+        related: lsp_types::DiagnosticRelatedInformation {
+            location: location(config, workspace_root, spans[0], snap),
+            message,
+        },
+        suggested_fix,
+    })
 }
 
 #[derive(Debug)]
@@ -284,48 +280,56 @@
 /// If the diagnostic has no primary span this will return `None`
 pub(crate) fn map_rust_diagnostic_to_lsp(
     config: &DiagnosticsMapConfig,
-    rd: &crate::flycheck::Diagnostic,
+    crate::flycheck::Diagnostic {
+        mut message,
+        code: diagnostic_code,
+        level,
+        spans,
+        children,
+        rendered,
+        ..
+    }: crate::flycheck::Diagnostic,
     workspace_root: &AbsPath,
     snap: &GlobalStateSnapshot,
 ) -> Vec<MappedRustDiagnostic> {
-    let primary_spans: Vec<&DiagnosticSpan> = rd.spans.iter().filter(|s| s.is_primary).collect();
+    let (primary_spans, secondary_spans): (
+        SmallVec<[DiagnosticSpan; 1]>,
+        SmallVec<[DiagnosticSpan; 1]>,
+    ) = spans.into_iter().partition(|s| s.is_primary);
     if primary_spans.is_empty() {
         return Vec::new();
     }
 
-    let severity = diagnostic_severity(config, rd.level, rd.code.clone());
+    let mut code = diagnostic_code.as_ref().map(|c| &*c.code);
 
-    let mut source = String::from("rustc");
-    let mut code = rd.code.as_ref().map(|c| c.code.clone());
-
-    if let Some(code_val) = &code
+    if let Some(code_val) = code
         && config.check_ignore.contains(code_val)
     {
         return Vec::new();
     }
 
-    if let Some(code_val) = &code {
+    let severity = diagnostic_severity(config, level, diagnostic_code.as_ref());
+
+    let mut source = "rustc";
+    if let Some(code_val) = code {
         // See if this is an RFC #2103 scoped lint (e.g. from Clippy)
-        let scoped_code: Vec<&str> = code_val.split("::").collect();
-        if scoped_code.len() == 2 {
-            source = String::from(scoped_code[0]);
-            code = Some(String::from(scoped_code[1]));
+        if let Some((s, c)) = code_val.split("::").collect_tuple() {
+            source = s;
+            code = Some(c);
         }
     }
 
     let mut needs_primary_span_label = true;
     let mut subdiagnostics = Vec::new();
-    let mut tags = Vec::new();
 
-    for secondary_span in rd.spans.iter().filter(|s| !s.is_primary) {
+    for secondary_span in secondary_spans {
         let related = diagnostic_related_information(config, workspace_root, secondary_span, snap);
         if let Some(related) = related {
             subdiagnostics.push(SubDiagnostic { related, suggested_fix: None });
         }
     }
 
-    let mut message = rd.message.clone();
-    for child in &rd.children {
+    for child in &children {
         let child = map_rust_child_diagnostic(config, workspace_root, child, snap);
         match child {
             MappedRustChildDiagnostic::SubDiagnostic(sub) => {
@@ -340,155 +344,146 @@
             }
         }
     }
+    let message = message;
 
-    if let Some(code) = &rd.code {
-        let code = code.code.as_str();
-        if matches!(
-            code,
-            "dead_code"
-                | "unknown_lints"
-                | "unreachable_code"
-                | "unused_attributes"
-                | "unused_imports"
-                | "unused_macros"
-                | "unused_variables"
-        ) {
-            tags.push(lsp_types::DiagnosticTag::UNNECESSARY);
-        }
-
-        if matches!(code, "deprecated") {
-            tags.push(lsp_types::DiagnosticTag::DEPRECATED);
+    let mut tag = None;
+    if let Some(code) = &diagnostic_code {
+        match &*code.code {
+            "dead_code" | "unknown_lints" | "unreachable_code" | "unused_attributes"
+            | "unused_imports" | "unused_macros" | "unused_variables" => {
+                tag = Some(lsp_types::DiagnosticTag::UNNECESSARY);
+            }
+            "deprecated" => {
+                tag = Some(lsp_types::DiagnosticTag::DEPRECATED);
+            }
+            _ => {}
         }
     }
 
-    let code_description = match source.as_str() {
-        "rustc" => rustc_code_description(code.as_deref()),
-        "clippy" => clippy_code_description(code.as_deref()),
+    let code_description = match source {
+        "rustc" => rustc_code_description(code),
+        "clippy" => clippy_code_description(code),
         _ => None,
     };
+    // Each primary diagnostic span may result in multiple LSP diagnostics.
+    let mut diagnostics = Vec::new();
 
-    primary_spans
-        .iter()
-        .flat_map(|primary_span| {
-            let primary_location = primary_location(config, workspace_root, primary_span, snap);
-            let message = {
-                let mut message = message.clone();
-                if needs_primary_span_label && let Some(primary_span_label) = &primary_span.label {
-                    format_to!(message, "\n{}", primary_span_label);
-                }
-                message
-            };
-            // Each primary diagnostic span may result in multiple LSP diagnostics.
-            let mut diagnostics = Vec::new();
+    for primary_span in primary_spans {
+        let primary_location = primary_location(config, workspace_root, &primary_span, snap);
+        let message = {
+            let mut message = message.clone();
+            if needs_primary_span_label && let Some(primary_span_label) = &primary_span.label {
+                format_to!(message, "\n{}", primary_span_label);
+            }
+            message
+        };
 
-            let mut related_info_macro_calls = vec![];
+        let mut related_info_macro_calls = vec![];
 
-            // If error occurs from macro expansion, add related info pointing to
-            // where the error originated
-            // Also, we would generate an additional diagnostic, so that exact place of macro
-            // will be highlighted in the error origin place.
-            let span_stack = std::iter::successors(Some(*primary_span), |span| {
-                Some(&span.expansion.as_ref()?.span)
-            });
-            for (i, span) in span_stack.enumerate() {
-                if is_dummy_macro_file(&span.file_name) {
-                    continue;
-                }
-
-                // First span is the original diagnostic, others are macro call locations that
-                // generated that code.
-                let is_in_macro_call = i != 0;
-
-                let secondary_location = location(config, workspace_root, span, snap);
-                if secondary_location == primary_location {
-                    continue;
-                }
-                related_info_macro_calls.push(lsp_types::DiagnosticRelatedInformation {
-                    location: secondary_location.clone(),
-                    message: if is_in_macro_call {
-                        "Error originated from macro call here".to_owned()
-                    } else {
-                        "Actual error occurred here".to_owned()
-                    },
-                });
-                // For the additional in-macro diagnostic we add the inverse message pointing to the error location in code.
-                let information_for_additional_diagnostic =
-                    vec![lsp_types::DiagnosticRelatedInformation {
-                        location: primary_location.clone(),
-                        message: "Exact error occurred here".to_owned(),
-                    }];
-
-                let diagnostic = lsp_types::Diagnostic {
-                    range: secondary_location.range,
-                    // downgrade to hint if we're pointing at the macro
-                    severity: Some(lsp_types::DiagnosticSeverity::HINT),
-                    code: code.clone().map(lsp_types::NumberOrString::String),
-                    code_description: code_description.clone(),
-                    source: Some(source.clone()),
-                    message: message.clone(),
-                    related_information: Some(information_for_additional_diagnostic),
-                    tags: if tags.is_empty() { None } else { Some(tags.clone()) },
-                    data: Some(serde_json::json!({ "rendered": rd.rendered })),
-                };
-                diagnostics.push(MappedRustDiagnostic {
-                    url: secondary_location.uri,
-                    diagnostic,
-                    fix: None,
-                });
+        // If error occurs from macro expansion, add related info pointing to
+        // where the error originated
+        // Also, we would generate an additional diagnostic, so that exact place of macro
+        // will be highlighted in the error origin place.
+        let span_stack =
+            std::iter::successors(Some(&primary_span), |span| Some(&span.expansion.as_ref()?.span))
+                .skip(1);
+        for (i, span) in span_stack.enumerate() {
+            if is_dummy_macro_file(&span.file_name) {
+                continue;
+            }
+            let secondary_location = location(config, workspace_root, span, snap);
+            if secondary_location == primary_location {
+                continue;
             }
 
-            // Emit the primary diagnostic.
-            diagnostics.push(MappedRustDiagnostic {
-                url: primary_location.uri.clone(),
-                diagnostic: lsp_types::Diagnostic {
-                    range: primary_location.range,
-                    severity,
-                    code: code.clone().map(lsp_types::NumberOrString::String),
-                    code_description: code_description.clone(),
-                    source: Some(source.clone()),
-                    message,
-                    related_information: {
-                        let info = related_info_macro_calls
-                            .iter()
-                            .cloned()
-                            .chain(subdiagnostics.iter().map(|sub| sub.related.clone()))
-                            .collect::<Vec<_>>();
-                        if info.is_empty() { None } else { Some(info) }
-                    },
-                    tags: if tags.is_empty() { None } else { Some(tags.clone()) },
-                    data: Some(serde_json::json!({ "rendered": rd.rendered })),
+            // First span is the original diagnostic, others are macro call locations that
+            // generated that code.
+            let is_in_macro_call = i != 0;
+
+            related_info_macro_calls.push(lsp_types::DiagnosticRelatedInformation {
+                location: secondary_location.clone(),
+                message: if is_in_macro_call {
+                    "Error originated from macro call here".to_owned()
+                } else {
+                    "Actual error occurred here".to_owned()
                 },
+            });
+            // For the additional in-macro diagnostic we add the inverse message pointing to the error location in code.
+            let information_for_additional_diagnostic =
+                vec![lsp_types::DiagnosticRelatedInformation {
+                    location: primary_location.clone(),
+                    message: "Exact error occurred here".to_owned(),
+                }];
+
+            let diagnostic = lsp_types::Diagnostic {
+                range: secondary_location.range,
+                // downgrade to hint if we're pointing at the macro
+                severity: Some(lsp_types::DiagnosticSeverity::HINT),
+                code: code.map(ToOwned::to_owned).map(lsp_types::NumberOrString::String),
+                code_description: code_description.clone(),
+                source: Some(source.to_owned()),
+                message: message.clone(),
+                related_information: Some(information_for_additional_diagnostic),
+                tags: tag.clone().map(|tag| vec![tag]),
+                data: Some(serde_json::json!({ "rendered": rendered })),
+            };
+            diagnostics.push(MappedRustDiagnostic {
+                url: secondary_location.uri,
+                diagnostic,
                 fix: None,
             });
+        }
 
-            // Emit hint-level diagnostics for all `related_information` entries such as "help"s.
-            // This is useful because they will show up in the user's editor, unlike
-            // `related_information`, which just produces hard-to-read links, at least in VS Code.
-            let back_ref = lsp_types::DiagnosticRelatedInformation {
-                location: primary_location,
-                message: "original diagnostic".to_owned(),
-            };
-            for sub in &subdiagnostics {
-                diagnostics.push(MappedRustDiagnostic {
-                    url: sub.related.location.uri.clone(),
-                    fix: sub.suggested_fix.clone(),
-                    diagnostic: lsp_types::Diagnostic {
-                        range: sub.related.location.range,
-                        severity: Some(lsp_types::DiagnosticSeverity::HINT),
-                        code: code.clone().map(lsp_types::NumberOrString::String),
-                        code_description: code_description.clone(),
-                        source: Some(source.clone()),
-                        message: sub.related.message.clone(),
-                        related_information: Some(vec![back_ref.clone()]),
-                        tags: None, // don't apply modifiers again
-                        data: None,
-                    },
-                });
-            }
+        // Emit the primary diagnostic.
+        diagnostics.push(MappedRustDiagnostic {
+            url: primary_location.uri.clone(),
+            diagnostic: lsp_types::Diagnostic {
+                range: primary_location.range,
+                severity,
+                code: code.map(ToOwned::to_owned).map(lsp_types::NumberOrString::String),
+                code_description: code_description.clone(),
+                source: Some(source.to_owned()),
+                message,
+                related_information: {
+                    let info = related_info_macro_calls
+                        .iter()
+                        .cloned()
+                        .chain(subdiagnostics.iter().map(|sub| sub.related.clone()))
+                        .collect::<Vec<_>>();
+                    if info.is_empty() { None } else { Some(info) }
+                },
+                tags: tag.clone().map(|tag| vec![tag]),
+                data: Some(serde_json::json!({ "rendered": rendered })),
+            },
+            fix: None,
+        });
 
-            diagnostics
-        })
-        .collect()
+        // Emit hint-level diagnostics for all `related_information` entries such as "help"s.
+        // This is useful because they will show up in the user's editor, unlike
+        // `related_information`, which just produces hard-to-read links, at least in VS Code.
+        let back_ref = lsp_types::DiagnosticRelatedInformation {
+            location: primary_location,
+            message: "original diagnostic".to_owned(),
+        };
+        for sub in &subdiagnostics {
+            diagnostics.push(MappedRustDiagnostic {
+                url: sub.related.location.uri.clone(),
+                fix: sub.suggested_fix.clone(),
+                diagnostic: lsp_types::Diagnostic {
+                    range: sub.related.location.range,
+                    severity: Some(lsp_types::DiagnosticSeverity::HINT),
+                    code: code.map(ToOwned::to_owned).map(lsp_types::NumberOrString::String),
+                    code_description: code_description.clone(),
+                    source: Some(source.to_owned()),
+                    message: sub.related.message.clone(),
+                    related_information: Some(vec![back_ref.clone()]),
+                    tags: None, // don't apply modifiers again
+                    data: None,
+                },
+            });
+        }
+    }
+    diagnostics
 }
 
 fn rustc_code_description(code: Option<&str>) -> Option<lsp_types::CodeDescription> {
@@ -545,7 +540,7 @@
             ),
         );
         let snap = state.snapshot();
-        let mut actual = map_rust_diagnostic_to_lsp(&config, &diagnostic, workspace_root, &snap);
+        let mut actual = map_rust_diagnostic_to_lsp(&config, diagnostic, workspace_root, &snap);
         actual.iter_mut().for_each(|diag| diag.diagnostic.data = None);
         expect.assert_debug_eq(&actual)
     }
diff --git a/crates/rust-analyzer/src/diagnostics/test_data/macro_compiler_error.txt b/crates/rust-analyzer/src/diagnostics/test_data/macro_compiler_error.txt
index fe5cf9b..b44569b 100644
--- a/crates/rust-analyzer/src/diagnostics/test_data/macro_compiler_error.txt
+++ b/crates/rust-analyzer/src/diagnostics/test_data/macro_compiler_error.txt
@@ -191,7 +191,7 @@
                                 },
                             },
                         },
-                        message: "Error originated from macro call here",
+                        message: "Actual error occurred here",
                     },
                     DiagnosticRelatedInformation {
                         location: Location {
diff --git a/crates/rust-analyzer/src/flycheck.rs b/crates/rust-analyzer/src/flycheck.rs
index 73a51bb..68337dd 100644
--- a/crates/rust-analyzer/src/flycheck.rs
+++ b/crates/rust-analyzer/src/flycheck.rs
@@ -13,6 +13,7 @@
 use ide_db::FxHashSet;
 use itertools::Itertools;
 use paths::{AbsPath, AbsPathBuf, Utf8Path, Utf8PathBuf};
+use project_model::TargetDirectoryConfig;
 use rustc_hash::FxHashMap;
 use serde::Deserialize as _;
 use serde_derive::Deserialize;
@@ -46,7 +47,7 @@
     pub(crate) extra_args: Vec<String>,
     pub(crate) extra_test_bin_args: Vec<String>,
     pub(crate) extra_env: FxHashMap<String, Option<String>>,
-    pub(crate) target_dir: Option<Utf8PathBuf>,
+    pub(crate) target_dir_config: TargetDirectoryConfig,
 }
 
 #[derive(Clone, Debug)]
@@ -58,7 +59,7 @@
 }
 
 impl CargoOptions {
-    pub(crate) fn apply_on_command(&self, cmd: &mut Command) {
+    pub(crate) fn apply_on_command(&self, cmd: &mut Command, ws_target_dir: Option<&Utf8Path>) {
         for target in &self.target_tuples {
             cmd.args(["--target", target.as_str()]);
         }
@@ -82,8 +83,8 @@
                 cmd.arg(self.features.join(" "));
             }
         }
-        if let Some(target_dir) = &self.target_dir {
-            cmd.arg("--target-dir").arg(target_dir);
+        if let Some(target_dir) = self.target_dir_config.target_dir(ws_target_dir) {
+            cmd.arg("--target-dir").arg(target_dir.as_ref());
         }
     }
 }
@@ -158,6 +159,7 @@
         sysroot_root: Option<AbsPathBuf>,
         workspace_root: AbsPathBuf,
         manifest_path: Option<AbsPathBuf>,
+        ws_target_dir: Option<Utf8PathBuf>,
     ) -> FlycheckHandle {
         let actor = FlycheckActor::new(
             id,
@@ -167,6 +169,7 @@
             sysroot_root,
             workspace_root,
             manifest_path,
+            ws_target_dir,
         );
         let (sender, receiver) = unbounded::<StateChange>();
         let thread =
@@ -314,6 +317,7 @@
     sender: Sender<FlycheckMessage>,
     config: FlycheckConfig,
     manifest_path: Option<AbsPathBuf>,
+    ws_target_dir: Option<Utf8PathBuf>,
     /// Either the workspace root of the workspace we are flychecking,
     /// or the project root of the project.
     root: Arc<AbsPathBuf>,
@@ -355,6 +359,7 @@
         sysroot_root: Option<AbsPathBuf>,
         workspace_root: AbsPathBuf,
         manifest_path: Option<AbsPathBuf>,
+        ws_target_dir: Option<Utf8PathBuf>,
     ) -> FlycheckActor {
         tracing::info!(%id, ?workspace_root, "Spawning flycheck");
         FlycheckActor {
@@ -366,6 +371,7 @@
             root: Arc::new(workspace_root),
             scope: FlycheckScope::Workspace,
             manifest_path,
+            ws_target_dir,
             command_handle: None,
             command_receiver: None,
             diagnostics_cleared_for: Default::default(),
@@ -428,15 +434,32 @@
                         CargoCheckParser,
                         sender,
                         match &self.config {
-                            FlycheckConfig::CargoCommand { options, .. } => Some(
-                                options
-                                    .target_dir
-                                    .as_deref()
-                                    .unwrap_or(
-                                        Utf8Path::new("target").join("rust-analyzer").as_path(),
-                                    )
-                                    .join(format!("flycheck{}", self.id)),
-                            ),
+                            FlycheckConfig::CargoCommand { options, .. } => {
+                                let ws_target_dir =
+                                    self.ws_target_dir.as_ref().map(Utf8PathBuf::as_path);
+                                let target_dir =
+                                    options.target_dir_config.target_dir(ws_target_dir);
+
+                                // If `"rust-analyzer.cargo.targetDir": null`, we should use
+                                // workspace's target dir instead of hard-coded fallback.
+                                let target_dir = target_dir.as_deref().or(ws_target_dir);
+
+                                Some(
+                                    // As `CommandHandle::spawn`'s working directory is
+                                    // rust-analyzer's working directory, which might be different
+                                    // from the flycheck's working directory, we should canonicalize
+                                    // the output directory, otherwise we might write it into the
+                                    // wrong target dir.
+                                    // If `target_dir` is an absolute path, it will replace
+                                    // `self.root` and that's an intended behavior.
+                                    self.root
+                                        .join(target_dir.unwrap_or(
+                                            Utf8Path::new("target").join("rust-analyzer").as_path(),
+                                        ))
+                                        .join(format!("flycheck{}", self.id))
+                                        .into(),
+                                )
+                            }
                             _ => None,
                         },
                     ) {
@@ -672,7 +695,10 @@
 
                 cmd.arg("--keep-going");
 
-                options.apply_on_command(&mut cmd);
+                options.apply_on_command(
+                    &mut cmd,
+                    self.ws_target_dir.as_ref().map(Utf8PathBuf::as_path),
+                );
                 cmd.args(&options.extra_args);
                 Some(cmd)
             }
diff --git a/crates/rust-analyzer/src/handlers/request.rs b/crates/rust-analyzer/src/handlers/request.rs
index 55d092f..7e52673 100644
--- a/crates/rust-analyzer/src/handlers/request.rs
+++ b/crates/rust-analyzer/src/handlers/request.rs
@@ -33,7 +33,9 @@
 use vfs::{AbsPath, AbsPathBuf, FileId, VfsPath};
 
 use crate::{
-    config::{Config, RustfmtConfig, WorkspaceSymbolConfig},
+    config::{
+        ClientCommandsConfig, Config, HoverActionsConfig, RustfmtConfig, WorkspaceSymbolConfig,
+    },
     diagnostics::convert_diagnostic,
     global_state::{FetchWorkspaceRequest, GlobalState, GlobalStateSnapshot},
     line_index::LineEndings,
@@ -124,17 +126,35 @@
     Ok(buf)
 }
 
-pub(crate) fn handle_memory_usage(state: &mut GlobalState, _: ()) -> anyhow::Result<String> {
+pub(crate) fn handle_memory_usage(_state: &mut GlobalState, _: ()) -> anyhow::Result<String> {
     let _p = tracing::info_span!("handle_memory_usage").entered();
-    let mem = state.analysis_host.per_query_memory_usage();
 
-    let mut out = String::new();
-    for (name, bytes, entries) in mem {
-        format_to!(out, "{:>8} {:>6} {}\n", bytes, entries, name);
+    #[cfg(not(feature = "dhat"))]
+    {
+        Err(anyhow::anyhow!(
+            "Memory profiling is not enabled for this build of rust-analyzer.\n\n\
+            To build rust-analyzer with profiling support, pass `--features dhat --profile dev-rel` to `cargo build`
+            when building from source, or pass `--enable-profiling` to `cargo xtask`."
+        ))
     }
-    format_to!(out, "{:>8}        Remaining\n", profile::memory_usage().allocated);
-
-    Ok(out)
+    #[cfg(feature = "dhat")]
+    {
+        if let Some(dhat_output_file) = _state.config.dhat_output_file() {
+            let mut profiler = crate::DHAT_PROFILER.lock().unwrap();
+            let old_profiler = profiler.take();
+            // Need to drop the old profiler before creating a new one.
+            drop(old_profiler);
+            *profiler = Some(dhat::Profiler::builder().file_name(&dhat_output_file).build());
+            Ok(format!(
+                "Memory profile was saved successfully to {dhat_output_file}.\n\n\
+                See https://docs.rs/dhat/latest/dhat/#viewing for how to inspect the profile."
+            ))
+        } else {
+            Err(anyhow::anyhow!(
+                "Please set `rust-analyzer.profiling.memoryProfile` to the path where you want to save the profile."
+            ))
+        }
+    }
 }
 
 pub(crate) fn handle_view_syntax_tree(
@@ -264,6 +284,7 @@
                     path,
                     state.config.cargo_test_options(None),
                     cargo.workspace_root(),
+                    Some(cargo.target_directory().as_ref()),
                     target,
                     state.test_run_sender.clone(),
                 )?;
@@ -847,10 +868,11 @@
     let _p = tracing::info_span!("handle_goto_implementation").entered();
     let position =
         try_default!(from_proto::file_position(&snap, params.text_document_position_params)?);
-    let nav_info = match snap.analysis.goto_implementation(position)? {
-        None => return Ok(None),
-        Some(it) => it,
-    };
+    let nav_info =
+        match snap.analysis.goto_implementation(&snap.config.goto_implementation(), position)? {
+            None => return Ok(None),
+            Some(it) => it,
+        };
     let src = FileRange { file_id: position.file_id, range: nav_info.range };
     let res = to_proto::goto_definition_response(&snap, Some(src), nav_info.info)?;
     Ok(Some(res))
@@ -1325,8 +1347,12 @@
     let _p = tracing::info_span!("handle_rename").entered();
     let position = try_default!(from_proto::file_position(&snap, params.text_document_position)?);
 
-    let mut change =
-        snap.analysis.rename(position, &params.new_name)?.map_err(to_proto::rename_error)?;
+    let source_root = snap.analysis.source_root_id(position.file_id).ok();
+    let config = snap.config.rename(source_root);
+    let mut change = snap
+        .analysis
+        .rename(position, &params.new_name, &config)?
+        .map_err(to_proto::rename_error)?;
 
     // this is kind of a hack to prevent double edits from happening when moving files
     // When a module gets renamed by renaming the mod declaration this causes the file to move
@@ -1459,13 +1485,14 @@
         resolve,
         frange,
     )?;
+    let client_commands = snap.config.client_commands();
     for (index, assist) in assists.into_iter().enumerate() {
         let resolve_data = if code_action_resolve_cap {
             Some((index, params.clone(), snap.file_version(file_id)))
         } else {
             None
         };
-        let code_action = to_proto::code_action(&snap, assist, resolve_data)?;
+        let code_action = to_proto::code_action(&snap, &client_commands, assist, resolve_data)?;
 
         // Check if the client supports the necessary `ResourceOperation`s.
         let changes = code_action.edit.as_ref().and_then(|it| it.document_changes.as_ref());
@@ -1566,7 +1593,7 @@
         ))
         .into());
     }
-    let ca = to_proto::code_action(&snap, assist.clone(), None)?;
+    let ca = to_proto::code_action(&snap, &snap.config.client_commands(), assist.clone(), None)?;
     code_action.edit = ca.edit;
     code_action.command = ca.command;
 
@@ -2130,10 +2157,15 @@
 fn show_impl_command_link(
     snap: &GlobalStateSnapshot,
     position: &FilePosition,
+    implementations: bool,
+    show_references: bool,
 ) -> Option<lsp_ext::CommandLinkGroup> {
-    if snap.config.hover_actions().implementations
-        && snap.config.client_commands().show_reference
-        && let Some(nav_data) = snap.analysis.goto_implementation(*position).unwrap_or(None)
+    if implementations
+        && show_references
+        && let Some(nav_data) = snap
+            .analysis
+            .goto_implementation(&snap.config.goto_implementation(), *position)
+            .unwrap_or(None)
     {
         let uri = to_proto::url(snap, position.file_id);
         let line_index = snap.file_line_index(position.file_id).ok()?;
@@ -2157,9 +2189,11 @@
 fn show_ref_command_link(
     snap: &GlobalStateSnapshot,
     position: &FilePosition,
+    references: bool,
+    show_reference: bool,
 ) -> Option<lsp_ext::CommandLinkGroup> {
-    if snap.config.hover_actions().references
-        && snap.config.client_commands().show_reference
+    if references
+        && show_reference
         && let Some(ref_search_res) = snap
             .analysis
             .find_all_refs(
@@ -2194,8 +2228,9 @@
 fn runnable_action_links(
     snap: &GlobalStateSnapshot,
     runnable: Runnable,
+    hover_actions_config: &HoverActionsConfig,
+    client_commands_config: &ClientCommandsConfig,
 ) -> Option<lsp_ext::CommandLinkGroup> {
-    let hover_actions_config = snap.config.hover_actions();
     if !hover_actions_config.runnable() {
         return None;
     }
@@ -2205,7 +2240,6 @@
         return None;
     }
 
-    let client_commands_config = snap.config.client_commands();
     if !(client_commands_config.run_single || client_commands_config.debug_single) {
         return None;
     }
@@ -2240,11 +2274,10 @@
 fn goto_type_action_links(
     snap: &GlobalStateSnapshot,
     nav_targets: &[HoverGotoTypeData],
+    hover_actions: &HoverActionsConfig,
+    client_commands: &ClientCommandsConfig,
 ) -> Option<lsp_ext::CommandLinkGroup> {
-    if !snap.config.hover_actions().goto_type_def
-        || nav_targets.is_empty()
-        || !snap.config.client_commands().goto_location
-    {
+    if !hover_actions.goto_type_def || nav_targets.is_empty() || !client_commands.goto_location {
         return None;
     }
 
@@ -2264,13 +2297,29 @@
     snap: &GlobalStateSnapshot,
     actions: &[HoverAction],
 ) -> Vec<lsp_ext::CommandLinkGroup> {
+    let hover_actions = snap.config.hover_actions();
+    let client_commands = snap.config.client_commands();
     actions
         .iter()
         .filter_map(|it| match it {
-            HoverAction::Implementation(position) => show_impl_command_link(snap, position),
-            HoverAction::Reference(position) => show_ref_command_link(snap, position),
-            HoverAction::Runnable(r) => runnable_action_links(snap, r.clone()),
-            HoverAction::GoToType(targets) => goto_type_action_links(snap, targets),
+            HoverAction::Implementation(position) => show_impl_command_link(
+                snap,
+                position,
+                hover_actions.implementations,
+                client_commands.show_reference,
+            ),
+            HoverAction::Reference(position) => show_ref_command_link(
+                snap,
+                position,
+                hover_actions.references,
+                client_commands.show_reference,
+            ),
+            HoverAction::Runnable(r) => {
+                runnable_action_links(snap, r.clone(), &hover_actions, &client_commands)
+            }
+            HoverAction::GoToType(targets) => {
+                goto_type_action_links(snap, targets, &hover_actions, &client_commands)
+            }
         })
         .collect()
 }
diff --git a/crates/rust-analyzer/src/lib.rs b/crates/rust-analyzer/src/lib.rs
index 44af8fb..6ae527a 100644
--- a/crates/rust-analyzer/src/lib.rs
+++ b/crates/rust-analyzer/src/lib.rs
@@ -82,3 +82,10 @@
     };
 }
 pub(crate) use try_default_ as try_default;
+
+#[cfg(feature = "dhat")]
+#[global_allocator]
+static ALLOC: dhat::Alloc = dhat::Alloc;
+
+#[cfg(feature = "dhat")]
+static DHAT_PROFILER: std::sync::Mutex<Option<dhat::Profiler>> = std::sync::Mutex::new(None);
diff --git a/crates/rust-analyzer/src/lsp/to_proto.rs b/crates/rust-analyzer/src/lsp/to_proto.rs
index 024c13e..995e6c4 100644
--- a/crates/rust-analyzer/src/lsp/to_proto.rs
+++ b/crates/rust-analyzer/src/lsp/to_proto.rs
@@ -26,7 +26,7 @@
 use vfs::AbsPath;
 
 use crate::{
-    config::{CallInfoConfig, Config},
+    config::{CallInfoConfig, ClientCommandsConfig, Config},
     global_state::GlobalStateSnapshot,
     line_index::{LineEndings, LineIndex, PositionEncoding},
     lsp::{
@@ -258,10 +258,12 @@
 
     let max_relevance = items.iter().map(|it| it.relevance.score()).max().unwrap_or_default();
     let mut res = Vec::with_capacity(items.len());
+    let client_commands = config.client_commands();
     for item in items {
         completion_item(
             &mut res,
             config,
+            &client_commands,
             fields_to_resolve,
             line_index,
             version,
@@ -283,6 +285,7 @@
 fn completion_item(
     acc: &mut Vec<lsp_types::CompletionItem>,
     config: &Config,
+    client_commands: &ClientCommandsConfig,
     fields_to_resolve: &CompletionFieldsToResolve,
     line_index: &LineIndex,
     version: Option<i32>,
@@ -342,7 +345,7 @@
     } else {
         item.deprecated.then(|| vec![lsp_types::CompletionItemTag::DEPRECATED])
     };
-    let command = if item.trigger_call_info && config.client_commands().trigger_parameter_hints {
+    let command = if item.trigger_call_info && client_commands.trigger_parameter_hints {
         if fields_to_resolve.resolve_command {
             something_to_resolve |= true;
             None
@@ -1500,6 +1503,7 @@
 
 pub(crate) fn code_action(
     snap: &GlobalStateSnapshot,
+    commands: &ClientCommandsConfig,
     assist: Assist,
     resolve_data: Option<(usize, lsp_types::CodeActionParams, Option<i32>)>,
 ) -> Cancellable<lsp_ext::CodeAction> {
@@ -1513,7 +1517,6 @@
         command: None,
     };
 
-    let commands = snap.config.client_commands();
     res.command = match assist.command {
         Some(assists::Command::TriggerParameterHints) if commands.trigger_parameter_hints => {
             Some(command::trigger_parameter_hints())
diff --git a/crates/rust-analyzer/src/main_loop.rs b/crates/rust-analyzer/src/main_loop.rs
index c0947b2..c2b887c 100644
--- a/crates/rust-analyzer/src/main_loop.rs
+++ b/crates/rust-analyzer/src/main_loop.rs
@@ -60,6 +60,14 @@
         SetThreadPriority(thread, thread_priority_above_normal);
     }
 
+    #[cfg(feature = "dhat")]
+    {
+        if let Some(dhat_output_file) = config.dhat_output_file() {
+            *crate::DHAT_PROFILER.lock().unwrap() =
+                Some(dhat::Profiler::builder().file_name(&dhat_output_file).build());
+        }
+    }
+
     GlobalState::new(connection.sender, config).run(connection.receiver)
 }
 
@@ -1023,9 +1031,9 @@
                 package_id,
             } => {
                 let snap = self.snapshot();
-                let diagnostics = crate::diagnostics::to_proto::map_rust_diagnostic_to_lsp(
+                let diagnostics = crate::diagnostics::flycheck_to_proto::map_rust_diagnostic_to_lsp(
                     &self.config.diagnostics_map(None),
-                    &diagnostic,
+                    diagnostic,
                     &workspace_root,
                     &snap,
                 );
diff --git a/crates/rust-analyzer/src/reload.rs b/crates/rust-analyzer/src/reload.rs
index 1475f02..bb971eb 100644
--- a/crates/rust-analyzer/src/reload.rs
+++ b/crates/rust-analyzer/src/reload.rs
@@ -23,6 +23,7 @@
 use itertools::Itertools;
 use load_cargo::{ProjectFolders, load_proc_macro};
 use lsp_types::FileSystemWatcher;
+use paths::Utf8Path;
 use proc_macro_api::ProcMacroClient;
 use project_model::{ManifestPath, ProjectWorkspace, ProjectWorkspaceKind, WorkspaceBuildScripts};
 use stdx::{format_to, thread::ThreadIntent};
@@ -876,6 +877,7 @@
                     None,
                     self.config.root_path().clone(),
                     None,
+                    None,
                 )]
             }
             crate::flycheck::InvocationStrategy::PerWorkspace => {
@@ -890,13 +892,17 @@
                                 | ProjectWorkspaceKind::DetachedFile {
                                     cargo: Some((cargo, _, _)),
                                     ..
-                                } => (cargo.workspace_root(), Some(cargo.manifest_path())),
+                                } => (
+                                    cargo.workspace_root(),
+                                    Some(cargo.manifest_path()),
+                                    Some(cargo.target_directory()),
+                                ),
                                 ProjectWorkspaceKind::Json(project) => {
                                     // Enable flychecks for json projects if a custom flycheck command was supplied
                                     // in the workspace configuration.
                                     match config {
                                         FlycheckConfig::CustomCommand { .. } => {
-                                            (project.path(), None)
+                                            (project.path(), None, None)
                                         }
                                         _ => return None,
                                     }
@@ -906,7 +912,7 @@
                             ws.sysroot.root().map(ToOwned::to_owned),
                         ))
                     })
-                    .map(|(id, (root, manifest_path), sysroot_root)| {
+                    .map(|(id, (root, manifest_path, target_dir), sysroot_root)| {
                         FlycheckHandle::spawn(
                             id,
                             next_gen,
@@ -915,6 +921,7 @@
                             sysroot_root,
                             root.to_path_buf(),
                             manifest_path.map(|it| it.to_path_buf()),
+                            target_dir.map(|it| AsRef::<Utf8Path>::as_ref(it).to_path_buf()),
                         )
                     })
                     .collect()
diff --git a/crates/rust-analyzer/src/test_runner.rs b/crates/rust-analyzer/src/test_runner.rs
index 0c8658c..9a65e70 100644
--- a/crates/rust-analyzer/src/test_runner.rs
+++ b/crates/rust-analyzer/src/test_runner.rs
@@ -2,7 +2,7 @@
 //! thread and report the result of each test in a channel.
 
 use crossbeam_channel::Sender;
-use paths::AbsPath;
+use paths::{AbsPath, Utf8Path};
 use project_model::TargetKind;
 use serde::Deserialize as _;
 use serde_derive::Deserialize;
@@ -98,6 +98,7 @@
         path: Option<&str>,
         options: CargoOptions,
         root: &AbsPath,
+        ws_target_dir: Option<&Utf8Path>,
         test_target: TestTarget,
         sender: Sender<CargoTestMessage>,
     ) -> std::io::Result<Self> {
@@ -123,7 +124,7 @@
         cmd.arg("--no-fail-fast");
         cmd.arg("--manifest-path");
         cmd.arg(root.join("Cargo.toml"));
-        options.apply_on_command(&mut cmd);
+        options.apply_on_command(&mut cmd, ws_target_dir);
         cmd.arg("--");
         if let Some(path) = path {
             cmd.arg(path);
diff --git a/crates/syntax/src/ast/make.rs b/crates/syntax/src/ast/make.rs
index 051c583..dba3920 100644
--- a/crates/syntax/src/ast/make.rs
+++ b/crates/syntax/src/ast/make.rs
@@ -1355,7 +1355,7 @@
 
     pub(super) static SOURCE_FILE: LazyLock<Parse<SourceFile>> = LazyLock::new(|| {
         SourceFile::parse(
-            "use crate::foo; const C: <()>::Item = ( true && true , true || true , 1 != 1, 2 == 2, 3 < 3, 4 <= 4, 5 > 5, 6 >= 6, !true, *p, &p , &mut p, async { let _ @ [] })\n;\n\nunsafe impl A for B where: {}",
+            "use crate::foo; const C: <()>::Item = ( true && true , true || true , 1 != 1, 2 == 2, 3 < 3, 4 <= 4, 5 > 5, 6 >= 6, !true, *p, &p , &mut p, async { let _ @ [] }, while loop {} {})\n;\n\nunsafe impl A for B where: {}",
             Edition::CURRENT,
         )
     });
diff --git a/crates/syntax/src/ast/syntax_factory/constructors.rs b/crates/syntax/src/ast/syntax_factory/constructors.rs
index 8bf27f9..9695523 100644
--- a/crates/syntax/src/ast/syntax_factory/constructors.rs
+++ b/crates/syntax/src/ast/syntax_factory/constructors.rs
@@ -644,6 +644,20 @@
         ast
     }
 
+    pub fn expr_loop(&self, body: ast::BlockExpr) -> ast::LoopExpr {
+        let ast::Expr::LoopExpr(ast) = make::expr_loop(body.clone()).clone_for_update() else {
+            unreachable!()
+        };
+
+        if let Some(mut mapping) = self.mappings() {
+            let mut builder = SyntaxMappingBuilder::new(ast.syntax().clone());
+            builder.map_node(body.syntax().clone(), ast.loop_body().unwrap().syntax().clone());
+            builder.finish(&mut mapping);
+        }
+
+        ast
+    }
+
     pub fn expr_while_loop(&self, condition: ast::Expr, body: ast::BlockExpr) -> ast::WhileExpr {
         let ast = make::expr_while_loop(condition.clone(), body.clone()).clone_for_update();
 
diff --git a/crates/tt/src/lib.rs b/crates/tt/src/lib.rs
index 243a27b..f9a547f 100644
--- a/crates/tt/src/lib.rs
+++ b/crates/tt/src/lib.rs
@@ -622,6 +622,15 @@
     let lit = &lit[start_offset..lit.len() - end_offset];
     let suffix = match suffix {
         "" | "_" => None,
+        // ill-suffixed literals
+        _ if !matches!(kind, LitKind::Integer | LitKind::Float | LitKind::Err(_)) => {
+            return Literal {
+                span,
+                symbol: Symbol::intern(text),
+                kind: LitKind::Err(()),
+                suffix: None,
+            };
+        }
         suffix => Some(Symbol::intern(suffix)),
     };
 
diff --git a/docs/book/src/configuration_generated.md b/docs/book/src/configuration_generated.md
index d768993..21e199c 100644
--- a/docs/book/src/configuration_generated.md
+++ b/docs/book/src/configuration_generated.md
@@ -635,6 +635,13 @@
 Controls file watching implementation.
 
 
+## rust-analyzer.gotoImplementations.filterAdjacentDerives {#gotoImplementations.filterAdjacentDerives}
+
+Default: `false`
+
+If this is `true`, when "Goto Implementations" and in "Implementations" lens, are triggered on a `struct` or `enum` or `union`, we filter out trait implementations that originate from `derive`s above the type.
+
+
 ## rust-analyzer.highlightRelated.branchExitPoints.enable {#highlightRelated.branchExitPoints.enable}
 
 Default: `true`
@@ -1289,6 +1296,16 @@
 Internal config, path to proc-macro server executable.
 
 
+## rust-analyzer.profiling.memoryProfile {#profiling.memoryProfile}
+
+Default: `null`
+
+The path where to save memory profiling output.
+
+**Note:** Memory profiling is not enabled by default in rust-analyzer builds, you need to build
+from source for it.
+
+
 ## rust-analyzer.references.excludeImports {#references.excludeImports}
 
 Default: `false`
diff --git a/docs/book/src/non_cargo_based_projects.md b/docs/book/src/non_cargo_based_projects.md
index befb631..74489a9 100644
--- a/docs/book/src/non_cargo_based_projects.md
+++ b/docs/book/src/non_cargo_based_projects.md
@@ -31,7 +31,7 @@
     /// It should point to the directory where std,
     /// core, and friends can be found:
     ///
-    /// https://github.com/rust-lang/rust/tree/master/library.
+    /// https://github.com/rust-lang/rust/tree/HEAD/library.
     ///
     /// If provided, rust-analyzer automatically adds
     /// dependencies on sysroot crates. Conversely,
diff --git a/editors/code/package.json b/editors/code/package.json
index d659421..7db4986 100644
--- a/editors/code/package.json
+++ b/editors/code/package.json
@@ -1628,6 +1628,16 @@
                 }
             },
             {
+                "title": "Goto Implementations",
+                "properties": {
+                    "rust-analyzer.gotoImplementations.filterAdjacentDerives": {
+                        "markdownDescription": "If this is `true`, when \"Goto Implementations\" and in \"Implementations\" lens, are triggered on a `struct` or `enum` or `union`, we filter out trait implementations that originate from `derive`s above the type.",
+                        "default": false,
+                        "type": "boolean"
+                    }
+                }
+            },
+            {
                 "title": "Highlight Related",
                 "properties": {
                     "rust-analyzer.highlightRelated.branchExitPoints.enable": {
@@ -2750,6 +2760,19 @@
                 }
             },
             {
+                "title": "Profiling",
+                "properties": {
+                    "rust-analyzer.profiling.memoryProfile": {
+                        "markdownDescription": "The path where to save memory profiling output.\n\n**Note:** Memory profiling is not enabled by default in rust-analyzer builds, you need to build\nfrom source for it.",
+                        "default": null,
+                        "type": [
+                            "null",
+                            "string"
+                        ]
+                    }
+                }
+            },
+            {
                 "title": "References",
                 "properties": {
                     "rust-analyzer.references.excludeImports": {
diff --git a/editors/code/src/commands.ts b/editors/code/src/commands.ts
index 25b3001..16fc586 100644
--- a/editors/code/src/commands.ts
+++ b/editors/code/src/commands.ts
@@ -71,32 +71,9 @@
 }
 
 export function memoryUsage(ctx: CtxInit): Cmd {
-    const tdcp = new (class implements vscode.TextDocumentContentProvider {
-        readonly uri = vscode.Uri.parse("rust-analyzer-memory://memory");
-        readonly eventEmitter = new vscode.EventEmitter<vscode.Uri>();
-
-        provideTextDocumentContent(_uri: vscode.Uri): vscode.ProviderResult<string> {
-            if (!vscode.window.activeTextEditor) return "";
-
-            // eslint-disable-next-line @typescript-eslint/no-explicit-any
-            return ctx.client.sendRequest(ra.memoryUsage).then((mem: any) => {
-                return "Per-query memory usage:\n" + mem + "\n(note: database has been cleared)";
-            });
-        }
-
-        get onDidChange(): vscode.Event<vscode.Uri> {
-            return this.eventEmitter.event;
-        }
-    })();
-
-    ctx.pushExtCleanup(
-        vscode.workspace.registerTextDocumentContentProvider("rust-analyzer-memory", tdcp),
-    );
-
     return async () => {
-        tdcp.eventEmitter.fire(tdcp.uri);
-        const document = await vscode.workspace.openTextDocument(tdcp.uri);
-        return vscode.window.showTextDocument(document, vscode.ViewColumn.Two, true);
+        const response = await ctx.client.sendRequest(ra.memoryUsage);
+        vscode.window.showInformationMessage(response);
     };
 }
 
diff --git a/editors/code/src/snippets.ts b/editors/code/src/snippets.ts
index e3f43a8..a469a9c 100644
--- a/editors/code/src/snippets.ts
+++ b/editors/code/src/snippets.ts
@@ -24,7 +24,9 @@
                 for (const indel of edits) {
                     assert(
                         !(indel instanceof vscode.SnippetTextEdit),
-                        `bad ws edit: snippet received with multiple edits: ${JSON.stringify(edit)}`,
+                        `bad ws edit: snippet received with multiple edits: ${JSON.stringify(
+                            edit,
+                        )}`,
                     );
                     builder.replace(indel.range, indel.newText);
                 }
diff --git a/rust-version b/rust-version
index c9529fd..0e89b4a 100644
--- a/rust-version
+++ b/rust-version
@@ -1 +1 @@
-fb24b04b096a980bffd80154f6aba22fd07cb3d9
+c5dabe8cf798123087d094f06417f5a767ca73e8
diff --git a/xtask/src/dist.rs b/xtask/src/dist.rs
index dbfecdb..1b1fb53 100644
--- a/xtask/src/dist.rs
+++ b/xtask/src/dist.rs
@@ -45,11 +45,22 @@
                 allocator,
                 self.zig,
                 self.pgo,
+                // Profiling requires debug information.
+                self.enable_profiling,
             )?;
             let release_tag = if stable { date_iso(sh)? } else { "nightly".to_owned() };
             dist_client(sh, &version, &release_tag, &target)?;
         } else {
-            dist_server(sh, "0.0.0-standalone", &target, allocator, self.zig, self.pgo)?;
+            dist_server(
+                sh,
+                "0.0.0-standalone",
+                &target,
+                allocator,
+                self.zig,
+                self.pgo,
+                // Profiling requires debug information.
+                self.enable_profiling,
+            )?;
         }
         Ok(())
     }
@@ -92,9 +103,11 @@
     allocator: Malloc,
     zig: bool,
     pgo: Option<PgoTrainingCrate>,
+    dev_rel: bool,
 ) -> anyhow::Result<()> {
     let _e = sh.push_env("CFG_RELEASE", release);
     let _e = sh.push_env("CARGO_PROFILE_RELEASE_LTO", "thin");
+    let _e = sh.push_env("CARGO_PROFILE_DEV_REL_LTO", "thin");
 
     // Uncomment to enable debug info for releases. Note that:
     //   * debug info is split on windows and macs, so it does nothing for those platforms,
@@ -120,7 +133,7 @@
         None
     };
 
-    let mut cmd = build_command(sh, command, &target_name, features);
+    let mut cmd = build_command(sh, command, &target_name, features, dev_rel);
     if let Some(profile) = pgo_profile {
         cmd = cmd.env("RUSTFLAGS", format!("-Cprofile-use={}", profile.to_str().unwrap()));
     }
@@ -141,10 +154,12 @@
     command: &str,
     target_name: &str,
     features: &[&str],
+    dev_rel: bool,
 ) -> Cmd<'a> {
+    let profile = if dev_rel { "dev-rel" } else { "release" };
     cmd!(
         sh,
-        "cargo {command} --manifest-path ./crates/rust-analyzer/Cargo.toml --bin rust-analyzer --target {target_name} {features...} --release"
+        "cargo {command} --manifest-path ./crates/rust-analyzer/Cargo.toml --bin rust-analyzer --target {target_name} {features...} --profile {profile}"
     )
 }
 
diff --git a/xtask/src/flags.rs b/xtask/src/flags.rs
index 8f70a18..e72d8f2 100644
--- a/xtask/src/flags.rs
+++ b/xtask/src/flags.rs
@@ -42,6 +42,10 @@
             optional --mimalloc
             /// Use jemalloc allocator for server.
             optional --jemalloc
+            // Enable memory profiling support.
+            //
+            // **Warning:** This will produce a slower build of rust-analyzer, use only for profiling.
+            optional --enable-profiling
 
             /// Install the proc-macro server.
             optional --proc-macro-server
@@ -67,6 +71,10 @@
             optional --mimalloc
             /// Use jemalloc allocator for server
             optional --jemalloc
+            // Enable memory profiling support.
+            //
+            // **Warning:** This will produce a slower build of rust-analyzer, use only for profiling.
+            optional --enable-profiling
             optional --client-patch-version version: String
             /// Use cargo-zigbuild
             optional --zig
@@ -125,6 +133,7 @@
     pub server: bool,
     pub mimalloc: bool,
     pub jemalloc: bool,
+    pub enable_profiling: bool,
     pub proc_macro_server: bool,
     pub dev_rel: bool,
     pub force_always_assert: bool,
@@ -143,6 +152,7 @@
 pub struct Dist {
     pub mimalloc: bool,
     pub jemalloc: bool,
+    pub enable_profiling: bool,
     pub client_patch_version: Option<String>,
     pub zig: bool,
     pub pgo: Option<PgoTrainingCrate>,
@@ -280,6 +290,7 @@
     System,
     Mimalloc,
     Jemalloc,
+    Dhat,
 }
 
 impl Malloc {
@@ -288,6 +299,7 @@
             Malloc::System => &[][..],
             Malloc::Mimalloc => &["--features", "mimalloc"],
             Malloc::Jemalloc => &["--features", "jemalloc"],
+            Malloc::Dhat => &["--features", "dhat"],
         }
     }
 }
@@ -301,12 +313,15 @@
             Malloc::Mimalloc
         } else if self.jemalloc {
             Malloc::Jemalloc
+        } else if self.enable_profiling {
+            Malloc::Dhat
         } else {
             Malloc::System
         };
         Some(ServerOpt {
             malloc,
-            dev_rel: self.dev_rel,
+            // Profiling requires debug information.
+            dev_rel: self.dev_rel || self.enable_profiling,
             pgo: self.pgo.clone(),
             force_always_assert: self.force_always_assert,
         })
@@ -331,6 +346,8 @@
             Malloc::Mimalloc
         } else if self.jemalloc {
             Malloc::Jemalloc
+        } else if self.enable_profiling {
+            Malloc::Dhat
         } else {
             Malloc::System
         }