about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMakai <m4kai410@gmail.com>2025-05-05 15:31:34 +0800
committerMakai <m4kai410@gmail.com>2025-07-04 01:33:17 +0000
commit0f6f68313d6d1b503c695bddd2f41dc09f6c1058 (patch)
treebbbf98cc0a4de2805e2aa21c090e81db6989036b
parent3b328e111a8b4fc67e7c4e7b39f45b89231d1487 (diff)
downloadrust-0f6f68313d6d1b503c695bddd2f41dc09f6c1058.tar.gz
rust-0f6f68313d6d1b503c695bddd2f41dc09f6c1058.zip
refactor: rewrite the whole `rustc_smir::context`
This commit removes the `Tables` field from `SmirCtxt`, since borrows of `tables` should only be managed by `SmirInterface`.

This change prevents `SmirCtxt` from holding separate borrows and requires passing `tables` explicitly when needed.

We use the `traits.rs` file to define traits that are used for encapsulating the associated functions in the rustc's internals. This is much easier to use and maintain than directly cramming everything into `SmirCtxt`.
-rw-r--r--compiler/rustc_smir/src/rustc_smir/context.rs1000
-rw-r--r--compiler/rustc_smir/src/rustc_smir/context/impls.rs772
-rw-r--r--compiler/rustc_smir/src/rustc_smir/context/mod.rs79
-rw-r--r--compiler/rustc_smir/src/rustc_smir/context/traits.rs50
4 files changed, 901 insertions, 1000 deletions
diff --git a/compiler/rustc_smir/src/rustc_smir/context.rs b/compiler/rustc_smir/src/rustc_smir/context.rs
deleted file mode 100644
index 3fa83cfc6a0..00000000000
--- a/compiler/rustc_smir/src/rustc_smir/context.rs
+++ /dev/null
@@ -1,1000 +0,0 @@
-//! Implementation of StableMIR Context.
-
-#![allow(rustc::usage_of_qualified_ty)]
-
-use std::cell::RefCell;
-use std::iter;
-
-use rustc_abi::HasDataLayout;
-use rustc_hir::{Attribute, LangItem};
-use rustc_middle::ty::layout::{
-    FnAbiOf, FnAbiOfHelpers, HasTyCtxt, HasTypingEnv, LayoutOf, LayoutOfHelpers,
-};
-use rustc_middle::ty::print::{with_forced_trimmed_paths, with_no_trimmed_paths};
-use rustc_middle::ty::{
-    CoroutineArgsExt, GenericPredicates, Instance, List, ScalarInt, TyCtxt, TypeVisitableExt,
-    ValTree,
-};
-use rustc_middle::{mir, ty};
-use rustc_span::def_id::LOCAL_CRATE;
-use stable_mir::abi::{FnAbi, Layout, LayoutShape, ReprOptions};
-use stable_mir::mir::alloc::GlobalAlloc;
-use stable_mir::mir::mono::{InstanceDef, StaticDef};
-use stable_mir::mir::{BinOp, Body, Place, UnOp};
-use stable_mir::target::{MachineInfo, MachineSize};
-use stable_mir::ty::{
-    AdtDef, AdtKind, Allocation, ClosureDef, ClosureKind, CoroutineDef, Discr, FieldDef, FnDef,
-    ForeignDef, ForeignItemKind, GenericArgs, IntrinsicDef, LineInfo, MirConst, PolyFnSig, RigidTy,
-    Span, Ty, TyConst, TyKind, UintTy, VariantDef, VariantIdx,
-};
-use stable_mir::{Crate, CrateDef, CrateItem, CrateNum, DefId, Error, Filename, ItemKind, Symbol};
-
-use crate::rustc_internal::RustcInternal;
-use crate::rustc_smir::builder::BodyBuilder;
-use crate::rustc_smir::{Stable, Tables, alloc, filter_def_ids, new_item_kind, smir_crate};
-use crate::stable_mir;
-
-/// Provides direct access to rustc's internal queries.
-///
-/// The [`crate::stable_mir::compiler_interface::SmirInterface`] must go through
-/// this context to obtain rustc-level information.
-pub struct SmirCtxt<'tcx>(pub RefCell<Tables<'tcx>>);
-
-impl<'tcx> SmirCtxt<'tcx> {
-    pub fn target_info(&self) -> MachineInfo {
-        let mut tables = self.0.borrow_mut();
-        MachineInfo {
-            endian: tables.tcx.data_layout.endian.stable(&mut *tables),
-            pointer_width: MachineSize::from_bits(
-                tables.tcx.data_layout.pointer_size.bits().try_into().unwrap(),
-            ),
-        }
-    }
-
-    pub 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))
-    }
-
-    /// Retrieve all items of the local crate that have a MIR associated with them.
-    pub 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()
-    }
-
-    /// Retrieve the body of a function.
-    /// This function will panic if the body is not available.
-    pub 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::InstanceKind::Item(def_id)).stable(&mut tables)
-    }
-
-    /// Check whether the body of a function is available.
-    pub fn has_body(&self, def: DefId) -> bool {
-        let mut tables = self.0.borrow_mut();
-        let tcx = tables.tcx;
-        let def_id = def.internal(&mut *tables, tcx);
-        tables.item_has_body(def_id)
-    }
-
-    pub fn foreign_modules(&self, crate_num: CrateNum) -> Vec<stable_mir::ty::ForeignModuleDef> {
-        let mut tables = self.0.borrow_mut();
-        let tcx = tables.tcx;
-        tcx.foreign_modules(crate_num.internal(&mut *tables, tcx))
-            .keys()
-            .map(|mod_def_id| tables.foreign_module_def(*mod_def_id))
-            .collect()
-    }
-
-    /// Retrieve all functions defined in this crate.
-    pub fn crate_functions(&self, crate_num: CrateNum) -> Vec<FnDef> {
-        let mut tables = self.0.borrow_mut();
-        let tcx = tables.tcx;
-        let krate = crate_num.internal(&mut *tables, tcx);
-        filter_def_ids(tcx, krate, |def_id| tables.to_fn_def(def_id))
-    }
-
-    /// Retrieve all static items defined in this crate.
-    pub fn crate_statics(&self, crate_num: CrateNum) -> Vec<StaticDef> {
-        let mut tables = self.0.borrow_mut();
-        let tcx = tables.tcx;
-        let krate = crate_num.internal(&mut *tables, tcx);
-        filter_def_ids(tcx, krate, |def_id| tables.to_static(def_id))
-    }
-
-    pub fn foreign_module(
-        &self,
-        mod_def: stable_mir::ty::ForeignModuleDef,
-    ) -> stable_mir::ty::ForeignModule {
-        let mut tables = self.0.borrow_mut();
-        let def_id = tables[mod_def.def_id()];
-        let mod_def = tables.tcx.foreign_modules(def_id.krate).get(&def_id).unwrap();
-        mod_def.stable(&mut *tables)
-    }
-
-    pub fn foreign_items(&self, mod_def: stable_mir::ty::ForeignModuleDef) -> Vec<ForeignDef> {
-        let mut tables = self.0.borrow_mut();
-        let def_id = tables[mod_def.def_id()];
-        tables
-            .tcx
-            .foreign_modules(def_id.krate)
-            .get(&def_id)
-            .unwrap()
-            .foreign_items
-            .iter()
-            .map(|item_def| tables.foreign_def(*item_def))
-            .collect()
-    }
-
-    pub fn all_trait_decls(&self) -> stable_mir::TraitDecls {
-        let mut tables = self.0.borrow_mut();
-        tables
-            .tcx
-            .all_traits_including_private()
-            .map(|trait_def_id| tables.trait_def(trait_def_id))
-            .collect()
-    }
-
-    pub fn trait_decls(&self, crate_num: CrateNum) -> stable_mir::TraitDecls {
-        let mut tables = self.0.borrow_mut();
-        let tcx = tables.tcx;
-        tcx.traits(crate_num.internal(&mut *tables, tcx))
-            .iter()
-            .map(|trait_def_id| tables.trait_def(*trait_def_id))
-            .collect()
-    }
-
-    pub 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)
-    }
-
-    pub fn all_trait_impls(&self) -> stable_mir::ImplTraitDecls {
-        let mut tables = self.0.borrow_mut();
-        let tcx = tables.tcx;
-        iter::once(LOCAL_CRATE)
-            .chain(tables.tcx.crates(()).iter().copied())
-            .flat_map(|cnum| tcx.trait_impls_in_crate(cnum).iter())
-            .map(|impl_def_id| tables.impl_def(*impl_def_id))
-            .collect()
-    }
-
-    pub fn trait_impls(&self, crate_num: CrateNum) -> stable_mir::ImplTraitDecls {
-        let mut tables = self.0.borrow_mut();
-        let tcx = tables.tcx;
-        tcx.trait_impls_in_crate(crate_num.internal(&mut *tables, tcx))
-            .iter()
-            .map(|impl_def_id| tables.impl_def(*impl_def_id))
-            .collect()
-    }
-
-    pub 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)
-    }
-
-    pub 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)
-    }
-
-    pub 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(),
-        }
-    }
-
-    pub 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(),
-        }
-    }
-
-    /// Get information about the local crate.
-    pub fn local_crate(&self) -> stable_mir::Crate {
-        let tables = self.0.borrow();
-        smir_crate(tables.tcx, LOCAL_CRATE)
-    }
-
-    /// Retrieve a list of all external crates.
-    pub 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()
-    }
-
-    /// Find a crate with the given name.
-    pub 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())
-            .filter_map(|crate_num| {
-                let crate_name = tables.tcx.crate_name(*crate_num).to_string();
-                (name == crate_name).then(|| smir_crate(tables.tcx, *crate_num))
-            })
-            .collect();
-        crates
-    }
-
-    /// Returns the name of given `DefId`.
-    pub 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]))
-        }
-    }
-
-    /// Return registered tool attributes with the given attribute name.
-    ///
-    /// FIXME(jdonszelmann): may panic on non-tool attributes. After more attribute work, non-tool
-    /// attributes will simply return an empty list.
-    ///
-    /// Single segmented name like `#[clippy]` is specified as `&["clippy".to_string()]`.
-    /// Multi-segmented name like `#[rustfmt::skip]` is specified as `&["rustfmt".to_string(), "skip".to_string()]`.
-    pub fn tool_attrs(
-        &self,
-        def_id: stable_mir::DefId,
-        attr: &[stable_mir::Symbol],
-    ) -> Vec<stable_mir::crate_def::Attribute> {
-        let mut tables = self.0.borrow_mut();
-        let tcx = tables.tcx;
-        let did = tables[def_id];
-        let attr_name: Vec<_> = attr.iter().map(|seg| rustc_span::Symbol::intern(&seg)).collect();
-        tcx.get_attrs_by_path(did, &attr_name)
-            .filter_map(|attribute| {
-                if let Attribute::Unparsed(u) = attribute {
-                    let attr_str = rustc_hir_pretty::attribute_to_string(&tcx, attribute);
-                    Some(stable_mir::crate_def::Attribute::new(
-                        attr_str,
-                        u.span.stable(&mut *tables),
-                    ))
-                } else {
-                    None
-                }
-            })
-            .collect()
-    }
-
-    /// Get all tool attributes of a definition.
-    pub fn all_tool_attrs(
-        &self,
-        def_id: stable_mir::DefId,
-    ) -> Vec<stable_mir::crate_def::Attribute> {
-        let mut tables = self.0.borrow_mut();
-        let tcx = tables.tcx;
-        let did = tables[def_id];
-        let attrs_iter = if let Some(did) = did.as_local() {
-            tcx.hir_attrs(tcx.local_def_id_to_hir_id(did)).iter()
-        } else {
-            tcx.attrs_for_def(did).iter()
-        };
-        attrs_iter
-            .filter_map(|attribute| {
-                if let Attribute::Unparsed(u) = attribute {
-                    let attr_str = rustc_hir_pretty::attribute_to_string(&tcx, attribute);
-                    Some(stable_mir::crate_def::Attribute::new(
-                        attr_str,
-                        u.span.stable(&mut *tables),
-                    ))
-                } else {
-                    None
-                }
-            })
-            .collect()
-    }
-
-    /// Returns printable, human readable form of `Span`.
-    pub 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])
-    }
-
-    /// Return filename from given `Span`, for diagnostic purposes.
-    pub 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()
-    }
-
-    /// Return lines corresponding to this `Span`.
-    pub 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 }
-    }
-
-    /// Returns the `kind` of given `DefId`.
-    pub fn item_kind(&self, item: CrateItem) -> ItemKind {
-        let tables = self.0.borrow();
-        new_item_kind(tables.tcx.def_kind(tables[item.0]))
-    }
-
-    /// Returns whether this is a foreign item.
-    pub fn is_foreign_item(&self, item: DefId) -> bool {
-        let tables = self.0.borrow();
-        tables.tcx.is_foreign_item(tables[item])
-    }
-
-    /// Returns the kind of a given foreign item.
-    pub fn foreign_item_kind(&self, def: ForeignDef) -> ForeignItemKind {
-        let mut tables = self.0.borrow_mut();
-        let def_id = tables[def.def_id()];
-        let tcx = tables.tcx;
-        use rustc_hir::def::DefKind;
-        match tcx.def_kind(def_id) {
-            DefKind::Fn => ForeignItemKind::Fn(tables.fn_def(def_id)),
-            DefKind::Static { .. } => ForeignItemKind::Static(tables.static_def(def_id)),
-            DefKind::ForeignTy => ForeignItemKind::Type(
-                tables.intern_ty(rustc_middle::ty::Ty::new_foreign(tcx, def_id)),
-            ),
-            def_kind => unreachable!("Unexpected kind for a foreign item: {:?}", def_kind),
-        }
-    }
-
-    /// Returns the kind of a given algebraic data type.
-    pub fn adt_kind(&self, def: AdtDef) -> AdtKind {
-        let mut tables = self.0.borrow_mut();
-        let tcx = tables.tcx;
-        def.internal(&mut *tables, tcx).adt_kind().stable(&mut *tables)
-    }
-
-    /// Returns if the ADT is a box.
-    pub fn adt_is_box(&self, def: AdtDef) -> bool {
-        let mut tables = self.0.borrow_mut();
-        let tcx = tables.tcx;
-        def.internal(&mut *tables, tcx).is_box()
-    }
-
-    /// Returns whether this ADT is simd.
-    pub fn adt_is_simd(&self, def: AdtDef) -> bool {
-        let mut tables = self.0.borrow_mut();
-        let tcx = tables.tcx;
-        def.internal(&mut *tables, tcx).repr().simd()
-    }
-
-    /// Returns whether this definition is a C string.
-    pub fn adt_is_cstr(&self, def: AdtDef) -> bool {
-        let mut tables = self.0.borrow_mut();
-        let tcx = tables.tcx;
-        let def_id = def.0.internal(&mut *tables, tcx);
-        tables.tcx.is_lang_item(def_id, LangItem::CStr)
-    }
-
-    /// Returns the representation options for this ADT
-    pub fn adt_repr(&self, def: AdtDef) -> ReprOptions {
-        let mut tables = self.0.borrow_mut();
-        let tcx = tables.tcx;
-        def.internal(&mut *tables, tcx).repr().stable(&mut *tables)
-    }
-
-    /// Retrieve the function signature for the given generic arguments.
-    pub fn fn_sig(&self, def: FnDef, args: &GenericArgs) -> PolyFnSig {
-        let mut tables = self.0.borrow_mut();
-        let tcx = tables.tcx;
-        let def_id = def.0.internal(&mut *tables, tcx);
-        let sig =
-            tables.tcx.fn_sig(def_id).instantiate(tables.tcx, args.internal(&mut *tables, tcx));
-        sig.stable(&mut *tables)
-    }
-
-    /// Retrieve the intrinsic definition if the item corresponds one.
-    pub fn intrinsic(&self, def: DefId) -> Option<IntrinsicDef> {
-        let mut tables = self.0.borrow_mut();
-        let tcx = tables.tcx;
-        let def_id = def.internal(&mut *tables, tcx);
-        let intrinsic = tcx.intrinsic_raw(def_id);
-        intrinsic.map(|_| IntrinsicDef(def))
-    }
-
-    /// Retrieve the plain function name of an intrinsic.
-    pub fn intrinsic_name(&self, def: IntrinsicDef) -> Symbol {
-        let mut tables = self.0.borrow_mut();
-        let tcx = tables.tcx;
-        let def_id = def.0.internal(&mut *tables, tcx);
-        tcx.intrinsic(def_id).unwrap().name.to_string()
-    }
-
-    /// Retrieve the closure signature for the given generic arguments.
-    pub fn closure_sig(&self, args: &GenericArgs) -> PolyFnSig {
-        let mut tables = self.0.borrow_mut();
-        let tcx = tables.tcx;
-        let args_ref = args.internal(&mut *tables, tcx);
-        let sig = args_ref.as_closure().sig();
-        sig.stable(&mut *tables)
-    }
-
-    /// The number of variants in this ADT.
-    pub fn adt_variants_len(&self, def: AdtDef) -> usize {
-        let mut tables = self.0.borrow_mut();
-        let tcx = tables.tcx;
-        def.internal(&mut *tables, tcx).variants().len()
-    }
-
-    /// Discriminant for a given variant index of AdtDef
-    pub fn adt_discr_for_variant(&self, adt: AdtDef, variant: VariantIdx) -> Discr {
-        let mut tables = self.0.borrow_mut();
-        let tcx = tables.tcx;
-        let adt = adt.internal(&mut *tables, tcx);
-        let variant = variant.internal(&mut *tables, tcx);
-        adt.discriminant_for_variant(tcx, variant).stable(&mut *tables)
-    }
-
-    /// Discriminant for a given variand index and args of a coroutine
-    pub fn coroutine_discr_for_variant(
-        &self,
-        coroutine: CoroutineDef,
-        args: &GenericArgs,
-        variant: VariantIdx,
-    ) -> Discr {
-        let mut tables = self.0.borrow_mut();
-        let tcx = tables.tcx;
-        let coroutine = coroutine.def_id().internal(&mut *tables, tcx);
-        let args = args.internal(&mut *tables, tcx);
-        let variant = variant.internal(&mut *tables, tcx);
-        args.as_coroutine().discriminant_for_variant(coroutine, tcx, variant).stable(&mut *tables)
-    }
-
-    /// The name of a variant.
-    pub fn variant_name(&self, def: VariantDef) -> Symbol {
-        let mut tables = self.0.borrow_mut();
-        let tcx = tables.tcx;
-        def.internal(&mut *tables, tcx).name.to_string()
-    }
-
-    pub fn variant_fields(&self, def: VariantDef) -> Vec<FieldDef> {
-        let mut tables = self.0.borrow_mut();
-        let tcx = tables.tcx;
-        def.internal(&mut *tables, tcx).fields.iter().map(|f| f.stable(&mut *tables)).collect()
-    }
-
-    /// Evaluate constant as a target usize.
-    pub fn eval_target_usize(&self, cnst: &MirConst) -> Result<u64, Error> {
-        let mut tables = self.0.borrow_mut();
-        let tcx = tables.tcx;
-        let mir_const = cnst.internal(&mut *tables, tcx);
-        mir_const
-            .try_eval_target_usize(tables.tcx, ty::TypingEnv::fully_monomorphized())
-            .ok_or_else(|| Error::new(format!("Const `{cnst:?}` cannot be encoded as u64")))
-    }
-    pub fn eval_target_usize_ty(&self, cnst: &TyConst) -> Result<u64, Error> {
-        let mut tables = self.0.borrow_mut();
-        let tcx = tables.tcx;
-        let mir_const = cnst.internal(&mut *tables, tcx);
-        mir_const
-            .try_to_target_usize(tables.tcx)
-            .ok_or_else(|| Error::new(format!("Const `{cnst:?}` cannot be encoded as u64")))
-    }
-
-    /// Create a new zero-sized constant.
-    pub fn try_new_const_zst(&self, ty: Ty) -> Result<MirConst, Error> {
-        let mut tables = self.0.borrow_mut();
-        let tcx = tables.tcx;
-        let ty_internal = ty.internal(&mut *tables, tcx);
-        let size = tables
-            .tcx
-            .layout_of(ty::TypingEnv::fully_monomorphized().as_query_input(ty_internal))
-            .map_err(|err| {
-                Error::new(format!(
-                    "Cannot create a zero-sized constant for type `{ty_internal}`: {err}"
-                ))
-            })?
-            .size;
-        if size.bytes() != 0 {
-            return Err(Error::new(format!(
-                "Cannot create a zero-sized constant for type `{ty_internal}`: \
-                 Type `{ty_internal}` has {} bytes",
-                size.bytes()
-            )));
-        }
-
-        Ok(mir::Const::Ty(ty_internal, ty::Const::zero_sized(tables.tcx, ty_internal))
-            .stable(&mut *tables))
-    }
-
-    /// Create a new constant that represents the given string value.
-    pub fn new_const_str(&self, value: &str) -> MirConst {
-        let mut tables = self.0.borrow_mut();
-        let tcx = tables.tcx;
-        let ty = ty::Ty::new_static_str(tcx);
-        let bytes = value.as_bytes();
-        let valtree = ty::ValTree::from_raw_bytes(tcx, bytes);
-        let cv = ty::Value { ty, valtree };
-        let val = tcx.valtree_to_const_val(cv);
-        mir::Const::from_value(val, ty).stable(&mut tables)
-    }
-
-    /// Create a new constant that represents the given boolean value.
-    pub fn new_const_bool(&self, value: bool) -> MirConst {
-        let mut tables = self.0.borrow_mut();
-        mir::Const::from_bool(tables.tcx, value).stable(&mut tables)
-    }
-
-    /// Create a new constant that represents the given value.
-    pub fn try_new_const_uint(&self, value: u128, uint_ty: UintTy) -> Result<MirConst, Error> {
-        let mut tables = self.0.borrow_mut();
-        let tcx = tables.tcx;
-        let ty = ty::Ty::new_uint(tcx, uint_ty.internal(&mut *tables, tcx));
-        let size = tables
-            .tcx
-            .layout_of(ty::TypingEnv::fully_monomorphized().as_query_input(ty))
-            .unwrap()
-            .size;
-        let scalar = ScalarInt::try_from_uint(value, size).ok_or_else(|| {
-            Error::new(format!("Value overflow: cannot convert `{value}` to `{ty}`."))
-        })?;
-        Ok(mir::Const::from_scalar(tcx, mir::interpret::Scalar::Int(scalar), ty)
-            .stable(&mut tables))
-    }
-    pub fn try_new_ty_const_uint(
-        &self,
-        value: u128,
-        uint_ty: UintTy,
-    ) -> Result<stable_mir::ty::TyConst, Error> {
-        let mut tables = self.0.borrow_mut();
-        let tcx = tables.tcx;
-        let ty = ty::Ty::new_uint(tcx, uint_ty.internal(&mut *tables, tcx));
-        let size = tables
-            .tcx
-            .layout_of(ty::TypingEnv::fully_monomorphized().as_query_input(ty))
-            .unwrap()
-            .size;
-
-        // We don't use Const::from_bits since it doesn't have any error checking.
-        let scalar = ScalarInt::try_from_uint(value, size).ok_or_else(|| {
-            Error::new(format!("Value overflow: cannot convert `{value}` to `{ty}`."))
-        })?;
-        Ok(ty::Const::new_value(tcx, ValTree::from_scalar_int(tcx, scalar), ty)
-            .stable(&mut *tables))
-    }
-
-    /// Create a new type from the given kind.
-    pub fn new_rigid_ty(&self, kind: RigidTy) -> stable_mir::ty::Ty {
-        let mut tables = self.0.borrow_mut();
-        let tcx = tables.tcx;
-        let internal_kind = kind.internal(&mut *tables, tcx);
-        tables.tcx.mk_ty_from_kind(internal_kind).stable(&mut *tables)
-    }
-
-    /// Create a new box type, `Box<T>`, for the given inner type `T`.
-    pub fn new_box_ty(&self, ty: stable_mir::ty::Ty) -> stable_mir::ty::Ty {
-        let mut tables = self.0.borrow_mut();
-        let tcx = tables.tcx;
-        let inner = ty.internal(&mut *tables, tcx);
-        ty::Ty::new_box(tables.tcx, inner).stable(&mut *tables)
-    }
-
-    /// Returns the type of given crate item.
-    pub fn def_ty(&self, item: stable_mir::DefId) -> stable_mir::ty::Ty {
-        let mut tables = self.0.borrow_mut();
-        let tcx = tables.tcx;
-        tcx.type_of(item.internal(&mut *tables, tcx)).instantiate_identity().stable(&mut *tables)
-    }
-
-    /// Returns the type of given definition instantiated with the given arguments.
-    pub fn def_ty_with_args(
-        &self,
-        item: stable_mir::DefId,
-        args: &GenericArgs,
-    ) -> stable_mir::ty::Ty {
-        let mut tables = self.0.borrow_mut();
-        let tcx = tables.tcx;
-        let args = args.internal(&mut *tables, tcx);
-        let def_ty = tables.tcx.type_of(item.internal(&mut *tables, tcx));
-        tables
-            .tcx
-            .instantiate_and_normalize_erasing_regions(
-                args,
-                ty::TypingEnv::fully_monomorphized(),
-                def_ty,
-            )
-            .stable(&mut *tables)
-    }
-
-    /// Returns literal value of a const as a string.
-    pub fn mir_const_pretty(&self, cnst: &stable_mir::ty::MirConst) -> String {
-        let mut tables = self.0.borrow_mut();
-        let tcx = tables.tcx;
-        cnst.internal(&mut *tables, tcx).to_string()
-    }
-
-    /// `Span` of an item.
-    pub 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)
-    }
-
-    /// Obtain the representation of a type.
-    pub fn ty_pretty(&self, ty: stable_mir::ty::Ty) -> String {
-        let tables = self.0.borrow_mut();
-        tables.types[ty].to_string()
-    }
-
-    /// Obtain the representation of a type.
-    pub fn ty_kind(&self, ty: stable_mir::ty::Ty) -> TyKind {
-        let mut tables = self.0.borrow_mut();
-        tables.types[ty].kind().stable(&mut *tables)
-    }
-
-    pub fn ty_const_pretty(&self, ct: stable_mir::ty::TyConstId) -> String {
-        let tables = self.0.borrow_mut();
-        tables.ty_consts[ct].to_string()
-    }
-
-    /// Get the discriminant Ty for this Ty if there's one.
-    pub fn rigid_ty_discriminant_ty(&self, ty: &RigidTy) -> stable_mir::ty::Ty {
-        let mut tables = self.0.borrow_mut();
-        let tcx = tables.tcx;
-        let internal_kind = ty.internal(&mut *tables, tcx);
-        let internal_ty = tables.tcx.mk_ty_from_kind(internal_kind);
-        internal_ty.discriminant_ty(tables.tcx).stable(&mut *tables)
-    }
-
-    /// Get the body of an Instance which is already monomorphized.
-    pub fn instance_body(&self, def: InstanceDef) -> Option<Body> {
-        let mut tables = self.0.borrow_mut();
-        let instance = tables.instances[def];
-        tables
-            .instance_has_body(instance)
-            .then(|| BodyBuilder::new(tables.tcx, instance).build(&mut *tables))
-    }
-
-    /// Get the instance type with generic instantiations applied and lifetimes erased.
-    pub fn instance_ty(&self, def: InstanceDef) -> stable_mir::ty::Ty {
-        let mut tables = self.0.borrow_mut();
-        let instance = tables.instances[def];
-        assert!(!instance.has_non_region_param(), "{instance:?} needs further instantiation");
-        instance.ty(tables.tcx, ty::TypingEnv::fully_monomorphized()).stable(&mut *tables)
-    }
-
-    /// Get the instantiation types.
-    pub fn instance_args(&self, def: InstanceDef) -> GenericArgs {
-        let mut tables = self.0.borrow_mut();
-        let instance = tables.instances[def];
-        instance.args.stable(&mut *tables)
-    }
-
-    /// Get an instance ABI.
-    pub fn instance_abi(&self, def: InstanceDef) -> Result<FnAbi, Error> {
-        let mut tables = self.0.borrow_mut();
-        let instance = tables.instances[def];
-        Ok(tables.fn_abi_of_instance(instance, List::empty())?.stable(&mut *tables))
-    }
-
-    /// Get the ABI of a function pointer.
-    pub fn fn_ptr_abi(&self, fn_ptr: PolyFnSig) -> Result<FnAbi, Error> {
-        let mut tables = self.0.borrow_mut();
-        let tcx = tables.tcx;
-        let sig = fn_ptr.internal(&mut *tables, tcx);
-        Ok(tables.fn_abi_of_fn_ptr(sig, List::empty())?.stable(&mut *tables))
-    }
-
-    /// Get the instance.
-    pub 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)
-    }
-
-    /// Get the instance mangled name.
-    pub 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()
-    }
-
-    /// Check if this is an empty DropGlue shim.
-    pub fn is_empty_drop_shim(&self, def: InstanceDef) -> bool {
-        let tables = self.0.borrow_mut();
-        let instance = tables.instances[def];
-        matches!(instance.def, ty::InstanceKind::DropGlue(_, None))
-    }
-
-    /// Convert a non-generic crate item into an instance.
-    /// This function will panic if the item is generic.
-    pub fn mono_instance(&self, def_id: stable_mir::DefId) -> stable_mir::mir::mono::Instance {
-        let mut tables = self.0.borrow_mut();
-        let def_id = tables[def_id];
-        Instance::mono(tables.tcx, def_id).stable(&mut *tables)
-    }
-
-    /// Item requires monomorphization.
-    pub 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
-    }
-
-    /// Resolve an instance from the given function definition and generic arguments.
-    pub 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 tcx = tables.tcx;
-        let def_id = def.0.internal(&mut *tables, tcx);
-        let args_ref = args.internal(&mut *tables, tcx);
-        match Instance::try_resolve(
-            tables.tcx,
-            ty::TypingEnv::fully_monomorphized(),
-            def_id,
-            args_ref,
-        ) {
-            Ok(Some(instance)) => Some(instance.stable(&mut *tables)),
-            Ok(None) | Err(_) => None,
-        }
-    }
-
-    /// Resolve an instance for drop_in_place for the given type.
-    pub fn resolve_drop_in_place(&self, ty: stable_mir::ty::Ty) -> stable_mir::mir::mono::Instance {
-        let mut tables = self.0.borrow_mut();
-        let tcx = tables.tcx;
-        let internal_ty = ty.internal(&mut *tables, tcx);
-        let instance = Instance::resolve_drop_in_place(tables.tcx, internal_ty);
-        instance.stable(&mut *tables)
-    }
-
-    /// Resolve instance for a function pointer.
-    pub fn resolve_for_fn_ptr(
-        &self,
-        def: FnDef,
-        args: &GenericArgs,
-    ) -> Option<stable_mir::mir::mono::Instance> {
-        let mut tables = self.0.borrow_mut();
-        let tcx = tables.tcx;
-        let def_id = def.0.internal(&mut *tables, tcx);
-        let args_ref = args.internal(&mut *tables, tcx);
-        Instance::resolve_for_fn_ptr(
-            tables.tcx,
-            ty::TypingEnv::fully_monomorphized(),
-            def_id,
-            args_ref,
-        )
-        .stable(&mut *tables)
-    }
-
-    /// Resolve instance for a closure with the requested type.
-    pub fn resolve_closure(
-        &self,
-        def: ClosureDef,
-        args: &GenericArgs,
-        kind: ClosureKind,
-    ) -> Option<stable_mir::mir::mono::Instance> {
-        let mut tables = self.0.borrow_mut();
-        let tcx = tables.tcx;
-        let def_id = def.0.internal(&mut *tables, tcx);
-        let args_ref = args.internal(&mut *tables, tcx);
-        let closure_kind = kind.internal(&mut *tables, tcx);
-        Some(
-            Instance::resolve_closure(tables.tcx, def_id, args_ref, closure_kind)
-                .stable(&mut *tables),
-        )
-    }
-
-    /// Try to evaluate an instance into a constant.
-    pub fn eval_instance(&self, def: InstanceDef, const_ty: Ty) -> Result<Allocation, Error> {
-        let mut tables = self.0.borrow_mut();
-        let instance = tables.instances[def];
-        let tcx = tables.tcx;
-        let result = tcx.const_eval_instance(
-            ty::TypingEnv::fully_monomorphized(),
-            instance,
-            tcx.def_span(instance.def_id()),
-        );
-        result
-            .map(|const_val| {
-                alloc::try_new_allocation(
-                    const_ty.internal(&mut *tables, tcx),
-                    const_val,
-                    &mut *tables,
-                )
-            })
-            .map_err(|e| e.stable(&mut *tables))?
-    }
-
-    /// Evaluate a static's initializer.
-    pub fn eval_static_initializer(&self, def: StaticDef) -> Result<Allocation, Error> {
-        let mut tables = self.0.borrow_mut();
-        let tcx = tables.tcx;
-        let def_id = def.0.internal(&mut *tables, tcx);
-        tables.tcx.eval_static_initializer(def_id).stable(&mut *tables)
-    }
-
-    /// Retrieve global allocation for the given allocation ID.
-    pub fn global_alloc(&self, alloc: stable_mir::mir::alloc::AllocId) -> GlobalAlloc {
-        let mut tables = self.0.borrow_mut();
-        let tcx = tables.tcx;
-        let alloc_id = alloc.internal(&mut *tables, tcx);
-        tables.tcx.global_alloc(alloc_id).stable(&mut *tables)
-    }
-
-    /// Retrieve the id for the virtual table.
-    pub 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 tcx = tables.tcx;
-        let alloc_id = tables.tcx.vtable_allocation((
-            ty.internal(&mut *tables, tcx),
-            trait_ref
-                .internal(&mut *tables, tcx)
-                .map(|principal| tcx.instantiate_bound_regions_with_erased(principal)),
-        ));
-        Some(alloc_id.stable(&mut *tables))
-    }
-
-    pub 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`.
-    pub 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)
-            )
-        }
-    }
-
-    /// Get the layout of a type.
-    pub fn ty_layout(&self, ty: Ty) -> Result<Layout, Error> {
-        let mut tables = self.0.borrow_mut();
-        let tcx = tables.tcx;
-        let ty = ty.internal(&mut *tables, tcx);
-        let layout = tables.layout_of(ty)?.layout;
-        Ok(layout.stable(&mut *tables))
-    }
-
-    /// Get the layout shape.
-    pub fn layout_shape(&self, id: Layout) -> LayoutShape {
-        let mut tables = self.0.borrow_mut();
-        let tcx = tables.tcx;
-        id.internal(&mut *tables, tcx).0.stable(&mut *tables)
-    }
-
-    /// Get a debug string representation of a place.
-    pub fn place_pretty(&self, place: &Place) -> String {
-        let mut tables = self.0.borrow_mut();
-        let tcx = tables.tcx;
-        format!("{:?}", place.internal(&mut *tables, tcx))
-    }
-
-    /// Get the resulting type of binary operation.
-    pub fn binop_ty(&self, bin_op: BinOp, rhs: Ty, lhs: Ty) -> Ty {
-        let mut tables = self.0.borrow_mut();
-        let tcx = tables.tcx;
-        let rhs_internal = rhs.internal(&mut *tables, tcx);
-        let lhs_internal = lhs.internal(&mut *tables, tcx);
-        let ty = bin_op.internal(&mut *tables, tcx).ty(tcx, rhs_internal, lhs_internal);
-        ty.stable(&mut *tables)
-    }
-
-    /// Get the resulting type of unary operation.
-    pub fn unop_ty(&self, un_op: UnOp, arg: Ty) -> Ty {
-        let mut tables = self.0.borrow_mut();
-        let tcx = tables.tcx;
-        let arg_internal = arg.internal(&mut *tables, tcx);
-        let ty = un_op.internal(&mut *tables, tcx).ty(tcx, arg_internal);
-        ty.stable(&mut *tables)
-    }
-
-    /// Get all associated items of a definition.
-    pub fn associated_items(&self, def_id: stable_mir::DefId) -> stable_mir::AssocItems {
-        let mut tables = self.0.borrow_mut();
-        let tcx = tables.tcx;
-        let def_id = tables[def_id];
-        let assoc_items = if tcx.is_trait_alias(def_id) {
-            Vec::new()
-        } else {
-            tcx.associated_item_def_ids(def_id)
-                .iter()
-                .map(|did| tcx.associated_item(*did).stable(&mut *tables))
-                .collect()
-        };
-        assoc_items
-    }
-}
-
-/// Implement error handling for extracting function ABI information.
-impl<'tcx> FnAbiOfHelpers<'tcx> for Tables<'tcx> {
-    type FnAbiOfResult = Result<&'tcx rustc_target::callconv::FnAbi<'tcx, ty::Ty<'tcx>>, Error>;
-
-    #[inline]
-    fn handle_fn_abi_err(
-        &self,
-        err: ty::layout::FnAbiError<'tcx>,
-        _span: rustc_span::Span,
-        fn_abi_request: ty::layout::FnAbiRequest<'tcx>,
-    ) -> Error {
-        Error::new(format!("Failed to get ABI for `{fn_abi_request:?}`: {err:?}"))
-    }
-}
-
-impl<'tcx> LayoutOfHelpers<'tcx> for Tables<'tcx> {
-    type LayoutOfResult = Result<ty::layout::TyAndLayout<'tcx>, Error>;
-
-    #[inline]
-    fn handle_layout_err(
-        &self,
-        err: ty::layout::LayoutError<'tcx>,
-        _span: rustc_span::Span,
-        ty: ty::Ty<'tcx>,
-    ) -> Error {
-        Error::new(format!("Failed to get layout for `{ty}`: {err}"))
-    }
-}
-
-impl<'tcx> HasTypingEnv<'tcx> for Tables<'tcx> {
-    fn typing_env(&self) -> ty::TypingEnv<'tcx> {
-        ty::TypingEnv::fully_monomorphized()
-    }
-}
-
-impl<'tcx> HasTyCtxt<'tcx> for Tables<'tcx> {
-    fn tcx(&self) -> TyCtxt<'tcx> {
-        self.tcx
-    }
-}
-
-impl<'tcx> HasDataLayout for Tables<'tcx> {
-    fn data_layout(&self) -> &rustc_abi::TargetDataLayout {
-        self.tcx.data_layout()
-    }
-}
diff --git a/compiler/rustc_smir/src/rustc_smir/context/impls.rs b/compiler/rustc_smir/src/rustc_smir/context/impls.rs
new file mode 100644
index 00000000000..77a2f879d6a
--- /dev/null
+++ b/compiler/rustc_smir/src/rustc_smir/context/impls.rs
@@ -0,0 +1,772 @@
+//! Implementation of StableMIR Context.
+
+#![allow(rustc::usage_of_qualified_ty)]
+
+use std::iter;
+
+use rustc_abi::{Endian, Layout};
+use rustc_hir::def::DefKind;
+use rustc_hir::{Attribute, LangItem};
+use rustc_middle::infer::canonical::ir::{
+    Binder, EarlyBinder, ExistentialTraitRef, FnSig, TraitRef,
+};
+use rustc_middle::mir::interpret::{AllocId, ConstAllocation, ErrorHandled, GlobalAlloc, Scalar};
+use rustc_middle::mir::{BinOp, Body, Const as MirConst, ConstValue, UnOp};
+use rustc_middle::ty::layout::{FnAbiOf, LayoutOf};
+use rustc_middle::ty::print::{with_forced_trimmed_paths, with_no_trimmed_paths};
+use rustc_middle::ty::{
+    AdtDef, AdtKind, AssocItem, ClosureKind, GenericArgsRef, GenericPredicates, Instance,
+    InstanceKind, IntrinsicDef, List, PolyFnSig, ScalarInt, TraitDef, Ty, TyCtxt, TyKind,
+    TypeVisitableExt, UintTy, ValTree, VariantDef,
+};
+use rustc_middle::{mir, ty};
+use rustc_session::cstore::ForeignModule;
+use rustc_span::def_id::{CrateNum, DefId, LOCAL_CRATE};
+use rustc_span::{FileNameDisplayPreference, Span, Symbol};
+use rustc_target::callconv::FnAbi;
+
+use super::{
+    SmirAllocRange, SmirCtxt, SmirExistentialProjection, SmirExistentialTraitRef, SmirRegion,
+    SmirTraitRef, SmirTy, SmirTypingEnv,
+};
+use crate::rustc_smir::builder::BodyBuilder;
+use crate::rustc_smir::{Bridge, SmirError, Tables, filter_def_ids};
+
+impl<'tcx, B: Bridge> SmirExistentialProjection<'tcx> for SmirCtxt<'tcx, B> {
+    fn new_from_args(
+        &self,
+        def_id: rustc_span::def_id::DefId,
+        args: ty::GenericArgsRef<'tcx>,
+        term: ty::Term<'tcx>,
+    ) -> ty::ExistentialProjection<'tcx> {
+        ty::ExistentialProjection::new_from_args(self.tcx, def_id, args, term)
+    }
+}
+
+impl<'tcx, B: Bridge> SmirExistentialTraitRef<'tcx> for SmirCtxt<'tcx, B> {
+    fn new_from_args(
+        &self,
+        trait_def_id: DefId,
+        args: ty::GenericArgsRef<'tcx>,
+    ) -> ty::ExistentialTraitRef<'tcx> {
+        ty::ExistentialTraitRef::new_from_args(self.tcx, trait_def_id, args)
+    }
+}
+
+impl<'tcx, B: Bridge> SmirTraitRef<'tcx> for SmirCtxt<'tcx, B> {
+    fn new_from_args(
+        &self,
+        trait_def_id: DefId,
+        args: ty::GenericArgsRef<'tcx>,
+    ) -> ty::TraitRef<'tcx> {
+        ty::TraitRef::new_from_args(self.tcx, trait_def_id, args)
+    }
+}
+
+impl<'tcx, B: Bridge> SmirTy<'tcx> for SmirCtxt<'tcx, B> {
+    fn new_foreign(&self, def_id: DefId) -> ty::Ty<'tcx> {
+        ty::Ty::new_foreign(self.tcx, def_id)
+    }
+}
+
+impl<'tcx, B: Bridge> SmirTypingEnv<'tcx> for SmirCtxt<'tcx, B> {
+    fn fully_monomorphized(&self) -> ty::TypingEnv<'tcx> {
+        ty::TypingEnv::fully_monomorphized()
+    }
+}
+
+impl<'tcx, B: Bridge> SmirAllocRange<'tcx> for SmirCtxt<'tcx, B> {
+    fn alloc_range(
+        &self,
+        offset: rustc_abi::Size,
+        size: rustc_abi::Size,
+    ) -> mir::interpret::AllocRange {
+        rustc_middle::mir::interpret::alloc_range(offset, size)
+    }
+}
+
+impl<'tcx, B: Bridge> SmirRegion<'tcx> for SmirCtxt<'tcx, B> {
+    fn lifetimes_re_erased(&self) -> ty::Region<'tcx> {
+        self.tcx.lifetimes.re_erased
+    }
+}
+
+impl<'tcx, B: Bridge> SmirCtxt<'tcx, B> {
+    pub fn lift<T: ty::Lift<TyCtxt<'tcx>>>(&self, value: T) -> Option<T::Lifted> {
+        self.tcx.lift(value)
+    }
+
+    pub fn mk_args_from_iter<I, T>(&self, iter: I) -> T::Output
+    where
+        I: Iterator<Item = T>,
+        T: ty::CollectAndApply<ty::GenericArg<'tcx>, ty::GenericArgsRef<'tcx>>,
+    {
+        self.tcx.mk_args_from_iter(iter)
+    }
+
+    pub fn mk_pat(&self, v: ty::PatternKind<'tcx>) -> ty::Pattern<'tcx> {
+        self.tcx.mk_pat(v)
+    }
+
+    pub fn mk_poly_existential_predicates(
+        &self,
+        eps: &[ty::PolyExistentialPredicate<'tcx>],
+    ) -> &'tcx List<ty::PolyExistentialPredicate<'tcx>> {
+        self.tcx.mk_poly_existential_predicates(eps)
+    }
+
+    pub fn mk_type_list(&self, v: &[Ty<'tcx>]) -> &'tcx List<Ty<'tcx>> {
+        self.tcx.mk_type_list(v)
+    }
+
+    pub fn mk_bound_variable_kinds_from_iter<I, T>(&self, iter: I) -> T::Output
+    where
+        I: Iterator<Item = T>,
+        T: ty::CollectAndApply<ty::BoundVariableKind, &'tcx List<ty::BoundVariableKind>>,
+    {
+        self.tcx.mk_bound_variable_kinds_from_iter(iter)
+    }
+
+    pub fn mk_place_elems(&self, v: &[mir::PlaceElem<'tcx>]) -> &'tcx List<mir::PlaceElem<'tcx>> {
+        self.tcx.mk_place_elems(v)
+    }
+
+    pub fn adt_def(&self, def_id: DefId) -> AdtDef<'tcx> {
+        self.tcx.adt_def(def_id)
+    }
+
+    pub fn coroutine_movability(&self, def_id: DefId) -> ty::Movability {
+        self.tcx.coroutine_movability(def_id)
+    }
+
+    pub fn valtree_to_const_val(&self, key: ty::Value<'tcx>) -> ConstValue<'tcx> {
+        self.tcx.valtree_to_const_val(key)
+    }
+
+    pub fn target_endian(&self) -> Endian {
+        self.tcx.data_layout.endian
+    }
+
+    pub fn target_pointer_size(&self) -> usize {
+        self.tcx.data_layout.pointer_size.bits().try_into().unwrap()
+    }
+
+    pub fn entry_fn(&self) -> Option<DefId> {
+        Some(self.tcx.entry_fn(())?.0)
+    }
+
+    /// Retrieve all items of the local crate that have a MIR associated with them.
+    pub fn all_local_items(&self) -> Vec<DefId> {
+        self.tcx.mir_keys(()).iter().map(|item| item.to_def_id()).collect()
+    }
+
+    /// Retrieve the body of a function.
+    /// This function will panic if the body is not available.
+    pub fn mir_body(&self, item: DefId) -> &'tcx Body<'tcx> {
+        self.tcx.instance_mir(InstanceKind::Item(item))
+    }
+
+    /// Check whether the body of a function is available.
+    pub fn has_body(&self, def: DefId, tables: &mut Tables<'_, B>) -> bool {
+        tables.item_has_body(def)
+    }
+
+    pub fn foreign_modules(&self, crate_num: CrateNum) -> Vec<DefId> {
+        self.tcx.foreign_modules(crate_num).keys().map(|mod_def_id| *mod_def_id).collect()
+    }
+
+    /// Retrieve all functions defined in this crate.
+    pub fn crate_functions(&self, crate_num: CrateNum, tables: &mut Tables<'_, B>) -> Vec<DefId> {
+        filter_def_ids(self.tcx, crate_num, |def_id| tables.filter_fn_def(def_id))
+    }
+
+    /// Retrieve all static items defined in this crate.
+    pub fn crate_statics(&self, crate_num: CrateNum, tables: &mut Tables<'_, B>) -> Vec<DefId> {
+        filter_def_ids(self.tcx, crate_num, |def_id| tables.filter_static_def(def_id))
+    }
+
+    pub fn foreign_module(&self, mod_def: DefId) -> &ForeignModule {
+        self.tcx.foreign_modules(mod_def.krate).get(&mod_def).unwrap()
+    }
+
+    pub fn foreign_items(&self, mod_def: DefId) -> Vec<DefId> {
+        self.tcx
+            .foreign_modules(mod_def.krate)
+            .get(&mod_def)
+            .unwrap()
+            .foreign_items
+            .iter()
+            .map(|item_def| *item_def)
+            .collect()
+    }
+
+    pub fn all_trait_decls(&self) -> impl Iterator<Item = DefId> {
+        self.tcx.all_traits_including_private()
+    }
+
+    pub fn trait_decls(&self, crate_num: CrateNum) -> Vec<DefId> {
+        self.tcx.traits(crate_num).iter().map(|trait_def_id| *trait_def_id).collect()
+    }
+
+    pub fn trait_decl(&self, trait_def: DefId) -> &'tcx TraitDef {
+        self.tcx.trait_def(trait_def)
+    }
+
+    pub fn all_trait_impls(&self) -> Vec<DefId> {
+        iter::once(LOCAL_CRATE)
+            .chain(self.tcx.crates(()).iter().copied())
+            .flat_map(|cnum| self.tcx.trait_impls_in_crate(cnum).iter())
+            .map(|impl_def_id| *impl_def_id)
+            .collect()
+    }
+
+    pub fn trait_impls(&self, crate_num: CrateNum) -> Vec<DefId> {
+        self.tcx.trait_impls_in_crate(crate_num).iter().map(|impl_def_id| *impl_def_id).collect()
+    }
+
+    pub fn trait_impl(&self, impl_def: DefId) -> EarlyBinder<TyCtxt<'tcx>, TraitRef<TyCtxt<'tcx>>> {
+        self.tcx.impl_trait_ref(impl_def).unwrap()
+    }
+
+    pub fn generics_of(&self, def_id: DefId) -> &'tcx ty::Generics {
+        self.tcx.generics_of(def_id)
+    }
+
+    pub fn predicates_of(&self, def_id: DefId) -> GenericPredicates<'tcx> {
+        self.tcx.predicates_of(def_id)
+    }
+
+    pub fn explicit_predicates_of(&self, def_id: DefId) -> GenericPredicates<'tcx> {
+        self.tcx.explicit_predicates_of(def_id)
+    }
+
+    pub fn crate_name(&self, crate_num: CrateNum) -> String {
+        self.tcx.crate_name(crate_num).to_string()
+    }
+
+    pub fn crate_is_local(&self, crate_num: CrateNum) -> bool {
+        crate_num == LOCAL_CRATE
+    }
+
+    pub fn crate_num_id(&self, crate_num: CrateNum) -> usize {
+        crate_num.into()
+    }
+
+    pub fn local_crate_num(&self) -> CrateNum {
+        LOCAL_CRATE
+    }
+
+    /// Retrieve a list of all external crates.
+    pub fn external_crates(&self) -> Vec<CrateNum> {
+        self.tcx.crates(()).iter().map(|crate_num| *crate_num).collect()
+    }
+
+    /// Find a crate with the given name.
+    pub fn find_crates(&self, name: &str) -> Vec<CrateNum> {
+        let crates: Vec<CrateNum> = [LOCAL_CRATE]
+            .iter()
+            .chain(self.tcx.crates(()).iter())
+            .filter_map(|crate_num| {
+                let crate_name = self.tcx.crate_name(*crate_num).to_string();
+                (name == crate_name).then(|| *crate_num)
+            })
+            .collect();
+        crates
+    }
+
+    /// Returns the name of given `DefId`.
+    pub fn def_name(&self, def_id: DefId, trimmed: bool) -> String {
+        if trimmed {
+            with_forced_trimmed_paths!(self.tcx.def_path_str(def_id))
+        } else {
+            with_no_trimmed_paths!(self.tcx.def_path_str(def_id))
+        }
+    }
+
+    /// Return registered tool attributes with the given attribute name.
+    ///
+    /// FIXME(jdonszelmann): may panic on non-tool attributes. After more attribute work, non-tool
+    /// attributes will simply return an empty list.
+    ///
+    /// Single segmented name like `#[clippy]` is specified as `&["clippy".to_string()]`.
+    /// Multi-segmented name like `#[rustfmt::skip]` is specified as `&["rustfmt".to_string(), "skip".to_string()]`.
+    pub fn tool_attrs(&self, def_id: DefId, attr: &[String]) -> Vec<(String, Span)> {
+        let attr_name: Vec<_> = attr.iter().map(|seg| Symbol::intern(&seg)).collect();
+        self.tcx
+            .get_attrs_by_path(def_id, &attr_name)
+            .filter_map(|attribute| {
+                if let Attribute::Unparsed(u) = attribute {
+                    let attr_str = rustc_hir_pretty::attribute_to_string(&self.tcx, attribute);
+                    Some((attr_str, u.span))
+                } else {
+                    None
+                }
+            })
+            .collect()
+    }
+
+    /// Get all tool attributes of a definition.
+    pub fn all_tool_attrs(&self, did: DefId) -> Vec<(String, Span)> {
+        let attrs_iter = if let Some(did) = did.as_local() {
+            self.tcx.hir_attrs(self.tcx.local_def_id_to_hir_id(did)).iter()
+        } else {
+            self.tcx.attrs_for_def(did).iter()
+        };
+        attrs_iter
+            .filter_map(|attribute| {
+                if let Attribute::Unparsed(u) = attribute {
+                    let attr_str = rustc_hir_pretty::attribute_to_string(&self.tcx, attribute);
+                    Some((attr_str, u.span))
+                } else {
+                    None
+                }
+            })
+            .collect()
+    }
+
+    /// Returns printable, human readable form of `Span`.
+    pub fn span_to_string(&self, span: Span) -> String {
+        self.tcx.sess.source_map().span_to_diagnostic_string(span)
+    }
+
+    /// Return filename from given `Span`, for diagnostic purposes.
+    pub fn get_filename(&self, span: Span) -> String {
+        self.tcx
+            .sess
+            .source_map()
+            .span_to_filename(span)
+            .display(FileNameDisplayPreference::Local)
+            .to_string()
+    }
+
+    /// Return lines corresponding to this `Span`.
+    pub fn get_lines(&self, span: Span) -> (usize, usize, usize, usize) {
+        let lines = &self.tcx.sess.source_map().span_to_location_info(span);
+        (lines.1, lines.2, lines.3, lines.4)
+    }
+
+    /// Returns the `kind` of given `DefId`.
+    pub fn def_kind(&self, item: DefId) -> DefKind {
+        self.tcx.def_kind(item)
+    }
+
+    /// Returns whether this is a foreign item.
+    pub fn is_foreign_item(&self, item: DefId) -> bool {
+        self.tcx.is_foreign_item(item)
+    }
+
+    /// Returns the kind of a given foreign item.
+    pub fn foreign_item_kind(&self, def_id: DefId) -> DefKind {
+        self.tcx.def_kind(def_id)
+    }
+
+    /// Returns the kind of a given algebraic data type.
+    pub fn adt_kind(&self, def: AdtDef<'tcx>) -> AdtKind {
+        def.adt_kind()
+    }
+
+    /// Returns if the ADT is a box.
+    pub fn adt_is_box(&self, def: AdtDef<'tcx>) -> bool {
+        def.is_box()
+    }
+
+    /// Returns whether this ADT is simd.
+    pub fn adt_is_simd(&self, def: AdtDef<'tcx>) -> bool {
+        def.repr().simd()
+    }
+
+    /// Returns whether this definition is a C string.
+    pub fn adt_is_cstr(&self, def_id: DefId) -> bool {
+        self.tcx.is_lang_item(def_id, LangItem::CStr)
+    }
+
+    /// Retrieve the function signature for the given generic arguments.
+    pub fn fn_sig(
+        &self,
+        def_id: DefId,
+        args_ref: GenericArgsRef<'tcx>,
+    ) -> Binder<TyCtxt<'tcx>, FnSig<TyCtxt<'tcx>>> {
+        let sig = self.tcx.fn_sig(def_id).instantiate(self.tcx, args_ref);
+        sig
+    }
+
+    /// Retrieve the intrinsic definition if the item corresponds one.
+    pub fn intrinsic(&self, def_id: DefId) -> Option<IntrinsicDef> {
+        let intrinsic = self.tcx.intrinsic_raw(def_id);
+        intrinsic
+    }
+
+    /// Retrieve the plain function name of an intrinsic.
+    pub fn intrinsic_name(&self, def_id: DefId) -> String {
+        self.tcx.intrinsic(def_id).unwrap().name.to_string()
+    }
+
+    /// Retrieve the closure signature for the given generic arguments.
+    pub fn closure_sig(
+        &self,
+        args_ref: GenericArgsRef<'tcx>,
+    ) -> Binder<TyCtxt<'tcx>, FnSig<TyCtxt<'tcx>>> {
+        args_ref.as_closure().sig()
+    }
+
+    /// The number of variants in this ADT.
+    pub fn adt_variants_len(&self, def: AdtDef<'tcx>) -> usize {
+        def.variants().len()
+    }
+
+    /// The name of a variant.
+    pub fn variant_name(&self, def: &'tcx VariantDef) -> String {
+        def.name.to_string()
+    }
+
+    /// Evaluate constant as a target usize.
+    pub fn eval_target_usize(&self, cnst: MirConst<'tcx>) -> Result<u64, B::Error> {
+        use crate::rustc_smir::context::SmirTypingEnv;
+        cnst.try_eval_target_usize(self.tcx, self.fully_monomorphized())
+            .ok_or_else(|| B::Error::new(format!("Const `{cnst:?}` cannot be encoded as u64")))
+    }
+
+    pub fn eval_target_usize_ty(&self, cnst: ty::Const<'tcx>) -> Result<u64, B::Error> {
+        cnst.try_to_target_usize(self.tcx)
+            .ok_or_else(|| B::Error::new(format!("Const `{cnst:?}` cannot be encoded as u64")))
+    }
+
+    pub(crate) fn try_new_const_zst(
+        &self,
+        ty_internal: Ty<'tcx>,
+    ) -> Result<MirConst<'tcx>, B::Error> {
+        let size = self
+            .tcx
+            .layout_of(self.fully_monomorphized().as_query_input(ty_internal))
+            .map_err(|err| {
+                B::Error::new(format!(
+                    "Cannot create a zero-sized constant for type `{ty_internal}`: {err}"
+                ))
+            })?
+            .size;
+        if size.bytes() != 0 {
+            return Err(B::Error::new(format!(
+                "Cannot create a zero-sized constant for type `{ty_internal}`: \
+                Type `{ty_internal}` has {} bytes",
+                size.bytes()
+            )));
+        }
+
+        Ok(MirConst::Ty(ty_internal, self.const_zero_sized(ty_internal)))
+    }
+
+    pub fn const_zero_sized(&self, ty_internal: Ty<'tcx>) -> ty::Const<'tcx> {
+        ty::Const::zero_sized(self.tcx, ty_internal)
+    }
+
+    /// Create a new constant that represents the given string value.
+    pub fn new_const_str(&self, value: &str) -> MirConst<'tcx> {
+        let ty = Ty::new_static_str(self.tcx);
+        let bytes = value.as_bytes();
+        let valtree = ValTree::from_raw_bytes(self.tcx, bytes);
+        let cv = ty::Value { ty, valtree };
+        let val = self.tcx.valtree_to_const_val(cv);
+        MirConst::from_value(val, ty)
+    }
+
+    /// Create a new constant that represents the given boolean value.
+    pub fn new_const_bool(&self, value: bool) -> MirConst<'tcx> {
+        MirConst::from_bool(self.tcx, value)
+    }
+
+    pub fn try_new_const_uint(
+        &self,
+        value: u128,
+        ty_internal: Ty<'tcx>,
+    ) -> Result<MirConst<'tcx>, B::Error> {
+        let size = self
+            .tcx
+            .layout_of(self.fully_monomorphized().as_query_input(ty_internal))
+            .unwrap()
+            .size;
+        let scalar = ScalarInt::try_from_uint(value, size).ok_or_else(|| {
+            B::Error::new(format!("Value overflow: cannot convert `{value}` to `{ty_internal}`."))
+        })?;
+        Ok(self.mir_const_from_scalar(Scalar::Int(scalar), ty_internal))
+    }
+
+    pub fn try_new_ty_const_uint(
+        &self,
+        value: u128,
+        ty_internal: Ty<'tcx>,
+    ) -> Result<ty::Const<'tcx>, B::Error> {
+        let size = self
+            .tcx
+            .layout_of(self.fully_monomorphized().as_query_input(ty_internal))
+            .unwrap()
+            .size;
+        let scalar = ScalarInt::try_from_uint(value, size).ok_or_else(|| {
+            B::Error::new(format!("Value overflow: cannot convert `{value}` to `{ty_internal}`."))
+        })?;
+
+        Ok(self.ty_const_new_value(ValTree::from_scalar_int(self.tcx, scalar), ty_internal))
+    }
+
+    pub fn ty_new_uint(&self, ty: UintTy) -> Ty<'tcx> {
+        Ty::new_uint(self.tcx, ty)
+    }
+
+    pub fn mir_const_from_scalar(&self, s: Scalar, ty: Ty<'tcx>) -> MirConst<'tcx> {
+        MirConst::from_scalar(self.tcx, s, ty)
+    }
+
+    pub fn ty_const_new_value(&self, valtree: ValTree<'tcx>, ty: Ty<'tcx>) -> ty::Const<'tcx> {
+        ty::Const::new_value(self.tcx, valtree, ty)
+    }
+
+    pub fn ty_valtree_from_scalar_int(&self, i: ScalarInt) -> ValTree<'tcx> {
+        ValTree::from_scalar_int(self.tcx, i)
+    }
+
+    /// Create a new type from the given kind.
+    pub fn new_rigid_ty(&self, internal_kind: TyKind<'tcx>) -> Ty<'tcx> {
+        self.tcx.mk_ty_from_kind(internal_kind)
+    }
+
+    /// Create a new box type, `Box<T>`, for the given inner type `T`.
+    pub fn new_box_ty(&self, ty: Ty<'tcx>) -> Ty<'tcx> {
+        ty::Ty::new_box(self.tcx, ty)
+    }
+
+    /// Returns the type of given crate item.
+    pub fn def_ty(&self, item: DefId) -> Ty<'tcx> {
+        self.tcx.type_of(item).instantiate_identity()
+    }
+
+    /// Returns the type of given definition instantiated with the given arguments.
+    pub fn def_ty_with_args(&self, item: DefId, args_ref: GenericArgsRef<'tcx>) -> Ty<'tcx> {
+        let def_ty = self.tcx.type_of(item);
+        self.tcx.instantiate_and_normalize_erasing_regions(
+            args_ref,
+            self.fully_monomorphized(),
+            def_ty,
+        )
+    }
+
+    /// `Span` of an item.
+    pub fn span_of_an_item(&self, def_id: DefId) -> Span {
+        self.tcx.def_span(def_id)
+    }
+
+    pub fn ty_const_pretty(&self, ct: ty::Const<'tcx>) -> String {
+        ct.to_string()
+    }
+
+    /// Obtain the representation of a type.
+    pub fn ty_pretty(&self, ty: Ty<'tcx>) -> String {
+        ty.to_string()
+    }
+
+    /// Obtain the kind of a type.
+    pub fn ty_kind(&self, ty: Ty<'tcx>) -> &'tcx TyKind<'tcx> {
+        ty.kind()
+    }
+
+    /// Get the discriminant Ty for this Ty if there's one.
+    pub fn rigid_ty_discriminant_ty(&self, internal_kind: TyKind<'tcx>) -> Ty<'tcx> {
+        let internal_ty = self.tcx.mk_ty_from_kind(internal_kind);
+        internal_ty.discriminant_ty(self.tcx)
+    }
+
+    /// Get the body of an Instance which is already monomorphized.
+    pub fn instance_body(
+        &self,
+        instance: ty::Instance<'tcx>,
+        tables: &mut Tables<'tcx, B>,
+    ) -> Option<Body<'tcx>> {
+        tables
+            .instance_has_body(instance)
+            .then(|| BodyBuilder::new(self.tcx, instance).build(tables))
+    }
+
+    /// Get the instance type with generic instantiations applied and lifetimes erased.
+    pub fn instance_ty(&self, instance: ty::Instance<'tcx>) -> Ty<'tcx> {
+        assert!(!instance.has_non_region_param(), "{instance:?} needs further instantiation");
+        instance.ty(self.tcx, self.fully_monomorphized())
+    }
+
+    /// Get the instantiation types.
+    pub fn instance_args(&self, instance: ty::Instance<'tcx>) -> GenericArgsRef<'tcx> {
+        instance.args
+    }
+
+    /// Get an instance ABI.
+    pub fn instance_abi(
+        &self,
+        instance: ty::Instance<'tcx>,
+        tables: &mut Tables<'tcx, B>,
+    ) -> Result<&FnAbi<'tcx, Ty<'tcx>>, B::Error> {
+        Ok(tables.fn_abi_of_instance(instance, List::empty())?)
+    }
+
+    /// Get the ABI of a function pointer.
+    pub fn fn_ptr_abi(
+        &self,
+        sig: PolyFnSig<'tcx>,
+        tables: &mut Tables<'tcx, B>,
+    ) -> Result<&FnAbi<'tcx, Ty<'tcx>>, B::Error> {
+        Ok(tables.fn_abi_of_fn_ptr(sig, List::empty())?)
+    }
+
+    /// Get the instance.
+    pub fn instance_def_id(
+        &self,
+        instances: ty::Instance<'tcx>,
+        tables: &mut Tables<'_, B>,
+    ) -> B::DefId {
+        let def_id = instances.def_id();
+        tables.create_def_id(def_id)
+    }
+
+    /// Get the instance mangled name.
+    pub fn instance_mangled_name(&self, instance: ty::Instance<'tcx>) -> String {
+        self.tcx.symbol_name(instance).name.to_string()
+    }
+
+    /// Check if this is an empty DropGlue shim.
+    pub fn is_empty_drop_shim(&self, instance: ty::Instance<'tcx>) -> bool {
+        matches!(instance.def, ty::InstanceKind::DropGlue(_, None))
+    }
+
+    /// Convert a non-generic crate item into an instance.
+    /// This function will panic if the item is generic.
+    pub fn mono_instance(&self, def_id: DefId) -> Instance<'tcx> {
+        Instance::mono(self.tcx, def_id)
+    }
+
+    /// Item requires monomorphization.
+    pub fn requires_monomorphization(&self, def_id: DefId) -> bool {
+        let generics = self.tcx.generics_of(def_id);
+        let result = generics.requires_monomorphization(self.tcx);
+        result
+    }
+
+    /// Resolve an instance from the given function definition and generic arguments.
+    pub fn resolve_instance(
+        &self,
+        def_id: DefId,
+        args_ref: GenericArgsRef<'tcx>,
+    ) -> Option<Instance<'tcx>> {
+        match Instance::try_resolve(self.tcx, self.fully_monomorphized(), def_id, args_ref) {
+            Ok(Some(instance)) => Some(instance),
+            Ok(None) | Err(_) => None,
+        }
+    }
+
+    /// Resolve an instance for drop_in_place for the given type.
+    pub fn resolve_drop_in_place(&self, internal_ty: Ty<'tcx>) -> Instance<'tcx> {
+        let instance = Instance::resolve_drop_in_place(self.tcx, internal_ty);
+        instance
+    }
+
+    /// Resolve instance for a function pointer.
+    pub fn resolve_for_fn_ptr(
+        &self,
+        def_id: DefId,
+        args_ref: GenericArgsRef<'tcx>,
+    ) -> Option<Instance<'tcx>> {
+        Instance::resolve_for_fn_ptr(self.tcx, self.fully_monomorphized(), def_id, args_ref)
+    }
+
+    /// Resolve instance for a closure with the requested type.
+    pub fn resolve_closure(
+        &self,
+        def_id: DefId,
+        args_ref: GenericArgsRef<'tcx>,
+        closure_kind: ClosureKind,
+    ) -> Option<Instance<'tcx>> {
+        Some(Instance::resolve_closure(self.tcx, def_id, args_ref, closure_kind))
+    }
+
+    /// Try to evaluate an instance into a constant.
+    pub fn eval_instance(
+        &self,
+        instance: ty::Instance<'tcx>,
+    ) -> Result<ConstValue<'tcx>, ErrorHandled> {
+        self.tcx.const_eval_instance(
+            self.fully_monomorphized(),
+            instance,
+            self.tcx.def_span(instance.def_id()),
+        )
+    }
+
+    /// Evaluate a static's initializer.
+    pub fn eval_static_initializer(
+        &self,
+        def_id: DefId,
+    ) -> Result<ConstAllocation<'tcx>, ErrorHandled> {
+        self.tcx.eval_static_initializer(def_id)
+    }
+
+    /// Retrieve global allocation for the given allocation ID.
+    pub fn global_alloc(&self, alloc_id: AllocId) -> GlobalAlloc<'tcx> {
+        self.tcx.global_alloc(alloc_id)
+    }
+
+    /// Retrieve the id for the virtual table.
+    pub fn vtable_allocation(
+        &self,
+        ty: Ty<'tcx>,
+        trait_ref: Option<Binder<TyCtxt<'tcx>, ExistentialTraitRef<TyCtxt<'tcx>>>>,
+    ) -> AllocId {
+        let alloc_id = self.tcx.vtable_allocation((
+            ty,
+            trait_ref.map(|principal| self.tcx.instantiate_bound_regions_with_erased(principal)),
+        ));
+        alloc_id
+    }
+
+    /// Retrieve the instance name for diagnostic messages.
+    ///
+    /// This will return the specialized name, e.g., `Vec<char>::new`.
+    pub fn instance_name(&self, instance: ty::Instance<'tcx>, trimmed: bool) -> String {
+        if trimmed {
+            with_forced_trimmed_paths!(
+                self.tcx.def_path_str_with_args(instance.def_id(), instance.args)
+            )
+        } else {
+            with_no_trimmed_paths!(
+                self.tcx.def_path_str_with_args(instance.def_id(), instance.args)
+            )
+        }
+    }
+
+    /// Get the layout of a type.
+    pub fn ty_layout(
+        &self,
+        ty: Ty<'tcx>,
+        tables: &mut Tables<'tcx, B>,
+    ) -> Result<Layout<'tcx>, B::Error> {
+        let layout = tables.layout_of(ty)?.layout;
+        Ok(layout)
+    }
+
+    /// Get the resulting type of binary operation.
+    pub fn binop_ty(&self, bin_op: BinOp, rhs: Ty<'tcx>, lhs: Ty<'tcx>) -> Ty<'tcx> {
+        bin_op.ty(self.tcx, rhs, lhs)
+    }
+
+    /// Get the resulting type of unary operation.
+    pub fn unop_ty(&self, un_op: UnOp, arg: Ty<'tcx>) -> Ty<'tcx> {
+        un_op.ty(self.tcx, arg)
+    }
+
+    /// Get all associated items of a definition.
+    pub fn associated_items(&self, def_id: DefId) -> Vec<AssocItem> {
+        let assoc_items = if self.tcx.is_trait_alias(def_id) {
+            Vec::new()
+        } else {
+            self.tcx
+                .associated_item_def_ids(def_id)
+                .iter()
+                .map(|did| self.tcx.associated_item(*did))
+                .collect()
+        };
+        assoc_items
+    }
+}
diff --git a/compiler/rustc_smir/src/rustc_smir/context/mod.rs b/compiler/rustc_smir/src/rustc_smir/context/mod.rs
new file mode 100644
index 00000000000..75acede8d34
--- /dev/null
+++ b/compiler/rustc_smir/src/rustc_smir/context/mod.rs
@@ -0,0 +1,79 @@
+//! Implementation of StableMIR Context.
+
+#![allow(rustc::usage_of_qualified_ty)]
+
+use std::marker::PhantomData;
+
+use rustc_abi::HasDataLayout;
+use rustc_middle::ty;
+use rustc_middle::ty::layout::{FnAbiOfHelpers, HasTyCtxt, HasTypingEnv, LayoutOfHelpers};
+use rustc_middle::ty::{Ty, TyCtxt};
+
+use crate::rustc_smir::{Bridge, SmirError, Tables};
+
+mod impls;
+mod traits;
+
+pub use traits::*;
+
+/// Provides direct access to rustc's internal queries.
+///
+/// The [`crate::stable_mir::compiler_interface::SmirInterface`] must go through
+/// this context to obtain rustc-level information.
+pub struct SmirCtxt<'tcx, B: Bridge> {
+    tcx: TyCtxt<'tcx>,
+    _marker: PhantomData<B>,
+}
+
+impl<'tcx, B: Bridge> SmirCtxt<'tcx, B> {
+    pub(crate) fn new(tcx: TyCtxt<'tcx>) -> Self {
+        Self { tcx, _marker: Default::default() }
+    }
+}
+
+/// Implement error handling for extracting function ABI information.
+impl<'tcx, B: Bridge> FnAbiOfHelpers<'tcx> for Tables<'tcx, B> {
+    type FnAbiOfResult = Result<&'tcx rustc_target::callconv::FnAbi<'tcx, Ty<'tcx>>, B::Error>;
+
+    #[inline]
+    fn handle_fn_abi_err(
+        &self,
+        err: ty::layout::FnAbiError<'tcx>,
+        _span: rustc_span::Span,
+        fn_abi_request: ty::layout::FnAbiRequest<'tcx>,
+    ) -> B::Error {
+        B::Error::new(format!("Failed to get ABI for `{fn_abi_request:?}`: {err:?}"))
+    }
+}
+
+impl<'tcx, B: Bridge> LayoutOfHelpers<'tcx> for Tables<'tcx, B> {
+    type LayoutOfResult = Result<ty::layout::TyAndLayout<'tcx>, B::Error>;
+
+    #[inline]
+    fn handle_layout_err(
+        &self,
+        err: ty::layout::LayoutError<'tcx>,
+        _span: rustc_span::Span,
+        ty: Ty<'tcx>,
+    ) -> B::Error {
+        B::Error::new(format!("Failed to get layout for `{ty}`: {err}"))
+    }
+}
+
+impl<'tcx, B: Bridge> HasTypingEnv<'tcx> for Tables<'tcx, B> {
+    fn typing_env(&self) -> ty::TypingEnv<'tcx> {
+        ty::TypingEnv::fully_monomorphized()
+    }
+}
+
+impl<'tcx, B: Bridge> HasTyCtxt<'tcx> for Tables<'tcx, B> {
+    fn tcx(&self) -> TyCtxt<'tcx> {
+        self.tcx
+    }
+}
+
+impl<'tcx, B: Bridge> HasDataLayout for Tables<'tcx, B> {
+    fn data_layout(&self) -> &rustc_abi::TargetDataLayout {
+        self.tcx.data_layout()
+    }
+}
diff --git a/compiler/rustc_smir/src/rustc_smir/context/traits.rs b/compiler/rustc_smir/src/rustc_smir/context/traits.rs
new file mode 100644
index 00000000000..f5cd7c330b8
--- /dev/null
+++ b/compiler/rustc_smir/src/rustc_smir/context/traits.rs
@@ -0,0 +1,50 @@
+//! A set of traits that define a stable interface to rustc's internals.
+//!
+//! These traits abstract rustc's internal APIs, allowing StableMIR to maintain a stable
+//! interface regardless of internal compiler changes.
+
+use rustc_middle::mir::interpret::AllocRange;
+use rustc_middle::ty;
+use rustc_middle::ty::Ty;
+use rustc_span::def_id::DefId;
+
+pub trait SmirExistentialProjection<'tcx> {
+    fn new_from_args(
+        &self,
+        def_id: DefId,
+        args: ty::GenericArgsRef<'tcx>,
+        term: ty::Term<'tcx>,
+    ) -> ty::ExistentialProjection<'tcx>;
+}
+
+pub trait SmirExistentialTraitRef<'tcx> {
+    fn new_from_args(
+        &self,
+        trait_def_id: DefId,
+        args: ty::GenericArgsRef<'tcx>,
+    ) -> ty::ExistentialTraitRef<'tcx>;
+}
+
+pub trait SmirTraitRef<'tcx> {
+    fn new_from_args(
+        &self,
+        trait_def_id: DefId,
+        args: ty::GenericArgsRef<'tcx>,
+    ) -> ty::TraitRef<'tcx>;
+}
+
+pub trait SmirTy<'tcx> {
+    fn new_foreign(&self, def_id: DefId) -> Ty<'tcx>;
+}
+
+pub trait SmirTypingEnv<'tcx> {
+    fn fully_monomorphized(&self) -> ty::TypingEnv<'tcx>;
+}
+
+pub trait SmirAllocRange<'tcx> {
+    fn alloc_range(&self, offset: rustc_abi::Size, size: rustc_abi::Size) -> AllocRange;
+}
+
+pub trait SmirRegion<'tcx> {
+    fn lifetimes_re_erased(&self) -> ty::Region<'tcx>;
+}