2 * Methods for the various MIR types. These are intended for use after
3 * building is complete.
7 use crate::ty::subst::{Subst, SubstsRef};
8 use crate::ty::{self, AdtDef, Ty, TyCtxt};
9 use crate::ty::layout::VariantIdx;
11 use crate::ty::util::IntTypeExt;
13 #[derive(Copy, Clone, Debug)]
14 pub enum PlaceTy<'tcx> {
18 /// Downcast to a particular variant of an enum.
19 Downcast { adt_def: &'tcx AdtDef,
20 substs: SubstsRef<'tcx>,
21 variant_index: VariantIdx },
24 static_assert!(PLACE_TY_IS_3_PTRS_LARGE:
25 mem::size_of::<PlaceTy<'_>>() <= 24
28 impl<'a, 'gcx, 'tcx> PlaceTy<'tcx> {
29 pub fn from_ty(ty: Ty<'tcx>) -> PlaceTy<'tcx> {
33 pub fn to_ty(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Ty<'tcx> {
37 PlaceTy::Downcast { adt_def, substs, variant_index: _ } =>
38 tcx.mk_adt(adt_def, substs),
42 /// `place_ty.field_ty(tcx, f)` computes the type at a given field
43 /// of a record or enum-variant. (Most clients of `PlaceTy` can
44 /// instead just extract the relevant type directly from their
45 /// `PlaceElem`, but some instances of `ProjectionElem<V, T>` do
46 /// not carry a `Ty` for `T`.)
48 /// Note that the resulting type has not been normalized.
49 pub fn field_ty(self, tcx: TyCtxt<'a, 'gcx, 'tcx>, f: &Field) -> Ty<'tcx>
51 // Pass `0` here so it can be used as a "default" variant_index in first arm below
52 let answer = match (self, VariantIdx::new(0)) {
54 ty: &ty::TyS { sty: ty::TyKind::Adt(adt_def, substs), .. } }, variant_index) |
55 (PlaceTy::Downcast { adt_def, substs, variant_index }, _) => {
56 let variant_def = &adt_def.variants[variant_index];
57 let field_def = &variant_def.fields[f.index()];
58 field_def.ty(tcx, substs)
60 (PlaceTy::Ty { ty }, _) => {
62 ty::Tuple(ref tys) => tys[f.index()],
63 _ => bug!("extracting field of non-tuple non-adt: {:?}", self),
67 debug!("field_ty self: {:?} f: {:?} yields: {:?}", self, f, answer);
71 /// Convenience wrapper around `projection_ty_core` for
72 /// `PlaceElem`, where we can just use the `Ty` that is already
73 /// stored inline on field projection elems.
74 pub fn projection_ty(self, tcx: TyCtxt<'a, 'gcx, 'tcx>,
75 elem: &PlaceElem<'tcx>)
78 self.projection_ty_core(tcx, elem, |_, _, ty| ty)
81 /// `place_ty.projection_ty_core(tcx, elem, |...| { ... })`
82 /// projects `place_ty` onto `elem`, returning the appropriate
83 /// `Ty` or downcast variant corresponding to that projection.
84 /// The `handle_field` callback must map a `Field` to its `Ty`,
85 /// (which should be trivial when `T` = `Ty`).
86 pub fn projection_ty_core<V, T>(
88 tcx: TyCtxt<'a, 'gcx, 'tcx>,
89 elem: &ProjectionElem<'tcx, V, T>,
90 mut handle_field: impl FnMut(&Self, &Field, &T) -> Ty<'tcx>)
93 V: ::std::fmt::Debug, T: ::std::fmt::Debug
95 let answer = match *elem {
96 ProjectionElem::Deref => {
97 let ty = self.to_ty(tcx)
100 bug!("deref projection of non-dereferencable ty {:?}", self)
107 ProjectionElem::Index(_) | ProjectionElem::ConstantIndex { .. } =>
109 ty: self.to_ty(tcx).builtin_index().unwrap()
111 ProjectionElem::Subslice { from, to } => {
112 let ty = self.to_ty(tcx);
115 ty::Array(inner, size) => {
116 let size = size.unwrap_usize(tcx);
117 let len = size - (from as u64) - (to as u64);
118 tcx.mk_array(inner, len)
122 bug!("cannot subslice non-array type: `{:?}`", self)
127 ProjectionElem::Downcast(adt_def1, index) =>
128 match self.to_ty(tcx).sty {
129 ty::Adt(adt_def, substs) => {
130 assert!(adt_def.is_enum());
131 assert!(index.as_usize() < adt_def.variants.len());
132 assert_eq!(adt_def, adt_def1);
133 PlaceTy::Downcast { adt_def,
135 variant_index: index }
138 bug!("cannot downcast non-ADT type: `{:?}`", self)
141 ProjectionElem::Field(ref f, ref fty) =>
142 PlaceTy::Ty { ty: handle_field(&self, f, fty) },
144 debug!("projection_ty self: {:?} elem: {:?} yields: {:?}", self, elem, answer);
149 EnumTypeFoldableImpl! {
150 impl<'tcx> TypeFoldable<'tcx> for PlaceTy<'tcx> {
151 (PlaceTy::Ty) { ty },
152 (PlaceTy::Downcast) { adt_def, substs, variant_index },
156 impl<'tcx> Place<'tcx> {
157 pub fn ty<'a, 'gcx, D>(&self, local_decls: &D, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> PlaceTy<'tcx>
158 where D: HasLocalDecls<'tcx>
161 Place::Base(PlaceBase::Local(index)) =>
162 PlaceTy::Ty { ty: local_decls.local_decls()[index].ty },
163 Place::Base(PlaceBase::Static(ref data)) =>
164 PlaceTy::Ty { ty: data.ty },
165 Place::Projection(ref proj) =>
166 proj.base.ty(local_decls, tcx).projection_ty(tcx, &proj.elem),
170 /// If this is a field projection, and the field is being projected from a closure type,
171 /// then returns the index of the field being projected. Note that this closure will always
172 /// be `self` in the current MIR, because that is the only time we directly access the fields
173 /// of a closure type.
174 pub fn is_upvar_field_projection<'cx, 'gcx>(&self, mir: &'cx Mir<'tcx>,
175 tcx: &TyCtxt<'cx, 'gcx, 'tcx>) -> Option<Field> {
176 let (place, by_ref) = if let Place::Projection(ref proj) = self {
177 if let ProjectionElem::Deref = proj.elem {
187 Place::Projection(ref proj) => match proj.elem {
188 ProjectionElem::Field(field, _ty) => {
189 let base_ty = proj.base.ty(mir, *tcx).to_ty(*tcx);
191 if (base_ty.is_closure() || base_ty.is_generator()) &&
192 (!by_ref || mir.upvar_decls[field.index()].by_ref)
206 pub enum RvalueInitializationState {
211 impl<'tcx> Rvalue<'tcx> {
212 pub fn ty<'a, 'gcx, D>(&self, local_decls: &D, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Ty<'tcx>
213 where D: HasLocalDecls<'tcx>
216 Rvalue::Use(ref operand) => operand.ty(local_decls, tcx),
217 Rvalue::Repeat(ref operand, count) => {
218 tcx.mk_array(operand.ty(local_decls, tcx), count)
220 Rvalue::Ref(reg, bk, ref place) => {
221 let place_ty = place.ty(local_decls, tcx).to_ty(tcx);
225 mutbl: bk.to_mutbl_lossy()
229 Rvalue::Len(..) => tcx.types.usize,
230 Rvalue::Cast(.., ty) => ty,
231 Rvalue::BinaryOp(op, ref lhs, ref rhs) => {
232 let lhs_ty = lhs.ty(local_decls, tcx);
233 let rhs_ty = rhs.ty(local_decls, tcx);
234 op.ty(tcx, lhs_ty, rhs_ty)
236 Rvalue::CheckedBinaryOp(op, ref lhs, ref rhs) => {
237 let lhs_ty = lhs.ty(local_decls, tcx);
238 let rhs_ty = rhs.ty(local_decls, tcx);
239 let ty = op.ty(tcx, lhs_ty, rhs_ty);
240 tcx.intern_tup(&[ty, tcx.types.bool])
242 Rvalue::UnaryOp(UnOp::Not, ref operand) |
243 Rvalue::UnaryOp(UnOp::Neg, ref operand) => {
244 operand.ty(local_decls, tcx)
246 Rvalue::Discriminant(ref place) => {
247 let ty = place.ty(local_decls, tcx).to_ty(tcx);
248 if let ty::Adt(adt_def, _) = ty.sty {
249 adt_def.repr.discr_type().to_ty(tcx)
251 // This can only be `0`, for now, so `u8` will suffice.
255 Rvalue::NullaryOp(NullOp::Box, t) => tcx.mk_box(t),
256 Rvalue::NullaryOp(NullOp::SizeOf, _) => tcx.types.usize,
257 Rvalue::Aggregate(ref ak, ref ops) => {
259 AggregateKind::Array(ty) => {
260 tcx.mk_array(ty, ops.len() as u64)
262 AggregateKind::Tuple => {
263 tcx.mk_tup(ops.iter().map(|op| op.ty(local_decls, tcx)))
265 AggregateKind::Adt(def, _, substs, _, _) => {
266 tcx.type_of(def.did).subst(tcx, substs)
268 AggregateKind::Closure(did, substs) => {
269 tcx.mk_closure(did, substs)
271 AggregateKind::Generator(did, substs, movability) => {
272 tcx.mk_generator(did, substs, movability)
280 /// Returns `true` if this rvalue is deeply initialized (most rvalues) or
281 /// whether its only shallowly initialized (`Rvalue::Box`).
282 pub fn initialization_state(&self) -> RvalueInitializationState {
284 Rvalue::NullaryOp(NullOp::Box, _) => RvalueInitializationState::Shallow,
285 _ => RvalueInitializationState::Deep
290 impl<'tcx> Operand<'tcx> {
291 pub fn ty<'a, 'gcx, D>(&self, local_decls: &D, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Ty<'tcx>
292 where D: HasLocalDecls<'tcx>
295 &Operand::Copy(ref l) |
296 &Operand::Move(ref l) => l.ty(local_decls, tcx).to_ty(tcx),
297 &Operand::Constant(ref c) => c.ty,
303 pub fn ty<'a, 'gcx>(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>,
307 // FIXME: handle SIMD correctly
309 &BinOp::Add | &BinOp::Sub | &BinOp::Mul | &BinOp::Div | &BinOp::Rem |
310 &BinOp::BitXor | &BinOp::BitAnd | &BinOp::BitOr => {
311 // these should be integers or floats of the same size.
312 assert_eq!(lhs_ty, rhs_ty);
315 &BinOp::Shl | &BinOp::Shr | &BinOp::Offset => {
316 lhs_ty // lhs_ty can be != rhs_ty
318 &BinOp::Eq | &BinOp::Lt | &BinOp::Le |
319 &BinOp::Ne | &BinOp::Ge | &BinOp::Gt => {
327 pub fn to_mutbl_lossy(self) -> hir::Mutability {
329 BorrowKind::Mut { .. } => hir::MutMutable,
330 BorrowKind::Shared => hir::MutImmutable,
332 // We have no type corresponding to a unique imm borrow, so
333 // use `&mut`. It gives all the capabilities of an `&uniq`
334 // and hence is a safe "over approximation".
335 BorrowKind::Unique => hir::MutMutable,
337 // We have no type corresponding to a shallow borrow, so use
338 // `&` as an approximation.
339 BorrowKind::Shallow => hir::MutImmutable,
345 pub fn to_hir_binop(self) -> hir::BinOpKind {
347 BinOp::Add => hir::BinOpKind::Add,
348 BinOp::Sub => hir::BinOpKind::Sub,
349 BinOp::Mul => hir::BinOpKind::Mul,
350 BinOp::Div => hir::BinOpKind::Div,
351 BinOp::Rem => hir::BinOpKind::Rem,
352 BinOp::BitXor => hir::BinOpKind::BitXor,
353 BinOp::BitAnd => hir::BinOpKind::BitAnd,
354 BinOp::BitOr => hir::BinOpKind::BitOr,
355 BinOp::Shl => hir::BinOpKind::Shl,
356 BinOp::Shr => hir::BinOpKind::Shr,
357 BinOp::Eq => hir::BinOpKind::Eq,
358 BinOp::Ne => hir::BinOpKind::Ne,
359 BinOp::Lt => hir::BinOpKind::Lt,
360 BinOp::Gt => hir::BinOpKind::Gt,
361 BinOp::Le => hir::BinOpKind::Le,
362 BinOp::Ge => hir::BinOpKind::Ge,
363 BinOp::Offset => unreachable!()