Skip to content

Commit

Permalink
Auto merge of #118015 - celinval:smir-place-ty, r=compiler-errors
Browse files Browse the repository at this point in the history
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`
  • Loading branch information
bors committed Nov 21, 2023
2 parents baf4abf + d94df62 commit 390e3c8
Show file tree
Hide file tree
Showing 11 changed files with 323 additions and 41 deletions.
87 changes: 85 additions & 2 deletions compiler/rustc_smir/src/rustc_internal/internal.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};

Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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>,
Expand Down
46 changes: 39 additions & 7 deletions compiler/rustc_smir/src/rustc_smir/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;

Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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>>);
Expand Down
9 changes: 7 additions & 2 deletions compiler/stable_mir/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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> {
Expand All @@ -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)
}
}
Expand Down
20 changes: 18 additions & 2 deletions compiler/stable_mir/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,17 +31,18 @@ use self::ty::{
#[macro_use]
extern crate scoped_tls;

#[macro_use]
pub mod error;
pub mod mir;
pub mod ty;
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;
Expand Down Expand Up @@ -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;

Expand Down
83 changes: 68 additions & 15 deletions compiler/stable_mir/src/mir/body.rs
Original file line number Diff line number Diff line change
@@ -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 {
Expand Down Expand Up @@ -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,
Expand All @@ -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,
Expand Down Expand Up @@ -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()),
}
}
}
Expand All @@ -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)
}
}
Loading

0 comments on commit 390e3c8

Please sign in to comment.