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