]> git.lizzy.rs Git - rust.git/blob - src/librustc/mir/tcx.rs
Improve some compiletest documentation
[rust.git] / src / librustc / mir / tcx.rs
1 /*!
2  * Methods for the various MIR types. These are intended for use after
3  * building is complete.
4  */
5
6 use crate::mir::*;
7 use crate::ty::subst::{Subst, SubstsRef};
8 use crate::ty::{self, AdtDef, Ty, TyCtxt};
9 use crate::ty::layout::VariantIdx;
10 use crate::hir;
11 use crate::ty::util::IntTypeExt;
12
13 #[derive(Copy, Clone, Debug)]
14 pub enum PlaceTy<'tcx> {
15     /// Normal type.
16     Ty { ty: Ty<'tcx> },
17
18     /// Downcast to a particular variant of an enum.
19     Downcast { adt_def: &'tcx AdtDef,
20                substs: SubstsRef<'tcx>,
21                variant_index: VariantIdx },
22 }
23
24 static_assert!(PLACE_TY_IS_3_PTRS_LARGE:
25     mem::size_of::<PlaceTy<'_>>() <= 24
26 );
27
28 impl<'a, 'gcx, 'tcx> PlaceTy<'tcx> {
29     pub fn from_ty(ty: Ty<'tcx>) -> PlaceTy<'tcx> {
30         PlaceTy::Ty { ty }
31     }
32
33     pub fn to_ty(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Ty<'tcx> {
34         match *self {
35             PlaceTy::Ty { ty } =>
36                 ty,
37             PlaceTy::Downcast { adt_def, substs, variant_index: _ } =>
38                 tcx.mk_adt(adt_def, substs),
39         }
40     }
41
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`.)
47     ///
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>
50     {
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)) {
53             (PlaceTy::Ty {
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)
59             }
60             (PlaceTy::Ty { ty }, _) => {
61                 match ty.sty {
62                     ty::Tuple(ref tys) => tys[f.index()],
63                     _ => bug!("extracting field of non-tuple non-adt: {:?}", self),
64                 }
65             }
66         };
67         debug!("field_ty self: {:?} f: {:?} yields: {:?}", self, f, answer);
68         answer
69     }
70
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>)
76                          -> PlaceTy<'tcx>
77     {
78         self.projection_ty_core(tcx, elem, |_, _, ty| ty)
79     }
80
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>(
87         self,
88         tcx: TyCtxt<'a, 'gcx, 'tcx>,
89         elem: &ProjectionElem<'tcx, V, T>,
90         mut handle_field: impl FnMut(&Self, &Field, &T) -> Ty<'tcx>)
91         -> PlaceTy<'tcx>
92     where
93         V: ::std::fmt::Debug, T: ::std::fmt::Debug
94     {
95         let answer = match *elem {
96             ProjectionElem::Deref => {
97                 let ty = self.to_ty(tcx)
98                              .builtin_deref(true)
99                              .unwrap_or_else(|| {
100                                  bug!("deref projection of non-dereferencable ty {:?}", self)
101                              })
102                              .ty;
103                 PlaceTy::Ty {
104                     ty,
105                 }
106             }
107             ProjectionElem::Index(_) | ProjectionElem::ConstantIndex { .. } =>
108                 PlaceTy::Ty {
109                     ty: self.to_ty(tcx).builtin_index().unwrap()
110                 },
111             ProjectionElem::Subslice { from, to } => {
112                 let ty = self.to_ty(tcx);
113                 PlaceTy::Ty {
114                     ty: match ty.sty {
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)
119                         }
120                         ty::Slice(..) => ty,
121                         _ => {
122                             bug!("cannot subslice non-array type: `{:?}`", self)
123                         }
124                     }
125                 }
126             }
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,
134                                             substs,
135                                             variant_index: index }
136                     }
137                     _ => {
138                         bug!("cannot downcast non-ADT type: `{:?}`", self)
139                     }
140                 },
141             ProjectionElem::Field(ref f, ref fty) =>
142                 PlaceTy::Ty { ty: handle_field(&self, f, fty) },
143         };
144         debug!("projection_ty self: {:?} elem: {:?} yields: {:?}", self, elem, answer);
145         answer
146     }
147 }
148
149 EnumTypeFoldableImpl! {
150     impl<'tcx> TypeFoldable<'tcx> for PlaceTy<'tcx> {
151         (PlaceTy::Ty) { ty },
152         (PlaceTy::Downcast) { adt_def, substs, variant_index },
153     }
154 }
155
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>
159     {
160         match *self {
161             Place::Base(PlaceBase::Local(index)) =>
162                 PlaceTy::Ty { ty: local_decls.local_decls()[index].ty },
163             Place::Base(PlaceBase::Promoted(ref data)) => PlaceTy::Ty { ty: data.1 },
164             Place::Base(PlaceBase::Static(ref data)) =>
165                 PlaceTy::Ty { ty: data.ty },
166             Place::Projection(ref proj) =>
167                 proj.base.ty(local_decls, tcx).projection_ty(tcx, &proj.elem),
168         }
169     }
170
171     /// If this is a field projection, and the field is being projected from a closure type,
172     /// then returns the index of the field being projected. Note that this closure will always
173     /// be `self` in the current MIR, because that is the only time we directly access the fields
174     /// of a closure type.
175     pub fn is_upvar_field_projection<'cx, 'gcx>(&self, mir: &'cx Mir<'tcx>,
176                                                 tcx: &TyCtxt<'cx, 'gcx, 'tcx>) -> Option<Field> {
177         let (place, by_ref) = if let Place::Projection(ref proj) = self {
178             if let ProjectionElem::Deref = proj.elem {
179                 (&proj.base, true)
180             } else {
181                 (self, false)
182             }
183         } else {
184             (self, false)
185         };
186
187         match place {
188             Place::Projection(ref proj) => match proj.elem {
189                 ProjectionElem::Field(field, _ty) => {
190                     let base_ty = proj.base.ty(mir, *tcx).to_ty(*tcx);
191
192                     if (base_ty.is_closure() || base_ty.is_generator()) &&
193                         (!by_ref || mir.upvar_decls[field.index()].by_ref)
194                     {
195                         Some(field)
196                     } else {
197                         None
198                     }
199                 },
200                 _ => None,
201             }
202             _ => None,
203         }
204     }
205 }
206
207 pub enum RvalueInitializationState {
208     Shallow,
209     Deep
210 }
211
212 impl<'tcx> Rvalue<'tcx> {
213     pub fn ty<'a, 'gcx, D>(&self, local_decls: &D, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Ty<'tcx>
214         where D: HasLocalDecls<'tcx>
215     {
216         match *self {
217             Rvalue::Use(ref operand) => operand.ty(local_decls, tcx),
218             Rvalue::Repeat(ref operand, count) => {
219                 tcx.mk_array(operand.ty(local_decls, tcx), count)
220             }
221             Rvalue::Ref(reg, bk, ref place) => {
222                 let place_ty = place.ty(local_decls, tcx).to_ty(tcx);
223                 tcx.mk_ref(reg,
224                     ty::TypeAndMut {
225                         ty: place_ty,
226                         mutbl: bk.to_mutbl_lossy()
227                     }
228                 )
229             }
230             Rvalue::Len(..) => tcx.types.usize,
231             Rvalue::Cast(.., ty) => ty,
232             Rvalue::BinaryOp(op, ref lhs, ref rhs) => {
233                 let lhs_ty = lhs.ty(local_decls, tcx);
234                 let rhs_ty = rhs.ty(local_decls, tcx);
235                 op.ty(tcx, lhs_ty, rhs_ty)
236             }
237             Rvalue::CheckedBinaryOp(op, ref lhs, ref rhs) => {
238                 let lhs_ty = lhs.ty(local_decls, tcx);
239                 let rhs_ty = rhs.ty(local_decls, tcx);
240                 let ty = op.ty(tcx, lhs_ty, rhs_ty);
241                 tcx.intern_tup(&[ty, tcx.types.bool])
242             }
243             Rvalue::UnaryOp(UnOp::Not, ref operand) |
244             Rvalue::UnaryOp(UnOp::Neg, ref operand) => {
245                 operand.ty(local_decls, tcx)
246             }
247             Rvalue::Discriminant(ref place) => {
248                 let ty = place.ty(local_decls, tcx).to_ty(tcx);
249                 if let ty::Adt(adt_def, _) = ty.sty {
250                     adt_def.repr.discr_type().to_ty(tcx)
251                 } else {
252                     // This can only be `0`, for now, so `u8` will suffice.
253                     tcx.types.u8
254                 }
255             }
256             Rvalue::NullaryOp(NullOp::Box, t) => tcx.mk_box(t),
257             Rvalue::NullaryOp(NullOp::SizeOf, _) => tcx.types.usize,
258             Rvalue::Aggregate(ref ak, ref ops) => {
259                 match **ak {
260                     AggregateKind::Array(ty) => {
261                         tcx.mk_array(ty, ops.len() as u64)
262                     }
263                     AggregateKind::Tuple => {
264                         tcx.mk_tup(ops.iter().map(|op| op.ty(local_decls, tcx)))
265                     }
266                     AggregateKind::Adt(def, _, substs, _, _) => {
267                         tcx.type_of(def.did).subst(tcx, substs)
268                     }
269                     AggregateKind::Closure(did, substs) => {
270                         tcx.mk_closure(did, substs)
271                     }
272                     AggregateKind::Generator(did, substs, movability) => {
273                         tcx.mk_generator(did, substs, movability)
274                     }
275                 }
276             }
277         }
278     }
279
280     #[inline]
281     /// Returns `true` if this rvalue is deeply initialized (most rvalues) or
282     /// whether its only shallowly initialized (`Rvalue::Box`).
283     pub fn initialization_state(&self) -> RvalueInitializationState {
284         match *self {
285             Rvalue::NullaryOp(NullOp::Box, _) => RvalueInitializationState::Shallow,
286             _ => RvalueInitializationState::Deep
287         }
288     }
289 }
290
291 impl<'tcx> Operand<'tcx> {
292     pub fn ty<'a, 'gcx, D>(&self, local_decls: &D, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Ty<'tcx>
293         where D: HasLocalDecls<'tcx>
294     {
295         match self {
296             &Operand::Copy(ref l) |
297             &Operand::Move(ref l) => l.ty(local_decls, tcx).to_ty(tcx),
298             &Operand::Constant(ref c) => c.ty,
299         }
300     }
301 }
302
303 impl<'tcx> BinOp {
304       pub fn ty<'a, 'gcx>(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>,
305                           lhs_ty: Ty<'tcx>,
306                           rhs_ty: Ty<'tcx>)
307                           -> Ty<'tcx> {
308         // FIXME: handle SIMD correctly
309         match self {
310             &BinOp::Add | &BinOp::Sub | &BinOp::Mul | &BinOp::Div | &BinOp::Rem |
311             &BinOp::BitXor | &BinOp::BitAnd | &BinOp::BitOr => {
312                 // these should be integers or floats of the same size.
313                 assert_eq!(lhs_ty, rhs_ty);
314                 lhs_ty
315             }
316             &BinOp::Shl | &BinOp::Shr | &BinOp::Offset => {
317                 lhs_ty // lhs_ty can be != rhs_ty
318             }
319             &BinOp::Eq | &BinOp::Lt | &BinOp::Le |
320             &BinOp::Ne | &BinOp::Ge | &BinOp::Gt => {
321                 tcx.types.bool
322             }
323         }
324     }
325 }
326
327 impl BorrowKind {
328     pub fn to_mutbl_lossy(self) -> hir::Mutability {
329         match self {
330             BorrowKind::Mut { .. } => hir::MutMutable,
331             BorrowKind::Shared => hir::MutImmutable,
332
333             // We have no type corresponding to a unique imm borrow, so
334             // use `&mut`. It gives all the capabilities of an `&uniq`
335             // and hence is a safe "over approximation".
336             BorrowKind::Unique => hir::MutMutable,
337
338             // We have no type corresponding to a shallow borrow, so use
339             // `&` as an approximation.
340             BorrowKind::Shallow => hir::MutImmutable,
341         }
342     }
343 }
344
345 impl BinOp {
346     pub fn to_hir_binop(self) -> hir::BinOpKind {
347         match self {
348             BinOp::Add => hir::BinOpKind::Add,
349             BinOp::Sub => hir::BinOpKind::Sub,
350             BinOp::Mul => hir::BinOpKind::Mul,
351             BinOp::Div => hir::BinOpKind::Div,
352             BinOp::Rem => hir::BinOpKind::Rem,
353             BinOp::BitXor => hir::BinOpKind::BitXor,
354             BinOp::BitAnd => hir::BinOpKind::BitAnd,
355             BinOp::BitOr => hir::BinOpKind::BitOr,
356             BinOp::Shl => hir::BinOpKind::Shl,
357             BinOp::Shr => hir::BinOpKind::Shr,
358             BinOp::Eq => hir::BinOpKind::Eq,
359             BinOp::Ne => hir::BinOpKind::Ne,
360             BinOp::Lt => hir::BinOpKind::Lt,
361             BinOp::Gt => hir::BinOpKind::Gt,
362             BinOp::Le => hir::BinOpKind::Le,
363             BinOp::Ge => hir::BinOpKind::Ge,
364             BinOp::Offset => unreachable!()
365         }
366     }
367 }