about summary refs log tree commit diff
diff options
context:
space:
mode:
authorCelina G. Val <celinval@amazon.com>2023-11-16 06:24:53 -0800
committerCelina G. Val <celinval@amazon.com>2023-11-20 12:43:39 -0800
commitd3fa6a0e352d979aadb56e2f260b96ecc6169d12 (patch)
tree6bb055390dfb549d1da89c0c678317ac67bfeac2
parent46ecc10c6951a2a0e52d93fe5d3acae9743e3ab9 (diff)
downloadrust-d3fa6a0e352d979aadb56e2f260b96ecc6169d12.tar.gz
rust-d3fa6a0e352d979aadb56e2f260b96ecc6169d12.zip
Add place.ty() and Ty build from a kind to smir
-rw-r--r--compiler/rustc_smir/src/rustc_internal/internal.rs91
-rw-r--r--compiler/rustc_smir/src/rustc_smir/mod.rs46
-rw-r--r--compiler/stable_mir/src/error.rs9
-rw-r--r--compiler/stable_mir/src/lib.rs20
-rw-r--r--compiler/stable_mir/src/mir/body.rs77
-rw-r--r--compiler/stable_mir/src/mir/mono.rs13
-rw-r--r--compiler/stable_mir/src/ty.rs77
-rw-r--r--tests/ui-fulldeps/stable-mir/check_instance.rs3
-rw-r--r--tests/ui-fulldeps/stable-mir/crate-info.rs3
-rw-r--r--tests/ui-fulldeps/stable-mir/projections.rs20
-rw-r--r--tests/ui-fulldeps/stable-mir/smir_visitor.rs3
11 files changed, 321 insertions, 41 deletions
diff --git a/compiler/rustc_smir/src/rustc_internal/internal.rs b/compiler/rustc_smir/src/rustc_internal/internal.rs
index 5bb3c1a0d4c..954b292a3b9 100644
--- a/compiler/rustc_smir/src/rustc_internal/internal.rs
+++ b/compiler/rustc_smir/src/rustc_internal/internal.rs
@@ -9,8 +9,8 @@ use rustc_middle::ty::{self as rustc_ty, Ty as InternalTy};
 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,
+    AdtDef, Binder, BoundRegionKind, BoundTyKind, BoundVariableKind, ClosureKind, Const, FloatTy,
+    GenericArgKind, GenericArgs, IntTy, Region, RigidTy, TraitRef, Ty, UintTy,
 };
 use stable_mir::{AllocId, CrateItem, DefId};
 
@@ -63,6 +63,82 @@ impl<'tcx> RustcInternal<'tcx> for Ty {
     }
 }
 
+impl<'tcx> RustcInternal<'tcx> for RigidTy {
+    type T = rustc_ty::TyKind<'tcx>;
+
+    fn internal(&self, tables: &mut Tables<'tcx>) -> Self::T {
+        match self {
+            RigidTy::Bool => rustc_ty::TyKind::Bool,
+            RigidTy::Char => rustc_ty::TyKind::Char,
+            RigidTy::Int(int_ty) => rustc_ty::TyKind::Int(int_ty.internal(tables)),
+            RigidTy::Uint(uint_ty) => rustc_ty::TyKind::Uint(uint_ty.internal(tables)),
+            RigidTy::Float(float_ty) => rustc_ty::TyKind::Float(float_ty.internal(tables)),
+            RigidTy::Never => rustc_ty::TyKind::Never,
+            RigidTy::Array(ty, cnst) => {
+                rustc_ty::TyKind::Array(ty.internal(tables), ty_const(cnst, tables))
+            }
+            RigidTy::Adt(def, args) => {
+                rustc_ty::TyKind::Adt(def.internal(tables), args.internal(tables))
+            }
+            RigidTy::Str => rustc_ty::TyKind::Str,
+            RigidTy::Slice(ty) => rustc_ty::TyKind::Slice(ty.internal(tables)),
+            RigidTy::RawPtr(..)
+            | RigidTy::Ref(..)
+            | RigidTy::Foreign(_)
+            | RigidTy::FnDef(_, _)
+            | RigidTy::FnPtr(_)
+            | RigidTy::Closure(..)
+            | RigidTy::Coroutine(..)
+            | RigidTy::CoroutineWitness(..)
+            | RigidTy::Dynamic(..)
+            | RigidTy::Tuple(..) => {
+                todo!()
+            }
+        }
+    }
+}
+
+impl<'tcx> RustcInternal<'tcx> for IntTy {
+    type T = rustc_ty::IntTy;
+
+    fn internal(&self, _tables: &mut Tables<'tcx>) -> Self::T {
+        match self {
+            IntTy::Isize => rustc_ty::IntTy::Isize,
+            IntTy::I8 => rustc_ty::IntTy::I8,
+            IntTy::I16 => rustc_ty::IntTy::I16,
+            IntTy::I32 => rustc_ty::IntTy::I32,
+            IntTy::I64 => rustc_ty::IntTy::I64,
+            IntTy::I128 => rustc_ty::IntTy::I128,
+        }
+    }
+}
+
+impl<'tcx> RustcInternal<'tcx> for UintTy {
+    type T = rustc_ty::UintTy;
+
+    fn internal(&self, _tables: &mut Tables<'tcx>) -> Self::T {
+        match self {
+            UintTy::Usize => rustc_ty::UintTy::Usize,
+            UintTy::U8 => rustc_ty::UintTy::U8,
+            UintTy::U16 => rustc_ty::UintTy::U16,
+            UintTy::U32 => rustc_ty::UintTy::U32,
+            UintTy::U64 => rustc_ty::UintTy::U64,
+            UintTy::U128 => rustc_ty::UintTy::U128,
+        }
+    }
+}
+
+impl<'tcx> RustcInternal<'tcx> for FloatTy {
+    type T = rustc_ty::FloatTy;
+
+    fn internal(&self, _tables: &mut Tables<'tcx>) -> Self::T {
+        match self {
+            FloatTy::F32 => rustc_ty::FloatTy::F32,
+            FloatTy::F64 => rustc_ty::FloatTy::F64,
+        }
+    }
+}
+
 fn ty_const<'tcx>(constant: &Const, tables: &mut Tables<'tcx>) -> rustc_ty::Const<'tcx> {
     match constant.internal(tables) {
         rustc_middle::mir::Const::Ty(c) => c,
@@ -183,6 +259,17 @@ impl<'tcx> RustcInternal<'tcx> for ClosureKind {
     }
 }
 
+impl<'tcx> RustcInternal<'tcx> for AdtDef {
+    type T = rustc_ty::AdtDef<'tcx>;
+    fn internal(&self, tables: &mut Tables<'tcx>) -> Self::T {
+        let ty = tables.tcx.type_of(self.0.internal(&mut *tables)).instantiate_identity().kind();
+        let rustc_ty::TyKind::Adt(def, _) = ty else {
+            panic!("Expected an ADT definition, but found: {ty:?}")
+        };
+        *def
+    }
+}
+
 impl<'tcx, T> RustcInternal<'tcx> for &T
 where
     T: RustcInternal<'tcx>,
diff --git a/compiler/rustc_smir/src/rustc_smir/mod.rs b/compiler/rustc_smir/src/rustc_smir/mod.rs
index 89dbf40c7b4..f72cd9a9255 100644
--- a/compiler/rustc_smir/src/rustc_smir/mod.rs
+++ b/compiler/rustc_smir/src/rustc_smir/mod.rs
@@ -14,7 +14,7 @@ use rustc_hir::def::DefKind;
 use rustc_middle::mir;
 use rustc_middle::mir::interpret::{alloc_range, AllocId};
 use rustc_middle::mir::mono::MonoItem;
-use rustc_middle::ty::{self, Instance, ParamEnv, Ty, TyCtxt, Variance};
+use rustc_middle::ty::{self, Instance, ParamEnv, ScalarInt, Ty, TyCtxt, Variance};
 use rustc_span::def_id::{CrateNum, DefId, LOCAL_CRATE};
 use rustc_target::abi::FieldIdx;
 use stable_mir::mir::mono::InstanceDef;
@@ -24,7 +24,7 @@ use stable_mir::ty::{
     FloatTy, FnDef, GenericArgs, GenericParamDef, IntTy, LineInfo, Movability, RigidTy, Span,
     TyKind, UintTy,
 };
-use stable_mir::{self, opaque, Context, CrateItem, Filename, ItemKind};
+use stable_mir::{self, opaque, Context, CrateItem, Error, Filename, ItemKind};
 use std::cell::RefCell;
 use tracing::debug;
 
@@ -91,13 +91,14 @@ impl<'tcx> Context for TablesWrapper<'tcx> {
         new_item_kind(tables.tcx.def_kind(tables[item.0]))
     }
 
+    fn is_foreign_item(&self, item: CrateItem) -> bool {
+        let tables = self.0.borrow();
+        tables.tcx.is_foreign_item(tables[item.0])
+    }
+
     fn adt_kind(&self, def: AdtDef) -> AdtKind {
         let mut tables = self.0.borrow_mut();
-        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)
+        def.internal(&mut *tables).adt_kind().stable(&mut *tables)
     }
 
     fn def_ty(&self, item: stable_mir::DefId) -> stable_mir::ty::Ty {
@@ -302,6 +303,37 @@ impl<'tcx> Context for TablesWrapper<'tcx> {
         let closure_kind = kind.internal(&mut *tables);
         Instance::resolve_closure(tables.tcx, def_id, args_ref, closure_kind).stable(&mut *tables)
     }
+
+    fn adt_is_box(&self, def: AdtDef) -> bool {
+        let mut tables = self.0.borrow_mut();
+        def.internal(&mut *tables).is_box()
+    }
+
+    fn eval_target_usize(&self, cnst: &Const) -> Result<u64, Error> {
+        let mut tables = self.0.borrow_mut();
+        let mir_const = cnst.internal(&mut *tables);
+        mir_const
+            .try_eval_target_usize(tables.tcx, ParamEnv::empty())
+            .ok_or_else(|| Error::new(format!("Const `{cnst:?}` cannot be encoded as u64")))
+    }
+
+    fn usize_to_const(&self, val: u64) -> Result<Const, Error> {
+        let mut tables = self.0.borrow_mut();
+        let ty = tables.tcx.types.usize;
+        let size = tables.tcx.layout_of(ParamEnv::empty().and(ty)).unwrap().size;
+
+        let scalar = ScalarInt::try_from_uint(val, size).ok_or_else(|| {
+            Error::new(format!("Value overflow: cannot covert `{val}` to usize."))
+        })?;
+        Ok(ty::Const::new_value(tables.tcx, ty::ValTree::from_scalar_int(scalar), ty)
+            .stable(&mut *tables))
+    }
+
+    fn new_rigid_ty(&self, kind: RigidTy) -> stable_mir::ty::Ty {
+        let mut tables = self.0.borrow_mut();
+        let internal_kind = kind.internal(&mut *tables);
+        tables.tcx.mk_ty_from_kind(internal_kind).stable(&mut *tables)
+    }
 }
 
 pub(crate) struct TablesWrapper<'tcx>(pub(crate) RefCell<Tables<'tcx>>);
diff --git a/compiler/stable_mir/src/error.rs b/compiler/stable_mir/src/error.rs
index 19910691456..1ff65717e87 100644
--- a/compiler/stable_mir/src/error.rs
+++ b/compiler/stable_mir/src/error.rs
@@ -8,6 +8,11 @@ use std::convert::From;
 use std::fmt::{Debug, Display, Formatter};
 use std::{error, fmt};
 
+macro_rules! error {
+     ($fmt: literal $(,)?) => { Error(format!($fmt)) };
+     ($fmt: literal, $($arg:tt)*) => { Error(format!($fmt, $($arg:tt)*)) };
+ }
+
 /// An error type used to represent an error that has already been reported by the compiler.
 #[derive(Clone, Copy, PartialEq, Eq)]
 pub enum CompilerError<T> {
@@ -24,10 +29,10 @@ pub enum CompilerError<T> {
 
 /// A generic error to represent an API request that cannot be fulfilled.
 #[derive(Debug)]
-pub struct Error(String);
+pub struct Error(pub(crate) String);
 
 impl Error {
-    pub(crate) fn new(msg: String) -> Self {
+    pub fn new(msg: String) -> Self {
         Self(msg)
     }
 }
diff --git a/compiler/stable_mir/src/lib.rs b/compiler/stable_mir/src/lib.rs
index 79102dcce35..91f1066d720 100644
--- a/compiler/stable_mir/src/lib.rs
+++ b/compiler/stable_mir/src/lib.rs
@@ -31,6 +31,7 @@ use self::ty::{
 #[macro_use]
 extern crate scoped_tls;
 
+#[macro_use]
 pub mod error;
 pub mod mir;
 pub mod ty;
@@ -38,10 +39,10 @@ pub mod visitor;
 
 use crate::mir::pretty::function_name;
 use crate::mir::Mutability;
-use crate::ty::{AdtDef, AdtKind, ClosureDef, ClosureKind};
+use crate::ty::{AdtDef, AdtKind, ClosureDef, ClosureKind, Const, RigidTy};
 pub use error::*;
 use mir::mono::Instance;
-use ty::{Const, FnDef, GenericArgs};
+use ty::{FnDef, GenericArgs};
 
 /// Use String for now but we should replace it.
 pub type Symbol = String;
@@ -224,9 +225,24 @@ pub trait Context {
     /// Returns the `kind` of given `DefId`
     fn item_kind(&self, item: CrateItem) -> ItemKind;
 
+    /// Returns whether this is a foreign item.
+    fn is_foreign_item(&self, item: CrateItem) -> bool;
+
     /// Returns the kind of a given algebraic data type
     fn adt_kind(&self, def: AdtDef) -> AdtKind;
 
+    /// Returns if the ADT is a box.
+    fn adt_is_box(&self, def: AdtDef) -> bool;
+
+    /// Evaluate constant as a target usize.
+    fn eval_target_usize(&self, cnst: &Const) -> Result<u64, Error>;
+
+    /// Create a target usize constant for the given value.
+    fn usize_to_const(&self, val: u64) -> Result<Const, Error>;
+
+    /// Create a new type from the given kind.
+    fn new_rigid_ty(&self, kind: RigidTy) -> Ty;
+
     /// Returns the type of given crate item.
     fn def_ty(&self, item: DefId) -> Ty;
 
diff --git a/compiler/stable_mir/src/mir/body.rs b/compiler/stable_mir/src/mir/body.rs
index fa58a7ffe15..8cdb054de9a 100644
--- a/compiler/stable_mir/src/mir/body.rs
+++ b/compiler/stable_mir/src/mir/body.rs
@@ -1,8 +1,10 @@
 use crate::mir::pretty::{function_body, pretty_statement};
-use crate::ty::{AdtDef, ClosureDef, Const, CoroutineDef, GenericArgs, Movability, Region, Ty};
-use crate::Opaque;
-use crate::Span;
+use crate::ty::{
+    AdtDef, ClosureDef, Const, CoroutineDef, GenericArgs, Movability, Region, RigidTy, Ty, TyKind,
+};
+use crate::{Error, Span, Opaque};
 use std::io;
+
 /// The SMIR representation of a single function.
 #[derive(Clone, Debug)]
 pub struct Body {
@@ -561,7 +563,7 @@ pub struct SwitchTarget {
     pub target: usize,
 }
 
-#[derive(Clone, Debug, Eq, PartialEq)]
+#[derive(Copy, Clone, Debug, Eq, PartialEq)]
 pub enum BorrowKind {
     /// Data must be immutable and is aliasable.
     Shared,
@@ -579,14 +581,14 @@ pub enum BorrowKind {
     },
 }
 
-#[derive(Clone, Debug, Eq, PartialEq)]
+#[derive(Copy, Clone, Debug, Eq, PartialEq)]
 pub enum MutBorrowKind {
     Default,
     TwoPhaseBorrow,
     ClosureCapture,
 }
 
-#[derive(Clone, Debug, PartialEq, Eq)]
+#[derive(Copy, Clone, Debug, PartialEq, Eq)]
 pub enum Mutability {
     Not,
     Mut,
@@ -651,10 +653,16 @@ pub enum NullOp {
 }
 
 impl Operand {
-    pub fn ty(&self, locals: &[LocalDecl]) -> Ty {
+    /// Get the type of an operand relative to the local declaration.
+    ///
+    /// In order to retrieve the correct type, the `locals` argument must match the list of all
+    /// locals from the function body where this operand originates from.
+    ///
+    /// Errors indicate a malformed operand or incompatible locals list.
+    pub fn ty(&self, locals: &[LocalDecl]) -> Result<Ty, Error> {
         match self {
             Operand::Copy(place) | Operand::Move(place) => place.ty(locals),
-            Operand::Constant(c) => c.ty(),
+            Operand::Constant(c) => Ok(c.ty()),
         }
     }
 }
@@ -666,12 +674,51 @@ impl Constant {
 }
 
 impl Place {
-    // FIXME(klinvill): This function is expected to resolve down the chain of projections to get
-    // the type referenced at the end of it. E.g. calling `ty()` on `*(_1.f)` should end up
-    // returning the type referenced by `f`. The information needed to do this may not currently be
-    // present in Stable MIR since at least an implementation for AdtDef is probably needed.
-    pub fn ty(&self, locals: &[LocalDecl]) -> Ty {
-        let _start_ty = locals[self.local].ty;
-        todo!("Implement projection")
+    /// Resolve down the chain of projections to get the type referenced at the end of it.
+    /// E.g.:
+    /// Calling `ty()` on `var.field` should return the type of `field`.
+    ///
+    /// In order to retrieve the correct type, the `locals` argument must match the list of all
+    /// locals from the function body where this place originates from.
+    pub fn ty(&self, locals: &[LocalDecl]) -> Result<Ty, Error> {
+        let start_ty = locals[self.local].ty;
+        self.projection.iter().fold(Ok(start_ty), |place_ty, elem| {
+            let ty = place_ty?;
+            match elem {
+                ProjectionElem::Deref => {
+                    let deref_ty = ty
+                        .kind()
+                        .builtin_deref(true)
+                        .ok_or_else(|| error!("Cannot dereference type: {ty:?}"))?;
+                    Ok(deref_ty.ty)
+                }
+                ProjectionElem::Field(_idx, fty) => Ok(*fty),
+                ProjectionElem::Index(_) | ProjectionElem::ConstantIndex { .. } => ty
+                    .kind()
+                    .builtin_index()
+                    .ok_or_else(|| error!("Cannot index non-array type: {ty:?}")),
+                ProjectionElem::Subslice { from, to, from_end } => {
+                    let ty_kind = ty.kind();
+                    match ty_kind {
+                        TyKind::RigidTy(RigidTy::Slice(..)) => Ok(ty),
+                        TyKind::RigidTy(RigidTy::Array(inner, _)) if !from_end => {
+                            Ty::try_new_array(
+                                inner,
+                                to.checked_sub(*from)
+                                    .ok_or_else(|| error!("Subslice overflow: {from}..{to}"))?,
+                            )
+                        }
+                        TyKind::RigidTy(RigidTy::Array(inner, size)) => {
+                            let size = size.eval_target_usize()?;
+                            let len = size - from - to;
+                            Ty::try_new_array(inner, len)
+                        }
+                        _ => Err(Error(format!("Cannot subslice non-array type: `{ty_kind:?}`"))),
+                    }
+                }
+                ProjectionElem::Downcast(_) => Ok(ty),
+                ProjectionElem::OpaqueCast(ty) | ProjectionElem::Subtype(ty) => Ok(*ty),
+            }
+        })
     }
 }
diff --git a/compiler/stable_mir/src/mir/mono.rs b/compiler/stable_mir/src/mir/mono.rs
index 8562bfd3905..8c43f2c4b8f 100644
--- a/compiler/stable_mir/src/mir/mono.rs
+++ b/compiler/stable_mir/src/mir/mono.rs
@@ -1,7 +1,7 @@
 use crate::mir::Body;
 use crate::ty::{ClosureDef, ClosureKind, FnDef, GenericArgs, IndexedVal, Ty};
 use crate::{with, CrateItem, DefId, Error, ItemKind, Opaque};
-use std::fmt::Debug;
+use std::fmt::{Debug, Formatter};
 
 #[derive(Clone, Debug, PartialEq, Eq, Hash)]
 pub enum MonoItem {
@@ -10,7 +10,7 @@ pub enum MonoItem {
     GlobalAsm(Opaque),
 }
 
-#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
+#[derive(Copy, Clone, PartialEq, Eq, Hash)]
 pub struct Instance {
     /// The type of instance.
     pub kind: InstanceKind,
@@ -83,6 +83,15 @@ impl Instance {
     }
 }
 
+impl Debug for Instance {
+    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
+        f.debug_struct("Instance")
+            .field("kind", &self.kind)
+            .field("def", &self.mangled_name())
+            .finish()
+    }
+}
+
 /// Try to convert a crate item into an instance.
 /// The item cannot be generic in order to be converted into an instance.
 impl TryFrom<CrateItem> for Instance {
diff --git a/compiler/stable_mir/src/ty.rs b/compiler/stable_mir/src/ty.rs
index fa932c5d81a..f0b11dce9aa 100644
--- a/compiler/stable_mir/src/ty.rs
+++ b/compiler/stable_mir/src/ty.rs
@@ -1,7 +1,7 @@
 use super::{
     mir::Safety,
     mir::{Body, Mutability},
-    with, AllocId, DefId, Symbol,
+    with, AllocId, DefId, Error, Symbol,
 };
 use crate::{Filename, Opaque};
 use std::fmt::{self, Debug, Display, Formatter};
@@ -15,6 +15,21 @@ impl Debug for Ty {
     }
 }
 
+/// Constructors for `Ty`.
+impl Ty {
+    /// Create a new type from a given kind.
+    ///
+    /// Note that not all types may be supported at this point.
+    fn from_rigid_kind(kind: RigidTy) -> Ty {
+        with(|cx| cx.new_rigid_ty(kind))
+    }
+
+    /// Create a new array type.
+    pub fn try_new_array(elem_ty: Ty, size: u64) -> Result<Ty, Error> {
+        Ok(Ty::from_rigid_kind(RigidTy::Array(elem_ty, Const::try_from_target_usize(size)?)))
+    }
+}
+
 impl Ty {
     pub fn kind(&self) -> TyKind {
         with(|context| context.ty_kind(*self))
@@ -47,6 +62,16 @@ impl Const {
     pub fn ty(&self) -> Ty {
         self.ty
     }
+
+    /// Creates an interned usize constant.
+    fn try_from_target_usize(val: u64) -> Result<Self, Error> {
+        with(|cx| cx.usize_to_const(val))
+    }
+
+    /// Try to evaluate to a target `usize`.
+    pub fn eval_target_usize(&self) -> Result<u64, Error> {
+        with(|cx| cx.eval_target_usize(self))
+    }
 }
 
 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
@@ -173,6 +198,38 @@ impl TyKind {
             None
         }
     }
+
+    /// Returns the type of `ty[i]` for builtin types.
+    pub fn builtin_index(&self) -> Option<Ty> {
+        match self.rigid()? {
+            RigidTy::Array(ty, _) | RigidTy::Slice(ty) => Some(*ty),
+            _ => None,
+        }
+    }
+
+    /// Returns the type and mutability of `*ty` for builtin types.
+    ///
+    /// The parameter `explicit` indicates if this is an *explicit* dereference.
+    /// Some types -- notably unsafe ptrs -- can only be dereferenced explicitly.
+    pub fn builtin_deref(&self, explicit: bool) -> Option<TypeAndMut> {
+        match self.rigid()? {
+            RigidTy::Adt(def, args) if def.is_box() => {
+                Some(TypeAndMut { ty: *args.0.first()?.ty()?, mutability: Mutability::Not })
+            }
+            RigidTy::Ref(_, ty, mutability) => {
+                Some(TypeAndMut { ty: *ty, mutability: *mutability })
+            }
+            RigidTy::RawPtr(ty, mutability) if explicit => {
+                Some(TypeAndMut { ty: *ty, mutability: *mutability })
+            }
+            _ => None,
+        }
+    }
+}
+
+pub struct TypeAndMut {
+    pub ty: Ty,
+    pub mutability: Mutability,
 }
 
 #[derive(Clone, Debug, Eq, PartialEq)]
@@ -199,6 +256,12 @@ pub enum RigidTy {
     CoroutineWitness(CoroutineWitnessDef, GenericArgs),
 }
 
+impl From<RigidTy> for TyKind {
+    fn from(value: RigidTy) -> Self {
+        TyKind::RigidTy(value)
+    }
+}
+
 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
 pub enum IntTy {
     Isize,
@@ -269,6 +332,10 @@ impl AdtDef {
     pub fn kind(&self) -> AdtKind {
         with(|cx| cx.adt_kind(*self))
     }
+
+    pub fn is_box(&self) -> bool {
+        with(|cx| cx.adt_is_box(*self))
+    }
 }
 
 impl Display for AdtKind {
@@ -363,6 +430,14 @@ impl GenericArgKind {
             _ => panic!("{self:?}"),
         }
     }
+
+    /// Return the generic argument type if applicable, otherwise return `None`.
+    pub fn ty(&self) -> Option<&Ty> {
+        match self {
+            GenericArgKind::Type(ty) => Some(ty),
+            _ => None,
+        }
+    }
 }
 
 #[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 e5a480cd61d..976dfee774b 100644
--- a/tests/ui-fulldeps/stable-mir/check_instance.rs
+++ b/tests/ui-fulldeps/stable-mir/check_instance.rs
@@ -59,7 +59,8 @@ fn test_body(body: mir::Body) {
     for term in body.blocks.iter().map(|bb| &bb.terminator) {
         match &term.kind {
             Call { func, .. } => {
-                let TyKind::RigidTy(ty) = func.ty(body.locals()).kind() else { unreachable!() };
+                let TyKind::RigidTy(ty) = func.ty(body.locals()).unwrap().kind() else { unreachable!
+                () };
                 let RigidTy::FnDef(def, args) = ty else { unreachable!() };
                 let instance = Instance::resolve(def, &args).unwrap();
                 let mangled_name = instance.mangled_name();
diff --git a/tests/ui-fulldeps/stable-mir/crate-info.rs b/tests/ui-fulldeps/stable-mir/crate-info.rs
index 025ed1b6a95..4164f041022 100644
--- a/tests/ui-fulldeps/stable-mir/crate-info.rs
+++ b/tests/ui-fulldeps/stable-mir/crate-info.rs
@@ -124,7 +124,8 @@ fn test_stable_mir(_tcx: TyCtxt<'_>) -> ControlFlow<()> {
     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 TyKind::RigidTy(ty) = func.ty(&body.locals()).unwrap().kind() else {
+                    unreachable!() };
                 let RigidTy::FnDef(def, args) = ty else { unreachable!() };
                 let next_func = Instance::resolve(def, &args).unwrap();
                 match next_func.body().unwrap().locals()[1].ty.kind() {
diff --git a/tests/ui-fulldeps/stable-mir/projections.rs b/tests/ui-fulldeps/stable-mir/projections.rs
index d00f17d206b..29930763591 100644
--- a/tests/ui-fulldeps/stable-mir/projections.rs
+++ b/tests/ui-fulldeps/stable-mir/projections.rs
@@ -22,7 +22,7 @@ extern crate stable_mir;
 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::ty::{RigidTy, TyKind, UintTy};
 use stable_mir::ItemKind;
 use std::assert_matches::assert_matches;
 use std::io::Write;
@@ -39,7 +39,7 @@ fn test_place_projections(_tcx: TyCtxt<'_>) -> ControlFlow<()> {
     // `s` is passed as a reference argument, and a field access for field `c`.
     match &body.blocks[0].statements[0].kind {
         StatementKind::Assign(
-            stable_mir::mir::Place { local: _, projection: local_proj },
+            place @ stable_mir::mir::Place { local: _, projection: local_proj },
             Rvalue::Ref(_, _, stable_mir::mir::Place { local: _, projection: r_proj }),
         ) => {
             // We can't match on vecs, only on slices. Comparing statements for equality wouldn't be
@@ -48,10 +48,14 @@ fn test_place_projections(_tcx: TyCtxt<'_>) -> ControlFlow<()> {
             assert!(local_proj.is_empty());
             match &r_proj[..] {
                 // Similarly we can't match against a type, only against its kind.
-                [ProjectionElem::Deref, ProjectionElem::Field(2, ty)] => assert_matches!(
-                    ty.kind(),
-                    TyKind::RigidTy(RigidTy::Uint(stable_mir::ty::UintTy::U8))
-                ),
+                [ProjectionElem::Deref, ProjectionElem::Field(2, ty)] => {
+                    assert_matches!(
+                        ty.kind(),
+                        TyKind::RigidTy(RigidTy::Uint(stable_mir::ty::UintTy::U8))
+                    );
+                    let ty = place.ty(body.locals()).unwrap();
+                    assert_matches!(ty.kind().rigid(), Some(RigidTy::Ref(..)));
+                },
                 other => panic!(
                     "Unable to match against expected rvalue projection. Expected the projection \
                      for `s.c`, which is a Deref and u8 Field. Got: {:?}",
@@ -69,7 +73,7 @@ fn test_place_projections(_tcx: TyCtxt<'_>) -> ControlFlow<()> {
     // since `slice` is a reference, and an index.
     match &body.blocks[2].statements[0].kind {
         StatementKind::Assign(
-            stable_mir::mir::Place { local: _, projection: local_proj },
+            place @ stable_mir::mir::Place { local: _, projection: local_proj },
             Rvalue::Use(stable_mir::mir::Operand::Copy(stable_mir::mir::Place {
                 local: _,
                 projection: r_proj,
@@ -80,6 +84,8 @@ fn test_place_projections(_tcx: TyCtxt<'_>) -> ControlFlow<()> {
             // wildcards.
             assert!(local_proj.is_empty());
             assert_matches!(r_proj[..], [ProjectionElem::Deref, ProjectionElem::Index(_)]);
+            let ty = place.ty(body.locals()).unwrap();
+            assert_matches!(ty.kind().rigid(), Some(RigidTy::Uint(UintTy::U8)));
         }
         other => panic!(
             "Unable to match against expected Assign statement with a Use rvalue. Expected the \
diff --git a/tests/ui-fulldeps/stable-mir/smir_visitor.rs b/tests/ui-fulldeps/stable-mir/smir_visitor.rs
index 3ec63efcc06..027b0e7d9e8 100644
--- a/tests/ui-fulldeps/stable-mir/smir_visitor.rs
+++ b/tests/ui-fulldeps/stable-mir/smir_visitor.rs
@@ -92,7 +92,8 @@ impl<'a> mir::MirVisitor for TestVisitor<'a> {
 
     fn visit_terminator(&mut self, term: &mir::Terminator, location: mir::visit::Location) {
         if let mir::TerminatorKind::Call { func, .. } = &term.kind {
-            let ty::TyKind::RigidTy(ty) = func.ty(self.body.locals()).kind() else { unreachable!
+            let ty::TyKind::RigidTy(ty) = func.ty(self.body.locals()).unwrap().kind() else {
+                unreachable!
             () };
             let ty::RigidTy::FnDef(def, args) = ty else { unreachable!() };
             self.calls.push(mir::mono::Instance::resolve(def, &args).unwrap());