mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-02 07:22:42 +00:00
Auto merge of #118015 - celinval:smir-place-ty, r=compiler-errors
Add place.ty() and Ty build from a kind to smir Add a method to retrieve the type of a place and a few utility functions needed to build the projection type. I decided to return a result to avoid panicking if the user passes invalid inputs, such as wrong list of locals. r? `@spastorino`
This commit is contained in:
commit
390e3c8b66
@ -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,13 @@ 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 {
|
||||
tables.tcx.adt_def(self.0.internal(&mut *tables))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx, T> RustcInternal<'tcx> for &T
|
||||
where
|
||||
T: RustcInternal<'tcx>,
|
||||
|
@ -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 convert `{val}` to usize."))
|
||||
})?;
|
||||
Ok(ty::Const::new_value(tables.tcx, ty::ValTree::from_scalar_int(scalar), ty)
|
||||
.stable(&mut *tables))
|
||||
}
|
||||
|
||||
fn new_rigid_ty(&self, kind: RigidTy) -> stable_mir::ty::Ty {
|
||||
let mut tables = self.0.borrow_mut();
|
||||
let internal_kind = kind.internal(&mut *tables);
|
||||
tables.tcx.mk_ty_from_kind(internal_kind).stable(&mut *tables)
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) struct TablesWrapper<'tcx>(pub(crate) RefCell<Tables<'tcx>>);
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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, Opaque, Span};
|
||||
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,57 @@ 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 => Self::deref_ty(ty),
|
||||
ProjectionElem::Field(_idx, fty) => Ok(*fty),
|
||||
ProjectionElem::Index(_) | ProjectionElem::ConstantIndex { .. } => {
|
||||
Self::index_ty(ty)
|
||||
}
|
||||
ProjectionElem::Subslice { from, to, from_end } => {
|
||||
Self::subslice_ty(ty, from, to, from_end)
|
||||
}
|
||||
ProjectionElem::Downcast(_) => Ok(ty),
|
||||
ProjectionElem::OpaqueCast(ty) | ProjectionElem::Subtype(ty) => Ok(*ty),
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fn index_ty(ty: Ty) -> Result<Ty, Error> {
|
||||
ty.kind().builtin_index().ok_or_else(|| error!("Cannot index non-array type: {ty:?}"))
|
||||
}
|
||||
|
||||
fn subslice_ty(ty: Ty, from: &u64, to: &u64, from_end: &bool) -> Result<Ty, Error> {
|
||||
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:?}`"))),
|
||||
}
|
||||
}
|
||||
|
||||
fn deref_ty(ty: Ty) -> Result<Ty, Error> {
|
||||
let deref_ty = ty
|
||||
.kind()
|
||||
.builtin_deref(true)
|
||||
.ok_or_else(|| error!("Cannot dereference type: {ty:?}"))?;
|
||||
Ok(deref_ty.ty)
|
||||
}
|
||||
}
|
||||
|
@ -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 {
|
||||
|
@ -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)]
|
||||
|
@ -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();
|
||||
|
@ -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() {
|
||||
|
@ -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 \
|
||||
|
@ -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());
|
||||
|
Loading…
Reference in New Issue
Block a user