]> git.lizzy.rs Git - rust.git/blob - src/librustc/mir/tcx.rs
Rollup merge of #34175 - rwz:patch-2, r=alexcrichton
[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::repr::*;
17 use ty::subst::{Subst, Substs};
18 use ty::{self, AdtDef, Ty, TyCtxt};
19 use ty::fold::{TypeFoldable, TypeFolder, TypeVisitor};
20 use hir;
21
22 #[derive(Copy, Clone, Debug)]
23 pub enum LvalueTy<'tcx> {
24     /// Normal type.
25     Ty { ty: Ty<'tcx> },
26
27     /// Downcast to a particular variant of an enum.
28     Downcast { adt_def: AdtDef<'tcx>,
29                substs: &'tcx Substs<'tcx>,
30                variant_index: usize },
31 }
32
33 impl<'a, 'gcx, 'tcx> LvalueTy<'tcx> {
34     pub fn from_ty(ty: Ty<'tcx>) -> LvalueTy<'tcx> {
35         LvalueTy::Ty { ty: ty }
36     }
37
38     pub fn to_ty(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Ty<'tcx> {
39         match *self {
40             LvalueTy::Ty { ty } =>
41                 ty,
42             LvalueTy::Downcast { adt_def, substs, variant_index: _ } =>
43                 tcx.mk_enum(adt_def, substs),
44         }
45     }
46
47     pub fn projection_ty(self, tcx: TyCtxt<'a, 'gcx, 'tcx>,
48                          elem: &LvalueElem<'tcx>)
49                          -> LvalueTy<'tcx>
50     {
51         match *elem {
52             ProjectionElem::Deref =>
53                 LvalueTy::Ty {
54                     ty: self.to_ty(tcx).builtin_deref(true, ty::LvaluePreference::NoPreference)
55                                           .unwrap()
56                                           .ty
57                 },
58             ProjectionElem::Index(_) | ProjectionElem::ConstantIndex { .. } =>
59                 LvalueTy::Ty {
60                     ty: self.to_ty(tcx).builtin_index().unwrap()
61                 },
62             ProjectionElem::Subslice { from, to } => {
63                 let ty = self.to_ty(tcx);
64                 LvalueTy::Ty {
65                     ty: match ty.sty {
66                         ty::TyArray(inner, size) => {
67                             tcx.mk_array(inner, size-(from as usize)-(to as usize))
68                         }
69                         ty::TySlice(..) => ty,
70                         _ => {
71                             bug!("cannot subslice non-array type: `{:?}`", self)
72                         }
73                     }
74                 }
75             }
76             ProjectionElem::Downcast(adt_def1, index) =>
77                 match self.to_ty(tcx).sty {
78                     ty::TyEnum(adt_def, substs) => {
79                         assert!(index < adt_def.variants.len());
80                         assert_eq!(adt_def, adt_def1);
81                         LvalueTy::Downcast { adt_def: adt_def,
82                                              substs: substs,
83                                              variant_index: index }
84                     }
85                     _ => {
86                         bug!("cannot downcast non-enum type: `{:?}`", self)
87                     }
88                 },
89             ProjectionElem::Field(_, fty) => LvalueTy::Ty { ty: fty }
90         }
91     }
92 }
93
94 impl<'tcx> TypeFoldable<'tcx> for LvalueTy<'tcx> {
95     fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
96         match *self {
97             LvalueTy::Ty { ty } => LvalueTy::Ty { ty: ty.fold_with(folder) },
98             LvalueTy::Downcast { adt_def, substs, variant_index } => {
99                 LvalueTy::Downcast {
100                     adt_def: adt_def,
101                     substs: substs.fold_with(folder),
102                     variant_index: variant_index
103                 }
104             }
105         }
106     }
107
108     fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
109         match *self {
110             LvalueTy::Ty { ty } => ty.visit_with(visitor),
111             LvalueTy::Downcast { substs, .. } => substs.visit_with(visitor)
112         }
113     }
114 }
115
116 impl<'a, 'gcx, 'tcx> Mir<'tcx> {
117     pub fn operand_ty(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>,
118                       operand: &Operand<'tcx>)
119                       -> Ty<'tcx>
120     {
121         match *operand {
122             Operand::Consume(ref l) => self.lvalue_ty(tcx, l).to_ty(tcx),
123             Operand::Constant(ref c) => c.ty,
124         }
125     }
126
127     pub fn binop_ty(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>,
128                     op: BinOp,
129                     lhs_ty: Ty<'tcx>,
130                     rhs_ty: Ty<'tcx>)
131                     -> Ty<'tcx>
132     {
133         // FIXME: handle SIMD correctly
134         match op {
135             BinOp::Add | BinOp::Sub | BinOp::Mul | BinOp::Div | BinOp::Rem |
136             BinOp::BitXor | BinOp::BitAnd | BinOp::BitOr => {
137                 // these should be integers or floats of the same size.
138                 assert_eq!(lhs_ty, rhs_ty);
139                 lhs_ty
140             }
141             BinOp::Shl | BinOp::Shr => {
142                 lhs_ty // lhs_ty can be != rhs_ty
143             }
144             BinOp::Eq | BinOp::Lt | BinOp::Le |
145             BinOp::Ne | BinOp::Ge | BinOp::Gt => {
146                 tcx.types.bool
147             }
148         }
149     }
150
151     pub fn lvalue_ty(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>,
152                      lvalue: &Lvalue<'tcx>)
153                      -> LvalueTy<'tcx>
154     {
155         match *lvalue {
156             Lvalue::Var(index) =>
157                 LvalueTy::Ty { ty: self.var_decls[index].ty },
158             Lvalue::Temp(index) =>
159                 LvalueTy::Ty { ty: self.temp_decls[index].ty },
160             Lvalue::Arg(index) =>
161                 LvalueTy::Ty { ty: self.arg_decls[index].ty },
162             Lvalue::Static(def_id) =>
163                 LvalueTy::Ty { ty: tcx.lookup_item_type(def_id).ty },
164             Lvalue::ReturnPointer =>
165                 LvalueTy::Ty { ty: self.return_ty.unwrap() },
166             Lvalue::Projection(ref proj) =>
167                 self.lvalue_ty(tcx, &proj.base).projection_ty(tcx, &proj.elem)
168         }
169     }
170
171     pub fn rvalue_ty(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>,
172                      rvalue: &Rvalue<'tcx>)
173                      -> Option<Ty<'tcx>>
174     {
175         match *rvalue {
176             Rvalue::Use(ref operand) => Some(self.operand_ty(tcx, operand)),
177             Rvalue::Repeat(ref operand, ref count) => {
178                 let op_ty = self.operand_ty(tcx, operand);
179                 let count = count.value.as_u64(tcx.sess.target.uint_type);
180                 assert_eq!(count as usize as u64, count);
181                 Some(tcx.mk_array(op_ty, count as usize))
182             }
183             Rvalue::Ref(reg, bk, ref lv) => {
184                 let lv_ty = self.lvalue_ty(tcx, lv).to_ty(tcx);
185                 Some(tcx.mk_ref(
186                     tcx.mk_region(reg),
187                     ty::TypeAndMut {
188                         ty: lv_ty,
189                         mutbl: bk.to_mutbl_lossy()
190                     }
191                 ))
192             }
193             Rvalue::Len(..) => Some(tcx.types.usize),
194             Rvalue::Cast(_, _, ty) => Some(ty),
195             Rvalue::BinaryOp(op, ref lhs, ref rhs) => {
196                 let lhs_ty = self.operand_ty(tcx, lhs);
197                 let rhs_ty = self.operand_ty(tcx, rhs);
198                 Some(self.binop_ty(tcx, op, lhs_ty, rhs_ty))
199             }
200             Rvalue::CheckedBinaryOp(op, ref lhs, ref rhs) => {
201                 let lhs_ty = self.operand_ty(tcx, lhs);
202                 let rhs_ty = self.operand_ty(tcx, rhs);
203                 let ty = self.binop_ty(tcx, op, lhs_ty, rhs_ty);
204                 let ty = tcx.mk_tup(vec![ty, tcx.types.bool]);
205                 Some(ty)
206             }
207             Rvalue::UnaryOp(_, ref operand) => {
208                 Some(self.operand_ty(tcx, operand))
209             }
210             Rvalue::Box(t) => {
211                 Some(tcx.mk_box(t))
212             }
213             Rvalue::Aggregate(ref ak, ref ops) => {
214                 match *ak {
215                     AggregateKind::Vec => {
216                         if let Some(operand) = ops.get(0) {
217                             let ty = self.operand_ty(tcx, operand);
218                             Some(tcx.mk_array(ty, ops.len()))
219                         } else {
220                             None
221                         }
222                     }
223                     AggregateKind::Tuple => {
224                         Some(tcx.mk_tup(
225                             ops.iter().map(|op| self.operand_ty(tcx, op)).collect()
226                         ))
227                     }
228                     AggregateKind::Adt(def, _, substs) => {
229                         Some(tcx.lookup_item_type(def.did).ty.subst(tcx, substs))
230                     }
231                     AggregateKind::Closure(did, substs) => {
232                         Some(tcx.mk_closure_from_closure_substs(did, substs))
233                     }
234                 }
235             }
236             Rvalue::InlineAsm { .. } => None
237         }
238     }
239 }
240
241 impl BorrowKind {
242     pub fn to_mutbl_lossy(self) -> hir::Mutability {
243         match self {
244             BorrowKind::Mut => hir::MutMutable,
245             BorrowKind::Shared => hir::MutImmutable,
246
247             // We have no type corresponding to a unique imm borrow, so
248             // use `&mut`. It gives all the capabilities of an `&uniq`
249             // and hence is a safe "over approximation".
250             BorrowKind::Unique => hir::MutMutable,
251         }
252     }
253 }
254
255 impl BinOp {
256     pub fn to_hir_binop(self) -> hir::BinOp_ {
257         match self {
258             BinOp::Add => hir::BinOp_::BiAdd,
259             BinOp::Sub => hir::BinOp_::BiSub,
260             BinOp::Mul => hir::BinOp_::BiMul,
261             BinOp::Div => hir::BinOp_::BiDiv,
262             BinOp::Rem => hir::BinOp_::BiRem,
263             BinOp::BitXor => hir::BinOp_::BiBitXor,
264             BinOp::BitAnd => hir::BinOp_::BiBitAnd,
265             BinOp::BitOr => hir::BinOp_::BiBitOr,
266             BinOp::Shl => hir::BinOp_::BiShl,
267             BinOp::Shr => hir::BinOp_::BiShr,
268             BinOp::Eq => hir::BinOp_::BiEq,
269             BinOp::Ne => hir::BinOp_::BiNe,
270             BinOp::Lt => hir::BinOp_::BiLt,
271             BinOp::Gt => hir::BinOp_::BiGt,
272             BinOp::Le => hir::BinOp_::BiLe,
273             BinOp::Ge => hir::BinOp_::BiGe
274         }
275     }
276 }