Skip to content

Commit 857eb17

Browse files
committed
Add place.ty() and Ty build from a kind to smir
1 parent 4d7f952 commit 857eb17

File tree

11 files changed

+319
-39
lines changed

11 files changed

+319
-39
lines changed

compiler/rustc_smir/src/rustc_internal/internal.rs

+89-2
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@ use rustc_middle::ty::{self as rustc_ty, Ty as InternalTy};
99
use rustc_span::Symbol;
1010
use stable_mir::mir::mono::{Instance, MonoItem, StaticDef};
1111
use stable_mir::ty::{
12-
Binder, BoundRegionKind, BoundTyKind, BoundVariableKind, ClosureKind, Const, GenericArgKind,
13-
GenericArgs, Region, TraitRef, Ty,
12+
AdtDef, Binder, BoundRegionKind, BoundTyKind, BoundVariableKind, ClosureKind, Const, FloatTy,
13+
GenericArgKind, GenericArgs, IntTy, Region, RigidTy, TraitRef, Ty, UintTy,
1414
};
1515
use stable_mir::{AllocId, CrateItem, DefId};
1616

@@ -63,6 +63,82 @@ impl<'tcx> RustcInternal<'tcx> for Ty {
6363
}
6464
}
6565

66+
impl<'tcx> RustcInternal<'tcx> for RigidTy {
67+
type T = rustc_ty::TyKind<'tcx>;
68+
69+
fn internal(&self, tables: &mut Tables<'tcx>) -> Self::T {
70+
match self {
71+
RigidTy::Bool => rustc_ty::TyKind::Bool,
72+
RigidTy::Char => rustc_ty::TyKind::Char,
73+
RigidTy::Int(int_ty) => rustc_ty::TyKind::Int(int_ty.internal(tables)),
74+
RigidTy::Uint(uint_ty) => rustc_ty::TyKind::Uint(uint_ty.internal(tables)),
75+
RigidTy::Float(float_ty) => rustc_ty::TyKind::Float(float_ty.internal(tables)),
76+
RigidTy::Never => rustc_ty::TyKind::Never,
77+
RigidTy::Array(ty, cnst) => {
78+
rustc_ty::TyKind::Array(ty.internal(tables), ty_const(cnst, tables))
79+
}
80+
RigidTy::Adt(def, args) => {
81+
rustc_ty::TyKind::Adt(def.internal(tables), args.internal(tables))
82+
}
83+
RigidTy::Str => rustc_ty::TyKind::Str,
84+
RigidTy::Slice(ty) => rustc_ty::TyKind::Slice(ty.internal(tables)),
85+
RigidTy::RawPtr(..)
86+
| RigidTy::Ref(..)
87+
| RigidTy::Foreign(_)
88+
| RigidTy::FnDef(_, _)
89+
| RigidTy::FnPtr(_)
90+
| RigidTy::Closure(..)
91+
| RigidTy::Coroutine(..)
92+
| RigidTy::CoroutineWitness(..)
93+
| RigidTy::Dynamic(..)
94+
| RigidTy::Tuple(..) => {
95+
todo!()
96+
}
97+
}
98+
}
99+
}
100+
101+
impl<'tcx> RustcInternal<'tcx> for IntTy {
102+
type T = rustc_ty::IntTy;
103+
104+
fn internal(&self, _tables: &mut Tables<'tcx>) -> Self::T {
105+
match self {
106+
IntTy::Isize => rustc_ty::IntTy::Isize,
107+
IntTy::I8 => rustc_ty::IntTy::I8,
108+
IntTy::I16 => rustc_ty::IntTy::I16,
109+
IntTy::I32 => rustc_ty::IntTy::I32,
110+
IntTy::I64 => rustc_ty::IntTy::I64,
111+
IntTy::I128 => rustc_ty::IntTy::I128,
112+
}
113+
}
114+
}
115+
116+
impl<'tcx> RustcInternal<'tcx> for UintTy {
117+
type T = rustc_ty::UintTy;
118+
119+
fn internal(&self, _tables: &mut Tables<'tcx>) -> Self::T {
120+
match self {
121+
UintTy::Usize => rustc_ty::UintTy::Usize,
122+
UintTy::U8 => rustc_ty::UintTy::U8,
123+
UintTy::U16 => rustc_ty::UintTy::U16,
124+
UintTy::U32 => rustc_ty::UintTy::U32,
125+
UintTy::U64 => rustc_ty::UintTy::U64,
126+
UintTy::U128 => rustc_ty::UintTy::U128,
127+
}
128+
}
129+
}
130+
131+
impl<'tcx> RustcInternal<'tcx> for FloatTy {
132+
type T = rustc_ty::FloatTy;
133+
134+
fn internal(&self, _tables: &mut Tables<'tcx>) -> Self::T {
135+
match self {
136+
FloatTy::F32 => rustc_ty::FloatTy::F32,
137+
FloatTy::F64 => rustc_ty::FloatTy::F64,
138+
}
139+
}
140+
}
141+
66142
fn ty_const<'tcx>(constant: &Const, tables: &mut Tables<'tcx>) -> rustc_ty::Const<'tcx> {
67143
match constant.internal(tables) {
68144
rustc_middle::mir::Const::Ty(c) => c,
@@ -183,6 +259,17 @@ impl<'tcx> RustcInternal<'tcx> for ClosureKind {
183259
}
184260
}
185261

262+
impl<'tcx> RustcInternal<'tcx> for AdtDef {
263+
type T = rustc_ty::AdtDef<'tcx>;
264+
fn internal(&self, tables: &mut Tables<'tcx>) -> Self::T {
265+
let ty = tables.tcx.type_of(self.0.internal(&mut *tables)).instantiate_identity().kind();
266+
let rustc_ty::TyKind::Adt(def, _) = ty else {
267+
panic!("Expected an ADT definition, but found: {ty:?}")
268+
};
269+
*def
270+
}
271+
}
272+
186273
impl<'tcx, T> RustcInternal<'tcx> for &T
187274
where
188275
T: RustcInternal<'tcx>,

compiler/rustc_smir/src/rustc_smir/mod.rs

+39-7
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ use rustc_hir::def::DefKind;
1414
use rustc_middle::mir;
1515
use rustc_middle::mir::interpret::{alloc_range, AllocId};
1616
use rustc_middle::mir::mono::MonoItem;
17-
use rustc_middle::ty::{self, Instance, ParamEnv, Ty, TyCtxt, Variance};
17+
use rustc_middle::ty::{self, Instance, ParamEnv, ScalarInt, Ty, TyCtxt, Variance};
1818
use rustc_span::def_id::{CrateNum, DefId, LOCAL_CRATE};
1919
use rustc_target::abi::FieldIdx;
2020
use stable_mir::mir::mono::InstanceDef;
@@ -24,7 +24,7 @@ use stable_mir::ty::{
2424
FloatTy, FnDef, GenericArgs, GenericParamDef, IntTy, LineInfo, Movability, RigidTy, Span,
2525
TyKind, UintTy,
2626
};
27-
use stable_mir::{self, opaque, Context, CrateItem, Filename, ItemKind};
27+
use stable_mir::{self, opaque, Context, CrateItem, Error, Filename, ItemKind};
2828
use std::cell::RefCell;
2929
use tracing::debug;
3030

@@ -91,13 +91,14 @@ impl<'tcx> Context for TablesWrapper<'tcx> {
9191
new_item_kind(tables.tcx.def_kind(tables[item.0]))
9292
}
9393

94+
fn is_foreign_item(&self, item: CrateItem) -> bool {
95+
let tables = self.0.borrow();
96+
tables.tcx.is_foreign_item(tables[item.0])
97+
}
98+
9499
fn adt_kind(&self, def: AdtDef) -> AdtKind {
95100
let mut tables = self.0.borrow_mut();
96-
let ty = tables.tcx.type_of(def.0.internal(&mut *tables)).instantiate_identity().kind();
97-
let ty::TyKind::Adt(def, _) = ty else {
98-
panic!("Expected an ADT definition, but found: {ty:?}")
99-
};
100-
def.adt_kind().stable(&mut *tables)
101+
def.internal(&mut *tables).adt_kind().stable(&mut *tables)
101102
}
102103

103104
fn def_ty(&self, item: stable_mir::DefId) -> stable_mir::ty::Ty {
@@ -298,6 +299,37 @@ impl<'tcx> Context for TablesWrapper<'tcx> {
298299
let closure_kind = kind.internal(&mut *tables);
299300
Instance::resolve_closure(tables.tcx, def_id, args_ref, closure_kind).stable(&mut *tables)
300301
}
302+
303+
fn adt_is_box(&self, def: AdtDef) -> bool {
304+
let mut tables = self.0.borrow_mut();
305+
def.internal(&mut *tables).is_box()
306+
}
307+
308+
fn eval_target_usize(&self, cnst: &Const) -> Result<u64, Error> {
309+
let mut tables = self.0.borrow_mut();
310+
let mir_const = cnst.internal(&mut *tables);
311+
mir_const
312+
.try_eval_target_usize(tables.tcx, ParamEnv::empty())
313+
.ok_or_else(|| Error::new(format!("Const `{cnst:?}` cannot be encoded as u64")))
314+
}
315+
316+
fn usize_to_const(&self, val: u64) -> Result<Const, Error> {
317+
let mut tables = self.0.borrow_mut();
318+
let ty = tables.tcx.types.usize;
319+
let size = tables.tcx.layout_of(ParamEnv::empty().and(ty)).unwrap().size;
320+
321+
let scalar = ScalarInt::try_from_uint(val, size).ok_or_else(|| {
322+
Error::new(format!("Value overflow: cannot covert `{val}` to usize."))
323+
})?;
324+
Ok(ty::Const::new_value(tables.tcx, ty::ValTree::from_scalar_int(scalar), ty)
325+
.stable(&mut *tables))
326+
}
327+
328+
fn new_rigid_ty(&self, kind: RigidTy) -> stable_mir::ty::Ty {
329+
let mut tables = self.0.borrow_mut();
330+
let internal_kind = kind.internal(&mut *tables);
331+
tables.tcx.mk_ty_from_kind(internal_kind).stable(&mut *tables)
332+
}
301333
}
302334

303335
pub(crate) struct TablesWrapper<'tcx>(pub(crate) RefCell<Tables<'tcx>>);

compiler/stable_mir/src/error.rs

+7-2
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,11 @@ use std::convert::From;
88
use std::fmt::{Debug, Display, Formatter};
99
use std::{error, fmt};
1010

11+
macro_rules! error {
12+
($fmt: literal $(,)?) => { Error(format!($fmt)) };
13+
($fmt: literal, $($arg:tt)*) => { Error(format!($fmt, $($arg:tt)*)) };
14+
}
15+
1116
/// An error type used to represent an error that has already been reported by the compiler.
1217
#[derive(Clone, Copy, PartialEq, Eq)]
1318
pub enum CompilerError<T> {
@@ -24,10 +29,10 @@ pub enum CompilerError<T> {
2429

2530
/// A generic error to represent an API request that cannot be fulfilled.
2631
#[derive(Debug)]
27-
pub struct Error(String);
32+
pub struct Error(pub(crate) String);
2833

2934
impl Error {
30-
pub(crate) fn new(msg: String) -> Self {
35+
pub fn new(msg: String) -> Self {
3136
Self(msg)
3237
}
3338
}

compiler/stable_mir/src/lib.rs

+17-1
Original file line numberDiff line numberDiff line change
@@ -31,12 +31,13 @@ use self::ty::{
3131
#[macro_use]
3232
extern crate scoped_tls;
3333

34+
#[macro_use]
3435
pub mod error;
3536
pub mod mir;
3637
pub mod ty;
3738
pub mod visitor;
3839

39-
use crate::ty::{AdtDef, AdtKind, ClosureDef, ClosureKind};
40+
use crate::ty::{AdtDef, AdtKind, ClosureDef, ClosureKind, Const, RigidTy};
4041
pub use error::*;
4142
use mir::mono::Instance;
4243
use ty::{FnDef, GenericArgs};
@@ -217,9 +218,24 @@ pub trait Context {
217218
/// Returns the `kind` of given `DefId`
218219
fn item_kind(&self, item: CrateItem) -> ItemKind;
219220

221+
/// Returns whether this is a foreign item.
222+
fn is_foreign_item(&self, item: CrateItem) -> bool;
223+
220224
/// Returns the kind of a given algebraic data type
221225
fn adt_kind(&self, def: AdtDef) -> AdtKind;
222226

227+
/// Returns if the ADT is a box.
228+
fn adt_is_box(&self, def: AdtDef) -> bool;
229+
230+
/// Evaluate constant as a target usize.
231+
fn eval_target_usize(&self, cnst: &Const) -> Result<u64, Error>;
232+
233+
/// Create a target usize constant for the given value.
234+
fn usize_to_const(&self, val: u64) -> Result<Const, Error>;
235+
236+
/// Create a new type from the given kind.
237+
fn new_rigid_ty(&self, kind: RigidTy) -> Ty;
238+
223239
/// Returns the type of given crate item.
224240
fn def_ty(&self, item: DefId) -> Ty;
225241

compiler/stable_mir/src/mir/body.rs

+61-14
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
1-
use crate::ty::{AdtDef, ClosureDef, Const, CoroutineDef, GenericArgs, Movability, Region, Ty};
2-
use crate::Opaque;
1+
use crate::ty::{
2+
AdtDef, ClosureDef, Const, CoroutineDef, GenericArgs, Movability, Region, RigidTy, Ty, TyKind,
3+
};
34
use crate::Span;
5+
use crate::{Error, Opaque};
46

57
/// The SMIR representation of a single function.
68
#[derive(Clone, Debug)]
@@ -537,7 +539,7 @@ pub struct SwitchTarget {
537539
pub target: usize,
538540
}
539541

540-
#[derive(Clone, Debug, Eq, PartialEq)]
542+
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
541543
pub enum BorrowKind {
542544
/// Data must be immutable and is aliasable.
543545
Shared,
@@ -555,14 +557,14 @@ pub enum BorrowKind {
555557
},
556558
}
557559

558-
#[derive(Clone, Debug, Eq, PartialEq)]
560+
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
559561
pub enum MutBorrowKind {
560562
Default,
561563
TwoPhaseBorrow,
562564
ClosureCapture,
563565
}
564566

565-
#[derive(Clone, Debug, PartialEq, Eq)]
567+
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
566568
pub enum Mutability {
567569
Not,
568570
Mut,
@@ -627,10 +629,16 @@ pub enum NullOp {
627629
}
628630

629631
impl Operand {
630-
pub fn ty(&self, locals: &[LocalDecl]) -> Ty {
632+
/// Get the type of an operand relative to the local declaration.
633+
///
634+
/// In order to retrieve the correct type, the `locals` argument must match the list of all
635+
/// locals from the function body where this operand originates from.
636+
///
637+
/// Errors indicate a malformed operand or incompatible locals list.
638+
pub fn ty(&self, locals: &[LocalDecl]) -> Result<Ty, Error> {
631639
match self {
632640
Operand::Copy(place) | Operand::Move(place) => place.ty(locals),
633-
Operand::Constant(c) => c.ty(),
641+
Operand::Constant(c) => Ok(c.ty()),
634642
}
635643
}
636644
}
@@ -642,12 +650,51 @@ impl Constant {
642650
}
643651

644652
impl Place {
645-
// FIXME(klinvill): This function is expected to resolve down the chain of projections to get
646-
// the type referenced at the end of it. E.g. calling `ty()` on `*(_1.f)` should end up
647-
// returning the type referenced by `f`. The information needed to do this may not currently be
648-
// present in Stable MIR since at least an implementation for AdtDef is probably needed.
649-
pub fn ty(&self, locals: &[LocalDecl]) -> Ty {
650-
let _start_ty = locals[self.local].ty;
651-
todo!("Implement projection")
653+
/// Resolve down the chain of projections to get the type referenced at the end of it.
654+
/// E.g.:
655+
/// Calling `ty()` on `var.field` should return the type of `field`.
656+
///
657+
/// In order to retrieve the correct type, the `locals` argument must match the list of all
658+
/// locals from the function body where this place originates from.
659+
pub fn ty(&self, locals: &[LocalDecl]) -> Result<Ty, Error> {
660+
let start_ty = locals[self.local].ty;
661+
self.projection.iter().fold(Ok(start_ty), |place_ty, elem| {
662+
let ty = place_ty?;
663+
match elem {
664+
ProjectionElem::Deref => {
665+
let deref_ty = ty
666+
.kind()
667+
.builtin_deref(true)
668+
.ok_or_else(|| error!("Cannot dereference type: {ty:?}"))?;
669+
Ok(deref_ty.ty)
670+
}
671+
ProjectionElem::Field(_idx, fty) => Ok(*fty),
672+
ProjectionElem::Index(_) | ProjectionElem::ConstantIndex { .. } => ty
673+
.kind()
674+
.builtin_index()
675+
.ok_or_else(|| error!("Cannot index non-array type: {ty:?}")),
676+
ProjectionElem::Subslice { from, to, from_end } => {
677+
let ty_kind = ty.kind();
678+
match ty_kind {
679+
TyKind::RigidTy(RigidTy::Slice(..)) => Ok(ty),
680+
TyKind::RigidTy(RigidTy::Array(inner, _)) if !from_end => {
681+
Ty::try_new_array(
682+
inner,
683+
to.checked_sub(*from)
684+
.ok_or_else(|| error!("Subslice overflow: {from}..{to}"))?,
685+
)
686+
}
687+
TyKind::RigidTy(RigidTy::Array(inner, size)) => {
688+
let size = size.eval_target_usize()?;
689+
let len = size - from - to;
690+
Ty::try_new_array(inner, len)
691+
}
692+
_ => Err(Error(format!("Cannot subslice non-array type: `{ty_kind:?}`"))),
693+
}
694+
}
695+
ProjectionElem::Downcast(_) => Ok(ty),
696+
ProjectionElem::OpaqueCast(ty) | ProjectionElem::Subtype(ty) => Ok(*ty),
697+
}
698+
})
652699
}
653700
}

0 commit comments

Comments
 (0)