]> git.lizzy.rs Git - rust.git/blob - src/librustc/mir/tcx.rs
MIR: split Operand::Consume into Copy and Move.
[rust.git] / src / librustc / mir / tcx.rs
1 // Copyright 2015 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
4 //
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
10
11 /*!
12  * Methods for the various MIR types. These are intended for use after
13  * building is complete.
14  */
15
16 use mir::*;
17 use ty::subst::{Subst, Substs};
18 use ty::{self, AdtDef, Ty, TyCtxt};
19 use ty::fold::{TypeFoldable, TypeFolder, TypeVisitor};
20 use hir;
21 use ty::util::IntTypeExt;
22
23 #[derive(Copy, Clone, Debug)]
24 pub enum LvalueTy<'tcx> {
25     /// Normal type.
26     Ty { ty: Ty<'tcx> },
27
28     /// Downcast to a particular variant of an enum.
29     Downcast { adt_def: &'tcx AdtDef,
30                substs: &'tcx Substs<'tcx>,
31                variant_index: usize },
32 }
33
34 impl<'a, 'gcx, 'tcx> LvalueTy<'tcx> {
35     pub fn from_ty(ty: Ty<'tcx>) -> LvalueTy<'tcx> {
36         LvalueTy::Ty { ty: ty }
37     }
38
39     pub fn to_ty(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Ty<'tcx> {
40         match *self {
41             LvalueTy::Ty { ty } =>
42                 ty,
43             LvalueTy::Downcast { adt_def, substs, variant_index: _ } =>
44                 tcx.mk_adt(adt_def, substs),
45         }
46     }
47
48     pub fn projection_ty(self, tcx: TyCtxt<'a, 'gcx, 'tcx>,
49                          elem: &LvalueElem<'tcx>)
50                          -> LvalueTy<'tcx>
51     {
52         match *elem {
53             ProjectionElem::Deref => {
54                 let ty = self.to_ty(tcx)
55                              .builtin_deref(true, ty::LvaluePreference::NoPreference)
56                              .unwrap_or_else(|| {
57                                  bug!("deref projection of non-dereferencable ty {:?}", self)
58                              })
59                              .ty;
60                 LvalueTy::Ty {
61                     ty,
62                 }
63             }
64             ProjectionElem::Index(_) | ProjectionElem::ConstantIndex { .. } =>
65                 LvalueTy::Ty {
66                     ty: self.to_ty(tcx).builtin_index().unwrap()
67                 },
68             ProjectionElem::Subslice { from, to } => {
69                 let ty = self.to_ty(tcx);
70                 LvalueTy::Ty {
71                     ty: match ty.sty {
72                         ty::TyArray(inner, size) => {
73                             let size = size.val.to_const_int().unwrap().to_u64().unwrap();
74                             let len = size - (from as u64) - (to as u64);
75                             tcx.mk_array(inner, len)
76                         }
77                         ty::TySlice(..) => ty,
78                         _ => {
79                             bug!("cannot subslice non-array type: `{:?}`", self)
80                         }
81                     }
82                 }
83             }
84             ProjectionElem::Downcast(adt_def1, index) =>
85                 match self.to_ty(tcx).sty {
86                     ty::TyAdt(adt_def, substs) => {
87                         assert!(adt_def.is_enum());
88                         assert!(index < adt_def.variants.len());
89                         assert_eq!(adt_def, adt_def1);
90                         LvalueTy::Downcast { adt_def,
91                                              substs,
92                                              variant_index: index }
93                     }
94                     _ => {
95                         bug!("cannot downcast non-ADT type: `{:?}`", self)
96                     }
97                 },
98             ProjectionElem::Field(_, fty) => LvalueTy::Ty { ty: fty }
99         }
100     }
101 }
102
103 impl<'tcx> TypeFoldable<'tcx> for LvalueTy<'tcx> {
104     fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
105         match *self {
106             LvalueTy::Ty { ty } => LvalueTy::Ty { ty: ty.fold_with(folder) },
107             LvalueTy::Downcast { adt_def, substs, variant_index } => {
108                 LvalueTy::Downcast {
109                     adt_def,
110                     substs: substs.fold_with(folder),
111                     variant_index,
112                 }
113             }
114         }
115     }
116
117     fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
118         match *self {
119             LvalueTy::Ty { ty } => ty.visit_with(visitor),
120             LvalueTy::Downcast { substs, .. } => substs.visit_with(visitor)
121         }
122     }
123 }
124
125 impl<'tcx> Lvalue<'tcx> {
126     pub fn ty<'a, 'gcx, D>(&self, local_decls: &D, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> LvalueTy<'tcx>
127         where D: HasLocalDecls<'tcx>
128     {
129         match *self {
130             Lvalue::Local(index) =>
131                 LvalueTy::Ty { ty: local_decls.local_decls()[index].ty },
132             Lvalue::Static(ref data) =>
133                 LvalueTy::Ty { ty: data.ty },
134             Lvalue::Projection(ref proj) =>
135                 proj.base.ty(local_decls, tcx).projection_ty(tcx, &proj.elem),
136         }
137     }
138 }
139
140 pub enum RvalueInitializationState {
141     Shallow,
142     Deep
143 }
144
145 impl<'tcx> Rvalue<'tcx> {
146     pub fn ty<'a, 'gcx, D>(&self, local_decls: &D, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Ty<'tcx>
147         where D: HasLocalDecls<'tcx>
148     {
149         match *self {
150             Rvalue::Use(ref operand) => operand.ty(local_decls, tcx),
151             Rvalue::Repeat(ref operand, count) => {
152                 tcx.mk_array_const_usize(operand.ty(local_decls, tcx), count)
153             }
154             Rvalue::Ref(reg, bk, ref lv) => {
155                 let lv_ty = lv.ty(local_decls, tcx).to_ty(tcx);
156                 tcx.mk_ref(reg,
157                     ty::TypeAndMut {
158                         ty: lv_ty,
159                         mutbl: bk.to_mutbl_lossy()
160                     }
161                 )
162             }
163             Rvalue::Len(..) => tcx.types.usize,
164             Rvalue::Cast(.., ty) => ty,
165             Rvalue::BinaryOp(op, ref lhs, ref rhs) => {
166                 let lhs_ty = lhs.ty(local_decls, tcx);
167                 let rhs_ty = rhs.ty(local_decls, tcx);
168                 op.ty(tcx, lhs_ty, rhs_ty)
169             }
170             Rvalue::CheckedBinaryOp(op, ref lhs, ref rhs) => {
171                 let lhs_ty = lhs.ty(local_decls, tcx);
172                 let rhs_ty = rhs.ty(local_decls, tcx);
173                 let ty = op.ty(tcx, lhs_ty, rhs_ty);
174                 tcx.intern_tup(&[ty, tcx.types.bool], false)
175             }
176             Rvalue::UnaryOp(UnOp::Not, ref operand) |
177             Rvalue::UnaryOp(UnOp::Neg, ref operand) => {
178                 operand.ty(local_decls, tcx)
179             }
180             Rvalue::Discriminant(ref lval) => {
181                 let ty = lval.ty(local_decls, tcx).to_ty(tcx);
182                 if let ty::TyAdt(adt_def, _) = ty.sty {
183                     adt_def.repr.discr_type().to_ty(tcx)
184                 } else {
185                     // Undefined behaviour, bug for now; may want to return something for
186                     // the `discriminant` intrinsic later.
187                     bug!("Rvalue::Discriminant on Lvalue of type {:?}", ty);
188                 }
189             }
190             Rvalue::NullaryOp(NullOp::Box, t) => tcx.mk_box(t),
191             Rvalue::NullaryOp(NullOp::SizeOf, _) => tcx.types.usize,
192             Rvalue::Aggregate(ref ak, ref ops) => {
193                 match **ak {
194                     AggregateKind::Array(ty) => {
195                         tcx.mk_array(ty, ops.len() as u64)
196                     }
197                     AggregateKind::Tuple => {
198                         tcx.mk_tup(
199                             ops.iter().map(|op| op.ty(local_decls, tcx)),
200                             false
201                         )
202                     }
203                     AggregateKind::Adt(def, _, substs, _) => {
204                         tcx.type_of(def.did).subst(tcx, substs)
205                     }
206                     AggregateKind::Closure(did, substs) => {
207                         tcx.mk_closure_from_closure_substs(did, substs)
208                     }
209                     AggregateKind::Generator(did, substs, interior) => {
210                         tcx.mk_generator(did, substs, interior)
211                     }
212                 }
213             }
214         }
215     }
216
217     #[inline]
218     /// Returns whether this rvalue is deeply initialized (most rvalues) or
219     /// whether its only shallowly initialized (`Rvalue::Box`).
220     pub fn initialization_state(&self) -> RvalueInitializationState {
221         match *self {
222             Rvalue::NullaryOp(NullOp::Box, _) => RvalueInitializationState::Shallow,
223             _ => RvalueInitializationState::Deep
224         }
225     }
226 }
227
228 impl<'tcx> Operand<'tcx> {
229     pub fn ty<'a, 'gcx, D>(&self, local_decls: &D, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Ty<'tcx>
230         where D: HasLocalDecls<'tcx>
231     {
232         match self {
233             &Operand::Copy(ref l) |
234             &Operand::Move(ref l) => l.ty(local_decls, tcx).to_ty(tcx),
235             &Operand::Constant(ref c) => c.ty,
236         }
237     }
238 }
239
240 impl<'tcx> BinOp {
241       pub fn ty<'a, 'gcx>(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>,
242                     lhs_ty: Ty<'tcx>,
243                     rhs_ty: Ty<'tcx>)
244                     -> Ty<'tcx> {
245         // FIXME: handle SIMD correctly
246         match self {
247             &BinOp::Add | &BinOp::Sub | &BinOp::Mul | &BinOp::Div | &BinOp::Rem |
248             &BinOp::BitXor | &BinOp::BitAnd | &BinOp::BitOr => {
249                 // these should be integers or floats of the same size.
250                 assert_eq!(lhs_ty, rhs_ty);
251                 lhs_ty
252             }
253             &BinOp::Shl | &BinOp::Shr | &BinOp::Offset => {
254                 lhs_ty // lhs_ty can be != rhs_ty
255             }
256             &BinOp::Eq | &BinOp::Lt | &BinOp::Le |
257             &BinOp::Ne | &BinOp::Ge | &BinOp::Gt => {
258                 tcx.types.bool
259             }
260         }
261     }
262 }
263
264 impl BorrowKind {
265     pub fn to_mutbl_lossy(self) -> hir::Mutability {
266         match self {
267             BorrowKind::Mut => hir::MutMutable,
268             BorrowKind::Shared => hir::MutImmutable,
269
270             // We have no type corresponding to a unique imm borrow, so
271             // use `&mut`. It gives all the capabilities of an `&uniq`
272             // and hence is a safe "over approximation".
273             BorrowKind::Unique => hir::MutMutable,
274         }
275     }
276 }
277
278 impl BinOp {
279     pub fn to_hir_binop(self) -> hir::BinOp_ {
280         match self {
281             BinOp::Add => hir::BinOp_::BiAdd,
282             BinOp::Sub => hir::BinOp_::BiSub,
283             BinOp::Mul => hir::BinOp_::BiMul,
284             BinOp::Div => hir::BinOp_::BiDiv,
285             BinOp::Rem => hir::BinOp_::BiRem,
286             BinOp::BitXor => hir::BinOp_::BiBitXor,
287             BinOp::BitAnd => hir::BinOp_::BiBitAnd,
288             BinOp::BitOr => hir::BinOp_::BiBitOr,
289             BinOp::Shl => hir::BinOp_::BiShl,
290             BinOp::Shr => hir::BinOp_::BiShr,
291             BinOp::Eq => hir::BinOp_::BiEq,
292             BinOp::Ne => hir::BinOp_::BiNe,
293             BinOp::Lt => hir::BinOp_::BiLt,
294             BinOp::Gt => hir::BinOp_::BiGt,
295             BinOp::Le => hir::BinOp_::BiLe,
296             BinOp::Ge => hir::BinOp_::BiGe,
297             BinOp::Offset => unreachable!()
298         }
299     }
300 }