Skip to content

Commit 390e3c8

Browse files
committed
Auto merge of rust-lang#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`
2 parents baf4abf + d94df62 commit 390e3c8

File tree

11 files changed

+323
-41
lines changed

11 files changed

+323
-41
lines changed

compiler/rustc_smir/src/rustc_internal/internal.rs

+85-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,13 @@ 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+
tables.tcx.adt_def(self.0.internal(&mut *tables))
266+
}
267+
}
268+
186269
impl<'tcx, T> RustcInternal<'tcx> for &T
187270
where
188271
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 {
@@ -302,6 +303,37 @@ impl<'tcx> Context for TablesWrapper<'tcx> {
302303
let closure_kind = kind.internal(&mut *tables);
303304
Instance::resolve_closure(tables.tcx, def_id, args_ref, closure_kind).stable(&mut *tables)
304305
}
306+
307+
fn adt_is_box(&self, def: AdtDef) -> bool {
308+
let mut tables = self.0.borrow_mut();
309+
def.internal(&mut *tables).is_box()
310+
}
311+
312+
fn eval_target_usize(&self, cnst: &Const) -> Result<u64, Error> {
313+
let mut tables = self.0.borrow_mut();
314+
let mir_const = cnst.internal(&mut *tables);
315+
mir_const
316+
.try_eval_target_usize(tables.tcx, ParamEnv::empty())
317+
.ok_or_else(|| Error::new(format!("Const `{cnst:?}` cannot be encoded as u64")))
318+
}
319+
320+
fn usize_to_const(&self, val: u64) -> Result<Const, Error> {
321+
let mut tables = self.0.borrow_mut();
322+
let ty = tables.tcx.types.usize;
323+
let size = tables.tcx.layout_of(ParamEnv::empty().and(ty)).unwrap().size;
324+
325+
let scalar = ScalarInt::try_from_uint(val, size).ok_or_else(|| {
326+
Error::new(format!("Value overflow: cannot convert `{val}` to usize."))
327+
})?;
328+
Ok(ty::Const::new_value(tables.tcx, ty::ValTree::from_scalar_int(scalar), ty)
329+
.stable(&mut *tables))
330+
}
331+
332+
fn new_rigid_ty(&self, kind: RigidTy) -> stable_mir::ty::Ty {
333+
let mut tables = self.0.borrow_mut();
334+
let internal_kind = kind.internal(&mut *tables);
335+
tables.tcx.mk_ty_from_kind(internal_kind).stable(&mut *tables)
336+
}
305337
}
306338

307339
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

+18-2
Original file line numberDiff line numberDiff line change
@@ -31,17 +31,18 @@ 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

3940
use crate::mir::pretty::function_name;
4041
use crate::mir::Mutability;
41-
use crate::ty::{AdtDef, AdtKind, ClosureDef, ClosureKind};
42+
use crate::ty::{AdtDef, AdtKind, ClosureDef, ClosureKind, Const, RigidTy};
4243
pub use error::*;
4344
use mir::mono::Instance;
44-
use ty::{Const, FnDef, GenericArgs};
45+
use ty::{FnDef, GenericArgs};
4546

4647
/// Use String for now but we should replace it.
4748
pub type Symbol = String;
@@ -224,9 +225,24 @@ pub trait Context {
224225
/// Returns the `kind` of given `DefId`
225226
fn item_kind(&self, item: CrateItem) -> ItemKind;
226227

228+
/// Returns whether this is a foreign item.
229+
fn is_foreign_item(&self, item: CrateItem) -> bool;
230+
227231
/// Returns the kind of a given algebraic data type
228232
fn adt_kind(&self, def: AdtDef) -> AdtKind;
229233

234+
/// Returns if the ADT is a box.
235+
fn adt_is_box(&self, def: AdtDef) -> bool;
236+
237+
/// Evaluate constant as a target usize.
238+
fn eval_target_usize(&self, cnst: &Const) -> Result<u64, Error>;
239+
240+
/// Create a target usize constant for the given value.
241+
fn usize_to_const(&self, val: u64) -> Result<Const, Error>;
242+
243+
/// Create a new type from the given kind.
244+
fn new_rigid_ty(&self, kind: RigidTy) -> Ty;
245+
230246
/// Returns the type of given crate item.
231247
fn def_ty(&self, item: DefId) -> Ty;
232248

compiler/stable_mir/src/mir/body.rs

+68-15
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
use crate::mir::pretty::{function_body, pretty_statement};
2-
use crate::ty::{AdtDef, ClosureDef, Const, CoroutineDef, GenericArgs, Movability, Region, Ty};
3-
use crate::Opaque;
4-
use crate::Span;
2+
use crate::ty::{
3+
AdtDef, ClosureDef, Const, CoroutineDef, GenericArgs, Movability, Region, RigidTy, Ty, TyKind,
4+
};
5+
use crate::{Error, Opaque, Span};
56
use std::io;
7+
68
/// The SMIR representation of a single function.
79
#[derive(Clone, Debug)]
810
pub struct Body {
@@ -561,7 +563,7 @@ pub struct SwitchTarget {
561563
pub target: usize,
562564
}
563565

564-
#[derive(Clone, Debug, Eq, PartialEq)]
566+
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
565567
pub enum BorrowKind {
566568
/// Data must be immutable and is aliasable.
567569
Shared,
@@ -579,14 +581,14 @@ pub enum BorrowKind {
579581
},
580582
}
581583

582-
#[derive(Clone, Debug, Eq, PartialEq)]
584+
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
583585
pub enum MutBorrowKind {
584586
Default,
585587
TwoPhaseBorrow,
586588
ClosureCapture,
587589
}
588590

589-
#[derive(Clone, Debug, PartialEq, Eq)]
591+
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
590592
pub enum Mutability {
591593
Not,
592594
Mut,
@@ -651,10 +653,16 @@ pub enum NullOp {
651653
}
652654

653655
impl Operand {
654-
pub fn ty(&self, locals: &[LocalDecl]) -> Ty {
656+
/// Get the type of an operand relative to the local declaration.
657+
///
658+
/// In order to retrieve the correct type, the `locals` argument must match the list of all
659+
/// locals from the function body where this operand originates from.
660+
///
661+
/// Errors indicate a malformed operand or incompatible locals list.
662+
pub fn ty(&self, locals: &[LocalDecl]) -> Result<Ty, Error> {
655663
match self {
656664
Operand::Copy(place) | Operand::Move(place) => place.ty(locals),
657-
Operand::Constant(c) => c.ty(),
665+
Operand::Constant(c) => Ok(c.ty()),
658666
}
659667
}
660668
}
@@ -666,12 +674,57 @@ impl Constant {
666674
}
667675

668676
impl Place {
669-
// FIXME(klinvill): This function is expected to resolve down the chain of projections to get
670-
// the type referenced at the end of it. E.g. calling `ty()` on `*(_1.f)` should end up
671-
// returning the type referenced by `f`. The information needed to do this may not currently be
672-
// present in Stable MIR since at least an implementation for AdtDef is probably needed.
673-
pub fn ty(&self, locals: &[LocalDecl]) -> Ty {
674-
let _start_ty = locals[self.local].ty;
675-
todo!("Implement projection")
677+
/// Resolve down the chain of projections to get the type referenced at the end of it.
678+
/// E.g.:
679+
/// Calling `ty()` on `var.field` should return the type of `field`.
680+
///
681+
/// In order to retrieve the correct type, the `locals` argument must match the list of all
682+
/// locals from the function body where this place originates from.
683+
pub fn ty(&self, locals: &[LocalDecl]) -> Result<Ty, Error> {
684+
let start_ty = locals[self.local].ty;
685+
self.projection.iter().fold(Ok(start_ty), |place_ty, elem| {
686+
let ty = place_ty?;
687+
match elem {
688+
ProjectionElem::Deref => Self::deref_ty(ty),
689+
ProjectionElem::Field(_idx, fty) => Ok(*fty),
690+
ProjectionElem::Index(_) | ProjectionElem::ConstantIndex { .. } => {
691+
Self::index_ty(ty)
692+
}
693+
ProjectionElem::Subslice { from, to, from_end } => {
694+
Self::subslice_ty(ty, from, to, from_end)
695+
}
696+
ProjectionElem::Downcast(_) => Ok(ty),
697+
ProjectionElem::OpaqueCast(ty) | ProjectionElem::Subtype(ty) => Ok(*ty),
698+
}
699+
})
700+
}
701+
702+
fn index_ty(ty: Ty) -> Result<Ty, Error> {
703+
ty.kind().builtin_index().ok_or_else(|| error!("Cannot index non-array type: {ty:?}"))
704+
}
705+
706+
fn subslice_ty(ty: Ty, from: &u64, to: &u64, from_end: &bool) -> Result<Ty, Error> {
707+
let ty_kind = ty.kind();
708+
match ty_kind {
709+
TyKind::RigidTy(RigidTy::Slice(..)) => Ok(ty),
710+
TyKind::RigidTy(RigidTy::Array(inner, _)) if !from_end => Ty::try_new_array(
711+
inner,
712+
to.checked_sub(*from).ok_or_else(|| error!("Subslice overflow: {from}..{to}"))?,
713+
),
714+
TyKind::RigidTy(RigidTy::Array(inner, size)) => {
715+
let size = size.eval_target_usize()?;
716+
let len = size - from - to;
717+
Ty::try_new_array(inner, len)
718+
}
719+
_ => Err(Error(format!("Cannot subslice non-array type: `{ty_kind:?}`"))),
720+
}
721+
}
722+
723+
fn deref_ty(ty: Ty) -> Result<Ty, Error> {
724+
let deref_ty = ty
725+
.kind()
726+
.builtin_deref(true)
727+
.ok_or_else(|| error!("Cannot dereference type: {ty:?}"))?;
728+
Ok(deref_ty.ty)
676729
}
677730
}

0 commit comments

Comments
 (0)