]> git.lizzy.rs Git - rust.git/blob - src/librustc/mir/tcx.rs
Rollup merge of #59432 - phansch:compiletest_docs, r=alexcrichton
[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::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),
167         }
168     }
169
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 {
178                 (&proj.base, true)
179             } else {
180                 (self, false)
181             }
182         } else {
183             (self, false)
184         };
185
186         match place {
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);
190
191                     if (base_ty.is_closure() || base_ty.is_generator()) &&
192                         (!by_ref || mir.upvar_decls[field.index()].by_ref)
193                     {
194                         Some(field)
195                     } else {
196                         None
197                     }
198                 },
199                 _ => None,
200             }
201             _ => None,
202         }
203     }
204 }
205
206 pub enum RvalueInitializationState {
207     Shallow,
208     Deep
209 }
210
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>
214     {
215         match *self {
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)
219             }
220             Rvalue::Ref(reg, bk, ref place) => {
221                 let place_ty = place.ty(local_decls, tcx).to_ty(tcx);
222                 tcx.mk_ref(reg,
223                     ty::TypeAndMut {
224                         ty: place_ty,
225                         mutbl: bk.to_mutbl_lossy()
226                     }
227                 )
228             }
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)
235             }
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])
241             }
242             Rvalue::UnaryOp(UnOp::Not, ref operand) |
243             Rvalue::UnaryOp(UnOp::Neg, ref operand) => {
244                 operand.ty(local_decls, tcx)
245             }
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)
250                 } else {
251                     // This can only be `0`, for now, so `u8` will suffice.
252                     tcx.types.u8
253                 }
254             }
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) => {
258                 match **ak {
259                     AggregateKind::Array(ty) => {
260                         tcx.mk_array(ty, ops.len() as u64)
261                     }
262                     AggregateKind::Tuple => {
263                         tcx.mk_tup(ops.iter().map(|op| op.ty(local_decls, tcx)))
264                     }
265                     AggregateKind::Adt(def, _, substs, _, _) => {
266                         tcx.type_of(def.did).subst(tcx, substs)
267                     }
268                     AggregateKind::Closure(did, substs) => {
269                         tcx.mk_closure(did, substs)
270                     }
271                     AggregateKind::Generator(did, substs, movability) => {
272                         tcx.mk_generator(did, substs, movability)
273                     }
274                 }
275             }
276         }
277     }
278
279     #[inline]
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 {
283         match *self {
284             Rvalue::NullaryOp(NullOp::Box, _) => RvalueInitializationState::Shallow,
285             _ => RvalueInitializationState::Deep
286         }
287     }
288 }
289
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>
293     {
294         match self {
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,
298         }
299     }
300 }
301
302 impl<'tcx> BinOp {
303       pub fn ty<'a, 'gcx>(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>,
304                           lhs_ty: Ty<'tcx>,
305                           rhs_ty: Ty<'tcx>)
306                           -> Ty<'tcx> {
307         // FIXME: handle SIMD correctly
308         match self {
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);
313                 lhs_ty
314             }
315             &BinOp::Shl | &BinOp::Shr | &BinOp::Offset => {
316                 lhs_ty // lhs_ty can be != rhs_ty
317             }
318             &BinOp::Eq | &BinOp::Lt | &BinOp::Le |
319             &BinOp::Ne | &BinOp::Ge | &BinOp::Gt => {
320                 tcx.types.bool
321             }
322         }
323     }
324 }
325
326 impl BorrowKind {
327     pub fn to_mutbl_lossy(self) -> hir::Mutability {
328         match self {
329             BorrowKind::Mut { .. } => hir::MutMutable,
330             BorrowKind::Shared => hir::MutImmutable,
331
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,
336
337             // We have no type corresponding to a shallow borrow, so use
338             // `&` as an approximation.
339             BorrowKind::Shallow => hir::MutImmutable,
340         }
341     }
342 }
343
344 impl BinOp {
345     pub fn to_hir_binop(self) -> hir::BinOpKind {
346         match self {
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!()
364         }
365     }
366 }