1
Fork 0

Add place.ty() and Ty build from a kind to smir

This commit is contained in:
Celina G. Val 2023-11-16 06:24:53 -08:00
parent 46ecc10c69
commit d3fa6a0e35
11 changed files with 321 additions and 41 deletions

View file

@ -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)
}
}

View file

@ -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;

View file

@ -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),
}
})
}
}

View file

@ -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 {

View file

@ -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)]