about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2023-11-25 13:27:26 +0000
committerbors <bors@rust-lang.org>2023-11-25 13:27:26 +0000
commit547598b67ea272ef134c52b779299012f3fc230e (patch)
treeb4b16bd5ca5f257512de1726c967a3b76cc90cea
parent535db180026d8772fde3a3cc6d6bda9a3a360f2a (diff)
parentfeb37829e152e0880dffa337e4897f75ca35eb84 (diff)
downloadrust-547598b67ea272ef134c52b779299012f3fc230e.tar.gz
rust-547598b67ea272ef134c52b779299012f3fc230e.zip
Auto merge of #3191 - RalfJung:rustup, r=RalfJung
Rustup
-rw-r--r--compiler/rustc_borrowck/src/dataflow.rs34
-rw-r--r--compiler/rustc_borrowck/src/lib.rs2
-rw-r--r--compiler/rustc_codegen_cranelift/scripts/rustc-clif.rs2
-rw-r--r--compiler/rustc_codegen_cranelift/scripts/rustdoc-clif.rs2
-rw-r--r--compiler/rustc_expand/src/tests.rs2
-rw-r--r--compiler/rustc_hir_analysis/src/astconv/mod.rs5
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs10
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/nice_region_error/util.rs3
-rw-r--r--compiler/rustc_infer/src/infer/resolve.rs82
-rw-r--r--compiler/rustc_lint/src/non_fmt_panic.rs16
-rw-r--r--compiler/rustc_middle/src/ty/print/pretty.rs7
-rw-r--r--compiler/rustc_mir_dataflow/src/drop_flag_effects.rs45
-rw-r--r--compiler/rustc_mir_dataflow/src/framework/cursor.rs7
-rw-r--r--compiler/rustc_mir_dataflow/src/framework/direction.rs14
-rw-r--r--compiler/rustc_mir_dataflow/src/framework/engine.rs15
-rw-r--r--compiler/rustc_mir_dataflow/src/framework/graphviz.rs8
-rw-r--r--compiler/rustc_mir_dataflow/src/framework/mod.rs2
-rw-r--r--compiler/rustc_mir_dataflow/src/impls/initialized.rs43
-rw-r--r--compiler/rustc_mir_dataflow/src/impls/liveness.rs1
-rw-r--r--compiler/rustc_mir_dataflow/src/lib.rs31
-rw-r--r--compiler/rustc_mir_dataflow/src/rustc_peek.rs45
-rw-r--r--compiler/rustc_mir_dataflow/src/un_derefer.rs8
-rw-r--r--compiler/rustc_mir_dataflow/src/value_analysis.rs33
-rw-r--r--compiler/rustc_mir_transform/src/coroutine.rs20
-rw-r--r--compiler/rustc_mir_transform/src/elaborate_drops.rs51
-rw-r--r--compiler/rustc_smir/src/rustc_internal/mod.rs4
-rw-r--r--compiler/rustc_smir/src/rustc_smir/context.rs376
-rw-r--r--compiler/rustc_smir/src/rustc_smir/convert/mir.rs745
-rw-r--r--compiler/rustc_smir/src/rustc_smir/convert/mod.rs76
-rw-r--r--compiler/rustc_smir/src/rustc_smir/convert/ty.rs815
-rw-r--r--compiler/rustc_smir/src/rustc_smir/mod.rs1999
-rw-r--r--compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs85
-rw-r--r--compiler/rustc_trait_selection/src/traits/project.rs22
-rw-r--r--compiler/stable_mir/src/compiler_interface.rs164
-rw-r--r--compiler/stable_mir/src/lib.rs176
-rw-r--r--compiler/stable_mir/src/mir/pretty.rs6
-rw-r--r--config.example.toml2
-rw-r--r--src/bootstrap/README.md2
-rw-r--r--src/bootstrap/src/bin/main.rs4
-rw-r--r--src/bootstrap/src/core/build_steps/setup.rs3
-rw-r--r--src/bootstrap/src/lib.rs88
-rw-r--r--src/bootstrap/src/utils/change_tracker.rs89
-rw-r--r--src/bootstrap/src/utils/mod.rs1
-rw-r--r--src/librustdoc/html/render/print_item.rs6
-rw-r--r--src/librustdoc/html/static/js/search.js32
-rw-r--r--src/tools/compiletest/src/header.rs2
-rw-r--r--src/tools/miri/rust-version2
-rw-r--r--src/tools/miri/tests/fail/intrinsics/float_to_int_32_inf1.stderr4
-rw-r--r--src/tools/miri/tests/fail/intrinsics/float_to_int_32_infneg1.stderr4
-rw-r--r--src/tools/miri/tests/fail/intrinsics/float_to_int_32_nan.stderr4
-rw-r--r--src/tools/miri/tests/fail/intrinsics/float_to_int_32_nanneg.stderr4
-rw-r--r--src/tools/miri/tests/fail/intrinsics/float_to_int_64_inf1.stderr4
-rw-r--r--src/tools/miri/tests/fail/intrinsics/float_to_int_64_infneg1.stderr4
-rw-r--r--src/tools/miri/tests/fail/intrinsics/float_to_int_64_infneg2.stderr4
-rw-r--r--src/tools/miri/tests/fail/intrinsics/float_to_int_64_nan.stderr4
-rw-r--r--tests/rustdoc-js/assoc-type-loop.js9
-rw-r--r--tests/rustdoc-js/assoc-type-loop.rs35
-rw-r--r--triagebot.toml24
58 files changed, 2679 insertions, 2608 deletions
diff --git a/compiler/rustc_borrowck/src/dataflow.rs b/compiler/rustc_borrowck/src/dataflow.rs
index 27b558be3b7..b3d14c1beb5 100644
--- a/compiler/rustc_borrowck/src/dataflow.rs
+++ b/compiler/rustc_borrowck/src/dataflow.rs
@@ -121,24 +121,24 @@ rustc_index::newtype_index! {
 /// `BorrowIndex`, and maps each such index to a `BorrowData`
 /// describing the borrow. These indexes are used for representing the
 /// borrows in compact bitvectors.
-pub struct Borrows<'a, 'tcx> {
+pub struct Borrows<'mir, 'tcx> {
     tcx: TyCtxt<'tcx>,
-    body: &'a Body<'tcx>,
+    body: &'mir Body<'tcx>,
 
-    borrow_set: &'a BorrowSet<'tcx>,
+    borrow_set: &'mir BorrowSet<'tcx>,
     borrows_out_of_scope_at_location: FxIndexMap<Location, Vec<BorrowIndex>>,
 }
 
-struct OutOfScopePrecomputer<'a, 'tcx> {
+struct OutOfScopePrecomputer<'mir, 'tcx> {
     visited: BitSet<mir::BasicBlock>,
     visit_stack: Vec<mir::BasicBlock>,
-    body: &'a Body<'tcx>,
-    regioncx: &'a RegionInferenceContext<'tcx>,
+    body: &'mir Body<'tcx>,
+    regioncx: &'mir RegionInferenceContext<'tcx>,
     borrows_out_of_scope_at_location: FxIndexMap<Location, Vec<BorrowIndex>>,
 }
 
-impl<'a, 'tcx> OutOfScopePrecomputer<'a, 'tcx> {
-    fn new(body: &'a Body<'tcx>, regioncx: &'a RegionInferenceContext<'tcx>) -> Self {
+impl<'mir, 'tcx> OutOfScopePrecomputer<'mir, 'tcx> {
+    fn new(body: &'mir Body<'tcx>, regioncx: &'mir RegionInferenceContext<'tcx>) -> Self {
         OutOfScopePrecomputer {
             visited: BitSet::new_empty(body.basic_blocks.len()),
             visit_stack: vec![],
@@ -241,17 +241,17 @@ pub fn calculate_borrows_out_of_scope_at_location<'tcx>(
     prec.borrows_out_of_scope_at_location
 }
 
-struct PoloniusOutOfScopePrecomputer<'a, 'tcx> {
+struct PoloniusOutOfScopePrecomputer<'mir, 'tcx> {
     visited: BitSet<mir::BasicBlock>,
     visit_stack: Vec<mir::BasicBlock>,
-    body: &'a Body<'tcx>,
-    regioncx: &'a RegionInferenceContext<'tcx>,
+    body: &'mir Body<'tcx>,
+    regioncx: &'mir RegionInferenceContext<'tcx>,
 
     loans_out_of_scope_at_location: FxIndexMap<Location, Vec<BorrowIndex>>,
 }
 
-impl<'a, 'tcx> PoloniusOutOfScopePrecomputer<'a, 'tcx> {
-    fn new(body: &'a Body<'tcx>, regioncx: &'a RegionInferenceContext<'tcx>) -> Self {
+impl<'mir, 'tcx> PoloniusOutOfScopePrecomputer<'mir, 'tcx> {
+    fn new(body: &'mir Body<'tcx>, regioncx: &'mir RegionInferenceContext<'tcx>) -> Self {
         Self {
             visited: BitSet::new_empty(body.basic_blocks.len()),
             visit_stack: vec![],
@@ -404,12 +404,12 @@ impl<'tcx> PoloniusOutOfScopePrecomputer<'_, 'tcx> {
     }
 }
 
-impl<'a, 'tcx> Borrows<'a, 'tcx> {
+impl<'mir, 'tcx> Borrows<'mir, 'tcx> {
     pub fn new(
         tcx: TyCtxt<'tcx>,
-        body: &'a Body<'tcx>,
-        regioncx: &'a RegionInferenceContext<'tcx>,
-        borrow_set: &'a BorrowSet<'tcx>,
+        body: &'mir Body<'tcx>,
+        regioncx: &'mir RegionInferenceContext<'tcx>,
+        borrow_set: &'mir BorrowSet<'tcx>,
     ) -> Self {
         let mut borrows_out_of_scope_at_location =
             calculate_borrows_out_of_scope_at_location(body, regioncx, borrow_set);
diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs
index 0bfd2e7e710..804060d00ed 100644
--- a/compiler/rustc_borrowck/src/lib.rs
+++ b/compiler/rustc_borrowck/src/lib.rs
@@ -288,7 +288,7 @@ fn do_mir_borrowck<'tcx>(
         .into_engine(tcx, body)
         .pass_name("borrowck")
         .iterate_to_fixpoint();
-    let flow_ever_inits = EverInitializedPlaces::new(tcx, body, &mdpe)
+    let flow_ever_inits = EverInitializedPlaces::new(body, &mdpe)
         .into_engine(tcx, body)
         .pass_name("borrowck")
         .iterate_to_fixpoint();
diff --git a/compiler/rustc_codegen_cranelift/scripts/rustc-clif.rs b/compiler/rustc_codegen_cranelift/scripts/rustc-clif.rs
index 33d51bdddea..550f2051553 100644
--- a/compiler/rustc_codegen_cranelift/scripts/rustc-clif.rs
+++ b/compiler/rustc_codegen_cranelift/scripts/rustc-clif.rs
@@ -27,7 +27,7 @@ fn main() {
         args.push(codegen_backend_arg);
     }
     if !passed_args.iter().any(|arg| {
-        arg == "--sysroot" || arg.to_str().map(|s| s.starts_with("--sysroot=")) == Some(true)
+        arg == "--sysroot" || arg.to_str().is_some_and(|s| s.starts_with("--sysroot="))
     }) {
         args.push(OsString::from("--sysroot"));
         args.push(OsString::from(sysroot.to_str().unwrap()));
diff --git a/compiler/rustc_codegen_cranelift/scripts/rustdoc-clif.rs b/compiler/rustc_codegen_cranelift/scripts/rustdoc-clif.rs
index 10582cc7bb3..f7d1bdbc4c6 100644
--- a/compiler/rustc_codegen_cranelift/scripts/rustdoc-clif.rs
+++ b/compiler/rustc_codegen_cranelift/scripts/rustdoc-clif.rs
@@ -27,7 +27,7 @@ fn main() {
         args.push(codegen_backend_arg);
     }
     if !passed_args.iter().any(|arg| {
-        arg == "--sysroot" || arg.to_str().map(|s| s.starts_with("--sysroot=")) == Some(true)
+        arg == "--sysroot" || arg.to_str().is_some_and(|s| s.starts_with("--sysroot="))
     }) {
         args.push(OsString::from("--sysroot"));
         args.push(OsString::from(sysroot.to_str().unwrap()));
diff --git a/compiler/rustc_expand/src/tests.rs b/compiler/rustc_expand/src/tests.rs
index 9f52669e188..b4724b0e9d0 100644
--- a/compiler/rustc_expand/src/tests.rs
+++ b/compiler/rustc_expand/src/tests.rs
@@ -135,7 +135,7 @@ pub(crate) fn matches_codepattern(a: &str, b: &str) -> bool {
 
 /// Advances the given peekable `Iterator` until it reaches a non-whitespace character.
 fn scan_for_non_ws_or_end<I: Iterator<Item = char>>(iter: &mut Peekable<I>) {
-    while iter.peek().copied().map(rustc_lexer::is_whitespace) == Some(true) {
+    while iter.peek().copied().is_some_and(rustc_lexer::is_whitespace) {
         iter.next();
     }
 }
diff --git a/compiler/rustc_hir_analysis/src/astconv/mod.rs b/compiler/rustc_hir_analysis/src/astconv/mod.rs
index 102c83751aa..ff92d4c4a3e 100644
--- a/compiler/rustc_hir_analysis/src/astconv/mod.rs
+++ b/compiler/rustc_hir_analysis/src/astconv/mod.rs
@@ -1674,10 +1674,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                         let impl_ty = ocx.normalize(&cause, param_env, impl_ty);
 
                         // Check that the self types can be related.
-                        // FIXME(inherent_associated_types): Should we use `eq` here? Method probing uses
-                        // `sup` for this situtation, too. What for? To constrain inference variables?
-                        if ocx.sup(&ObligationCause::dummy(), param_env, impl_ty, self_ty).is_err()
-                        {
+                        if ocx.eq(&ObligationCause::dummy(), param_env, impl_ty, self_ty).is_err() {
                             return false;
                         }
 
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
index 78e755378f5..773f184472b 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
@@ -2293,12 +2293,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         let clone_trait =
                             self.tcx.require_lang_item(LangItem::Clone, Some(segment.ident.span));
                         if args.is_empty()
-                            && self.typeck_results.borrow().type_dependent_def_id(expr.hir_id).map(
-                                |did| {
+                            && self
+                                .typeck_results
+                                .borrow()
+                                .type_dependent_def_id(expr.hir_id)
+                                .is_some_and(|did| {
                                     let ai = self.tcx.associated_item(did);
                                     ai.trait_container(self.tcx) == Some(clone_trait)
-                                },
-                            ) == Some(true)
+                                })
                             && segment.ident.name == sym::clone
                         {
                             // If this expression had a clone call when suggesting borrowing
diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/util.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/util.rs
index 7252a812466..b26ce464486 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/util.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/util.rs
@@ -161,7 +161,6 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
             && self
                 .tcx()
                 .opt_associated_item(scope_def_id.to_def_id())
-                .map(|i| i.fn_has_self_parameter)
-                == Some(true)
+                .is_some_and(|i| i.fn_has_self_parameter)
     }
 }
diff --git a/compiler/rustc_infer/src/infer/resolve.rs b/compiler/rustc_infer/src/infer/resolve.rs
index 18a9cb6b44b..ece30bbba12 100644
--- a/compiler/rustc_infer/src/infer/resolve.rs
+++ b/compiler/rustc_infer/src/infer/resolve.rs
@@ -260,3 +260,85 @@ impl<'a, 'tcx> FallibleTypeFolder<TyCtxt<'tcx>> for FullTypeResolver<'a, 'tcx> {
         }
     }
 }
+
+///////////////////////////////////////////////////////////////////////////
+// EAGER RESOLUTION
+
+/// Resolves ty, region, and const vars to their inferred values or their root vars.
+pub struct EagerResolver<'a, 'tcx> {
+    infcx: &'a InferCtxt<'tcx>,
+}
+
+impl<'a, 'tcx> EagerResolver<'a, 'tcx> {
+    pub fn new(infcx: &'a InferCtxt<'tcx>) -> Self {
+        EagerResolver { infcx }
+    }
+}
+
+impl<'tcx> TypeFolder<TyCtxt<'tcx>> for EagerResolver<'_, 'tcx> {
+    fn interner(&self) -> TyCtxt<'tcx> {
+        self.infcx.tcx
+    }
+
+    fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
+        match *t.kind() {
+            ty::Infer(ty::TyVar(vid)) => match self.infcx.probe_ty_var(vid) {
+                Ok(t) => t.fold_with(self),
+                Err(_) => Ty::new_var(self.infcx.tcx, self.infcx.root_var(vid)),
+            },
+            ty::Infer(ty::IntVar(vid)) => self.infcx.opportunistic_resolve_int_var(vid),
+            ty::Infer(ty::FloatVar(vid)) => self.infcx.opportunistic_resolve_float_var(vid),
+            _ => {
+                if t.has_infer() {
+                    t.super_fold_with(self)
+                } else {
+                    t
+                }
+            }
+        }
+    }
+
+    fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
+        match *r {
+            ty::ReVar(vid) => self
+                .infcx
+                .inner
+                .borrow_mut()
+                .unwrap_region_constraints()
+                .opportunistic_resolve_var(self.infcx.tcx, vid),
+            _ => r,
+        }
+    }
+
+    fn fold_const(&mut self, c: ty::Const<'tcx>) -> ty::Const<'tcx> {
+        match c.kind() {
+            ty::ConstKind::Infer(ty::InferConst::Var(vid)) => {
+                // FIXME: we need to fold the ty too, I think.
+                match self.infcx.probe_const_var(vid) {
+                    Ok(c) => c.fold_with(self),
+                    Err(_) => {
+                        ty::Const::new_var(self.infcx.tcx, self.infcx.root_const_var(vid), c.ty())
+                    }
+                }
+            }
+            ty::ConstKind::Infer(ty::InferConst::EffectVar(vid)) => {
+                debug_assert_eq!(c.ty(), self.infcx.tcx.types.bool);
+                match self.infcx.probe_effect_var(vid) {
+                    Some(c) => c.as_const(self.infcx.tcx),
+                    None => ty::Const::new_infer(
+                        self.infcx.tcx,
+                        ty::InferConst::EffectVar(self.infcx.root_effect_var(vid)),
+                        self.infcx.tcx.types.bool,
+                    ),
+                }
+            }
+            _ => {
+                if c.has_infer() {
+                    c.super_fold_with(self)
+                } else {
+                    c
+                }
+            }
+        }
+    }
+}
diff --git a/compiler/rustc_lint/src/non_fmt_panic.rs b/compiler/rustc_lint/src/non_fmt_panic.rs
index b218cc5789d..f0e415492ae 100644
--- a/compiler/rustc_lint/src/non_fmt_panic.rs
+++ b/compiler/rustc_lint/src/non_fmt_panic.rs
@@ -154,17 +154,13 @@ fn check_panic<'tcx>(cx: &LateContext<'tcx>, f: &'tcx hir::Expr<'tcx>, arg: &'tc
 
             let infcx = cx.tcx.infer_ctxt().build();
             let suggest_display = is_str
-                || cx
-                    .tcx
-                    .get_diagnostic_item(sym::Display)
-                    .map(|t| infcx.type_implements_trait(t, [ty], cx.param_env).may_apply())
-                    == Some(true);
+                || cx.tcx.get_diagnostic_item(sym::Display).is_some_and(|t| {
+                    infcx.type_implements_trait(t, [ty], cx.param_env).may_apply()
+                });
             let suggest_debug = !suggest_display
-                && cx
-                    .tcx
-                    .get_diagnostic_item(sym::Debug)
-                    .map(|t| infcx.type_implements_trait(t, [ty], cx.param_env).may_apply())
-                    == Some(true);
+                && cx.tcx.get_diagnostic_item(sym::Debug).is_some_and(|t| {
+                    infcx.type_implements_trait(t, [ty], cx.param_env).may_apply()
+                });
 
             let suggest_panic_any = !is_str && panic == sym::std_panic_macro;
 
diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs
index 25a151443d5..2bde339ec77 100644
--- a/compiler/rustc_middle/src/ty/print/pretty.rs
+++ b/compiler/rustc_middle/src/ty/print/pretty.rs
@@ -8,6 +8,7 @@ use crate::ty::{
 };
 use crate::ty::{GenericArg, GenericArgKind};
 use rustc_apfloat::ieee::{Double, Single};
+use rustc_apfloat::Float;
 use rustc_data_structures::fx::{FxHashMap, FxIndexMap};
 use rustc_data_structures::sso::SsoHashSet;
 use rustc_hir as hir;
@@ -1477,10 +1478,12 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write {
             ty::Bool if int == ScalarInt::TRUE => p!("true"),
             // Float
             ty::Float(ty::FloatTy::F32) => {
-                p!(write("{}f32", Single::try_from(int).unwrap()))
+                let val = Single::try_from(int).unwrap();
+                p!(write("{}{}f32", val, if val.is_finite() { "" } else { "_" }))
             }
             ty::Float(ty::FloatTy::F64) => {
-                p!(write("{}f64", Double::try_from(int).unwrap()))
+                let val = Double::try_from(int).unwrap();
+                p!(write("{}{}f64", val, if val.is_finite() { "" } else { "_" }))
             }
             // Int
             ty::Uint(_) | ty::Int(_) => {
diff --git a/compiler/rustc_mir_dataflow/src/drop_flag_effects.rs b/compiler/rustc_mir_dataflow/src/drop_flag_effects.rs
index 163d74cc9cf..de1ca8d823b 100644
--- a/compiler/rustc_mir_dataflow/src/drop_flag_effects.rs
+++ b/compiler/rustc_mir_dataflow/src/drop_flag_effects.rs
@@ -1,10 +1,8 @@
 use crate::elaborate_drops::DropFlagState;
 use rustc_middle::mir::{self, Body, Location, Terminator, TerminatorKind};
-use rustc_middle::ty::TyCtxt;
 use rustc_target::abi::VariantIdx;
 
-use super::indexes::MovePathIndex;
-use super::move_paths::{InitKind, LookupResult, MoveData};
+use super::move_paths::{InitKind, LookupResult, MoveData, MovePathIndex};
 use super::MoveDataParamEnv;
 
 pub fn move_path_children_matching<'tcx, F>(
@@ -30,8 +28,6 @@ where
 }
 
 pub fn on_lookup_result_bits<'tcx, F>(
-    tcx: TyCtxt<'tcx>,
-    body: &Body<'tcx>,
     move_data: &MoveData<'tcx>,
     lookup_result: LookupResult,
     each_child: F,
@@ -42,13 +38,11 @@ pub fn on_lookup_result_bits<'tcx, F>(
         LookupResult::Parent(..) => {
             // access to untracked value - do not touch children
         }
-        LookupResult::Exact(e) => on_all_children_bits(tcx, body, move_data, e, each_child),
+        LookupResult::Exact(e) => on_all_children_bits(move_data, e, each_child),
     }
 }
 
 pub fn on_all_children_bits<'tcx, F>(
-    tcx: TyCtxt<'tcx>,
-    body: &Body<'tcx>,
     move_data: &MoveData<'tcx>,
     move_path_index: MovePathIndex,
     mut each_child: F,
@@ -56,8 +50,6 @@ pub fn on_all_children_bits<'tcx, F>(
     F: FnMut(MovePathIndex),
 {
     fn on_all_children_bits<'tcx, F>(
-        tcx: TyCtxt<'tcx>,
-        body: &Body<'tcx>,
         move_data: &MoveData<'tcx>,
         move_path_index: MovePathIndex,
         each_child: &mut F,
@@ -68,15 +60,14 @@ pub fn on_all_children_bits<'tcx, F>(
 
         let mut next_child_index = move_data.move_paths[move_path_index].first_child;
         while let Some(child_index) = next_child_index {
-            on_all_children_bits(tcx, body, move_data, child_index, each_child);
+            on_all_children_bits(move_data, child_index, each_child);
             next_child_index = move_data.move_paths[child_index].next_sibling;
         }
     }
-    on_all_children_bits(tcx, body, move_data, move_path_index, &mut each_child);
+    on_all_children_bits(move_data, move_path_index, &mut each_child);
 }
 
 pub fn drop_flag_effects_for_function_entry<'tcx, F>(
-    tcx: TyCtxt<'tcx>,
     body: &Body<'tcx>,
     ctxt: &MoveDataParamEnv<'tcx>,
     mut callback: F,
@@ -87,14 +78,13 @@ pub fn drop_flag_effects_for_function_entry<'tcx, F>(
     for arg in body.args_iter() {
         let place = mir::Place::from(arg);
         let lookup_result = move_data.rev_lookup.find(place.as_ref());
-        on_lookup_result_bits(tcx, body, move_data, lookup_result, |mpi| {
+        on_lookup_result_bits(move_data, lookup_result, |mpi| {
             callback(mpi, DropFlagState::Present)
         });
     }
 }
 
 pub fn drop_flag_effects_for_location<'tcx, F>(
-    tcx: TyCtxt<'tcx>,
     body: &Body<'tcx>,
     ctxt: &MoveDataParamEnv<'tcx>,
     loc: Location,
@@ -110,7 +100,7 @@ pub fn drop_flag_effects_for_location<'tcx, F>(
         let path = mi.move_path_index(move_data);
         debug!("moving out of path {:?}", move_data.move_paths[path]);
 
-        on_all_children_bits(tcx, body, move_data, path, |mpi| callback(mpi, DropFlagState::Absent))
+        on_all_children_bits(move_data, path, |mpi| callback(mpi, DropFlagState::Absent))
     }
 
     // Drop does not count as a move but we should still consider the variable uninitialized.
@@ -118,24 +108,17 @@ pub fn drop_flag_effects_for_location<'tcx, F>(
         body.stmt_at(loc).right()
     {
         if let LookupResult::Exact(mpi) = move_data.rev_lookup.find(place.as_ref()) {
-            on_all_children_bits(tcx, body, move_data, mpi, |mpi| {
-                callback(mpi, DropFlagState::Absent)
-            })
+            on_all_children_bits(move_data, mpi, |mpi| callback(mpi, DropFlagState::Absent))
         }
     }
 
     debug!("drop_flag_effects: assignment for location({:?})", loc);
 
-    for_location_inits(tcx, body, move_data, loc, |mpi| callback(mpi, DropFlagState::Present));
+    for_location_inits(move_data, loc, |mpi| callback(mpi, DropFlagState::Present));
 }
 
-pub fn for_location_inits<'tcx, F>(
-    tcx: TyCtxt<'tcx>,
-    body: &Body<'tcx>,
-    move_data: &MoveData<'tcx>,
-    loc: Location,
-    mut callback: F,
-) where
+fn for_location_inits<'tcx, F>(move_data: &MoveData<'tcx>, loc: Location, mut callback: F)
+where
     F: FnMut(MovePathIndex),
 {
     for ii in &move_data.init_loc_map[loc] {
@@ -144,7 +127,7 @@ pub fn for_location_inits<'tcx, F>(
             InitKind::Deep => {
                 let path = init.path;
 
-                on_all_children_bits(tcx, body, move_data, path, &mut callback)
+                on_all_children_bits(move_data, path, &mut callback)
             }
             InitKind::Shallow => {
                 let mpi = init.path;
@@ -161,8 +144,6 @@ pub fn for_location_inits<'tcx, F>(
 /// NOTE: If there are no move paths corresponding to an inactive variant,
 /// `handle_inactive_variant` will not be called for that variant.
 pub(crate) fn on_all_inactive_variants<'tcx>(
-    tcx: TyCtxt<'tcx>,
-    body: &mir::Body<'tcx>,
     move_data: &MoveData<'tcx>,
     enum_place: mir::Place<'tcx>,
     active_variant: VariantIdx,
@@ -185,9 +166,7 @@ pub(crate) fn on_all_inactive_variants<'tcx>(
         };
 
         if variant_idx != active_variant {
-            on_all_children_bits(tcx, body, move_data, variant_mpi, |mpi| {
-                handle_inactive_variant(mpi)
-            });
+            on_all_children_bits(move_data, variant_mpi, |mpi| handle_inactive_variant(mpi));
         }
     }
 }
diff --git a/compiler/rustc_mir_dataflow/src/framework/cursor.rs b/compiler/rustc_mir_dataflow/src/framework/cursor.rs
index c978bddfef5..c9bce80853d 100644
--- a/compiler/rustc_mir_dataflow/src/framework/cursor.rs
+++ b/compiler/rustc_mir_dataflow/src/framework/cursor.rs
@@ -147,7 +147,7 @@ where
     }
 
     /// Returns the underlying `Results`.
-    pub fn results(&mut self) -> &Results<'tcx, A, R::EntrySets> {
+    pub fn results(&self) -> &Results<'tcx, A, R::EntrySets> {
         self.results.borrow()
     }
 
@@ -166,11 +166,6 @@ where
         &mut self.results.borrow_mut().analysis
     }
 
-    /// Returns both the dataflow state at the current location and the `Analysis`.
-    pub fn get_with_analysis(&mut self) -> (&A::Domain, &mut A) {
-        (&self.state, &mut self.results.borrow_mut().analysis)
-    }
-
     /// Resets the cursor to hold the entry set for the given basic block.
     ///
     /// For forward dataflow analyses, this is the dataflow state prior to the first statement.
diff --git a/compiler/rustc_mir_dataflow/src/framework/direction.rs b/compiler/rustc_mir_dataflow/src/framework/direction.rs
index 04c9f7a016c..08b7b1a2619 100644
--- a/compiler/rustc_mir_dataflow/src/framework/direction.rs
+++ b/compiler/rustc_mir_dataflow/src/framework/direction.rs
@@ -287,12 +287,12 @@ impl Direction for Backward {
     }
 }
 
-struct BackwardSwitchIntEdgeEffectsApplier<'a, 'tcx, D, F> {
-    body: &'a mir::Body<'tcx>,
+struct BackwardSwitchIntEdgeEffectsApplier<'mir, 'tcx, D, F> {
+    body: &'mir mir::Body<'tcx>,
     pred: BasicBlock,
-    exit_state: &'a mut D,
+    exit_state: &'mir mut D,
     bb: BasicBlock,
-    propagate: &'a mut F,
+    propagate: &'mir mut F,
     effects_applied: bool,
 }
 
@@ -523,9 +523,9 @@ impl Direction for Forward {
     }
 }
 
-struct ForwardSwitchIntEdgeEffectsApplier<'a, D, F> {
-    exit_state: &'a mut D,
-    targets: &'a SwitchTargets,
+struct ForwardSwitchIntEdgeEffectsApplier<'mir, D, F> {
+    exit_state: &'mir mut D,
+    targets: &'mir SwitchTargets,
     propagate: F,
 
     effects_applied: bool,
diff --git a/compiler/rustc_mir_dataflow/src/framework/engine.rs b/compiler/rustc_mir_dataflow/src/framework/engine.rs
index 204e854235f..ed82b1e8cdc 100644
--- a/compiler/rustc_mir_dataflow/src/framework/engine.rs
+++ b/compiler/rustc_mir_dataflow/src/framework/engine.rs
@@ -128,12 +128,12 @@ where
 }
 
 /// A solver for dataflow problems.
-pub struct Engine<'a, 'tcx, A>
+pub struct Engine<'mir, 'tcx, A>
 where
     A: Analysis<'tcx>,
 {
     tcx: TyCtxt<'tcx>,
-    body: &'a mir::Body<'tcx>,
+    body: &'mir mir::Body<'tcx>,
     entry_sets: IndexVec<BasicBlock, A::Domain>,
     pass_name: Option<&'static str>,
     analysis: A,
@@ -147,14 +147,14 @@ where
     apply_statement_trans_for_block: Option<Box<dyn Fn(BasicBlock, &mut A::Domain)>>,
 }
 
-impl<'a, 'tcx, A, D, T> Engine<'a, 'tcx, A>
+impl<'mir, 'tcx, A, D, T> Engine<'mir, 'tcx, A>
 where
     A: GenKillAnalysis<'tcx, Idx = T, Domain = D>,
     D: Clone + JoinSemiLattice + GenKill<T> + BitSetExt<T>,
     T: Idx,
 {
     /// Creates a new `Engine` to solve a gen-kill dataflow problem.
-    pub fn new_gen_kill(tcx: TyCtxt<'tcx>, body: &'a mir::Body<'tcx>, mut analysis: A) -> Self {
+    pub fn new_gen_kill(tcx: TyCtxt<'tcx>, body: &'mir mir::Body<'tcx>, mut analysis: A) -> Self {
         // If there are no back-edges in the control-flow graph, we only ever need to apply the
         // transfer function for each block exactly once (assuming that we process blocks in RPO).
         //
@@ -186,7 +186,7 @@ where
     }
 }
 
-impl<'a, 'tcx, A, D> Engine<'a, 'tcx, A>
+impl<'mir, 'tcx, A, D> Engine<'mir, 'tcx, A>
 where
     A: Analysis<'tcx, Domain = D>,
     D: Clone + JoinSemiLattice,
@@ -196,13 +196,13 @@ where
     ///
     /// Gen-kill problems should use `new_gen_kill`, which will coalesce transfer functions for
     /// better performance.
-    pub fn new_generic(tcx: TyCtxt<'tcx>, body: &'a mir::Body<'tcx>, analysis: A) -> Self {
+    pub fn new_generic(tcx: TyCtxt<'tcx>, body: &'mir mir::Body<'tcx>, analysis: A) -> Self {
         Self::new(tcx, body, analysis, None)
     }
 
     fn new(
         tcx: TyCtxt<'tcx>,
-        body: &'a mir::Body<'tcx>,
+        body: &'mir mir::Body<'tcx>,
         analysis: A,
         apply_statement_trans_for_block: Option<Box<dyn Fn(BasicBlock, &mut A::Domain)>>,
     ) -> Self {
@@ -239,7 +239,6 @@ where
             tcx,
             apply_statement_trans_for_block,
             pass_name,
-            ..
         } = self;
 
         let mut dirty_queue: WorkQueue<BasicBlock> = WorkQueue::with_none(body.basic_blocks.len());
diff --git a/compiler/rustc_mir_dataflow/src/framework/graphviz.rs b/compiler/rustc_mir_dataflow/src/framework/graphviz.rs
index c12ccba1e5c..832d1cba9a7 100644
--- a/compiler/rustc_mir_dataflow/src/framework/graphviz.rs
+++ b/compiler/rustc_mir_dataflow/src/framework/graphviz.rs
@@ -15,7 +15,7 @@ use super::fmt::{DebugDiffWithAdapter, DebugWithAdapter, DebugWithContext};
 use super::{Analysis, CallReturnPlaces, Direction, Results, ResultsRefCursor, ResultsVisitor};
 
 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
-pub enum OutputStyle {
+pub(crate) enum OutputStyle {
     AfterOnly,
     BeforeAndAfter,
 }
@@ -29,7 +29,7 @@ impl OutputStyle {
     }
 }
 
-pub struct Formatter<'res, 'mir, 'tcx, A>
+pub(crate) struct Formatter<'res, 'mir, 'tcx, A>
 where
     A: Analysis<'tcx>,
 {
@@ -43,7 +43,7 @@ impl<'res, 'mir, 'tcx, A> Formatter<'res, 'mir, 'tcx, A>
 where
     A: Analysis<'tcx>,
 {
-    pub fn new(
+    pub(crate) fn new(
         body: &'mir Body<'tcx>,
         results: &'res mut Results<'tcx, A>,
         style: OutputStyle,
@@ -55,7 +55,7 @@ where
 
 /// A pair of a basic block and an index into that basic blocks `successors`.
 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
-pub struct CfgEdge {
+pub(crate) struct CfgEdge {
     source: BasicBlock,
     index: usize,
 }
diff --git a/compiler/rustc_mir_dataflow/src/framework/mod.rs b/compiler/rustc_mir_dataflow/src/framework/mod.rs
index 5020a1cf0b2..a5ae1edf221 100644
--- a/compiler/rustc_mir_dataflow/src/framework/mod.rs
+++ b/compiler/rustc_mir_dataflow/src/framework/mod.rs
@@ -45,7 +45,7 @@ pub mod graphviz;
 pub mod lattice;
 mod visitor;
 
-pub use self::cursor::{AnalysisResults, ResultsClonedCursor, ResultsCursor, ResultsRefCursor};
+pub use self::cursor::{ResultsClonedCursor, ResultsCursor, ResultsRefCursor};
 pub use self::direction::{Backward, Direction, Forward};
 pub use self::engine::{Engine, EntrySets, Results, ResultsCloned};
 pub use self::lattice::{JoinSemiLattice, MaybeReachable};
diff --git a/compiler/rustc_mir_dataflow/src/impls/initialized.rs b/compiler/rustc_mir_dataflow/src/impls/initialized.rs
index 61be100d70e..b050e963d8e 100644
--- a/compiler/rustc_mir_dataflow/src/impls/initialized.rs
+++ b/compiler/rustc_mir_dataflow/src/impls/initialized.rs
@@ -72,7 +72,7 @@ impl<'a, 'tcx> MaybeInitializedPlaces<'a, 'tcx> {
     ) -> bool {
         if let LookupResult::Exact(path) = self.move_data().rev_lookup.find(place.as_ref()) {
             let mut maybe_live = false;
-            on_all_children_bits(self.tcx, self.body, self.move_data(), path, |child| {
+            on_all_children_bits(self.move_data(), path, |child| {
                 maybe_live |= state.contains(child);
             });
             !maybe_live
@@ -203,14 +203,13 @@ impl<'a, 'tcx> HasMoveData<'tcx> for MaybeUninitializedPlaces<'a, 'tcx> {
 /// this data and `MaybeInitializedPlaces` yields the set of places
 /// that would require a dynamic drop-flag at that statement.
 pub struct DefinitelyInitializedPlaces<'a, 'tcx> {
-    tcx: TyCtxt<'tcx>,
     body: &'a Body<'tcx>,
     mdpe: &'a MoveDataParamEnv<'tcx>,
 }
 
 impl<'a, 'tcx> DefinitelyInitializedPlaces<'a, 'tcx> {
-    pub fn new(tcx: TyCtxt<'tcx>, body: &'a Body<'tcx>, mdpe: &'a MoveDataParamEnv<'tcx>) -> Self {
-        DefinitelyInitializedPlaces { tcx, body, mdpe }
+    pub fn new(body: &'a Body<'tcx>, mdpe: &'a MoveDataParamEnv<'tcx>) -> Self {
+        DefinitelyInitializedPlaces { body, mdpe }
     }
 }
 
@@ -250,15 +249,13 @@ impl<'a, 'tcx> HasMoveData<'tcx> for DefinitelyInitializedPlaces<'a, 'tcx> {
 /// }
 /// ```
 pub struct EverInitializedPlaces<'a, 'tcx> {
-    #[allow(dead_code)]
-    tcx: TyCtxt<'tcx>,
     body: &'a Body<'tcx>,
     mdpe: &'a MoveDataParamEnv<'tcx>,
 }
 
 impl<'a, 'tcx> EverInitializedPlaces<'a, 'tcx> {
-    pub fn new(tcx: TyCtxt<'tcx>, body: &'a Body<'tcx>, mdpe: &'a MoveDataParamEnv<'tcx>) -> Self {
-        EverInitializedPlaces { tcx, body, mdpe }
+    pub fn new(body: &'a Body<'tcx>, mdpe: &'a MoveDataParamEnv<'tcx>) -> Self {
+        EverInitializedPlaces { body, mdpe }
     }
 }
 
@@ -319,7 +316,7 @@ impl<'tcx> AnalysisDomain<'tcx> for MaybeInitializedPlaces<'_, 'tcx> {
     fn initialize_start_block(&self, _: &mir::Body<'tcx>, state: &mut Self::Domain) {
         *state =
             MaybeReachable::Reachable(ChunkedBitSet::new_empty(self.move_data().move_paths.len()));
-        drop_flag_effects_for_function_entry(self.tcx, self.body, self.mdpe, |path, s| {
+        drop_flag_effects_for_function_entry(self.body, self.mdpe, |path, s| {
             assert!(s == DropFlagState::Present);
             state.gen(path);
         });
@@ -339,7 +336,7 @@ impl<'tcx> GenKillAnalysis<'tcx> for MaybeInitializedPlaces<'_, 'tcx> {
         statement: &mir::Statement<'tcx>,
         location: Location,
     ) {
-        drop_flag_effects_for_location(self.tcx, self.body, self.mdpe, location, |path, s| {
+        drop_flag_effects_for_location(self.body, self.mdpe, location, |path, s| {
             Self::update_bits(trans, path, s)
         });
 
@@ -351,7 +348,7 @@ impl<'tcx> GenKillAnalysis<'tcx> for MaybeInitializedPlaces<'_, 'tcx> {
                 | mir::Rvalue::AddressOf(_, place) = rvalue
             && let LookupResult::Exact(mpi) = self.move_data().rev_lookup.find(place.as_ref())
         {
-            on_all_children_bits(self.tcx, self.body, self.move_data(), mpi, |child| {
+            on_all_children_bits(self.move_data(), mpi, |child| {
                 trans.gen(child);
             })
         }
@@ -371,7 +368,7 @@ impl<'tcx> GenKillAnalysis<'tcx> for MaybeInitializedPlaces<'_, 'tcx> {
         {
             edges = TerminatorEdges::Single(target);
         }
-        drop_flag_effects_for_location(self.tcx, self.body, self.mdpe, location, |path, s| {
+        drop_flag_effects_for_location(self.body, self.mdpe, location, |path, s| {
             Self::update_bits(state, path, s)
         });
         edges
@@ -387,8 +384,6 @@ impl<'tcx> GenKillAnalysis<'tcx> for MaybeInitializedPlaces<'_, 'tcx> {
             // when a call returns successfully, that means we need to set
             // the bits for that dest_place to 1 (initialized).
             on_lookup_result_bits(
-                self.tcx,
-                self.body,
                 self.move_data(),
                 self.move_data().rev_lookup.find(place.as_ref()),
                 |mpi| {
@@ -432,8 +427,6 @@ impl<'tcx> GenKillAnalysis<'tcx> for MaybeInitializedPlaces<'_, 'tcx> {
             // Kill all move paths that correspond to variants we know to be inactive along this
             // particular outgoing edge of a `SwitchInt`.
             drop_flag_effects::on_all_inactive_variants(
-                self.tcx,
-                self.body,
                 self.move_data(),
                 enum_place,
                 variant,
@@ -458,7 +451,7 @@ impl<'tcx> AnalysisDomain<'tcx> for MaybeUninitializedPlaces<'_, 'tcx> {
         // set all bits to 1 (uninit) before gathering counter-evidence
         state.insert_all();
 
-        drop_flag_effects_for_function_entry(self.tcx, self.body, self.mdpe, |path, s| {
+        drop_flag_effects_for_function_entry(self.body, self.mdpe, |path, s| {
             assert!(s == DropFlagState::Present);
             state.remove(path);
         });
@@ -478,7 +471,7 @@ impl<'tcx> GenKillAnalysis<'tcx> for MaybeUninitializedPlaces<'_, 'tcx> {
         _statement: &mir::Statement<'tcx>,
         location: Location,
     ) {
-        drop_flag_effects_for_location(self.tcx, self.body, self.mdpe, location, |path, s| {
+        drop_flag_effects_for_location(self.body, self.mdpe, location, |path, s| {
             Self::update_bits(trans, path, s)
         });
 
@@ -492,7 +485,7 @@ impl<'tcx> GenKillAnalysis<'tcx> for MaybeUninitializedPlaces<'_, 'tcx> {
         terminator: &'mir mir::Terminator<'tcx>,
         location: Location,
     ) -> TerminatorEdges<'mir, 'tcx> {
-        drop_flag_effects_for_location(self.tcx, self.body, self.mdpe, location, |path, s| {
+        drop_flag_effects_for_location(self.body, self.mdpe, location, |path, s| {
             Self::update_bits(trans, path, s)
         });
         if self.skip_unreachable_unwind.contains(location.block) {
@@ -514,8 +507,6 @@ impl<'tcx> GenKillAnalysis<'tcx> for MaybeUninitializedPlaces<'_, 'tcx> {
             // when a call returns successfully, that means we need to set
             // the bits for that dest_place to 0 (initialized).
             on_lookup_result_bits(
-                self.tcx,
-                self.body,
                 self.move_data(),
                 self.move_data().rev_lookup.find(place.as_ref()),
                 |mpi| {
@@ -563,8 +554,6 @@ impl<'tcx> GenKillAnalysis<'tcx> for MaybeUninitializedPlaces<'_, 'tcx> {
             // Mark all move paths that correspond to variants other than this one as maybe
             // uninitialized (in reality, they are *definitely* uninitialized).
             drop_flag_effects::on_all_inactive_variants(
-                self.tcx,
-                self.body,
                 self.move_data(),
                 enum_place,
                 variant,
@@ -589,7 +578,7 @@ impl<'a, 'tcx> AnalysisDomain<'tcx> for DefinitelyInitializedPlaces<'a, 'tcx> {
     fn initialize_start_block(&self, _: &mir::Body<'tcx>, state: &mut Self::Domain) {
         state.0.clear();
 
-        drop_flag_effects_for_function_entry(self.tcx, self.body, self.mdpe, |path, s| {
+        drop_flag_effects_for_function_entry(self.body, self.mdpe, |path, s| {
             assert!(s == DropFlagState::Present);
             state.0.insert(path);
         });
@@ -609,7 +598,7 @@ impl<'tcx> GenKillAnalysis<'tcx> for DefinitelyInitializedPlaces<'_, 'tcx> {
         _statement: &mir::Statement<'tcx>,
         location: Location,
     ) {
-        drop_flag_effects_for_location(self.tcx, self.body, self.mdpe, location, |path, s| {
+        drop_flag_effects_for_location(self.body, self.mdpe, location, |path, s| {
             Self::update_bits(trans, path, s)
         })
     }
@@ -620,7 +609,7 @@ impl<'tcx> GenKillAnalysis<'tcx> for DefinitelyInitializedPlaces<'_, 'tcx> {
         terminator: &'mir mir::Terminator<'tcx>,
         location: Location,
     ) -> TerminatorEdges<'mir, 'tcx> {
-        drop_flag_effects_for_location(self.tcx, self.body, self.mdpe, location, |path, s| {
+        drop_flag_effects_for_location(self.body, self.mdpe, location, |path, s| {
             Self::update_bits(trans, path, s)
         });
         terminator.edges()
@@ -636,8 +625,6 @@ impl<'tcx> GenKillAnalysis<'tcx> for DefinitelyInitializedPlaces<'_, 'tcx> {
             // when a call returns successfully, that means we need to set
             // the bits for that dest_place to 1 (initialized).
             on_lookup_result_bits(
-                self.tcx,
-                self.body,
                 self.move_data(),
                 self.move_data().rev_lookup.find(place.as_ref()),
                 |mpi| {
diff --git a/compiler/rustc_mir_dataflow/src/impls/liveness.rs b/compiler/rustc_mir_dataflow/src/impls/liveness.rs
index bdfb6a6ff6b..c3fdca1641a 100644
--- a/compiler/rustc_mir_dataflow/src/impls/liveness.rs
+++ b/compiler/rustc_mir_dataflow/src/impls/liveness.rs
@@ -23,7 +23,6 @@ use crate::{Analysis, AnalysisDomain, Backward, GenKill, GenKillAnalysis};
 /// [`MaybeBorrowedLocals`]: super::MaybeBorrowedLocals
 /// [flow-test]: https://github.com/rust-lang/rust/blob/a08c47310c7d49cbdc5d7afb38408ba519967ecd/src/test/ui/mir-dataflow/liveness-ptr.rs
 /// [liveness]: https://en.wikipedia.org/wiki/Live_variable_analysis
-#[derive(Clone, Copy)]
 pub struct MaybeLiveLocals;
 
 impl<'tcx> AnalysisDomain<'tcx> for MaybeLiveLocals {
diff --git a/compiler/rustc_mir_dataflow/src/lib.rs b/compiler/rustc_mir_dataflow/src/lib.rs
index eea0e030e7d..cd3378375d8 100644
--- a/compiler/rustc_mir_dataflow/src/lib.rs
+++ b/compiler/rustc_mir_dataflow/src/lib.rs
@@ -4,7 +4,6 @@
 #![feature(let_chains)]
 #![feature(min_specialization)]
 #![feature(stmt_expr_attributes)]
-#![feature(trusted_step)]
 #![recursion_limit = "256"]
 #![deny(rustc::untranslatable_diagnostic)]
 #![deny(rustc::diagnostic_outside_of_impl)]
@@ -14,24 +13,19 @@ extern crate tracing;
 #[macro_use]
 extern crate rustc_middle;
 
-use rustc_ast::MetaItem;
 use rustc_errors::{DiagnosticMessage, SubdiagnosticMessage};
 use rustc_fluent_macro::fluent_messages;
-use rustc_hir::def_id::DefId;
-use rustc_middle::ty::{self, TyCtxt};
-use rustc_span::symbol::{sym, Symbol};
+use rustc_middle::ty;
 
 pub use self::drop_flag_effects::{
     drop_flag_effects_for_function_entry, drop_flag_effects_for_location,
     move_path_children_matching, on_all_children_bits, on_lookup_result_bits,
 };
 pub use self::framework::{
-    fmt, graphviz, lattice, visit_results, Analysis, AnalysisDomain, AnalysisResults, Backward,
-    CloneAnalysis, Direction, Engine, Forward, GenKill, GenKillAnalysis, JoinSemiLattice,
-    MaybeReachable, Results, ResultsCloned, ResultsClonedCursor, ResultsCursor, ResultsRefCursor,
-    ResultsVisitable, ResultsVisitor, SwitchIntEdgeEffects,
+    fmt, lattice, visit_results, Analysis, AnalysisDomain, Direction, GenKill, GenKillAnalysis,
+    JoinSemiLattice, MaybeReachable, Results, ResultsCursor, ResultsVisitable, ResultsVisitor,
 };
-
+use self::framework::{Backward, CloneAnalysis, ResultsClonedCursor, SwitchIntEdgeEffects};
 use self::move_paths::MoveData;
 
 pub mod debuginfo;
@@ -48,24 +42,7 @@ pub mod value_analysis;
 
 fluent_messages! { "../messages.ftl" }
 
-pub(crate) mod indexes {
-    pub(crate) use super::move_paths::MovePathIndex;
-}
-
 pub struct MoveDataParamEnv<'tcx> {
     pub move_data: MoveData<'tcx>,
     pub param_env: ty::ParamEnv<'tcx>,
 }
-
-pub fn has_rustc_mir_with(tcx: TyCtxt<'_>, def_id: DefId, name: Symbol) -> Option<MetaItem> {
-    for attr in tcx.get_attrs(def_id, sym::rustc_mir) {
-        let items = attr.meta_item_list();
-        for item in items.iter().flat_map(|l| l.iter()) {
-            match item.meta_item() {
-                Some(mi) if mi.has_name(name) => return Some(mi.clone()),
-                _ => continue,
-            }
-        }
-    }
-    None
-}
diff --git a/compiler/rustc_mir_dataflow/src/rustc_peek.rs b/compiler/rustc_mir_dataflow/src/rustc_peek.rs
index f9468c8e8cc..448128b6993 100644
--- a/compiler/rustc_mir_dataflow/src/rustc_peek.rs
+++ b/compiler/rustc_mir_dataflow/src/rustc_peek.rs
@@ -1,11 +1,3 @@
-use rustc_span::symbol::sym;
-use rustc_span::Span;
-
-use rustc_index::bit_set::ChunkedBitSet;
-use rustc_middle::mir::MirPass;
-use rustc_middle::mir::{self, Body, Local, Location};
-use rustc_middle::ty::{self, Ty, TyCtxt};
-
 use crate::errors::{
     PeekArgumentNotALocal, PeekArgumentUntracked, PeekBitNotSet, PeekMustBeNotTemporary,
     PeekMustBePlaceOrRefPlace, StopAfterDataFlowEndedCompilation,
@@ -18,13 +10,33 @@ use crate::move_paths::{HasMoveData, MoveData};
 use crate::move_paths::{LookupResult, MovePathIndex};
 use crate::MoveDataParamEnv;
 use crate::{Analysis, JoinSemiLattice, ResultsCursor};
+use rustc_ast::MetaItem;
+use rustc_hir::def_id::DefId;
+use rustc_index::bit_set::ChunkedBitSet;
+use rustc_middle::mir::MirPass;
+use rustc_middle::mir::{self, Body, Local, Location};
+use rustc_middle::ty::{self, Ty, TyCtxt};
+use rustc_span::symbol::{sym, Symbol};
+use rustc_span::Span;
 
 pub struct SanityCheck;
 
+fn has_rustc_mir_with(tcx: TyCtxt<'_>, def_id: DefId, name: Symbol) -> Option<MetaItem> {
+    for attr in tcx.get_attrs(def_id, sym::rustc_mir) {
+        let items = attr.meta_item_list();
+        for item in items.iter().flat_map(|l| l.iter()) {
+            match item.meta_item() {
+                Some(mi) if mi.has_name(name) => return Some(mi.clone()),
+                _ => continue,
+            }
+        }
+    }
+    None
+}
+
 // FIXME: This should be a `MirLint`, but it needs to be moved back to `rustc_mir_transform` first.
 impl<'tcx> MirPass<'tcx> for SanityCheck {
     fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
-        use crate::has_rustc_mir_with;
         let def_id = body.source.def_id();
         if !tcx.has_attr(def_id, sym::rustc_mir) {
             debug!("skipping rustc_peek::SanityCheck on {}", tcx.def_path_str(def_id));
@@ -54,7 +66,7 @@ impl<'tcx> MirPass<'tcx> for SanityCheck {
         }
 
         if has_rustc_mir_with(tcx, def_id, sym::rustc_peek_definite_init).is_some() {
-            let flow_def_inits = DefinitelyInitializedPlaces::new(tcx, body, &mdpe)
+            let flow_def_inits = DefinitelyInitializedPlaces::new(body, &mdpe)
                 .into_engine(tcx, body)
                 .iterate_to_fixpoint();
 
@@ -89,10 +101,8 @@ impl<'tcx> MirPass<'tcx> for SanityCheck {
 /// (If there are any calls to `rustc_peek` that do not match the
 /// expression form above, then that emits an error as well, but those
 /// errors are not intended to be used for unit tests.)
-pub fn sanity_check_via_rustc_peek<'tcx, A>(
-    tcx: TyCtxt<'tcx>,
-    mut cursor: ResultsCursor<'_, 'tcx, A>,
-) where
+fn sanity_check_via_rustc_peek<'tcx, A>(tcx: TyCtxt<'tcx>, mut cursor: ResultsCursor<'_, 'tcx, A>)
+where
     A: RustcPeekAt<'tcx>,
 {
     let def_id = cursor.body().source.def_id();
@@ -129,7 +139,8 @@ pub fn sanity_check_via_rustc_peek<'tcx, A>(
             ) => {
                 let loc = Location { block: bb, statement_index };
                 cursor.seek_before_primary_effect(loc);
-                let (state, analysis) = cursor.get_with_analysis();
+                let state = cursor.get();
+                let analysis = cursor.analysis();
                 analysis.peek_at(tcx, *place, state, call);
             }
 
@@ -173,7 +184,7 @@ impl PeekCallKind {
 }
 
 #[derive(Clone, Copy, Debug)]
-pub struct PeekCall {
+struct PeekCall {
     arg: Local,
     kind: PeekCallKind,
     span: Span,
@@ -221,7 +232,7 @@ impl PeekCall {
     }
 }
 
-pub trait RustcPeekAt<'tcx>: Analysis<'tcx> {
+trait RustcPeekAt<'tcx>: Analysis<'tcx> {
     fn peek_at(
         &self,
         tcx: TyCtxt<'tcx>,
diff --git a/compiler/rustc_mir_dataflow/src/un_derefer.rs b/compiler/rustc_mir_dataflow/src/un_derefer.rs
index 874d50ffd0e..b803ecc575e 100644
--- a/compiler/rustc_mir_dataflow/src/un_derefer.rs
+++ b/compiler/rustc_mir_dataflow/src/un_derefer.rs
@@ -3,13 +3,13 @@ use rustc_middle::mir::*;
 
 /// Used for reverting changes made by `DerefSeparator`
 #[derive(Default, Debug)]
-pub struct UnDerefer<'tcx> {
+pub(crate) struct UnDerefer<'tcx> {
     deref_chains: FxHashMap<Local, Vec<PlaceRef<'tcx>>>,
 }
 
 impl<'tcx> UnDerefer<'tcx> {
     #[inline]
-    pub fn insert(&mut self, local: Local, reffed: PlaceRef<'tcx>) {
+    pub(crate) fn insert(&mut self, local: Local, reffed: PlaceRef<'tcx>) {
         let mut chain = self.deref_chains.remove(&reffed.local).unwrap_or_default();
         chain.push(reffed);
         self.deref_chains.insert(local, chain);
@@ -17,7 +17,7 @@ impl<'tcx> UnDerefer<'tcx> {
 
     /// Returns the chain of places behind `DerefTemp` locals
     #[inline]
-    pub fn deref_chain(&self, local: Local) -> &[PlaceRef<'tcx>] {
+    pub(crate) fn deref_chain(&self, local: Local) -> &[PlaceRef<'tcx>] {
         self.deref_chains.get(&local).map(Vec::as_slice).unwrap_or_default()
     }
 
@@ -25,7 +25,7 @@ impl<'tcx> UnDerefer<'tcx> {
     ///
     /// See [`PlaceRef::iter_projections`]
     #[inline]
-    pub fn iter_projections(
+    pub(crate) fn iter_projections(
         &self,
         place: PlaceRef<'tcx>,
     ) -> impl Iterator<Item = (PlaceRef<'tcx>, PlaceElem<'tcx>)> + '_ {
diff --git a/compiler/rustc_mir_dataflow/src/value_analysis.rs b/compiler/rustc_mir_dataflow/src/value_analysis.rs
index 025d2ddfd4f..9dcd5f22a2d 100644
--- a/compiler/rustc_mir_dataflow/src/value_analysis.rs
+++ b/compiler/rustc_mir_dataflow/src/value_analysis.rs
@@ -332,8 +332,6 @@ pub struct ValueAnalysisWrapper<T>(pub T);
 impl<'tcx, T: ValueAnalysis<'tcx>> AnalysisDomain<'tcx> for ValueAnalysisWrapper<T> {
     type Domain = State<T::Value>;
 
-    type Direction = crate::Forward;
-
     const NAME: &'static str = T::NAME;
 
     fn bottom_value(&self, _body: &Body<'tcx>) -> Self::Domain {
@@ -476,26 +474,10 @@ impl<V: Clone> State<V> {
         }
     }
 
-    pub fn is_reachable(&self) -> bool {
+    fn is_reachable(&self) -> bool {
         matches!(&self.0, StateData::Reachable(_))
     }
 
-    pub fn mark_unreachable(&mut self) {
-        self.0 = StateData::Unreachable;
-    }
-
-    pub fn flood_all(&mut self)
-    where
-        V: HasTop,
-    {
-        self.flood_all_with(V::TOP)
-    }
-
-    pub fn flood_all_with(&mut self, value: V) {
-        let StateData::Reachable(values) = &mut self.0 else { return };
-        values.raw.fill(value);
-    }
-
     /// Assign `value` to all places that are contained in `place` or may alias one.
     pub fn flood_with(&mut self, place: PlaceRef<'_>, map: &Map, value: V) {
         self.flood_with_tail_elem(place, None, map, value)
@@ -510,7 +492,7 @@ impl<V: Clone> State<V> {
     }
 
     /// Assign `value` to the discriminant of `place` and all places that may alias it.
-    pub fn flood_discr_with(&mut self, place: PlaceRef<'_>, map: &Map, value: V) {
+    fn flood_discr_with(&mut self, place: PlaceRef<'_>, map: &Map, value: V) {
         self.flood_with_tail_elem(place, Some(TrackElem::Discriminant), map, value)
     }
 
@@ -546,7 +528,7 @@ impl<V: Clone> State<V> {
     /// This does nothing if the place is not tracked.
     ///
     /// The target place must have been flooded before calling this method.
-    pub fn insert_idx(&mut self, target: PlaceIndex, result: ValueOrPlace<V>, map: &Map) {
+    fn insert_idx(&mut self, target: PlaceIndex, result: ValueOrPlace<V>, map: &Map) {
         match result {
             ValueOrPlace::Value(value) => self.insert_value_idx(target, value, map),
             ValueOrPlace::Place(source) => self.insert_place_idx(target, source, map),
@@ -910,18 +892,13 @@ impl Map {
         self.inner_values[root] = start..end;
     }
 
-    /// Returns the number of tracked places, i.e., those for which a value can be stored.
-    pub fn tracked_places(&self) -> usize {
-        self.value_count
-    }
-
     /// Applies a single projection element, yielding the corresponding child.
     pub fn apply(&self, place: PlaceIndex, elem: TrackElem) -> Option<PlaceIndex> {
         self.projections.get(&(place, elem)).copied()
     }
 
     /// Locates the given place, if it exists in the tree.
-    pub fn find_extra(
+    fn find_extra(
         &self,
         place: PlaceRef<'_>,
         extra: impl IntoIterator<Item = TrackElem>,
@@ -954,7 +931,7 @@ impl Map {
     }
 
     /// Iterate over all direct children.
-    pub fn children(&self, parent: PlaceIndex) -> impl Iterator<Item = PlaceIndex> + '_ {
+    fn children(&self, parent: PlaceIndex) -> impl Iterator<Item = PlaceIndex> + '_ {
         Children::new(self, parent)
     }
 
diff --git a/compiler/rustc_mir_transform/src/coroutine.rs b/compiler/rustc_mir_transform/src/coroutine.rs
index 84bcc540167..1cb1a9886a0 100644
--- a/compiler/rustc_mir_transform/src/coroutine.rs
+++ b/compiler/rustc_mir_transform/src/coroutine.rs
@@ -668,36 +668,34 @@ fn locals_live_across_suspend_points<'tcx>(
     always_live_locals: &BitSet<Local>,
     movable: bool,
 ) -> LivenessInfo {
-    let body_ref: &Body<'_> = body;
-
     // Calculate when MIR locals have live storage. This gives us an upper bound of their
     // lifetimes.
     let mut storage_live = MaybeStorageLive::new(std::borrow::Cow::Borrowed(always_live_locals))
-        .into_engine(tcx, body_ref)
+        .into_engine(tcx, body)
         .iterate_to_fixpoint()
-        .into_results_cursor(body_ref);
+        .into_results_cursor(body);
 
     // Calculate the MIR locals which have been previously
     // borrowed (even if they are still active).
     let borrowed_locals_results =
-        MaybeBorrowedLocals.into_engine(tcx, body_ref).pass_name("coroutine").iterate_to_fixpoint();
+        MaybeBorrowedLocals.into_engine(tcx, body).pass_name("coroutine").iterate_to_fixpoint();
 
-    let mut borrowed_locals_cursor = borrowed_locals_results.cloned_results_cursor(body_ref);
+    let mut borrowed_locals_cursor = borrowed_locals_results.cloned_results_cursor(body);
 
     // Calculate the MIR locals that we actually need to keep storage around
     // for.
     let mut requires_storage_results =
         MaybeRequiresStorage::new(borrowed_locals_results.cloned_results_cursor(body))
-            .into_engine(tcx, body_ref)
+            .into_engine(tcx, body)
             .iterate_to_fixpoint();
-    let mut requires_storage_cursor = requires_storage_results.as_results_cursor(body_ref);
+    let mut requires_storage_cursor = requires_storage_results.as_results_cursor(body);
 
     // Calculate the liveness of MIR locals ignoring borrows.
     let mut liveness = MaybeLiveLocals
-        .into_engine(tcx, body_ref)
+        .into_engine(tcx, body)
         .pass_name("coroutine")
         .iterate_to_fixpoint()
-        .into_results_cursor(body_ref);
+        .into_results_cursor(body);
 
     let mut storage_liveness_map = IndexVec::from_elem(None, &body.basic_blocks);
     let mut live_locals_at_suspension_points = Vec::new();
@@ -763,7 +761,7 @@ fn locals_live_across_suspend_points<'tcx>(
         .collect();
 
     let storage_conflicts = compute_storage_conflicts(
-        body_ref,
+        body,
         &saved_locals,
         always_live_locals.clone(),
         requires_storage_results,
diff --git a/compiler/rustc_mir_transform/src/elaborate_drops.rs b/compiler/rustc_mir_transform/src/elaborate_drops.rs
index d4e40a1b57c..83517aef7e2 100644
--- a/compiler/rustc_mir_transform/src/elaborate_drops.rs
+++ b/compiler/rustc_mir_transform/src/elaborate_drops.rs
@@ -172,19 +172,13 @@ impl<'a, 'tcx> DropElaborator<'a, 'tcx> for Elaborator<'a, '_, 'tcx> {
                 let mut some_live = false;
                 let mut some_dead = false;
                 let mut children_count = 0;
-                on_all_children_bits(
-                    self.tcx(),
-                    self.body(),
-                    self.ctxt.move_data(),
-                    path,
-                    |child| {
-                        let (live, dead) = self.ctxt.init_data.maybe_live_dead(child);
-                        debug!("elaborate_drop: state({:?}) = {:?}", child, (live, dead));
-                        some_live |= live;
-                        some_dead |= dead;
-                        children_count += 1;
-                    },
-                );
+                on_all_children_bits(self.ctxt.move_data(), path, |child| {
+                    let (live, dead) = self.ctxt.init_data.maybe_live_dead(child);
+                    debug!("elaborate_drop: state({:?}) = {:?}", child, (live, dead));
+                    some_live |= live;
+                    some_dead |= dead;
+                    children_count += 1;
+                });
                 ((some_live, some_dead), children_count != 1)
             }
         };
@@ -202,13 +196,9 @@ impl<'a, 'tcx> DropElaborator<'a, 'tcx> for Elaborator<'a, '_, 'tcx> {
                 self.ctxt.set_drop_flag(loc, path, DropFlagState::Absent);
             }
             DropFlagMode::Deep => {
-                on_all_children_bits(
-                    self.tcx(),
-                    self.body(),
-                    self.ctxt.move_data(),
-                    path,
-                    |child| self.ctxt.set_drop_flag(loc, child, DropFlagState::Absent),
-                );
+                on_all_children_bits(self.ctxt.move_data(), path, |child| {
+                    self.ctxt.set_drop_flag(loc, child, DropFlagState::Absent)
+                });
             }
         }
     }
@@ -268,10 +258,9 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> {
     }
 
     fn create_drop_flag(&mut self, index: MovePathIndex, span: Span) {
-        let tcx = self.tcx;
         let patch = &mut self.patch;
         debug!("create_drop_flag({:?})", self.body.span);
-        self.drop_flags[index].get_or_insert_with(|| patch.new_temp(tcx.types.bool, span));
+        self.drop_flags[index].get_or_insert_with(|| patch.new_temp(self.tcx.types.bool, span));
     }
 
     fn drop_flag(&mut self, index: MovePathIndex) -> Option<Place<'tcx>> {
@@ -304,7 +293,7 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> {
             match path {
                 LookupResult::Exact(path) => {
                     self.init_data.seek_before(self.body.terminator_loc(bb));
-                    on_all_children_bits(self.tcx, self.body, self.move_data(), path, |child| {
+                    on_all_children_bits(self.move_data(), path, |child| {
                         let (maybe_live, maybe_dead) = self.init_data.maybe_live_dead(child);
                         debug!(
                             "collect_drop_flags: collecting {:?} from {:?}@{:?} - {:?}",
@@ -444,7 +433,7 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> {
 
                 let loc = Location { block: tgt, statement_index: 0 };
                 let path = self.move_data().rev_lookup.find(destination.as_ref());
-                on_lookup_result_bits(self.tcx, self.body, self.move_data(), path, |child| {
+                on_lookup_result_bits(self.move_data(), path, |child| {
                     self.set_drop_flag(loc, child, DropFlagState::Present)
                 });
             }
@@ -453,14 +442,9 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> {
 
     fn drop_flags_for_args(&mut self) {
         let loc = Location::START;
-        rustc_mir_dataflow::drop_flag_effects_for_function_entry(
-            self.tcx,
-            self.body,
-            self.env,
-            |path, ds| {
-                self.set_drop_flag(loc, path, ds);
-            },
-        )
+        rustc_mir_dataflow::drop_flag_effects_for_function_entry(self.body, self.env, |path, ds| {
+            self.set_drop_flag(loc, path, ds);
+        })
     }
 
     fn drop_flags_for_locs(&mut self) {
@@ -492,7 +476,6 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> {
                 }
                 let loc = Location { block: bb, statement_index: i };
                 rustc_mir_dataflow::drop_flag_effects_for_location(
-                    self.tcx,
                     self.body,
                     self.env,
                     loc,
@@ -515,7 +498,7 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> {
 
                 let loc = Location { block: bb, statement_index: data.statements.len() };
                 let path = self.move_data().rev_lookup.find(destination.as_ref());
-                on_lookup_result_bits(self.tcx, self.body, self.move_data(), path, |child| {
+                on_lookup_result_bits(self.move_data(), path, |child| {
                     self.set_drop_flag(loc, child, DropFlagState::Present)
                 });
             }
diff --git a/compiler/rustc_smir/src/rustc_internal/mod.rs b/compiler/rustc_smir/src/rustc_internal/mod.rs
index fed21f16a4e..c3db9b358e8 100644
--- a/compiler/rustc_smir/src/rustc_internal/mod.rs
+++ b/compiler/rustc_smir/src/rustc_internal/mod.rs
@@ -3,7 +3,7 @@
 //! For that, we define APIs that will temporarily be public to 3P that exposes rustc internal APIs
 //! until stable MIR is complete.
 
-use crate::rustc_smir::{Stable, Tables, TablesWrapper};
+use crate::rustc_smir::{context::TablesWrapper, Stable, Tables};
 use rustc_data_structures::fx;
 use rustc_data_structures::fx::FxIndexMap;
 use rustc_middle::mir::interpret::AllocId;
@@ -181,7 +181,7 @@ where
         instances: IndexMap::default(),
         constants: IndexMap::default(),
     }));
-    stable_mir::run(&tables, || init(&tables, f))
+    stable_mir::compiler_interface::run(&tables, || init(&tables, f))
 }
 
 #[macro_export]
diff --git a/compiler/rustc_smir/src/rustc_smir/context.rs b/compiler/rustc_smir/src/rustc_smir/context.rs
new file mode 100644
index 00000000000..3449176f729
--- /dev/null
+++ b/compiler/rustc_smir/src/rustc_smir/context.rs
@@ -0,0 +1,376 @@
+//! Implementation of `[stable_mir::compiler_interface::Context]` trait.
+//!
+//! This trait is currently the main interface between the Rust compiler,
+//! and the `stable_mir` crate.
+
+use rustc_middle::ty::print::{with_forced_trimmed_paths, with_no_trimmed_paths};
+use rustc_middle::ty::{GenericPredicates, Instance, ParamEnv, ScalarInt, ValTree};
+use rustc_span::def_id::LOCAL_CRATE;
+use stable_mir::compiler_interface::Context;
+use stable_mir::mir::alloc::GlobalAlloc;
+use stable_mir::mir::mono::{InstanceDef, StaticDef};
+use stable_mir::mir::Body;
+use stable_mir::ty::{
+    AdtDef, AdtKind, Allocation, ClosureDef, ClosureKind, Const, FnDef, GenericArgs, LineInfo,
+    RigidTy, Span, TyKind,
+};
+use stable_mir::{self, Crate, CrateItem, Error, Filename, ItemKind, Symbol};
+use std::cell::RefCell;
+
+use crate::rustc_internal::{internal, RustcInternal};
+use crate::rustc_smir::builder::BodyBuilder;
+use crate::rustc_smir::{new_item_kind, smir_crate, Stable, Tables};
+
+impl<'tcx> Context for TablesWrapper<'tcx> {
+    fn entry_fn(&self) -> Option<stable_mir::CrateItem> {
+        let mut tables = self.0.borrow_mut();
+        let tcx = tables.tcx;
+        Some(tables.crate_item(tcx.entry_fn(())?.0))
+    }
+
+    fn all_local_items(&self) -> stable_mir::CrateItems {
+        let mut tables = self.0.borrow_mut();
+        tables.tcx.mir_keys(()).iter().map(|item| tables.crate_item(item.to_def_id())).collect()
+    }
+
+    fn mir_body(&self, item: stable_mir::DefId) -> stable_mir::mir::Body {
+        let mut tables = self.0.borrow_mut();
+        let def_id = tables[item];
+        tables.tcx.instance_mir(rustc_middle::ty::InstanceDef::Item(def_id)).stable(&mut tables)
+    }
+
+    fn all_trait_decls(&self) -> stable_mir::TraitDecls {
+        let mut tables = self.0.borrow_mut();
+        tables
+            .tcx
+            .traits(LOCAL_CRATE)
+            .iter()
+            .map(|trait_def_id| tables.trait_def(*trait_def_id))
+            .collect()
+    }
+
+    fn trait_decl(&self, trait_def: &stable_mir::ty::TraitDef) -> stable_mir::ty::TraitDecl {
+        let mut tables = self.0.borrow_mut();
+        let def_id = tables[trait_def.0];
+        let trait_def = tables.tcx.trait_def(def_id);
+        trait_def.stable(&mut *tables)
+    }
+
+    fn all_trait_impls(&self) -> stable_mir::ImplTraitDecls {
+        let mut tables = self.0.borrow_mut();
+        tables
+            .tcx
+            .trait_impls_in_crate(LOCAL_CRATE)
+            .iter()
+            .map(|impl_def_id| tables.impl_def(*impl_def_id))
+            .collect()
+    }
+
+    fn trait_impl(&self, impl_def: &stable_mir::ty::ImplDef) -> stable_mir::ty::ImplTrait {
+        let mut tables = self.0.borrow_mut();
+        let def_id = tables[impl_def.0];
+        let impl_trait = tables.tcx.impl_trait_ref(def_id).unwrap();
+        impl_trait.stable(&mut *tables)
+    }
+
+    fn generics_of(&self, def_id: stable_mir::DefId) -> stable_mir::ty::Generics {
+        let mut tables = self.0.borrow_mut();
+        let def_id = tables[def_id];
+        let generics = tables.tcx.generics_of(def_id);
+        generics.stable(&mut *tables)
+    }
+
+    fn predicates_of(&self, def_id: stable_mir::DefId) -> stable_mir::ty::GenericPredicates {
+        let mut tables = self.0.borrow_mut();
+        let def_id = tables[def_id];
+        let GenericPredicates { parent, predicates } = tables.tcx.predicates_of(def_id);
+        stable_mir::ty::GenericPredicates {
+            parent: parent.map(|did| tables.trait_def(did)),
+            predicates: predicates
+                .iter()
+                .map(|(clause, span)| {
+                    (
+                        clause.as_predicate().kind().skip_binder().stable(&mut *tables),
+                        span.stable(&mut *tables),
+                    )
+                })
+                .collect(),
+        }
+    }
+
+    fn explicit_predicates_of(
+        &self,
+        def_id: stable_mir::DefId,
+    ) -> stable_mir::ty::GenericPredicates {
+        let mut tables = self.0.borrow_mut();
+        let def_id = tables[def_id];
+        let GenericPredicates { parent, predicates } = tables.tcx.explicit_predicates_of(def_id);
+        stable_mir::ty::GenericPredicates {
+            parent: parent.map(|did| tables.trait_def(did)),
+            predicates: predicates
+                .iter()
+                .map(|(clause, span)| {
+                    (
+                        clause.as_predicate().kind().skip_binder().stable(&mut *tables),
+                        span.stable(&mut *tables),
+                    )
+                })
+                .collect(),
+        }
+    }
+
+    fn local_crate(&self) -> stable_mir::Crate {
+        let tables = self.0.borrow();
+        smir_crate(tables.tcx, LOCAL_CRATE)
+    }
+
+    fn external_crates(&self) -> Vec<stable_mir::Crate> {
+        let tables = self.0.borrow();
+        tables.tcx.crates(()).iter().map(|crate_num| smir_crate(tables.tcx, *crate_num)).collect()
+    }
+
+    fn find_crates(&self, name: &str) -> Vec<stable_mir::Crate> {
+        let tables = self.0.borrow();
+        let crates: Vec<stable_mir::Crate> = [LOCAL_CRATE]
+            .iter()
+            .chain(tables.tcx.crates(()).iter())
+            .map(|crate_num| {
+                let crate_name = tables.tcx.crate_name(*crate_num).to_string();
+                (name == crate_name).then(|| smir_crate(tables.tcx, *crate_num))
+            })
+            .into_iter()
+            .filter_map(|c| c)
+            .collect();
+        crates
+    }
+
+    fn def_name(&self, def_id: stable_mir::DefId, trimmed: bool) -> Symbol {
+        let tables = self.0.borrow();
+        if trimmed {
+            with_forced_trimmed_paths!(tables.tcx.def_path_str(tables[def_id]))
+        } else {
+            with_no_trimmed_paths!(tables.tcx.def_path_str(tables[def_id]))
+        }
+    }
+
+    fn span_to_string(&self, span: stable_mir::ty::Span) -> String {
+        let tables = self.0.borrow();
+        tables.tcx.sess.source_map().span_to_diagnostic_string(tables[span])
+    }
+
+    fn get_filename(&self, span: &Span) -> Filename {
+        let tables = self.0.borrow();
+        tables
+            .tcx
+            .sess
+            .source_map()
+            .span_to_filename(tables[*span])
+            .display(rustc_span::FileNameDisplayPreference::Local)
+            .to_string()
+    }
+
+    fn get_lines(&self, span: &Span) -> LineInfo {
+        let tables = self.0.borrow();
+        let lines = &tables.tcx.sess.source_map().span_to_location_info(tables[*span]);
+        LineInfo { start_line: lines.1, start_col: lines.2, end_line: lines.3, end_col: lines.4 }
+    }
+
+    fn item_kind(&self, item: CrateItem) -> ItemKind {
+        let tables = self.0.borrow();
+        new_item_kind(tables.tcx.def_kind(tables[item.0]))
+    }
+
+    fn is_foreign_item(&self, item: CrateItem) -> bool {
+        let tables = self.0.borrow();
+        tables.tcx.is_foreign_item(tables[item.0])
+    }
+
+    fn adt_kind(&self, def: AdtDef) -> AdtKind {
+        let mut tables = self.0.borrow_mut();
+        def.internal(&mut *tables).adt_kind().stable(&mut *tables)
+    }
+
+    fn adt_is_box(&self, def: AdtDef) -> bool {
+        let mut tables = self.0.borrow_mut();
+        def.internal(&mut *tables).is_box()
+    }
+
+    fn eval_target_usize(&self, cnst: &Const) -> Result<u64, Error> {
+        let mut tables = self.0.borrow_mut();
+        let mir_const = cnst.internal(&mut *tables);
+        mir_const
+            .try_eval_target_usize(tables.tcx, ParamEnv::empty())
+            .ok_or_else(|| Error::new(format!("Const `{cnst:?}` cannot be encoded as u64")))
+    }
+
+    fn usize_to_const(&self, val: u64) -> Result<Const, Error> {
+        let mut tables = self.0.borrow_mut();
+        let ty = tables.tcx.types.usize;
+        let size = tables.tcx.layout_of(ParamEnv::empty().and(ty)).unwrap().size;
+
+        let scalar = ScalarInt::try_from_uint(val, size).ok_or_else(|| {
+            Error::new(format!("Value overflow: cannot convert `{val}` to usize."))
+        })?;
+        Ok(rustc_middle::ty::Const::new_value(tables.tcx, ValTree::from_scalar_int(scalar), ty)
+            .stable(&mut *tables))
+    }
+
+    fn new_rigid_ty(&self, kind: RigidTy) -> stable_mir::ty::Ty {
+        let mut tables = self.0.borrow_mut();
+        let internal_kind = kind.internal(&mut *tables);
+        tables.tcx.mk_ty_from_kind(internal_kind).stable(&mut *tables)
+    }
+
+    fn def_ty(&self, item: stable_mir::DefId) -> stable_mir::ty::Ty {
+        let mut tables = self.0.borrow_mut();
+        tables.tcx.type_of(item.internal(&mut *tables)).instantiate_identity().stable(&mut *tables)
+    }
+
+    fn const_literal(&self, cnst: &stable_mir::ty::Const) -> String {
+        internal(cnst).to_string()
+    }
+
+    fn span_of_an_item(&self, def_id: stable_mir::DefId) -> Span {
+        let mut tables = self.0.borrow_mut();
+        tables.tcx.def_span(tables[def_id]).stable(&mut *tables)
+    }
+
+    fn ty_kind(&self, ty: stable_mir::ty::Ty) -> TyKind {
+        let mut tables = self.0.borrow_mut();
+        tables.types[ty].kind().stable(&mut *tables)
+    }
+
+    fn instance_body(&self, def: InstanceDef) -> Option<Body> {
+        let mut tables = self.0.borrow_mut();
+        let instance = tables.instances[def];
+        tables
+            .has_body(instance)
+            .then(|| BodyBuilder::new(tables.tcx, instance).build(&mut *tables))
+    }
+
+    fn instance_ty(&self, def: InstanceDef) -> stable_mir::ty::Ty {
+        let mut tables = self.0.borrow_mut();
+        let instance = tables.instances[def];
+        instance.ty(tables.tcx, ParamEnv::empty()).stable(&mut *tables)
+    }
+
+    fn instance_def_id(&self, def: InstanceDef) -> stable_mir::DefId {
+        let mut tables = self.0.borrow_mut();
+        let def_id = tables.instances[def].def_id();
+        tables.create_def_id(def_id)
+    }
+
+    fn instance_mangled_name(&self, instance: InstanceDef) -> Symbol {
+        let tables = self.0.borrow_mut();
+        let instance = tables.instances[instance];
+        tables.tcx.symbol_name(instance).name.to_string()
+    }
+
+    fn mono_instance(&self, item: stable_mir::CrateItem) -> stable_mir::mir::mono::Instance {
+        let mut tables = self.0.borrow_mut();
+        let def_id = tables[item.0];
+        Instance::mono(tables.tcx, def_id).stable(&mut *tables)
+    }
+
+    fn requires_monomorphization(&self, def_id: stable_mir::DefId) -> bool {
+        let tables = self.0.borrow();
+        let def_id = tables[def_id];
+        let generics = tables.tcx.generics_of(def_id);
+        let result = generics.requires_monomorphization(tables.tcx);
+        result
+    }
+
+    fn resolve_instance(
+        &self,
+        def: stable_mir::ty::FnDef,
+        args: &stable_mir::ty::GenericArgs,
+    ) -> Option<stable_mir::mir::mono::Instance> {
+        let mut tables = self.0.borrow_mut();
+        let def_id = def.0.internal(&mut *tables);
+        let args_ref = args.internal(&mut *tables);
+        match Instance::resolve(tables.tcx, ParamEnv::reveal_all(), def_id, args_ref) {
+            Ok(Some(instance)) => Some(instance.stable(&mut *tables)),
+            Ok(None) | Err(_) => None,
+        }
+    }
+
+    fn resolve_drop_in_place(&self, ty: stable_mir::ty::Ty) -> stable_mir::mir::mono::Instance {
+        let mut tables = self.0.borrow_mut();
+        let internal_ty = ty.internal(&mut *tables);
+        let instance = Instance::resolve_drop_in_place(tables.tcx, internal_ty);
+        instance.stable(&mut *tables)
+    }
+
+    fn resolve_for_fn_ptr(
+        &self,
+        def: FnDef,
+        args: &GenericArgs,
+    ) -> Option<stable_mir::mir::mono::Instance> {
+        let mut tables = self.0.borrow_mut();
+        let def_id = def.0.internal(&mut *tables);
+        let args_ref = args.internal(&mut *tables);
+        Instance::resolve_for_fn_ptr(tables.tcx, ParamEnv::reveal_all(), def_id, args_ref)
+            .stable(&mut *tables)
+    }
+
+    fn resolve_closure(
+        &self,
+        def: ClosureDef,
+        args: &GenericArgs,
+        kind: ClosureKind,
+    ) -> Option<stable_mir::mir::mono::Instance> {
+        let mut tables = self.0.borrow_mut();
+        let def_id = def.0.internal(&mut *tables);
+        let args_ref = args.internal(&mut *tables);
+        let closure_kind = kind.internal(&mut *tables);
+        Instance::resolve_closure(tables.tcx, def_id, args_ref, closure_kind).stable(&mut *tables)
+    }
+
+    fn eval_static_initializer(&self, def: StaticDef) -> Result<Allocation, Error> {
+        let mut tables = self.0.borrow_mut();
+        let def_id = def.0.internal(&mut *tables);
+        tables.tcx.eval_static_initializer(def_id).stable(&mut *tables)
+    }
+
+    fn global_alloc(&self, alloc: stable_mir::mir::alloc::AllocId) -> GlobalAlloc {
+        let mut tables = self.0.borrow_mut();
+        let alloc_id = alloc.internal(&mut *tables);
+        tables.tcx.global_alloc(alloc_id).stable(&mut *tables)
+    }
+
+    fn vtable_allocation(
+        &self,
+        global_alloc: &GlobalAlloc,
+    ) -> Option<stable_mir::mir::alloc::AllocId> {
+        let mut tables = self.0.borrow_mut();
+        let GlobalAlloc::VTable(ty, trait_ref) = global_alloc else { return None };
+        let alloc_id = tables
+            .tcx
+            .vtable_allocation((ty.internal(&mut *tables), trait_ref.internal(&mut *tables)));
+        Some(alloc_id.stable(&mut *tables))
+    }
+
+    fn krate(&self, def_id: stable_mir::DefId) -> Crate {
+        let tables = self.0.borrow();
+        smir_crate(tables.tcx, tables[def_id].krate)
+    }
+
+    /// Retrieve the instance name for diagnostic messages.
+    ///
+    /// This will return the specialized name, e.g., `Vec<char>::new`.
+    fn instance_name(&self, def: InstanceDef, trimmed: bool) -> Symbol {
+        let tables = self.0.borrow_mut();
+        let instance = tables.instances[def];
+        if trimmed {
+            with_forced_trimmed_paths!(
+                tables.tcx.def_path_str_with_args(instance.def_id(), instance.args)
+            )
+        } else {
+            with_no_trimmed_paths!(
+                tables.tcx.def_path_str_with_args(instance.def_id(), instance.args)
+            )
+        }
+    }
+}
+
+pub struct TablesWrapper<'tcx>(pub RefCell<Tables<'tcx>>);
diff --git a/compiler/rustc_smir/src/rustc_smir/convert/mir.rs b/compiler/rustc_smir/src/rustc_smir/convert/mir.rs
new file mode 100644
index 00000000000..62a26bc089a
--- /dev/null
+++ b/compiler/rustc_smir/src/rustc_smir/convert/mir.rs
@@ -0,0 +1,745 @@
+//! Conversion of internal Rust compiler `mir` items to stable ones.
+
+use rustc_middle::mir;
+use rustc_middle::mir::interpret::alloc_range;
+use rustc_middle::mir::mono::MonoItem;
+use stable_mir::mir::alloc::GlobalAlloc;
+use stable_mir::mir::{ConstOperand, Statement, UserTypeProjection, VarDebugInfoFragment};
+use stable_mir::ty::{Allocation, Const, ConstantKind};
+use stable_mir::{opaque, Error};
+
+use crate::rustc_smir::{alloc, Stable, Tables};
+
+impl<'tcx> Stable<'tcx> for mir::Body<'tcx> {
+    type T = stable_mir::mir::Body;
+
+    fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T {
+        stable_mir::mir::Body::new(
+            self.basic_blocks
+                .iter()
+                .map(|block| stable_mir::mir::BasicBlock {
+                    terminator: block.terminator().stable(tables),
+                    statements: block
+                        .statements
+                        .iter()
+                        .map(|statement| statement.stable(tables))
+                        .collect(),
+                })
+                .collect(),
+            self.local_decls
+                .iter()
+                .map(|decl| stable_mir::mir::LocalDecl {
+                    ty: decl.ty.stable(tables),
+                    span: decl.source_info.span.stable(tables),
+                    mutability: decl.mutability.stable(tables),
+                })
+                .collect(),
+            self.arg_count,
+            self.var_debug_info.iter().map(|info| info.stable(tables)).collect(),
+        )
+    }
+}
+
+impl<'tcx> Stable<'tcx> for mir::VarDebugInfo<'tcx> {
+    type T = stable_mir::mir::VarDebugInfo;
+    fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T {
+        stable_mir::mir::VarDebugInfo {
+            name: self.name.to_string(),
+            source_info: self.source_info.stable(tables),
+            composite: self.composite.as_ref().map(|composite| composite.stable(tables)),
+            value: self.value.stable(tables),
+            argument_index: self.argument_index,
+        }
+    }
+}
+
+impl<'tcx> Stable<'tcx> for mir::Statement<'tcx> {
+    type T = stable_mir::mir::Statement;
+    fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T {
+        Statement { kind: self.kind.stable(tables), span: self.source_info.span.stable(tables) }
+    }
+}
+
+impl<'tcx> Stable<'tcx> for mir::SourceInfo {
+    type T = stable_mir::mir::SourceInfo;
+    fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T {
+        stable_mir::mir::SourceInfo { span: self.span.stable(tables), scope: self.scope.into() }
+    }
+}
+
+impl<'tcx> Stable<'tcx> for mir::VarDebugInfoFragment<'tcx> {
+    type T = stable_mir::mir::VarDebugInfoFragment;
+    fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T {
+        VarDebugInfoFragment {
+            ty: self.ty.stable(tables),
+            projection: self.projection.iter().map(|e| e.stable(tables)).collect(),
+        }
+    }
+}
+
+impl<'tcx> Stable<'tcx> for mir::VarDebugInfoContents<'tcx> {
+    type T = stable_mir::mir::VarDebugInfoContents;
+    fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T {
+        match self {
+            mir::VarDebugInfoContents::Place(place) => {
+                stable_mir::mir::VarDebugInfoContents::Place(place.stable(tables))
+            }
+            mir::VarDebugInfoContents::Const(const_operand) => {
+                let op = ConstOperand {
+                    span: const_operand.span.stable(tables),
+                    user_ty: const_operand.user_ty.map(|index| index.as_usize()),
+                    const_: const_operand.const_.stable(tables),
+                };
+                stable_mir::mir::VarDebugInfoContents::Const(op)
+            }
+        }
+    }
+}
+
+impl<'tcx> Stable<'tcx> for mir::StatementKind<'tcx> {
+    type T = stable_mir::mir::StatementKind;
+    fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T {
+        match self {
+            mir::StatementKind::Assign(assign) => stable_mir::mir::StatementKind::Assign(
+                assign.0.stable(tables),
+                assign.1.stable(tables),
+            ),
+            mir::StatementKind::FakeRead(fake_read_place) => {
+                stable_mir::mir::StatementKind::FakeRead(
+                    fake_read_place.0.stable(tables),
+                    fake_read_place.1.stable(tables),
+                )
+            }
+            mir::StatementKind::SetDiscriminant { place, variant_index } => {
+                stable_mir::mir::StatementKind::SetDiscriminant {
+                    place: place.as_ref().stable(tables),
+                    variant_index: variant_index.stable(tables),
+                }
+            }
+            mir::StatementKind::Deinit(place) => {
+                stable_mir::mir::StatementKind::Deinit(place.stable(tables))
+            }
+
+            mir::StatementKind::StorageLive(place) => {
+                stable_mir::mir::StatementKind::StorageLive(place.stable(tables))
+            }
+
+            mir::StatementKind::StorageDead(place) => {
+                stable_mir::mir::StatementKind::StorageDead(place.stable(tables))
+            }
+            mir::StatementKind::Retag(retag, place) => {
+                stable_mir::mir::StatementKind::Retag(retag.stable(tables), place.stable(tables))
+            }
+            mir::StatementKind::PlaceMention(place) => {
+                stable_mir::mir::StatementKind::PlaceMention(place.stable(tables))
+            }
+            mir::StatementKind::AscribeUserType(place_projection, variance) => {
+                stable_mir::mir::StatementKind::AscribeUserType {
+                    place: place_projection.as_ref().0.stable(tables),
+                    projections: place_projection.as_ref().1.stable(tables),
+                    variance: variance.stable(tables),
+                }
+            }
+            mir::StatementKind::Coverage(coverage) => {
+                stable_mir::mir::StatementKind::Coverage(opaque(coverage))
+            }
+            mir::StatementKind::Intrinsic(intrinstic) => {
+                stable_mir::mir::StatementKind::Intrinsic(intrinstic.stable(tables))
+            }
+            mir::StatementKind::ConstEvalCounter => {
+                stable_mir::mir::StatementKind::ConstEvalCounter
+            }
+            mir::StatementKind::Nop => stable_mir::mir::StatementKind::Nop,
+        }
+    }
+}
+
+impl<'tcx> Stable<'tcx> for mir::Rvalue<'tcx> {
+    type T = stable_mir::mir::Rvalue;
+    fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T {
+        use rustc_middle::mir::Rvalue::*;
+        match self {
+            Use(op) => stable_mir::mir::Rvalue::Use(op.stable(tables)),
+            Repeat(op, len) => {
+                let len = len.stable(tables);
+                stable_mir::mir::Rvalue::Repeat(op.stable(tables), len)
+            }
+            Ref(region, kind, place) => stable_mir::mir::Rvalue::Ref(
+                region.stable(tables),
+                kind.stable(tables),
+                place.stable(tables),
+            ),
+            ThreadLocalRef(def_id) => {
+                stable_mir::mir::Rvalue::ThreadLocalRef(tables.crate_item(*def_id))
+            }
+            AddressOf(mutability, place) => {
+                stable_mir::mir::Rvalue::AddressOf(mutability.stable(tables), place.stable(tables))
+            }
+            Len(place) => stable_mir::mir::Rvalue::Len(place.stable(tables)),
+            Cast(cast_kind, op, ty) => stable_mir::mir::Rvalue::Cast(
+                cast_kind.stable(tables),
+                op.stable(tables),
+                ty.stable(tables),
+            ),
+            BinaryOp(bin_op, ops) => stable_mir::mir::Rvalue::BinaryOp(
+                bin_op.stable(tables),
+                ops.0.stable(tables),
+                ops.1.stable(tables),
+            ),
+            CheckedBinaryOp(bin_op, ops) => stable_mir::mir::Rvalue::CheckedBinaryOp(
+                bin_op.stable(tables),
+                ops.0.stable(tables),
+                ops.1.stable(tables),
+            ),
+            NullaryOp(null_op, ty) => {
+                stable_mir::mir::Rvalue::NullaryOp(null_op.stable(tables), ty.stable(tables))
+            }
+            UnaryOp(un_op, op) => {
+                stable_mir::mir::Rvalue::UnaryOp(un_op.stable(tables), op.stable(tables))
+            }
+            Discriminant(place) => stable_mir::mir::Rvalue::Discriminant(place.stable(tables)),
+            Aggregate(agg_kind, operands) => {
+                let operands = operands.iter().map(|op| op.stable(tables)).collect();
+                stable_mir::mir::Rvalue::Aggregate(agg_kind.stable(tables), operands)
+            }
+            ShallowInitBox(op, ty) => {
+                stable_mir::mir::Rvalue::ShallowInitBox(op.stable(tables), ty.stable(tables))
+            }
+            CopyForDeref(place) => stable_mir::mir::Rvalue::CopyForDeref(place.stable(tables)),
+        }
+    }
+}
+
+impl<'tcx> Stable<'tcx> for mir::Mutability {
+    type T = stable_mir::mir::Mutability;
+    fn stable(&self, _: &mut Tables<'tcx>) -> Self::T {
+        use rustc_hir::Mutability::*;
+        match *self {
+            Not => stable_mir::mir::Mutability::Not,
+            Mut => stable_mir::mir::Mutability::Mut,
+        }
+    }
+}
+
+impl<'tcx> Stable<'tcx> for mir::BorrowKind {
+    type T = stable_mir::mir::BorrowKind;
+    fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T {
+        use rustc_middle::mir::BorrowKind::*;
+        match *self {
+            Shared => stable_mir::mir::BorrowKind::Shared,
+            Fake => stable_mir::mir::BorrowKind::Fake,
+            Mut { kind } => stable_mir::mir::BorrowKind::Mut { kind: kind.stable(tables) },
+        }
+    }
+}
+
+impl<'tcx> Stable<'tcx> for mir::MutBorrowKind {
+    type T = stable_mir::mir::MutBorrowKind;
+    fn stable(&self, _: &mut Tables<'tcx>) -> Self::T {
+        use rustc_middle::mir::MutBorrowKind::*;
+        match *self {
+            Default => stable_mir::mir::MutBorrowKind::Default,
+            TwoPhaseBorrow => stable_mir::mir::MutBorrowKind::TwoPhaseBorrow,
+            ClosureCapture => stable_mir::mir::MutBorrowKind::ClosureCapture,
+        }
+    }
+}
+
+impl<'tcx> Stable<'tcx> for mir::NullOp<'tcx> {
+    type T = stable_mir::mir::NullOp;
+    fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T {
+        use rustc_middle::mir::NullOp::*;
+        match self {
+            SizeOf => stable_mir::mir::NullOp::SizeOf,
+            AlignOf => stable_mir::mir::NullOp::AlignOf,
+            OffsetOf(indices) => stable_mir::mir::NullOp::OffsetOf(
+                indices.iter().map(|idx| idx.stable(tables)).collect(),
+            ),
+        }
+    }
+}
+
+impl<'tcx> Stable<'tcx> for mir::CastKind {
+    type T = stable_mir::mir::CastKind;
+    fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T {
+        use rustc_middle::mir::CastKind::*;
+        match self {
+            PointerExposeAddress => stable_mir::mir::CastKind::PointerExposeAddress,
+            PointerFromExposedAddress => stable_mir::mir::CastKind::PointerFromExposedAddress,
+            PointerCoercion(c) => stable_mir::mir::CastKind::PointerCoercion(c.stable(tables)),
+            DynStar => stable_mir::mir::CastKind::DynStar,
+            IntToInt => stable_mir::mir::CastKind::IntToInt,
+            FloatToInt => stable_mir::mir::CastKind::FloatToInt,
+            FloatToFloat => stable_mir::mir::CastKind::FloatToFloat,
+            IntToFloat => stable_mir::mir::CastKind::IntToFloat,
+            PtrToPtr => stable_mir::mir::CastKind::PtrToPtr,
+            FnPtrToPtr => stable_mir::mir::CastKind::FnPtrToPtr,
+            Transmute => stable_mir::mir::CastKind::Transmute,
+        }
+    }
+}
+
+impl<'tcx> Stable<'tcx> for mir::FakeReadCause {
+    type T = stable_mir::mir::FakeReadCause;
+    fn stable(&self, _: &mut Tables<'tcx>) -> Self::T {
+        use rustc_middle::mir::FakeReadCause::*;
+        match self {
+            ForMatchGuard => stable_mir::mir::FakeReadCause::ForMatchGuard,
+            ForMatchedPlace(local_def_id) => {
+                stable_mir::mir::FakeReadCause::ForMatchedPlace(opaque(local_def_id))
+            }
+            ForGuardBinding => stable_mir::mir::FakeReadCause::ForGuardBinding,
+            ForLet(local_def_id) => stable_mir::mir::FakeReadCause::ForLet(opaque(local_def_id)),
+            ForIndex => stable_mir::mir::FakeReadCause::ForIndex,
+        }
+    }
+}
+
+impl<'tcx> Stable<'tcx> for mir::Operand<'tcx> {
+    type T = stable_mir::mir::Operand;
+    fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T {
+        use rustc_middle::mir::Operand::*;
+        match self {
+            Copy(place) => stable_mir::mir::Operand::Copy(place.stable(tables)),
+            Move(place) => stable_mir::mir::Operand::Move(place.stable(tables)),
+            Constant(c) => stable_mir::mir::Operand::Constant(c.stable(tables)),
+        }
+    }
+}
+
+impl<'tcx> Stable<'tcx> for mir::ConstOperand<'tcx> {
+    type T = stable_mir::mir::Constant;
+
+    fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T {
+        stable_mir::mir::Constant {
+            span: self.span.stable(tables),
+            user_ty: self.user_ty.map(|u| u.as_usize()).or(None),
+            literal: self.const_.stable(tables),
+        }
+    }
+}
+
+impl<'tcx> Stable<'tcx> for mir::Place<'tcx> {
+    type T = stable_mir::mir::Place;
+    fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T {
+        stable_mir::mir::Place {
+            local: self.local.as_usize(),
+            projection: self.projection.iter().map(|e| e.stable(tables)).collect(),
+        }
+    }
+}
+
+impl<'tcx> Stable<'tcx> for mir::PlaceElem<'tcx> {
+    type T = stable_mir::mir::ProjectionElem;
+    fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T {
+        use rustc_middle::mir::ProjectionElem::*;
+        match self {
+            Deref => stable_mir::mir::ProjectionElem::Deref,
+            Field(idx, ty) => {
+                stable_mir::mir::ProjectionElem::Field(idx.stable(tables), ty.stable(tables))
+            }
+            Index(local) => stable_mir::mir::ProjectionElem::Index(local.stable(tables)),
+            ConstantIndex { offset, min_length, from_end } => {
+                stable_mir::mir::ProjectionElem::ConstantIndex {
+                    offset: *offset,
+                    min_length: *min_length,
+                    from_end: *from_end,
+                }
+            }
+            Subslice { from, to, from_end } => stable_mir::mir::ProjectionElem::Subslice {
+                from: *from,
+                to: *to,
+                from_end: *from_end,
+            },
+            // MIR includes an `Option<Symbol>` argument for `Downcast` that is the name of the
+            // variant, used for printing MIR. However this information should also be accessible
+            // via a lookup using the `VariantIdx`. The `Option<Symbol>` argument is therefore
+            // dropped when converting to Stable MIR. A brief justification for this decision can be
+            // found at https://github.com/rust-lang/rust/pull/117517#issuecomment-1811683486
+            Downcast(_, idx) => stable_mir::mir::ProjectionElem::Downcast(idx.stable(tables)),
+            OpaqueCast(ty) => stable_mir::mir::ProjectionElem::OpaqueCast(ty.stable(tables)),
+            Subtype(ty) => stable_mir::mir::ProjectionElem::Subtype(ty.stable(tables)),
+        }
+    }
+}
+
+impl<'tcx> Stable<'tcx> for mir::UserTypeProjection {
+    type T = stable_mir::mir::UserTypeProjection;
+
+    fn stable(&self, _tables: &mut Tables<'tcx>) -> Self::T {
+        UserTypeProjection { base: self.base.as_usize(), projection: opaque(&self.projs) }
+    }
+}
+
+impl<'tcx> Stable<'tcx> for mir::Local {
+    type T = stable_mir::mir::Local;
+    fn stable(&self, _: &mut Tables<'tcx>) -> Self::T {
+        self.as_usize()
+    }
+}
+
+impl<'tcx> Stable<'tcx> for mir::RetagKind {
+    type T = stable_mir::mir::RetagKind;
+    fn stable(&self, _: &mut Tables<'tcx>) -> Self::T {
+        use rustc_middle::mir::RetagKind;
+        match self {
+            RetagKind::FnEntry => stable_mir::mir::RetagKind::FnEntry,
+            RetagKind::TwoPhase => stable_mir::mir::RetagKind::TwoPhase,
+            RetagKind::Raw => stable_mir::mir::RetagKind::Raw,
+            RetagKind::Default => stable_mir::mir::RetagKind::Default,
+        }
+    }
+}
+
+impl<'tcx> Stable<'tcx> for mir::UnwindAction {
+    type T = stable_mir::mir::UnwindAction;
+    fn stable(&self, _: &mut Tables<'tcx>) -> Self::T {
+        use rustc_middle::mir::UnwindAction;
+        match self {
+            UnwindAction::Continue => stable_mir::mir::UnwindAction::Continue,
+            UnwindAction::Unreachable => stable_mir::mir::UnwindAction::Unreachable,
+            UnwindAction::Terminate(_) => stable_mir::mir::UnwindAction::Terminate,
+            UnwindAction::Cleanup(bb) => stable_mir::mir::UnwindAction::Cleanup(bb.as_usize()),
+        }
+    }
+}
+
+impl<'tcx> Stable<'tcx> for mir::NonDivergingIntrinsic<'tcx> {
+    type T = stable_mir::mir::NonDivergingIntrinsic;
+
+    fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T {
+        use rustc_middle::mir::NonDivergingIntrinsic;
+        use stable_mir::mir::CopyNonOverlapping;
+        match self {
+            NonDivergingIntrinsic::Assume(op) => {
+                stable_mir::mir::NonDivergingIntrinsic::Assume(op.stable(tables))
+            }
+            NonDivergingIntrinsic::CopyNonOverlapping(copy_non_overlapping) => {
+                stable_mir::mir::NonDivergingIntrinsic::CopyNonOverlapping(CopyNonOverlapping {
+                    src: copy_non_overlapping.src.stable(tables),
+                    dst: copy_non_overlapping.dst.stable(tables),
+                    count: copy_non_overlapping.count.stable(tables),
+                })
+            }
+        }
+    }
+}
+
+impl<'tcx> Stable<'tcx> for mir::AssertMessage<'tcx> {
+    type T = stable_mir::mir::AssertMessage;
+    fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T {
+        use rustc_middle::mir::AssertKind;
+        match self {
+            AssertKind::BoundsCheck { len, index } => stable_mir::mir::AssertMessage::BoundsCheck {
+                len: len.stable(tables),
+                index: index.stable(tables),
+            },
+            AssertKind::Overflow(bin_op, op1, op2) => stable_mir::mir::AssertMessage::Overflow(
+                bin_op.stable(tables),
+                op1.stable(tables),
+                op2.stable(tables),
+            ),
+            AssertKind::OverflowNeg(op) => {
+                stable_mir::mir::AssertMessage::OverflowNeg(op.stable(tables))
+            }
+            AssertKind::DivisionByZero(op) => {
+                stable_mir::mir::AssertMessage::DivisionByZero(op.stable(tables))
+            }
+            AssertKind::RemainderByZero(op) => {
+                stable_mir::mir::AssertMessage::RemainderByZero(op.stable(tables))
+            }
+            AssertKind::ResumedAfterReturn(coroutine) => {
+                stable_mir::mir::AssertMessage::ResumedAfterReturn(coroutine.stable(tables))
+            }
+            AssertKind::ResumedAfterPanic(coroutine) => {
+                stable_mir::mir::AssertMessage::ResumedAfterPanic(coroutine.stable(tables))
+            }
+            AssertKind::MisalignedPointerDereference { required, found } => {
+                stable_mir::mir::AssertMessage::MisalignedPointerDereference {
+                    required: required.stable(tables),
+                    found: found.stable(tables),
+                }
+            }
+        }
+    }
+}
+
+impl<'tcx> Stable<'tcx> for mir::BinOp {
+    type T = stable_mir::mir::BinOp;
+    fn stable(&self, _: &mut Tables<'tcx>) -> Self::T {
+        use rustc_middle::mir::BinOp;
+        match self {
+            BinOp::Add => stable_mir::mir::BinOp::Add,
+            BinOp::AddUnchecked => stable_mir::mir::BinOp::AddUnchecked,
+            BinOp::Sub => stable_mir::mir::BinOp::Sub,
+            BinOp::SubUnchecked => stable_mir::mir::BinOp::SubUnchecked,
+            BinOp::Mul => stable_mir::mir::BinOp::Mul,
+            BinOp::MulUnchecked => stable_mir::mir::BinOp::MulUnchecked,
+            BinOp::Div => stable_mir::mir::BinOp::Div,
+            BinOp::Rem => stable_mir::mir::BinOp::Rem,
+            BinOp::BitXor => stable_mir::mir::BinOp::BitXor,
+            BinOp::BitAnd => stable_mir::mir::BinOp::BitAnd,
+            BinOp::BitOr => stable_mir::mir::BinOp::BitOr,
+            BinOp::Shl => stable_mir::mir::BinOp::Shl,
+            BinOp::ShlUnchecked => stable_mir::mir::BinOp::ShlUnchecked,
+            BinOp::Shr => stable_mir::mir::BinOp::Shr,
+            BinOp::ShrUnchecked => stable_mir::mir::BinOp::ShrUnchecked,
+            BinOp::Eq => stable_mir::mir::BinOp::Eq,
+            BinOp::Lt => stable_mir::mir::BinOp::Lt,
+            BinOp::Le => stable_mir::mir::BinOp::Le,
+            BinOp::Ne => stable_mir::mir::BinOp::Ne,
+            BinOp::Ge => stable_mir::mir::BinOp::Ge,
+            BinOp::Gt => stable_mir::mir::BinOp::Gt,
+            BinOp::Offset => stable_mir::mir::BinOp::Offset,
+        }
+    }
+}
+
+impl<'tcx> Stable<'tcx> for mir::UnOp {
+    type T = stable_mir::mir::UnOp;
+    fn stable(&self, _: &mut Tables<'tcx>) -> Self::T {
+        use rustc_middle::mir::UnOp;
+        match self {
+            UnOp::Not => stable_mir::mir::UnOp::Not,
+            UnOp::Neg => stable_mir::mir::UnOp::Neg,
+        }
+    }
+}
+
+impl<'tcx> Stable<'tcx> for mir::AggregateKind<'tcx> {
+    type T = stable_mir::mir::AggregateKind;
+    fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T {
+        match self {
+            mir::AggregateKind::Array(ty) => {
+                stable_mir::mir::AggregateKind::Array(ty.stable(tables))
+            }
+            mir::AggregateKind::Tuple => stable_mir::mir::AggregateKind::Tuple,
+            mir::AggregateKind::Adt(def_id, var_idx, generic_arg, user_ty_index, field_idx) => {
+                stable_mir::mir::AggregateKind::Adt(
+                    tables.adt_def(*def_id),
+                    var_idx.index(),
+                    generic_arg.stable(tables),
+                    user_ty_index.map(|idx| idx.index()),
+                    field_idx.map(|idx| idx.index()),
+                )
+            }
+            mir::AggregateKind::Closure(def_id, generic_arg) => {
+                stable_mir::mir::AggregateKind::Closure(
+                    tables.closure_def(*def_id),
+                    generic_arg.stable(tables),
+                )
+            }
+            mir::AggregateKind::Coroutine(def_id, generic_arg, movability) => {
+                stable_mir::mir::AggregateKind::Coroutine(
+                    tables.coroutine_def(*def_id),
+                    generic_arg.stable(tables),
+                    movability.stable(tables),
+                )
+            }
+        }
+    }
+}
+
+impl<'tcx> Stable<'tcx> for mir::InlineAsmOperand<'tcx> {
+    type T = stable_mir::mir::InlineAsmOperand;
+    fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T {
+        use rustc_middle::mir::InlineAsmOperand;
+
+        let (in_value, out_place) = match self {
+            InlineAsmOperand::In { value, .. } => (Some(value.stable(tables)), None),
+            InlineAsmOperand::Out { place, .. } => (None, place.map(|place| place.stable(tables))),
+            InlineAsmOperand::InOut { in_value, out_place, .. } => {
+                (Some(in_value.stable(tables)), out_place.map(|place| place.stable(tables)))
+            }
+            InlineAsmOperand::Const { .. }
+            | InlineAsmOperand::SymFn { .. }
+            | InlineAsmOperand::SymStatic { .. } => (None, None),
+        };
+
+        stable_mir::mir::InlineAsmOperand { in_value, out_place, raw_rpr: format!("{self:?}") }
+    }
+}
+
+impl<'tcx> Stable<'tcx> for mir::Terminator<'tcx> {
+    type T = stable_mir::mir::Terminator;
+    fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T {
+        use stable_mir::mir::Terminator;
+        Terminator { kind: self.kind.stable(tables), span: self.source_info.span.stable(tables) }
+    }
+}
+
+impl<'tcx> Stable<'tcx> for mir::TerminatorKind<'tcx> {
+    type T = stable_mir::mir::TerminatorKind;
+    fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T {
+        use stable_mir::mir::TerminatorKind;
+        match self {
+            mir::TerminatorKind::Goto { target } => {
+                TerminatorKind::Goto { target: target.as_usize() }
+            }
+            mir::TerminatorKind::SwitchInt { discr, targets } => TerminatorKind::SwitchInt {
+                discr: discr.stable(tables),
+                targets: targets
+                    .iter()
+                    .map(|(value, target)| stable_mir::mir::SwitchTarget {
+                        value,
+                        target: target.as_usize(),
+                    })
+                    .collect(),
+                otherwise: targets.otherwise().as_usize(),
+            },
+            mir::TerminatorKind::UnwindResume => TerminatorKind::Resume,
+            mir::TerminatorKind::UnwindTerminate(_) => TerminatorKind::Abort,
+            mir::TerminatorKind::Return => TerminatorKind::Return,
+            mir::TerminatorKind::Unreachable => TerminatorKind::Unreachable,
+            mir::TerminatorKind::Drop { place, target, unwind, replace: _ } => {
+                TerminatorKind::Drop {
+                    place: place.stable(tables),
+                    target: target.as_usize(),
+                    unwind: unwind.stable(tables),
+                }
+            }
+            mir::TerminatorKind::Call {
+                func,
+                args,
+                destination,
+                target,
+                unwind,
+                call_source: _,
+                fn_span: _,
+            } => TerminatorKind::Call {
+                func: func.stable(tables),
+                args: args.iter().map(|arg| arg.stable(tables)).collect(),
+                destination: destination.stable(tables),
+                target: target.map(|t| t.as_usize()),
+                unwind: unwind.stable(tables),
+            },
+            mir::TerminatorKind::Assert { cond, expected, msg, target, unwind } => {
+                TerminatorKind::Assert {
+                    cond: cond.stable(tables),
+                    expected: *expected,
+                    msg: msg.stable(tables),
+                    target: target.as_usize(),
+                    unwind: unwind.stable(tables),
+                }
+            }
+            mir::TerminatorKind::InlineAsm {
+                template,
+                operands,
+                options,
+                line_spans,
+                destination,
+                unwind,
+            } => TerminatorKind::InlineAsm {
+                template: format!("{template:?}"),
+                operands: operands.iter().map(|operand| operand.stable(tables)).collect(),
+                options: format!("{options:?}"),
+                line_spans: format!("{line_spans:?}"),
+                destination: destination.map(|d| d.as_usize()),
+                unwind: unwind.stable(tables),
+            },
+            mir::TerminatorKind::Yield { .. }
+            | mir::TerminatorKind::CoroutineDrop
+            | mir::TerminatorKind::FalseEdge { .. }
+            | mir::TerminatorKind::FalseUnwind { .. } => unreachable!(),
+        }
+    }
+}
+
+impl<'tcx> Stable<'tcx> for mir::interpret::ConstAllocation<'tcx> {
+    type T = Allocation;
+
+    fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T {
+        self.inner().stable(tables)
+    }
+}
+
+impl<'tcx> Stable<'tcx> for mir::interpret::Allocation {
+    type T = stable_mir::ty::Allocation;
+
+    fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T {
+        alloc::allocation_filter(
+            self,
+            alloc_range(rustc_target::abi::Size::ZERO, self.size()),
+            tables,
+        )
+    }
+}
+
+impl<'tcx> Stable<'tcx> for mir::interpret::AllocId {
+    type T = stable_mir::mir::alloc::AllocId;
+    fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T {
+        tables.create_alloc_id(*self)
+    }
+}
+
+impl<'tcx> Stable<'tcx> for mir::interpret::GlobalAlloc<'tcx> {
+    type T = GlobalAlloc;
+
+    fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T {
+        match self {
+            mir::interpret::GlobalAlloc::Function(instance) => {
+                GlobalAlloc::Function(instance.stable(tables))
+            }
+            mir::interpret::GlobalAlloc::VTable(ty, trait_ref) => {
+                GlobalAlloc::VTable(ty.stable(tables), trait_ref.stable(tables))
+            }
+            mir::interpret::GlobalAlloc::Static(def) => {
+                GlobalAlloc::Static(tables.static_def(*def))
+            }
+            mir::interpret::GlobalAlloc::Memory(alloc) => GlobalAlloc::Memory(alloc.stable(tables)),
+        }
+    }
+}
+
+impl<'tcx> Stable<'tcx> for rustc_middle::mir::Const<'tcx> {
+    type T = stable_mir::ty::Const;
+
+    fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T {
+        match *self {
+            mir::Const::Ty(c) => c.stable(tables),
+            mir::Const::Unevaluated(unev_const, ty) => {
+                let kind =
+                    stable_mir::ty::ConstantKind::Unevaluated(stable_mir::ty::UnevaluatedConst {
+                        def: tables.const_def(unev_const.def),
+                        args: unev_const.args.stable(tables),
+                        promoted: unev_const.promoted.map(|u| u.as_u32()),
+                    });
+                let ty = ty.stable(tables);
+                let id = tables.intern_const(*self);
+                Const::new(kind, ty, id)
+            }
+            mir::Const::Val(val, ty) if matches!(val, mir::ConstValue::ZeroSized) => {
+                let ty = ty.stable(tables);
+                let id = tables.intern_const(*self);
+                Const::new(ConstantKind::ZeroSized, ty, id)
+            }
+            mir::Const::Val(val, ty) => {
+                let kind = ConstantKind::Allocated(alloc::new_allocation(ty, val, tables));
+                let ty = ty.stable(tables);
+                let id = tables.intern_const(*self);
+                Const::new(kind, ty, id)
+            }
+        }
+    }
+}
+
+impl<'tcx> Stable<'tcx> for mir::interpret::ErrorHandled {
+    type T = Error;
+
+    fn stable(&self, _tables: &mut Tables<'tcx>) -> Self::T {
+        Error::new(format!("{self:?}"))
+    }
+}
+
+impl<'tcx> Stable<'tcx> for MonoItem<'tcx> {
+    type T = stable_mir::mir::mono::MonoItem;
+
+    fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T {
+        use stable_mir::mir::mono::MonoItem as StableMonoItem;
+        match self {
+            MonoItem::Fn(instance) => StableMonoItem::Fn(instance.stable(tables)),
+            MonoItem::Static(def_id) => StableMonoItem::Static(tables.static_def(*def_id)),
+            MonoItem::GlobalAsm(item_id) => StableMonoItem::GlobalAsm(opaque(item_id)),
+        }
+    }
+}
diff --git a/compiler/rustc_smir/src/rustc_smir/convert/mod.rs b/compiler/rustc_smir/src/rustc_smir/convert/mod.rs
new file mode 100644
index 00000000000..edb32df305c
--- /dev/null
+++ b/compiler/rustc_smir/src/rustc_smir/convert/mod.rs
@@ -0,0 +1,76 @@
+//! Conversion of internal Rust compiler items to stable ones.
+
+use rustc_target::abi::FieldIdx;
+use stable_mir::mir::VariantIdx;
+
+use crate::rustc_smir::{Stable, Tables};
+
+mod mir;
+mod ty;
+
+impl<'tcx> Stable<'tcx> for rustc_hir::Unsafety {
+    type T = stable_mir::mir::Safety;
+    fn stable(&self, _: &mut Tables<'tcx>) -> Self::T {
+        match self {
+            rustc_hir::Unsafety::Unsafe => stable_mir::mir::Safety::Unsafe,
+            rustc_hir::Unsafety::Normal => stable_mir::mir::Safety::Normal,
+        }
+    }
+}
+
+impl<'tcx> Stable<'tcx> for FieldIdx {
+    type T = usize;
+    fn stable(&self, _: &mut Tables<'tcx>) -> Self::T {
+        self.as_usize()
+    }
+}
+
+impl<'tcx> Stable<'tcx> for (rustc_target::abi::VariantIdx, FieldIdx) {
+    type T = (usize, usize);
+    fn stable(&self, _: &mut Tables<'tcx>) -> Self::T {
+        (self.0.as_usize(), self.1.as_usize())
+    }
+}
+
+impl<'tcx> Stable<'tcx> for rustc_target::abi::VariantIdx {
+    type T = VariantIdx;
+    fn stable(&self, _: &mut Tables<'tcx>) -> Self::T {
+        self.as_usize()
+    }
+}
+
+impl<'tcx> Stable<'tcx> for rustc_hir::CoroutineSource {
+    type T = stable_mir::mir::CoroutineSource;
+    fn stable(&self, _: &mut Tables<'tcx>) -> Self::T {
+        use rustc_hir::CoroutineSource;
+        match self {
+            CoroutineSource::Block => stable_mir::mir::CoroutineSource::Block,
+            CoroutineSource::Closure => stable_mir::mir::CoroutineSource::Closure,
+            CoroutineSource::Fn => stable_mir::mir::CoroutineSource::Fn,
+        }
+    }
+}
+
+impl<'tcx> Stable<'tcx> for rustc_hir::CoroutineKind {
+    type T = stable_mir::mir::CoroutineKind;
+    fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T {
+        use rustc_hir::CoroutineKind;
+        match self {
+            CoroutineKind::Async(source) => {
+                stable_mir::mir::CoroutineKind::Async(source.stable(tables))
+            }
+            CoroutineKind::Gen(source) => {
+                stable_mir::mir::CoroutineKind::Gen(source.stable(tables))
+            }
+            CoroutineKind::Coroutine => stable_mir::mir::CoroutineKind::Coroutine,
+        }
+    }
+}
+
+impl<'tcx> Stable<'tcx> for rustc_span::Span {
+    type T = stable_mir::ty::Span;
+
+    fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T {
+        tables.create_span(*self)
+    }
+}
diff --git a/compiler/rustc_smir/src/rustc_smir/convert/ty.rs b/compiler/rustc_smir/src/rustc_smir/convert/ty.rs
new file mode 100644
index 00000000000..32ee928ddd4
--- /dev/null
+++ b/compiler/rustc_smir/src/rustc_smir/convert/ty.rs
@@ -0,0 +1,815 @@
+//! Conversion of internal Rust compiler `ty` items to stable ones.
+
+use rustc_middle::ty::Ty;
+use rustc_middle::{mir, ty};
+use stable_mir::ty::{
+    AdtKind, Const, ConstantKind, FloatTy, GenericArgs, GenericParamDef, IntTy, Region, RigidTy,
+    TyKind, UintTy,
+};
+
+use crate::rustc_smir::{alloc, Stable, Tables};
+
+impl<'tcx> Stable<'tcx> for ty::AliasKind {
+    type T = stable_mir::ty::AliasKind;
+    fn stable(&self, _: &mut Tables<'tcx>) -> Self::T {
+        use rustc_middle::ty::AliasKind::*;
+        match self {
+            Projection => stable_mir::ty::AliasKind::Projection,
+            Inherent => stable_mir::ty::AliasKind::Inherent,
+            Opaque => stable_mir::ty::AliasKind::Opaque,
+            Weak => stable_mir::ty::AliasKind::Weak,
+        }
+    }
+}
+
+impl<'tcx> Stable<'tcx> for ty::AliasTy<'tcx> {
+    type T = stable_mir::ty::AliasTy;
+    fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T {
+        let ty::AliasTy { args, def_id, .. } = self;
+        stable_mir::ty::AliasTy { def_id: tables.alias_def(*def_id), args: args.stable(tables) }
+    }
+}
+
+impl<'tcx> Stable<'tcx> for ty::DynKind {
+    type T = stable_mir::ty::DynKind;
+
+    fn stable(&self, _: &mut Tables<'tcx>) -> Self::T {
+        use rustc_middle::ty::DynKind;
+        match self {
+            DynKind::Dyn => stable_mir::ty::DynKind::Dyn,
+            DynKind::DynStar => stable_mir::ty::DynKind::DynStar,
+        }
+    }
+}
+
+impl<'tcx> Stable<'tcx> for ty::ExistentialPredicate<'tcx> {
+    type T = stable_mir::ty::ExistentialPredicate;
+
+    fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T {
+        use stable_mir::ty::ExistentialPredicate::*;
+        match self {
+            ty::ExistentialPredicate::Trait(existential_trait_ref) => {
+                Trait(existential_trait_ref.stable(tables))
+            }
+            ty::ExistentialPredicate::Projection(existential_projection) => {
+                Projection(existential_projection.stable(tables))
+            }
+            ty::ExistentialPredicate::AutoTrait(def_id) => AutoTrait(tables.trait_def(*def_id)),
+        }
+    }
+}
+
+impl<'tcx> Stable<'tcx> for ty::ExistentialTraitRef<'tcx> {
+    type T = stable_mir::ty::ExistentialTraitRef;
+
+    fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T {
+        let ty::ExistentialTraitRef { def_id, args } = self;
+        stable_mir::ty::ExistentialTraitRef {
+            def_id: tables.trait_def(*def_id),
+            generic_args: args.stable(tables),
+        }
+    }
+}
+
+impl<'tcx> Stable<'tcx> for ty::TermKind<'tcx> {
+    type T = stable_mir::ty::TermKind;
+
+    fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T {
+        use stable_mir::ty::TermKind;
+        match self {
+            ty::TermKind::Ty(ty) => TermKind::Type(ty.stable(tables)),
+            ty::TermKind::Const(cnst) => {
+                let cnst = cnst.stable(tables);
+                TermKind::Const(cnst)
+            }
+        }
+    }
+}
+
+impl<'tcx> Stable<'tcx> for ty::ExistentialProjection<'tcx> {
+    type T = stable_mir::ty::ExistentialProjection;
+
+    fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T {
+        let ty::ExistentialProjection { def_id, args, term } = self;
+        stable_mir::ty::ExistentialProjection {
+            def_id: tables.trait_def(*def_id),
+            generic_args: args.stable(tables),
+            term: term.unpack().stable(tables),
+        }
+    }
+}
+
+impl<'tcx> Stable<'tcx> for ty::adjustment::PointerCoercion {
+    type T = stable_mir::mir::PointerCoercion;
+    fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T {
+        use rustc_middle::ty::adjustment::PointerCoercion;
+        match self {
+            PointerCoercion::ReifyFnPointer => stable_mir::mir::PointerCoercion::ReifyFnPointer,
+            PointerCoercion::UnsafeFnPointer => stable_mir::mir::PointerCoercion::UnsafeFnPointer,
+            PointerCoercion::ClosureFnPointer(unsafety) => {
+                stable_mir::mir::PointerCoercion::ClosureFnPointer(unsafety.stable(tables))
+            }
+            PointerCoercion::MutToConstPointer => {
+                stable_mir::mir::PointerCoercion::MutToConstPointer
+            }
+            PointerCoercion::ArrayToPointer => stable_mir::mir::PointerCoercion::ArrayToPointer,
+            PointerCoercion::Unsize => stable_mir::mir::PointerCoercion::Unsize,
+        }
+    }
+}
+
+impl<'tcx> Stable<'tcx> for ty::UserTypeAnnotationIndex {
+    type T = usize;
+    fn stable(&self, _: &mut Tables<'tcx>) -> Self::T {
+        self.as_usize()
+    }
+}
+
+impl<'tcx> Stable<'tcx> for ty::AdtKind {
+    type T = AdtKind;
+
+    fn stable(&self, _tables: &mut Tables<'tcx>) -> Self::T {
+        match self {
+            ty::AdtKind::Struct => AdtKind::Struct,
+            ty::AdtKind::Union => AdtKind::Union,
+            ty::AdtKind::Enum => AdtKind::Enum,
+        }
+    }
+}
+
+impl<'tcx> Stable<'tcx> for ty::GenericArgs<'tcx> {
+    type T = stable_mir::ty::GenericArgs;
+    fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T {
+        GenericArgs(self.iter().map(|arg| arg.unpack().stable(tables)).collect())
+    }
+}
+
+impl<'tcx> Stable<'tcx> for ty::GenericArgKind<'tcx> {
+    type T = stable_mir::ty::GenericArgKind;
+
+    fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T {
+        use stable_mir::ty::GenericArgKind;
+        match self {
+            ty::GenericArgKind::Lifetime(region) => GenericArgKind::Lifetime(region.stable(tables)),
+            ty::GenericArgKind::Type(ty) => GenericArgKind::Type(ty.stable(tables)),
+            ty::GenericArgKind::Const(cnst) => GenericArgKind::Const(cnst.stable(tables)),
+        }
+    }
+}
+
+impl<'tcx, S, V> Stable<'tcx> for ty::Binder<'tcx, S>
+where
+    S: Stable<'tcx, T = V>,
+{
+    type T = stable_mir::ty::Binder<V>;
+
+    fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T {
+        use stable_mir::ty::Binder;
+
+        Binder {
+            value: self.as_ref().skip_binder().stable(tables),
+            bound_vars: self
+                .bound_vars()
+                .iter()
+                .map(|bound_var| bound_var.stable(tables))
+                .collect(),
+        }
+    }
+}
+
+impl<'tcx, S, V> Stable<'tcx> for ty::EarlyBinder<S>
+where
+    S: Stable<'tcx, T = V>,
+{
+    type T = stable_mir::ty::EarlyBinder<V>;
+
+    fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T {
+        use stable_mir::ty::EarlyBinder;
+
+        EarlyBinder { value: self.as_ref().skip_binder().stable(tables) }
+    }
+}
+
+impl<'tcx> Stable<'tcx> for ty::FnSig<'tcx> {
+    type T = stable_mir::ty::FnSig;
+    fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T {
+        use rustc_target::spec::abi;
+        use stable_mir::ty::{Abi, FnSig};
+
+        FnSig {
+            inputs_and_output: self.inputs_and_output.iter().map(|ty| ty.stable(tables)).collect(),
+            c_variadic: self.c_variadic,
+            unsafety: self.unsafety.stable(tables),
+            abi: match self.abi {
+                abi::Abi::Rust => Abi::Rust,
+                abi::Abi::C { unwind } => Abi::C { unwind },
+                abi::Abi::Cdecl { unwind } => Abi::Cdecl { unwind },
+                abi::Abi::Stdcall { unwind } => Abi::Stdcall { unwind },
+                abi::Abi::Fastcall { unwind } => Abi::Fastcall { unwind },
+                abi::Abi::Vectorcall { unwind } => Abi::Vectorcall { unwind },
+                abi::Abi::Thiscall { unwind } => Abi::Thiscall { unwind },
+                abi::Abi::Aapcs { unwind } => Abi::Aapcs { unwind },
+                abi::Abi::Win64 { unwind } => Abi::Win64 { unwind },
+                abi::Abi::SysV64 { unwind } => Abi::SysV64 { unwind },
+                abi::Abi::PtxKernel => Abi::PtxKernel,
+                abi::Abi::Msp430Interrupt => Abi::Msp430Interrupt,
+                abi::Abi::X86Interrupt => Abi::X86Interrupt,
+                abi::Abi::AmdGpuKernel => Abi::AmdGpuKernel,
+                abi::Abi::EfiApi => Abi::EfiApi,
+                abi::Abi::AvrInterrupt => Abi::AvrInterrupt,
+                abi::Abi::AvrNonBlockingInterrupt => Abi::AvrNonBlockingInterrupt,
+                abi::Abi::CCmseNonSecureCall => Abi::CCmseNonSecureCall,
+                abi::Abi::Wasm => Abi::Wasm,
+                abi::Abi::System { unwind } => Abi::System { unwind },
+                abi::Abi::RustIntrinsic => Abi::RustIntrinsic,
+                abi::Abi::RustCall => Abi::RustCall,
+                abi::Abi::PlatformIntrinsic => Abi::PlatformIntrinsic,
+                abi::Abi::Unadjusted => Abi::Unadjusted,
+                abi::Abi::RustCold => Abi::RustCold,
+                abi::Abi::RiscvInterruptM => Abi::RiscvInterruptM,
+                abi::Abi::RiscvInterruptS => Abi::RiscvInterruptS,
+            },
+        }
+    }
+}
+
+impl<'tcx> Stable<'tcx> for ty::BoundTyKind {
+    type T = stable_mir::ty::BoundTyKind;
+
+    fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T {
+        use stable_mir::ty::BoundTyKind;
+
+        match self {
+            ty::BoundTyKind::Anon => BoundTyKind::Anon,
+            ty::BoundTyKind::Param(def_id, symbol) => {
+                BoundTyKind::Param(tables.param_def(*def_id), symbol.to_string())
+            }
+        }
+    }
+}
+
+impl<'tcx> Stable<'tcx> for ty::BoundRegionKind {
+    type T = stable_mir::ty::BoundRegionKind;
+
+    fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T {
+        use stable_mir::ty::BoundRegionKind;
+
+        match self {
+            ty::BoundRegionKind::BrAnon => BoundRegionKind::BrAnon,
+            ty::BoundRegionKind::BrNamed(def_id, symbol) => {
+                BoundRegionKind::BrNamed(tables.br_named_def(*def_id), symbol.to_string())
+            }
+            ty::BoundRegionKind::BrEnv => BoundRegionKind::BrEnv,
+        }
+    }
+}
+
+impl<'tcx> Stable<'tcx> for ty::BoundVariableKind {
+    type T = stable_mir::ty::BoundVariableKind;
+
+    fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T {
+        use stable_mir::ty::BoundVariableKind;
+
+        match self {
+            ty::BoundVariableKind::Ty(bound_ty_kind) => {
+                BoundVariableKind::Ty(bound_ty_kind.stable(tables))
+            }
+            ty::BoundVariableKind::Region(bound_region_kind) => {
+                BoundVariableKind::Region(bound_region_kind.stable(tables))
+            }
+            ty::BoundVariableKind::Const => BoundVariableKind::Const,
+        }
+    }
+}
+
+impl<'tcx> Stable<'tcx> for ty::IntTy {
+    type T = IntTy;
+
+    fn stable(&self, _: &mut Tables<'tcx>) -> Self::T {
+        match self {
+            ty::IntTy::Isize => IntTy::Isize,
+            ty::IntTy::I8 => IntTy::I8,
+            ty::IntTy::I16 => IntTy::I16,
+            ty::IntTy::I32 => IntTy::I32,
+            ty::IntTy::I64 => IntTy::I64,
+            ty::IntTy::I128 => IntTy::I128,
+        }
+    }
+}
+
+impl<'tcx> Stable<'tcx> for ty::UintTy {
+    type T = UintTy;
+
+    fn stable(&self, _: &mut Tables<'tcx>) -> Self::T {
+        match self {
+            ty::UintTy::Usize => UintTy::Usize,
+            ty::UintTy::U8 => UintTy::U8,
+            ty::UintTy::U16 => UintTy::U16,
+            ty::UintTy::U32 => UintTy::U32,
+            ty::UintTy::U64 => UintTy::U64,
+            ty::UintTy::U128 => UintTy::U128,
+        }
+    }
+}
+
+impl<'tcx> Stable<'tcx> for ty::FloatTy {
+    type T = FloatTy;
+
+    fn stable(&self, _: &mut Tables<'tcx>) -> Self::T {
+        match self {
+            ty::FloatTy::F32 => FloatTy::F32,
+            ty::FloatTy::F64 => FloatTy::F64,
+        }
+    }
+}
+
+impl<'tcx> Stable<'tcx> for Ty<'tcx> {
+    type T = stable_mir::ty::Ty;
+    fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T {
+        tables.intern_ty(*self)
+    }
+}
+
+impl<'tcx> Stable<'tcx> for ty::TyKind<'tcx> {
+    type T = stable_mir::ty::TyKind;
+    fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T {
+        match self {
+            ty::Bool => TyKind::RigidTy(RigidTy::Bool),
+            ty::Char => TyKind::RigidTy(RigidTy::Char),
+            ty::Int(int_ty) => TyKind::RigidTy(RigidTy::Int(int_ty.stable(tables))),
+            ty::Uint(uint_ty) => TyKind::RigidTy(RigidTy::Uint(uint_ty.stable(tables))),
+            ty::Float(float_ty) => TyKind::RigidTy(RigidTy::Float(float_ty.stable(tables))),
+            ty::Adt(adt_def, generic_args) => TyKind::RigidTy(RigidTy::Adt(
+                tables.adt_def(adt_def.did()),
+                generic_args.stable(tables),
+            )),
+            ty::Foreign(def_id) => TyKind::RigidTy(RigidTy::Foreign(tables.foreign_def(*def_id))),
+            ty::Str => TyKind::RigidTy(RigidTy::Str),
+            ty::Array(ty, constant) => {
+                TyKind::RigidTy(RigidTy::Array(ty.stable(tables), constant.stable(tables)))
+            }
+            ty::Slice(ty) => TyKind::RigidTy(RigidTy::Slice(ty.stable(tables))),
+            ty::RawPtr(ty::TypeAndMut { ty, mutbl }) => {
+                TyKind::RigidTy(RigidTy::RawPtr(ty.stable(tables), mutbl.stable(tables)))
+            }
+            ty::Ref(region, ty, mutbl) => TyKind::RigidTy(RigidTy::Ref(
+                region.stable(tables),
+                ty.stable(tables),
+                mutbl.stable(tables),
+            )),
+            ty::FnDef(def_id, generic_args) => {
+                TyKind::RigidTy(RigidTy::FnDef(tables.fn_def(*def_id), generic_args.stable(tables)))
+            }
+            ty::FnPtr(poly_fn_sig) => TyKind::RigidTy(RigidTy::FnPtr(poly_fn_sig.stable(tables))),
+            ty::Dynamic(existential_predicates, region, dyn_kind) => {
+                TyKind::RigidTy(RigidTy::Dynamic(
+                    existential_predicates
+                        .iter()
+                        .map(|existential_predicate| existential_predicate.stable(tables))
+                        .collect(),
+                    region.stable(tables),
+                    dyn_kind.stable(tables),
+                ))
+            }
+            ty::Closure(def_id, generic_args) => TyKind::RigidTy(RigidTy::Closure(
+                tables.closure_def(*def_id),
+                generic_args.stable(tables),
+            )),
+            ty::Coroutine(def_id, generic_args, movability) => TyKind::RigidTy(RigidTy::Coroutine(
+                tables.coroutine_def(*def_id),
+                generic_args.stable(tables),
+                movability.stable(tables),
+            )),
+            ty::Never => TyKind::RigidTy(RigidTy::Never),
+            ty::Tuple(fields) => {
+                TyKind::RigidTy(RigidTy::Tuple(fields.iter().map(|ty| ty.stable(tables)).collect()))
+            }
+            ty::Alias(alias_kind, alias_ty) => {
+                TyKind::Alias(alias_kind.stable(tables), alias_ty.stable(tables))
+            }
+            ty::Param(param_ty) => TyKind::Param(param_ty.stable(tables)),
+            ty::Bound(debruijn_idx, bound_ty) => {
+                TyKind::Bound(debruijn_idx.as_usize(), bound_ty.stable(tables))
+            }
+            ty::CoroutineWitness(def_id, args) => TyKind::RigidTy(RigidTy::CoroutineWitness(
+                tables.coroutine_witness_def(*def_id),
+                args.stable(tables),
+            )),
+            ty::Placeholder(..) | ty::Infer(_) | ty::Error(_) => {
+                unreachable!();
+            }
+        }
+    }
+}
+
+impl<'tcx> Stable<'tcx> for ty::Const<'tcx> {
+    type T = stable_mir::ty::Const;
+
+    fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T {
+        let kind = match self.kind() {
+            ty::Value(val) => {
+                let const_val = tables.tcx.valtree_to_const_val((self.ty(), val));
+                if matches!(const_val, mir::ConstValue::ZeroSized) {
+                    ConstantKind::ZeroSized
+                } else {
+                    stable_mir::ty::ConstantKind::Allocated(alloc::new_allocation(
+                        self.ty(),
+                        const_val,
+                        tables,
+                    ))
+                }
+            }
+            ty::ParamCt(param) => stable_mir::ty::ConstantKind::Param(param.stable(tables)),
+            ty::ErrorCt(_) => unreachable!(),
+            ty::InferCt(_) => unreachable!(),
+            ty::BoundCt(_, _) => unimplemented!(),
+            ty::PlaceholderCt(_) => unimplemented!(),
+            ty::Unevaluated(uv) => {
+                stable_mir::ty::ConstantKind::Unevaluated(stable_mir::ty::UnevaluatedConst {
+                    def: tables.const_def(uv.def),
+                    args: uv.args.stable(tables),
+                    promoted: None,
+                })
+            }
+            ty::ExprCt(_) => unimplemented!(),
+        };
+        let ty = self.ty().stable(tables);
+        let id = tables.intern_const(mir::Const::Ty(*self));
+        Const::new(kind, ty, id)
+    }
+}
+
+impl<'tcx> Stable<'tcx> for ty::ParamConst {
+    type T = stable_mir::ty::ParamConst;
+    fn stable(&self, _: &mut Tables<'tcx>) -> Self::T {
+        use stable_mir::ty::ParamConst;
+        ParamConst { index: self.index, name: self.name.to_string() }
+    }
+}
+
+impl<'tcx> Stable<'tcx> for ty::ParamTy {
+    type T = stable_mir::ty::ParamTy;
+    fn stable(&self, _: &mut Tables<'tcx>) -> Self::T {
+        use stable_mir::ty::ParamTy;
+        ParamTy { index: self.index, name: self.name.to_string() }
+    }
+}
+
+impl<'tcx> Stable<'tcx> for ty::BoundTy {
+    type T = stable_mir::ty::BoundTy;
+    fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T {
+        use stable_mir::ty::BoundTy;
+        BoundTy { var: self.var.as_usize(), kind: self.kind.stable(tables) }
+    }
+}
+
+impl<'tcx> Stable<'tcx> for ty::trait_def::TraitSpecializationKind {
+    type T = stable_mir::ty::TraitSpecializationKind;
+    fn stable(&self, _: &mut Tables<'tcx>) -> Self::T {
+        use stable_mir::ty::TraitSpecializationKind;
+
+        match self {
+            ty::trait_def::TraitSpecializationKind::None => TraitSpecializationKind::None,
+            ty::trait_def::TraitSpecializationKind::Marker => TraitSpecializationKind::Marker,
+            ty::trait_def::TraitSpecializationKind::AlwaysApplicable => {
+                TraitSpecializationKind::AlwaysApplicable
+            }
+        }
+    }
+}
+
+impl<'tcx> Stable<'tcx> for ty::TraitDef {
+    type T = stable_mir::ty::TraitDecl;
+    fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T {
+        use stable_mir::opaque;
+        use stable_mir::ty::TraitDecl;
+
+        TraitDecl {
+            def_id: tables.trait_def(self.def_id),
+            unsafety: self.unsafety.stable(tables),
+            paren_sugar: self.paren_sugar,
+            has_auto_impl: self.has_auto_impl,
+            is_marker: self.is_marker,
+            is_coinductive: self.is_coinductive,
+            skip_array_during_method_dispatch: self.skip_array_during_method_dispatch,
+            specialization_kind: self.specialization_kind.stable(tables),
+            must_implement_one_of: self
+                .must_implement_one_of
+                .as_ref()
+                .map(|idents| idents.iter().map(|ident| opaque(ident)).collect()),
+            implement_via_object: self.implement_via_object,
+            deny_explicit_impl: self.deny_explicit_impl,
+        }
+    }
+}
+
+impl<'tcx> Stable<'tcx> for ty::TraitRef<'tcx> {
+    type T = stable_mir::ty::TraitRef;
+    fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T {
+        use stable_mir::ty::TraitRef;
+
+        TraitRef::try_new(tables.trait_def(self.def_id), self.args.stable(tables)).unwrap()
+    }
+}
+
+impl<'tcx> Stable<'tcx> for ty::Generics {
+    type T = stable_mir::ty::Generics;
+
+    fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T {
+        use stable_mir::ty::Generics;
+
+        let params: Vec<_> = self.params.iter().map(|param| param.stable(tables)).collect();
+        let param_def_id_to_index =
+            params.iter().map(|param| (param.def_id, param.index)).collect();
+
+        Generics {
+            parent: self.parent.map(|did| tables.generic_def(did)),
+            parent_count: self.parent_count,
+            params,
+            param_def_id_to_index,
+            has_self: self.has_self,
+            has_late_bound_regions: self
+                .has_late_bound_regions
+                .as_ref()
+                .map(|late_bound_regions| late_bound_regions.stable(tables)),
+            host_effect_index: self.host_effect_index,
+        }
+    }
+}
+
+impl<'tcx> Stable<'tcx> for rustc_middle::ty::GenericParamDefKind {
+    type T = stable_mir::ty::GenericParamDefKind;
+
+    fn stable(&self, _: &mut Tables<'tcx>) -> Self::T {
+        use stable_mir::ty::GenericParamDefKind;
+        match self {
+            ty::GenericParamDefKind::Lifetime => GenericParamDefKind::Lifetime,
+            ty::GenericParamDefKind::Type { has_default, synthetic } => {
+                GenericParamDefKind::Type { has_default: *has_default, synthetic: *synthetic }
+            }
+            ty::GenericParamDefKind::Const { has_default, is_host_effect: _ } => {
+                GenericParamDefKind::Const { has_default: *has_default }
+            }
+        }
+    }
+}
+
+impl<'tcx> Stable<'tcx> for rustc_middle::ty::GenericParamDef {
+    type T = stable_mir::ty::GenericParamDef;
+
+    fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T {
+        GenericParamDef {
+            name: self.name.to_string(),
+            def_id: tables.generic_def(self.def_id),
+            index: self.index,
+            pure_wrt_drop: self.pure_wrt_drop,
+            kind: self.kind.stable(tables),
+        }
+    }
+}
+
+impl<'tcx> Stable<'tcx> for ty::PredicateKind<'tcx> {
+    type T = stable_mir::ty::PredicateKind;
+
+    fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T {
+        use rustc_middle::ty::PredicateKind;
+        match self {
+            PredicateKind::Clause(clause_kind) => {
+                stable_mir::ty::PredicateKind::Clause(clause_kind.stable(tables))
+            }
+            PredicateKind::ObjectSafe(did) => {
+                stable_mir::ty::PredicateKind::ObjectSafe(tables.trait_def(*did))
+            }
+            PredicateKind::Subtype(subtype_predicate) => {
+                stable_mir::ty::PredicateKind::SubType(subtype_predicate.stable(tables))
+            }
+            PredicateKind::Coerce(coerce_predicate) => {
+                stable_mir::ty::PredicateKind::Coerce(coerce_predicate.stable(tables))
+            }
+            PredicateKind::ConstEquate(a, b) => {
+                stable_mir::ty::PredicateKind::ConstEquate(a.stable(tables), b.stable(tables))
+            }
+            PredicateKind::Ambiguous => stable_mir::ty::PredicateKind::Ambiguous,
+            PredicateKind::AliasRelate(a, b, alias_relation_direction) => {
+                stable_mir::ty::PredicateKind::AliasRelate(
+                    a.unpack().stable(tables),
+                    b.unpack().stable(tables),
+                    alias_relation_direction.stable(tables),
+                )
+            }
+        }
+    }
+}
+
+impl<'tcx> Stable<'tcx> for ty::ClauseKind<'tcx> {
+    type T = stable_mir::ty::ClauseKind;
+
+    fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T {
+        use rustc_middle::ty::ClauseKind;
+        match *self {
+            ClauseKind::Trait(trait_object) => {
+                stable_mir::ty::ClauseKind::Trait(trait_object.stable(tables))
+            }
+            ClauseKind::RegionOutlives(region_outlives) => {
+                stable_mir::ty::ClauseKind::RegionOutlives(region_outlives.stable(tables))
+            }
+            ClauseKind::TypeOutlives(type_outlives) => {
+                let ty::OutlivesPredicate::<_, _>(a, b) = type_outlives;
+                stable_mir::ty::ClauseKind::TypeOutlives(stable_mir::ty::OutlivesPredicate(
+                    a.stable(tables),
+                    b.stable(tables),
+                ))
+            }
+            ClauseKind::Projection(projection_predicate) => {
+                stable_mir::ty::ClauseKind::Projection(projection_predicate.stable(tables))
+            }
+            ClauseKind::ConstArgHasType(const_, ty) => stable_mir::ty::ClauseKind::ConstArgHasType(
+                const_.stable(tables),
+                ty.stable(tables),
+            ),
+            ClauseKind::WellFormed(generic_arg) => {
+                stable_mir::ty::ClauseKind::WellFormed(generic_arg.unpack().stable(tables))
+            }
+            ClauseKind::ConstEvaluatable(const_) => {
+                stable_mir::ty::ClauseKind::ConstEvaluatable(const_.stable(tables))
+            }
+        }
+    }
+}
+
+impl<'tcx> Stable<'tcx> for ty::ClosureKind {
+    type T = stable_mir::ty::ClosureKind;
+
+    fn stable(&self, _: &mut Tables<'tcx>) -> Self::T {
+        use rustc_middle::ty::ClosureKind::*;
+        match self {
+            Fn => stable_mir::ty::ClosureKind::Fn,
+            FnMut => stable_mir::ty::ClosureKind::FnMut,
+            FnOnce => stable_mir::ty::ClosureKind::FnOnce,
+        }
+    }
+}
+
+impl<'tcx> Stable<'tcx> for ty::SubtypePredicate<'tcx> {
+    type T = stable_mir::ty::SubtypePredicate;
+
+    fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T {
+        let ty::SubtypePredicate { a, b, a_is_expected: _ } = self;
+        stable_mir::ty::SubtypePredicate { a: a.stable(tables), b: b.stable(tables) }
+    }
+}
+
+impl<'tcx> Stable<'tcx> for ty::CoercePredicate<'tcx> {
+    type T = stable_mir::ty::CoercePredicate;
+
+    fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T {
+        let ty::CoercePredicate { a, b } = self;
+        stable_mir::ty::CoercePredicate { a: a.stable(tables), b: b.stable(tables) }
+    }
+}
+
+impl<'tcx> Stable<'tcx> for ty::AliasRelationDirection {
+    type T = stable_mir::ty::AliasRelationDirection;
+
+    fn stable(&self, _: &mut Tables<'tcx>) -> Self::T {
+        use rustc_middle::ty::AliasRelationDirection::*;
+        match self {
+            Equate => stable_mir::ty::AliasRelationDirection::Equate,
+            Subtype => stable_mir::ty::AliasRelationDirection::Subtype,
+        }
+    }
+}
+
+impl<'tcx> Stable<'tcx> for ty::TraitPredicate<'tcx> {
+    type T = stable_mir::ty::TraitPredicate;
+
+    fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T {
+        let ty::TraitPredicate { trait_ref, polarity } = self;
+        stable_mir::ty::TraitPredicate {
+            trait_ref: trait_ref.stable(tables),
+            polarity: polarity.stable(tables),
+        }
+    }
+}
+
+impl<'tcx, A, B, U, V> Stable<'tcx> for ty::OutlivesPredicate<A, B>
+where
+    A: Stable<'tcx, T = U>,
+    B: Stable<'tcx, T = V>,
+{
+    type T = stable_mir::ty::OutlivesPredicate<U, V>;
+
+    fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T {
+        let ty::OutlivesPredicate(a, b) = self;
+        stable_mir::ty::OutlivesPredicate(a.stable(tables), b.stable(tables))
+    }
+}
+
+impl<'tcx> Stable<'tcx> for ty::ProjectionPredicate<'tcx> {
+    type T = stable_mir::ty::ProjectionPredicate;
+
+    fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T {
+        let ty::ProjectionPredicate { projection_ty, term } = self;
+        stable_mir::ty::ProjectionPredicate {
+            projection_ty: projection_ty.stable(tables),
+            term: term.unpack().stable(tables),
+        }
+    }
+}
+
+impl<'tcx> Stable<'tcx> for ty::ImplPolarity {
+    type T = stable_mir::ty::ImplPolarity;
+
+    fn stable(&self, _: &mut Tables<'tcx>) -> Self::T {
+        use rustc_middle::ty::ImplPolarity::*;
+        match self {
+            Positive => stable_mir::ty::ImplPolarity::Positive,
+            Negative => stable_mir::ty::ImplPolarity::Negative,
+            Reservation => stable_mir::ty::ImplPolarity::Reservation,
+        }
+    }
+}
+
+impl<'tcx> Stable<'tcx> for ty::Region<'tcx> {
+    type T = stable_mir::ty::Region;
+
+    fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T {
+        Region { kind: self.kind().stable(tables) }
+    }
+}
+
+impl<'tcx> Stable<'tcx> for ty::RegionKind<'tcx> {
+    type T = stable_mir::ty::RegionKind;
+
+    fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T {
+        use stable_mir::ty::{BoundRegion, EarlyParamRegion, RegionKind};
+        match self {
+            ty::ReEarlyParam(early_reg) => RegionKind::ReEarlyParam(EarlyParamRegion {
+                def_id: tables.region_def(early_reg.def_id),
+                index: early_reg.index,
+                name: early_reg.name.to_string(),
+            }),
+            ty::ReBound(db_index, bound_reg) => RegionKind::ReBound(
+                db_index.as_u32(),
+                BoundRegion { var: bound_reg.var.as_u32(), kind: bound_reg.kind.stable(tables) },
+            ),
+            ty::ReStatic => RegionKind::ReStatic,
+            ty::RePlaceholder(place_holder) => {
+                RegionKind::RePlaceholder(stable_mir::ty::Placeholder {
+                    universe: place_holder.universe.as_u32(),
+                    bound: BoundRegion {
+                        var: place_holder.bound.var.as_u32(),
+                        kind: place_holder.bound.kind.stable(tables),
+                    },
+                })
+            }
+            ty::ReErased => RegionKind::ReErased,
+            _ => unreachable!("{self:?}"),
+        }
+    }
+}
+
+impl<'tcx> Stable<'tcx> for ty::Instance<'tcx> {
+    type T = stable_mir::mir::mono::Instance;
+
+    fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T {
+        let def = tables.instance_def(*self);
+        let kind = match self.def {
+            ty::InstanceDef::Item(..) => stable_mir::mir::mono::InstanceKind::Item,
+            ty::InstanceDef::Intrinsic(..) => stable_mir::mir::mono::InstanceKind::Intrinsic,
+            ty::InstanceDef::Virtual(..) => stable_mir::mir::mono::InstanceKind::Virtual,
+            ty::InstanceDef::VTableShim(..)
+            | ty::InstanceDef::ReifyShim(..)
+            | ty::InstanceDef::FnPtrAddrShim(..)
+            | ty::InstanceDef::ClosureOnceShim { .. }
+            | ty::InstanceDef::ThreadLocalShim(..)
+            | ty::InstanceDef::DropGlue(..)
+            | ty::InstanceDef::CloneShim(..)
+            | ty::InstanceDef::FnPtrShim(..) => stable_mir::mir::mono::InstanceKind::Shim,
+        };
+        stable_mir::mir::mono::Instance { def, kind }
+    }
+}
+
+impl<'tcx> Stable<'tcx> for ty::Variance {
+    type T = stable_mir::mir::Variance;
+    fn stable(&self, _: &mut Tables<'tcx>) -> Self::T {
+        match self {
+            ty::Variance::Bivariant => stable_mir::mir::Variance::Bivariant,
+            ty::Variance::Contravariant => stable_mir::mir::Variance::Contravariant,
+            ty::Variance::Covariant => stable_mir::mir::Variance::Covariant,
+            ty::Variance::Invariant => stable_mir::mir::Variance::Invariant,
+        }
+    }
+}
+
+impl<'tcx> Stable<'tcx> for ty::Movability {
+    type T = stable_mir::ty::Movability;
+
+    fn stable(&self, _: &mut Tables<'tcx>) -> Self::T {
+        match self {
+            ty::Movability::Static => stable_mir::ty::Movability::Static,
+            ty::Movability::Movable => stable_mir::ty::Movability::Movable,
+        }
+    }
+}
diff --git a/compiler/rustc_smir/src/rustc_smir/mod.rs b/compiler/rustc_smir/src/rustc_smir/mod.rs
index 9921a89eb23..5d903e69c6c 100644
--- a/compiler/rustc_smir/src/rustc_smir/mod.rs
+++ b/compiler/rustc_smir/src/rustc_smir/mod.rs
@@ -7,389 +7,22 @@
 //!
 //! For now, we are developing everything inside `rustc`, thus, we keep this module private.
 
-use crate::rustc_internal::{internal, IndexMap, RustcInternal};
-use crate::rustc_smir::stable_mir::ty::{BoundRegion, Region};
-use rustc_hir as hir;
 use rustc_hir::def::DefKind;
 use rustc_middle::mir;
-use rustc_middle::mir::interpret::{alloc_range, AllocId};
-use rustc_middle::mir::mono::MonoItem;
-use rustc_middle::ty::print::{with_forced_trimmed_paths, with_no_trimmed_paths};
-use rustc_middle::ty::{self, Instance, ParamEnv, ScalarInt, Ty, TyCtxt, Variance};
+use rustc_middle::mir::interpret::AllocId;
+use rustc_middle::ty::{self, Instance, Ty, TyCtxt};
 use rustc_span::def_id::{CrateNum, DefId, LOCAL_CRATE};
-use rustc_target::abi::FieldIdx;
-use stable_mir::mir::alloc::GlobalAlloc;
-use stable_mir::mir::mono::{InstanceDef, StaticDef};
-use stable_mir::mir::{
-    Body, ConstOperand, CopyNonOverlapping, Statement, UserTypeProjection, VarDebugInfoFragment,
-    VariantIdx,
-};
-use stable_mir::ty::{
-    AdtDef, AdtKind, Allocation, ClosureDef, ClosureKind, Const, ConstId, ConstantKind,
-    EarlyParamRegion, FloatTy, FnDef, GenericArgs, GenericParamDef, IntTy, LineInfo, Movability,
-    RigidTy, Span, TyKind, UintTy,
-};
-use stable_mir::{self, opaque, Context, Crate, CrateItem, Error, Filename, ItemKind, Symbol};
-use std::cell::RefCell;
+use stable_mir::mir::mono::InstanceDef;
+use stable_mir::ty::{ConstId, Span};
+use stable_mir::{self, ItemKind};
 use tracing::debug;
 
+use crate::rustc_internal::IndexMap;
+
 mod alloc;
 mod builder;
-
-impl<'tcx> Context for TablesWrapper<'tcx> {
-    fn local_crate(&self) -> stable_mir::Crate {
-        let tables = self.0.borrow();
-        smir_crate(tables.tcx, LOCAL_CRATE)
-    }
-
-    fn external_crates(&self) -> Vec<stable_mir::Crate> {
-        let tables = self.0.borrow();
-        tables.tcx.crates(()).iter().map(|crate_num| smir_crate(tables.tcx, *crate_num)).collect()
-    }
-
-    fn find_crates(&self, name: &str) -> Vec<stable_mir::Crate> {
-        let tables = self.0.borrow();
-        let crates: Vec<stable_mir::Crate> = [LOCAL_CRATE]
-            .iter()
-            .chain(tables.tcx.crates(()).iter())
-            .map(|crate_num| {
-                let crate_name = tables.tcx.crate_name(*crate_num).to_string();
-                (name == crate_name).then(|| smir_crate(tables.tcx, *crate_num))
-            })
-            .into_iter()
-            .filter_map(|c| c)
-            .collect();
-        crates
-    }
-
-    fn def_name(&self, def_id: stable_mir::DefId, trimmed: bool) -> Symbol {
-        let tables = self.0.borrow();
-        if trimmed {
-            with_forced_trimmed_paths!(tables.tcx.def_path_str(tables[def_id]))
-        } else {
-            with_no_trimmed_paths!(tables.tcx.def_path_str(tables[def_id]))
-        }
-    }
-
-    fn krate(&self, def_id: stable_mir::DefId) -> Crate {
-        let tables = self.0.borrow();
-        smir_crate(tables.tcx, tables[def_id].krate)
-    }
-
-    fn span_to_string(&self, span: stable_mir::ty::Span) -> String {
-        let tables = self.0.borrow();
-        tables.tcx.sess.source_map().span_to_diagnostic_string(tables[span])
-    }
-
-    fn get_filename(&self, span: &Span) -> Filename {
-        let tables = self.0.borrow();
-        tables
-            .tcx
-            .sess
-            .source_map()
-            .span_to_filename(tables[*span])
-            .display(rustc_span::FileNameDisplayPreference::Local)
-            .to_string()
-    }
-
-    fn get_lines(&self, span: &Span) -> LineInfo {
-        let tables = self.0.borrow();
-        let lines = &tables.tcx.sess.source_map().span_to_location_info(tables[*span]);
-        LineInfo { start_line: lines.1, start_col: lines.2, end_line: lines.3, end_col: lines.4 }
-    }
-
-    fn item_kind(&self, item: CrateItem) -> ItemKind {
-        let tables = self.0.borrow();
-        new_item_kind(tables.tcx.def_kind(tables[item.0]))
-    }
-
-    fn is_foreign_item(&self, item: CrateItem) -> bool {
-        let tables = self.0.borrow();
-        tables.tcx.is_foreign_item(tables[item.0])
-    }
-
-    fn adt_kind(&self, def: AdtDef) -> AdtKind {
-        let mut tables = self.0.borrow_mut();
-        def.internal(&mut *tables).adt_kind().stable(&mut *tables)
-    }
-
-    fn def_ty(&self, item: stable_mir::DefId) -> stable_mir::ty::Ty {
-        let mut tables = self.0.borrow_mut();
-        tables.tcx.type_of(item.internal(&mut *tables)).instantiate_identity().stable(&mut *tables)
-    }
-
-    fn const_literal(&self, cnst: &stable_mir::ty::Const) -> String {
-        internal(cnst).to_string()
-    }
-
-    fn span_of_an_item(&self, def_id: stable_mir::DefId) -> Span {
-        let mut tables = self.0.borrow_mut();
-        tables.tcx.def_span(tables[def_id]).stable(&mut *tables)
-    }
-
-    fn all_local_items(&self) -> stable_mir::CrateItems {
-        let mut tables = self.0.borrow_mut();
-        tables.tcx.mir_keys(()).iter().map(|item| tables.crate_item(item.to_def_id())).collect()
-    }
-
-    fn entry_fn(&self) -> Option<stable_mir::CrateItem> {
-        let mut tables = self.0.borrow_mut();
-        let tcx = tables.tcx;
-        Some(tables.crate_item(tcx.entry_fn(())?.0))
-    }
-
-    fn all_trait_decls(&self) -> stable_mir::TraitDecls {
-        let mut tables = self.0.borrow_mut();
-        tables
-            .tcx
-            .traits(LOCAL_CRATE)
-            .iter()
-            .map(|trait_def_id| tables.trait_def(*trait_def_id))
-            .collect()
-    }
-
-    fn trait_decl(&self, trait_def: &stable_mir::ty::TraitDef) -> stable_mir::ty::TraitDecl {
-        let mut tables = self.0.borrow_mut();
-        let def_id = tables[trait_def.0];
-        let trait_def = tables.tcx.trait_def(def_id);
-        trait_def.stable(&mut *tables)
-    }
-
-    fn all_trait_impls(&self) -> stable_mir::ImplTraitDecls {
-        let mut tables = self.0.borrow_mut();
-        tables
-            .tcx
-            .trait_impls_in_crate(LOCAL_CRATE)
-            .iter()
-            .map(|impl_def_id| tables.impl_def(*impl_def_id))
-            .collect()
-    }
-
-    fn trait_impl(&self, impl_def: &stable_mir::ty::ImplDef) -> stable_mir::ty::ImplTrait {
-        let mut tables = self.0.borrow_mut();
-        let def_id = tables[impl_def.0];
-        let impl_trait = tables.tcx.impl_trait_ref(def_id).unwrap();
-        impl_trait.stable(&mut *tables)
-    }
-
-    fn mir_body(&self, item: stable_mir::DefId) -> stable_mir::mir::Body {
-        let mut tables = self.0.borrow_mut();
-        let def_id = tables[item];
-        tables.tcx.instance_mir(ty::InstanceDef::Item(def_id)).stable(&mut tables)
-    }
-
-    fn ty_kind(&self, ty: stable_mir::ty::Ty) -> TyKind {
-        let mut tables = self.0.borrow_mut();
-        tables.types[ty].kind().stable(&mut *tables)
-    }
-
-    fn generics_of(&self, def_id: stable_mir::DefId) -> stable_mir::ty::Generics {
-        let mut tables = self.0.borrow_mut();
-        let def_id = tables[def_id];
-        let generics = tables.tcx.generics_of(def_id);
-        generics.stable(&mut *tables)
-    }
-
-    fn predicates_of(&self, def_id: stable_mir::DefId) -> stable_mir::ty::GenericPredicates {
-        let mut tables = self.0.borrow_mut();
-        let def_id = tables[def_id];
-        let ty::GenericPredicates { parent, predicates } = tables.tcx.predicates_of(def_id);
-        stable_mir::ty::GenericPredicates {
-            parent: parent.map(|did| tables.trait_def(did)),
-            predicates: predicates
-                .iter()
-                .map(|(clause, span)| {
-                    (
-                        clause.as_predicate().kind().skip_binder().stable(&mut *tables),
-                        span.stable(&mut *tables),
-                    )
-                })
-                .collect(),
-        }
-    }
-
-    fn explicit_predicates_of(
-        &self,
-        def_id: stable_mir::DefId,
-    ) -> stable_mir::ty::GenericPredicates {
-        let mut tables = self.0.borrow_mut();
-        let def_id = tables[def_id];
-        let ty::GenericPredicates { parent, predicates } =
-            tables.tcx.explicit_predicates_of(def_id);
-        stable_mir::ty::GenericPredicates {
-            parent: parent.map(|did| tables.trait_def(did)),
-            predicates: predicates
-                .iter()
-                .map(|(clause, span)| {
-                    (
-                        clause.as_predicate().kind().skip_binder().stable(&mut *tables),
-                        span.stable(&mut *tables),
-                    )
-                })
-                .collect(),
-        }
-    }
-
-    fn instance_body(&self, def: InstanceDef) -> Option<Body> {
-        let mut tables = self.0.borrow_mut();
-        let instance = tables.instances[def];
-        tables
-            .has_body(instance)
-            .then(|| builder::BodyBuilder::new(tables.tcx, instance).build(&mut *tables))
-    }
-
-    fn instance_ty(&self, def: InstanceDef) -> stable_mir::ty::Ty {
-        let mut tables = self.0.borrow_mut();
-        let instance = tables.instances[def];
-        instance.ty(tables.tcx, ParamEnv::empty()).stable(&mut *tables)
-    }
-
-    fn instance_def_id(&self, def: InstanceDef) -> stable_mir::DefId {
-        let mut tables = self.0.borrow_mut();
-        let def_id = tables.instances[def].def_id();
-        tables.create_def_id(def_id)
-    }
-
-    fn instance_mangled_name(&self, instance: InstanceDef) -> Symbol {
-        let tables = self.0.borrow_mut();
-        let instance = tables.instances[instance];
-        tables.tcx.symbol_name(instance).name.to_string()
-    }
-
-    /// Retrieve the instance name for diagnostic messages.
-    ///
-    /// This will return the specialized name, e.g., `Vec<char>::new`.
-    fn instance_name(&self, def: InstanceDef, trimmed: bool) -> Symbol {
-        let tables = self.0.borrow_mut();
-        let instance = tables.instances[def];
-        if trimmed {
-            with_forced_trimmed_paths!(
-                tables.tcx.def_path_str_with_args(instance.def_id(), instance.args)
-            )
-        } else {
-            with_no_trimmed_paths!(
-                tables.tcx.def_path_str_with_args(instance.def_id(), instance.args)
-            )
-        }
-    }
-
-    fn mono_instance(&self, item: stable_mir::CrateItem) -> stable_mir::mir::mono::Instance {
-        let mut tables = self.0.borrow_mut();
-        let def_id = tables[item.0];
-        Instance::mono(tables.tcx, def_id).stable(&mut *tables)
-    }
-
-    fn requires_monomorphization(&self, def_id: stable_mir::DefId) -> bool {
-        let tables = self.0.borrow();
-        let def_id = tables[def_id];
-        let generics = tables.tcx.generics_of(def_id);
-        let result = generics.requires_monomorphization(tables.tcx);
-        result
-    }
-
-    fn resolve_instance(
-        &self,
-        def: stable_mir::ty::FnDef,
-        args: &stable_mir::ty::GenericArgs,
-    ) -> Option<stable_mir::mir::mono::Instance> {
-        let mut tables = self.0.borrow_mut();
-        let def_id = def.0.internal(&mut *tables);
-        let args_ref = args.internal(&mut *tables);
-        match Instance::resolve(tables.tcx, ParamEnv::reveal_all(), def_id, args_ref) {
-            Ok(Some(instance)) => Some(instance.stable(&mut *tables)),
-            Ok(None) | Err(_) => None,
-        }
-    }
-
-    fn resolve_drop_in_place(&self, ty: stable_mir::ty::Ty) -> stable_mir::mir::mono::Instance {
-        let mut tables = self.0.borrow_mut();
-        let internal_ty = ty.internal(&mut *tables);
-        let instance = Instance::resolve_drop_in_place(tables.tcx, internal_ty);
-        instance.stable(&mut *tables)
-    }
-
-    fn resolve_for_fn_ptr(
-        &self,
-        def: FnDef,
-        args: &GenericArgs,
-    ) -> Option<stable_mir::mir::mono::Instance> {
-        let mut tables = self.0.borrow_mut();
-        let def_id = def.0.internal(&mut *tables);
-        let args_ref = args.internal(&mut *tables);
-        Instance::resolve_for_fn_ptr(tables.tcx, ParamEnv::reveal_all(), def_id, args_ref)
-            .stable(&mut *tables)
-    }
-
-    fn resolve_closure(
-        &self,
-        def: ClosureDef,
-        args: &GenericArgs,
-        kind: ClosureKind,
-    ) -> Option<stable_mir::mir::mono::Instance> {
-        let mut tables = self.0.borrow_mut();
-        let def_id = def.0.internal(&mut *tables);
-        let args_ref = args.internal(&mut *tables);
-        let closure_kind = kind.internal(&mut *tables);
-        Instance::resolve_closure(tables.tcx, def_id, args_ref, closure_kind).stable(&mut *tables)
-    }
-
-    fn adt_is_box(&self, def: AdtDef) -> bool {
-        let mut tables = self.0.borrow_mut();
-        def.internal(&mut *tables).is_box()
-    }
-
-    fn eval_target_usize(&self, cnst: &Const) -> Result<u64, Error> {
-        let mut tables = self.0.borrow_mut();
-        let mir_const = cnst.internal(&mut *tables);
-        mir_const
-            .try_eval_target_usize(tables.tcx, ParamEnv::empty())
-            .ok_or_else(|| Error::new(format!("Const `{cnst:?}` cannot be encoded as u64")))
-    }
-
-    fn eval_static_initializer(&self, def: StaticDef) -> Result<Allocation, Error> {
-        let mut tables = self.0.borrow_mut();
-        let def_id = def.0.internal(&mut *tables);
-        tables.tcx.eval_static_initializer(def_id).stable(&mut *tables)
-    }
-
-    fn global_alloc(&self, alloc: stable_mir::mir::alloc::AllocId) -> GlobalAlloc {
-        let mut tables = self.0.borrow_mut();
-        let alloc_id = alloc.internal(&mut *tables);
-        tables.tcx.global_alloc(alloc_id).stable(&mut *tables)
-    }
-
-    fn vtable_allocation(
-        &self,
-        global_alloc: &GlobalAlloc,
-    ) -> Option<stable_mir::mir::alloc::AllocId> {
-        let mut tables = self.0.borrow_mut();
-        let GlobalAlloc::VTable(ty, trait_ref) = global_alloc else { return None };
-        let alloc_id = tables
-            .tcx
-            .vtable_allocation((ty.internal(&mut *tables), trait_ref.internal(&mut *tables)));
-        Some(alloc_id.stable(&mut *tables))
-    }
-
-    fn usize_to_const(&self, val: u64) -> Result<Const, Error> {
-        let mut tables = self.0.borrow_mut();
-        let ty = tables.tcx.types.usize;
-        let size = tables.tcx.layout_of(ParamEnv::empty().and(ty)).unwrap().size;
-
-        let scalar = ScalarInt::try_from_uint(val, size).ok_or_else(|| {
-            Error::new(format!("Value overflow: cannot convert `{val}` to usize."))
-        })?;
-        Ok(ty::Const::new_value(tables.tcx, ty::ValTree::from_scalar_int(scalar), ty)
-            .stable(&mut *tables))
-    }
-
-    fn new_rigid_ty(&self, kind: RigidTy) -> stable_mir::ty::Ty {
-        let mut tables = self.0.borrow_mut();
-        let internal_kind = kind.internal(&mut *tables);
-        tables.tcx.mk_ty_from_kind(internal_kind).stable(&mut *tables)
-    }
-}
-
-pub(crate) struct TablesWrapper<'tcx>(pub(crate) RefCell<Tables<'tcx>>);
+pub(crate) mod context;
+mod convert;
 
 pub struct Tables<'tcx> {
     pub(crate) tcx: TyCtxt<'tcx>,
@@ -402,15 +35,15 @@ pub struct Tables<'tcx> {
 }
 
 impl<'tcx> Tables<'tcx> {
-    fn intern_ty(&mut self, ty: Ty<'tcx>) -> stable_mir::ty::Ty {
+    pub(crate) fn intern_ty(&mut self, ty: Ty<'tcx>) -> stable_mir::ty::Ty {
         self.types.create_or_fetch(ty)
     }
 
-    fn intern_const(&mut self, constant: mir::Const<'tcx>) -> ConstId {
+    pub(crate) fn intern_const(&mut self, constant: mir::Const<'tcx>) -> ConstId {
         self.constants.create_or_fetch(constant)
     }
 
-    fn has_body(&self, instance: Instance<'tcx>) -> bool {
+    pub(crate) fn has_body(&self, instance: Instance<'tcx>) -> bool {
         let def_id = instance.def_id();
         self.tcx.is_mir_available(def_id)
             || !matches!(
@@ -423,14 +56,14 @@ impl<'tcx> Tables<'tcx> {
 }
 
 /// Build a stable mir crate from a given crate number.
-fn smir_crate(tcx: TyCtxt<'_>, crate_num: CrateNum) -> stable_mir::Crate {
+pub(crate) fn smir_crate(tcx: TyCtxt<'_>, crate_num: CrateNum) -> stable_mir::Crate {
     let crate_name = tcx.crate_name(crate_num).to_string();
     let is_local = crate_num == LOCAL_CRATE;
     debug!(?crate_name, ?crate_num, "smir_crate");
     stable_mir::Crate { id: crate_num.into(), name: crate_name, is_local }
 }
 
-fn new_item_kind(kind: DefKind) -> ItemKind {
+pub(crate) fn new_item_kind(kind: DefKind) -> ItemKind {
     match kind {
         DefKind::Mod
         | DefKind::Struct
@@ -472,1610 +105,6 @@ pub trait Stable<'tcx> {
     fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T;
 }
 
-impl<'tcx> Stable<'tcx> for mir::Body<'tcx> {
-    type T = stable_mir::mir::Body;
-
-    fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T {
-        stable_mir::mir::Body::new(
-            self.basic_blocks
-                .iter()
-                .map(|block| stable_mir::mir::BasicBlock {
-                    terminator: block.terminator().stable(tables),
-                    statements: block
-                        .statements
-                        .iter()
-                        .map(|statement| statement.stable(tables))
-                        .collect(),
-                })
-                .collect(),
-            self.local_decls
-                .iter()
-                .map(|decl| stable_mir::mir::LocalDecl {
-                    ty: decl.ty.stable(tables),
-                    span: decl.source_info.span.stable(tables),
-                    mutability: decl.mutability.stable(tables),
-                })
-                .collect(),
-            self.arg_count,
-            self.var_debug_info.iter().map(|info| info.stable(tables)).collect(),
-        )
-    }
-}
-
-impl<'tcx> Stable<'tcx> for mir::VarDebugInfo<'tcx> {
-    type T = stable_mir::mir::VarDebugInfo;
-    fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T {
-        stable_mir::mir::VarDebugInfo {
-            name: self.name.to_string(),
-            source_info: self.source_info.stable(tables),
-            composite: self.composite.as_ref().map(|composite| composite.stable(tables)),
-            value: self.value.stable(tables),
-            argument_index: self.argument_index,
-        }
-    }
-}
-
-impl<'tcx> Stable<'tcx> for mir::Statement<'tcx> {
-    type T = stable_mir::mir::Statement;
-    fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T {
-        Statement { kind: self.kind.stable(tables), span: self.source_info.span.stable(tables) }
-    }
-}
-
-impl<'tcx> Stable<'tcx> for mir::SourceInfo {
-    type T = stable_mir::mir::SourceInfo;
-    fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T {
-        stable_mir::mir::SourceInfo { span: self.span.stable(tables), scope: self.scope.into() }
-    }
-}
-
-impl<'tcx> Stable<'tcx> for mir::VarDebugInfoFragment<'tcx> {
-    type T = stable_mir::mir::VarDebugInfoFragment;
-    fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T {
-        VarDebugInfoFragment {
-            ty: self.ty.stable(tables),
-            projection: self.projection.iter().map(|e| e.stable(tables)).collect(),
-        }
-    }
-}
-
-impl<'tcx> Stable<'tcx> for mir::VarDebugInfoContents<'tcx> {
-    type T = stable_mir::mir::VarDebugInfoContents;
-    fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T {
-        match self {
-            mir::VarDebugInfoContents::Place(place) => {
-                stable_mir::mir::VarDebugInfoContents::Place(place.stable(tables))
-            }
-            mir::VarDebugInfoContents::Const(const_operand) => {
-                let op = ConstOperand {
-                    span: const_operand.span.stable(tables),
-                    user_ty: const_operand.user_ty.map(|index| index.as_usize()),
-                    const_: const_operand.const_.stable(tables),
-                };
-                stable_mir::mir::VarDebugInfoContents::Const(op)
-            }
-        }
-    }
-}
-
-impl<'tcx> Stable<'tcx> for mir::StatementKind<'tcx> {
-    type T = stable_mir::mir::StatementKind;
-    fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T {
-        match self {
-            mir::StatementKind::Assign(assign) => stable_mir::mir::StatementKind::Assign(
-                assign.0.stable(tables),
-                assign.1.stable(tables),
-            ),
-            mir::StatementKind::FakeRead(fake_read_place) => {
-                stable_mir::mir::StatementKind::FakeRead(
-                    fake_read_place.0.stable(tables),
-                    fake_read_place.1.stable(tables),
-                )
-            }
-            mir::StatementKind::SetDiscriminant { place, variant_index } => {
-                stable_mir::mir::StatementKind::SetDiscriminant {
-                    place: place.as_ref().stable(tables),
-                    variant_index: variant_index.stable(tables),
-                }
-            }
-            mir::StatementKind::Deinit(place) => {
-                stable_mir::mir::StatementKind::Deinit(place.stable(tables))
-            }
-
-            mir::StatementKind::StorageLive(place) => {
-                stable_mir::mir::StatementKind::StorageLive(place.stable(tables))
-            }
-
-            mir::StatementKind::StorageDead(place) => {
-                stable_mir::mir::StatementKind::StorageDead(place.stable(tables))
-            }
-            mir::StatementKind::Retag(retag, place) => {
-                stable_mir::mir::StatementKind::Retag(retag.stable(tables), place.stable(tables))
-            }
-            mir::StatementKind::PlaceMention(place) => {
-                stable_mir::mir::StatementKind::PlaceMention(place.stable(tables))
-            }
-            mir::StatementKind::AscribeUserType(place_projection, variance) => {
-                stable_mir::mir::StatementKind::AscribeUserType {
-                    place: place_projection.as_ref().0.stable(tables),
-                    projections: place_projection.as_ref().1.stable(tables),
-                    variance: variance.stable(tables),
-                }
-            }
-            mir::StatementKind::Coverage(coverage) => {
-                stable_mir::mir::StatementKind::Coverage(opaque(coverage))
-            }
-            mir::StatementKind::Intrinsic(intrinstic) => {
-                stable_mir::mir::StatementKind::Intrinsic(intrinstic.stable(tables))
-            }
-            mir::StatementKind::ConstEvalCounter => {
-                stable_mir::mir::StatementKind::ConstEvalCounter
-            }
-            mir::StatementKind::Nop => stable_mir::mir::StatementKind::Nop,
-        }
-    }
-}
-
-impl<'tcx> Stable<'tcx> for mir::Rvalue<'tcx> {
-    type T = stable_mir::mir::Rvalue;
-    fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T {
-        use mir::Rvalue::*;
-        match self {
-            Use(op) => stable_mir::mir::Rvalue::Use(op.stable(tables)),
-            Repeat(op, len) => {
-                let len = len.stable(tables);
-                stable_mir::mir::Rvalue::Repeat(op.stable(tables), len)
-            }
-            Ref(region, kind, place) => stable_mir::mir::Rvalue::Ref(
-                region.stable(tables),
-                kind.stable(tables),
-                place.stable(tables),
-            ),
-            ThreadLocalRef(def_id) => {
-                stable_mir::mir::Rvalue::ThreadLocalRef(tables.crate_item(*def_id))
-            }
-            AddressOf(mutability, place) => {
-                stable_mir::mir::Rvalue::AddressOf(mutability.stable(tables), place.stable(tables))
-            }
-            Len(place) => stable_mir::mir::Rvalue::Len(place.stable(tables)),
-            Cast(cast_kind, op, ty) => stable_mir::mir::Rvalue::Cast(
-                cast_kind.stable(tables),
-                op.stable(tables),
-                ty.stable(tables),
-            ),
-            BinaryOp(bin_op, ops) => stable_mir::mir::Rvalue::BinaryOp(
-                bin_op.stable(tables),
-                ops.0.stable(tables),
-                ops.1.stable(tables),
-            ),
-            CheckedBinaryOp(bin_op, ops) => stable_mir::mir::Rvalue::CheckedBinaryOp(
-                bin_op.stable(tables),
-                ops.0.stable(tables),
-                ops.1.stable(tables),
-            ),
-            NullaryOp(null_op, ty) => {
-                stable_mir::mir::Rvalue::NullaryOp(null_op.stable(tables), ty.stable(tables))
-            }
-            UnaryOp(un_op, op) => {
-                stable_mir::mir::Rvalue::UnaryOp(un_op.stable(tables), op.stable(tables))
-            }
-            Discriminant(place) => stable_mir::mir::Rvalue::Discriminant(place.stable(tables)),
-            Aggregate(agg_kind, operands) => {
-                let operands = operands.iter().map(|op| op.stable(tables)).collect();
-                stable_mir::mir::Rvalue::Aggregate(agg_kind.stable(tables), operands)
-            }
-            ShallowInitBox(op, ty) => {
-                stable_mir::mir::Rvalue::ShallowInitBox(op.stable(tables), ty.stable(tables))
-            }
-            CopyForDeref(place) => stable_mir::mir::Rvalue::CopyForDeref(place.stable(tables)),
-        }
-    }
-}
-
-impl<'tcx> Stable<'tcx> for mir::Mutability {
-    type T = stable_mir::mir::Mutability;
-    fn stable(&self, _: &mut Tables<'tcx>) -> Self::T {
-        use mir::Mutability::*;
-        match *self {
-            Not => stable_mir::mir::Mutability::Not,
-            Mut => stable_mir::mir::Mutability::Mut,
-        }
-    }
-}
-
-impl<'tcx> Stable<'tcx> for mir::BorrowKind {
-    type T = stable_mir::mir::BorrowKind;
-    fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T {
-        use mir::BorrowKind::*;
-        match *self {
-            Shared => stable_mir::mir::BorrowKind::Shared,
-            Fake => stable_mir::mir::BorrowKind::Fake,
-            Mut { kind } => stable_mir::mir::BorrowKind::Mut { kind: kind.stable(tables) },
-        }
-    }
-}
-
-impl<'tcx> Stable<'tcx> for mir::MutBorrowKind {
-    type T = stable_mir::mir::MutBorrowKind;
-    fn stable(&self, _: &mut Tables<'tcx>) -> Self::T {
-        use mir::MutBorrowKind::*;
-        match *self {
-            Default => stable_mir::mir::MutBorrowKind::Default,
-            TwoPhaseBorrow => stable_mir::mir::MutBorrowKind::TwoPhaseBorrow,
-            ClosureCapture => stable_mir::mir::MutBorrowKind::ClosureCapture,
-        }
-    }
-}
-
-impl<'tcx> Stable<'tcx> for mir::NullOp<'tcx> {
-    type T = stable_mir::mir::NullOp;
-    fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T {
-        use mir::NullOp::*;
-        match self {
-            SizeOf => stable_mir::mir::NullOp::SizeOf,
-            AlignOf => stable_mir::mir::NullOp::AlignOf,
-            OffsetOf(indices) => stable_mir::mir::NullOp::OffsetOf(
-                indices.iter().map(|idx| idx.stable(tables)).collect(),
-            ),
-        }
-    }
-}
-
-impl<'tcx> Stable<'tcx> for mir::CastKind {
-    type T = stable_mir::mir::CastKind;
-    fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T {
-        use mir::CastKind::*;
-        match self {
-            PointerExposeAddress => stable_mir::mir::CastKind::PointerExposeAddress,
-            PointerFromExposedAddress => stable_mir::mir::CastKind::PointerFromExposedAddress,
-            PointerCoercion(c) => stable_mir::mir::CastKind::PointerCoercion(c.stable(tables)),
-            DynStar => stable_mir::mir::CastKind::DynStar,
-            IntToInt => stable_mir::mir::CastKind::IntToInt,
-            FloatToInt => stable_mir::mir::CastKind::FloatToInt,
-            FloatToFloat => stable_mir::mir::CastKind::FloatToFloat,
-            IntToFloat => stable_mir::mir::CastKind::IntToFloat,
-            PtrToPtr => stable_mir::mir::CastKind::PtrToPtr,
-            FnPtrToPtr => stable_mir::mir::CastKind::FnPtrToPtr,
-            Transmute => stable_mir::mir::CastKind::Transmute,
-        }
-    }
-}
-
-impl<'tcx> Stable<'tcx> for ty::AliasKind {
-    type T = stable_mir::ty::AliasKind;
-    fn stable(&self, _: &mut Tables<'tcx>) -> Self::T {
-        use ty::AliasKind::*;
-        match self {
-            Projection => stable_mir::ty::AliasKind::Projection,
-            Inherent => stable_mir::ty::AliasKind::Inherent,
-            Opaque => stable_mir::ty::AliasKind::Opaque,
-            Weak => stable_mir::ty::AliasKind::Weak,
-        }
-    }
-}
-
-impl<'tcx> Stable<'tcx> for ty::AliasTy<'tcx> {
-    type T = stable_mir::ty::AliasTy;
-    fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T {
-        let ty::AliasTy { args, def_id, .. } = self;
-        stable_mir::ty::AliasTy { def_id: tables.alias_def(*def_id), args: args.stable(tables) }
-    }
-}
-
-impl<'tcx> Stable<'tcx> for ty::DynKind {
-    type T = stable_mir::ty::DynKind;
-
-    fn stable(&self, _: &mut Tables<'tcx>) -> Self::T {
-        use ty::DynKind;
-        match self {
-            DynKind::Dyn => stable_mir::ty::DynKind::Dyn,
-            DynKind::DynStar => stable_mir::ty::DynKind::DynStar,
-        }
-    }
-}
-
-impl<'tcx> Stable<'tcx> for ty::ExistentialPredicate<'tcx> {
-    type T = stable_mir::ty::ExistentialPredicate;
-
-    fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T {
-        use stable_mir::ty::ExistentialPredicate::*;
-        match self {
-            ty::ExistentialPredicate::Trait(existential_trait_ref) => {
-                Trait(existential_trait_ref.stable(tables))
-            }
-            ty::ExistentialPredicate::Projection(existential_projection) => {
-                Projection(existential_projection.stable(tables))
-            }
-            ty::ExistentialPredicate::AutoTrait(def_id) => AutoTrait(tables.trait_def(*def_id)),
-        }
-    }
-}
-
-impl<'tcx> Stable<'tcx> for ty::ExistentialTraitRef<'tcx> {
-    type T = stable_mir::ty::ExistentialTraitRef;
-
-    fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T {
-        let ty::ExistentialTraitRef { def_id, args } = self;
-        stable_mir::ty::ExistentialTraitRef {
-            def_id: tables.trait_def(*def_id),
-            generic_args: args.stable(tables),
-        }
-    }
-}
-
-impl<'tcx> Stable<'tcx> for ty::TermKind<'tcx> {
-    type T = stable_mir::ty::TermKind;
-
-    fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T {
-        use stable_mir::ty::TermKind;
-        match self {
-            ty::TermKind::Ty(ty) => TermKind::Type(ty.stable(tables)),
-            ty::TermKind::Const(cnst) => {
-                let cnst = cnst.stable(tables);
-                TermKind::Const(cnst)
-            }
-        }
-    }
-}
-
-impl<'tcx> Stable<'tcx> for ty::ExistentialProjection<'tcx> {
-    type T = stable_mir::ty::ExistentialProjection;
-
-    fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T {
-        let ty::ExistentialProjection { def_id, args, term } = self;
-        stable_mir::ty::ExistentialProjection {
-            def_id: tables.trait_def(*def_id),
-            generic_args: args.stable(tables),
-            term: term.unpack().stable(tables),
-        }
-    }
-}
-
-impl<'tcx> Stable<'tcx> for ty::adjustment::PointerCoercion {
-    type T = stable_mir::mir::PointerCoercion;
-    fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T {
-        use ty::adjustment::PointerCoercion;
-        match self {
-            PointerCoercion::ReifyFnPointer => stable_mir::mir::PointerCoercion::ReifyFnPointer,
-            PointerCoercion::UnsafeFnPointer => stable_mir::mir::PointerCoercion::UnsafeFnPointer,
-            PointerCoercion::ClosureFnPointer(unsafety) => {
-                stable_mir::mir::PointerCoercion::ClosureFnPointer(unsafety.stable(tables))
-            }
-            PointerCoercion::MutToConstPointer => {
-                stable_mir::mir::PointerCoercion::MutToConstPointer
-            }
-            PointerCoercion::ArrayToPointer => stable_mir::mir::PointerCoercion::ArrayToPointer,
-            PointerCoercion::Unsize => stable_mir::mir::PointerCoercion::Unsize,
-        }
-    }
-}
-
-impl<'tcx> Stable<'tcx> for rustc_hir::Unsafety {
-    type T = stable_mir::mir::Safety;
-    fn stable(&self, _: &mut Tables<'tcx>) -> Self::T {
-        match self {
-            rustc_hir::Unsafety::Unsafe => stable_mir::mir::Safety::Unsafe,
-            rustc_hir::Unsafety::Normal => stable_mir::mir::Safety::Normal,
-        }
-    }
-}
-
-impl<'tcx> Stable<'tcx> for mir::FakeReadCause {
-    type T = stable_mir::mir::FakeReadCause;
-    fn stable(&self, _: &mut Tables<'tcx>) -> Self::T {
-        use mir::FakeReadCause::*;
-        match self {
-            ForMatchGuard => stable_mir::mir::FakeReadCause::ForMatchGuard,
-            ForMatchedPlace(local_def_id) => {
-                stable_mir::mir::FakeReadCause::ForMatchedPlace(opaque(local_def_id))
-            }
-            ForGuardBinding => stable_mir::mir::FakeReadCause::ForGuardBinding,
-            ForLet(local_def_id) => stable_mir::mir::FakeReadCause::ForLet(opaque(local_def_id)),
-            ForIndex => stable_mir::mir::FakeReadCause::ForIndex,
-        }
-    }
-}
-
-impl<'tcx> Stable<'tcx> for FieldIdx {
-    type T = usize;
-    fn stable(&self, _: &mut Tables<'tcx>) -> Self::T {
-        self.as_usize()
-    }
-}
-
-impl<'tcx> Stable<'tcx> for (rustc_target::abi::VariantIdx, FieldIdx) {
-    type T = (usize, usize);
-    fn stable(&self, _: &mut Tables<'tcx>) -> Self::T {
-        (self.0.as_usize(), self.1.as_usize())
-    }
-}
-
-impl<'tcx> Stable<'tcx> for mir::Operand<'tcx> {
-    type T = stable_mir::mir::Operand;
-    fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T {
-        use mir::Operand::*;
-        match self {
-            Copy(place) => stable_mir::mir::Operand::Copy(place.stable(tables)),
-            Move(place) => stable_mir::mir::Operand::Move(place.stable(tables)),
-            Constant(c) => stable_mir::mir::Operand::Constant(c.stable(tables)),
-        }
-    }
-}
-
-impl<'tcx> Stable<'tcx> for mir::ConstOperand<'tcx> {
-    type T = stable_mir::mir::Constant;
-
-    fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T {
-        stable_mir::mir::Constant {
-            span: self.span.stable(tables),
-            user_ty: self.user_ty.map(|u| u.as_usize()).or(None),
-            literal: self.const_.stable(tables),
-        }
-    }
-}
-
-impl<'tcx> Stable<'tcx> for mir::Place<'tcx> {
-    type T = stable_mir::mir::Place;
-    fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T {
-        stable_mir::mir::Place {
-            local: self.local.as_usize(),
-            projection: self.projection.iter().map(|e| e.stable(tables)).collect(),
-        }
-    }
-}
-
-impl<'tcx> Stable<'tcx> for mir::PlaceElem<'tcx> {
-    type T = stable_mir::mir::ProjectionElem;
-    fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T {
-        use mir::ProjectionElem::*;
-        match self {
-            Deref => stable_mir::mir::ProjectionElem::Deref,
-            Field(idx, ty) => {
-                stable_mir::mir::ProjectionElem::Field(idx.stable(tables), ty.stable(tables))
-            }
-            Index(local) => stable_mir::mir::ProjectionElem::Index(local.stable(tables)),
-            ConstantIndex { offset, min_length, from_end } => {
-                stable_mir::mir::ProjectionElem::ConstantIndex {
-                    offset: *offset,
-                    min_length: *min_length,
-                    from_end: *from_end,
-                }
-            }
-            Subslice { from, to, from_end } => stable_mir::mir::ProjectionElem::Subslice {
-                from: *from,
-                to: *to,
-                from_end: *from_end,
-            },
-            // MIR includes an `Option<Symbol>` argument for `Downcast` that is the name of the
-            // variant, used for printing MIR. However this information should also be accessible
-            // via a lookup using the `VariantIdx`. The `Option<Symbol>` argument is therefore
-            // dropped when converting to Stable MIR. A brief justification for this decision can be
-            // found at https://github.com/rust-lang/rust/pull/117517#issuecomment-1811683486
-            Downcast(_, idx) => stable_mir::mir::ProjectionElem::Downcast(idx.stable(tables)),
-            OpaqueCast(ty) => stable_mir::mir::ProjectionElem::OpaqueCast(ty.stable(tables)),
-            Subtype(ty) => stable_mir::mir::ProjectionElem::Subtype(ty.stable(tables)),
-        }
-    }
-}
-
-impl<'tcx> Stable<'tcx> for mir::UserTypeProjection {
-    type T = stable_mir::mir::UserTypeProjection;
-
-    fn stable(&self, _tables: &mut Tables<'tcx>) -> Self::T {
-        UserTypeProjection { base: self.base.as_usize(), projection: opaque(&self.projs) }
-    }
-}
-
-impl<'tcx> Stable<'tcx> for mir::Local {
-    type T = stable_mir::mir::Local;
-    fn stable(&self, _: &mut Tables<'tcx>) -> Self::T {
-        self.as_usize()
-    }
-}
-
-impl<'tcx> Stable<'tcx> for rustc_target::abi::VariantIdx {
-    type T = VariantIdx;
-    fn stable(&self, _: &mut Tables<'tcx>) -> Self::T {
-        self.as_usize()
-    }
-}
-
-impl<'tcx> Stable<'tcx> for Variance {
-    type T = stable_mir::mir::Variance;
-    fn stable(&self, _: &mut Tables<'tcx>) -> Self::T {
-        match self {
-            Variance::Bivariant => stable_mir::mir::Variance::Bivariant,
-            Variance::Contravariant => stable_mir::mir::Variance::Contravariant,
-            Variance::Covariant => stable_mir::mir::Variance::Covariant,
-            Variance::Invariant => stable_mir::mir::Variance::Invariant,
-        }
-    }
-}
-
-impl<'tcx> Stable<'tcx> for mir::RetagKind {
-    type T = stable_mir::mir::RetagKind;
-    fn stable(&self, _: &mut Tables<'tcx>) -> Self::T {
-        use rustc_middle::mir::RetagKind;
-        match self {
-            RetagKind::FnEntry => stable_mir::mir::RetagKind::FnEntry,
-            RetagKind::TwoPhase => stable_mir::mir::RetagKind::TwoPhase,
-            RetagKind::Raw => stable_mir::mir::RetagKind::Raw,
-            RetagKind::Default => stable_mir::mir::RetagKind::Default,
-        }
-    }
-}
-
-impl<'tcx> Stable<'tcx> for ty::UserTypeAnnotationIndex {
-    type T = usize;
-    fn stable(&self, _: &mut Tables<'tcx>) -> Self::T {
-        self.as_usize()
-    }
-}
-
-impl<'tcx> Stable<'tcx> for mir::UnwindAction {
-    type T = stable_mir::mir::UnwindAction;
-    fn stable(&self, _: &mut Tables<'tcx>) -> Self::T {
-        use rustc_middle::mir::UnwindAction;
-        match self {
-            UnwindAction::Continue => stable_mir::mir::UnwindAction::Continue,
-            UnwindAction::Unreachable => stable_mir::mir::UnwindAction::Unreachable,
-            UnwindAction::Terminate(_) => stable_mir::mir::UnwindAction::Terminate,
-            UnwindAction::Cleanup(bb) => stable_mir::mir::UnwindAction::Cleanup(bb.as_usize()),
-        }
-    }
-}
-
-impl<'tcx> Stable<'tcx> for mir::NonDivergingIntrinsic<'tcx> {
-    type T = stable_mir::mir::NonDivergingIntrinsic;
-
-    fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T {
-        use rustc_middle::mir::NonDivergingIntrinsic;
-        match self {
-            NonDivergingIntrinsic::Assume(op) => {
-                stable_mir::mir::NonDivergingIntrinsic::Assume(op.stable(tables))
-            }
-            NonDivergingIntrinsic::CopyNonOverlapping(copy_non_overlapping) => {
-                stable_mir::mir::NonDivergingIntrinsic::CopyNonOverlapping(CopyNonOverlapping {
-                    src: copy_non_overlapping.src.stable(tables),
-                    dst: copy_non_overlapping.dst.stable(tables),
-                    count: copy_non_overlapping.count.stable(tables),
-                })
-            }
-        }
-    }
-}
-
-impl<'tcx> Stable<'tcx> for mir::AssertMessage<'tcx> {
-    type T = stable_mir::mir::AssertMessage;
-    fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T {
-        use rustc_middle::mir::AssertKind;
-        match self {
-            AssertKind::BoundsCheck { len, index } => stable_mir::mir::AssertMessage::BoundsCheck {
-                len: len.stable(tables),
-                index: index.stable(tables),
-            },
-            AssertKind::Overflow(bin_op, op1, op2) => stable_mir::mir::AssertMessage::Overflow(
-                bin_op.stable(tables),
-                op1.stable(tables),
-                op2.stable(tables),
-            ),
-            AssertKind::OverflowNeg(op) => {
-                stable_mir::mir::AssertMessage::OverflowNeg(op.stable(tables))
-            }
-            AssertKind::DivisionByZero(op) => {
-                stable_mir::mir::AssertMessage::DivisionByZero(op.stable(tables))
-            }
-            AssertKind::RemainderByZero(op) => {
-                stable_mir::mir::AssertMessage::RemainderByZero(op.stable(tables))
-            }
-            AssertKind::ResumedAfterReturn(coroutine) => {
-                stable_mir::mir::AssertMessage::ResumedAfterReturn(coroutine.stable(tables))
-            }
-            AssertKind::ResumedAfterPanic(coroutine) => {
-                stable_mir::mir::AssertMessage::ResumedAfterPanic(coroutine.stable(tables))
-            }
-            AssertKind::MisalignedPointerDereference { required, found } => {
-                stable_mir::mir::AssertMessage::MisalignedPointerDereference {
-                    required: required.stable(tables),
-                    found: found.stable(tables),
-                }
-            }
-        }
-    }
-}
-
-impl<'tcx> Stable<'tcx> for mir::BinOp {
-    type T = stable_mir::mir::BinOp;
-    fn stable(&self, _: &mut Tables<'tcx>) -> Self::T {
-        use mir::BinOp;
-        match self {
-            BinOp::Add => stable_mir::mir::BinOp::Add,
-            BinOp::AddUnchecked => stable_mir::mir::BinOp::AddUnchecked,
-            BinOp::Sub => stable_mir::mir::BinOp::Sub,
-            BinOp::SubUnchecked => stable_mir::mir::BinOp::SubUnchecked,
-            BinOp::Mul => stable_mir::mir::BinOp::Mul,
-            BinOp::MulUnchecked => stable_mir::mir::BinOp::MulUnchecked,
-            BinOp::Div => stable_mir::mir::BinOp::Div,
-            BinOp::Rem => stable_mir::mir::BinOp::Rem,
-            BinOp::BitXor => stable_mir::mir::BinOp::BitXor,
-            BinOp::BitAnd => stable_mir::mir::BinOp::BitAnd,
-            BinOp::BitOr => stable_mir::mir::BinOp::BitOr,
-            BinOp::Shl => stable_mir::mir::BinOp::Shl,
-            BinOp::ShlUnchecked => stable_mir::mir::BinOp::ShlUnchecked,
-            BinOp::Shr => stable_mir::mir::BinOp::Shr,
-            BinOp::ShrUnchecked => stable_mir::mir::BinOp::ShrUnchecked,
-            BinOp::Eq => stable_mir::mir::BinOp::Eq,
-            BinOp::Lt => stable_mir::mir::BinOp::Lt,
-            BinOp::Le => stable_mir::mir::BinOp::Le,
-            BinOp::Ne => stable_mir::mir::BinOp::Ne,
-            BinOp::Ge => stable_mir::mir::BinOp::Ge,
-            BinOp::Gt => stable_mir::mir::BinOp::Gt,
-            BinOp::Offset => stable_mir::mir::BinOp::Offset,
-        }
-    }
-}
-
-impl<'tcx> Stable<'tcx> for mir::UnOp {
-    type T = stable_mir::mir::UnOp;
-    fn stable(&self, _: &mut Tables<'tcx>) -> Self::T {
-        use mir::UnOp;
-        match self {
-            UnOp::Not => stable_mir::mir::UnOp::Not,
-            UnOp::Neg => stable_mir::mir::UnOp::Neg,
-        }
-    }
-}
-
-impl<'tcx> Stable<'tcx> for mir::AggregateKind<'tcx> {
-    type T = stable_mir::mir::AggregateKind;
-    fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T {
-        match self {
-            mir::AggregateKind::Array(ty) => {
-                stable_mir::mir::AggregateKind::Array(ty.stable(tables))
-            }
-            mir::AggregateKind::Tuple => stable_mir::mir::AggregateKind::Tuple,
-            mir::AggregateKind::Adt(def_id, var_idx, generic_arg, user_ty_index, field_idx) => {
-                stable_mir::mir::AggregateKind::Adt(
-                    tables.adt_def(*def_id),
-                    var_idx.index(),
-                    generic_arg.stable(tables),
-                    user_ty_index.map(|idx| idx.index()),
-                    field_idx.map(|idx| idx.index()),
-                )
-            }
-            mir::AggregateKind::Closure(def_id, generic_arg) => {
-                stable_mir::mir::AggregateKind::Closure(
-                    tables.closure_def(*def_id),
-                    generic_arg.stable(tables),
-                )
-            }
-            mir::AggregateKind::Coroutine(def_id, generic_arg, movability) => {
-                stable_mir::mir::AggregateKind::Coroutine(
-                    tables.coroutine_def(*def_id),
-                    generic_arg.stable(tables),
-                    movability.stable(tables),
-                )
-            }
-        }
-    }
-}
-
-impl<'tcx> Stable<'tcx> for ty::AdtKind {
-    type T = AdtKind;
-
-    fn stable(&self, _tables: &mut Tables<'tcx>) -> Self::T {
-        match self {
-            ty::AdtKind::Struct => AdtKind::Struct,
-            ty::AdtKind::Union => AdtKind::Union,
-            ty::AdtKind::Enum => AdtKind::Enum,
-        }
-    }
-}
-
-impl<'tcx> Stable<'tcx> for rustc_hir::CoroutineSource {
-    type T = stable_mir::mir::CoroutineSource;
-    fn stable(&self, _: &mut Tables<'tcx>) -> Self::T {
-        use rustc_hir::CoroutineSource;
-        match self {
-            CoroutineSource::Block => stable_mir::mir::CoroutineSource::Block,
-            CoroutineSource::Closure => stable_mir::mir::CoroutineSource::Closure,
-            CoroutineSource::Fn => stable_mir::mir::CoroutineSource::Fn,
-        }
-    }
-}
-
-impl<'tcx> Stable<'tcx> for rustc_hir::CoroutineKind {
-    type T = stable_mir::mir::CoroutineKind;
-    fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T {
-        use rustc_hir::CoroutineKind;
-        match self {
-            CoroutineKind::Async(source) => {
-                stable_mir::mir::CoroutineKind::Async(source.stable(tables))
-            }
-            CoroutineKind::Gen(source) => {
-                stable_mir::mir::CoroutineKind::Gen(source.stable(tables))
-            }
-            CoroutineKind::Coroutine => stable_mir::mir::CoroutineKind::Coroutine,
-        }
-    }
-}
-
-impl<'tcx> Stable<'tcx> for mir::InlineAsmOperand<'tcx> {
-    type T = stable_mir::mir::InlineAsmOperand;
-    fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T {
-        use rustc_middle::mir::InlineAsmOperand;
-
-        let (in_value, out_place) = match self {
-            InlineAsmOperand::In { value, .. } => (Some(value.stable(tables)), None),
-            InlineAsmOperand::Out { place, .. } => (None, place.map(|place| place.stable(tables))),
-            InlineAsmOperand::InOut { in_value, out_place, .. } => {
-                (Some(in_value.stable(tables)), out_place.map(|place| place.stable(tables)))
-            }
-            InlineAsmOperand::Const { .. }
-            | InlineAsmOperand::SymFn { .. }
-            | InlineAsmOperand::SymStatic { .. } => (None, None),
-        };
-
-        stable_mir::mir::InlineAsmOperand { in_value, out_place, raw_rpr: format!("{self:?}") }
-    }
-}
-
-impl<'tcx> Stable<'tcx> for mir::Terminator<'tcx> {
-    type T = stable_mir::mir::Terminator;
-    fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T {
-        use stable_mir::mir::Terminator;
-        Terminator { kind: self.kind.stable(tables), span: self.source_info.span.stable(tables) }
-    }
-}
-
-impl<'tcx> Stable<'tcx> for mir::TerminatorKind<'tcx> {
-    type T = stable_mir::mir::TerminatorKind;
-    fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T {
-        use stable_mir::mir::TerminatorKind;
-        match self {
-            mir::TerminatorKind::Goto { target } => {
-                TerminatorKind::Goto { target: target.as_usize() }
-            }
-            mir::TerminatorKind::SwitchInt { discr, targets } => TerminatorKind::SwitchInt {
-                discr: discr.stable(tables),
-                targets: targets
-                    .iter()
-                    .map(|(value, target)| stable_mir::mir::SwitchTarget {
-                        value,
-                        target: target.as_usize(),
-                    })
-                    .collect(),
-                otherwise: targets.otherwise().as_usize(),
-            },
-            mir::TerminatorKind::UnwindResume => TerminatorKind::Resume,
-            mir::TerminatorKind::UnwindTerminate(_) => TerminatorKind::Abort,
-            mir::TerminatorKind::Return => TerminatorKind::Return,
-            mir::TerminatorKind::Unreachable => TerminatorKind::Unreachable,
-            mir::TerminatorKind::Drop { place, target, unwind, replace: _ } => {
-                TerminatorKind::Drop {
-                    place: place.stable(tables),
-                    target: target.as_usize(),
-                    unwind: unwind.stable(tables),
-                }
-            }
-            mir::TerminatorKind::Call {
-                func,
-                args,
-                destination,
-                target,
-                unwind,
-                call_source: _,
-                fn_span: _,
-            } => TerminatorKind::Call {
-                func: func.stable(tables),
-                args: args.iter().map(|arg| arg.stable(tables)).collect(),
-                destination: destination.stable(tables),
-                target: target.map(|t| t.as_usize()),
-                unwind: unwind.stable(tables),
-            },
-            mir::TerminatorKind::Assert { cond, expected, msg, target, unwind } => {
-                TerminatorKind::Assert {
-                    cond: cond.stable(tables),
-                    expected: *expected,
-                    msg: msg.stable(tables),
-                    target: target.as_usize(),
-                    unwind: unwind.stable(tables),
-                }
-            }
-            mir::TerminatorKind::InlineAsm {
-                template,
-                operands,
-                options,
-                line_spans,
-                destination,
-                unwind,
-            } => TerminatorKind::InlineAsm {
-                template: format!("{template:?}"),
-                operands: operands.iter().map(|operand| operand.stable(tables)).collect(),
-                options: format!("{options:?}"),
-                line_spans: format!("{line_spans:?}"),
-                destination: destination.map(|d| d.as_usize()),
-                unwind: unwind.stable(tables),
-            },
-            mir::TerminatorKind::Yield { .. }
-            | mir::TerminatorKind::CoroutineDrop
-            | mir::TerminatorKind::FalseEdge { .. }
-            | mir::TerminatorKind::FalseUnwind { .. } => unreachable!(),
-        }
-    }
-}
-
-impl<'tcx> Stable<'tcx> for ty::GenericArgs<'tcx> {
-    type T = stable_mir::ty::GenericArgs;
-    fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T {
-        GenericArgs(self.iter().map(|arg| arg.unpack().stable(tables)).collect())
-    }
-}
-
-impl<'tcx> Stable<'tcx> for ty::GenericArgKind<'tcx> {
-    type T = stable_mir::ty::GenericArgKind;
-
-    fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T {
-        use stable_mir::ty::GenericArgKind;
-        match self {
-            ty::GenericArgKind::Lifetime(region) => GenericArgKind::Lifetime(region.stable(tables)),
-            ty::GenericArgKind::Type(ty) => GenericArgKind::Type(ty.stable(tables)),
-            ty::GenericArgKind::Const(cnst) => GenericArgKind::Const(cnst.stable(tables)),
-        }
-    }
-}
-
-impl<'tcx, S, V> Stable<'tcx> for ty::Binder<'tcx, S>
-where
-    S: Stable<'tcx, T = V>,
-{
-    type T = stable_mir::ty::Binder<V>;
-
-    fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T {
-        use stable_mir::ty::Binder;
-
-        Binder {
-            value: self.as_ref().skip_binder().stable(tables),
-            bound_vars: self
-                .bound_vars()
-                .iter()
-                .map(|bound_var| bound_var.stable(tables))
-                .collect(),
-        }
-    }
-}
-
-impl<'tcx, S, V> Stable<'tcx> for ty::EarlyBinder<S>
-where
-    S: Stable<'tcx, T = V>,
-{
-    type T = stable_mir::ty::EarlyBinder<V>;
-
-    fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T {
-        use stable_mir::ty::EarlyBinder;
-
-        EarlyBinder { value: self.as_ref().skip_binder().stable(tables) }
-    }
-}
-
-impl<'tcx> Stable<'tcx> for ty::FnSig<'tcx> {
-    type T = stable_mir::ty::FnSig;
-    fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T {
-        use rustc_target::spec::abi;
-        use stable_mir::ty::{Abi, FnSig};
-
-        FnSig {
-            inputs_and_output: self.inputs_and_output.iter().map(|ty| ty.stable(tables)).collect(),
-            c_variadic: self.c_variadic,
-            unsafety: self.unsafety.stable(tables),
-            abi: match self.abi {
-                abi::Abi::Rust => Abi::Rust,
-                abi::Abi::C { unwind } => Abi::C { unwind },
-                abi::Abi::Cdecl { unwind } => Abi::Cdecl { unwind },
-                abi::Abi::Stdcall { unwind } => Abi::Stdcall { unwind },
-                abi::Abi::Fastcall { unwind } => Abi::Fastcall { unwind },
-                abi::Abi::Vectorcall { unwind } => Abi::Vectorcall { unwind },
-                abi::Abi::Thiscall { unwind } => Abi::Thiscall { unwind },
-                abi::Abi::Aapcs { unwind } => Abi::Aapcs { unwind },
-                abi::Abi::Win64 { unwind } => Abi::Win64 { unwind },
-                abi::Abi::SysV64 { unwind } => Abi::SysV64 { unwind },
-                abi::Abi::PtxKernel => Abi::PtxKernel,
-                abi::Abi::Msp430Interrupt => Abi::Msp430Interrupt,
-                abi::Abi::X86Interrupt => Abi::X86Interrupt,
-                abi::Abi::AmdGpuKernel => Abi::AmdGpuKernel,
-                abi::Abi::EfiApi => Abi::EfiApi,
-                abi::Abi::AvrInterrupt => Abi::AvrInterrupt,
-                abi::Abi::AvrNonBlockingInterrupt => Abi::AvrNonBlockingInterrupt,
-                abi::Abi::CCmseNonSecureCall => Abi::CCmseNonSecureCall,
-                abi::Abi::Wasm => Abi::Wasm,
-                abi::Abi::System { unwind } => Abi::System { unwind },
-                abi::Abi::RustIntrinsic => Abi::RustIntrinsic,
-                abi::Abi::RustCall => Abi::RustCall,
-                abi::Abi::PlatformIntrinsic => Abi::PlatformIntrinsic,
-                abi::Abi::Unadjusted => Abi::Unadjusted,
-                abi::Abi::RustCold => Abi::RustCold,
-                abi::Abi::RiscvInterruptM => Abi::RiscvInterruptM,
-                abi::Abi::RiscvInterruptS => Abi::RiscvInterruptS,
-            },
-        }
-    }
-}
-
-impl<'tcx> Stable<'tcx> for ty::BoundTyKind {
-    type T = stable_mir::ty::BoundTyKind;
-
-    fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T {
-        use stable_mir::ty::BoundTyKind;
-
-        match self {
-            ty::BoundTyKind::Anon => BoundTyKind::Anon,
-            ty::BoundTyKind::Param(def_id, symbol) => {
-                BoundTyKind::Param(tables.param_def(*def_id), symbol.to_string())
-            }
-        }
-    }
-}
-
-impl<'tcx> Stable<'tcx> for ty::BoundRegionKind {
-    type T = stable_mir::ty::BoundRegionKind;
-
-    fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T {
-        use stable_mir::ty::BoundRegionKind;
-
-        match self {
-            ty::BoundRegionKind::BrAnon => BoundRegionKind::BrAnon,
-            ty::BoundRegionKind::BrNamed(def_id, symbol) => {
-                BoundRegionKind::BrNamed(tables.br_named_def(*def_id), symbol.to_string())
-            }
-            ty::BoundRegionKind::BrEnv => BoundRegionKind::BrEnv,
-        }
-    }
-}
-
-impl<'tcx> Stable<'tcx> for ty::BoundVariableKind {
-    type T = stable_mir::ty::BoundVariableKind;
-
-    fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T {
-        use stable_mir::ty::BoundVariableKind;
-
-        match self {
-            ty::BoundVariableKind::Ty(bound_ty_kind) => {
-                BoundVariableKind::Ty(bound_ty_kind.stable(tables))
-            }
-            ty::BoundVariableKind::Region(bound_region_kind) => {
-                BoundVariableKind::Region(bound_region_kind.stable(tables))
-            }
-            ty::BoundVariableKind::Const => BoundVariableKind::Const,
-        }
-    }
-}
-
-impl<'tcx> Stable<'tcx> for ty::IntTy {
-    type T = IntTy;
-
-    fn stable(&self, _: &mut Tables<'tcx>) -> Self::T {
-        match self {
-            ty::IntTy::Isize => IntTy::Isize,
-            ty::IntTy::I8 => IntTy::I8,
-            ty::IntTy::I16 => IntTy::I16,
-            ty::IntTy::I32 => IntTy::I32,
-            ty::IntTy::I64 => IntTy::I64,
-            ty::IntTy::I128 => IntTy::I128,
-        }
-    }
-}
-
-impl<'tcx> Stable<'tcx> for ty::UintTy {
-    type T = UintTy;
-
-    fn stable(&self, _: &mut Tables<'tcx>) -> Self::T {
-        match self {
-            ty::UintTy::Usize => UintTy::Usize,
-            ty::UintTy::U8 => UintTy::U8,
-            ty::UintTy::U16 => UintTy::U16,
-            ty::UintTy::U32 => UintTy::U32,
-            ty::UintTy::U64 => UintTy::U64,
-            ty::UintTy::U128 => UintTy::U128,
-        }
-    }
-}
-
-impl<'tcx> Stable<'tcx> for ty::FloatTy {
-    type T = FloatTy;
-
-    fn stable(&self, _: &mut Tables<'tcx>) -> Self::T {
-        match self {
-            ty::FloatTy::F32 => FloatTy::F32,
-            ty::FloatTy::F64 => FloatTy::F64,
-        }
-    }
-}
-
-impl<'tcx> Stable<'tcx> for hir::Movability {
-    type T = Movability;
-
-    fn stable(&self, _: &mut Tables<'tcx>) -> Self::T {
-        match self {
-            hir::Movability::Static => Movability::Static,
-            hir::Movability::Movable => Movability::Movable,
-        }
-    }
-}
-
-impl<'tcx> Stable<'tcx> for Ty<'tcx> {
-    type T = stable_mir::ty::Ty;
-    fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T {
-        tables.intern_ty(*self)
-    }
-}
-
-impl<'tcx> Stable<'tcx> for ty::TyKind<'tcx> {
-    type T = stable_mir::ty::TyKind;
-    fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T {
-        match self {
-            ty::Bool => TyKind::RigidTy(RigidTy::Bool),
-            ty::Char => TyKind::RigidTy(RigidTy::Char),
-            ty::Int(int_ty) => TyKind::RigidTy(RigidTy::Int(int_ty.stable(tables))),
-            ty::Uint(uint_ty) => TyKind::RigidTy(RigidTy::Uint(uint_ty.stable(tables))),
-            ty::Float(float_ty) => TyKind::RigidTy(RigidTy::Float(float_ty.stable(tables))),
-            ty::Adt(adt_def, generic_args) => TyKind::RigidTy(RigidTy::Adt(
-                tables.adt_def(adt_def.did()),
-                generic_args.stable(tables),
-            )),
-            ty::Foreign(def_id) => TyKind::RigidTy(RigidTy::Foreign(tables.foreign_def(*def_id))),
-            ty::Str => TyKind::RigidTy(RigidTy::Str),
-            ty::Array(ty, constant) => {
-                TyKind::RigidTy(RigidTy::Array(ty.stable(tables), constant.stable(tables)))
-            }
-            ty::Slice(ty) => TyKind::RigidTy(RigidTy::Slice(ty.stable(tables))),
-            ty::RawPtr(ty::TypeAndMut { ty, mutbl }) => {
-                TyKind::RigidTy(RigidTy::RawPtr(ty.stable(tables), mutbl.stable(tables)))
-            }
-            ty::Ref(region, ty, mutbl) => TyKind::RigidTy(RigidTy::Ref(
-                region.stable(tables),
-                ty.stable(tables),
-                mutbl.stable(tables),
-            )),
-            ty::FnDef(def_id, generic_args) => {
-                TyKind::RigidTy(RigidTy::FnDef(tables.fn_def(*def_id), generic_args.stable(tables)))
-            }
-            ty::FnPtr(poly_fn_sig) => TyKind::RigidTy(RigidTy::FnPtr(poly_fn_sig.stable(tables))),
-            ty::Dynamic(existential_predicates, region, dyn_kind) => {
-                TyKind::RigidTy(RigidTy::Dynamic(
-                    existential_predicates
-                        .iter()
-                        .map(|existential_predicate| existential_predicate.stable(tables))
-                        .collect(),
-                    region.stable(tables),
-                    dyn_kind.stable(tables),
-                ))
-            }
-            ty::Closure(def_id, generic_args) => TyKind::RigidTy(RigidTy::Closure(
-                tables.closure_def(*def_id),
-                generic_args.stable(tables),
-            )),
-            ty::Coroutine(def_id, generic_args, movability) => TyKind::RigidTy(RigidTy::Coroutine(
-                tables.coroutine_def(*def_id),
-                generic_args.stable(tables),
-                movability.stable(tables),
-            )),
-            ty::Never => TyKind::RigidTy(RigidTy::Never),
-            ty::Tuple(fields) => {
-                TyKind::RigidTy(RigidTy::Tuple(fields.iter().map(|ty| ty.stable(tables)).collect()))
-            }
-            ty::Alias(alias_kind, alias_ty) => {
-                TyKind::Alias(alias_kind.stable(tables), alias_ty.stable(tables))
-            }
-            ty::Param(param_ty) => TyKind::Param(param_ty.stable(tables)),
-            ty::Bound(debruijn_idx, bound_ty) => {
-                TyKind::Bound(debruijn_idx.as_usize(), bound_ty.stable(tables))
-            }
-            ty::CoroutineWitness(def_id, args) => TyKind::RigidTy(RigidTy::CoroutineWitness(
-                tables.coroutine_witness_def(*def_id),
-                args.stable(tables),
-            )),
-            ty::Placeholder(..) | ty::Infer(_) | ty::Error(_) => {
-                unreachable!();
-            }
-        }
-    }
-}
-
-impl<'tcx> Stable<'tcx> for ty::Const<'tcx> {
-    type T = stable_mir::ty::Const;
-
-    fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T {
-        let kind = match self.kind() {
-            ty::Value(val) => {
-                let const_val = tables.tcx.valtree_to_const_val((self.ty(), val));
-                if matches!(const_val, mir::ConstValue::ZeroSized) {
-                    ConstantKind::ZeroSized
-                } else {
-                    stable_mir::ty::ConstantKind::Allocated(alloc::new_allocation(
-                        self.ty(),
-                        const_val,
-                        tables,
-                    ))
-                }
-            }
-            ty::ParamCt(param) => stable_mir::ty::ConstantKind::Param(param.stable(tables)),
-            ty::ErrorCt(_) => unreachable!(),
-            ty::InferCt(_) => unreachable!(),
-            ty::BoundCt(_, _) => unimplemented!(),
-            ty::PlaceholderCt(_) => unimplemented!(),
-            ty::Unevaluated(uv) => {
-                stable_mir::ty::ConstantKind::Unevaluated(stable_mir::ty::UnevaluatedConst {
-                    def: tables.const_def(uv.def),
-                    args: uv.args.stable(tables),
-                    promoted: None,
-                })
-            }
-            ty::ExprCt(_) => unimplemented!(),
-        };
-        let ty = self.ty().stable(tables);
-        let id = tables.intern_const(mir::Const::Ty(*self));
-        Const::new(kind, ty, id)
-    }
-}
-
-impl<'tcx> Stable<'tcx> for ty::ParamConst {
-    type T = stable_mir::ty::ParamConst;
-    fn stable(&self, _: &mut Tables<'tcx>) -> Self::T {
-        use stable_mir::ty::ParamConst;
-        ParamConst { index: self.index, name: self.name.to_string() }
-    }
-}
-
-impl<'tcx> Stable<'tcx> for ty::ParamTy {
-    type T = stable_mir::ty::ParamTy;
-    fn stable(&self, _: &mut Tables<'tcx>) -> Self::T {
-        use stable_mir::ty::ParamTy;
-        ParamTy { index: self.index, name: self.name.to_string() }
-    }
-}
-
-impl<'tcx> Stable<'tcx> for ty::BoundTy {
-    type T = stable_mir::ty::BoundTy;
-    fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T {
-        use stable_mir::ty::BoundTy;
-        BoundTy { var: self.var.as_usize(), kind: self.kind.stable(tables) }
-    }
-}
-
-impl<'tcx> Stable<'tcx> for mir::interpret::ConstAllocation<'tcx> {
-    type T = Allocation;
-
-    fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T {
-        self.inner().stable(tables)
-    }
-}
-
-impl<'tcx> Stable<'tcx> for mir::interpret::Allocation {
-    type T = stable_mir::ty::Allocation;
-
-    fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T {
-        alloc::allocation_filter(
-            self,
-            alloc_range(rustc_target::abi::Size::ZERO, self.size()),
-            tables,
-        )
-    }
-}
-
-impl<'tcx> Stable<'tcx> for mir::interpret::AllocId {
-    type T = stable_mir::mir::alloc::AllocId;
-    fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T {
-        tables.create_alloc_id(*self)
-    }
-}
-
-impl<'tcx> Stable<'tcx> for mir::interpret::GlobalAlloc<'tcx> {
-    type T = GlobalAlloc;
-
-    fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T {
-        match self {
-            mir::interpret::GlobalAlloc::Function(instance) => {
-                GlobalAlloc::Function(instance.stable(tables))
-            }
-            mir::interpret::GlobalAlloc::VTable(ty, trait_ref) => {
-                GlobalAlloc::VTable(ty.stable(tables), trait_ref.stable(tables))
-            }
-            mir::interpret::GlobalAlloc::Static(def) => {
-                GlobalAlloc::Static(tables.static_def(*def))
-            }
-            mir::interpret::GlobalAlloc::Memory(alloc) => GlobalAlloc::Memory(alloc.stable(tables)),
-        }
-    }
-}
-
-impl<'tcx> Stable<'tcx> for ty::trait_def::TraitSpecializationKind {
-    type T = stable_mir::ty::TraitSpecializationKind;
-    fn stable(&self, _: &mut Tables<'tcx>) -> Self::T {
-        use stable_mir::ty::TraitSpecializationKind;
-
-        match self {
-            ty::trait_def::TraitSpecializationKind::None => TraitSpecializationKind::None,
-            ty::trait_def::TraitSpecializationKind::Marker => TraitSpecializationKind::Marker,
-            ty::trait_def::TraitSpecializationKind::AlwaysApplicable => {
-                TraitSpecializationKind::AlwaysApplicable
-            }
-        }
-    }
-}
-
-impl<'tcx> Stable<'tcx> for ty::TraitDef {
-    type T = stable_mir::ty::TraitDecl;
-    fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T {
-        use stable_mir::ty::TraitDecl;
-
-        TraitDecl {
-            def_id: tables.trait_def(self.def_id),
-            unsafety: self.unsafety.stable(tables),
-            paren_sugar: self.paren_sugar,
-            has_auto_impl: self.has_auto_impl,
-            is_marker: self.is_marker,
-            is_coinductive: self.is_coinductive,
-            skip_array_during_method_dispatch: self.skip_array_during_method_dispatch,
-            specialization_kind: self.specialization_kind.stable(tables),
-            must_implement_one_of: self
-                .must_implement_one_of
-                .as_ref()
-                .map(|idents| idents.iter().map(|ident| opaque(ident)).collect()),
-            implement_via_object: self.implement_via_object,
-            deny_explicit_impl: self.deny_explicit_impl,
-        }
-    }
-}
-
-impl<'tcx> Stable<'tcx> for rustc_middle::mir::Const<'tcx> {
-    type T = stable_mir::ty::Const;
-
-    fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T {
-        match *self {
-            mir::Const::Ty(c) => c.stable(tables),
-            mir::Const::Unevaluated(unev_const, ty) => {
-                let kind =
-                    stable_mir::ty::ConstantKind::Unevaluated(stable_mir::ty::UnevaluatedConst {
-                        def: tables.const_def(unev_const.def),
-                        args: unev_const.args.stable(tables),
-                        promoted: unev_const.promoted.map(|u| u.as_u32()),
-                    });
-                let ty = ty.stable(tables);
-                let id = tables.intern_const(*self);
-                Const::new(kind, ty, id)
-            }
-            mir::Const::Val(val, ty) if matches!(val, mir::ConstValue::ZeroSized) => {
-                let ty = ty.stable(tables);
-                let id = tables.intern_const(*self);
-                Const::new(ConstantKind::ZeroSized, ty, id)
-            }
-            mir::Const::Val(val, ty) => {
-                let kind = ConstantKind::Allocated(alloc::new_allocation(ty, val, tables));
-                let ty = ty.stable(tables);
-                let id = tables.intern_const(*self);
-                Const::new(kind, ty, id)
-            }
-        }
-    }
-}
-
-impl<'tcx> Stable<'tcx> for ty::TraitRef<'tcx> {
-    type T = stable_mir::ty::TraitRef;
-    fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T {
-        use stable_mir::ty::TraitRef;
-
-        TraitRef::try_new(tables.trait_def(self.def_id), self.args.stable(tables)).unwrap()
-    }
-}
-
-impl<'tcx> Stable<'tcx> for ty::Generics {
-    type T = stable_mir::ty::Generics;
-
-    fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T {
-        use stable_mir::ty::Generics;
-
-        let params: Vec<_> = self.params.iter().map(|param| param.stable(tables)).collect();
-        let param_def_id_to_index =
-            params.iter().map(|param| (param.def_id, param.index)).collect();
-
-        Generics {
-            parent: self.parent.map(|did| tables.generic_def(did)),
-            parent_count: self.parent_count,
-            params,
-            param_def_id_to_index,
-            has_self: self.has_self,
-            has_late_bound_regions: self
-                .has_late_bound_regions
-                .as_ref()
-                .map(|late_bound_regions| late_bound_regions.stable(tables)),
-            host_effect_index: self.host_effect_index,
-        }
-    }
-}
-
-impl<'tcx> Stable<'tcx> for rustc_middle::ty::GenericParamDefKind {
-    type T = stable_mir::ty::GenericParamDefKind;
-
-    fn stable(&self, _: &mut Tables<'tcx>) -> Self::T {
-        use stable_mir::ty::GenericParamDefKind;
-        match self {
-            ty::GenericParamDefKind::Lifetime => GenericParamDefKind::Lifetime,
-            ty::GenericParamDefKind::Type { has_default, synthetic } => {
-                GenericParamDefKind::Type { has_default: *has_default, synthetic: *synthetic }
-            }
-            ty::GenericParamDefKind::Const { has_default, is_host_effect: _ } => {
-                GenericParamDefKind::Const { has_default: *has_default }
-            }
-        }
-    }
-}
-
-impl<'tcx> Stable<'tcx> for rustc_middle::ty::GenericParamDef {
-    type T = stable_mir::ty::GenericParamDef;
-
-    fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T {
-        GenericParamDef {
-            name: self.name.to_string(),
-            def_id: tables.generic_def(self.def_id),
-            index: self.index,
-            pure_wrt_drop: self.pure_wrt_drop,
-            kind: self.kind.stable(tables),
-        }
-    }
-}
-
-impl<'tcx> Stable<'tcx> for ty::PredicateKind<'tcx> {
-    type T = stable_mir::ty::PredicateKind;
-
-    fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T {
-        use ty::PredicateKind;
-        match self {
-            PredicateKind::Clause(clause_kind) => {
-                stable_mir::ty::PredicateKind::Clause(clause_kind.stable(tables))
-            }
-            PredicateKind::ObjectSafe(did) => {
-                stable_mir::ty::PredicateKind::ObjectSafe(tables.trait_def(*did))
-            }
-            PredicateKind::Subtype(subtype_predicate) => {
-                stable_mir::ty::PredicateKind::SubType(subtype_predicate.stable(tables))
-            }
-            PredicateKind::Coerce(coerce_predicate) => {
-                stable_mir::ty::PredicateKind::Coerce(coerce_predicate.stable(tables))
-            }
-            PredicateKind::ConstEquate(a, b) => {
-                stable_mir::ty::PredicateKind::ConstEquate(a.stable(tables), b.stable(tables))
-            }
-            PredicateKind::Ambiguous => stable_mir::ty::PredicateKind::Ambiguous,
-            PredicateKind::AliasRelate(a, b, alias_relation_direction) => {
-                stable_mir::ty::PredicateKind::AliasRelate(
-                    a.unpack().stable(tables),
-                    b.unpack().stable(tables),
-                    alias_relation_direction.stable(tables),
-                )
-            }
-        }
-    }
-}
-
-impl<'tcx> Stable<'tcx> for ty::ClauseKind<'tcx> {
-    type T = stable_mir::ty::ClauseKind;
-
-    fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T {
-        use ty::ClauseKind;
-        match *self {
-            ClauseKind::Trait(trait_object) => {
-                stable_mir::ty::ClauseKind::Trait(trait_object.stable(tables))
-            }
-            ClauseKind::RegionOutlives(region_outlives) => {
-                stable_mir::ty::ClauseKind::RegionOutlives(region_outlives.stable(tables))
-            }
-            ClauseKind::TypeOutlives(type_outlives) => {
-                let ty::OutlivesPredicate::<_, _>(a, b) = type_outlives;
-                stable_mir::ty::ClauseKind::TypeOutlives(stable_mir::ty::OutlivesPredicate(
-                    a.stable(tables),
-                    b.stable(tables),
-                ))
-            }
-            ClauseKind::Projection(projection_predicate) => {
-                stable_mir::ty::ClauseKind::Projection(projection_predicate.stable(tables))
-            }
-            ClauseKind::ConstArgHasType(const_, ty) => stable_mir::ty::ClauseKind::ConstArgHasType(
-                const_.stable(tables),
-                ty.stable(tables),
-            ),
-            ClauseKind::WellFormed(generic_arg) => {
-                stable_mir::ty::ClauseKind::WellFormed(generic_arg.unpack().stable(tables))
-            }
-            ClauseKind::ConstEvaluatable(const_) => {
-                stable_mir::ty::ClauseKind::ConstEvaluatable(const_.stable(tables))
-            }
-        }
-    }
-}
-
-impl<'tcx> Stable<'tcx> for ty::ClosureKind {
-    type T = stable_mir::ty::ClosureKind;
-
-    fn stable(&self, _: &mut Tables<'tcx>) -> Self::T {
-        use ty::ClosureKind::*;
-        match self {
-            Fn => stable_mir::ty::ClosureKind::Fn,
-            FnMut => stable_mir::ty::ClosureKind::FnMut,
-            FnOnce => stable_mir::ty::ClosureKind::FnOnce,
-        }
-    }
-}
-
-impl<'tcx> Stable<'tcx> for ty::SubtypePredicate<'tcx> {
-    type T = stable_mir::ty::SubtypePredicate;
-
-    fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T {
-        let ty::SubtypePredicate { a, b, a_is_expected: _ } = self;
-        stable_mir::ty::SubtypePredicate { a: a.stable(tables), b: b.stable(tables) }
-    }
-}
-
-impl<'tcx> Stable<'tcx> for ty::CoercePredicate<'tcx> {
-    type T = stable_mir::ty::CoercePredicate;
-
-    fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T {
-        let ty::CoercePredicate { a, b } = self;
-        stable_mir::ty::CoercePredicate { a: a.stable(tables), b: b.stable(tables) }
-    }
-}
-
-impl<'tcx> Stable<'tcx> for ty::AliasRelationDirection {
-    type T = stable_mir::ty::AliasRelationDirection;
-
-    fn stable(&self, _: &mut Tables<'tcx>) -> Self::T {
-        use ty::AliasRelationDirection::*;
-        match self {
-            Equate => stable_mir::ty::AliasRelationDirection::Equate,
-            Subtype => stable_mir::ty::AliasRelationDirection::Subtype,
-        }
-    }
-}
-
-impl<'tcx> Stable<'tcx> for ty::TraitPredicate<'tcx> {
-    type T = stable_mir::ty::TraitPredicate;
-
-    fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T {
-        let ty::TraitPredicate { trait_ref, polarity } = self;
-        stable_mir::ty::TraitPredicate {
-            trait_ref: trait_ref.stable(tables),
-            polarity: polarity.stable(tables),
-        }
-    }
-}
-
-impl<'tcx, A, B, U, V> Stable<'tcx> for ty::OutlivesPredicate<A, B>
-where
-    A: Stable<'tcx, T = U>,
-    B: Stable<'tcx, T = V>,
-{
-    type T = stable_mir::ty::OutlivesPredicate<U, V>;
-
-    fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T {
-        let ty::OutlivesPredicate(a, b) = self;
-        stable_mir::ty::OutlivesPredicate(a.stable(tables), b.stable(tables))
-    }
-}
-
-impl<'tcx> Stable<'tcx> for ty::ProjectionPredicate<'tcx> {
-    type T = stable_mir::ty::ProjectionPredicate;
-
-    fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T {
-        let ty::ProjectionPredicate { projection_ty, term } = self;
-        stable_mir::ty::ProjectionPredicate {
-            projection_ty: projection_ty.stable(tables),
-            term: term.unpack().stable(tables),
-        }
-    }
-}
-
-impl<'tcx> Stable<'tcx> for ty::ImplPolarity {
-    type T = stable_mir::ty::ImplPolarity;
-
-    fn stable(&self, _: &mut Tables<'tcx>) -> Self::T {
-        use ty::ImplPolarity::*;
-        match self {
-            Positive => stable_mir::ty::ImplPolarity::Positive,
-            Negative => stable_mir::ty::ImplPolarity::Negative,
-            Reservation => stable_mir::ty::ImplPolarity::Reservation,
-        }
-    }
-}
-
-impl<'tcx> Stable<'tcx> for ty::Region<'tcx> {
-    type T = stable_mir::ty::Region;
-
-    fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T {
-        Region { kind: self.kind().stable(tables) }
-    }
-}
-
-impl<'tcx> Stable<'tcx> for ty::RegionKind<'tcx> {
-    type T = stable_mir::ty::RegionKind;
-
-    fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T {
-        use stable_mir::ty::RegionKind;
-        match self {
-            ty::ReEarlyParam(early_reg) => RegionKind::ReEarlyParam(EarlyParamRegion {
-                def_id: tables.region_def(early_reg.def_id),
-                index: early_reg.index,
-                name: early_reg.name.to_string(),
-            }),
-            ty::ReBound(db_index, bound_reg) => RegionKind::ReBound(
-                db_index.as_u32(),
-                BoundRegion { var: bound_reg.var.as_u32(), kind: bound_reg.kind.stable(tables) },
-            ),
-            ty::ReStatic => RegionKind::ReStatic,
-            ty::RePlaceholder(place_holder) => {
-                RegionKind::RePlaceholder(stable_mir::ty::Placeholder {
-                    universe: place_holder.universe.as_u32(),
-                    bound: BoundRegion {
-                        var: place_holder.bound.var.as_u32(),
-                        kind: place_holder.bound.kind.stable(tables),
-                    },
-                })
-            }
-            ty::ReErased => RegionKind::ReErased,
-            _ => unreachable!("{self:?}"),
-        }
-    }
-}
-
-impl<'tcx> Stable<'tcx> for rustc_span::Span {
-    type T = stable_mir::ty::Span;
-
-    fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T {
-        tables.create_span(*self)
-    }
-}
-
-impl<'tcx> Stable<'tcx> for ty::Instance<'tcx> {
-    type T = stable_mir::mir::mono::Instance;
-
-    fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T {
-        let def = tables.instance_def(*self);
-        let kind = match self.def {
-            ty::InstanceDef::Item(..) => stable_mir::mir::mono::InstanceKind::Item,
-            ty::InstanceDef::Intrinsic(..) => stable_mir::mir::mono::InstanceKind::Intrinsic,
-            ty::InstanceDef::Virtual(..) => stable_mir::mir::mono::InstanceKind::Virtual,
-            ty::InstanceDef::VTableShim(..)
-            | ty::InstanceDef::ReifyShim(..)
-            | ty::InstanceDef::FnPtrAddrShim(..)
-            | ty::InstanceDef::ClosureOnceShim { .. }
-            | ty::InstanceDef::ThreadLocalShim(..)
-            | ty::InstanceDef::DropGlue(..)
-            | ty::InstanceDef::CloneShim(..)
-            | ty::InstanceDef::FnPtrShim(..) => stable_mir::mir::mono::InstanceKind::Shim,
-        };
-        stable_mir::mir::mono::Instance { def, kind }
-    }
-}
-
-impl<'tcx> Stable<'tcx> for MonoItem<'tcx> {
-    type T = stable_mir::mir::mono::MonoItem;
-
-    fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T {
-        use stable_mir::mir::mono::MonoItem as StableMonoItem;
-        match self {
-            MonoItem::Fn(instance) => StableMonoItem::Fn(instance.stable(tables)),
-            MonoItem::Static(def_id) => StableMonoItem::Static(tables.static_def(*def_id)),
-            MonoItem::GlobalAsm(item_id) => StableMonoItem::GlobalAsm(opaque(item_id)),
-        }
-    }
-}
-
-impl<'tcx> Stable<'tcx> for mir::interpret::ErrorHandled {
-    type T = Error;
-
-    fn stable(&self, _tables: &mut Tables<'tcx>) -> Self::T {
-        Error::new(format!("{self:?}"))
-    }
-}
-
 impl<'tcx, T> Stable<'tcx> for &T
 where
     T: Stable<'tcx>,
diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs
index ae7f6ca2f7a..da2f16e9760 100644
--- a/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs
+++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs
@@ -18,6 +18,7 @@ use rustc_index::IndexVec;
 use rustc_infer::infer::canonical::query_response::make_query_region_constraints;
 use rustc_infer::infer::canonical::CanonicalVarValues;
 use rustc_infer::infer::canonical::{CanonicalExt, QueryRegionConstraints};
+use rustc_infer::infer::resolve::EagerResolver;
 use rustc_infer::infer::{DefineOpaqueTypes, InferCtxt, InferOk};
 use rustc_middle::infer::canonical::Canonical;
 use rustc_middle::traits::query::NoSolution;
@@ -25,10 +26,7 @@ use rustc_middle::traits::solve::{
     ExternalConstraintsData, MaybeCause, PredefinedOpaquesData, QueryInput,
 };
 use rustc_middle::traits::ObligationCause;
-use rustc_middle::ty::{
-    self, BoundVar, GenericArgKind, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable,
-    TypeVisitableExt,
-};
+use rustc_middle::ty::{self, BoundVar, GenericArgKind, Ty, TyCtxt, TypeFoldable};
 use rustc_span::DUMMY_SP;
 use std::iter;
 use std::ops::Deref;
@@ -58,7 +56,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
     ) -> (Vec<ty::GenericArg<'tcx>>, CanonicalInput<'tcx, T>) {
         let opaque_types = self.infcx.clone_opaque_types_for_query_response();
         let (goal, opaque_types) =
-            (goal, opaque_types).fold_with(&mut EagerResolver { infcx: self.infcx });
+            (goal, opaque_types).fold_with(&mut EagerResolver::new(self.infcx));
 
         let mut orig_values = Default::default();
         let canonical_goal = Canonicalizer::canonicalize(
@@ -115,7 +113,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
         let external_constraints = self.compute_external_query_constraints()?;
 
         let (var_values, mut external_constraints) =
-            (var_values, external_constraints).fold_with(&mut EagerResolver { infcx: self.infcx });
+            (var_values, external_constraints).fold_with(&mut EagerResolver::new(self.infcx));
         // Remove any trivial region constraints once we've resolved regions
         external_constraints
             .region_constraints
@@ -364,86 +362,13 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
     }
 }
 
-/// Resolves ty, region, and const vars to their inferred values or their root vars.
-struct EagerResolver<'a, 'tcx> {
-    infcx: &'a InferCtxt<'tcx>,
-}
-
-impl<'tcx> TypeFolder<TyCtxt<'tcx>> for EagerResolver<'_, 'tcx> {
-    fn interner(&self) -> TyCtxt<'tcx> {
-        self.infcx.tcx
-    }
-
-    fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
-        match *t.kind() {
-            ty::Infer(ty::TyVar(vid)) => match self.infcx.probe_ty_var(vid) {
-                Ok(t) => t.fold_with(self),
-                Err(_) => Ty::new_var(self.infcx.tcx, self.infcx.root_var(vid)),
-            },
-            ty::Infer(ty::IntVar(vid)) => self.infcx.opportunistic_resolve_int_var(vid),
-            ty::Infer(ty::FloatVar(vid)) => self.infcx.opportunistic_resolve_float_var(vid),
-            _ => {
-                if t.has_infer() {
-                    t.super_fold_with(self)
-                } else {
-                    t
-                }
-            }
-        }
-    }
-
-    fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
-        match *r {
-            ty::ReVar(vid) => self
-                .infcx
-                .inner
-                .borrow_mut()
-                .unwrap_region_constraints()
-                .opportunistic_resolve_var(self.infcx.tcx, vid),
-            _ => r,
-        }
-    }
-
-    fn fold_const(&mut self, c: ty::Const<'tcx>) -> ty::Const<'tcx> {
-        match c.kind() {
-            ty::ConstKind::Infer(ty::InferConst::Var(vid)) => {
-                // FIXME: we need to fold the ty too, I think.
-                match self.infcx.probe_const_var(vid) {
-                    Ok(c) => c.fold_with(self),
-                    Err(_) => {
-                        ty::Const::new_var(self.infcx.tcx, self.infcx.root_const_var(vid), c.ty())
-                    }
-                }
-            }
-            ty::ConstKind::Infer(ty::InferConst::EffectVar(vid)) => {
-                debug_assert_eq!(c.ty(), self.infcx.tcx.types.bool);
-                match self.infcx.probe_effect_var(vid) {
-                    Some(c) => c.as_const(self.infcx.tcx),
-                    None => ty::Const::new_infer(
-                        self.infcx.tcx,
-                        ty::InferConst::EffectVar(self.infcx.root_effect_var(vid)),
-                        self.infcx.tcx.types.bool,
-                    ),
-                }
-            }
-            _ => {
-                if c.has_infer() {
-                    c.super_fold_with(self)
-                } else {
-                    c
-                }
-            }
-        }
-    }
-}
-
 impl<'tcx> inspect::ProofTreeBuilder<'tcx> {
     pub fn make_canonical_state<T: TypeFoldable<TyCtxt<'tcx>>>(
         ecx: &EvalCtxt<'_, 'tcx>,
         data: T,
     ) -> inspect::CanonicalState<'tcx, T> {
         let state = inspect::State { var_values: ecx.var_values, data };
-        let state = state.fold_with(&mut EagerResolver { infcx: ecx.infcx });
+        let state = state.fold_with(&mut EagerResolver::new(ecx.infcx));
         Canonicalizer::canonicalize(
             ecx.infcx,
             CanonicalizeMode::Response { max_input_universe: ecx.max_input_universe },
diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs
index 06f65e414da..8f5afdf0a1f 100644
--- a/compiler/rustc_trait_selection/src/traits/project.rs
+++ b/compiler/rustc_trait_selection/src/traits/project.rs
@@ -1001,7 +1001,7 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for PlaceholderReplacer<'_, 'tcx> {
         &mut self,
         t: ty::Binder<'tcx, T>,
     ) -> ty::Binder<'tcx, T> {
-        if !t.has_placeholders() && !t.has_infer_regions() {
+        if !t.has_placeholders() && !t.has_infer() {
             return t;
         }
         self.current_index.shift_in(1);
@@ -1048,6 +1048,7 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for PlaceholderReplacer<'_, 'tcx> {
     }
 
     fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
+        let ty = self.infcx.shallow_resolve(ty);
         match *ty.kind() {
             ty::Placeholder(p) => {
                 let replace_var = self.mapped_types.get(&p);
@@ -1063,16 +1064,23 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for PlaceholderReplacer<'_, 'tcx> {
                         );
                         Ty::new_bound(self.infcx.tcx, db, *replace_var)
                     }
-                    None => ty,
+                    None => {
+                        if ty.has_infer() {
+                            ty.super_fold_with(self)
+                        } else {
+                            ty
+                        }
+                    }
                 }
             }
 
-            _ if ty.has_placeholders() || ty.has_infer_regions() => ty.super_fold_with(self),
+            _ if ty.has_placeholders() || ty.has_infer() => ty.super_fold_with(self),
             _ => ty,
         }
     }
 
     fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> {
+        let ct = self.infcx.shallow_resolve(ct);
         if let ty::ConstKind::Placeholder(p) = ct.kind() {
             let replace_var = self.mapped_consts.get(&p);
             match replace_var {
@@ -1087,7 +1095,13 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for PlaceholderReplacer<'_, 'tcx> {
                     );
                     ty::Const::new_bound(self.infcx.tcx, db, *replace_var, ct.ty())
                 }
-                None => ct,
+                None => {
+                    if ct.has_infer() {
+                        ct.super_fold_with(self)
+                    } else {
+                        ct
+                    }
+                }
             }
         } else {
             ct.super_fold_with(self)
diff --git a/compiler/stable_mir/src/compiler_interface.rs b/compiler/stable_mir/src/compiler_interface.rs
new file mode 100644
index 00000000000..827418a6432
--- /dev/null
+++ b/compiler/stable_mir/src/compiler_interface.rs
@@ -0,0 +1,164 @@
+//! Define the interface with the Rust compiler.
+//!
+//! StableMIR users should not use any of the items in this module directly.
+//! These APIs have no stability guarantee.
+
+use std::cell::Cell;
+
+use crate::mir::alloc::{AllocId, GlobalAlloc};
+use crate::mir::mono::{Instance, InstanceDef, StaticDef};
+use crate::mir::Body;
+use crate::ty::{
+    AdtDef, AdtKind, Allocation, ClosureDef, ClosureKind, Const, FnDef, GenericArgs,
+    GenericPredicates, Generics, ImplDef, ImplTrait, LineInfo, RigidTy, Span, TraitDecl, TraitDef,
+    Ty, TyKind,
+};
+use crate::{
+    mir, Crate, CrateItem, CrateItems, DefId, Error, Filename, ImplTraitDecls, ItemKind, Symbol,
+    TraitDecls,
+};
+
+/// This trait defines the interface between stable_mir and the Rust compiler.
+/// Do not use this directly.
+pub trait Context {
+    fn entry_fn(&self) -> Option<CrateItem>;
+    /// Retrieve all items of the local crate that have a MIR associated with them.
+    fn all_local_items(&self) -> CrateItems;
+    fn mir_body(&self, item: DefId) -> mir::Body;
+    fn all_trait_decls(&self) -> TraitDecls;
+    fn trait_decl(&self, trait_def: &TraitDef) -> TraitDecl;
+    fn all_trait_impls(&self) -> ImplTraitDecls;
+    fn trait_impl(&self, trait_impl: &ImplDef) -> ImplTrait;
+    fn generics_of(&self, def_id: DefId) -> Generics;
+    fn predicates_of(&self, def_id: DefId) -> GenericPredicates;
+    fn explicit_predicates_of(&self, def_id: DefId) -> GenericPredicates;
+    /// Get information about the local crate.
+    fn local_crate(&self) -> Crate;
+    /// Retrieve a list of all external crates.
+    fn external_crates(&self) -> Vec<Crate>;
+
+    /// Find a crate with the given name.
+    fn find_crates(&self, name: &str) -> Vec<Crate>;
+
+    /// Returns the name of given `DefId`
+    fn def_name(&self, def_id: DefId, trimmed: bool) -> Symbol;
+
+    /// Returns printable, human readable form of `Span`
+    fn span_to_string(&self, span: Span) -> String;
+
+    /// Return filename from given `Span`, for diagnostic purposes
+    fn get_filename(&self, span: &Span) -> Filename;
+
+    /// Return lines corresponding to this `Span`
+    fn get_lines(&self, span: &Span) -> LineInfo;
+
+    /// Returns the `kind` of given `DefId`
+    fn item_kind(&self, item: CrateItem) -> ItemKind;
+
+    /// Returns whether this is a foreign item.
+    fn is_foreign_item(&self, item: CrateItem) -> bool;
+
+    /// Returns the kind of a given algebraic data type
+    fn adt_kind(&self, def: AdtDef) -> AdtKind;
+
+    /// Returns if the ADT is a box.
+    fn adt_is_box(&self, def: AdtDef) -> bool;
+
+    /// Evaluate constant as a target usize.
+    fn eval_target_usize(&self, cnst: &Const) -> Result<u64, Error>;
+
+    /// Create a target usize constant for the given value.
+    fn usize_to_const(&self, val: u64) -> Result<Const, Error>;
+
+    /// Create a new type from the given kind.
+    fn new_rigid_ty(&self, kind: RigidTy) -> Ty;
+
+    /// Returns the type of given crate item.
+    fn def_ty(&self, item: DefId) -> Ty;
+
+    /// Returns literal value of a const as a string.
+    fn const_literal(&self, cnst: &Const) -> String;
+
+    /// `Span` of an item
+    fn span_of_an_item(&self, def_id: DefId) -> Span;
+
+    /// Obtain the representation of a type.
+    fn ty_kind(&self, ty: Ty) -> TyKind;
+
+    /// Get the body of an Instance.
+    /// FIXME: Monomorphize the body.
+    fn instance_body(&self, instance: InstanceDef) -> Option<Body>;
+
+    /// Get the instance type with generic substitutions applied and lifetimes erased.
+    fn instance_ty(&self, instance: InstanceDef) -> Ty;
+
+    /// Get the instance.
+    fn instance_def_id(&self, instance: InstanceDef) -> DefId;
+
+    /// Get the instance mangled name.
+    fn instance_mangled_name(&self, instance: InstanceDef) -> Symbol;
+
+    /// Convert a non-generic crate item into an instance.
+    /// This function will panic if the item is generic.
+    fn mono_instance(&self, item: CrateItem) -> Instance;
+
+    /// Item requires monomorphization.
+    fn requires_monomorphization(&self, def_id: DefId) -> bool;
+
+    /// Resolve an instance from the given function definition and generic arguments.
+    fn resolve_instance(&self, def: FnDef, args: &GenericArgs) -> Option<Instance>;
+
+    /// Resolve an instance for drop_in_place for the given type.
+    fn resolve_drop_in_place(&self, ty: Ty) -> Instance;
+
+    /// Resolve instance for a function pointer.
+    fn resolve_for_fn_ptr(&self, def: FnDef, args: &GenericArgs) -> Option<Instance>;
+
+    /// Resolve instance for a closure with the requested type.
+    fn resolve_closure(
+        &self,
+        def: ClosureDef,
+        args: &GenericArgs,
+        kind: ClosureKind,
+    ) -> Option<Instance>;
+
+    /// Evaluate a static's initializer.
+    fn eval_static_initializer(&self, def: StaticDef) -> Result<Allocation, Error>;
+
+    /// Retrieve global allocation for the given allocation ID.
+    fn global_alloc(&self, id: AllocId) -> GlobalAlloc;
+
+    /// Retrieve the id for the virtual table.
+    fn vtable_allocation(&self, global_alloc: &GlobalAlloc) -> Option<AllocId>;
+    fn krate(&self, def_id: DefId) -> Crate;
+    fn instance_name(&self, def: InstanceDef, trimmed: bool) -> Symbol;
+}
+
+// A thread local variable that stores a pointer to the tables mapping between TyCtxt
+// datastructures and stable MIR datastructures
+scoped_thread_local! (static TLV: Cell<*const ()>);
+
+pub fn run<F, T>(context: &dyn Context, f: F) -> Result<T, Error>
+where
+    F: FnOnce() -> T,
+{
+    if TLV.is_set() {
+        Err(Error::from("StableMIR already running"))
+    } else {
+        let ptr: *const () = &context as *const &_ as _;
+        TLV.set(&Cell::new(ptr), || Ok(f()))
+    }
+}
+
+/// Execute the given function with access the compiler [Context].
+///
+/// I.e., This function will load the current context and calls a function with it.
+/// Do not nest these, as that will ICE.
+pub(crate) fn with<R>(f: impl FnOnce(&dyn Context) -> R) -> R {
+    assert!(TLV.is_set());
+    TLV.with(|tlv| {
+        let ptr = tlv.get();
+        assert!(!ptr.is_null());
+        f(unsafe { *(ptr as *const &dyn Context) })
+    })
+}
diff --git a/compiler/stable_mir/src/lib.rs b/compiler/stable_mir/src/lib.rs
index 1b1faea4953..1f75dfb69cf 100644
--- a/compiler/stable_mir/src/lib.rs
+++ b/compiler/stable_mir/src/lib.rs
@@ -17,38 +17,31 @@
 //! The goal is to eventually be published on
 //! [crates.io](https://crates.io).
 
-use crate::mir::mono::{InstanceDef, StaticDef};
-use crate::mir::Body;
+#[macro_use]
+extern crate scoped_tls;
+
 use std::fmt;
 use std::fmt::Debug;
-use std::{cell::Cell, io};
+use std::io;
 
-use self::ty::{
-    GenericPredicates, Generics, ImplDef, ImplTrait, IndexedVal, LineInfo, Span, TraitDecl,
-    TraitDef, Ty, TyKind,
-};
-
-#[macro_use]
-extern crate scoped_tls;
+use crate::compiler_interface::with;
+pub use crate::crate_def::CrateDef;
+pub use crate::crate_def::DefId;
+pub use crate::error::*;
+use crate::mir::pretty::function_name;
+use crate::mir::Body;
+use crate::mir::Mutability;
+use crate::ty::{ImplDef, ImplTrait, IndexedVal, Span, TraitDecl, TraitDef, Ty};
 
 #[macro_use]
 pub mod crate_def;
+pub mod compiler_interface;
 #[macro_use]
 pub mod error;
 pub mod mir;
 pub mod ty;
 pub mod visitor;
 
-pub use crate::crate_def::CrateDef;
-pub use crate::crate_def::DefId;
-use crate::mir::alloc::{AllocId, GlobalAlloc};
-use crate::mir::pretty::function_name;
-use crate::mir::Mutability;
-use crate::ty::{AdtDef, AdtKind, Allocation, ClosureDef, ClosureKind, Const, RigidTy};
-pub use error::*;
-use mir::mono::Instance;
-use ty::{FnDef, GenericArgs};
-
 /// Use String for now but we should replace it.
 pub type Symbol = String;
 
@@ -179,149 +172,6 @@ pub fn trait_impl(trait_impl: &ImplDef) -> ImplTrait {
     with(|cx| cx.trait_impl(trait_impl))
 }
 
-/// This trait defines the interface between stable_mir and the Rust compiler.
-/// Do not use this directly.
-pub trait Context {
-    fn entry_fn(&self) -> Option<CrateItem>;
-    /// Retrieve all items of the local crate that have a MIR associated with them.
-    fn all_local_items(&self) -> CrateItems;
-    fn mir_body(&self, item: DefId) -> mir::Body;
-    fn all_trait_decls(&self) -> TraitDecls;
-    fn trait_decl(&self, trait_def: &TraitDef) -> TraitDecl;
-    fn all_trait_impls(&self) -> ImplTraitDecls;
-    fn trait_impl(&self, trait_impl: &ImplDef) -> ImplTrait;
-    fn generics_of(&self, def_id: DefId) -> Generics;
-    fn predicates_of(&self, def_id: DefId) -> GenericPredicates;
-    fn explicit_predicates_of(&self, def_id: DefId) -> GenericPredicates;
-    /// Get information about the local crate.
-    fn local_crate(&self) -> Crate;
-    /// Retrieve a list of all external crates.
-    fn external_crates(&self) -> Vec<Crate>;
-
-    /// Find a crate with the given name.
-    fn find_crates(&self, name: &str) -> Vec<Crate>;
-
-    /// Returns the name of given `DefId`
-    fn def_name(&self, def_id: DefId, trimmed: bool) -> Symbol;
-
-    /// Returns printable, human readable form of `Span`
-    fn span_to_string(&self, span: Span) -> String;
-
-    /// Return filename from given `Span`, for diagnostic purposes
-    fn get_filename(&self, span: &Span) -> Filename;
-
-    /// Return lines corresponding to this `Span`
-    fn get_lines(&self, span: &Span) -> LineInfo;
-
-    /// Returns the `kind` of given `DefId`
-    fn item_kind(&self, item: CrateItem) -> ItemKind;
-
-    /// Returns whether this is a foreign item.
-    fn is_foreign_item(&self, item: CrateItem) -> bool;
-
-    /// Returns the kind of a given algebraic data type
-    fn adt_kind(&self, def: AdtDef) -> AdtKind;
-
-    /// Returns if the ADT is a box.
-    fn adt_is_box(&self, def: AdtDef) -> bool;
-
-    /// Evaluate constant as a target usize.
-    fn eval_target_usize(&self, cnst: &Const) -> Result<u64, Error>;
-
-    /// Create a target usize constant for the given value.
-    fn usize_to_const(&self, val: u64) -> Result<Const, Error>;
-
-    /// Create a new type from the given kind.
-    fn new_rigid_ty(&self, kind: RigidTy) -> Ty;
-
-    /// Returns the type of given crate item.
-    fn def_ty(&self, item: DefId) -> Ty;
-
-    /// Returns literal value of a const as a string.
-    fn const_literal(&self, cnst: &Const) -> String;
-
-    /// `Span` of an item
-    fn span_of_an_item(&self, def_id: DefId) -> Span;
-
-    /// Obtain the representation of a type.
-    fn ty_kind(&self, ty: Ty) -> TyKind;
-
-    /// Get the body of an Instance.
-    /// FIXME: Monomorphize the body.
-    fn instance_body(&self, instance: InstanceDef) -> Option<Body>;
-
-    /// Get the instance type with generic substitutions applied and lifetimes erased.
-    fn instance_ty(&self, instance: InstanceDef) -> Ty;
-
-    /// Get the instance.
-    fn instance_def_id(&self, instance: InstanceDef) -> DefId;
-
-    /// Get the instance mangled name.
-    fn instance_mangled_name(&self, instance: InstanceDef) -> Symbol;
-
-    /// Convert a non-generic crate item into an instance.
-    /// This function will panic if the item is generic.
-    fn mono_instance(&self, item: CrateItem) -> Instance;
-
-    /// Item requires monomorphization.
-    fn requires_monomorphization(&self, def_id: DefId) -> bool;
-
-    /// Resolve an instance from the given function definition and generic arguments.
-    fn resolve_instance(&self, def: FnDef, args: &GenericArgs) -> Option<Instance>;
-
-    /// Resolve an instance for drop_in_place for the given type.
-    fn resolve_drop_in_place(&self, ty: Ty) -> Instance;
-
-    /// Resolve instance for a function pointer.
-    fn resolve_for_fn_ptr(&self, def: FnDef, args: &GenericArgs) -> Option<Instance>;
-
-    /// Resolve instance for a closure with the requested type.
-    fn resolve_closure(
-        &self,
-        def: ClosureDef,
-        args: &GenericArgs,
-        kind: ClosureKind,
-    ) -> Option<Instance>;
-
-    /// Evaluate a static's initializer.
-    fn eval_static_initializer(&self, def: StaticDef) -> Result<Allocation, Error>;
-
-    /// Retrieve global allocation for the given allocation ID.
-    fn global_alloc(&self, id: AllocId) -> GlobalAlloc;
-
-    /// Retrieve the id for the virtual table.
-    fn vtable_allocation(&self, global_alloc: &GlobalAlloc) -> Option<AllocId>;
-    fn krate(&self, def_id: DefId) -> Crate;
-    fn instance_name(&self, def: InstanceDef, trimmed: bool) -> Symbol;
-}
-
-// A thread local variable that stores a pointer to the tables mapping between TyCtxt
-// datastructures and stable MIR datastructures
-scoped_thread_local! (static TLV: Cell<*const ()>);
-
-pub fn run<F, T>(context: &dyn Context, f: F) -> Result<T, Error>
-where
-    F: FnOnce() -> T,
-{
-    if TLV.is_set() {
-        Err(Error::from("StableMIR already running"))
-    } else {
-        let ptr: *const () = &context as *const &_ as _;
-        TLV.set(&Cell::new(ptr), || Ok(f()))
-    }
-}
-
-/// Loads the current context and calls a function with it.
-/// Do not nest these, as that will ICE.
-pub fn with<R>(f: impl FnOnce(&dyn Context) -> R) -> R {
-    assert!(TLV.is_set());
-    TLV.with(|tlv| {
-        let ptr = tlv.get();
-        assert!(!ptr.is_null());
-        f(unsafe { *(ptr as *const &dyn Context) })
-    })
-}
-
 /// A type that provides internal information but that can still be used for debug purpose.
 #[derive(Clone, PartialEq, Eq, Hash)]
 pub struct Opaque(String);
diff --git a/compiler/stable_mir/src/mir/pretty.rs b/compiler/stable_mir/src/mir/pretty.rs
index c16d7ddf335..e7bca295b5a 100644
--- a/compiler/stable_mir/src/mir/pretty.rs
+++ b/compiler/stable_mir/src/mir/pretty.rs
@@ -171,7 +171,6 @@ pub fn pretty_rvalue(rval: &Rvalue) -> String {
 
 pub fn pretty_ty(ty: TyKind) -> String {
     let mut pretty = String::new();
-    pretty.push_str("");
     match ty {
         TyKind::RigidTy(rigid_ty) => match rigid_ty {
             RigidTy::Bool => "bool".to_string(),
@@ -215,7 +214,10 @@ pub fn pretty_ty(ty: TyKind) -> String {
                 pretty.push_str(&pretty_ty(ty.kind()));
                 pretty
             }
-            RigidTy::Ref(_, ty, _) => pretty_ty(ty.kind()),
+            RigidTy::Ref(_, ty, mutability) => match mutability {
+                Mutability::Not => format!("&{}", pretty_ty(ty.kind())),
+                Mutability::Mut => format!("&mut {}", pretty_ty(ty.kind())),
+            },
             RigidTy::FnDef(_, _) => format!("{:#?}", rigid_ty),
             RigidTy::FnPtr(_) => format!("{:#?}", rigid_ty),
             RigidTy::Closure(_, _) => format!("{:#?}", rigid_ty),
diff --git a/config.example.toml b/config.example.toml
index 5f9ae039b25..c91222169d9 100644
--- a/config.example.toml
+++ b/config.example.toml
@@ -30,7 +30,7 @@
 #
 # If `change-id` does not match the version that is currently running,
 # `x.py` will prompt you to update it and check the related PR for more details.
-change-id = 116881
+change-id = 117813
 
 # =============================================================================
 # Tweaking how LLVM is compiled
diff --git a/src/bootstrap/README.md b/src/bootstrap/README.md
index e7998a40a65..d0a069f45e1 100644
--- a/src/bootstrap/README.md
+++ b/src/bootstrap/README.md
@@ -183,7 +183,7 @@ Some general areas that you may be interested in modifying are:
 
 If you make a major change on bootstrap configuration, please remember to:
 
-+ Update `CONFIG_CHANGE_HISTORY` in `src/bootstrap/lib.rs`.
++ Update `CONFIG_CHANGE_HISTORY` in `src/bootstrap/src/utils/change_tracker.rs`.
 * Update `change-id = {pull-request-id}` in `config.example.toml`.
 
 A 'major change' includes
diff --git a/src/bootstrap/src/bin/main.rs b/src/bootstrap/src/bin/main.rs
index 7e6fdb7092d..952ef40ed42 100644
--- a/src/bootstrap/src/bin/main.rs
+++ b/src/bootstrap/src/bin/main.rs
@@ -120,7 +120,7 @@ fn check_version(config: &Config) -> Option<String> {
         }
 
         if let Ok(last_warned_id) = fs::read_to_string(&warned_id_path) {
-            if id.to_string() == last_warned_id {
+            if latest_change_id.to_string() == last_warned_id {
                 return None;
             }
         }
@@ -144,7 +144,7 @@ fn check_version(config: &Config) -> Option<String> {
             ));
 
             if io::stdout().is_terminal() {
-                t!(fs::write(warned_id_path, id.to_string()));
+                t!(fs::write(warned_id_path, latest_change_id.to_string()));
             }
         }
     } else {
diff --git a/src/bootstrap/src/core/build_steps/setup.rs b/src/bootstrap/src/core/build_steps/setup.rs
index bbbdb4c3186..49373177abe 100644
--- a/src/bootstrap/src/core/build_steps/setup.rs
+++ b/src/bootstrap/src/core/build_steps/setup.rs
@@ -1,6 +1,7 @@
 use crate::core::builder::{Builder, RunConfig, ShouldRun, Step};
+use crate::t;
+use crate::utils::change_tracker::CONFIG_CHANGE_HISTORY;
 use crate::Config;
-use crate::{t, CONFIG_CHANGE_HISTORY};
 use sha2::Digest;
 use std::env::consts::EXE_SUFFIX;
 use std::fmt::Write as _;
diff --git a/src/bootstrap/src/lib.rs b/src/bootstrap/src/lib.rs
index 736a9b312f0..480dd757915 100644
--- a/src/bootstrap/src/lib.rs
+++ b/src/bootstrap/src/lib.rs
@@ -47,9 +47,10 @@ use crate::utils::helpers::{self, dir_is_empty, exe, libdir, mtime, output, syml
 mod core;
 mod utils;
 
-pub use crate::core::builder::PathSet;
-pub use crate::core::config::flags::Subcommand;
-pub use crate::core::config::Config;
+pub use core::builder::PathSet;
+pub use core::config::flags::Subcommand;
+pub use core::config::Config;
+pub use utils::change_tracker::{find_recent_config_change_ids, CONFIG_CHANGE_HISTORY};
 
 const LLVM_TOOLS: &[&str] = &[
     "llvm-cov",      // used to generate coverage report
@@ -70,62 +71,6 @@ const LLVM_TOOLS: &[&str] = &[
 /// LLD file names for all flavors.
 const LLD_FILE_NAMES: &[&str] = &["ld.lld", "ld64.lld", "lld-link", "wasm-ld"];
 
-#[derive(Clone, Debug)]
-pub struct ChangeInfo {
-    /// Represents the ID of PR caused major change on bootstrap.
-    pub change_id: usize,
-    pub severity: ChangeSeverity,
-    /// Provides a short summary of the change that will guide developers
-    /// on "how to handle/behave" in response to the changes.
-    pub summary: &'static str,
-}
-
-#[derive(Clone, Debug)]
-pub enum ChangeSeverity {
-    /// Used when build configurations continue working as before.
-    Info,
-    /// Used when the default value of an option changes, or support for an option is removed entirely,
-    /// potentially requiring developers to update their build configurations.
-    Warning,
-}
-
-impl ToString for ChangeSeverity {
-    fn to_string(&self) -> String {
-        match self {
-            ChangeSeverity::Info => "INFO".to_string(),
-            ChangeSeverity::Warning => "WARNING".to_string(),
-        }
-    }
-}
-
-/// Keeps track of major changes made to the bootstrap configuration.
-///
-/// If you make any major changes (such as adding new values or changing default values),
-/// please ensure adding `ChangeInfo` to the end(because the list must be sorted by the merge date)
-/// of this list.
-pub const CONFIG_CHANGE_HISTORY: &[ChangeInfo] = &[
-    ChangeInfo {
-        change_id: 115898,
-        severity: ChangeSeverity::Info,
-        summary: "Implementation of this change-tracking system. Ignore this.",
-    },
-    ChangeInfo {
-        change_id: 116998,
-        severity: ChangeSeverity::Info,
-        summary: "Removed android-ndk r15 support in favor of android-ndk r25b.",
-    },
-    ChangeInfo {
-        change_id: 117435,
-        severity: ChangeSeverity::Info,
-        summary: "New option `rust.parallel-compiler` added to config.toml.",
-    },
-    ChangeInfo {
-        change_id: 116881,
-        severity: ChangeSeverity::Warning,
-        summary: "Default value of `download-ci-llvm` was changed for `codegen` profile.",
-    },
-];
-
 /// Extra --check-cfg to add when building
 /// (Mode restriction, config name, config values (if any))
 const EXTRA_CHECK_CFGS: &[(Option<Mode>, &str, Option<&[&'static str]>)] = &[
@@ -1895,31 +1840,6 @@ fn envify(s: &str) -> String {
         .collect()
 }
 
-pub fn find_recent_config_change_ids(current_id: usize) -> Vec<ChangeInfo> {
-    if !CONFIG_CHANGE_HISTORY.iter().any(|config| config.change_id == current_id) {
-        // If the current change-id is greater than the most recent one, return
-        // an empty list (it may be due to switching from a recent branch to an
-        // older one); otherwise, return the full list (assuming the user provided
-        // the incorrect change-id by accident).
-        if let Some(config) = CONFIG_CHANGE_HISTORY.iter().max_by_key(|config| config.change_id) {
-            if &current_id > &config.change_id {
-                return Vec::new();
-            }
-        }
-
-        return CONFIG_CHANGE_HISTORY.to_vec();
-    }
-
-    let index =
-        CONFIG_CHANGE_HISTORY.iter().position(|config| config.change_id == current_id).unwrap();
-
-    CONFIG_CHANGE_HISTORY
-        .iter()
-        .skip(index + 1) // Skip the current_id and IDs before it
-        .cloned()
-        .collect()
-}
-
 /// Computes a hash representing the state of a repository/submodule and additional input.
 ///
 /// It uses `git diff` for the actual changes, and `git status` for including the untracked
diff --git a/src/bootstrap/src/utils/change_tracker.rs b/src/bootstrap/src/utils/change_tracker.rs
new file mode 100644
index 00000000000..887b596b786
--- /dev/null
+++ b/src/bootstrap/src/utils/change_tracker.rs
@@ -0,0 +1,89 @@
+//! This module facilitates the tracking system for major changes made to the bootstrap,
+//! with the goal of keeping developers synchronized with important modifications in
+//! the bootstrap.
+
+#[derive(Clone, Debug)]
+pub struct ChangeInfo {
+    /// Represents the ID of PR caused major change on bootstrap.
+    pub change_id: usize,
+    pub severity: ChangeSeverity,
+    /// Provides a short summary of the change that will guide developers
+    /// on "how to handle/behave" in response to the changes.
+    pub summary: &'static str,
+}
+
+#[derive(Clone, Debug)]
+pub enum ChangeSeverity {
+    /// Used when build configurations continue working as before.
+    Info,
+    /// Used when the default value of an option changes, or support for an option is removed entirely,
+    /// potentially requiring developers to update their build configurations.
+    Warning,
+}
+
+impl ToString for ChangeSeverity {
+    fn to_string(&self) -> String {
+        match self {
+            ChangeSeverity::Info => "INFO".to_string(),
+            ChangeSeverity::Warning => "WARNING".to_string(),
+        }
+    }
+}
+
+pub fn find_recent_config_change_ids(current_id: usize) -> Vec<ChangeInfo> {
+    if !CONFIG_CHANGE_HISTORY.iter().any(|config| config.change_id == current_id) {
+        // If the current change-id is greater than the most recent one, return
+        // an empty list (it may be due to switching from a recent branch to an
+        // older one); otherwise, return the full list (assuming the user provided
+        // the incorrect change-id by accident).
+        if let Some(config) = CONFIG_CHANGE_HISTORY.iter().max_by_key(|config| config.change_id) {
+            if &current_id > &config.change_id {
+                return Vec::new();
+            }
+        }
+
+        return CONFIG_CHANGE_HISTORY.to_vec();
+    }
+
+    let index =
+        CONFIG_CHANGE_HISTORY.iter().position(|config| config.change_id == current_id).unwrap();
+
+    CONFIG_CHANGE_HISTORY
+        .iter()
+        .skip(index + 1) // Skip the current_id and IDs before it
+        .cloned()
+        .collect()
+}
+
+/// Keeps track of major changes made to the bootstrap configuration.
+///
+/// If you make any major changes (such as adding new values or changing default values),
+/// please ensure adding `ChangeInfo` to the end(because the list must be sorted by the merge date)
+/// of this list.
+pub const CONFIG_CHANGE_HISTORY: &[ChangeInfo] = &[
+    ChangeInfo {
+        change_id: 115898,
+        severity: ChangeSeverity::Info,
+        summary: "Implementation of this change-tracking system. Ignore this.",
+    },
+    ChangeInfo {
+        change_id: 116998,
+        severity: ChangeSeverity::Info,
+        summary: "Removed android-ndk r15 support in favor of android-ndk r25b.",
+    },
+    ChangeInfo {
+        change_id: 117435,
+        severity: ChangeSeverity::Info,
+        summary: "New option `rust.parallel-compiler` added to config.toml.",
+    },
+    ChangeInfo {
+        change_id: 116881,
+        severity: ChangeSeverity::Warning,
+        summary: "Default value of `download-ci-llvm` was changed for `codegen` profile.",
+    },
+    ChangeInfo {
+        change_id: 117813,
+        severity: ChangeSeverity::Info,
+        summary: "Use of the `if-available` value for `download-ci-llvm` is deprecated; prefer using the new `if-unchanged` value.",
+    },
+];
diff --git a/src/bootstrap/src/utils/mod.rs b/src/bootstrap/src/utils/mod.rs
index 8ca22d00865..cb535f0e163 100644
--- a/src/bootstrap/src/utils/mod.rs
+++ b/src/bootstrap/src/utils/mod.rs
@@ -4,6 +4,7 @@
 
 pub(crate) mod cache;
 pub(crate) mod cc_detect;
+pub(crate) mod change_tracker;
 pub(crate) mod channel;
 pub(crate) mod dylib;
 pub(crate) mod exec;
diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs
index ce9e1bcf488..14387e0d45d 100644
--- a/src/librustdoc/html/render/print_item.rs
+++ b/src/librustdoc/html/render/print_item.rs
@@ -596,8 +596,10 @@ fn extra_info_tags<'a, 'tcx: 'a>(
 
         // The "rustc_private" crates are permanently unstable so it makes no sense
         // to render "unstable" everywhere.
-        if item.stability(tcx).as_ref().map(|s| s.is_unstable() && s.feature != sym::rustc_private)
-            == Some(true)
+        if item
+            .stability(tcx)
+            .as_ref()
+            .is_some_and(|s| s.is_unstable() && s.feature != sym::rustc_private)
         {
             write!(f, "{}", tag_html("unstable", "", "Experimental"))?;
         }
diff --git a/src/librustdoc/html/static/js/search.js b/src/librustdoc/html/static/js/search.js
index 4822690fd04..0bb56cd9710 100644
--- a/src/librustdoc/html/static/js/search.js
+++ b/src/librustdoc/html/static/js/search.js
@@ -1755,17 +1755,26 @@ function initSearch(rawSearchIndex) {
                 if (mgens && mgens.has(fnType.id) && mgens.get(fnType.id) !== 0) {
                     return false;
                 }
+                // Where clauses can represent cyclical data.
+                // `null` prevents it from trying to unbox in an infinite loop
+                const mgensTmp = new Map(mgens);
+                mgensTmp.set(fnType.id, null);
                 // This is only a potential unbox if the search query appears in the where clause
                 // for example, searching `Read -> usize` should find
                 // `fn read_all<R: Read>(R) -> Result<usize>`
                 // generic `R` is considered "unboxed"
-                return checkIfInList(whereClause[(-fnType.id) - 1], queryElem, whereClause);
+                return checkIfInList(
+                    whereClause[(-fnType.id) - 1],
+                    queryElem,
+                    whereClause,
+                    mgensTmp
+                );
             } else if (fnType.generics.length > 0 || fnType.bindings.size > 0) {
                 const simplifiedGenerics = [
                     ...fnType.generics,
                     ...Array.from(fnType.bindings.values()).flat(),
                 ];
-                return checkIfInList(simplifiedGenerics, queryElem, whereClause);
+                return checkIfInList(simplifiedGenerics, queryElem, whereClause, mgens);
             }
             return false;
         }
@@ -1777,12 +1786,13 @@ function initSearch(rawSearchIndex) {
           * @param {Array<FunctionType>} list
           * @param {QueryElement} elem          - The element from the parsed query.
           * @param {[FunctionType]} whereClause - Trait bounds for generic items.
+         * @param {Map<number,number>|null} mgens - Map functions generics to query generics.
           *
           * @return {boolean} - Returns true if found, false otherwise.
           */
-        function checkIfInList(list, elem, whereClause) {
+        function checkIfInList(list, elem, whereClause, mgens) {
             for (const entry of list) {
-                if (checkType(entry, elem, whereClause)) {
+                if (checkType(entry, elem, whereClause, mgens)) {
                     return true;
                 }
             }
@@ -1796,23 +1806,29 @@ function initSearch(rawSearchIndex) {
           * @param {Row} row
           * @param {QueryElement} elem          - The element from the parsed query.
           * @param {[FunctionType]} whereClause - Trait bounds for generic items.
+         * @param {Map<number,number>|null} mgens - Map functions generics to query generics.
           *
           * @return {boolean} - Returns true if the type matches, false otherwise.
           */
-        function checkType(row, elem, whereClause) {
+        function checkType(row, elem, whereClause, mgens) {
             if (row.bindings.size === 0 && elem.bindings.size === 0) {
                 if (elem.id < 0) {
-                    return row.id < 0 || checkIfInList(row.generics, elem, whereClause);
+                    return row.id < 0 || checkIfInList(row.generics, elem, whereClause, mgens);
                 }
                 if (row.id > 0 && elem.id > 0 && elem.pathWithoutLast.length === 0 &&
                     typePassesFilter(elem.typeFilter, row.ty) && elem.generics.length === 0 &&
                     // special case
                     elem.id !== typeNameIdOfArrayOrSlice
                 ) {
-                    return row.id === elem.id || checkIfInList(row.generics, elem, whereClause);
+                    return row.id === elem.id || checkIfInList(
+                        row.generics,
+                        elem,
+                        whereClause,
+                        mgens
+                    );
                 }
             }
-            return unifyFunctionTypes([row], [elem], whereClause);
+            return unifyFunctionTypes([row], [elem], whereClause, mgens);
         }
 
         function checkPath(contains, ty, maxEditDistance) {
diff --git a/src/tools/compiletest/src/header.rs b/src/tools/compiletest/src/header.rs
index d6516cff63f..f85f9e674ab 100644
--- a/src/tools/compiletest/src/header.rs
+++ b/src/tools/compiletest/src/header.rs
@@ -632,7 +632,7 @@ fn iter_header_extra(
         it(None, directive, 0);
     }
 
-    let comment = if testfile.extension().map(|e| e == "rs") == Some(true) { "//" } else { "#" };
+    let comment = if testfile.extension().is_some_and(|e| e == "rs") { "//" } else { "#" };
 
     let mut rdr = BufReader::new(rdr);
     let mut ln = String::new();
diff --git a/src/tools/miri/rust-version b/src/tools/miri/rust-version
index 76ae9227983..ecebb8a331b 100644
--- a/src/tools/miri/rust-version
+++ b/src/tools/miri/rust-version
@@ -1 +1 @@
-34c5ab9aac327a8a18e18ea37a2468a320d82fb0
+3668a8af1b81447c4afa1f82f60d7b94b71a549f
diff --git a/src/tools/miri/tests/fail/intrinsics/float_to_int_32_inf1.stderr b/src/tools/miri/tests/fail/intrinsics/float_to_int_32_inf1.stderr
index 9ed527d850d..2de8f3420b7 100644
--- a/src/tools/miri/tests/fail/intrinsics/float_to_int_32_inf1.stderr
+++ b/src/tools/miri/tests/fail/intrinsics/float_to_int_32_inf1.stderr
@@ -1,8 +1,8 @@
-error: Undefined Behavior: `float_to_int_unchecked` intrinsic called on +Inff32 which cannot be represented in target type `i32`
+error: Undefined Behavior: `float_to_int_unchecked` intrinsic called on +Inf_f32 which cannot be represented in target type `i32`
   --> $DIR/float_to_int_32_inf1.rs:LL:CC
    |
 LL |         float_to_int_unchecked::<f32, i32>(f32::INFINITY);
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on +Inff32 which cannot be represented in target type `i32`
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on +Inf_f32 which cannot be represented in target type `i32`
    |
    = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
    = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
diff --git a/src/tools/miri/tests/fail/intrinsics/float_to_int_32_infneg1.stderr b/src/tools/miri/tests/fail/intrinsics/float_to_int_32_infneg1.stderr
index d1aaaf26a30..53ed208bdee 100644
--- a/src/tools/miri/tests/fail/intrinsics/float_to_int_32_infneg1.stderr
+++ b/src/tools/miri/tests/fail/intrinsics/float_to_int_32_infneg1.stderr
@@ -1,8 +1,8 @@
-error: Undefined Behavior: `float_to_int_unchecked` intrinsic called on -Inff32 which cannot be represented in target type `i32`
+error: Undefined Behavior: `float_to_int_unchecked` intrinsic called on -Inf_f32 which cannot be represented in target type `i32`
   --> $DIR/float_to_int_32_infneg1.rs:LL:CC
    |
 LL |         float_to_int_unchecked::<f32, i32>(f32::NEG_INFINITY);
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on -Inff32 which cannot be represented in target type `i32`
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on -Inf_f32 which cannot be represented in target type `i32`
    |
    = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
    = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
diff --git a/src/tools/miri/tests/fail/intrinsics/float_to_int_32_nan.stderr b/src/tools/miri/tests/fail/intrinsics/float_to_int_32_nan.stderr
index bd00f00e70a..afda7124c11 100644
--- a/src/tools/miri/tests/fail/intrinsics/float_to_int_32_nan.stderr
+++ b/src/tools/miri/tests/fail/intrinsics/float_to_int_32_nan.stderr
@@ -1,8 +1,8 @@
-error: Undefined Behavior: `float_to_int_unchecked` intrinsic called on NaNf32 which cannot be represented in target type `u32`
+error: Undefined Behavior: `float_to_int_unchecked` intrinsic called on NaN_f32 which cannot be represented in target type `u32`
   --> $DIR/float_to_int_32_nan.rs:LL:CC
    |
 LL |         float_to_int_unchecked::<f32, u32>(f32::NAN);
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on NaNf32 which cannot be represented in target type `u32`
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on NaN_f32 which cannot be represented in target type `u32`
    |
    = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
    = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
diff --git a/src/tools/miri/tests/fail/intrinsics/float_to_int_32_nanneg.stderr b/src/tools/miri/tests/fail/intrinsics/float_to_int_32_nanneg.stderr
index ab717efbfe0..8ba46de8641 100644
--- a/src/tools/miri/tests/fail/intrinsics/float_to_int_32_nanneg.stderr
+++ b/src/tools/miri/tests/fail/intrinsics/float_to_int_32_nanneg.stderr
@@ -1,8 +1,8 @@
-error: Undefined Behavior: `float_to_int_unchecked` intrinsic called on NaNf32 which cannot be represented in target type `u32`
+error: Undefined Behavior: `float_to_int_unchecked` intrinsic called on NaN_f32 which cannot be represented in target type `u32`
   --> $DIR/float_to_int_32_nanneg.rs:LL:CC
    |
 LL |         float_to_int_unchecked::<f32, u32>(-f32::NAN);
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on NaNf32 which cannot be represented in target type `u32`
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on NaN_f32 which cannot be represented in target type `u32`
    |
    = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
    = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
diff --git a/src/tools/miri/tests/fail/intrinsics/float_to_int_64_inf1.stderr b/src/tools/miri/tests/fail/intrinsics/float_to_int_64_inf1.stderr
index c68fd64f62a..5db9fb1417c 100644
--- a/src/tools/miri/tests/fail/intrinsics/float_to_int_64_inf1.stderr
+++ b/src/tools/miri/tests/fail/intrinsics/float_to_int_64_inf1.stderr
@@ -1,8 +1,8 @@
-error: Undefined Behavior: `float_to_int_unchecked` intrinsic called on +Inff64 which cannot be represented in target type `u128`
+error: Undefined Behavior: `float_to_int_unchecked` intrinsic called on +Inf_f64 which cannot be represented in target type `u128`
   --> $DIR/float_to_int_64_inf1.rs:LL:CC
    |
 LL |         float_to_int_unchecked::<f64, u128>(f64::INFINITY);
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on +Inff64 which cannot be represented in target type `u128`
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on +Inf_f64 which cannot be represented in target type `u128`
    |
    = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
    = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
diff --git a/src/tools/miri/tests/fail/intrinsics/float_to_int_64_infneg1.stderr b/src/tools/miri/tests/fail/intrinsics/float_to_int_64_infneg1.stderr
index 83b6c04bb1d..3e8dadb79e4 100644
--- a/src/tools/miri/tests/fail/intrinsics/float_to_int_64_infneg1.stderr
+++ b/src/tools/miri/tests/fail/intrinsics/float_to_int_64_infneg1.stderr
@@ -1,8 +1,8 @@
-error: Undefined Behavior: `float_to_int_unchecked` intrinsic called on -Inff64 which cannot be represented in target type `u128`
+error: Undefined Behavior: `float_to_int_unchecked` intrinsic called on -Inf_f64 which cannot be represented in target type `u128`
   --> $DIR/float_to_int_64_infneg1.rs:LL:CC
    |
 LL |         float_to_int_unchecked::<f64, u128>(f64::NEG_INFINITY);
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on -Inff64 which cannot be represented in target type `u128`
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on -Inf_f64 which cannot be represented in target type `u128`
    |
    = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
    = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
diff --git a/src/tools/miri/tests/fail/intrinsics/float_to_int_64_infneg2.stderr b/src/tools/miri/tests/fail/intrinsics/float_to_int_64_infneg2.stderr
index b7bfe1f7dd9..cb59974bf45 100644
--- a/src/tools/miri/tests/fail/intrinsics/float_to_int_64_infneg2.stderr
+++ b/src/tools/miri/tests/fail/intrinsics/float_to_int_64_infneg2.stderr
@@ -1,8 +1,8 @@
-error: Undefined Behavior: `float_to_int_unchecked` intrinsic called on -Inff64 which cannot be represented in target type `i128`
+error: Undefined Behavior: `float_to_int_unchecked` intrinsic called on -Inf_f64 which cannot be represented in target type `i128`
   --> $DIR/float_to_int_64_infneg2.rs:LL:CC
    |
 LL |         float_to_int_unchecked::<f64, i128>(f64::NEG_INFINITY);
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on -Inff64 which cannot be represented in target type `i128`
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on -Inf_f64 which cannot be represented in target type `i128`
    |
    = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
    = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
diff --git a/src/tools/miri/tests/fail/intrinsics/float_to_int_64_nan.stderr b/src/tools/miri/tests/fail/intrinsics/float_to_int_64_nan.stderr
index 1df594bce43..68697060515 100644
--- a/src/tools/miri/tests/fail/intrinsics/float_to_int_64_nan.stderr
+++ b/src/tools/miri/tests/fail/intrinsics/float_to_int_64_nan.stderr
@@ -1,8 +1,8 @@
-error: Undefined Behavior: `float_to_int_unchecked` intrinsic called on NaNf64 which cannot be represented in target type `u32`
+error: Undefined Behavior: `float_to_int_unchecked` intrinsic called on NaN_f64 which cannot be represented in target type `u32`
   --> $DIR/float_to_int_64_nan.rs:LL:CC
    |
 LL |         float_to_int_unchecked::<f64, u32>(f64::NAN);
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on NaNf64 which cannot be represented in target type `u32`
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on NaN_f64 which cannot be represented in target type `u32`
    |
    = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
    = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
diff --git a/tests/rustdoc-js/assoc-type-loop.js b/tests/rustdoc-js/assoc-type-loop.js
new file mode 100644
index 00000000000..f0192371ab4
--- /dev/null
+++ b/tests/rustdoc-js/assoc-type-loop.js
@@ -0,0 +1,9 @@
+// Crash reduction of
+// https://github.com/rust-lang/rust/issues/118242
+
+const EXPECTED = [
+    {
+        'query': 't',
+        'correction': null,
+    },
+];
diff --git a/tests/rustdoc-js/assoc-type-loop.rs b/tests/rustdoc-js/assoc-type-loop.rs
new file mode 100644
index 00000000000..f123c83f50f
--- /dev/null
+++ b/tests/rustdoc-js/assoc-type-loop.rs
@@ -0,0 +1,35 @@
+#![crate_name="foo"]
+
+// reduced from sqlx 0.7.3
+use std::future::Future;
+use std::pin::Pin;
+use std::ops::{Deref, DerefMut};
+pub enum Error {}
+pub trait Acquire<'c> {
+    type Database: Database;
+    type Connection: Deref<Target = <Self::Database as Database>::Connection> + DerefMut + Send;
+}
+pub trait Database {
+    type Connection: Connection<Database = Self>;
+}
+pub trait Connection {
+    type Database: Database;
+    type Options: ConnectionOptions<Connection = Self>;
+    fn begin(
+        &mut self
+    ) -> Pin<Box<dyn Future<Output = Result<Transaction<'_, Self::Database>, Error>> + Send + '_>>
+    where
+        Self: Sized;
+}
+pub trait ConnectionOptions {
+    type Connection: Connection;
+}
+pub struct Transaction<'c, DB: Database> {
+    _db: &'c DB,
+}
+impl<'t, 'c, DB: Database> Acquire<'t> for &'t mut Transaction<'c, DB>
+    where <DB as Database>::Connection: Send
+{
+    type Database = DB;
+    type Connection = &'t mut <DB as Database>::Connection;
+}
diff --git a/triagebot.toml b/triagebot.toml
index a72338d1950..c1482769852 100644
--- a/triagebot.toml
+++ b/triagebot.toml
@@ -533,6 +533,12 @@ message = "The Miri subtree was changed"
 cc = ["@rust-lang/miri"]
 
 [mentions."src/tools/rust-analyzer"]
+message = """
+rust-analyzer is developed in its own repository. If possible, consider making \
+this change to [rust-lang/rust-analyzer] instead.
+
+[rust-lang/rust-analyzer]: https://github.com/rust-lang/rust-analyzer
+"""
 cc = ["@rust-lang/rust-analyzer"]
 
 [mentions."src/tools/rustfmt"]
@@ -583,11 +589,23 @@ message = "The list of allowed third-party dependencies may have been modified!
 cc = ["@davidtwco", "@wesleywiser"]
 
 [mentions."src/bootstrap/src/core/config"]
-message = "This PR modifies `src/bootstrap/src/core/config`. If appropriate, please also update `CONFIG_CHANGE_HISTORY` in `src/bootstrap/src/lib.rs` and `change-id` in `config.example.toml`."
+message = """
+This PR modifies `src/bootstrap/src/core/config`.
+
+If appropriate, please update `CONFIG_CHANGE_HISTORY` in `src/bootstrap/src/utils/change_tracker.rs` and `change-id` in `config.example.toml`.
+"""
 [mentions."src/bootstrap/defaults"]
-message = "This PR modifies `src/bootstrap/defaults`. If appropriate, please also update `CONFIG_CHANGE_HISTORY` in `src/bootstrap/src/lib.rs` and `change-id` in `config.example.toml`."
+message = """
+This PR modifies `src/bootstrap/defaults`.
+
+If appropriate, please update `CONFIG_CHANGE_HISTORY` in `src/bootstrap/src/utils/change_tracker.rs` and `change-id` in `config.example.toml`.
+"""
 [mentions."config.example.toml"]
-message = "This PR changes `config.example.toml`. If appropriate, please also update `CONFIG_CHANGE_HISTORY` in `src/bootstrap/src/lib.rs` and `change-id` in `config.example.toml`."
+message = """
+This PR modifies `config.example.toml`.
+
+If appropriate, please update `CONFIG_CHANGE_HISTORY` in `src/bootstrap/src/utils/change_tracker.rs` and `change-id` in `config.example.toml`.
+"""
 
 [mentions."src/bootstrap/defaults/config.compiler.toml"]
 message = "This PR changes src/bootstrap/defaults/config.compiler.toml. If appropriate, please also update `config.codegen.toml` so the defaults are in sync."