]>
Commit | Line | Data |
---|---|---|
92a42be0 SL |
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::*; | |
54a0048b SL |
17 | use ty::subst::{Subst, Substs}; |
18 | use ty::{self, AdtDef, Ty, TyCtxt}; | |
19 | use ty::fold::{TypeFoldable, TypeFolder, TypeVisitor}; | |
20 | use hir; | |
92a42be0 SL |
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 | ||
54a0048b | 38 | pub fn to_ty(&self, tcx: &TyCtxt<'tcx>) -> Ty<'tcx> { |
92a42be0 SL |
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, | |
54a0048b | 48 | tcx: &TyCtxt<'tcx>, |
92a42be0 SL |
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 | _ => { | |
54a0048b | 73 | bug!("cannot downcast non-enum type: `{:?}`", self) |
92a42be0 SL |
74 | } |
75 | }, | |
7453a54e | 76 | ProjectionElem::Field(_, fty) => LvalueTy::Ty { ty: fty } |
92a42be0 SL |
77 | } |
78 | } | |
79 | } | |
80 | ||
54a0048b SL |
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 | ||
92a42be0 SL |
104 | impl<'tcx> Mir<'tcx> { |
105 | pub fn operand_ty(&self, | |
54a0048b | 106 | tcx: &TyCtxt<'tcx>, |
92a42be0 SL |
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, | |
54a0048b | 117 | tcx: &TyCtxt<'tcx>, |
92a42be0 SL |
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, | |
54a0048b | 142 | tcx: &TyCtxt<'tcx>, |
92a42be0 SL |
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 | } | |
7453a54e SL |
161 | |
162 | pub fn rvalue_ty(&self, | |
54a0048b | 163 | tcx: &TyCtxt<'tcx>, |
7453a54e SL |
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) => { | |
54a0048b SL |
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)) | |
7453a54e SL |
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, | |
54a0048b | 223 | Rvalue::InlineAsm { .. } => None |
7453a54e SL |
224 | } |
225 | } | |
92a42be0 SL |
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 | } |