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