about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMatthias Krüger <matthias.krueger@famsik.de>2023-11-17 08:10:26 +0100
committerGitHub <noreply@github.com>2023-11-17 08:10:26 +0100
commitc188486267c492c1e71d5db26c2fe42376654ed1 (patch)
tree22ebf65158b56edb0aee622f5036416fb0ae2f33
parent1cabedc256a590c770f1a64903b61da48622c587 (diff)
parent8e81fc00879b640ed6acc6a9ca870814189901e5 (diff)
downloadrust-c188486267c492c1e71d5db26c2fe42376654ed1.tar.gz
rust-c188486267c492c1e71d5db26c2fe42376654ed1.zip
Rollup merge of #117688 - celinval:smir-kani-reach, r=compiler-errors
Misc changes to StableMIR required to Kani use case.

First, I wanted to say that I can split this review into multiple if it makes reviewing easier. I bundled them up, since I've been testing them together (See https://github.com/rust-lang/project-stable-mir/pull/51 for the set of more thorough checks).

So far, this review includes 3 commits:

1. Add more APIs and fix `Instance::body`
    - Add more APIs to retrieve information about types.
    - Add a few more instance resolution options. For the drop shim, we return None if the drop body is empty. Not sure it will be enough.
    - Make `Instance::body()` return an Option<Body>, since not every instance might have an available body. For example, foreign instances, virtual instances, dependencies.
2. Fix a bug on MIRVisitor
    - We were not iterating over all local variables due to a typo.
3. Add more SMIR internal impl and callback return value
    - In cases like Kani, we will invoke the rustc_internal run command directly for now. It would be handly to be able to have a callback that can return a value.
    - We also need extra methods to convert stable constructs into internal ones, so we can break down the transition into finer grain commits.
    - For the internal implementation of Region, we're always returning `ReErased` for now.
-rw-r--r--compiler/rustc_smir/src/rustc_internal/internal.rs136
-rw-r--r--compiler/rustc_smir/src/rustc_internal/mod.rs24
-rw-r--r--compiler/rustc_smir/src/rustc_smir/builder.rs23
-rw-r--r--compiler/rustc_smir/src/rustc_smir/mod.rs159
-rw-r--r--compiler/stable_mir/src/lib.rs61
-rw-r--r--compiler/stable_mir/src/mir/mono.rs67
-rw-r--r--compiler/stable_mir/src/mir/visit.rs4
-rw-r--r--compiler/stable_mir/src/ty.rs149
-rw-r--r--tests/ui-fulldeps/stable-mir/check_instance.rs14
-rw-r--r--tests/ui-fulldeps/stable-mir/crate-info.rs8
-rw-r--r--tests/ui-fulldeps/stable-mir/projections.rs8
-rw-r--r--tests/ui-fulldeps/stable-mir/smir_visitor.rs2
12 files changed, 583 insertions, 72 deletions
diff --git a/compiler/rustc_smir/src/rustc_internal/internal.rs b/compiler/rustc_smir/src/rustc_internal/internal.rs
index 7cfdbbbf703..5bb3c1a0d4c 100644
--- a/compiler/rustc_smir/src/rustc_internal/internal.rs
+++ b/compiler/rustc_smir/src/rustc_internal/internal.rs
@@ -6,11 +6,23 @@
 // Prefer importing stable_mir over internal rustc constructs to make this file more readable.
 use crate::rustc_smir::Tables;
 use rustc_middle::ty::{self as rustc_ty, Ty as InternalTy};
-use stable_mir::ty::{Const, GenericArgKind, GenericArgs, Region, Ty};
-use stable_mir::DefId;
+use rustc_span::Symbol;
+use stable_mir::mir::mono::{Instance, MonoItem, StaticDef};
+use stable_mir::ty::{
+    Binder, BoundRegionKind, BoundTyKind, BoundVariableKind, ClosureKind, Const, GenericArgKind,
+    GenericArgs, Region, TraitRef, Ty,
+};
+use stable_mir::{AllocId, CrateItem, DefId};
 
 use super::RustcInternal;
 
+impl<'tcx> RustcInternal<'tcx> for CrateItem {
+    type T = rustc_span::def_id::DefId;
+    fn internal(&self, tables: &mut Tables<'tcx>) -> Self::T {
+        self.0.internal(tables)
+    }
+}
+
 impl<'tcx> RustcInternal<'tcx> for DefId {
     type T = rustc_span::def_id::DefId;
     fn internal(&self, tables: &mut Tables<'tcx>) -> Self::T {
@@ -38,8 +50,9 @@ impl<'tcx> RustcInternal<'tcx> for GenericArgKind {
 
 impl<'tcx> RustcInternal<'tcx> for Region {
     type T = rustc_ty::Region<'tcx>;
-    fn internal(&self, _tables: &mut Tables<'tcx>) -> Self::T {
-        todo!()
+    fn internal(&self, tables: &mut Tables<'tcx>) -> Self::T {
+        // Cannot recover region. Use erased instead.
+        tables.tcx.lifetimes.re_erased
     }
 }
 
@@ -65,3 +78,118 @@ impl<'tcx> RustcInternal<'tcx> for Const {
         tables.constants[self.id]
     }
 }
+
+impl<'tcx> RustcInternal<'tcx> for MonoItem {
+    type T = rustc_middle::mir::mono::MonoItem<'tcx>;
+
+    fn internal(&self, tables: &mut Tables<'tcx>) -> Self::T {
+        use rustc_middle::mir::mono as rustc_mono;
+        match self {
+            MonoItem::Fn(instance) => rustc_mono::MonoItem::Fn(instance.internal(tables)),
+            MonoItem::Static(def) => rustc_mono::MonoItem::Static(def.internal(tables)),
+            MonoItem::GlobalAsm(_) => {
+                unimplemented!()
+            }
+        }
+    }
+}
+
+impl<'tcx> RustcInternal<'tcx> for Instance {
+    type T = rustc_ty::Instance<'tcx>;
+
+    fn internal(&self, tables: &mut Tables<'tcx>) -> Self::T {
+        tables.instances[self.def]
+    }
+}
+
+impl<'tcx> RustcInternal<'tcx> for StaticDef {
+    type T = rustc_span::def_id::DefId;
+
+    fn internal(&self, tables: &mut Tables<'tcx>) -> Self::T {
+        self.0.internal(tables)
+    }
+}
+
+#[allow(rustc::usage_of_qualified_ty)]
+impl<'tcx, T> RustcInternal<'tcx> for Binder<T>
+where
+    T: RustcInternal<'tcx>,
+    T::T: rustc_ty::TypeVisitable<rustc_ty::TyCtxt<'tcx>>,
+{
+    type T = rustc_ty::Binder<'tcx, T::T>;
+
+    fn internal(&self, tables: &mut Tables<'tcx>) -> Self::T {
+        rustc_ty::Binder::bind_with_vars(
+            self.value.internal(tables),
+            tables.tcx.mk_bound_variable_kinds_from_iter(
+                self.bound_vars.iter().map(|bound| bound.internal(tables)),
+            ),
+        )
+    }
+}
+
+impl<'tcx> RustcInternal<'tcx> for BoundVariableKind {
+    type T = rustc_ty::BoundVariableKind;
+
+    fn internal(&self, tables: &mut Tables<'tcx>) -> Self::T {
+        match self {
+            BoundVariableKind::Ty(kind) => rustc_ty::BoundVariableKind::Ty(match kind {
+                BoundTyKind::Anon => rustc_ty::BoundTyKind::Anon,
+                BoundTyKind::Param(def, symbol) => {
+                    rustc_ty::BoundTyKind::Param(def.0.internal(tables), Symbol::intern(&symbol))
+                }
+            }),
+            BoundVariableKind::Region(kind) => rustc_ty::BoundVariableKind::Region(match kind {
+                BoundRegionKind::BrAnon => rustc_ty::BoundRegionKind::BrAnon,
+                BoundRegionKind::BrNamed(def, symbol) => rustc_ty::BoundRegionKind::BrNamed(
+                    def.0.internal(tables),
+                    Symbol::intern(&symbol),
+                ),
+                BoundRegionKind::BrEnv => rustc_ty::BoundRegionKind::BrEnv,
+            }),
+            BoundVariableKind::Const => rustc_ty::BoundVariableKind::Const,
+        }
+    }
+}
+
+impl<'tcx> RustcInternal<'tcx> for TraitRef {
+    type T = rustc_ty::TraitRef<'tcx>;
+
+    fn internal(&self, tables: &mut Tables<'tcx>) -> Self::T {
+        rustc_ty::TraitRef::new(
+            tables.tcx,
+            self.def_id.0.internal(tables),
+            self.args().internal(tables),
+        )
+    }
+}
+
+impl<'tcx> RustcInternal<'tcx> for AllocId {
+    type T = rustc_middle::mir::interpret::AllocId;
+    fn internal(&self, tables: &mut Tables<'tcx>) -> Self::T {
+        tables.alloc_ids[*self]
+    }
+}
+
+impl<'tcx> RustcInternal<'tcx> for ClosureKind {
+    type T = rustc_ty::ClosureKind;
+
+    fn internal(&self, _tables: &mut Tables<'tcx>) -> Self::T {
+        match self {
+            ClosureKind::Fn => rustc_ty::ClosureKind::Fn,
+            ClosureKind::FnMut => rustc_ty::ClosureKind::FnMut,
+            ClosureKind::FnOnce => rustc_ty::ClosureKind::FnOnce,
+        }
+    }
+}
+
+impl<'tcx, T> RustcInternal<'tcx> for &T
+where
+    T: RustcInternal<'tcx>,
+{
+    type T = T::T;
+
+    fn internal(&self, tables: &mut Tables<'tcx>) -> Self::T {
+        (*self).internal(tables)
+    }
+}
diff --git a/compiler/rustc_smir/src/rustc_internal/mod.rs b/compiler/rustc_smir/src/rustc_internal/mod.rs
index f0b368bec39..c82f948f195 100644
--- a/compiler/rustc_smir/src/rustc_internal/mod.rs
+++ b/compiler/rustc_smir/src/rustc_internal/mod.rs
@@ -13,6 +13,7 @@ use rustc_span::def_id::{CrateNum, DefId};
 use rustc_span::Span;
 use scoped_tls::scoped_thread_local;
 use stable_mir::ty::IndexedVal;
+use stable_mir::Error;
 use std::cell::Cell;
 use std::cell::RefCell;
 use std::fmt::Debug;
@@ -21,11 +22,11 @@ use std::ops::Index;
 
 mod internal;
 
-pub fn stable<'tcx, S: Stable<'tcx>>(item: &S) -> S::T {
+pub fn stable<'tcx, S: Stable<'tcx>>(item: S) -> S::T {
     with_tables(|tables| item.stable(tables))
 }
 
-pub fn internal<'tcx, S: RustcInternal<'tcx>>(item: &S) -> S::T {
+pub fn internal<'tcx, S: RustcInternal<'tcx>>(item: S) -> S::T {
     with_tables(|tables| item.internal(tables))
 }
 
@@ -144,12 +145,13 @@ pub fn crate_num(item: &stable_mir::Crate) -> CrateNum {
 // datastructures and stable MIR datastructures
 scoped_thread_local! (static TLV: Cell<*const ()>);
 
-pub(crate) fn init<'tcx>(tables: &TablesWrapper<'tcx>, f: impl FnOnce()) {
+pub(crate) fn init<'tcx, F, T>(tables: &TablesWrapper<'tcx>, f: F) -> T
+where
+    F: FnOnce() -> T,
+{
     assert!(!TLV.is_set());
     let ptr = tables as *const _ as *const ();
-    TLV.set(&Cell::new(ptr), || {
-        f();
-    });
+    TLV.set(&Cell::new(ptr), || f())
 }
 
 /// Loads the current context and calls a function with it.
@@ -165,7 +167,10 @@ pub(crate) fn with_tables<'tcx, R>(f: impl FnOnce(&mut Tables<'tcx>) -> R) -> R
     })
 }
 
-pub fn run(tcx: TyCtxt<'_>, f: impl FnOnce()) {
+pub fn run<F, T>(tcx: TyCtxt<'_>, f: F) -> Result<T, Error>
+where
+    F: FnOnce() -> T,
+{
     let tables = TablesWrapper(RefCell::new(Tables {
         tcx,
         def_ids: IndexMap::default(),
@@ -175,7 +180,7 @@ pub fn run(tcx: TyCtxt<'_>, f: impl FnOnce()) {
         instances: IndexMap::default(),
         constants: IndexMap::default(),
     }));
-    stable_mir::run(&tables, || init(&tables, f));
+    stable_mir::run(&tables, || init(&tables, f))
 }
 
 #[macro_export]
@@ -241,7 +246,8 @@ macro_rules! run {
                 queries.global_ctxt().unwrap().enter(|tcx| {
                     rustc_internal::run(tcx, || {
                         self.result = Some((self.callback)(tcx));
-                    });
+                    })
+                    .unwrap();
                     if self.result.as_ref().is_some_and(|val| val.is_continue()) {
                         Compilation::Continue
                     } else {
diff --git a/compiler/rustc_smir/src/rustc_smir/builder.rs b/compiler/rustc_smir/src/rustc_smir/builder.rs
index 8ff3958da7b..7e74a1d92c7 100644
--- a/compiler/rustc_smir/src/rustc_smir/builder.rs
+++ b/compiler/rustc_smir/src/rustc_smir/builder.rs
@@ -19,10 +19,15 @@ impl<'tcx> BodyBuilder<'tcx> {
         BodyBuilder { tcx, instance }
     }
 
+    /// Build a stable monomorphic body for a given instance based on the MIR body.
+    ///
+    /// Note that we skip instantiation for static and constants. Trying to do so can cause ICE.
+    ///
+    /// We do monomorphize non-generic functions to eval unevaluated constants.
     pub fn build(mut self, tables: &mut Tables<'tcx>) -> stable_mir::mir::Body {
         let mut body = self.tcx.instance_mir(self.instance.def).clone();
-        let generics = self.tcx.generics_of(self.instance.def_id());
-        if generics.requires_monomorphization(self.tcx) {
+        if self.tcx.def_kind(self.instance.def_id()).is_fn_like() || !self.instance.args.is_empty()
+        {
             self.visit_body(&mut body);
         }
         body.stable(tables)
@@ -49,6 +54,20 @@ impl<'tcx> MutVisitor<'tcx> for BodyBuilder<'tcx> {
         *ty = self.monomorphize(*ty);
     }
 
+    fn visit_constant(&mut self, constant: &mut mir::ConstOperand<'tcx>, location: mir::Location) {
+        let const_ = self.monomorphize(constant.const_);
+        let val = match const_.eval(self.tcx, ty::ParamEnv::reveal_all(), None) {
+            Ok(v) => v,
+            Err(mir::interpret::ErrorHandled::Reported(..)) => return,
+            Err(mir::interpret::ErrorHandled::TooGeneric(..)) => {
+                unreachable!("Failed to evaluate instance constant: {:?}", const_)
+            }
+        };
+        let ty = constant.ty();
+        constant.const_ = mir::Const::Val(val, ty);
+        self.super_constant(constant, location);
+    }
+
     fn tcx(&self) -> TyCtxt<'tcx> {
         self.tcx
     }
diff --git a/compiler/rustc_smir/src/rustc_smir/mod.rs b/compiler/rustc_smir/src/rustc_smir/mod.rs
index 8845320ca8b..3df09cef1c7 100644
--- a/compiler/rustc_smir/src/rustc_smir/mod.rs
+++ b/compiler/rustc_smir/src/rustc_smir/mod.rs
@@ -8,9 +8,9 @@
 //! For now, we are developing everything inside `rustc`, thus, we keep this module private.
 
 use crate::rustc_internal::{IndexMap, RustcInternal};
-use crate::rustc_smir::hir::def::DefKind;
-use crate::rustc_smir::stable_mir::ty::{BoundRegion, EarlyParamRegion, Region};
+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;
@@ -20,10 +20,11 @@ use rustc_target::abi::FieldIdx;
 use stable_mir::mir::mono::InstanceDef;
 use stable_mir::mir::{Body, CopyNonOverlapping, Statement, UserTypeProjection, VariantIdx};
 use stable_mir::ty::{
-    Const, ConstId, ConstantKind, FloatTy, GenericParamDef, IntTy, LineInfo, Movability, RigidTy,
-    Span, TyKind, UintTy,
+    AdtDef, AdtKind, ClosureDef, ClosureKind, Const, ConstId, ConstantKind, EarlyParamRegion,
+    FloatTy, FnDef, GenericArgs, GenericParamDef, IntTy, LineInfo, Movability, RigidTy, Span,
+    TyKind, UintTy,
 };
-use stable_mir::{self, opaque, Context, Filename};
+use stable_mir::{self, opaque, Context, CrateItem, Filename, ItemKind};
 use std::cell::RefCell;
 use tracing::debug;
 
@@ -85,9 +86,23 @@ impl<'tcx> Context for TablesWrapper<'tcx> {
         LineInfo { start_line: lines.1, start_col: lines.2, end_line: lines.3, end_col: lines.4 }
     }
 
-    fn def_kind(&self, def_id: stable_mir::DefId) -> stable_mir::DefKind {
+    fn item_kind(&self, item: CrateItem) -> ItemKind {
+        let tables = self.0.borrow();
+        new_item_kind(tables.tcx.def_kind(tables[item.0]))
+    }
+
+    fn adt_kind(&self, def: AdtDef) -> AdtKind {
+        let mut tables = self.0.borrow_mut();
+        let ty = tables.tcx.type_of(def.0.internal(&mut *tables)).instantiate_identity().kind();
+        let ty::TyKind::Adt(def, _) = ty else {
+            panic!("Expected an ADT definition, but found: {ty:?}")
+        };
+        def.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.def_kind(tables[def_id]).stable(&mut *tables)
+        tables.tcx.type_of(item.internal(&mut *tables)).instantiate_identity().stable(&mut *tables)
     }
 
     fn span_of_an_item(&self, def_id: stable_mir::DefId) -> Span {
@@ -198,10 +213,12 @@ impl<'tcx> Context for TablesWrapper<'tcx> {
         }
     }
 
-    fn instance_body(&self, def: InstanceDef) -> Body {
+    fn instance_body(&self, def: InstanceDef) -> Option<Body> {
         let mut tables = self.0.borrow_mut();
         let instance = tables.instances[def];
-        builder::BodyBuilder::new(tables.tcx, instance).build(&mut *tables)
+        tables
+            .has_body(instance)
+            .then(|| builder::BodyBuilder::new(tables.tcx, instance).build(&mut *tables))
     }
 
     fn instance_ty(&self, def: InstanceDef) -> stable_mir::ty::Ty {
@@ -249,6 +266,38 @@ impl<'tcx> Context for TablesWrapper<'tcx> {
             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)
+    }
 }
 
 pub(crate) struct TablesWrapper<'tcx>(pub(crate) RefCell<Tables<'tcx>>);
@@ -271,6 +320,17 @@ impl<'tcx> Tables<'tcx> {
     fn intern_const(&mut self, constant: mir::Const<'tcx>) -> ConstId {
         self.constants.create_or_fetch(constant)
     }
+
+    fn has_body(&self, instance: Instance<'tcx>) -> bool {
+        let def_id = instance.def_id();
+        self.tcx.is_mir_available(def_id)
+            || !matches!(
+                instance.def,
+                ty::InstanceDef::Virtual(..)
+                    | ty::InstanceDef::Intrinsic(..)
+                    | ty::InstanceDef::Item(..)
+            )
+    }
 }
 
 /// Build a stable mir crate from a given crate number.
@@ -281,6 +341,40 @@ fn smir_crate(tcx: TyCtxt<'_>, crate_num: CrateNum) -> stable_mir::Crate {
     stable_mir::Crate { id: crate_num.into(), name: crate_name, is_local }
 }
 
+fn new_item_kind(kind: DefKind) -> ItemKind {
+    match kind {
+        DefKind::Mod
+        | DefKind::Struct
+        | DefKind::Union
+        | DefKind::Enum
+        | DefKind::Variant
+        | DefKind::Trait
+        | DefKind::TyAlias
+        | DefKind::ForeignTy
+        | DefKind::TraitAlias
+        | DefKind::AssocTy
+        | DefKind::TyParam
+        | DefKind::ConstParam
+        | DefKind::Macro(_)
+        | DefKind::ExternCrate
+        | DefKind::Use
+        | DefKind::ForeignMod
+        | DefKind::OpaqueTy
+        | DefKind::Field
+        | DefKind::LifetimeParam
+        | DefKind::Impl { .. }
+        | DefKind::Ctor(_, _)
+        | DefKind::GlobalAsm => {
+            unreachable!("Not a valid item kind: {kind:?}");
+        }
+        DefKind::Closure | DefKind::Coroutine | DefKind::AssocFn | DefKind::Fn => ItemKind::Fn,
+        DefKind::Const | DefKind::InlineConst | DefKind::AssocConst | DefKind::AnonConst => {
+            ItemKind::Const
+        }
+        DefKind::Static(_) => ItemKind::Static,
+    }
+}
+
 /// Trait used to convert between an internal MIR type to a Stable MIR type.
 pub trait Stable<'tcx> {
     /// The stable representation of the type implementing Stable.
@@ -926,6 +1020,18 @@ impl<'tcx> Stable<'tcx> for mir::AggregateKind<'tcx> {
     }
 }
 
+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 {
@@ -1062,8 +1168,6 @@ impl<'tcx> Stable<'tcx> for mir::TerminatorKind<'tcx> {
 impl<'tcx> Stable<'tcx> for ty::GenericArgs<'tcx> {
     type T = stable_mir::ty::GenericArgs;
     fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T {
-        use stable_mir::ty::GenericArgs;
-
         GenericArgs(self.iter().map(|arg| arg.unpack().stable(tables)).collect())
     }
 }
@@ -1486,7 +1590,7 @@ impl<'tcx> Stable<'tcx> for ty::TraitRef<'tcx> {
     fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T {
         use stable_mir::ty::TraitRef;
 
-        TraitRef { def_id: tables.trait_def(self.def_id), args: self.args.stable(tables) }
+        TraitRef::try_new(tables.trait_def(self.def_id), self.args.stable(tables)).unwrap()
     }
 }
 
@@ -1762,15 +1866,6 @@ impl<'tcx> Stable<'tcx> for rustc_span::Span {
     }
 }
 
-impl<'tcx> Stable<'tcx> for DefKind {
-    type T = stable_mir::DefKind;
-
-    fn stable(&self, _: &mut Tables<'tcx>) -> Self::T {
-        // FIXME: add a real implementation of stable DefKind
-        opaque(self)
-    }
-}
-
 impl<'tcx> Stable<'tcx> for ty::Instance<'tcx> {
     type T = stable_mir::mir::mono::Instance;
 
@@ -1805,3 +1900,25 @@ impl<'tcx> Stable<'tcx> for MonoItem<'tcx> {
         }
     }
 }
+
+impl<'tcx, T> Stable<'tcx> for &T
+where
+    T: Stable<'tcx>,
+{
+    type T = T::T;
+
+    fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T {
+        (*self).stable(tables)
+    }
+}
+
+impl<'tcx, T> Stable<'tcx> for Option<T>
+where
+    T: Stable<'tcx>,
+{
+    type T = Option<T::T>;
+
+    fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T {
+        self.as_ref().map(|value| value.stable(tables))
+    }
+}
diff --git a/compiler/stable_mir/src/lib.rs b/compiler/stable_mir/src/lib.rs
index f316671b278..0262fb536e7 100644
--- a/compiler/stable_mir/src/lib.rs
+++ b/compiler/stable_mir/src/lib.rs
@@ -36,6 +36,7 @@ pub mod mir;
 pub mod ty;
 pub mod visitor;
 
+use crate::ty::{AdtDef, AdtKind, ClosureDef, ClosureKind};
 pub use error::*;
 use mir::mono::Instance;
 use ty::{FnDef, GenericArgs};
@@ -47,7 +48,7 @@ pub type Symbol = String;
 pub type CrateNum = usize;
 
 /// A unique identification number for each item accessible for the current compilation unit.
-#[derive(Clone, Copy, PartialEq, Eq)]
+#[derive(Clone, Copy, PartialEq, Eq, Hash)]
 pub struct DefId(usize);
 
 impl Debug for DefId {
@@ -99,7 +100,13 @@ pub struct Crate {
     pub is_local: bool,
 }
 
-pub type DefKind = Opaque;
+#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)]
+pub enum ItemKind {
+    Fn,
+    Static,
+    Const,
+}
+
 pub type Filename = Opaque;
 
 /// Holds information about an item in the crate.
@@ -119,13 +126,17 @@ impl CrateItem {
         with(|cx| cx.name_of_def_id(self.0))
     }
 
-    pub fn kind(&self) -> DefKind {
-        with(|cx| cx.def_kind(self.0))
+    pub fn kind(&self) -> ItemKind {
+        with(|cx| cx.item_kind(*self))
     }
 
     pub fn requires_monomorphization(&self) -> bool {
         with(|cx| cx.requires_monomorphization(self.0))
     }
+
+    pub fn ty(&self) -> Ty {
+        with(|cx| cx.def_ty(self.0))
+    }
 }
 
 /// Return the function where execution starts if the current
@@ -204,7 +215,13 @@ pub trait Context {
     fn get_lines(&self, span: &Span) -> LineInfo;
 
     /// Returns the `kind` of given `DefId`
-    fn def_kind(&self, def_id: DefId) -> DefKind;
+    fn item_kind(&self, item: CrateItem) -> ItemKind;
+
+    /// Returns the kind of a given algebraic data type
+    fn adt_kind(&self, def: AdtDef) -> AdtKind;
+
+    /// Returns the type of given crate item.
+    fn def_ty(&self, item: DefId) -> Ty;
 
     /// `Span` of an item
     fn span_of_an_item(&self, def_id: DefId) -> Span;
@@ -214,7 +231,7 @@ pub trait Context {
 
     /// Get the body of an Instance.
     /// FIXME: Monomorphize the body.
-    fn instance_body(&self, instance: InstanceDef) -> 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;
@@ -234,18 +251,36 @@ pub trait Context {
 
     /// 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>;
 }
 
 // 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(context: &dyn Context, f: impl FnOnce()) {
-    assert!(!TLV.is_set());
-    let ptr: *const () = &context as *const &_ as _;
-    TLV.set(&Cell::new(ptr), || {
-        f();
-    });
+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.
@@ -260,7 +295,7 @@ pub fn with<R>(f: impl FnOnce(&dyn Context) -> R) -> R {
 }
 
 /// A type that provides internal information but that can still be used for debug purpose.
-#[derive(Clone, Eq, PartialEq)]
+#[derive(Clone, PartialEq, Eq, Hash)]
 pub struct Opaque(String);
 
 impl std::fmt::Display for Opaque {
diff --git a/compiler/stable_mir/src/mir/mono.rs b/compiler/stable_mir/src/mir/mono.rs
index 8f533349848..8562bfd3905 100644
--- a/compiler/stable_mir/src/mir/mono.rs
+++ b/compiler/stable_mir/src/mir/mono.rs
@@ -1,16 +1,16 @@
 use crate::mir::Body;
-use crate::ty::{FnDef, GenericArgs, IndexedVal, Ty};
-use crate::{with, CrateItem, DefId, Error, Opaque};
+use crate::ty::{ClosureDef, ClosureKind, FnDef, GenericArgs, IndexedVal, Ty};
+use crate::{with, CrateItem, DefId, Error, ItemKind, Opaque};
 use std::fmt::Debug;
 
-#[derive(Clone, Debug)]
+#[derive(Clone, Debug, PartialEq, Eq, Hash)]
 pub enum MonoItem {
     Fn(Instance),
     Static(StaticDef),
     GlobalAsm(Opaque),
 }
 
-#[derive(Copy, Clone, Debug)]
+#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
 pub struct Instance {
     /// The type of instance.
     pub kind: InstanceKind,
@@ -19,7 +19,7 @@ pub struct Instance {
     pub def: InstanceDef,
 }
 
-#[derive(Copy, Clone, Debug, PartialEq, Eq)]
+#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
 pub enum InstanceKind {
     /// A user defined item.
     Item,
@@ -33,7 +33,7 @@ pub enum InstanceKind {
 
 impl Instance {
     /// Get the body of an Instance. The body will be eagerly monomorphized.
-    pub fn body(&self) -> Body {
+    pub fn body(&self) -> Option<Body> {
         with(|context| context.instance_body(self.def))
     }
 
@@ -54,6 +54,33 @@ impl Instance {
             })
         })
     }
+
+    /// Resolve the drop in place for a given type.
+    pub fn resolve_drop_in_place(ty: Ty) -> Instance {
+        with(|cx| cx.resolve_drop_in_place(ty))
+    }
+
+    /// Resolve an instance for a given function pointer.
+    pub fn resolve_for_fn_ptr(def: FnDef, args: &GenericArgs) -> Result<Instance, crate::Error> {
+        with(|context| {
+            context.resolve_for_fn_ptr(def, args).ok_or_else(|| {
+                crate::Error::new(format!("Failed to resolve `{def:?}` with `{args:?}`"))
+            })
+        })
+    }
+
+    /// Resolve a closure with the expected kind.
+    pub fn resolve_closure(
+        def: ClosureDef,
+        args: &GenericArgs,
+        kind: ClosureKind,
+    ) -> Result<Instance, crate::Error> {
+        with(|context| {
+            context.resolve_closure(def, args, kind).ok_or_else(|| {
+                crate::Error::new(format!("Failed to resolve `{def:?}` with `{args:?}`"))
+            })
+        })
+    }
 }
 
 /// Try to convert a crate item into an instance.
@@ -86,12 +113,36 @@ impl TryFrom<Instance> for CrateItem {
     }
 }
 
-#[derive(Clone, Copy, Debug, PartialEq, Eq)]
+impl From<Instance> for MonoItem {
+    fn from(value: Instance) -> Self {
+        MonoItem::Fn(value)
+    }
+}
+
+#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
 pub struct InstanceDef(usize);
 
-#[derive(Clone, Copy, PartialEq, Eq, Debug)]
+#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)]
 pub struct StaticDef(pub DefId);
 
+impl TryFrom<CrateItem> for StaticDef {
+    type Error = crate::Error;
+
+    fn try_from(value: CrateItem) -> Result<Self, Self::Error> {
+        if matches!(value.kind(), ItemKind::Static | ItemKind::Const) {
+            Ok(StaticDef(value.0))
+        } else {
+            Err(Error::new(format!("Expected a static item, but found: {value:?}")))
+        }
+    }
+}
+
+impl StaticDef {
+    pub fn ty(&self) -> Ty {
+        with(|cx| cx.def_ty(self.0))
+    }
+}
+
 impl IndexedVal for InstanceDef {
     fn to_val(index: usize) -> Self {
         InstanceDef(index)
diff --git a/compiler/stable_mir/src/mir/visit.rs b/compiler/stable_mir/src/mir/visit.rs
index 475d6e9763d..d6304d3ea39 100644
--- a/compiler/stable_mir/src/mir/visit.rs
+++ b/compiler/stable_mir/src/mir/visit.rs
@@ -142,7 +142,7 @@ pub trait MirVisitor {
         }
 
         let local_start = arg_count + 1;
-        for (idx, arg) in body.arg_locals().iter().enumerate() {
+        for (idx, arg) in body.inner_locals().iter().enumerate() {
             self.visit_local_decl(idx + local_start, arg)
         }
     }
@@ -417,7 +417,7 @@ pub trait MirVisitor {
 fn visit_opaque(_: &Opaque) {}
 
 /// The location of a statement / terminator in the code and the CFG.
-#[derive(Clone, Copy, PartialEq, Eq)]
+#[derive(Clone, Copy, PartialEq, Eq, Debug)]
 pub struct Location(Span);
 
 impl Location {
diff --git a/compiler/stable_mir/src/ty.rs b/compiler/stable_mir/src/ty.rs
index e95c09abe78..fa932c5d81a 100644
--- a/compiler/stable_mir/src/ty.rs
+++ b/compiler/stable_mir/src/ty.rs
@@ -4,7 +4,7 @@ use super::{
     with, AllocId, DefId, Symbol,
 };
 use crate::{Filename, Opaque};
-use std::fmt::{self, Debug, Formatter};
+use std::fmt::{self, Debug, Display, Formatter};
 
 #[derive(Copy, Clone, Eq, PartialEq, Hash)]
 pub struct Ty(pub usize);
@@ -135,6 +135,46 @@ pub enum TyKind {
     Bound(usize, BoundTy),
 }
 
+impl TyKind {
+    pub fn rigid(&self) -> Option<&RigidTy> {
+        if let TyKind::RigidTy(inner) = self { Some(inner) } else { None }
+    }
+
+    pub fn is_unit(&self) -> bool {
+        matches!(self, TyKind::RigidTy(RigidTy::Tuple(data)) if data.len() == 0)
+    }
+
+    pub fn is_trait(&self) -> bool {
+        matches!(self, TyKind::RigidTy(RigidTy::Dynamic(_, _, DynKind::Dyn)))
+    }
+
+    pub fn is_enum(&self) -> bool {
+        matches!(self, TyKind::RigidTy(RigidTy::Adt(def, _)) if def.kind() == AdtKind::Enum)
+    }
+
+    pub fn is_struct(&self) -> bool {
+        matches!(self, TyKind::RigidTy(RigidTy::Adt(def, _)) if def.kind() == AdtKind::Struct)
+    }
+
+    pub fn is_union(&self) -> bool {
+        matches!(self, TyKind::RigidTy(RigidTy::Adt(def, _)) if def.kind() == AdtKind::Union)
+    }
+
+    pub fn trait_principal(&self) -> Option<Binder<ExistentialTraitRef>> {
+        if let TyKind::RigidTy(RigidTy::Dynamic(predicates, _, _)) = self {
+            if let Some(Binder { value: ExistentialPredicate::Trait(trait_ref), bound_vars }) =
+                predicates.first()
+            {
+                Some(Binder { value: trait_ref.clone(), bound_vars: bound_vars.clone() })
+            } else {
+                None
+            }
+        } else {
+            None
+        }
+    }
+}
+
 #[derive(Clone, Debug, Eq, PartialEq)]
 pub enum RigidTy {
     Bool,
@@ -218,6 +258,43 @@ pub struct BrNamedDef(pub DefId);
 #[derive(Clone, Copy, PartialEq, Eq, Debug)]
 pub struct AdtDef(pub DefId);
 
+#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)]
+pub enum AdtKind {
+    Enum,
+    Union,
+    Struct,
+}
+
+impl AdtDef {
+    pub fn kind(&self) -> AdtKind {
+        with(|cx| cx.adt_kind(*self))
+    }
+}
+
+impl Display for AdtKind {
+    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
+        f.write_str(match self {
+            AdtKind::Enum => "enum",
+            AdtKind::Union => "union",
+            AdtKind::Struct => "struct",
+        })
+    }
+}
+
+impl AdtKind {
+    pub fn is_enum(&self) -> bool {
+        matches!(self, AdtKind::Enum)
+    }
+
+    pub fn is_struct(&self) -> bool {
+        matches!(self, AdtKind::Struct)
+    }
+
+    pub fn is_union(&self) -> bool {
+        matches!(self, AdtKind::Union)
+    }
+}
+
 #[derive(Clone, Copy, PartialEq, Eq, Debug)]
 pub struct AliasDef(pub DefId);
 
@@ -355,6 +432,30 @@ pub struct Binder<T> {
     pub bound_vars: Vec<BoundVariableKind>,
 }
 
+impl<T> Binder<T> {
+    pub fn skip_binder(self) -> T {
+        self.value
+    }
+
+    pub fn map_bound_ref<F, U>(&self, f: F) -> Binder<U>
+    where
+        F: FnOnce(&T) -> U,
+    {
+        let Binder { value, bound_vars } = self;
+        let new_value = f(value);
+        Binder { value: new_value, bound_vars: bound_vars.clone() }
+    }
+
+    pub fn map_bound<F, U>(self, f: F) -> Binder<U>
+    where
+        F: FnOnce(T) -> U,
+    {
+        let Binder { value, bound_vars } = self;
+        let new_value = f(value);
+        Binder { value: new_value, bound_vars }
+    }
+}
+
 #[derive(Clone, Debug, Eq, PartialEq)]
 pub struct EarlyBinder<T> {
     pub value: T,
@@ -393,12 +494,27 @@ pub enum ExistentialPredicate {
     AutoTrait(TraitDef),
 }
 
+/// An existential reference to a trait where `Self` is not included.
+///
+/// The `generic_args` will include any other known argument.
 #[derive(Clone, Debug, Eq, PartialEq)]
 pub struct ExistentialTraitRef {
     pub def_id: TraitDef,
     pub generic_args: GenericArgs,
 }
 
+impl Binder<ExistentialTraitRef> {
+    pub fn with_self_ty(&self, self_ty: Ty) -> Binder<TraitRef> {
+        self.map_bound_ref(|trait_ref| trait_ref.with_self_ty(self_ty))
+    }
+}
+
+impl ExistentialTraitRef {
+    pub fn with_self_ty(&self, self_ty: Ty) -> TraitRef {
+        TraitRef::new(self.def_id, self_ty, &self.generic_args)
+    }
+}
+
 #[derive(Clone, Debug, Eq, PartialEq)]
 pub struct ExistentialProjection {
     pub def_id: TraitDef,
@@ -504,10 +620,39 @@ impl TraitDecl {
 
 pub type ImplTrait = EarlyBinder<TraitRef>;
 
+/// A complete reference to a trait, i.e., one where `Self` is known.
 #[derive(Clone, Debug, Eq, PartialEq)]
 pub struct TraitRef {
     pub def_id: TraitDef,
-    pub args: GenericArgs,
+    /// The generic arguments for this definition.
+    /// The first element must always be type, and it represents `Self`.
+    args: GenericArgs,
+}
+
+impl TraitRef {
+    pub fn new(def_id: TraitDef, self_ty: Ty, gen_args: &GenericArgs) -> TraitRef {
+        let mut args = vec![GenericArgKind::Type(self_ty)];
+        args.extend_from_slice(&gen_args.0);
+        TraitRef { def_id, args: GenericArgs(args) }
+    }
+
+    pub fn try_new(def_id: TraitDef, args: GenericArgs) -> Result<TraitRef, ()> {
+        match &args.0[..] {
+            [GenericArgKind::Type(_), ..] => Ok(TraitRef { def_id, args }),
+            _ => Err(()),
+        }
+    }
+
+    pub fn args(&self) -> &GenericArgs {
+        &self.args
+    }
+
+    pub fn self_ty(&self) -> Ty {
+        let GenericArgKind::Type(self_ty) = self.args.0[0] else {
+            panic!("Self must be a type, but found: {:?}", self.args.0[0])
+        };
+        self_ty
+    }
 }
 
 #[derive(Clone, Debug, Eq, PartialEq)]
diff --git a/tests/ui-fulldeps/stable-mir/check_instance.rs b/tests/ui-fulldeps/stable-mir/check_instance.rs
index a340877752d..e5a480cd61d 100644
--- a/tests/ui-fulldeps/stable-mir/check_instance.rs
+++ b/tests/ui-fulldeps/stable-mir/check_instance.rs
@@ -49,7 +49,7 @@ fn test_stable_mir(_tcx: TyCtxt<'_>) -> ControlFlow<()> {
     assert!(generic.iter().all(|item| mir::mono::Instance::try_from(*item).is_err()));
 
     for instance in instances {
-        test_body(instance.body())
+        test_body(instance.body().unwrap())
     }
     ControlFlow::Continue(())
 }
@@ -61,8 +61,10 @@ fn test_body(body: mir::Body) {
             Call { func, .. } => {
                 let TyKind::RigidTy(ty) = func.ty(body.locals()).kind() else { unreachable!() };
                 let RigidTy::FnDef(def, args) = ty else { unreachable!() };
-                let result = Instance::resolve(def, &args);
-                assert!(result.is_ok());
+                let instance = Instance::resolve(def, &args).unwrap();
+                let mangled_name = instance.mangled_name();
+                let body = instance.body();
+                assert!(body.is_some() || mangled_name == "setpwent", "Failed: {func:?}");
             }
             Goto { .. } | Assert { .. } | SwitchInt { .. } | Return | Drop { .. } => {
                 /* Do nothing */
@@ -105,10 +107,16 @@ fn generate_input(path: &str) -> std::io::Result<()> {
         LEN > 0 && a[0]
     }}
 
+    extern "C" {{
+        // Body should not be available.
+        fn setpwent();
+    }}
+
     pub fn monomorphic() {{
         let v = vec![10];
         let dup = ty_param(&v);
         assert_eq!(v, dup);
+        unsafe {{ setpwent() }};
     }}
 
     pub mod foo {{
diff --git a/tests/ui-fulldeps/stable-mir/crate-info.rs b/tests/ui-fulldeps/stable-mir/crate-info.rs
index ed6b786f5e1..025ed1b6a95 100644
--- a/tests/ui-fulldeps/stable-mir/crate-info.rs
+++ b/tests/ui-fulldeps/stable-mir/crate-info.rs
@@ -22,6 +22,7 @@ extern crate stable_mir;
 use rustc_hir::def::DefKind;
 use rustc_middle::ty::TyCtxt;
 use rustc_smir::rustc_internal;
+use stable_mir::ItemKind;
 use stable_mir::mir::mono::Instance;
 use stable_mir::ty::{RigidTy, TyKind};
 use std::assert_matches::assert_matches;
@@ -120,13 +121,13 @@ fn test_stable_mir(_tcx: TyCtxt<'_>) -> ControlFlow<()> {
 
     let monomorphic = get_item(&items, (DefKind::Fn, "monomorphic")).unwrap();
     let instance = Instance::try_from(monomorphic.clone()).unwrap();
-    for block in instance.body().blocks {
+    for block in instance.body().unwrap().blocks {
         match &block.terminator.kind {
             stable_mir::mir::TerminatorKind::Call { func, .. } => {
                 let TyKind::RigidTy(ty) = func.ty(&body.locals()).kind() else { unreachable!() };
                 let RigidTy::FnDef(def, args) = ty else { unreachable!() };
                 let next_func = Instance::resolve(def, &args).unwrap();
-                match next_func.body().locals()[1].ty.kind() {
+                match next_func.body().unwrap().locals()[1].ty.kind() {
                     TyKind::RigidTy(RigidTy::Uint(_)) | TyKind::RigidTy(RigidTy::Tuple(_)) => {}
                     other => panic!("{other:?}"),
                 }
@@ -172,7 +173,8 @@ fn get_item<'a>(
     item: (DefKind, &str),
 ) -> Option<&'a stable_mir::CrateItem> {
     items.iter().find(|crate_item| {
-        crate_item.kind().to_string() == format!("{:?}", item.0) && crate_item.name() == item.1
+        matches!((item.0, crate_item.kind()), (DefKind::Fn, ItemKind::Fn) | (DefKind::Const,
+            ItemKind::Const)) && crate_item.name() == item.1
     })
 }
 
diff --git a/tests/ui-fulldeps/stable-mir/projections.rs b/tests/ui-fulldeps/stable-mir/projections.rs
index 9c649a2effc..d00f17d206b 100644
--- a/tests/ui-fulldeps/stable-mir/projections.rs
+++ b/tests/ui-fulldeps/stable-mir/projections.rs
@@ -19,11 +19,11 @@ extern crate rustc_driver;
 extern crate rustc_interface;
 extern crate stable_mir;
 
-use rustc_hir::def::DefKind;
 use rustc_middle::ty::TyCtxt;
 use rustc_smir::rustc_internal;
 use stable_mir::mir::{ProjectionElem, Rvalue, StatementKind};
 use stable_mir::ty::{RigidTy, TyKind};
+use stable_mir::ItemKind;
 use std::assert_matches::assert_matches;
 use std::io::Write;
 use std::ops::ControlFlow;
@@ -33,7 +33,7 @@ const CRATE_NAME: &str = "input";
 /// Tests projections within Place objects
 fn test_place_projections(_tcx: TyCtxt<'_>) -> ControlFlow<()> {
     let items = stable_mir::all_local_items();
-    let body = get_item(&items, (DefKind::Fn, "projections")).unwrap().body();
+    let body = get_item(&items, (ItemKind::Fn, "projections")).unwrap().body();
     assert_eq!(body.blocks.len(), 4);
     // The first statement assigns `&s.c` to a local. The projections include a deref for `s`, since
     // `s` is passed as a reference argument, and a field access for field `c`.
@@ -131,10 +131,10 @@ fn test_place_projections(_tcx: TyCtxt<'_>) -> ControlFlow<()> {
 // Use internal API to find a function in a crate.
 fn get_item<'a>(
     items: &'a stable_mir::CrateItems,
-    item: (DefKind, &str),
+    item: (ItemKind, &str),
 ) -> Option<&'a stable_mir::CrateItem> {
     items.iter().find(|crate_item| {
-        crate_item.kind().to_string() == format!("{:?}", item.0) && crate_item.name() == item.1
+        crate_item.kind() == item.0 && crate_item.name() == item.1
     })
 }
 
diff --git a/tests/ui-fulldeps/stable-mir/smir_visitor.rs b/tests/ui-fulldeps/stable-mir/smir_visitor.rs
index de5148bb5f4..3ec63efcc06 100644
--- a/tests/ui-fulldeps/stable-mir/smir_visitor.rs
+++ b/tests/ui-fulldeps/stable-mir/smir_visitor.rs
@@ -40,7 +40,7 @@ fn test_visitor(_tcx: TyCtxt<'_>) -> ControlFlow<()> {
     let exit_fn = main_visitor.calls.last().unwrap();
     assert!(exit_fn.mangled_name().contains("exit_fn"), "Unexpected last function: {exit_fn:?}");
 
-    let exit_body = exit_fn.body();
+    let exit_body = exit_fn.body().unwrap();
     let exit_visitor = TestVisitor::collect(&exit_body);
     assert!(exit_visitor.ret_val.is_some());
     assert_eq!(exit_visitor.args.len(), 1);