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.
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.
12 * Methods for the various MIR types. These are intended for use after
13 * building is complete.
17 use ty
::subst
::{Subst, Substs}
;
18 use ty
::{self, AdtDef, Ty, TyCtxt}
;
19 use ty
::fold
::{TypeFoldable, TypeFolder, TypeVisitor}
;
21 use ty
::util
::IntTypeExt
;
23 #[derive(Copy, Clone, Debug)]
24 pub enum LvalueTy
<'tcx
> {
28 /// Downcast to a particular variant of an enum.
29 Downcast
{ adt_def
: &'tcx AdtDef
,
30 substs
: &'tcx Substs
<'tcx
>,
31 variant_index
: usize },
34 impl<'a
, 'gcx
, 'tcx
> LvalueTy
<'tcx
> {
35 pub fn from_ty(ty
: Ty
<'tcx
>) -> LvalueTy
<'tcx
> {
36 LvalueTy
::Ty { ty: ty }
39 pub fn to_ty(&self, tcx
: TyCtxt
<'a
, 'gcx
, 'tcx
>) -> Ty
<'tcx
> {
41 LvalueTy
::Ty { ty }
=>
43 LvalueTy
::Downcast { adt_def, substs, variant_index: _ }
=>
44 tcx
.mk_adt(adt_def
, substs
),
48 pub fn projection_ty(self, tcx
: TyCtxt
<'a
, 'gcx
, 'tcx
>,
49 elem
: &LvalueElem
<'tcx
>)
53 ProjectionElem
::Deref
=> {
54 let ty
= self.to_ty(tcx
)
55 .builtin_deref(true, ty
::LvaluePreference
::NoPreference
)
57 bug
!("deref projection of non-dereferencable ty {:?}", self)
64 ProjectionElem
::Index(_
) | ProjectionElem
::ConstantIndex { .. }
=>
66 ty
: self.to_ty(tcx
).builtin_index().unwrap()
68 ProjectionElem
::Subslice { from, to }
=> {
69 let ty
= self.to_ty(tcx
);
72 ty
::TyArray(inner
, size
) => {
73 tcx
.mk_array(inner
, size
-(from
as usize)-(to
as usize))
75 ty
::TySlice(..) => ty
,
77 bug
!("cannot subslice non-array type: `{:?}`", self)
82 ProjectionElem
::Downcast(adt_def1
, index
) =>
83 match self.to_ty(tcx
).sty
{
84 ty
::TyAdt(adt_def
, substs
) => {
85 assert
!(adt_def
.is_enum());
86 assert
!(index
< adt_def
.variants
.len());
87 assert_eq
!(adt_def
, adt_def1
);
88 LvalueTy
::Downcast
{ adt_def
: adt_def
,
90 variant_index
: index
}
93 bug
!("cannot downcast non-ADT type: `{:?}`", self)
96 ProjectionElem
::Field(_
, fty
) => LvalueTy
::Ty { ty: fty }
101 impl<'tcx
> TypeFoldable
<'tcx
> for LvalueTy
<'tcx
> {
102 fn super_fold_with
<'gcx
: 'tcx
, F
: TypeFolder
<'gcx
, 'tcx
>>(&self, folder
: &mut F
) -> Self {
104 LvalueTy
::Ty { ty }
=> LvalueTy
::Ty { ty: ty.fold_with(folder) }
,
105 LvalueTy
::Downcast { adt_def, substs, variant_index }
=> {
108 substs
: substs
.fold_with(folder
),
109 variant_index
: variant_index
115 fn super_visit_with
<V
: TypeVisitor
<'tcx
>>(&self, visitor
: &mut V
) -> bool
{
117 LvalueTy
::Ty { ty }
=> ty
.visit_with(visitor
),
118 LvalueTy
::Downcast { substs, .. }
=> substs
.visit_with(visitor
)
123 impl<'tcx
> Lvalue
<'tcx
> {
124 pub fn ty
<'a
, 'gcx
>(&self, mir
: &Mir
<'tcx
>, tcx
: TyCtxt
<'a
, 'gcx
, 'tcx
>) -> LvalueTy
<'tcx
> {
126 Lvalue
::Local(index
) =>
127 LvalueTy
::Ty { ty: mir.local_decls[index].ty }
,
128 Lvalue
::Static(ref data
) =>
129 LvalueTy
::Ty { ty: data.ty }
,
130 Lvalue
::Projection(ref proj
) =>
131 proj
.base
.ty(mir
, tcx
).projection_ty(tcx
, &proj
.elem
),
136 impl<'tcx
> Rvalue
<'tcx
> {
137 pub fn ty
<'a
, 'gcx
>(&self, mir
: &Mir
<'tcx
>, tcx
: TyCtxt
<'a
, 'gcx
, 'tcx
>) -> Ty
<'tcx
>
140 Rvalue
::Use(ref operand
) => operand
.ty(mir
, tcx
),
141 Rvalue
::Repeat(ref operand
, ref count
) => {
142 let op_ty
= operand
.ty(mir
, tcx
);
143 let count
= count
.as_u64(tcx
.sess
.target
.uint_type
);
144 assert_eq
!(count
as usize as u64, count
);
145 tcx
.mk_array(op_ty
, count
as usize)
147 Rvalue
::Ref(reg
, bk
, ref lv
) => {
148 let lv_ty
= lv
.ty(mir
, tcx
).to_ty(tcx
);
152 mutbl
: bk
.to_mutbl_lossy()
156 Rvalue
::Len(..) => tcx
.types
.usize,
157 Rvalue
::Cast(.., ty
) => ty
,
158 Rvalue
::BinaryOp(op
, ref lhs
, ref rhs
) => {
159 let lhs_ty
= lhs
.ty(mir
, tcx
);
160 let rhs_ty
= rhs
.ty(mir
, tcx
);
161 op
.ty(tcx
, lhs_ty
, rhs_ty
)
163 Rvalue
::CheckedBinaryOp(op
, ref lhs
, ref rhs
) => {
164 let lhs_ty
= lhs
.ty(mir
, tcx
);
165 let rhs_ty
= rhs
.ty(mir
, tcx
);
166 let ty
= op
.ty(tcx
, lhs_ty
, rhs_ty
);
167 tcx
.intern_tup(&[ty
, tcx
.types
.bool
], false)
169 Rvalue
::UnaryOp(UnOp
::Not
, ref operand
) |
170 Rvalue
::UnaryOp(UnOp
::Neg
, ref operand
) => {
173 Rvalue
::Discriminant(ref lval
) => {
174 let ty
= lval
.ty(mir
, tcx
).to_ty(tcx
);
175 if let ty
::TyAdt(adt_def
, _
) = ty
.sty
{
176 adt_def
.repr
.discr_type().to_ty(tcx
)
178 // Undefined behaviour, bug for now; may want to return something for
179 // the `discriminant` intrinsic later.
180 bug
!("Rvalue::Discriminant on Lvalue of type {:?}", ty
);
183 Rvalue
::NullaryOp(NullOp
::Box
, t
) => tcx
.mk_box(t
),
184 Rvalue
::NullaryOp(NullOp
::SizeOf
, _
) => tcx
.types
.usize,
185 Rvalue
::Aggregate(ref ak
, ref ops
) => {
187 AggregateKind
::Array(ty
) => {
188 tcx
.mk_array(ty
, ops
.len())
190 AggregateKind
::Tuple
=> {
192 ops
.iter().map(|op
| op
.ty(mir
, tcx
)),
196 AggregateKind
::Adt(def
, _
, substs
, _
) => {
197 tcx
.type_of(def
.did
).subst(tcx
, substs
)
199 AggregateKind
::Closure(did
, substs
) => {
200 tcx
.mk_closure_from_closure_substs(did
, substs
)
208 impl<'tcx
> Operand
<'tcx
> {
209 pub fn ty
<'a
, 'gcx
>(&self, mir
: &Mir
<'tcx
>, tcx
: TyCtxt
<'a
, 'gcx
, 'tcx
>) -> Ty
<'tcx
> {
211 &Operand
::Consume(ref l
) => l
.ty(mir
, tcx
).to_ty(tcx
),
212 &Operand
::Constant(ref c
) => c
.ty
,
218 pub fn ty
<'a
, 'gcx
>(&self, tcx
: TyCtxt
<'a
, 'gcx
, 'tcx
>,
222 // FIXME: handle SIMD correctly
224 &BinOp
::Add
| &BinOp
::Sub
| &BinOp
::Mul
| &BinOp
::Div
| &BinOp
::Rem
|
225 &BinOp
::BitXor
| &BinOp
::BitAnd
| &BinOp
::BitOr
=> {
226 // these should be integers or floats of the same size.
227 assert_eq
!(lhs_ty
, rhs_ty
);
230 &BinOp
::Shl
| &BinOp
::Shr
| &BinOp
::Offset
=> {
231 lhs_ty
// lhs_ty can be != rhs_ty
233 &BinOp
::Eq
| &BinOp
::Lt
| &BinOp
::Le
|
234 &BinOp
::Ne
| &BinOp
::Ge
| &BinOp
::Gt
=> {
242 pub fn to_mutbl_lossy(self) -> hir
::Mutability
{
244 BorrowKind
::Mut
=> hir
::MutMutable
,
245 BorrowKind
::Shared
=> hir
::MutImmutable
,
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
,
256 pub fn to_hir_binop(self) -> hir
::BinOp_
{
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 BinOp
::Offset
=> unreachable
!()