Merge pull request #22238 from MavenRain/fixme-array-pat-incorrect-length

ide-diagnostics: emit error for mismatched array pattern length
diff --git a/crates/hir-def/src/attrs.rs b/crates/hir-def/src/attrs.rs
index 5dc410b..7757d53 100644
--- a/crates/hir-def/src/attrs.rs
+++ b/crates/hir-def/src/attrs.rs
@@ -137,6 +137,7 @@
                 "deprecated" => attr_flags.insert(AttrFlags::IS_DEPRECATED),
                 "ignore" => attr_flags.insert(AttrFlags::IS_IGNORE),
                 "lang" => attr_flags.insert(AttrFlags::LANG_ITEM),
+                "must_use" => attr_flags.insert(AttrFlags::IS_MUST_USE),
                 "path" => attr_flags.insert(AttrFlags::HAS_PATH),
                 "unstable" => attr_flags.insert(AttrFlags::IS_UNSTABLE),
                 "export_name" => {
@@ -227,6 +228,7 @@
                     "unstable" => attr_flags.insert(AttrFlags::IS_UNSTABLE),
                     "deprecated" => attr_flags.insert(AttrFlags::IS_DEPRECATED),
                     "macro_export" => attr_flags.insert(AttrFlags::IS_MACRO_EXPORT),
+                    "must_use" => attr_flags.insert(AttrFlags::IS_MUST_USE),
                     "no_mangle" => attr_flags.insert(AttrFlags::NO_MANGLE),
                     "pointee" => attr_flags.insert(AttrFlags::IS_POINTEE),
                     "non_exhaustive" => attr_flags.insert(AttrFlags::NON_EXHAUSTIVE),
@@ -335,6 +337,8 @@
         const MACRO_STYLE_PARENTHESES = 1 << 48;
 
         const PREFER_UNDERSCORE_IMPORT = 1 << 49;
+
+        const IS_MUST_USE = 1 << 50;
     }
 }
 
diff --git a/crates/hir-def/src/nameres/attr_resolution.rs b/crates/hir-def/src/nameres/attr_resolution.rs
index 062b55f..5aabd7d 100644
--- a/crates/hir-def/src/nameres/attr_resolution.rs
+++ b/crates/hir-def/src/nameres/attr_resolution.rs
@@ -9,7 +9,6 @@
 };
 use span::SyntaxContext;
 use syntax::ast;
-use triomphe::Arc;
 
 use crate::{
     AstIdWithPath, MacroId, ModuleId, UnresolvedMacro,
@@ -126,7 +125,7 @@
         krate,
         MacroCallKind::Attr {
             ast_id: item_attr.ast_id,
-            attr_args: arg.map(Arc::new),
+            attr_args: arg.map(Box::new),
             censored_attr_ids,
         },
         macro_attr.ctxt,
diff --git a/crates/hir-def/src/nameres/tests/incremental.rs b/crates/hir-def/src/nameres/tests/incremental.rs
index 60ec303..08f672a 100644
--- a/crates/hir-def/src/nameres/tests/incremental.rs
+++ b/crates/hir-def/src/nameres/tests/incremental.rs
@@ -227,7 +227,7 @@
                 "ast_id_map",
                 "parse",
                 "real_span_map",
-                "decl_macro_expander_shim",
+                "DeclarativeMacroExpander::expander_",
                 "file_item_tree_query",
                 "ast_id_map",
                 "parse",
@@ -240,7 +240,7 @@
                 "file_item_tree_query",
                 "ast_id_map",
                 "parse_macro_expansion",
-                "macro_arg_shim",
+                "macro_arg",
             ]
         "#]],
         expect![[r#"
@@ -249,7 +249,7 @@
                 "ast_id_map",
                 "file_item_tree_query",
                 "real_span_map",
-                "macro_arg_shim",
+                "macro_arg",
                 "parse_macro_expansion",
                 "ast_id_map",
                 "file_item_tree_query",
@@ -303,8 +303,8 @@
                 "file_item_tree_query",
                 "ast_id_map",
                 "parse_macro_expansion",
-                "expand_proc_macro_shim",
-                "macro_arg_shim",
+                "expand_proc_macro",
+                "macro_arg",
                 "proc_macro_span_shim",
             ]
         "#]],
@@ -314,8 +314,8 @@
                 "ast_id_map",
                 "file_item_tree_query",
                 "real_span_map",
-                "macro_arg_shim",
-                "expand_proc_macro_shim",
+                "macro_arg",
+                "expand_proc_macro",
                 "parse_macro_expansion",
                 "ast_id_map",
                 "file_item_tree_query",
@@ -415,7 +415,7 @@
                 "ast_id_map",
                 "parse",
                 "real_span_map",
-                "decl_macro_expander_shim",
+                "DeclarativeMacroExpander::expander_",
                 "file_item_tree_query",
                 "ast_id_map",
                 "parse",
@@ -428,19 +428,19 @@
                 "file_item_tree_query",
                 "ast_id_map",
                 "parse_macro_expansion",
-                "macro_arg_shim",
-                "decl_macro_expander_shim",
+                "macro_arg",
+                "DeclarativeMacroExpander::expander_",
                 "macro_def_shim",
                 "file_item_tree_query",
                 "ast_id_map",
                 "parse_macro_expansion",
-                "macro_arg_shim",
+                "macro_arg",
                 "macro_def_shim",
                 "file_item_tree_query",
                 "ast_id_map",
                 "parse_macro_expansion",
-                "expand_proc_macro_shim",
-                "macro_arg_shim",
+                "expand_proc_macro",
+                "macro_arg",
                 "proc_macro_span_shim",
             ]
         "#]],
@@ -450,10 +450,10 @@
                 "ast_id_map",
                 "file_item_tree_query",
                 "real_span_map",
-                "macro_arg_shim",
-                "decl_macro_expander_shim",
-                "macro_arg_shim",
-                "macro_arg_shim",
+                "macro_arg",
+                "DeclarativeMacroExpander::expander_",
+                "macro_arg",
+                "macro_arg",
             ]
         "#]],
     );
@@ -526,7 +526,7 @@
                 "ast_id_map",
                 "parse",
                 "real_span_map",
-                "decl_macro_expander_shim",
+                "DeclarativeMacroExpander::expander_",
                 "file_item_tree_query",
                 "ast_id_map",
                 "parse",
@@ -539,15 +539,15 @@
                 "file_item_tree_query",
                 "ast_id_map",
                 "parse_macro_expansion",
-                "macro_arg_shim",
+                "macro_arg",
                 "file_item_tree_query",
                 "ast_id_map",
                 "parse_macro_expansion",
-                "macro_arg_shim",
+                "macro_arg",
                 "file_item_tree_query",
                 "ast_id_map",
                 "parse_macro_expansion",
-                "macro_arg_shim",
+                "macro_arg",
             ]
         "#]],
     );
@@ -575,9 +575,9 @@
                 "ast_id_map",
                 "file_item_tree_query",
                 "real_span_map",
-                "macro_arg_shim",
-                "macro_arg_shim",
-                "macro_arg_shim",
+                "macro_arg",
+                "macro_arg",
+                "macro_arg",
             ]
         "#]],
     );
diff --git a/crates/hir-expand/src/db.rs b/crates/hir-expand/src/db.rs
index 57c7874..4b26c1f 100644
--- a/crates/hir-expand/src/db.rs
+++ b/crates/hir-expand/src/db.rs
@@ -3,6 +3,7 @@
 use base_db::{Crate, SourceDatabase};
 use mbe::MatchedArmIndex;
 use span::{AstIdMap, Edition, Span, SyntaxContext};
+use std::borrow::Cow;
 use syntax::{AstNode, Parse, SyntaxError, SyntaxNode, SyntaxToken, T, ast};
 use syntax_bridge::{DocCommentDesugarMode, syntax_node_to_token_tree};
 use triomphe::Arc;
@@ -21,7 +22,7 @@
     tt,
 };
 /// This is just to ensure the types of smart_macro_arg and macro_arg are the same
-type MacroArgResult = (Arc<tt::TopSubtree>, SyntaxFixupUndoInfo, Span);
+type MacroArgResult = (tt::TopSubtree, SyntaxFixupUndoInfo, Span);
 /// Total limit on the number of tokens produced by any macro invocation.
 ///
 /// If an invocation produces more tokens than this limit, it will not be stored in the database and
@@ -30,10 +31,10 @@
 /// Actual max for `analysis-stats .` at some point: 30672.
 const TOKEN_LIMIT: usize = 2_097_152;
 
-#[derive(Debug, Clone, Eq, PartialEq)]
-pub enum TokenExpander {
+#[derive(Debug, Clone, Copy, Eq, PartialEq)]
+pub enum TokenExpander<'db> {
     /// Old-style `macro_rules` or the new macros 2.0
-    DeclarativeMacro(Arc<DeclarativeMacroExpander>),
+    DeclarativeMacro(&'db DeclarativeMacroExpander),
     /// Stuff like `line!` and `file!`.
     BuiltIn(BuiltinFnLikeExpander),
     /// Built-in eagerly expanded fn-like macros (`include!`, `concat!`, etc.)
@@ -99,34 +100,37 @@
     /// subtree.
     #[deprecated = "calling this is incorrect, call `macro_arg_considering_derives` instead"]
     #[salsa::invoke(macro_arg)]
-    fn macro_arg(&self, id: MacroCallId) -> MacroArgResult;
+    #[salsa::transparent]
+    fn macro_arg(&self, id: MacroCallId) -> &MacroArgResult;
 
     #[salsa::transparent]
-    fn macro_arg_considering_derives(
-        &self,
+    fn macro_arg_considering_derives<'db>(
+        &'db self,
         id: MacroCallId,
         kind: &MacroCallKind,
-    ) -> MacroArgResult;
+    ) -> &'db MacroArgResult;
 
     /// Fetches the expander for this macro.
     #[salsa::transparent]
     #[salsa::invoke(TokenExpander::macro_expander)]
-    fn macro_expander(&self, id: MacroDefId) -> TokenExpander;
+    fn macro_expander(&self, id: MacroDefId) -> TokenExpander<'_>;
 
     /// Fetches (and compiles) the expander of this decl macro.
     #[salsa::invoke(DeclarativeMacroExpander::expander)]
+    #[salsa::transparent]
     fn decl_macro_expander(
         &self,
         def_crate: Crate,
         id: AstId<ast::Macro>,
-    ) -> Arc<DeclarativeMacroExpander>;
+    ) -> &DeclarativeMacroExpander;
 
     /// Special case of the previous query for procedural macros. We can't LRU
     /// proc macros, since they are not deterministic in general, and
     /// non-determinism breaks salsa in a very, very, very bad way.
     /// @edwin0cheng heroically debugged this once! See #4315 for details
     #[salsa::invoke(expand_proc_macro)]
-    fn expand_proc_macro(&self, call: MacroCallId) -> ExpandResult<Arc<tt::TopSubtree>>;
+    #[salsa::transparent]
+    fn expand_proc_macro(&self, call: MacroCallId) -> &ExpandResult<tt::TopSubtree>;
     /// Retrieves the span to be used for a proc-macro expansions spans.
     /// This is a firewall query as it requires parsing the file, which we don't want proc-macros to
     /// directly depend on as that would cause to frequent invalidations, mainly because of the
@@ -135,12 +139,12 @@
     #[salsa::invoke_interned(proc_macro_span)]
     fn proc_macro_span(&self, fun: AstId<ast::Fn>) -> Span;
 
-    /// Firewall query that returns the errors from the `parse_macro_expansion` query.
     #[salsa::invoke(parse_macro_expansion_error)]
+    #[salsa::transparent]
     fn parse_macro_expansion_error(
         &self,
         macro_call: MacroCallId,
-    ) -> Option<Arc<ExpandResult<Arc<[SyntaxError]>>>>;
+    ) -> Option<ExpandResult<Arc<[SyntaxError]>>>;
 
     #[salsa::transparent]
     fn syntax_context(&self, file: HirFileId, edition: Edition) -> SyntaxContext;
@@ -179,7 +183,7 @@
     token_to_map: SyntaxToken,
 ) -> Option<(SyntaxNode, Vec<(SyntaxToken, u8)>)> {
     let loc = db.lookup_intern_macro_call(actual_macro_call);
-    let (_, _, span) = db.macro_arg_considering_derives(actual_macro_call, &loc.kind);
+    let (_, _, span) = *db.macro_arg_considering_derives(actual_macro_call, &loc.kind);
 
     let span_map = RealSpanMap::absolute(span.anchor.file_id);
     let span_map = SpanMap::RealSpanMap(&span_map);
@@ -369,14 +373,7 @@
     let expand_to = loc.expand_to();
     let mbe::ValueResult { value: (tt, matched_arm), err } = macro_expand(db, macro_file, loc);
 
-    let (parse, mut rev_token_map) = token_tree_to_syntax_node(
-        db,
-        match &tt {
-            CowArc::Arc(it) => it,
-            CowArc::Owned(it) => it,
-        },
-        expand_to,
-    );
+    let (parse, mut rev_token_map) = token_tree_to_syntax_node(db, &tt, expand_to);
     rev_token_map.matched_arm = matched_arm;
 
     ExpandResult { value: (parse, rev_token_map), err }
@@ -385,10 +382,10 @@
 fn parse_macro_expansion_error(
     db: &dyn ExpandDatabase,
     macro_call_id: MacroCallId,
-) -> Option<Arc<ExpandResult<Arc<[SyntaxError]>>>> {
+) -> Option<ExpandResult<Arc<[SyntaxError]>>> {
     let e: ExpandResult<Arc<[SyntaxError]>> =
         db.parse_macro_expansion(macro_call_id).as_ref().map(|it| Arc::from(it.0.errors()));
-    if e.value.is_empty() && e.err.is_none() { None } else { Some(Arc::new(e)) }
+    if e.value.is_empty() && e.err.is_none() { None } else { Some(e) }
 }
 
 pub(crate) fn parse_with_map(
@@ -411,11 +408,11 @@
 ///
 /// This is not connected to the database so it does not cached the result. However, the inner [macro_arg] query is
 #[allow(deprecated)] // we are macro_arg_considering_derives
-fn macro_arg_considering_derives(
-    db: &dyn ExpandDatabase,
+fn macro_arg_considering_derives<'db>(
+    db: &'db dyn ExpandDatabase,
     id: MacroCallId,
     kind: &MacroCallKind,
-) -> MacroArgResult {
+) -> &'db MacroArgResult {
     match kind {
         // Get the macro arg for the derive macro
         MacroCallKind::Derive { derive_macro_id, .. } => db.macro_arg(*derive_macro_id),
@@ -424,6 +421,7 @@
     }
 }
 
+#[salsa_macros::tracked(returns(ref))]
 fn macro_arg(db: &dyn ExpandDatabase, id: MacroCallId) -> MacroArgResult {
     let loc = db.lookup_intern_macro_call(id);
 
@@ -449,10 +447,10 @@
 
             let dummy_tt = |kind| {
                 (
-                    Arc::new(tt::TopSubtree::from_token_trees(
+                    tt::TopSubtree::from_token_trees(
                         tt::Delimiter { open: span, close: span, kind },
                         tt::TokenTreesView::empty(),
-                    )),
+                    ),
                     SyntaxFixupUndoInfo::default(),
                     span,
                 )
@@ -501,7 +499,7 @@
                 // proc macros expect their inputs without parentheses, MBEs expect it with them included
                 tt.set_top_subtree_delimiter_kind(tt::DelimiterKind::Invisible);
             }
-            return (Arc::new(tt), SyntaxFixupUndoInfo::NONE, span);
+            return (tt, SyntaxFixupUndoInfo::NONE, span);
         }
         // MacroCallKind::Derive should not be here. As we are getting the argument for the derive macro
         MacroCallKind::Derive { .. } => {
@@ -536,11 +534,11 @@
         tt.set_top_subtree_delimiter_kind(tt::DelimiterKind::Invisible);
     }
 
-    (Arc::new(tt), undo_info, span)
+    (tt, undo_info, span)
 }
 
-impl TokenExpander {
-    fn macro_expander(db: &dyn ExpandDatabase, id: MacroDefId) -> TokenExpander {
+impl<'db> TokenExpander<'db> {
+    fn macro_expander(db: &'db dyn ExpandDatabase, id: MacroDefId) -> TokenExpander<'db> {
         match id.kind {
             MacroDefKind::Declarative(ast_id, _) => {
                 TokenExpander::DeclarativeMacro(db.decl_macro_expander(id.krate, ast_id))
@@ -554,27 +552,26 @@
     }
 }
 
-enum CowArc<T> {
-    Arc(Arc<T>),
-    Owned(T),
-}
-
 fn macro_expand(
     db: &dyn ExpandDatabase,
     macro_call_id: MacroCallId,
     loc: MacroCallLoc,
-) -> ExpandResult<(CowArc<tt::TopSubtree>, MatchedArmIndex)> {
+) -> ExpandResult<(Cow<'_, tt::TopSubtree>, MatchedArmIndex)> {
     let _p = tracing::info_span!("macro_expand").entered();
 
     let (ExpandResult { value: (tt, matched_arm), err }, span) = match loc.def.kind {
         MacroDefKind::ProcMacro(..) => {
-            return db.expand_proc_macro(macro_call_id).map(CowArc::Arc).zip_val(None);
+            return db
+                .expand_proc_macro(macro_call_id)
+                .as_ref()
+                .map(|it| (Cow::Borrowed(it), None));
         }
         _ => {
             let (macro_arg, undo_info, span) =
                 db.macro_arg_considering_derives(macro_call_id, &loc.kind);
+            let span = *span;
 
-            let arg = &*macro_arg;
+            let arg = macro_arg;
             let res = match loc.def.kind {
                 MacroDefKind::Declarative(id, _) => db
                     .decl_macro_expander(loc.def.krate, id)
@@ -594,7 +591,7 @@
                     // As such we just return the input subtree here.
                     let eager = match &loc.kind {
                         MacroCallKind::FnLike { eager: None, .. } => {
-                            return ExpandResult::ok(CowArc::Arc(macro_arg.clone())).zip_val(None);
+                            return ExpandResult::ok(Cow::Borrowed(macro_arg)).zip_val(None);
                         }
                         MacroCallKind::FnLike { eager: Some(eager), .. } => Some(&**eager),
                         _ => None,
@@ -610,7 +607,7 @@
                 }
                 MacroDefKind::BuiltInAttr(_, it) => {
                     let mut res = it.expand(db, macro_call_id, arg, span);
-                    fixup::reverse_fixups(&mut res.value, &undo_info);
+                    fixup::reverse_fixups(&mut res.value, undo_info);
                     res.zip_val(None)
                 }
                 MacroDefKind::ProcMacro(_, _, _) => unreachable!(),
@@ -624,12 +621,12 @@
         // Set a hard limit for the expanded tt
         if let Err(value) = check_tt_count(&tt) {
             return value
-                .map(|()| CowArc::Owned(tt::TopSubtree::empty(tt::DelimSpan::from_single(span))))
+                .map(|()| Cow::Owned(tt::TopSubtree::empty(tt::DelimSpan::from_single(span))))
                 .zip_val(matched_arm);
         }
     }
 
-    ExpandResult { value: (CowArc::Owned(tt), matched_arm), err }
+    ExpandResult { value: (Cow::Owned(tt), matched_arm), err }
 }
 
 fn proc_macro_span(db: &dyn ExpandDatabase, ast: AstId<ast::Fn>) -> Span {
@@ -643,10 +640,8 @@
     span_map.span_for_range(range)
 }
 
-fn expand_proc_macro(
-    db: &dyn ExpandDatabase,
-    id: MacroCallId,
-) -> ExpandResult<Arc<tt::TopSubtree>> {
+#[salsa_macros::tracked(returns(ref))]
+fn expand_proc_macro(db: &dyn ExpandDatabase, id: MacroCallId) -> ExpandResult<tt::TopSubtree> {
     let loc = db.lookup_intern_macro_call(id);
     let (macro_arg, undo_info, span) = db.macro_arg_considering_derives(id, &loc.kind);
 
@@ -666,7 +661,7 @@
             db,
             loc.def.krate,
             loc.krate,
-            &macro_arg,
+            macro_arg,
             attr_arg,
             span_with_def_site_ctxt(db, span, id.into(), loc.def.edition),
             span_with_call_site_ctxt(db, span, id.into(), loc.def.edition),
@@ -676,12 +671,12 @@
 
     // Set a hard limit for the expanded tt
     if let Err(value) = check_tt_count(&tt) {
-        return value.map(|()| Arc::new(tt::TopSubtree::empty(tt::DelimSpan::from_single(span))));
+        return value.map(|()| tt::TopSubtree::empty(tt::DelimSpan::from_single(*span)));
     }
 
-    fixup::reverse_fixups(&mut tt, &undo_info);
+    fixup::reverse_fixups(&mut tt, undo_info);
 
-    ExpandResult { value: Arc::new(tt), err }
+    ExpandResult { value: tt, err }
 }
 
 pub(crate) fn token_tree_to_syntax_node(
diff --git a/crates/hir-expand/src/declarative.rs b/crates/hir-expand/src/declarative.rs
index aa745a2..ead10a5 100644
--- a/crates/hir-expand/src/declarative.rs
+++ b/crates/hir-expand/src/declarative.rs
@@ -10,7 +10,6 @@
     ast::{self, HasAttrs},
 };
 use syntax_bridge::DocCommentDesugarMode;
-use triomphe::Arc;
 
 use crate::{
     AstId, ExpandError, ExpandErrorKind, ExpandResult, HirFileId, Lookup, MacroCallId,
@@ -78,12 +77,16 @@
                 .map_err(Into::into),
         }
     }
+}
 
+#[salsa::tracked]
+impl DeclarativeMacroExpander {
+    #[salsa::tracked(returns(ref))]
     pub(crate) fn expander(
         db: &dyn ExpandDatabase,
         def_crate: Crate,
         id: AstId<ast::Macro>,
-    ) -> Arc<DeclarativeMacroExpander> {
+    ) -> DeclarativeMacroExpander {
         let (root, map) = crate::db::parse_with_map(db, id.file_id);
         let root = root.syntax_node();
 
@@ -177,6 +180,6 @@
             HirFileId::MacroFile(macro_file) => macro_file.lookup(db).ctxt,
             HirFileId::FileId(file) => SyntaxContext::root(file.edition(db)),
         });
-        Arc::new(DeclarativeMacroExpander { mac, transparency, edition })
+        DeclarativeMacroExpander { mac, transparency, edition }
     }
 }
diff --git a/crates/hir-expand/src/eager.rs b/crates/hir-expand/src/eager.rs
index 6e95ff0..dddef17 100644
--- a/crates/hir-expand/src/eager.rs
+++ b/crates/hir-expand/src/eager.rs
@@ -22,7 +22,6 @@
 use span::SyntaxContext;
 use syntax::{AstPtr, Parse, SyntaxElement, SyntaxNode, TextSize, WalkEvent, ted};
 use syntax_bridge::DocCommentDesugarMode;
-use triomphe::Arc;
 
 use crate::{
     AstId, EagerCallInfo, ExpandError, ExpandResult, ExpandTo, ExpansionSpanMap, InFile,
@@ -92,7 +91,7 @@
     let mut subtree = syntax_bridge::syntax_node_to_token_tree(
         &expanded_eager_input,
         arg_map,
-        span,
+        *span,
         DocCommentDesugarMode::Mbe,
     );
 
@@ -104,11 +103,11 @@
         kind: MacroCallKind::FnLike {
             ast_id,
             expand_to,
-            eager: Some(Arc::new(EagerCallInfo {
-                arg: Arc::new(subtree),
+            eager: Some(Box::new(EagerCallInfo {
+                arg: subtree,
                 arg_id,
                 error: err.clone(),
-                span,
+                span: *span,
             })),
         },
         ctxt: call_site,
diff --git a/crates/hir-expand/src/fixup.rs b/crates/hir-expand/src/fixup.rs
index b51ec39..939104b 100644
--- a/crates/hir-expand/src/fixup.rs
+++ b/crates/hir-expand/src/fixup.rs
@@ -14,7 +14,7 @@
     match_ast,
 };
 use syntax_bridge::DocCommentDesugarMode;
-use triomphe::Arc;
+use thin_vec::ThinVec;
 use tt::{Spacing, TransformTtAction, transform_tt};
 
 use crate::{
@@ -35,8 +35,7 @@
 /// This is the information needed to reverse the fixups.
 #[derive(Clone, Debug, Default, PartialEq, Eq)]
 pub struct SyntaxFixupUndoInfo {
-    // FIXME: ThinArc<[Subtree]>
-    original: Option<Arc<Box<[TopSubtree]>>>,
+    original: Option<ThinVec<TopSubtree>>,
 }
 
 impl SyntaxFixupUndoInfo {
@@ -59,7 +58,7 @@
     let mut append = FxHashMap::<SyntaxElement, _>::default();
     let mut remove = FxHashSet::<SyntaxElement>::default();
     let mut preorder = node.preorder();
-    let mut original = Vec::new();
+    let mut original = ThinVec::new();
     let dummy_range = FIXUP_DUMMY_RANGE;
     let fake_span = |range| {
         let span = span_map.span_for_range(range);
@@ -317,13 +316,12 @@
             }
         }
     }
+    original.shrink_to_fit();
     let needs_fixups = !append.is_empty() || !original.is_empty();
     SyntaxFixups {
         append,
         remove,
-        undo_info: SyntaxFixupUndoInfo {
-            original: needs_fixups.then(|| Arc::new(original.into_boxed_slice())),
-        },
+        undo_info: SyntaxFixupUndoInfo { original: needs_fixups.then_some(original) },
     }
 }
 
@@ -340,7 +338,7 @@
 }
 
 pub(crate) fn reverse_fixups(tt: &mut TopSubtree, undo_info: &SyntaxFixupUndoInfo) {
-    let Some(undo_info) = undo_info.original.as_deref() else { return };
+    let Some(undo_info) = &undo_info.original else { return };
     let undo_info = &**undo_info;
     let top_subtree = tt.top_subtree();
     let open_span = top_subtree.delimiter.open;
diff --git a/crates/hir-expand/src/lib.rs b/crates/hir-expand/src/lib.rs
index fc2a074..403e544 100644
--- a/crates/hir-expand/src/lib.rs
+++ b/crates/hir-expand/src/lib.rs
@@ -279,7 +279,7 @@
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
 pub struct EagerCallInfo {
     /// The expanded argument of the eager macro.
-    arg: Arc<tt::TopSubtree>,
+    arg: tt::TopSubtree,
     /// Call id of the eager macro's input file (this is the macro file for its fully expanded input).
     arg_id: MacroCallId,
     error: Option<ExpandError>,
@@ -296,7 +296,7 @@
         /// for the eager input macro file.
         // FIXME: This is being interned, subtrees can vary quickly differing just slightly causing
         // leakage problems here
-        eager: Option<Arc<EagerCallInfo>>,
+        eager: Option<Box<EagerCallInfo>>,
     },
     Derive {
         ast_id: AstId<ast::Adt>,
@@ -311,7 +311,7 @@
     Attr {
         ast_id: AstId<ast::Item>,
         // FIXME: This shouldn't be here, we can derive this from `invoc_attr_index`.
-        attr_args: Option<Arc<tt::TopSubtree>>,
+        attr_args: Option<Box<tt::TopSubtree>>,
         /// This contains the list of all *active* attributes (derives and attr macros) preceding this
         /// attribute, including this attribute. You can retrieve the [`AttrId`] of the current attribute
         /// by calling [`invoc_attr()`] on this.
diff --git a/crates/hir-ty/src/consteval.rs b/crates/hir-ty/src/consteval.rs
index 80e7e05..87633ad 100644
--- a/crates/hir-ty/src/consteval.rs
+++ b/crates/hir-ty/src/consteval.rs
@@ -16,7 +16,6 @@
 use rustc_apfloat::Float;
 use rustc_type_ir::inherent::IntoKind;
 use stdx::never;
-use triomphe::Arc;
 
 use crate::{
     LifetimeElisionKind, ParamEnvAndCrate, TyLoweringContext,
@@ -300,7 +299,7 @@
     if let Some(body_owner) = ctx.owner.as_def_with_body()
         && let Ok(mir_body) =
             lower_body_to_mir(ctx.db, body_owner, Body::of(ctx.db, body_owner), &infer, expr)
-        && let Ok((Ok(result), _)) = interpret_mir(ctx.db, Arc::new(mir_body), true, None)
+        && let Ok((Ok(result), _)) = interpret_mir(ctx.db, &mir_body, true, None)
     {
         return Const::new_from_allocation(
             ctx.interner(),
diff --git a/crates/hir-ty/src/db.rs b/crates/hir-ty/src/db.rs
index 2e130c1..5dba53a 100644
--- a/crates/hir-ty/src/db.rs
+++ b/crates/hir-ty/src/db.rs
@@ -37,33 +37,44 @@
 
     // FXME: Collapse `mir_body_for_closure` into `mir_body`
     // and `monomorphized_mir_body_for_closure` into `monomorphized_mir_body`
-    #[salsa::invoke(crate::mir::mir_body_query)]
-    #[salsa::cycle(cycle_result = crate::mir::mir_body_cycle_result)]
-    fn mir_body(&self, def: DefWithBodyId) -> Result<Arc<MirBody>, MirLowerError>;
+    #[salsa::transparent]
+    fn mir_body(&self, def: DefWithBodyId) -> Result<&MirBody, MirLowerError> {
+        crate::mir::mir_body_query(self, def).as_ref().map_err(|err| err.clone())
+    }
 
-    #[salsa::invoke(crate::mir::mir_body_for_closure_query)]
-    fn mir_body_for_closure(&self, def: InternedClosureId) -> Result<Arc<MirBody>, MirLowerError>;
+    #[salsa::transparent]
+    fn mir_body_for_closure(&self, def: InternedClosureId) -> Result<&MirBody, MirLowerError> {
+        crate::mir::mir_body_for_closure_query(self, def).as_ref().map_err(|err| err.clone())
+    }
 
-    #[salsa::invoke(crate::mir::monomorphized_mir_body_query)]
-    #[salsa::cycle(cycle_result = crate::mir::monomorphized_mir_body_cycle_result)]
+    #[salsa::transparent]
     fn monomorphized_mir_body(
         &self,
         def: DefWithBodyId,
         subst: StoredGenericArgs,
         env: StoredParamEnvAndCrate,
-    ) -> Result<Arc<MirBody>, MirLowerError>;
+    ) -> Result<&MirBody, MirLowerError> {
+        crate::mir::monomorphized_mir_body_query(self, def, subst, env)
+            .as_ref()
+            .map_err(|err| err.clone())
+    }
 
-    #[salsa::invoke(crate::mir::monomorphized_mir_body_for_closure_query)]
+    #[salsa::transparent]
     fn monomorphized_mir_body_for_closure(
         &self,
         def: InternedClosureId,
         subst: StoredGenericArgs,
         env: StoredParamEnvAndCrate,
-    ) -> Result<Arc<MirBody>, MirLowerError>;
+    ) -> Result<&MirBody, MirLowerError> {
+        crate::mir::monomorphized_mir_body_for_closure_query(self, def, subst, env)
+            .as_ref()
+            .map_err(|err| err.clone())
+    }
 
-    #[salsa::invoke(crate::mir::borrowck_query)]
-    #[salsa::lru(2024)]
-    fn borrowck(&self, def: DefWithBodyId) -> Result<Arc<[BorrowckResult]>, MirLowerError>;
+    #[salsa::transparent]
+    fn borrowck(&self, def: DefWithBodyId) -> Result<&[BorrowckResult], MirLowerError> {
+        crate::mir::borrowck_query(self, def).as_ref().map(|it| &**it).map_err(|err| err.clone())
+    }
 
     #[salsa::invoke(crate::consteval::const_eval)]
     #[salsa::transparent]
@@ -110,8 +121,10 @@
         env: StoredParamEnvAndCrate,
     ) -> Result<Arc<Layout>, LayoutError>;
 
-    #[salsa::invoke(crate::layout::target_data_layout_query)]
-    fn target_data_layout(&self, krate: Crate) -> Result<Arc<TargetDataLayout>, TargetLoadError>;
+    #[salsa::transparent]
+    fn target_data_layout(&self, krate: Crate) -> Result<&TargetDataLayout, TargetLoadError> {
+        crate::layout::target_data_layout_query(self, krate).as_ref().map_err(|err| err.clone())
+    }
 
     #[salsa::invoke(crate::dyn_compatibility::dyn_compatibility_of_trait_query)]
     fn dyn_compatibility_of_trait(&self, trait_: TraitId) -> Option<DynCompatibilityViolation>;
diff --git a/crates/hir-ty/src/diagnostics/expr.rs b/crates/hir-ty/src/diagnostics/expr.rs
index 93772ca..be29926 100644
--- a/crates/hir-ty/src/diagnostics/expr.rs
+++ b/crates/hir-ty/src/diagnostics/expr.rs
@@ -7,7 +7,9 @@
 use base_db::Crate;
 use either::Either;
 use hir_def::{
-    AdtId, AssocItemId, DefWithBodyId, HasModule, ItemContainerId, Lookup,
+    AdtId, AssocItemId, AttrDefId, CallableDefId, DefWithBodyId, HasModule, ItemContainerId,
+    Lookup,
+    attrs::AttrFlags,
     lang_item::LangItems,
     resolver::{HasResolver, ValueNs},
 };
@@ -33,7 +35,7 @@
     },
     display::{DisplayTarget, HirDisplay},
     next_solver::{
-        DbInterner, ParamEnv, Ty, TyKind, TypingMode,
+        CallableIdWrapper, DbInterner, ParamEnv, Ty, TyKind, TypingMode,
         infer::{DbInternerInferExt, InferCtxt},
     },
 };
@@ -67,6 +69,9 @@
     RemoveUnnecessaryElse {
         if_expr: ExprId,
     },
+    UnusedMustUse {
+        expr: ExprId,
+    },
 }
 
 impl BodyValidationDiagnostic {
@@ -328,54 +333,73 @@
         let pattern_arena = Arena::new();
         let cx = MatchCheckCtx::new(self.owner.module(self.db()), &self.infcx, self.env);
         for stmt in &**statements {
-            let &Statement::Let { pat, initializer, else_branch: None, .. } = stmt else {
-                continue;
-            };
-            if self.infer.type_mismatch_for_pat(pat).is_some() {
-                continue;
-            }
-            let Some(initializer) = initializer else { continue };
-            let Some(ty) = self.infer.type_of_expr_with_adjust(initializer) else { continue };
-            if ty.references_non_lt_error() {
-                continue;
-            }
-
-            let mut have_errors = false;
-            let deconstructed_pat = self.lower_pattern(&cx, pat, &mut have_errors);
-
-            // optimization, wildcard trivially hold
-            if have_errors || matches!(deconstructed_pat.ctor(), Constructor::Wildcard) {
-                continue;
-            }
-
-            let match_arm = rustc_pattern_analysis::MatchArm {
-                pat: pattern_arena.alloc(deconstructed_pat),
-                has_guard: false,
-                arm_data: (),
-            };
-            let report = match cx.compute_match_usefulness(&[match_arm], ty, None) {
-                Ok(v) => v,
-                Err(e) => {
-                    debug!(?e, "match usefulness error");
-                    continue;
+            let diag = match *stmt {
+                Statement::Expr { expr: stmt_expr, has_semi: true } if self.validate_lints => {
+                    self.check_unused_must_use(stmt_expr)
                 }
+                Statement::Let { pat, initializer, else_branch: None, .. } => {
+                    self.check_non_exhaustive_let(&cx, &pattern_arena, pat, initializer)
+                }
+                _ => None,
             };
-            let witnesses = report.non_exhaustiveness_witnesses;
-            if !witnesses.is_empty() {
-                self.diagnostics.push(BodyValidationDiagnostic::NonExhaustiveLet {
-                    pat,
-                    uncovered_patterns: missing_match_arms(
-                        &cx,
-                        ty,
-                        witnesses,
-                        false,
-                        self.owner.krate(self.db()),
-                    ),
-                });
+            if let Some(diag) = diag {
+                self.diagnostics.push(diag);
             }
         }
     }
 
+    fn check_non_exhaustive_let<'a>(
+        &self,
+        cx: &MatchCheckCtx<'a, 'db>,
+        pattern_arena: &'a Arena<DeconstructedPat<'a, 'db>>,
+        pat: PatId,
+        initializer: Option<ExprId>,
+    ) -> Option<BodyValidationDiagnostic> {
+        if self.infer.type_mismatch_for_pat(pat).is_some() {
+            return None;
+        }
+        let initializer = initializer?;
+        let ty = self.infer.type_of_expr_with_adjust(initializer)?;
+        if ty.references_non_lt_error() {
+            return None;
+        }
+
+        let mut have_errors = false;
+        let deconstructed_pat = self.lower_pattern(cx, pat, &mut have_errors);
+
+        // optimization, wildcard trivially hold
+        if have_errors || matches!(deconstructed_pat.ctor(), Constructor::Wildcard) {
+            return None;
+        }
+
+        let match_arm = rustc_pattern_analysis::MatchArm {
+            pat: pattern_arena.alloc(deconstructed_pat),
+            has_guard: false,
+            arm_data: (),
+        };
+        let report = match cx.compute_match_usefulness(&[match_arm], ty, None) {
+            Ok(v) => v,
+            Err(e) => {
+                debug!(?e, "match usefulness error");
+                return None;
+            }
+        };
+        let witnesses = report.non_exhaustiveness_witnesses;
+        if witnesses.is_empty() {
+            return None;
+        }
+        Some(BodyValidationDiagnostic::NonExhaustiveLet {
+            pat,
+            uncovered_patterns: missing_match_arms(
+                cx,
+                ty,
+                witnesses,
+                false,
+                self.owner.krate(self.db()),
+            ),
+        })
+    }
+
     fn lower_pattern<'a>(
         &self,
         cx: &MatchCheckCtx<'a, 'db>,
@@ -391,6 +415,37 @@
         pattern
     }
 
+    fn check_unused_must_use(&self, expr: ExprId) -> Option<BodyValidationDiagnostic> {
+        let db = self.db();
+        let must_use_fn = match &self.body[expr] {
+            Expr::Call { callee, .. } => {
+                let callee_ty = self.infer.expr_ty(*callee);
+                if let TyKind::FnDef(CallableIdWrapper(CallableDefId::FunctionId(func)), _) =
+                    callee_ty.kind()
+                {
+                    AttrFlags::query(db, AttrDefId::FunctionId(func))
+                        .contains(AttrFlags::IS_MUST_USE)
+                } else {
+                    false
+                }
+            }
+            Expr::MethodCall { .. } => {
+                self.infer.method_resolution(expr).is_some_and(|(func, _)| {
+                    AttrFlags::query(db, AttrDefId::FunctionId(func))
+                        .contains(AttrFlags::IS_MUST_USE)
+                })
+            }
+            _ => return None,
+        };
+        let must_use_ty =
+            self.infer.type_of_expr_with_adjust(expr).is_some_and(|ty| match ty.kind() {
+                TyKind::Adt(adt, _) => AttrFlags::query(db, AttrDefId::AdtId(adt.def_id()))
+                    .contains(AttrFlags::IS_MUST_USE),
+                _ => false,
+            });
+        (must_use_fn || must_use_ty).then_some(BodyValidationDiagnostic::UnusedMustUse { expr })
+    }
+
     fn check_for_trailing_return(&mut self, body_expr: ExprId, body: &Body) {
         if !self.validate_lints {
             return;
diff --git a/crates/hir-ty/src/display.rs b/crates/hir-ty/src/display.rs
index 2df190b..c300388 100644
--- a/crates/hir-ty/src/display.rs
+++ b/crates/hir-ty/src/display.rs
@@ -974,7 +974,7 @@
                         return f.write_str("<target-layout-not-available>");
                     };
                     let Some((var_id, var_layout)) =
-                        detect_variant_from_bytes(&layout, f.db, &target_data_layout, b, e)
+                        detect_variant_from_bytes(&layout, f.db, target_data_layout, b, e)
                     else {
                         return f.write_str("<failed-to-detect-variant>");
                     };
diff --git a/crates/hir-ty/src/layout.rs b/crates/hir-ty/src/layout.rs
index d2759dd..da0be81 100644
--- a/crates/hir-ty/src/layout.rs
+++ b/crates/hir-ty/src/layout.rs
@@ -167,7 +167,7 @@
     let Ok(target) = db.target_data_layout(krate) else {
         return Err(LayoutError::TargetLayoutNotAvailable);
     };
-    let dl = &*target;
+    let dl = target;
     let cx = LayoutCx::new(dl);
     let infer_ctxt = interner.infer_ctxt().build(TypingMode::PostAnalysis);
     let cause = ObligationCause::dummy();
@@ -187,7 +187,7 @@
                             repr.packed(),
                             &args,
                             trait_env.as_ref(),
-                            &target,
+                            target,
                         );
                     }
                 }
diff --git a/crates/hir-ty/src/layout/adt.rs b/crates/hir-ty/src/layout/adt.rs
index 6090ddf..e77fb13 100644
--- a/crates/hir-ty/src/layout/adt.rs
+++ b/crates/hir-ty/src/layout/adt.rs
@@ -29,7 +29,7 @@
     let Ok(target) = db.target_data_layout(krate) else {
         return Err(LayoutError::TargetLayoutNotAvailable);
     };
-    let dl = &*target;
+    let dl = target;
     let cx = LayoutCx::new(dl);
     let handle_variant = |def: VariantId, var: &VariantFields| {
         var.fields()
diff --git a/crates/hir-ty/src/layout/target.rs b/crates/hir-ty/src/layout/target.rs
index 1752b56..26fa73e 100644
--- a/crates/hir-ty/src/layout/target.rs
+++ b/crates/hir-ty/src/layout/target.rs
@@ -3,17 +3,17 @@
 use base_db::{Crate, target::TargetLoadError};
 use hir_def::layout::TargetDataLayout;
 use rustc_abi::{AddressSpace, AlignFromBytesError, TargetDataLayoutError};
-use triomphe::Arc;
 
 use crate::db::HirDatabase;
 
+#[salsa_macros::tracked(returns(ref))]
 pub fn target_data_layout_query(
     db: &dyn HirDatabase,
     krate: Crate,
-) -> Result<Arc<TargetDataLayout>, TargetLoadError> {
+) -> Result<TargetDataLayout, TargetLoadError> {
     match &krate.workspace_data(db).target {
         Ok(target) => match TargetDataLayout::parse_from_llvm_datalayout_string(&target.data_layout, AddressSpace::ZERO) {
-            Ok(it) => Ok(Arc::new(it)),
+            Ok(it) => Ok(it),
             Err(e) => {
                 Err(match e {
                     TargetDataLayoutError::InvalidAddressSpace { addr_space, cause, err } => {
diff --git a/crates/hir-ty/src/mir.rs b/crates/hir-ty/src/mir.rs
index a8e06f3..67cc67f 100644
--- a/crates/hir-ty/src/mir.rs
+++ b/crates/hir-ty/src/mir.rs
@@ -47,9 +47,6 @@
     monomorphized_mir_body_for_closure_query, monomorphized_mir_body_query,
 };
 
-pub(crate) use lower::mir_body_cycle_result;
-pub(crate) use monomorphization::monomorphized_mir_body_cycle_result;
-
 use super::consteval::try_const_usize;
 
 pub type BasicBlockId = Idx<BasicBlock>;
diff --git a/crates/hir-ty/src/mir/borrowck.rs b/crates/hir-ty/src/mir/borrowck.rs
index 17715d3..dcd06ae 100644
--- a/crates/hir-ty/src/mir/borrowck.rs
+++ b/crates/hir-ty/src/mir/borrowck.rs
@@ -5,11 +5,11 @@
 
 use std::iter;
 
+use either::Either;
 use hir_def::{DefWithBodyId, ExpressionStoreOwnerId, HasModule};
 use la_arena::ArenaMap;
 use rustc_hash::FxHashMap;
 use stdx::never;
-use triomphe::Arc;
 
 use crate::{
     closure_analysis::ProjectionKind as HirProjectionKind,
@@ -57,68 +57,86 @@
 
 #[derive(Debug, Clone, PartialEq, Eq)]
 pub struct BorrowckResult {
-    pub mir_body: Arc<MirBody>,
+    owner: Either<DefWithBodyId, InternedClosureId>,
     pub mutability_of_locals: ArenaMap<LocalId, MutabilityReason>,
     pub moved_out_of_ref: Vec<MovedOutOfRef>,
     pub partially_moved: Vec<PartiallyMoved>,
     pub borrow_regions: Vec<BorrowRegion>,
 }
 
-fn all_mir_bodies(
-    db: &dyn HirDatabase,
+impl BorrowckResult {
+    pub fn mir_body<'db>(&self, db: &'db dyn HirDatabase) -> &'db MirBody {
+        match self.owner {
+            Either::Left(it) => db.mir_body(it).unwrap(),
+            Either::Right(it) => db.mir_body_for_closure(it).unwrap(),
+        }
+    }
+}
+
+fn all_mir_bodies<'db>(
+    db: &'db dyn HirDatabase,
     def: DefWithBodyId,
-    mut cb: impl FnMut(Arc<MirBody>) -> BorrowckResult,
-    mut merge_from_closures: impl FnMut(&mut BorrowckResult, &BorrowckResult),
-) -> Result<Arc<[BorrowckResult]>, MirLowerError> {
-    fn for_closure(
-        db: &dyn HirDatabase,
+    mut cb: impl FnMut(&'db MirBody, Either<DefWithBodyId, InternedClosureId>) -> BorrowckResult,
+    mut merge_from_closures: impl FnMut(
+        (&mut BorrowckResult, &'db MirBody),
+        (&BorrowckResult, &'db MirBody),
+    ),
+) -> Result<Box<[BorrowckResult]>, MirLowerError> {
+    fn for_closure<'db>(
+        db: &'db dyn HirDatabase,
         c: InternedClosureId,
-        results: &mut Vec<BorrowckResult>,
-        cb: &mut impl FnMut(Arc<MirBody>) -> BorrowckResult,
-        merge_from_closures: &mut impl FnMut(&mut BorrowckResult, &BorrowckResult),
+        results: &mut Vec<(BorrowckResult, &'db MirBody)>,
+        cb: &mut impl FnMut(&'db MirBody, Either<DefWithBodyId, InternedClosureId>) -> BorrowckResult,
+        merge_from_closures: &mut impl FnMut(
+            (&mut BorrowckResult, &'db MirBody),
+            (&BorrowckResult, &'db MirBody),
+        ),
     ) -> Result<(), MirLowerError> {
         match db.mir_body_for_closure(c) {
             Ok(body) => {
                 let parent_index = results.len();
-                results.push(cb(body.clone()));
+                results.push((cb(body, Either::Right(c)), body));
                 body.closures
                     .iter()
                     .try_for_each(|&it| for_closure(db, it, results, cb, merge_from_closures))?;
                 merge(results, merge_from_closures, parent_index);
                 Ok(())
             }
-            Err(e) => Err(e),
+            Err(e) => Err(e.clone()),
         }
     }
 
-    fn merge(
-        results: &mut [BorrowckResult],
-        merge: &mut impl FnMut(&mut BorrowckResult, &BorrowckResult),
+    fn merge<'db>(
+        results: &mut [(BorrowckResult, &'db MirBody)],
+        merge: &mut impl FnMut((&mut BorrowckResult, &'db MirBody), (&BorrowckResult, &'db MirBody)),
         parent_index: usize,
     ) {
         let (parent_and_before, children) = results.split_at_mut(parent_index + 1);
-        let parent = &mut parent_and_before[parent_and_before.len() - 1];
-        children.iter().for_each(|child| merge(parent, child));
+        let (parent, parent_mir_body) = &mut parent_and_before[parent_and_before.len() - 1];
+        children.iter().for_each(|(child, child_mir_body)| {
+            merge((parent, parent_mir_body), (child, child_mir_body))
+        });
     }
 
     let mut results = Vec::new();
     match db.mir_body(def) {
         Ok(body) => {
-            results.push(cb(body.clone()));
+            results.push((cb(body, Either::Left(def)), body));
             body.closures.iter().try_for_each(|&it| {
                 for_closure(db, it, &mut results, &mut cb, &mut merge_from_closures)
             })?;
             merge(&mut results, &mut merge_from_closures, 0);
-            Ok(results.into())
+            Ok(results.into_iter().map(|(it, _)| it).collect())
         }
-        Err(e) => Err(e),
+        Err(e) => Err(e.clone()),
     }
 }
 
+#[salsa_macros::tracked(returns(ref), lru = 2024)]
 pub fn borrowck_query(
     db: &dyn HirDatabase,
     def: DefWithBodyId,
-) -> Result<Arc<[BorrowckResult]>, MirLowerError> {
+) -> Result<Box<[BorrowckResult]>, MirLowerError> {
     let _p = tracing::info_span!("borrowck_query").entered();
     let module = def.module(db);
     let interner = DbInterner::new_with(db, module.krate(db));
@@ -128,20 +146,20 @@
     let res = all_mir_bodies(
         db,
         def,
-        |body| {
+        |body, owner| {
             // FIXME(next-solver): Opaques.
             let infcx = interner.infer_ctxt().build(typing_mode);
             BorrowckResult {
-                mutability_of_locals: mutability_of_locals(&infcx, env, &body),
-                moved_out_of_ref: moved_out_of_ref(&infcx, env, &body),
-                partially_moved: partially_moved(&infcx, env, &body),
-                borrow_regions: borrow_regions(db, &body),
-                mir_body: body,
+                owner,
+                mutability_of_locals: mutability_of_locals(&infcx, env, body),
+                moved_out_of_ref: moved_out_of_ref(&infcx, env, body),
+                partially_moved: partially_moved(&infcx, env, body),
+                borrow_regions: borrow_regions(db, body),
             }
         },
-        |parent, child| {
-            for (upvar, child_locals) in &child.mir_body.upvar_locals {
-                let Some(&parent_local) = parent.mir_body.binding_locals.get(*upvar) else {
+        |(parent, parent_mir_body), (child, child_mir_body)| {
+            for (upvar, child_locals) in &child_mir_body.upvar_locals {
+                let Some(&parent_local) = parent_mir_body.binding_locals.get(*upvar) else {
                     continue;
                 };
                 for (child_local, capture_place) in child_locals {
diff --git a/crates/hir-ty/src/mir/eval.rs b/crates/hir-ty/src/mir/eval.rs
index 87d64e5..104b90e 100644
--- a/crates/hir-ty/src/mir/eval.rs
+++ b/crates/hir-ty/src/mir/eval.rs
@@ -156,26 +156,26 @@
     }
 }
 
-struct StackFrame {
-    locals: Locals,
+struct StackFrame<'a> {
+    locals: Locals<'a>,
     destination: Option<BasicBlockId>,
     prev_stack_ptr: usize,
     span: (MirSpan, DefWithBodyId),
 }
 
 #[derive(Clone)]
-enum MirOrDynIndex {
-    Mir(Arc<MirBody>),
+enum MirOrDynIndex<'a> {
+    Mir(&'a MirBody),
     Dyn(usize),
 }
 
-pub struct Evaluator<'db> {
+pub struct Evaluator<'a, 'db> {
     db: &'db dyn HirDatabase,
     param_env: ParamEnvAndCrate<'db>,
-    target_data_layout: Arc<TargetDataLayout>,
+    target_data_layout: &'db TargetDataLayout,
     stack: Vec<u8>,
     heap: Vec<u8>,
-    code_stack: Vec<StackFrame>,
+    code_stack: Vec<StackFrame<'a>>,
     /// Stores the global location of the statics. We const evaluate every static first time we need it
     /// and see it's missing, then we add it to this to reuse.
     static_locations: FxHashMap<StaticId, Address>,
@@ -190,11 +190,11 @@
     layout_cache: RefCell<FxHashMap<Ty<'db>, Arc<Layout>>>,
     projected_ty_cache: RefCell<FxHashMap<(Ty<'db>, PlaceElem), Ty<'db>>>,
     not_special_fn_cache: RefCell<FxHashSet<FunctionId>>,
-    mir_or_dyn_index_cache: RefCell<FxHashMap<(FunctionId, GenericArgs<'db>), MirOrDynIndex>>,
+    mir_or_dyn_index_cache: RefCell<FxHashMap<(FunctionId, GenericArgs<'db>), MirOrDynIndex<'a>>>,
     /// Constantly dropping and creating `Locals` is very costly. We store
     /// old locals that we normally want to drop here, to reuse their allocations
     /// later.
-    unused_locals_store: RefCell<FxHashMap<DefWithBodyId, Vec<Locals>>>,
+    unused_locals_store: RefCell<FxHashMap<DefWithBodyId, Vec<Locals<'a>>>>,
     cached_ptr_size: usize,
     cached_fn_trait_func: Option<FunctionId>,
     cached_fn_mut_trait_func: Option<FunctionId>,
@@ -237,17 +237,21 @@
         Self { addr, size }
     }
 
-    fn get<'a, 'db>(&self, memory: &'a Evaluator<'db>) -> Result<'db, &'a [u8]> {
+    fn get<'b, 'a, 'db: 'a>(&self, memory: &'b Evaluator<'a, 'db>) -> Result<'db, &'b [u8]> {
         memory.read_memory(self.addr, self.size)
     }
 
-    fn write_from_bytes<'db>(&self, memory: &mut Evaluator<'db>, bytes: &[u8]) -> Result<'db, ()> {
+    fn write_from_bytes<'a, 'db: 'a>(
+        &self,
+        memory: &mut Evaluator<'a, 'db>,
+        bytes: &[u8],
+    ) -> Result<'db, ()> {
         memory.write_memory(self.addr, bytes)
     }
 
-    fn write_from_interval<'db>(
+    fn write_from_interval<'a, 'db: 'a>(
         &self,
-        memory: &mut Evaluator<'db>,
+        memory: &mut Evaluator<'a, 'db>,
         interval: Interval,
     ) -> Result<'db, ()> {
         memory.copy_from_interval(self.addr, interval)
@@ -259,16 +263,22 @@
 }
 
 impl<'db> IntervalAndTy<'db> {
-    fn get<'a>(&self, memory: &'a Evaluator<'db>) -> Result<'db, &'a [u8]> {
+    fn get<'b, 'a>(&self, memory: &'b Evaluator<'a, 'db>) -> Result<'db, &'b [u8]>
+    where
+        'db: 'a,
+    {
         memory.read_memory(self.interval.addr, self.interval.size)
     }
 
-    fn new(
+    fn new<'a>(
         addr: Address,
         ty: Ty<'db>,
-        evaluator: &Evaluator<'db>,
-        locals: &Locals,
-    ) -> Result<'db, IntervalAndTy<'db>> {
+        evaluator: &Evaluator<'a, 'db>,
+        locals: &Locals<'a>,
+    ) -> Result<'db, IntervalAndTy<'db>>
+    where
+        'db: 'a,
+    {
         let size = evaluator.size_of_sized(ty, locals, "type of interval")?;
         Ok(IntervalAndTy { interval: Interval { addr, size }, ty })
     }
@@ -286,7 +296,7 @@
 }
 
 impl IntervalOrOwned {
-    fn get<'a, 'db>(&'a self, memory: &'a Evaluator<'db>) -> Result<'db, &'a [u8]> {
+    fn get<'b, 'a, 'db: 'a>(&'b self, memory: &'b Evaluator<'a, 'db>) -> Result<'db, &'b [u8]> {
         Ok(match self {
             IntervalOrOwned::Owned(o) => o,
             IntervalOrOwned::Borrowed(b) => b.get(memory)?,
@@ -576,9 +586,9 @@
 }
 
 #[derive(Debug)]
-struct Locals {
+struct Locals<'a> {
     ptr: ArenaMap<LocalId, Interval>,
-    body: Arc<MirBody>,
+    body: &'a MirBody,
     drop_flags: DropFlags,
 }
 
@@ -596,9 +606,9 @@
     }
 }
 
-pub fn interpret_mir<'db>(
+pub fn interpret_mir<'a, 'db: 'a>(
     db: &'db dyn HirDatabase,
-    body: Arc<MirBody>,
+    body: &MirBody,
     // FIXME: This is workaround. Ideally, const generics should have a separate body (issue #7434), but now
     // they share their body with their parent, so in MIR lowering we have locals of the parent body, which
     // might have placeholders. With this argument, we (wrongly) assume that every placeholder type has
@@ -613,7 +623,7 @@
         if evaluator.ptr_size() != size_of::<usize>() {
             not_supported!("targets with different pointer size from host");
         }
-        let interval = evaluator.interpret_mir(body.clone(), None.into_iter())?;
+        let interval = evaluator.interpret_mir(body, None.into_iter())?;
         let bytes = interval.get(&evaluator)?;
         let mut memory_map = evaluator.create_memory_map(
             bytes,
@@ -638,13 +648,13 @@
 #[cfg(not(test))]
 const EXECUTION_LIMIT: usize = 10_000_000;
 
-impl<'db> Evaluator<'db> {
+impl<'a, 'db: 'a> Evaluator<'a, 'db> {
     pub fn new(
         db: &'db dyn HirDatabase,
         owner: DefWithBodyId,
         assert_placeholder_ty_is_unused: bool,
         trait_env: Option<ParamEnvAndCrate<'db>>,
-    ) -> Result<'db, Evaluator<'db>> {
+    ) -> Result<'db, Evaluator<'a, 'db>> {
         let module = owner.module(db);
         let crate_id = module.krate(db);
         let target_data_layout = match db.target_data_layout(crate_id) {
@@ -705,11 +715,11 @@
         self.infcx.interner.lang_items()
     }
 
-    fn place_addr(&self, p: &Place, locals: &Locals) -> Result<'db, Address> {
+    fn place_addr(&self, p: &Place, locals: &Locals<'a>) -> Result<'db, Address> {
         Ok(self.place_addr_and_ty_and_metadata(p, locals)?.0)
     }
 
-    fn place_interval(&self, p: &Place, locals: &Locals) -> Result<'db, Interval> {
+    fn place_interval(&self, p: &Place, locals: &Locals<'a>) -> Result<'db, Interval> {
         let place_addr_and_ty = self.place_addr_and_ty_and_metadata(p, locals)?;
         Ok(Interval {
             addr: place_addr_and_ty.0,
@@ -736,10 +746,10 @@
         r
     }
 
-    fn place_addr_and_ty_and_metadata<'a>(
-        &'a self,
+    fn place_addr_and_ty_and_metadata<'b>(
+        &'b self,
         p: &Place,
-        locals: &'a Locals,
+        locals: &'b Locals<'a>,
     ) -> Result<'db, (Address, Ty<'db>, Option<IntervalOrOwned>)> {
         let mut addr = locals.ptr[p.local].addr;
         let mut ty: Ty<'db> = locals.body.locals[p.local].ty.as_ref();
@@ -873,11 +883,11 @@
         self.layout(Ty::new_adt(self.interner(), adt, subst))
     }
 
-    fn place_ty<'a>(&'a self, p: &Place, locals: &'a Locals) -> Result<'db, Ty<'db>> {
+    fn place_ty<'b>(&'b self, p: &Place, locals: &'b Locals<'a>) -> Result<'db, Ty<'db>> {
         Ok(self.place_addr_and_ty_and_metadata(p, locals)?.1)
     }
 
-    fn operand_ty(&self, o: &Operand, locals: &Locals) -> Result<'db, Ty<'db>> {
+    fn operand_ty(&self, o: &Operand, locals: &Locals<'a>) -> Result<'db, Ty<'db>> {
         Ok(match &o.kind {
             OperandKind::Copy(p) | OperandKind::Move(p) => self.place_ty(p, locals)?,
             OperandKind::Constant { konst: _, ty } => ty.as_ref(),
@@ -898,7 +908,7 @@
     fn operand_ty_and_eval(
         &mut self,
         o: &Operand,
-        locals: &mut Locals,
+        locals: &mut Locals<'a>,
     ) -> Result<'db, IntervalAndTy<'db>> {
         Ok(IntervalAndTy {
             interval: self.eval_operand(o, locals)?,
@@ -908,7 +918,7 @@
 
     fn interpret_mir(
         &mut self,
-        body: Arc<MirBody>,
+        body: &'a MirBody,
         args: impl Iterator<Item = IntervalOrOwned>,
     ) -> Result<'db, Interval> {
         if let Some(it) = self.stack_depth_limit.checked_sub(1) {
@@ -917,8 +927,8 @@
             return Err(MirEvalError::StackOverflow);
         }
         let mut current_block_idx = body.start_block;
-        let (mut locals, prev_stack_ptr) = self.create_locals_for_body(&body, None)?;
-        self.fill_locals_for_body(&body, &mut locals, args)?;
+        let (mut locals, prev_stack_ptr) = self.create_locals_for_body(body, None)?;
+        self.fill_locals_for_body(body, &mut locals, args)?;
         let prev_code_stack = mem::take(&mut self.code_stack);
         let span = (MirSpan::Unknown, body.owner);
         self.code_stack.push(StackFrame { locals, destination: None, prev_stack_ptr, span });
@@ -1073,7 +1083,7 @@
     fn fill_locals_for_body(
         &mut self,
         body: &MirBody,
-        locals: &mut Locals,
+        locals: &mut Locals<'a>,
         args: impl Iterator<Item = IntervalOrOwned>,
     ) -> Result<'db, ()> {
         let mut remain_args = body.param_locals.len();
@@ -1096,19 +1106,15 @@
 
     fn create_locals_for_body(
         &mut self,
-        body: &Arc<MirBody>,
+        body: &'a MirBody,
         destination: Option<Interval>,
-    ) -> Result<'db, (Locals, usize)> {
+    ) -> Result<'db, (Locals<'a>, usize)> {
         let mut locals =
             match self.unused_locals_store.borrow_mut().entry(body.owner).or_default().pop() {
-                None => Locals {
-                    ptr: ArenaMap::new(),
-                    body: body.clone(),
-                    drop_flags: DropFlags::default(),
-                },
+                None => Locals { ptr: ArenaMap::new(), body, drop_flags: DropFlags::default() },
                 Some(mut l) => {
                     l.drop_flags.clear();
-                    l.body = body.clone();
+                    l.body = body;
                     l
                 }
             };
@@ -1145,7 +1151,7 @@
         Ok((locals, prev_stack_pointer))
     }
 
-    fn eval_rvalue(&mut self, r: &Rvalue, locals: &mut Locals) -> Result<'db, IntervalOrOwned> {
+    fn eval_rvalue(&mut self, r: &Rvalue, locals: &mut Locals<'a>) -> Result<'db, IntervalOrOwned> {
         use IntervalOrOwned::*;
         Ok(match r {
             Rvalue::Use(it) => Borrowed(self.eval_operand(it, locals)?),
@@ -1662,7 +1668,7 @@
                 Ok(r)
             }
             Variants::Multiple { tag, tag_encoding, variants, .. } => {
-                let size = tag.size(&*self.target_data_layout).bytes_usize();
+                let size = tag.size(self.target_data_layout).bytes_usize();
                 let offset = layout.fields.offset(0).bytes_usize(); // The only field on enum variants is the tag field
                 let is_signed = tag.is_signed();
                 match tag_encoding {
@@ -1804,7 +1810,7 @@
         &mut self,
         it: VariantId,
         subst: GenericArgs<'db>,
-        locals: &Locals,
+        locals: &Locals<'a>,
     ) -> Result<'db, (usize, Arc<Layout>, Option<(usize, usize, i128)>)> {
         let adt = it.adt_id(self.db);
         if let DefWithBodyId::VariantId(f) = locals.body.owner
@@ -1851,7 +1857,7 @@
                     if have_tag {
                         Some((
                             layout.fields.offset(0).bytes_usize(),
-                            tag.size(&*self.target_data_layout).bytes_usize(),
+                            tag.size(self.target_data_layout).bytes_usize(),
                             discriminant,
                         ))
                     } else {
@@ -1898,7 +1904,7 @@
         Ok(result)
     }
 
-    fn eval_operand(&mut self, it: &Operand, locals: &mut Locals) -> Result<'db, Interval> {
+    fn eval_operand(&mut self, it: &Operand, locals: &mut Locals<'a>) -> Result<'db, Interval> {
         Ok(match &it.kind {
             OperandKind::Copy(p) | OperandKind::Move(p) => {
                 locals.drop_flags.remove_place(p, &locals.body.projection_store);
@@ -2051,7 +2057,7 @@
     #[allow(clippy::double_parens)]
     fn allocate_const_in_heap(
         &mut self,
-        locals: &Locals,
+        locals: &Locals<'a>,
         konst: Const<'db>,
     ) -> Result<'db, Interval> {
         match konst.kind() {
@@ -2089,7 +2095,7 @@
 
     fn allocate_allocation_in_heap(
         &mut self,
-        locals: &Locals,
+        locals: &Locals<'a>,
         allocation: Allocation<'db>,
     ) -> Result<'db, Interval> {
         let AllocationData { ty, memory: ref v, ref memory_map } = *allocation;
@@ -2128,7 +2134,7 @@
         Ok(Interval::new(addr, size))
     }
 
-    fn eval_place(&mut self, p: &Place, locals: &Locals) -> Result<'db, Interval> {
+    fn eval_place(&mut self, p: &Place, locals: &Locals<'a>) -> Result<'db, Interval> {
         let addr = self.place_addr(p, locals)?;
         Ok(Interval::new(
             addr,
@@ -2228,7 +2234,11 @@
         Ok(())
     }
 
-    fn size_align_of(&self, ty: Ty<'db>, locals: &Locals) -> Result<'db, Option<(usize, usize)>> {
+    fn size_align_of(
+        &self,
+        ty: Ty<'db>,
+        locals: &Locals<'a>,
+    ) -> Result<'db, Option<(usize, usize)>> {
         if let Some(layout) = self.layout_cache.borrow().get(&ty) {
             return Ok(layout
                 .is_sized()
@@ -2257,7 +2267,7 @@
     fn size_of_sized(
         &self,
         ty: Ty<'db>,
-        locals: &Locals,
+        locals: &Locals<'a>,
         what: &'static str,
     ) -> Result<'db, usize> {
         match self.size_align_of(ty, locals)? {
@@ -2271,7 +2281,7 @@
     fn size_align_of_sized(
         &self,
         ty: Ty<'db>,
-        locals: &Locals,
+        locals: &Locals<'a>,
         what: &'static str,
     ) -> Result<'db, (usize, usize)> {
         match self.size_align_of(ty, locals)? {
@@ -2312,13 +2322,13 @@
         &self,
         bytes: &[u8],
         ty: Ty<'db>,
-        locals: &Locals,
+        locals: &Locals<'a>,
     ) -> Result<'db, ComplexMemoryMap<'db>> {
-        fn rec<'db>(
-            this: &Evaluator<'db>,
+        fn rec<'a, 'db: 'a>(
+            this: &Evaluator<'a, 'db>,
             bytes: &[u8],
             ty: Ty<'db>,
-            locals: &Locals,
+            locals: &Locals<'a>,
             mm: &mut ComplexMemoryMap<'db>,
             stack_depth_limit: usize,
         ) -> Result<'db, ()> {
@@ -2436,7 +2446,7 @@
                         if let Some((v, l)) = detect_variant_from_bytes(
                             &layout,
                             this.db,
-                            &this.target_data_layout,
+                            this.target_data_layout,
                             bytes,
                             e,
                         ) {
@@ -2487,7 +2497,7 @@
         ty_of_bytes: impl Fn(&[u8]) -> Result<'db, Ty<'db>> + Copy,
         addr: Address,
         ty: Ty<'db>,
-        locals: &Locals,
+        locals: &Locals<'a>,
     ) -> Result<'db, ()> {
         // FIXME: support indirect references
         let layout = self.layout(ty)?;
@@ -2546,7 +2556,7 @@
                     if let Some((ev, layout)) = detect_variant_from_bytes(
                         &layout,
                         self.db,
-                        &self.target_data_layout,
+                        self.target_data_layout,
                         self.read_memory(addr, layout.size.bytes_usize())?,
                         e,
                     ) {
@@ -2619,10 +2629,10 @@
         bytes: Interval,
         destination: Interval,
         args: &[IntervalAndTy<'db>],
-        locals: &Locals,
+        locals: &Locals<'a>,
         target_bb: Option<BasicBlockId>,
         span: MirSpan,
-    ) -> Result<'db, Option<StackFrame>> {
+    ) -> Result<'db, Option<StackFrame<'a>>> {
         let id = from_bytes!(usize, bytes.get(self)?);
         let next_ty = self.vtable_map.ty(id)?;
         use rustc_type_ir::TyKind;
@@ -2650,9 +2660,9 @@
         generic_args: GenericArgs<'db>,
         destination: Interval,
         args: &[IntervalAndTy<'db>],
-        locals: &Locals,
+        locals: &Locals<'a>,
         span: MirSpan,
-    ) -> Result<'db, Option<StackFrame>> {
+    ) -> Result<'db, Option<StackFrame<'a>>> {
         let mir_body = self
             .db
             .monomorphized_mir_body_for_closure(
@@ -2688,10 +2698,10 @@
         generic_args: GenericArgs<'db>,
         destination: Interval,
         args: &[IntervalAndTy<'db>],
-        locals: &Locals,
+        locals: &Locals<'a>,
         target_bb: Option<BasicBlockId>,
         span: MirSpan,
-    ) -> Result<'db, Option<StackFrame>> {
+    ) -> Result<'db, Option<StackFrame<'a>>> {
         match def {
             CallableDefId::FunctionId(def) => {
                 if self.detect_fn_trait(def).is_some() {
@@ -2746,9 +2756,9 @@
         &self,
         def: FunctionId,
         generic_args: GenericArgs<'db>,
-        locals: &Locals,
+        locals: &Locals<'a>,
         span: MirSpan,
-    ) -> Result<'db, MirOrDynIndex> {
+    ) -> Result<'db, MirOrDynIndex<'a>> {
         let pair = (def, generic_args);
         if let Some(r) = self.mir_or_dyn_index_cache.borrow().get(&pair) {
             return Ok(r.clone());
@@ -2788,11 +2798,11 @@
         mut def: FunctionId,
         args: &[IntervalAndTy<'db>],
         generic_args: GenericArgs<'db>,
-        locals: &Locals,
+        locals: &Locals<'a>,
         destination: Interval,
         target_bb: Option<BasicBlockId>,
         span: MirSpan,
-    ) -> Result<'db, Option<StackFrame>> {
+    ) -> Result<'db, Option<StackFrame<'a>>> {
         if self.detect_and_exec_special_function(
             def,
             args,
@@ -2854,18 +2864,18 @@
 
     fn exec_looked_up_function(
         &mut self,
-        mir_body: Arc<MirBody>,
-        locals: &Locals,
+        mir_body: &'a MirBody,
+        locals: &Locals<'a>,
         def: FunctionId,
         arg_bytes: impl Iterator<Item = IntervalOrOwned>,
         span: MirSpan,
         destination: Interval,
         target_bb: Option<BasicBlockId>,
-    ) -> Result<'db, Option<StackFrame>> {
+    ) -> Result<'db, Option<StackFrame<'a>>> {
         Ok(if let Some(target_bb) = target_bb {
             let (mut locals, prev_stack_ptr) =
-                self.create_locals_for_body(&mir_body, Some(destination))?;
-            self.fill_locals_for_body(&mir_body, &mut locals, arg_bytes.into_iter())?;
+                self.create_locals_for_body(mir_body, Some(destination))?;
+            self.fill_locals_for_body(mir_body, &mut locals, arg_bytes.into_iter())?;
             let span = (span, locals.body.owner);
             Some(StackFrame { locals, destination: Some(target_bb), prev_stack_ptr, span })
         } else {
@@ -2885,11 +2895,11 @@
         def: FunctionId,
         args: &[IntervalAndTy<'db>],
         generic_args: GenericArgs<'db>,
-        locals: &Locals,
+        locals: &Locals<'a>,
         destination: Interval,
         target_bb: Option<BasicBlockId>,
         span: MirSpan,
-    ) -> Result<'db, Option<StackFrame>> {
+    ) -> Result<'db, Option<StackFrame<'a>>> {
         let func = args
             .first()
             .ok_or_else(|| MirEvalError::InternalError("fn trait with no arg".into()))?;
@@ -2954,7 +2964,7 @@
         }
     }
 
-    fn eval_static(&mut self, st: StaticId, locals: &Locals) -> Result<'db, Address> {
+    fn eval_static(&mut self, st: StaticId, locals: &Locals<'a>) -> Result<'db, Address> {
         if let Some(o) = self.static_locations.get(&st) {
             return Ok(*o);
         };
@@ -3001,7 +3011,12 @@
         }
     }
 
-    fn drop_place(&mut self, place: &Place, locals: &mut Locals, span: MirSpan) -> Result<'db, ()> {
+    fn drop_place(
+        &mut self,
+        place: &Place,
+        locals: &mut Locals<'a>,
+        span: MirSpan,
+    ) -> Result<'db, ()> {
         let (addr, ty, metadata) = self.place_addr_and_ty_and_metadata(place, locals)?;
         if !locals.drop_flags.remove_place(place, &locals.body.projection_store) {
             return Ok(());
@@ -3016,7 +3031,7 @@
     fn run_drop_glue_deep(
         &mut self,
         ty: Ty<'db>,
-        locals: &Locals,
+        locals: &Locals<'a>,
         addr: Address,
         _metadata: &[u8],
         span: MirSpan,
diff --git a/crates/hir-ty/src/mir/eval/shim.rs b/crates/hir-ty/src/mir/eval/shim.rs
index 4154760..a0978bd 100644
--- a/crates/hir-ty/src/mir/eval/shim.rs
+++ b/crates/hir-ty/src/mir/eval/shim.rs
@@ -29,13 +29,13 @@
     DropInPlace,
 }
 
-impl<'db> Evaluator<'db> {
+impl<'a, 'db: 'a> Evaluator<'a, 'db> {
     pub(super) fn detect_and_exec_special_function(
         &mut self,
         def: FunctionId,
         args: &[IntervalAndTy<'db>],
         generic_args: GenericArgs<'db>,
-        locals: &Locals,
+        locals: &Locals<'a>,
         destination: Interval,
         span: MirSpan,
     ) -> Result<'db, bool> {
@@ -132,7 +132,7 @@
         def: FunctionId,
         args: &[IntervalAndTy<'db>],
         self_ty: Ty<'db>,
-        locals: &Locals,
+        locals: &Locals<'a>,
         destination: Interval,
         span: MirSpan,
     ) -> Result<'db, ()> {
@@ -190,7 +190,7 @@
         layout: Arc<Layout>,
         addr: Address,
         def: FunctionId,
-        locals: &Locals,
+        locals: &Locals<'a>,
         destination: Interval,
         span: MirSpan,
     ) -> Result<'db, ()> {
@@ -296,7 +296,7 @@
         it: EvalLangItem,
         generic_args: GenericArgs<'db>,
         args: &[IntervalAndTy<'db>],
-        locals: &Locals,
+        locals: &Locals<'a>,
         span: MirSpan,
     ) -> Result<'db, Vec<u8>> {
         use EvalLangItem::*;
@@ -368,7 +368,7 @@
         id: i64,
         args: &[IntervalAndTy<'db>],
         destination: Interval,
-        _locals: &Locals,
+        _locals: &Locals<'a>,
         _span: MirSpan,
     ) -> Result<'db, ()> {
         match id {
@@ -399,7 +399,7 @@
         args: &[IntervalAndTy<'db>],
         _generic_args: GenericArgs<'db>,
         destination: Interval,
-        locals: &Locals,
+        locals: &Locals<'a>,
         span: MirSpan,
     ) -> Result<'db, ()> {
         match as_str {
@@ -563,7 +563,7 @@
         args: &[IntervalAndTy<'db>],
         generic_args: GenericArgs<'db>,
         destination: Interval,
-        locals: &Locals,
+        locals: &Locals<'a>,
         span: MirSpan,
         needs_override: bool,
     ) -> Result<'db, bool> {
@@ -1345,7 +1345,7 @@
         &mut self,
         ty: Ty<'db>,
         metadata: Interval,
-        locals: &Locals,
+        locals: &Locals<'a>,
     ) -> Result<'db, (usize, usize)> {
         Ok(match ty.kind() {
             TyKind::Str => (from_bytes!(usize, metadata.get(self)?), 1),
@@ -1404,7 +1404,7 @@
         args: &[IntervalAndTy<'db>],
         generic_args: GenericArgs<'db>,
         destination: Interval,
-        locals: &Locals,
+        locals: &Locals<'a>,
         _span: MirSpan,
     ) -> Result<'db, ()> {
         // We are a single threaded runtime with no UB checking and no optimization, so
diff --git a/crates/hir-ty/src/mir/eval/shim/simd.rs b/crates/hir-ty/src/mir/eval/shim/simd.rs
index 6e20562..2458597 100644
--- a/crates/hir-ty/src/mir/eval/shim/simd.rs
+++ b/crates/hir-ty/src/mir/eval/shim/simd.rs
@@ -6,7 +6,7 @@
 
 use super::*;
 
-impl<'db> Evaluator<'db> {
+impl<'a, 'db: 'a> Evaluator<'a, 'db> {
     fn detect_simd_ty(&self, ty: Ty<'db>) -> Result<'db, (usize, Ty<'db>)> {
         match ty.kind() {
             TyKind::Adt(adt_def, subst) => {
@@ -53,7 +53,7 @@
         args: &[IntervalAndTy<'db>],
         _generic_args: GenericArgs<'db>,
         destination: Interval,
-        _locals: &Locals,
+        _locals: &Locals<'a>,
         _span: MirSpan,
     ) -> Result<'db, ()> {
         match name {
diff --git a/crates/hir-ty/src/mir/lower.rs b/crates/hir-ty/src/mir/lower.rs
index 9c9cf0a..b2a7eaa 100644
--- a/crates/hir-ty/src/mir/lower.rs
+++ b/crates/hir-ty/src/mir/lower.rs
@@ -25,7 +25,6 @@
 use rustc_type_ir::inherent::{Const as _, GenericArgs as _, IntoKind, Ty as _};
 use span::{Edition, FileId};
 use syntax::TextRange;
-use triomphe::Arc;
 
 use crate::{
     Adjust, Adjustment, AutoBorrow, CallableDefId, ParamEnvAndCrate,
@@ -2137,10 +2136,11 @@
     })
 }
 
+#[salsa_macros::tracked(returns(ref), cycle_result = mir_body_for_closure_cycle_result)]
 pub fn mir_body_for_closure_query<'db>(
     db: &'db dyn HirDatabase,
     closure: InternedClosureId,
-) -> Result<'db, Arc<MirBody>> {
+) -> Result<'db, MirBody> {
     let InternedClosure { owner, expr, .. } = closure.loc(db);
     let body_owner =
         owner.as_def_with_body().expect("MIR lowering should only happen for body-owned closures");
@@ -2293,13 +2293,11 @@
         return Err(MirLowerError::UnresolvedUpvar(err));
     }
     ctx.result.shrink_to_fit();
-    Ok(Arc::new(ctx.result))
+    Ok(ctx.result)
 }
 
-pub fn mir_body_query<'db>(
-    db: &'db dyn HirDatabase,
-    def: DefWithBodyId,
-) -> Result<'db, Arc<MirBody>> {
+#[salsa_macros::tracked(returns(ref), cycle_result = mir_body_cycle_result)]
+pub fn mir_body_query<'db>(db: &'db dyn HirDatabase, def: DefWithBodyId) -> Result<'db, MirBody> {
     let krate = def.krate(db);
     let edition = krate.data(db).edition;
     let detail = match def {
@@ -2328,14 +2326,22 @@
     let infer = InferenceResult::of(db, def);
     let mut result = lower_body_to_mir(db, def, body, infer, body.root_expr())?;
     result.shrink_to_fit();
-    Ok(Arc::new(result))
+    Ok(result)
 }
 
-pub(crate) fn mir_body_cycle_result<'db>(
+fn mir_body_cycle_result<'db>(
     _db: &'db dyn HirDatabase,
     _: salsa::Id,
     _def: DefWithBodyId,
-) -> Result<'db, Arc<MirBody>> {
+) -> Result<'db, MirBody> {
+    Err(MirLowerError::Loop)
+}
+
+fn mir_body_for_closure_cycle_result<'db>(
+    _db: &'db dyn HirDatabase,
+    _: salsa::Id,
+    _def: InternedClosureId,
+) -> Result<'db, MirBody> {
     Err(MirLowerError::Loop)
 }
 
diff --git a/crates/hir-ty/src/mir/monomorphization.rs b/crates/hir-ty/src/mir/monomorphization.rs
index dfce8ca..b352943 100644
--- a/crates/hir-ty/src/mir/monomorphization.rs
+++ b/crates/hir-ty/src/mir/monomorphization.rs
@@ -12,7 +12,6 @@
 use rustc_type_ir::{
     FallibleTypeFolder, TypeFlags, TypeFoldable, TypeSuperFoldable, TypeVisitableExt,
 };
-use triomphe::Arc;
 
 use crate::{
     ParamEnvAndCrate,
@@ -240,38 +239,50 @@
     }
 }
 
+#[salsa_macros::tracked(returns(ref), cycle_result = monomorphized_mir_body_cycle_result)]
 pub fn monomorphized_mir_body_query(
     db: &dyn HirDatabase,
     owner: DefWithBodyId,
     subst: StoredGenericArgs,
     trait_env: StoredParamEnvAndCrate,
-) -> Result<Arc<MirBody>, MirLowerError> {
+) -> Result<MirBody, MirLowerError> {
     let mut filler = Filler::new(db, trait_env.as_ref(), subst.as_ref());
     let body = db.mir_body(owner)?;
     let mut body = (*body).clone();
     filler.fill_body(&mut body)?;
-    Ok(Arc::new(body))
+    Ok(body)
 }
 
-pub(crate) fn monomorphized_mir_body_cycle_result(
+fn monomorphized_mir_body_cycle_result(
     _db: &dyn HirDatabase,
     _: salsa::Id,
     _: DefWithBodyId,
     _: StoredGenericArgs,
     _: StoredParamEnvAndCrate,
-) -> Result<Arc<MirBody>, MirLowerError> {
+) -> Result<MirBody, MirLowerError> {
     Err(MirLowerError::Loop)
 }
 
+#[salsa_macros::tracked(returns(ref), cycle_result = monomorphized_mir_body_for_closure_cycle_result)]
 pub fn monomorphized_mir_body_for_closure_query(
     db: &dyn HirDatabase,
     closure: InternedClosureId,
     subst: StoredGenericArgs,
     trait_env: StoredParamEnvAndCrate,
-) -> Result<Arc<MirBody>, MirLowerError> {
+) -> Result<MirBody, MirLowerError> {
     let mut filler = Filler::new(db, trait_env.as_ref(), subst.as_ref());
     let body = db.mir_body_for_closure(closure)?;
     let mut body = (*body).clone();
     filler.fill_body(&mut body)?;
-    Ok(Arc::new(body))
+    Ok(body)
+}
+
+fn monomorphized_mir_body_for_closure_cycle_result(
+    _db: &dyn HirDatabase,
+    _: salsa::Id,
+    _: InternedClosureId,
+    _: StoredGenericArgs,
+    _: StoredParamEnvAndCrate,
+) -> Result<MirBody, MirLowerError> {
+    Err(MirLowerError::Loop)
 }
diff --git a/crates/hir-ty/src/mir/pretty.rs b/crates/hir-ty/src/mir/pretty.rs
index de5ee22..c224f20 100644
--- a/crates/hir-ty/src/mir/pretty.rs
+++ b/crates/hir-ty/src/mir/pretty.rs
@@ -160,7 +160,7 @@
         let result = mem::take(&mut self.result);
         let indent = mem::take(&mut self.indent);
         let mut ctx = MirPrettyCtx {
-            body: &body,
+            body,
             local_to_binding: body.local_to_binding_map(),
             result,
             indent,
diff --git a/crates/hir/src/diagnostics.rs b/crates/hir/src/diagnostics.rs
index 5d3e117..168854d 100644
--- a/crates/hir/src/diagnostics.rs
+++ b/crates/hir/src/diagnostics.rs
@@ -87,6 +87,7 @@
     PrivateField,
     RemoveTrailingReturn,
     RemoveUnnecessaryElse,
+    UnusedMustUse,
     ReplaceFilterMapNextWithFindMap,
     TraitImplIncorrectSafety,
     TraitImplMissingAssocItems,
@@ -407,6 +408,11 @@
 }
 
 #[derive(Debug)]
+pub struct UnusedMustUse {
+    pub expr: InFile<ExprOrPatPtr>,
+}
+
+#[derive(Debug)]
 pub struct CastToUnsized<'db> {
     pub expr: InFile<ExprOrPatPtr>,
     pub cast_ty: Type<'db>,
@@ -637,6 +643,11 @@
                     );
                 }
             }
+            BodyValidationDiagnostic::UnusedMustUse { expr } => {
+                if let Ok(source_ptr) = source_map.expr_syntax(expr) {
+                    return Some(UnusedMustUse { expr: source_ptr }.into());
+                }
+            }
         }
         None
     }
diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs
index 6f55086..b74f594 100644
--- a/crates/hir/src/lib.rs
+++ b/crates/hir/src/lib.rs
@@ -1120,7 +1120,7 @@
     let Some(e) = db.parse_macro_expansion_error(macro_call_id) else {
         return;
     };
-    let ValueResult { value: parse_errors, err } = &*e;
+    let ValueResult { value: parse_errors, err } = e;
     if let Some(err) = err {
         let loc = db.lookup_intern_macro_call(macro_call_id);
         let file_id = loc.kind.file_id();
@@ -1436,7 +1436,7 @@
         Type::new(db, var_id, ty)
     }
 
-    pub fn layout(&self, db: &dyn HirDatabase) -> Result<Layout, LayoutError> {
+    pub fn layout<'db>(&self, db: &'db dyn HirDatabase) -> Result<Layout<'db>, LayoutError> {
         db.layout_of_ty(
             self.ty(db).ty.store(),
             param_env_from_has_crate(
@@ -1696,7 +1696,7 @@
         self.variants(db).iter().any(|v| !matches!(v.kind(db), StructKind::Unit))
     }
 
-    pub fn layout(self, db: &dyn HirDatabase) -> Result<Layout, LayoutError> {
+    pub fn layout<'db>(self, db: &'db dyn HirDatabase) -> Result<Layout<'db>, LayoutError> {
         Adt::from(self).layout(db)
     }
 
@@ -1783,7 +1783,7 @@
         db.const_eval_discriminant(self.into())
     }
 
-    pub fn layout(&self, db: &dyn HirDatabase) -> Result<Layout, LayoutError> {
+    pub fn layout<'db>(&self, db: &'db dyn HirDatabase) -> Result<Layout<'db>, LayoutError> {
         let parent_enum = self.parent_enum(db);
         let parent_layout = parent_enum.layout(db)?;
         Ok(match &parent_layout.0.variants {
@@ -1866,7 +1866,7 @@
         has_non_default_type_params(db, self.into())
     }
 
-    pub fn layout(self, db: &dyn HirDatabase) -> Result<Layout, LayoutError> {
+    pub fn layout<'db>(self, db: &'db dyn HirDatabase) -> Result<Layout<'db>, LayoutError> {
         let interner = DbInterner::new_no_crate(db);
         let adt_id = AdtId::from(self);
         let args = GenericArgs::for_item_with_defaults(interner, adt_id.into(), |_, id, _| {
@@ -2211,7 +2211,7 @@
 
         if let Ok(borrowck_results) = db.borrowck(id) {
             for borrowck_result in borrowck_results.iter() {
-                let mir_body = &borrowck_result.mir_body;
+                let mir_body = borrowck_result.mir_body(db);
                 for moof in &borrowck_result.moved_out_of_ref {
                     let span: InFile<SyntaxNodePtr> = match moof.span {
                         mir::MirSpan::ExprId(e) => match source_map.expr_syntax(e) {
@@ -6530,7 +6530,7 @@
             .collect()
     }
 
-    pub fn layout(&self, db: &'db dyn HirDatabase) -> Result<Layout, LayoutError> {
+    pub fn layout(&self, db: &'db dyn HirDatabase) -> Result<Layout<'db>, LayoutError> {
         db.layout_of_ty(self.ty.store(), self.env.store())
             .map(|layout| Layout(layout, db.target_data_layout(self.env.krate).unwrap()))
     }
@@ -6702,9 +6702,9 @@
 }
 
 #[derive(Clone, Debug, Eq, PartialEq)]
-pub struct Layout(Arc<TyLayout>, Arc<TargetDataLayout>);
+pub struct Layout<'db>(Arc<TyLayout>, &'db TargetDataLayout);
 
-impl Layout {
+impl<'db> Layout<'db> {
     pub fn size(&self) -> u64 {
         self.0.size.bytes()
     }
@@ -6714,7 +6714,7 @@
     }
 
     pub fn niches(&self) -> Option<u128> {
-        Some(self.0.largest_niche?.available(&*self.1))
+        Some(self.0.largest_niche?.available(self.1))
     }
 
     pub fn field_offset(&self, field: Field) -> Option<u64> {
@@ -6803,7 +6803,7 @@
         let tag_size =
             if let layout::Variants::Multiple { tag, tag_encoding, .. } = &self.0.variants {
                 match tag_encoding {
-                    TagEncoding::Direct => tag.size(&*self.1).bytes_usize(),
+                    TagEncoding::Direct => tag.size(self.1).bytes_usize(),
                     TagEncoding::Niche { .. } => 0,
                 }
             } else {
diff --git a/crates/hir/src/term_search/tactics.rs b/crates/hir/src/term_search/tactics.rs
index b11f7a1..99ad1e0 100644
--- a/crates/hir/src/term_search/tactics.rs
+++ b/crates/hir/src/term_search/tactics.rs
@@ -56,11 +56,12 @@
                     let borrowck = db.borrowck(it.parent.as_def_with_body()?).ok()?;
 
                     let invalid = borrowck.iter().any(|b| {
+                        let mir_body = b.mir_body(ctx.sema.db);
                         b.partially_moved.iter().any(|moved| {
-                            Some(&moved.local) == b.mir_body.binding_locals.get(it.binding_id)
+                            Some(&moved.local) == mir_body.binding_locals.get(it.binding_id)
                         }) || b.borrow_regions.iter().any(|region| {
                             // Shared borrows are fine
-                            Some(&region.local) == b.mir_body.binding_locals.get(it.binding_id)
+                            Some(&region.local) == mir_body.binding_locals.get(it.binding_id)
                                 && region.kind != BorrowKind::Shared
                         })
                     });
diff --git a/crates/ide-assists/src/handlers/extract_function.rs b/crates/ide-assists/src/handlers/extract_function.rs
index a8aa0d6..44123dc 100644
--- a/crates/ide-assists/src/handlers/extract_function.rs
+++ b/crates/ide-assists/src/handlers/extract_function.rs
@@ -34,7 +34,7 @@
 use crate::{
     AssistId,
     assist_context::{AssistContext, Assists},
-    utils::generate_impl,
+    utils::generate_impl_with_item,
 };
 
 // Assist: extract_function
@@ -161,8 +161,8 @@
                 Some(adt) if anchor == Anchor::Method && !has_impl_wrapper => {
                     let fn_def = fn_def.indent_with_mapping(1.into(), make);
 
-                    let impl_ = generate_impl(make, &adt).indent(new_indent);
-                    impl_.get_or_create_assoc_item_list().add_item(fn_def.into());
+                    let body = make.assoc_item_list([fn_def.into()]);
+                    let impl_ = generate_impl_with_item(make, &adt, Some(body)).indent(new_indent);
 
                     impl_.syntax().clone()
                 }
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 e99dd81..3902ee1 100644
--- a/crates/ide-assists/src/handlers/generate_blanket_trait_impl.rs
+++ b/crates/ide-assists/src/handlers/generate_blanket_trait_impl.rs
@@ -91,6 +91,23 @@
             let trait_gen_args =
                 traitd.generic_param_list().map(|param_list| param_list.to_generic_args());
 
+            let body = traitd.assoc_item_list().and_then(|trait_assoc_list| {
+                let items = trait_assoc_list
+                    .assoc_items()
+                    .filter_map(|item| {
+                        let item = match item {
+                            ast::AssocItem::Fn(method) if method.body().is_none() => {
+                                todo_fn(make, &method, ctx.config).into()
+                            }
+                            ast::AssocItem::Const(_) | ast::AssocItem::TypeAlias(_) => item,
+                            _ => return None,
+                        };
+                        Some(item.reset_indent().indent(1.into()))
+                    })
+                    .collect::<Vec<_>>();
+                (!items.is_empty()).then(|| make.assoc_item_list(items))
+            });
+
             let impl_ = make.impl_trait(
                 cfg_attrs(&traitd),
                 is_unsafe,
@@ -103,23 +120,9 @@
                 thisty.into(),
                 trait_where_clause,
                 None,
-                None,
+                body,
             );
 
-            if let Some(trait_assoc_list) = traitd.assoc_item_list() {
-                let assoc_item_list = impl_.get_or_create_assoc_item_list_with_editor(&editor);
-                for item in trait_assoc_list.assoc_items() {
-                    let item = match item {
-                        ast::AssocItem::Fn(method) if method.body().is_none() => {
-                            todo_fn(make, &method, ctx.config).into()
-                        }
-                        ast::AssocItem::Const(_) | ast::AssocItem::TypeAlias(_) => item,
-                        _ => continue,
-                    };
-                    assoc_item_list.add_item(item.reset_indent().indent(1.into()));
-                }
-            }
-
             let impl_ = impl_.indent(indent);
 
             editor.insert_all(
diff --git a/crates/ide-assists/src/handlers/inline_call.rs b/crates/ide-assists/src/handlers/inline_call.rs
index d95456f..5299680 100644
--- a/crates/ide-assists/src/handlers/inline_call.rs
+++ b/crates/ide-assists/src/handlers/inline_call.rs
@@ -560,7 +560,7 @@
         let inline_direct = |editor: &SyntaxEditor, usage: &PathExpr, replacement: &ast::Expr| {
             if let Some(field) = path_expr_as_record_field(usage) {
                 cov_mark::hit!(inline_call_inline_direct_field);
-                field.replace_expr_with_editor(editor, replacement.clone());
+                field.replace_expr(editor, replacement.clone());
             } else {
                 editor.replace(usage.syntax(), replacement.syntax());
             }
diff --git a/crates/ide-diagnostics/src/handlers/unused_must_use.rs b/crates/ide-diagnostics/src/handlers/unused_must_use.rs
new file mode 100644
index 0000000..4b9ecf2
--- /dev/null
+++ b/crates/ide-diagnostics/src/handlers/unused_must_use.rs
@@ -0,0 +1,110 @@
+use crate::{Diagnostic, DiagnosticCode, DiagnosticsContext};
+
+// Diagnostic: unused-must-use
+//
+// This diagnostic is triggered when a value with the `#[must_use]` attribute
+// is dropped without being used.
+pub(crate) fn unused_must_use(
+    ctx: &DiagnosticsContext<'_, '_>,
+    d: &hir::UnusedMustUse,
+) -> Diagnostic {
+    Diagnostic::new_with_syntax_node_ptr(
+        ctx,
+        DiagnosticCode::RustcLint("unused_must_use"),
+        "unused return value that must be used",
+        d.expr.map(Into::into),
+    )
+    .stable()
+}
+
+#[cfg(test)]
+mod tests {
+    use crate::tests::check_diagnostics;
+
+    #[test]
+    fn unused_must_use_function_call() {
+        check_diagnostics(
+            r#"
+#[must_use]
+fn produces() -> i32 { 0 }
+fn main() {
+    produces();
+  //^^^^^^^^^^ warn: unused return value that must be used
+}
+"#,
+        );
+    }
+
+    #[test]
+    fn unused_must_use_method_call() {
+        check_diagnostics(
+            r#"
+struct S;
+impl S {
+    #[must_use]
+    fn produces(&self) -> i32 { 0 }
+}
+fn main() {
+    let s = S;
+    s.produces();
+  //^^^^^^^^^^^^ warn: unused return value that must be used
+}
+"#,
+        );
+    }
+
+    #[test]
+    fn unused_must_use_type() {
+        check_diagnostics(
+            r#"
+#[must_use]
+struct Important;
+fn produces() -> Important { Important }
+fn main() {
+    produces();
+  //^^^^^^^^^^ warn: unused return value that must be used
+}
+"#,
+        );
+    }
+
+    #[test]
+    fn no_warning_when_value_used() {
+        check_diagnostics(
+            r#"
+#[must_use]
+fn produces() -> i32 { 0 }
+fn main() {
+    let _x = produces();
+}
+"#,
+        );
+    }
+
+    #[test]
+    fn no_warning_when_no_must_use_attribute() {
+        check_diagnostics(
+            r#"
+fn ordinary() -> i32 { 0 }
+fn main() {
+    ordinary();
+}
+"#,
+        );
+    }
+
+    #[test]
+    fn no_warning_when_value_assigned() {
+        check_diagnostics(
+            r#"
+#[must_use]
+fn produces() -> i32 { 0 }
+fn main() {
+    let x;
+    x = produces();
+    let _ = x;
+}
+"#,
+        );
+    }
+}
diff --git a/crates/ide-diagnostics/src/lib.rs b/crates/ide-diagnostics/src/lib.rs
index d029b8d..3f803a8 100644
--- a/crates/ide-diagnostics/src/lib.rs
+++ b/crates/ide-diagnostics/src/lib.rs
@@ -83,6 +83,7 @@
     pub(crate) mod unresolved_macro_call;
     pub(crate) mod unresolved_method;
     pub(crate) mod unresolved_module;
+    pub(crate) mod unused_must_use;
     pub(crate) mod unused_variables;
 
     // The handlers below are unusual, the implement the diagnostics as well.
@@ -463,6 +464,7 @@
             AnyDiagnostic::UnresolvedMacroCall(d) => handlers::unresolved_macro_call::unresolved_macro_call(&ctx, &d),
             AnyDiagnostic::UnresolvedMethodCall(d) => handlers::unresolved_method::unresolved_method(&ctx, &d),
             AnyDiagnostic::UnresolvedModule(d) => handlers::unresolved_module::unresolved_module(&ctx, &d),
+            AnyDiagnostic::UnusedMustUse(d) => handlers::unused_must_use::unused_must_use(&ctx, &d),
             AnyDiagnostic::UnusedMut(d) => match handlers::mutability_errors::unused_mut(&ctx, &d) {
                 Some(it) => it,
                 None => continue,
diff --git a/crates/ide/src/hover/render.rs b/crates/ide/src/hover/render.rs
index 4f60321..e08bbc5 100644
--- a/crates/ide/src/hover/render.rs
+++ b/crates/ide/src/hover/render.rs
@@ -1136,12 +1136,12 @@
     }
 }
 
-fn render_memory_layout(
+fn render_memory_layout<'db>(
     config: Option<MemoryLayoutHoverConfig>,
-    layout: impl FnOnce() -> Result<Layout, LayoutError>,
-    offset: impl FnOnce(&Layout) -> Option<u64>,
-    padding: impl FnOnce(&Layout) -> Option<(&str, u64)>,
-    tag: impl FnOnce(&Layout) -> Option<usize>,
+    layout: impl FnOnce() -> Result<Layout<'db>, LayoutError>,
+    offset: impl FnOnce(&Layout<'db>) -> Option<u64>,
+    padding: impl for<'a> FnOnce(&'a Layout<'db>) -> Option<(&'a str, u64)>,
+    tag: impl FnOnce(&Layout<'db>) -> Option<usize>,
 ) -> Option<String> {
     let config = config?;
     let layout = layout().ok()?;
diff --git a/crates/ide/src/rename.rs b/crates/ide/src/rename.rs
index 2c6116f..6d1e141 100644
--- a/crates/ide/src/rename.rs
+++ b/crates/ide/src/rename.rs
@@ -16,7 +16,7 @@
 use stdx::{always, format_to, never};
 use syntax::{
     AstNode, SyntaxKind, SyntaxNode, TextRange, TextSize,
-    ast::{self, HasArgList, prec::ExprPrecedence},
+    ast::{self, HasArgList, make, prec::ExprPrecedence},
 };
 
 use ide_db::text_edit::TextEdit;
@@ -79,7 +79,10 @@
     let sema = Semantics::new(db);
     let source_file = sema.parse_guess_edition(position.file_id);
     let syntax = source_file.syntax();
-
+    if let Some(lifetime_token) = syntax.token_at_offset(position.offset).find(|t| t.text() == "'_")
+    {
+        return Ok(RangeInfo::new(lifetime_token.text_range(), ()));
+    }
     let res = find_definitions(&sema, syntax, position, &Name::new_symbol_root(sym::underscore))?
         .filter(|(_, _, def, _, _)| def.range_for_rename(&sema).is_some())
         .map(|(frange, kind, _, _, _)| {
@@ -133,6 +136,13 @@
 
     let edition = file_id.edition(db);
     let (new_name, kind) = IdentifierKind::classify(edition, new_name)?;
+    if kind == IdentifierKind::Lifetime
+        && let Some(lifetime_token) =
+            syntax.token_at_offset(position.offset).find(|t| t.text() == "'_")
+    {
+        let new_name_str = new_name.display(db, edition).to_string();
+        return rename_elided_lifetime(position, lifetime_token, &new_name_str);
+    }
 
     let defs = find_definitions(&sema, syntax, position, &new_name)?;
     let alias_fallback =
@@ -797,6 +807,30 @@
     Some(TextEdit::replace(self_param.syntax().text_range(), replacement_text))
 }
 
+fn rename_elided_lifetime(
+    position: FilePosition,
+    lifetime_token: syntax::SyntaxToken,
+    new_name: &str,
+) -> RenameResult<SourceChange> {
+    let parent = lifetime_token.parent().unwrap();
+    let root = parent.ancestors().last().unwrap();
+
+    let mut builder = SourceChangeBuilder::new(position.file_id);
+
+    let editor = builder.make_editor(&root);
+
+    editor.replace(lifetime_token, make::lifetime(new_name).syntax().clone());
+
+    if let Some(has_generic_params) = parent.ancestors().find_map(ast::AnyHasGenericParams::cast) {
+        let lifetime_param = make::lifetime_param(make::lifetime(new_name));
+        editor.add_generic_param(&has_generic_params, lifetime_param.into());
+    }
+
+    builder.add_file_edits(position.file_id, editor);
+
+    Ok(builder.finish())
+}
+
 #[cfg(test)]
 mod tests {
     use expect_test::{Expect, expect};
@@ -3989,4 +4023,60 @@
         "#,
         );
     }
+
+    #[test]
+    fn test_rename_elided_lifetime_fn_no_generics() {
+        check(
+            "'a",
+            r#"
+fn foo(x: &'_$0 str) {}
+"#,
+            r#"
+fn foo<'a>(x: &'a str) {}
+"#,
+        );
+    }
+
+    #[test]
+    fn test_rename_elided_lifetime_fn_with_generics() {
+        check(
+            "'a",
+            r#"
+fn foo<T>(x: &'_$0 str, y: T) {}
+"#,
+            r#"
+fn foo<'a, T>(x: &'a str, y: T) {}
+"#,
+        );
+    }
+
+    #[test]
+    fn test_rename_elided_lifetime_impl_no_generics() {
+        check(
+            "'a",
+            r#"
+struct Foo<'a>(&'a str);
+impl Foo<'_$0> {}
+"#,
+            r#"
+struct Foo<'a>(&'a str);
+impl<'a> Foo<'a> {}
+"#,
+        );
+    }
+
+    #[test]
+    fn test_rename_elided_lifetime_impl_with_generics() {
+        check(
+            "'a",
+            r#"
+struct Foo<'a, T>(&'a str, T);
+impl<T> Foo<'_$0, T> {}
+"#,
+            r#"
+struct Foo<'a, T>(&'a str, T);
+impl<'a, T> Foo<'a, T> {}
+"#,
+        );
+    }
 }
diff --git a/crates/ide/src/view_memory_layout.rs b/crates/ide/src/view_memory_layout.rs
index 47ca616..1b9df97 100644
--- a/crates/ide/src/view_memory_layout.rs
+++ b/crates/ide/src/view_memory_layout.rs
@@ -108,7 +108,7 @@
         nodes: &mut Vec<MemoryLayoutNode>,
         db: &RootDatabase,
         ty: &Type<'_>,
-        layout: &Layout,
+        layout: &Layout<'_>,
         parent_idx: usize,
         display_target: DisplayTarget,
     ) {
diff --git a/crates/intern/src/symbol/symbols.rs b/crates/intern/src/symbol/symbols.rs
index c0053a3..db3c3c5 100644
--- a/crates/intern/src/symbol/symbols.rs
+++ b/crates/intern/src/symbol/symbols.rs
@@ -332,6 +332,7 @@
     module_path,
     mul_assign,
     mul,
+    must_use,
     naked_asm,
     ne,
     neg,
diff --git a/crates/syntax/src/ast/edit_in_place.rs b/crates/syntax/src/ast/edit_in_place.rs
index 5396826..a893f65 100644
--- a/crates/syntax/src/ast/edit_in_place.rs
+++ b/crates/syntax/src/ast/edit_in_place.rs
@@ -10,11 +10,11 @@
     SyntaxNode, SyntaxToken,
     algo::{self, neighbor},
     ast::{self, edit::IndentLevel, make},
-    syntax_editor::SyntaxEditor,
+    syntax_editor::{self, SyntaxEditor},
     ted,
 };
 
-use super::{GenericParam, HasName};
+use super::HasName;
 
 pub trait AttrsOwnerEdit: ast::HasAttrs {
     fn remove_attrs_and_docs(&self) {
@@ -43,24 +43,6 @@
 impl<T: ast::HasAttrs> AttrsOwnerEdit for T {}
 
 impl ast::GenericParamList {
-    pub fn add_generic_param(&self, generic_param: ast::GenericParam) {
-        match self.generic_params().last() {
-            Some(last_param) => {
-                let position = ted::Position::after(last_param.syntax());
-                let elements = vec![
-                    make::token(T![,]).into(),
-                    make::tokens::single_space().into(),
-                    generic_param.syntax().clone().into(),
-                ];
-                ted::insert_all(position, elements);
-            }
-            None => {
-                let after_l_angle = ted::Position::after(self.l_angle_token().unwrap());
-                ted::insert(after_l_angle, generic_param.syntax());
-            }
-        }
-    }
-
     /// Removes the existing generic param
     pub fn remove_generic_param(&self, generic_param: ast::GenericParam) {
         if let Some(previous) = generic_param.syntax().prev_sibling() {
@@ -76,35 +58,6 @@
         }
     }
 
-    /// Find the params corresponded to generic arg
-    pub fn find_generic_arg(&self, generic_arg: &ast::GenericArg) -> Option<GenericParam> {
-        self.generic_params().find_map(move |param| match (&param, &generic_arg) {
-            (ast::GenericParam::LifetimeParam(a), ast::GenericArg::LifetimeArg(b)) => {
-                (a.lifetime()?.lifetime_ident_token()?.text()
-                    == b.lifetime()?.lifetime_ident_token()?.text())
-                .then_some(param)
-            }
-            (ast::GenericParam::TypeParam(a), ast::GenericArg::TypeArg(b)) => {
-                debug_assert_eq!(b.syntax().first_token(), b.syntax().last_token());
-                (a.name()?.text() == b.syntax().first_token()?.text()).then_some(param)
-            }
-            (ast::GenericParam::ConstParam(a), ast::GenericArg::TypeArg(b)) => {
-                debug_assert_eq!(b.syntax().first_token(), b.syntax().last_token());
-                (a.name()?.text() == b.syntax().first_token()?.text()).then_some(param)
-            }
-            _ => None,
-        })
-    }
-
-    /// Removes the corresponding generic arg
-    pub fn remove_generic_arg(&self, generic_arg: &ast::GenericArg) {
-        let param_to_remove = self.find_generic_arg(generic_arg);
-
-        if let Some(param) = &param_to_remove {
-            self.remove_generic_param(param.clone());
-        }
-    }
-
     /// Constructs a matching [`ast::GenericArgList`]
     pub fn to_generic_args(&self) -> ast::GenericArgList {
         let args = self.generic_params().filter_map(|param| match param {
@@ -124,44 +77,10 @@
     }
 }
 
-impl ast::WhereClause {
-    pub fn add_predicate(&self, predicate: ast::WherePred) {
-        if let Some(pred) = self.predicates().last()
-            && !pred.syntax().siblings_with_tokens(Direction::Next).any(|it| it.kind() == T![,])
-        {
-            ted::append_child_raw(self.syntax(), make::token(T![,]));
-        }
-        ted::append_child(self.syntax(), predicate.syntax());
-    }
-
-    pub fn remove_predicate(&self, predicate: ast::WherePred) {
-        if let Some(previous) = predicate.syntax().prev_sibling() {
-            if let Some(next_token) = previous.next_sibling_or_token() {
-                ted::remove_all(next_token..=predicate.syntax().clone().into());
-            }
-        } else if let Some(next) = predicate.syntax().next_sibling() {
-            if let Some(next_token) = next.prev_sibling_or_token() {
-                ted::remove_all(predicate.syntax().clone().into()..=next_token);
-            }
-        } else {
-            ted::remove(predicate.syntax());
-        }
-    }
-}
-
 pub trait Removable: AstNode {
     fn remove(&self);
 }
 
-impl Removable for ast::TypeBoundList {
-    fn remove(&self) {
-        match self.syntax().siblings_with_tokens(Direction::Prev).find(|it| it.kind() == T![:]) {
-            Some(colon) => ted::remove_all(colon..=self.syntax().clone().into()),
-            None => ted::remove(self.syntax()),
-        }
-    }
-}
-
 impl Removable for ast::UseTree {
     fn remove(&self) {
         for dir in [Direction::Next, Direction::Prev] {
@@ -371,26 +290,35 @@
     ///
     /// Attention! This function does align the first line of `item` with respect to `self`,
     /// but it does _not_ change indentation of other lines (if any).
-    pub fn add_item(&self, item: ast::AssocItem) {
+    pub fn add_item(&self, editor: &SyntaxEditor, item: ast::AssocItem) {
+        let make = editor.make();
         let (indent, position, whitespace) = match self.assoc_items().last() {
             Some(last_item) => (
                 IndentLevel::from_node(last_item.syntax()),
-                ted::Position::after(last_item.syntax()),
+                syntax_editor::Position::after(last_item.syntax()),
                 "\n\n",
             ),
             None => match self.l_curly_token() {
                 Some(l_curly) => {
-                    normalize_ws_between_braces(self.syntax());
-                    (IndentLevel::from_token(&l_curly) + 1, ted::Position::after(&l_curly), "\n")
+                    normalize_ws_between_braces_with_editor(editor, self.syntax());
+                    (
+                        IndentLevel::from_token(&l_curly) + 1,
+                        syntax_editor::Position::after(&l_curly),
+                        "\n",
+                    )
                 }
-                None => (IndentLevel::zero(), ted::Position::last_child_of(self.syntax()), "\n"),
+                None => (
+                    IndentLevel::zero(),
+                    syntax_editor::Position::last_child_of(self.syntax()),
+                    "\n",
+                ),
             },
         };
         let elements: Vec<SyntaxElement> = vec![
-            make::tokens::whitespace(&format!("{whitespace}{indent}")).into(),
+            make.whitespace(&format!("{whitespace}{indent}")).into(),
             item.syntax().clone().into(),
         ];
-        ted::insert_all(position, elements);
+        editor.insert_all(position, elements);
     }
 }
 
@@ -429,32 +357,7 @@
 impl ast::RecordExprField {
     /// This will either replace the initializer, or in the case that this is a shorthand convert
     /// the initializer into the name ref and insert the expr as the new initializer.
-    pub fn replace_expr(&self, expr: ast::Expr) {
-        if self.name_ref().is_some() {
-            match self.expr() {
-                Some(prev) => ted::replace(prev.syntax(), expr.syntax()),
-                None => ted::append_child(self.syntax(), expr.syntax()),
-            }
-            return;
-        }
-        // this is a shorthand
-        if let Some(ast::Expr::PathExpr(path_expr)) = self.expr()
-            && let Some(path) = path_expr.path()
-            && let Some(name_ref) = path.as_single_name_ref()
-        {
-            path_expr.syntax().detach();
-            let children = vec![
-                name_ref.syntax().clone().into(),
-                ast::make::token(T![:]).into(),
-                ast::make::tokens::single_space().into(),
-                expr.syntax().clone().into(),
-            ];
-            ted::insert_all_raw(ted::Position::last_child_of(self.syntax()), children);
-        }
-    }
-
-    /// [`SyntaxEditor`]-based equivalent of [`replace_expr`](Self::replace_expr).
-    pub fn replace_expr_with_editor(&self, editor: &SyntaxEditor, expr: ast::Expr) {
+    pub fn replace_expr(&self, editor: &SyntaxEditor, expr: ast::Expr) {
         if self.name_ref().is_some() {
             if let Some(prev) = self.expr() {
                 editor.replace(prev.syntax(), expr.syntax());
@@ -547,6 +450,35 @@
     Some(())
 }
 
+fn normalize_ws_between_braces_with_editor(editor: &SyntaxEditor, node: &SyntaxNode) -> Option<()> {
+    let make = editor.make();
+    let l = node
+        .children_with_tokens()
+        .filter_map(|it| it.into_token())
+        .find(|it| it.kind() == T!['{'])?;
+    let r = node
+        .children_with_tokens()
+        .filter_map(|it| it.into_token())
+        .find(|it| it.kind() == T!['}'])?;
+
+    let indent = IndentLevel::from_node(node);
+
+    match l.next_sibling_or_token() {
+        Some(ws)
+            if ws.kind() == SyntaxKind::WHITESPACE
+                && ws.next_sibling_or_token()?.into_token()? == r =>
+        {
+            editor.replace(ws, make.whitespace(&format!("\n{indent}")));
+        }
+        Some(ws) if ws.kind() == T!['}'] => {
+            editor
+                .insert(syntax_editor::Position::after(l), make.whitespace(&format!("\n{indent}")));
+        }
+        _ => (),
+    }
+    Some(())
+}
+
 pub trait Indent: AstNode + Clone + Sized {
     fn indent_level(&self) -> IndentLevel {
         IndentLevel::from_node(self.syntax())
diff --git a/crates/syntax/src/ast/make.rs b/crates/syntax/src/ast/make.rs
index e8f5c95..718e5e2 100644
--- a/crates/syntax/src/ast/make.rs
+++ b/crates/syntax/src/ast/make.rs
@@ -294,12 +294,7 @@
         (None, None) => None,
         (None, Some(bs)) => Some(bs),
         (Some(ps), None) => Some(ps),
-        (Some(ps), Some(bs)) => {
-            let preds = where_clause(std::iter::empty()).clone_for_update();
-            ps.predicates().for_each(|p| preds.add_predicate(p));
-            bs.predicates().for_each(|p| preds.add_predicate(p));
-            Some(preds)
-        }
+        (Some(ps), Some(bs)) => Some(where_clause(ps.predicates().chain(bs.predicates()))),
     }
 }
 
diff --git a/crates/syntax/src/syntax_editor/edits.rs b/crates/syntax/src/syntax_editor/edits.rs
index 28e8cee..a684c0b 100644
--- a/crates/syntax/src/syntax_editor/edits.rs
+++ b/crates/syntax/src/syntax_editor/edits.rs
@@ -3,7 +3,7 @@
 use crate::{
     AstToken, Direction, SyntaxElement, SyntaxKind, SyntaxNode, SyntaxToken, T,
     algo::neighbor,
-    ast::{self, AstNode, Fn, GenericParam, HasGenericParams, HasName, edit::IndentLevel, make},
+    ast::{self, AstNode, HasGenericParams, HasName, edit::IndentLevel, make},
     syntax_editor::{Position, SyntaxEditor},
 };
 
@@ -109,64 +109,79 @@
 }
 
 impl SyntaxEditor {
-    /// Adds a new generic param to the function using `SyntaxEditor`
-    pub fn add_generic_param(&self, function: &Fn, new_param: GenericParam) {
-        match function.generic_param_list() {
-            Some(generic_param_list) => match generic_param_list.generic_params().last() {
-                Some(last_param) => {
-                    // There exists a generic param list and it's not empty
-                    let position = generic_param_list.r_angle_token().map_or_else(
-                        || Position::last_child_of(function.syntax()),
-                        Position::before,
-                    );
+    /// Adds a new generic param to the node using `SyntaxEditor`
+    pub fn add_generic_param(
+        &self,
+        node: &impl ast::HasGenericParams,
+        new_param: ast::GenericParam,
+    ) {
+        let make = self.make();
+        match node.generic_param_list() {
+            Some(generic_param_list) => {
+                let is_lifetime = matches!(new_param, ast::GenericParam::LifetimeParam(_));
 
-                    if last_param
-                        .syntax()
-                        .next_sibling_or_token()
-                        .is_some_and(|it| it.kind() == SyntaxKind::COMMA)
-                    {
-                        self.insert(
-                            Position::after(last_param.syntax()),
-                            new_param.syntax().clone(),
-                        );
-                        self.insert(
-                            Position::after(last_param.syntax()),
-                            make::token(SyntaxKind::WHITESPACE),
-                        );
-                        self.insert(
-                            Position::after(last_param.syntax()),
-                            make::token(SyntaxKind::COMMA),
-                        );
+                if let Some(first_param) = generic_param_list.generic_params().next() {
+                    let last_lifetime = generic_param_list
+                        .generic_params()
+                        .filter(|p| matches!(p, ast::GenericParam::LifetimeParam(_)))
+                        .last();
+
+                    if is_lifetime {
+                        if let Some(last_lt) = last_lifetime {
+                            let elements = vec![
+                                make.token(SyntaxKind::COMMA).into(),
+                                make.token(SyntaxKind::WHITESPACE).into(),
+                                new_param.syntax().clone().into(),
+                            ];
+                            self.insert_all(Position::after(last_lt.syntax()), elements);
+                        } else {
+                            // Insert before the first parameter
+                            let elements = vec![
+                                new_param.syntax().clone().into(),
+                                make.token(SyntaxKind::COMMA).into(),
+                                make.token(SyntaxKind::WHITESPACE).into(),
+                            ];
+                            self.insert_all(Position::before(first_param.syntax()), elements);
+                        }
                     } else {
+                        let last_param = generic_param_list.generic_params().last().unwrap();
                         let elements = vec![
-                            make::token(SyntaxKind::COMMA).into(),
-                            make::token(SyntaxKind::WHITESPACE).into(),
+                            make.token(SyntaxKind::COMMA).into(),
+                            make.token(SyntaxKind::WHITESPACE).into(),
                             new_param.syntax().clone().into(),
                         ];
-                        self.insert_all(position, elements);
+                        self.insert_all(Position::after(last_param.syntax()), elements);
+                    }
+                } else {
+                    if let Some(l_angle) = generic_param_list.l_angle_token() {
+                        self.insert(Position::after(l_angle), new_param.syntax().clone());
                     }
                 }
-                None => {
-                    // There exists a generic param list but it's empty
-                    let position = Position::after(generic_param_list.l_angle_token().unwrap());
-                    self.insert(position, new_param.syntax());
-                }
-            },
+            }
             None => {
-                // There was no generic param list
-                let position = if let Some(name) = function.name() {
-                    Position::after(name.syntax)
-                } else if let Some(fn_token) = function.fn_token() {
-                    Position::after(fn_token)
-                } else if let Some(param_list) = function.param_list() {
-                    Position::before(param_list.syntax)
-                } else {
-                    Position::last_child_of(function.syntax())
-                };
+                let position =
+                    if let Some(name) = node.syntax().children().find_map(ast::Name::cast) {
+                        Position::after(name.syntax())
+                    } else if let Some(impl_node) = ast::Impl::cast(node.syntax().clone()) {
+                        impl_node
+                            .impl_token()
+                            .map_or_else(|| Position::last_child_of(node.syntax()), Position::after)
+                    } else if let Some(fn_node) = ast::Fn::cast(node.syntax().clone()) {
+                        if let Some(fn_token) = fn_node.fn_token() {
+                            Position::after(fn_token)
+                        } else if let Some(param_list) = fn_node.param_list() {
+                            Position::before(param_list.syntax())
+                        } else {
+                            Position::last_child_of(node.syntax())
+                        }
+                    } else {
+                        Position::last_child_of(node.syntax())
+                    };
+
                 let elements = vec![
-                    make::token(SyntaxKind::L_ANGLE).into(),
+                    make.token(SyntaxKind::L_ANGLE).into(),
                     new_param.syntax().clone().into(),
-                    make::token(SyntaxKind::R_ANGLE).into(),
+                    make.token(SyntaxKind::R_ANGLE).into(),
                 ];
                 self.insert_all(position, elements);
             }