eval_context.rs 61.2 KB
Newer Older
1 2 3
use std::cell::Ref;
use std::collections::HashMap;

4
use rustc::hir::def_id::DefId;
5
use rustc::hir::map::definitions::DefPathData;
6
use rustc::middle::const_val::ConstVal;
7
use rustc::mir;
S
Scott Olson 已提交
8
use rustc::traits::Reveal;
9
use rustc::ty::layout::{self, Layout, Size};
10
use rustc::ty::subst::{self, Subst, Substs};
11
use rustc::ty::{self, Ty, TyCtxt, TypeFoldable};
12
use rustc_data_structures::indexed_vec::Idx;
13
use rustc_data_structures::fx::FxHashSet;
14
use syntax::codemap::{self, DUMMY_SP};
15

16
use error::{EvalError, EvalResult};
17
use lvalue::{Global, GlobalId, Lvalue, LvalueExtra};
18
use memory::{Memory, Pointer};
19
use operator;
S
Scott Olson 已提交
20
use value::{PrimVal, PrimValKind, Value};
O
Oliver Schneider 已提交
21

S
Scott Olson 已提交
22
pub type MirRef<'tcx> = Ref<'tcx, mir::Mir<'tcx>>;
23

24
pub struct EvalContext<'a, 'tcx: 'a> {
25
    /// The results of the type checker, from rustc.
26
    pub(super) tcx: TyCtxt<'a, 'tcx, 'tcx>,
27 28

    /// The virtual memory system.
29
    pub(super) memory: Memory<'a, 'tcx>,
30

31
    /// Precomputed statics, constants and promoteds.
32
    pub(super) globals: HashMap<GlobalId<'tcx>, Global<'tcx>>,
33 34

    /// The virtual call stack.
35
    pub(super) stack: Vec<Frame<'tcx>>,
36 37

    /// The maximum number of stack frames allowed
38
    pub(super) stack_limit: usize,
39 40 41 42

    /// The maximum number of operations that may be executed.
    /// This prevents infinite loops and huge computations from freezing up const eval.
    /// Remove once halting problem is solved.
43
    pub(super) steps_remaining: u64,
44 45
}

46
/// A stack frame.
47
pub struct Frame<'tcx> {
48 49 50
    ////////////////////////////////////////////////////////////////////////////////
    // Function and callsite information
    ////////////////////////////////////////////////////////////////////////////////
51

52
    /// The MIR for the function called on this frame.
53
    pub mir: MirRef<'tcx>,
54 55 56

    /// The def_id of the current function.
    pub def_id: DefId,
57

58
    /// type substitutions for the current function invocation.
59
    pub substs: &'tcx Substs<'tcx>,
60

61 62
    /// The span of the call site.
    pub span: codemap::Span,
63

64
    ////////////////////////////////////////////////////////////////////////////////
65
    // Return lvalue and locals
66
    ////////////////////////////////////////////////////////////////////////////////
67

68
    /// The block to return to when returning from the current stack frame
69
    pub return_to_block: StackPopCleanup,
70

71
    /// The location where the result of the current stack frame should be written to.
72
    pub return_lvalue: Lvalue<'tcx>,
73 74 75 76

    /// The list of locals for this stack frame, stored in order as
    /// `[arguments..., variables..., temporaries...]`. The locals are stored as `Value`s, which
    /// can either directly contain `PrimVal` or refer to some part of an `Allocation`.
S
Scott Olson 已提交
77
    ///
78 79
    /// Before being initialized, all locals are `Value::ByVal(PrimVal::Undef)`.
    pub locals: Vec<Value>,
80

O
Oliver Schneider 已提交
81
    /// Temporary allocations introduced to save stackframes
82 83
    /// This is pure interpreter magic and has nothing to do with how rustc does it
    /// An example is calling an FnMut closure that has been converted to a FnOnce closure
O
Oliver Schneider 已提交
84
    /// The memory will be freed when the stackframe finishes
85
    pub interpreter_temporaries: Vec<Pointer>,
86

87 88 89 90 91 92 93 94 95
    ////////////////////////////////////////////////////////////////////////////////
    // Current position within the function
    ////////////////////////////////////////////////////////////////////////////////

    /// The block that is currently executed (or will be executed after the above call stacks
    /// return).
    pub block: mir::BasicBlock,

    /// The index of the currently evaluated statment.
96
    pub stmt: usize,
97
}
98

99 100
#[derive(Clone, Debug, Eq, PartialEq, Hash)]
pub enum StackPopCleanup {
101 102
    /// The stackframe existed to compute the initial value of a static/constant, make sure it
    /// isn't modifyable afterwards. The allocation of the result is frozen iff it's an
103 104
    /// actual allocation. `PrimVal`s are unmodifyable anyway.
    Freeze,
105 106 107 108 109 110 111
    /// A regular stackframe added due to a function call will need to get forwarded to the next
    /// block
    Goto(mir::BasicBlock),
    /// The main function and diverging functions have nowhere to return to
    None,
}

S
Scott Olson 已提交
112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128
#[derive(Copy, Clone, Debug)]
pub struct ResourceLimits {
    pub memory_size: u64,
    pub step_limit: u64,
    pub stack_limit: usize,
}

impl Default for ResourceLimits {
    fn default() -> Self {
        ResourceLimits {
            memory_size: 100 * 1024 * 1024, // 100 MB
            step_limit: 1_000_000,
            stack_limit: 100,
        }
    }
}

129
impl<'a, 'tcx> EvalContext<'a, 'tcx> {
S
Scott Olson 已提交
130
    pub fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>, limits: ResourceLimits) -> Self {
131
        EvalContext {
S
Scott Olson 已提交
132
            tcx,
S
Scott Olson 已提交
133
            memory: Memory::new(&tcx.data_layout, limits.memory_size),
134
            globals: HashMap::new(),
135
            stack: Vec::new(),
S
Scott Olson 已提交
136 137
            stack_limit: limits.stack_limit,
            steps_remaining: limits.step_limit,
138 139
        }
    }
140

S
Scott Olson 已提交
141 142 143 144 145 146
    pub fn alloc_ptr(&mut self, ty: Ty<'tcx>) -> EvalResult<'tcx, Pointer> {
        let substs = self.substs();
        self.alloc_ptr_with_substs(ty, substs)
    }

    pub fn alloc_ptr_with_substs(
147 148 149 150
        &mut self,
        ty: Ty<'tcx>,
        substs: &'tcx Substs<'tcx>
    ) -> EvalResult<'tcx, Pointer> {
151 152
        let size = self.type_size_with_substs(ty, substs)?.expect("cannot alloc memory for unsized type");
        let align = self.type_align_with_substs(ty, substs)?;
S
Scott Olson 已提交
153
        self.memory.allocate(size, align)
154
    }
O
Oliver Schneider 已提交
155

156
    pub fn memory(&self) -> &Memory<'a, 'tcx> {
157 158 159
        &self.memory
    }

160
    pub fn memory_mut(&mut self) -> &mut Memory<'a, 'tcx> {
O
Oliver Schneider 已提交
161 162 163
        &mut self.memory
    }

164
    pub fn stack(&self) -> &[Frame<'tcx>] {
165 166 167
        &self.stack
    }

168
    pub(super) fn str_to_value(&mut self, s: &str) -> EvalResult<'tcx, Value> {
169
        // FIXME: cache these allocs
170
        let ptr = self.memory.allocate(s.len() as u64, 1)?;
171 172
        self.memory.write_bytes(ptr, s.as_bytes())?;
        self.memory.freeze(ptr.alloc_id)?;
O
Oliver Schneider 已提交
173
        Ok(Value::ByValPair(PrimVal::Ptr(ptr), PrimVal::from_u128(s.len() as u128)))
174 175
    }

176
    pub(super) fn const_to_value(&mut self, const_val: &ConstVal) -> EvalResult<'tcx, Value> {
177
        use rustc::middle::const_val::ConstVal::*;
S
Scott Olson 已提交
178
        use rustc_const_math::ConstFloat;
179 180

        let primval = match *const_val {
O
Oliver Schneider 已提交
181
            Integral(const_int) => PrimVal::Bytes(const_int.to_u128_unchecked()),
S
Scott Olson 已提交
182 183 184 185 186 187 188 189

            Float(ConstFloat::F32(f)) => PrimVal::from_f32(f),
            Float(ConstFloat::F64(f)) => PrimVal::from_f64(f),
            Float(ConstFloat::FInfer { .. }) =>
                bug!("uninferred constants only exist before typeck"),

            Bool(b) => PrimVal::from_bool(b),
            Char(c) => PrimVal::from_char(c),
190

191
            Str(ref s) => return self.str_to_value(s),
192

193
            ByteStr(ref bs) => {
194
                let ptr = self.memory.allocate(bs.len() as u64, 1)?;
195
                self.memory.write_bytes(ptr, bs)?;
196
                self.memory.freeze(ptr.alloc_id)?;
197
                PrimVal::Ptr(ptr)
198
            }
199 200 201 202

            Struct(_)    => unimplemented!(),
            Tuple(_)     => unimplemented!(),
            Function(_)  => unimplemented!(),
S
Scott Olson 已提交
203
            Array(_)     => unimplemented!(),
204 205 206
            Repeat(_, _) => unimplemented!(),
        };

207
        Ok(Value::ByVal(primval))
208 209
    }

210
    pub(super) fn type_is_sized(&self, ty: Ty<'tcx>) -> bool {
O
Oliver Schneider 已提交
211
        // generics are weird, don't run this function on a generic
212
        assert!(!ty.needs_subst());
213 214 215
        ty.is_sized(self.tcx, &self.tcx.empty_parameter_environment(), DUMMY_SP)
    }

216
    pub fn load_mir(&self, def_id: DefId) -> EvalResult<'tcx, MirRef<'tcx>> {
217
        trace!("load mir {:?}", def_id);
218 219
        if def_id.is_local() || self.tcx.sess.cstore.is_item_mir_available(def_id) {
            Ok(self.tcx.item_mir(def_id))
S
Scott Olson 已提交
220
        } else {
221
            Err(EvalError::NoMirFor(self.tcx.item_path_str(def_id)))
222 223
        }
    }
O
Oliver Schneider 已提交
224

225
    pub fn monomorphize(&self, ty: Ty<'tcx>, substs: &'tcx Substs<'tcx>) -> Ty<'tcx> {
O
Oliver Schneider 已提交
226 227 228 229
        // miri doesn't care about lifetimes, and will choke on some crazy ones
        // let's simply get rid of them
        let without_lifetimes = self.tcx.erase_regions(&ty);
        let substituted = without_lifetimes.subst(self.tcx, substs);
S
Scott Olson 已提交
230
        self.tcx.normalize_associated_type(&substituted)
O
Oliver Schneider 已提交
231 232
    }

233
    pub(super) fn type_size(&self, ty: Ty<'tcx>) -> EvalResult<'tcx, Option<u64>> {
234
        self.type_size_with_substs(ty, self.substs())
O
Oliver Schneider 已提交
235 236
    }

237
    pub(super) fn type_align(&self, ty: Ty<'tcx>) -> EvalResult<'tcx, u64> {
238 239 240
        self.type_align_with_substs(ty, self.substs())
    }

241 242 243 244 245
    fn type_size_with_substs(
        &self,
        ty: Ty<'tcx>,
        substs: &'tcx Substs<'tcx>,
    ) -> EvalResult<'tcx, Option<u64>> {
246
        let layout = self.type_layout_with_substs(ty, substs)?;
247
        if layout.is_unsized() {
248
            Ok(None)
249
        } else {
250
            Ok(Some(layout.size(&self.tcx.data_layout).bytes()))
251
        }
252 253
    }

254 255
    fn type_align_with_substs(&self, ty: Ty<'tcx>, substs: &'tcx Substs<'tcx>) -> EvalResult<'tcx, u64> {
        self.type_layout_with_substs(ty, substs).map(|layout| layout.align(&self.tcx.data_layout).abi())
256 257
    }

258
    pub(super) fn type_layout(&self, ty: Ty<'tcx>) -> EvalResult<'tcx, &'tcx Layout> {
259 260 261
        self.type_layout_with_substs(ty, self.substs())
    }

262
    fn type_layout_with_substs(&self, ty: Ty<'tcx>, substs: &'tcx Substs<'tcx>) -> EvalResult<'tcx, &'tcx Layout> {
O
Oliver Schneider 已提交
263 264 265
        // TODO(solson): Is this inefficient? Needs investigation.
        let ty = self.monomorphize(ty, substs);

O
Oliver Schneider 已提交
266
        self.tcx.infer_ctxt((), Reveal::All).enter(|infcx| {
267
            ty.layout(&infcx).map_err(EvalError::Layout)
O
Oliver Schneider 已提交
268 269
        })
    }
270

O
Oliver Schneider 已提交
271 272 273 274
    pub fn push_stack_frame(
        &mut self,
        def_id: DefId,
        span: codemap::Span,
275
        mir: MirRef<'tcx>,
O
Oliver Schneider 已提交
276
        substs: &'tcx Substs<'tcx>,
277
        return_lvalue: Lvalue<'tcx>,
278
        return_to_block: StackPopCleanup,
279
        temporaries: Vec<Pointer>,
280
    ) -> EvalResult<'tcx> {
281 282
        ::log_settings::settings().indentation += 1;

S
Scott Olson 已提交
283 284 285
        // Subtract 1 because `local_decls` includes the ReturnPointer, but we don't store a local
        // `Value` for that.
        let num_locals = mir.local_decls.len() - 1;
286
        let locals = vec![Value::ByVal(PrimVal::Undef); num_locals];
287

288
        self.stack.push(Frame {
S
Scott Olson 已提交
289
            mir,
290
            block: mir::START_BLOCK,
S
Scott Olson 已提交
291 292 293
            return_to_block,
            return_lvalue,
            locals,
294
            interpreter_temporaries: temporaries,
S
Scott Olson 已提交
295 296 297
            span,
            def_id,
            substs,
298
            stmt: 0,
299
        });
300

301 302 303 304 305
        if self.stack.len() > self.stack_limit {
            Err(EvalError::StackFrameLimitReached)
        } else {
            Ok(())
        }
306 307
    }

308
    pub(super) fn pop_stack_frame(&mut self) -> EvalResult<'tcx> {
309
        ::log_settings::settings().indentation -= 1;
310
        let frame = self.stack.pop().expect("tried to pop a stack frame, but there were none");
311
        match frame.return_to_block {
312
            StackPopCleanup::Freeze => if let Lvalue::Global(id) = frame.return_lvalue {
313 314 315
                let global_value = self.globals.get_mut(&id)
                    .expect("global should have been cached (freeze)");
                match global_value.value {
316
                    Value::ByRef(ptr) => self.memory.freeze(ptr.alloc_id)?,
317 318
                    Value::ByVal(val) => if let PrimVal::Ptr(ptr) = val {
                        self.memory.freeze(ptr.alloc_id)?;
319
                    },
320 321 322
                    Value::ByValPair(val1, val2) => {
                        if let PrimVal::Ptr(ptr) = val1 {
                            self.memory.freeze(ptr.alloc_id)?;
323
                        }
324 325
                        if let PrimVal::Ptr(ptr) = val2 {
                            self.memory.freeze(ptr.alloc_id)?;
326 327 328
                        }
                    },
                }
329 330
                assert!(global_value.mutable);
                global_value.mutable = false;
331 332 333
            } else {
                bug!("StackPopCleanup::Freeze on: {:?}", frame.return_lvalue);
            },
334 335
            StackPopCleanup::Goto(target) => self.goto_block(target),
            StackPopCleanup::None => {},
336
        }
O
Oliver Schneider 已提交
337
        // deallocate all locals that are backed by an allocation
S
Scott Olson 已提交
338
        for local in frame.locals {
339
            if let Value::ByRef(ptr) = local {
340
                trace!("deallocating local");
341
                self.memory.dump_alloc(ptr.alloc_id);
342
                match self.memory.deallocate(ptr) {
O
Oliver Schneider 已提交
343 344 345 346
                    // Any frozen memory means that it belongs to a constant or something referenced
                    // by a constant. We could alternatively check whether the alloc_id is frozen
                    // before calling deallocate, but this is much simpler and is probably the
                    // rare case.
347 348 349 350 351
                    Ok(()) | Err(EvalError::DeallocatedFrozenMemory) => {},
                    other => return other,
                }
            }
        }
352 353 354
        // deallocate all temporary allocations
        for ptr in frame.interpreter_temporaries {
            trace!("deallocating temporary allocation");
355
            self.memory.dump_alloc(ptr.alloc_id);
356 357
            self.memory.deallocate(ptr)?;
        }
358
        Ok(())
359 360
    }

361 362 363 364 365
    pub fn assign_discr_and_fields<
        I: IntoIterator<Item = u64>,
        V: IntoValTyPair<'tcx>,
        J: IntoIterator<Item = V>,
    >(
366
        &mut self,
367
        dest: Lvalue<'tcx>,
368
        offsets: I,
369 370 371
        operands: J,
        discr_val: u128,
        discr_size: u64,
372
    ) -> EvalResult<'tcx> {
373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392
        // FIXME(solson)
        let dest_ptr = self.force_allocation(dest)?.to_ptr();

        let mut offsets = offsets.into_iter();
        let discr_offset = offsets.next().unwrap();
        let discr_dest = dest_ptr.offset(discr_offset);
        self.memory.write_uint(discr_dest, discr_val, discr_size)?;

        self.assign_fields(dest, offsets, operands)
    }

    pub fn assign_fields<
        I: IntoIterator<Item = u64>,
        V: IntoValTyPair<'tcx>,
        J: IntoIterator<Item = V>,
    >(
        &mut self,
        dest: Lvalue<'tcx>,
        offsets: I,
        operands: J,
393
    ) -> EvalResult<'tcx> {
394
        // FIXME(solson)
395
        let dest = self.force_allocation(dest)?.to_ptr();
396

397
        for (offset, operand) in offsets.into_iter().zip(operands) {
398
            let (value, value_ty) = operand.into_val_ty_pair(self)?;
399
            let field_dest = dest.offset(offset);
400
            self.write_value_to_ptr(value, field_dest, value_ty)?;
401 402 403 404
        }
        Ok(())
    }

405 406 407 408
    /// Evaluate an assignment statement.
    ///
    /// There is no separate `eval_rvalue` function. Instead, the code for handling each rvalue
    /// type writes its results directly into the memory specified by the lvalue.
409
    pub(super) fn eval_rvalue_into_lvalue(
410 411 412
        &mut self,
        rvalue: &mir::Rvalue<'tcx>,
        lvalue: &mir::Lvalue<'tcx>,
413
    ) -> EvalResult<'tcx> {
414
        let dest = self.eval_lvalue(lvalue)?;
S
Scott Olson 已提交
415
        let dest_ty = self.lvalue_ty(lvalue);
416
        let dest_layout = self.type_layout(dest_ty)?;
417

418
        use rustc::mir::Rvalue::*;
419
        match *rvalue {
420
            Use(ref operand) => {
421 422
                let value = self.eval_operand(operand)?;
                self.write_value(value, dest, dest_ty)?;
423
            }
424

425
            BinaryOp(bin_op, ref left, ref right) => {
426
                // ignore overflow bit, rustc inserts check branches for us
427
                self.intrinsic_overflowing(bin_op, left, right, dest, dest_ty)?;
428
            }
429

430
            CheckedBinaryOp(bin_op, ref left, ref right) => {
431
                self.intrinsic_with_overflow(bin_op, left, right, dest, dest_ty)?;
432
            }
433

434
            UnaryOp(un_op, ref operand) => {
435
                let val = self.eval_operand_to_primval(operand)?;
436
                let kind = self.ty_to_primval_kind(dest_ty)?;
437
                self.write_primval(dest, operator::unary_op(un_op, val, kind)?, dest_ty)?;
438
            }
439

440
            Aggregate(ref kind, ref operands) => {
441
                self.inc_step_counter_and_check_limit(operands.len() as u64)?;
442
                use rustc::ty::layout::Layout::*;
443
                match *dest_layout {
444
                    Univariant { ref variant, .. } => {
S
Scott Olson 已提交
445
                        let offsets = variant.offsets.iter().map(|s| s.bytes());
446 447 448 449
                        if variant.packed {
                            let ptr = self.force_allocation(dest)?.to_ptr_and_extra().0;
                            self.memory.mark_packed(ptr, variant.stride().bytes());
                        }
S
Scott Olson 已提交
450
                        self.assign_fields(dest, offsets, operands)?;
451 452
                    }

453
                    Array { .. } => {
454
                        let elem_size = match dest_ty.sty {
455 456
                            ty::TyArray(elem_ty, _) => self.type_size(elem_ty)?
                                .expect("array elements are sized") as u64,
457
                            _ => bug!("tried to assign {:?} to non-array type {:?}", kind, dest_ty),
458 459
                        };
                        let offsets = (0..).map(|i| i * elem_size);
S
Scott Olson 已提交
460
                        self.assign_fields(dest, offsets, operands)?;
461
                    }
462

463
                    General { discr, ref variants, .. } => {
464
                        if let mir::AggregateKind::Adt(adt_def, variant, _, _) = *kind {
O
Oliver Schneider 已提交
465
                            let discr_val = adt_def.variants[variant].disr_val.to_u128_unchecked();
466
                            let discr_size = discr.size().bytes();
467 468 469 470
                            if variants[variant].packed {
                                let ptr = self.force_allocation(dest)?.to_ptr_and_extra().0;
                                self.memory.mark_packed(ptr, variants[variant].stride().bytes());
                            }
471

472 473 474 475 476 477 478
                            self.assign_discr_and_fields(
                                dest,
                                variants[variant].offsets.iter().cloned().map(Size::bytes),
                                operands,
                                discr_val,
                                discr_size,
                            )?;
479
                        } else {
480
                            bug!("tried to assign {:?} to Layout::General", kind);
S
Scott Olson 已提交
481
                        }
482 483
                    }

484
                    RawNullablePointer { nndiscr, .. } => {
485
                        if let mir::AggregateKind::Adt(_, variant, _, _) = *kind {
486 487 488
                            if nndiscr == variant as u64 {
                                assert_eq!(operands.len(), 1);
                                let operand = &operands[0];
489 490 491
                                let value = self.eval_operand(operand)?;
                                let value_ty = self.operand_ty(operand);
                                self.write_value(value, dest, value_ty)?;
492
                            } else {
493 494 495
                                if let Some(operand) = operands.get(0) {
                                    assert_eq!(operands.len(), 1);
                                    let operand_ty = self.operand_ty(operand);
496
                                    assert_eq!(self.type_size(operand_ty)?, Some(0));
497
                                }
S
Scott Olson 已提交
498
                                self.write_primval(dest, PrimVal::Bytes(0), dest_ty)?;
499 500
                            }
                        } else {
501
                            bug!("tried to assign {:?} to Layout::RawNullablePointer", kind);
S
Scott Olson 已提交
502
                        }
503 504
                    }

S
Scott Olson 已提交
505
                    StructWrappedNullablePointer { nndiscr, ref nonnull, ref discrfield, .. } => {
506
                        if let mir::AggregateKind::Adt(_, variant, _, _) = *kind {
507 508 509 510
                            if nonnull.packed {
                                let ptr = self.force_allocation(dest)?.to_ptr_and_extra().0;
                                self.memory.mark_packed(ptr, nonnull.stride().bytes());
                            }
511
                            if nndiscr == variant as u64 {
S
Scott Olson 已提交
512
                                let offsets = nonnull.offsets.iter().map(|s| s.bytes());
S
Scott Olson 已提交
513
                                self.assign_fields(dest, offsets, operands)?;
514
                            } else {
515 516
                                for operand in operands {
                                    let operand_ty = self.operand_ty(operand);
517
                                    assert_eq!(self.type_size(operand_ty)?, Some(0));
518
                                }
519
                                let (offset, ty) = self.nonnull_offset_and_ty(dest_ty, nndiscr, discrfield)?;
520 521

                                // FIXME(solson)
522
                                let dest = self.force_allocation(dest)?.to_ptr();
523

524
                                let dest = dest.offset(offset.bytes());
525 526
                                let dest_size = self.type_size(ty)?
                                    .expect("bad StructWrappedNullablePointer discrfield");
S
Scott Olson 已提交
527
                                self.memory.write_int(dest, 0, dest_size)?;
528 529
                            }
                        } else {
530
                            bug!("tried to assign {:?} to Layout::RawNullablePointer", kind);
531 532 533
                        }
                    }

534
                    CEnum { .. } => {
535
                        assert_eq!(operands.len(), 0);
536
                        if let mir::AggregateKind::Adt(adt_def, variant, _, _) = *kind {
O
Oliver Schneider 已提交
537
                            let n = adt_def.variants[variant].disr_val.to_u128_unchecked();
538
                            self.write_primval(dest, PrimVal::Bytes(n), dest_ty)?;
539
                        } else {
540
                            bug!("tried to assign {:?} to Layout::CEnum", kind);
541 542 543
                        }
                    }

O
Oliver Schneider 已提交
544 545 546 547 548 549 550
                    Vector { element, count } => {
                        let elem_size = element.size(&self.tcx.data_layout).bytes();
                        debug_assert_eq!(count, operands.len() as u64);
                        let offsets = (0..).map(|i| i * elem_size);
                        self.assign_fields(dest, offsets, operands)?;
                    }

S
Scott Olson 已提交
551 552 553 554 555 556 557 558 559 560 561 562 563 564 565
                    UntaggedUnion { .. } => {
                        assert_eq!(operands.len(), 1);
                        let operand = &operands[0];
                        let value = self.eval_operand(operand)?;
                        let value_ty = self.operand_ty(operand);
                        self.write_value(value, dest, value_ty)?;
                    }

                    _ => {
                        return Err(EvalError::Unimplemented(format!(
                            "can't handle destination layout {:?} when assigning {:?}",
                            dest_layout,
                            kind
                        )));
                    }
566
                }
567
            }
568

569
            Repeat(ref operand, _) => {
570
                let (elem_ty, length) = match dest_ty.sty {
571
                    ty::TyArray(elem_ty, n) => (elem_ty, n as u64),
572
                    _ => bug!("tried to assign array-repeat to non-array type {:?}", dest_ty),
573
                };
574
                self.inc_step_counter_and_check_limit(length)?;
575 576
                let elem_size = self.type_size(elem_ty)?
                    .expect("repeat element type must be sized");
577
                let value = self.eval_operand(operand)?;
578 579

                // FIXME(solson)
580
                let dest = self.force_allocation(dest)?.to_ptr();
581

582
                for i in 0..length {
583
                    let elem_dest = dest.offset(i * elem_size);
584
                    self.write_value_to_ptr(value, elem_dest, elem_ty)?;
585 586
                }
            }
587

588
            Len(ref lvalue) => {
S
Scott Olson 已提交
589
                let src = self.eval_lvalue(lvalue)?;
590
                let ty = self.lvalue_ty(lvalue);
O
Oliver Schneider 已提交
591
                let (_, len) = src.elem_ty_and_len(ty);
O
Oliver Schneider 已提交
592
                self.write_primval(dest, PrimVal::from_u128(len as u128), dest_ty)?;
593 594
            }

S
Scott Olson 已提交
595
            Ref(_, _, ref lvalue) => {
596 597
                let src = self.eval_lvalue(lvalue)?;
                let (raw_ptr, extra) = self.force_allocation(src)?.to_ptr_and_extra();
598
                let ptr = PrimVal::Ptr(raw_ptr);
599

600 601
                let val = match extra {
                    LvalueExtra::None => Value::ByVal(ptr),
O
Oliver Schneider 已提交
602
                    LvalueExtra::Length(len) => Value::ByValPair(ptr, PrimVal::from_u128(len as u128)),
603
                    LvalueExtra::Vtable(vtable) => Value::ByValPair(ptr, PrimVal::Ptr(vtable)),
604 605
                    LvalueExtra::DowncastVariant(..) =>
                        bug!("attempted to take a reference to an enum downcast lvalue"),
606 607 608
                };

                self.write_value(val, dest, dest_ty)?;
S
Scott Olson 已提交
609
            }
S
Scott Olson 已提交
610

S
Scott Olson 已提交
611
            Box(ty) => {
612
                let ptr = self.alloc_ptr(ty)?;
613
                self.write_primval(dest, PrimVal::Ptr(ptr), dest_ty)?;
S
Scott Olson 已提交
614 615
            }

616 617
            Cast(kind, ref operand, cast_ty) => {
                debug_assert_eq!(self.monomorphize(cast_ty, self.substs()), dest_ty);
618
                use rustc::mir::CastKind::*;
619 620
                match kind {
                    Unsize => {
621
                        let src = self.eval_operand(operand)?;
O
Oliver Schneider 已提交
622
                        let src_ty = self.operand_ty(operand);
623
                        self.unsize_into(src, src_ty, dest, dest_ty)?;
624 625 626
                    }

                    Misc => {
627
                        let src = self.eval_operand(operand)?;
628
                        let src_ty = self.operand_ty(operand);
629
                        if self.type_is_fat_ptr(src_ty) {
630 631
                            trace!("misc cast: {:?}", src);
                            match (src, self.type_is_fat_ptr(dest_ty)) {
632 633 634
                                (Value::ByRef(_), _) |
                                (Value::ByValPair(..), true) => {
                                    self.write_value(src, dest, dest_ty)?;
635
                                },
636
                                (Value::ByValPair(data, _), false) => {
637
                                    self.write_value(Value::ByVal(data), dest, dest_ty)?;
638 639
                                },
                                (Value::ByVal(_), _) => bug!("expected fat ptr"),
O
Oliver Schneider 已提交
640
                            }
641
                        } else {
642
                            let src_val = self.value_to_primval(src, src_ty)?;
643
                            let dest_val = self.cast_primval(src_val, src_ty, dest_ty)?;
644
                            self.write_value(Value::ByVal(dest_val), dest, dest_ty)?;
645
                        }
646 647
                    }

O
Oliver Schneider 已提交
648
                    ReifyFnPointer => match self.operand_ty(operand).sty {
649
                        ty::TyFnDef(def_id, substs, fn_ty) => {
650
                            let fn_ty = self.tcx.erase_regions(&fn_ty);
651
                            let fn_ptr = self.memory.create_fn_ptr(self.tcx,def_id, substs, fn_ty);
652
                            self.write_value(Value::ByVal(PrimVal::Ptr(fn_ptr)), dest, dest_ty)?;
O
Oliver Schneider 已提交
653
                        },
654
                        ref other => bug!("reify fn pointer on {:?}", other),
O
Oliver Schneider 已提交
655 656
                    },

657 658
                    UnsafeFnPointer => match dest_ty.sty {
                        ty::TyFnPtr(unsafe_fn_ty) => {
659 660
                            let src = self.eval_operand(operand)?;
                            let ptr = src.read_ptr(&self.memory)?;
661
                            let (def_id, substs, _, _) = self.memory.get_fn(ptr.alloc_id)?;
662
                            let unsafe_fn_ty = self.tcx.erase_regions(&unsafe_fn_ty);
663
                            let fn_ptr = self.memory.create_fn_ptr(self.tcx, def_id, substs, unsafe_fn_ty);
664
                            self.write_value(Value::ByVal(PrimVal::Ptr(fn_ptr)), dest, dest_ty)?;
665
                        },
666
                        ref other => bug!("fn to unsafe fn cast on {:?}", other),
667
                    },
668 669 670
                }
            }

S
Scott Olson 已提交
671
            InlineAsm { .. } => return Err(EvalError::InlineAsm),
672
        }
673

S
Scott Olson 已提交
674 675 676 677
        if log_enabled!(::log::LogLevel::Trace) {
            self.dump_local(dest);
        }

678
        Ok(())
679 680
    }

O
Oliver Schneider 已提交
681 682
    fn type_is_fat_ptr(&self, ty: Ty<'tcx>) -> bool {
        match ty.sty {
O
rustup  
Oliver Schneider 已提交
683 684 685
            ty::TyRawPtr(ref tam) |
            ty::TyRef(_, ref tam) => !self.type_is_sized(tam.ty),
            ty::TyAdt(def, _) if def.is_box() => !self.type_is_sized(ty.boxed_ty()),
O
Oliver Schneider 已提交
686 687 688 689
            _ => false,
        }
    }

690 691 692 693 694 695
    pub(super) fn nonnull_offset_and_ty(
        &self,
        ty: Ty<'tcx>,
        nndiscr: u64,
        discrfield: &[u32],
    ) -> EvalResult<'tcx, (Size, Ty<'tcx>)> {
696 697
        // Skip the constant 0 at the start meant for LLVM GEP and the outer non-null variant
        let path = discrfield.iter().skip(2).map(|&i| i as usize);
698 699

        // Handle the field index for the outer non-null variant.
700
        let (inner_offset, inner_ty) = match ty.sty {
S
Scott Olson 已提交
701
            ty::TyAdt(adt_def, substs) => {
702
                let variant = &adt_def.variants[nndiscr as usize];
703 704
                let index = discrfield[1];
                let field = &variant.fields[index as usize];
705
                (self.get_field_offset(ty, index as usize)?, field.ty(self.tcx, substs))
706
            }
707
            _ => bug!("non-enum for StructWrappedNullablePointer: {}", ty),
708 709
        };

710
        self.field_path_offset_and_ty(inner_offset, inner_ty, path)
711 712
    }

713 714 715 716 717 718
    fn field_path_offset_and_ty<I: Iterator<Item = usize>>(
        &self,
        mut offset: Size,
        mut ty: Ty<'tcx>,
        path: I,
    ) -> EvalResult<'tcx, (Size, Ty<'tcx>)> {
719 720
        // Skip the initial 0 intended for LLVM GEP.
        for field_index in path {
721
            let field_offset = self.get_field_offset(ty, field_index)?;
722
            trace!("field_path_offset_and_ty: {}, {}, {:?}, {:?}", field_index, ty, field_offset, offset);
723
            ty = self.get_field_ty(ty, field_index)?;
724 725 726
            offset = offset.checked_add(field_offset, &self.tcx.data_layout).unwrap();
        }

727
        Ok((offset, ty))
728
    }
O
rustup  
Oliver Schneider 已提交
729 730 731 732 733 734 735 736 737
    fn get_fat_field(&self, pointee_ty: Ty<'tcx>, field_index: usize) -> EvalResult<'tcx, Ty<'tcx>> {
        match (field_index, &self.tcx.struct_tail(pointee_ty).sty) {
            (1, &ty::TyStr) |
            (1, &ty::TySlice(_)) => Ok(self.tcx.types.usize),
            (1, &ty::TyDynamic(..)) |
            (0, _) => Ok(self.tcx.mk_imm_ptr(self.tcx.types.u8)),
            _ => bug!("invalid fat pointee type: {}", pointee_ty),
        }
    }
738

O
Oliver Schneider 已提交
739
    pub fn get_field_ty(&self, ty: Ty<'tcx>, field_index: usize) -> EvalResult<'tcx, Ty<'tcx>> {
740
        match ty.sty {
O
rustup  
Oliver Schneider 已提交
741
            ty::TyAdt(adt_def, _) if adt_def.is_box() => self.get_fat_field(ty.boxed_ty(), field_index),
S
Scott Olson 已提交
742
            ty::TyAdt(adt_def, substs) => {
743
                Ok(adt_def.struct_variant().fields[field_index].ty(self.tcx, substs))
744 745
            }

746 747
            ty::TyTuple(fields) => Ok(fields[field_index]),

O
rustup  
Oliver Schneider 已提交
748 749
            ty::TyRef(_, ref tam) |
            ty::TyRawPtr(ref tam) => self.get_fat_field(tam.ty, field_index),
750
            _ => Err(EvalError::Unimplemented(format!("can't handle type: {:?}, {:?}", ty, ty.sty))),
751 752 753
        }
    }

754
    fn get_field_offset(&self, ty: Ty<'tcx>, field_index: usize) -> EvalResult<'tcx, Size> {
755
        let layout = self.type_layout(ty)?;
756 757 758

        use rustc::ty::layout::Layout::*;
        match *layout {
759
            Univariant { ref variant, .. } => {
S
Scott Olson 已提交
760
                Ok(variant.offsets[field_index])
761 762
            }
            FatPointer { .. } => {
763 764
                let bytes = field_index as u64 * self.memory.pointer_size();
                Ok(Size::from_bytes(bytes))
765
            }
766 767 768
            StructWrappedNullablePointer { ref nonnull, .. } => {
                Ok(nonnull.offsets[field_index])
            }
769 770 771 772 773 774 775 776
            _ => {
                let msg = format!("can't handle type: {:?}, with layout: {:?}", ty, layout);
                Err(EvalError::Unimplemented(msg))
            }
        }
    }

    fn get_field_count(&self, ty: Ty<'tcx>) -> EvalResult<'tcx, usize> {
777
        let layout = self.type_layout(ty)?;
778 779 780 781 782

        use rustc::ty::layout::Layout::*;
        match *layout {
            Univariant { ref variant, .. } => Ok(variant.offsets.len()),
            FatPointer { .. } => Ok(2),
783
            StructWrappedNullablePointer { ref nonnull, .. } => Ok(nonnull.offsets.len()),
784 785 786 787
            _ => {
                let msg = format!("can't handle type: {:?}, with layout: {:?}", ty, layout);
                Err(EvalError::Unimplemented(msg))
            }
788 789 790
        }
    }

791
    pub(super) fn eval_operand_to_primval(&mut self, op: &mir::Operand<'tcx>) -> EvalResult<'tcx, PrimVal> {
792 793 794 795 796
        let value = self.eval_operand(op)?;
        let ty = self.operand_ty(op);
        self.value_to_primval(value, ty)
    }

797
    pub(super) fn eval_operand(&mut self, op: &mir::Operand<'tcx>) -> EvalResult<'tcx, Value> {
798
        use rustc::mir::Operand::*;
799
        match *op {
800
            Consume(ref lvalue) => self.eval_and_read_lvalue(lvalue),
801

802
            Constant(mir::Constant { ref literal, ty, .. }) => {
803
                use rustc::mir::Literal;
804
                let value = match *literal {
805
                    Literal::Value { ref value } => self.const_to_value(value)?,
806 807

                    Literal::Item { def_id, substs } => {
808
                        if let ty::TyFnDef(..) = ty.sty {
O
Oliver Schneider 已提交
809
                            // function items are zero sized
810
                            Value::ByRef(self.memory.allocate(0, 0)?)
811
                        } else {
S
Scott Olson 已提交
812
                            let cid = GlobalId { def_id, substs, promoted: None };
813
                            self.read_lvalue(Lvalue::Global(cid))
814
                        }
815 816 817
                    }

                    Literal::Promoted { index } => {
818
                        let cid = GlobalId {
819 820
                            def_id: self.frame().def_id,
                            substs: self.substs(),
O
Oliver Schneider 已提交
821
                            promoted: Some(index),
822
                        };
823
                        self.read_lvalue(Lvalue::Global(cid))
824 825 826 827
                    }
                };

                Ok(value)
828 829 830
            }
        }
    }
S
Scott Olson 已提交
831

832
    pub(super) fn operand_ty(&self, operand: &mir::Operand<'tcx>) -> Ty<'tcx> {
S
Scott Olson 已提交
833
        self.monomorphize(operand.ty(&self.mir(), self.tcx), self.substs())
834 835
    }

836
    fn copy(&mut self, src: Pointer, dest: Pointer, ty: Ty<'tcx>) -> EvalResult<'tcx> {
837 838
        let size = self.type_size(ty)?.expect("cannot copy from an unsized type");
        let align = self.type_align(ty)?;
839
        self.memory.copy(src, dest, size, align)?;
S
Scott Olson 已提交
840 841 842
        Ok(())
    }

843 844 845 846
    pub(super) fn force_allocation(
        &mut self,
        lvalue: Lvalue<'tcx>,
    ) -> EvalResult<'tcx, Lvalue<'tcx>> {
847 848
        let new_lvalue = match lvalue {
            Lvalue::Local { frame, local } => {
849
                match self.stack[frame].get_local(local) {
850 851
                    Value::ByRef(ptr) => Lvalue::from_ptr(ptr),
                    val => {
852
                        let ty = self.stack[frame].mir.local_decls[local].ty;
853
                        let ty = self.monomorphize(ty, self.stack[frame].substs);
854
                        let substs = self.stack[frame].substs;
S
Scott Olson 已提交
855
                        let ptr = self.alloc_ptr_with_substs(ty, substs)?;
856
                        self.stack[frame].set_local(local, Value::ByRef(ptr));
857
                        self.write_value_to_ptr(val, ptr, ty)?;
858
                        Lvalue::from_ptr(ptr)
859
                    }
860
                }
861 862
            }
            Lvalue::Ptr { .. } => lvalue,
863 864
            Lvalue::Global(cid) => {
                let global_val = *self.globals.get(&cid).expect("global not cached");
865 866
                match global_val.value {
                    Value::ByRef(ptr) => Lvalue::from_ptr(ptr),
867
                    _ => {
868
                        let ptr = self.alloc_ptr_with_substs(global_val.ty, cid.substs)?;
869
                        self.write_value_to_ptr(global_val.value, ptr, global_val.ty)?;
870
                        if !global_val.mutable {
871 872
                            self.memory.freeze(ptr.alloc_id)?;
                        }
873 874
                        let lval = self.globals.get_mut(&cid).expect("already checked");
                        *lval = Global {
875
                            value: Value::ByRef(ptr),
876
                            .. global_val
877 878 879 880 881
                        };
                        Lvalue::from_ptr(ptr)
                    },
                }
            }
882 883 884 885
        };
        Ok(new_lvalue)
    }

886
    /// ensures this Value is not a ByRef
887
    pub(super) fn follow_by_ref_value(&mut self, value: Value, ty: Ty<'tcx>) -> EvalResult<'tcx, Value> {
888
        match value {
889 890 891 892 893
            Value::ByRef(ptr) => self.read_value(ptr, ty),
            other => Ok(other),
        }
    }

894
    pub(super) fn value_to_primval(&mut self, value: Value, ty: Ty<'tcx>) -> EvalResult<'tcx, PrimVal> {
895 896
        match self.follow_by_ref_value(value, ty)? {
            Value::ByRef(_) => bug!("follow_by_ref_value can't result in `ByRef`"),
897

898
            Value::ByVal(primval) => {
899 900
                self.ensure_valid_value(primval, ty)?;
                Ok(primval)
901 902
            }

903
            Value::ByValPair(..) => bug!("value_to_primval can't work with fat pointers"),
904 905 906
        }
    }

907
    pub(super) fn write_primval(
908
        &mut self,
909
        dest: Lvalue<'tcx>,
910
        val: PrimVal,
911
        dest_ty: Ty<'tcx>,
912
    ) -> EvalResult<'tcx> {
913 914 915
        match dest {
            Lvalue::Ptr { ptr, extra } => {
                assert_eq!(extra, LvalueExtra::None);
916 917
                let size = self.type_size(dest_ty)?.expect("dest type must be sized");
                self.memory.write_primval(ptr, val, size)
918 919 920 921 922
            }
            Lvalue::Local { frame, local } => {
                self.stack[frame].set_local(local, Value::ByVal(val));
                Ok(())
            }
923 924
            Lvalue::Global(cid) => {
                let global_val = self.globals.get_mut(&cid).expect("global not cached");
925
                if global_val.mutable {
926
                    global_val.value = Value::ByVal(val);
927 928 929 930
                    Ok(())
                } else {
                    Err(EvalError::ModifiedConstantMemory)
                }
931
            }
932
        }
933 934
    }

935
    pub(super) fn write_value(
936
        &mut self,
937
        src_val: Value,
938
        dest: Lvalue<'tcx>,
939
        dest_ty: Ty<'tcx>,
940
    ) -> EvalResult<'tcx> {
941
        match dest {
942 943
            Lvalue::Global(cid) => {
                let dest = *self.globals.get_mut(&cid).expect("global should be cached");
944 945 946
                if !dest.mutable {
                    return Err(EvalError::ModifiedConstantMemory);
                }
947 948 949 950 951 952 953
                let write_dest = |this: &mut Self, val| {
                    *this.globals.get_mut(&cid).expect("already checked") = Global {
                        value: val,
                        ..dest
                    }
                };
                self.write_value_possibly_by_val(src_val, write_dest, dest.value, dest_ty)
954 955
            },

956 957
            Lvalue::Ptr { ptr, extra } => {
                assert_eq!(extra, LvalueExtra::None);
958
                self.write_value_to_ptr(src_val, ptr, dest_ty)
959
            }
960

961
            Lvalue::Local { frame, local } => {
962
                let dest = self.stack[frame].get_local(local);
963
                self.write_value_possibly_by_val(
964 965 966 967 968
                    src_val,
                    |this, val| this.stack[frame].set_local(local, val),
                    dest,
                    dest_ty,
                )
969 970
            }
        }
971 972 973
    }

    // The cases here can be a bit subtle. Read carefully!
974
    fn write_value_possibly_by_val<F: FnOnce(&mut Self, Value)>(
975 976 977
        &mut self,
        src_val: Value,
        write_dest: F,
978
        old_dest_val: Value,
979
        dest_ty: Ty<'tcx>,
980
    ) -> EvalResult<'tcx> {
981
        if let Value::ByRef(dest_ptr) = old_dest_val {
982
            // If the value is already `ByRef` (that is, backed by an `Allocation`),
983 984 985 986 987
            // then we must write the new value into this allocation, because there may be
            // other pointers into the allocation. These other pointers are logically
            // pointers into the local variable, and must be able to observe the change.
            //
            // Thus, it would be an error to replace the `ByRef` with a `ByVal`, unless we
988
            // knew for certain that there were no outstanding pointers to this allocation.
989 990 991
            self.write_value_to_ptr(src_val, dest_ptr, dest_ty)?;

        } else if let Value::ByRef(src_ptr) = src_val {
992
            // If the value is not `ByRef`, then we know there are no pointers to it
993 994 995 996 997 998 999
            // and we can simply overwrite the `Value` in the locals array directly.
            //
            // In this specific case, where the source value is `ByRef`, we must duplicate
            // the allocation, because this is a by-value operation. It would be incorrect
            // if they referred to the same allocation, since then a change to one would
            // implicitly change the other.
            //
1000 1001 1002 1003 1004 1005 1006 1007 1008 1009
            // It is a valid optimization to attempt reading a primitive value out of the
            // source and write that into the destination without making an allocation, so
            // we do so here.
            if let Ok(Some(src_val)) = self.try_read_value(src_ptr, dest_ty) {
                write_dest(self, src_val);
            } else {
                let dest_ptr = self.alloc_ptr(dest_ty)?;
                self.copy(src_ptr, dest_ptr, dest_ty)?;
                write_dest(self, Value::ByRef(dest_ptr));
            }
1010 1011 1012

        } else {
            // Finally, we have the simple case where neither source nor destination are
1013
            // `ByRef`. We may simply copy the source value over the the destintion.
1014 1015
            write_dest(self, src_val);
        }
1016
        Ok(())
1017 1018
    }

1019
    pub(super) fn write_value_to_ptr(
1020 1021 1022
        &mut self,
        value: Value,
        dest: Pointer,
1023
        dest_ty: Ty<'tcx>,
1024
    ) -> EvalResult<'tcx> {
1025
        match value {
1026
            Value::ByRef(ptr) => self.copy(ptr, dest, dest_ty),
1027
            Value::ByVal(primval) => {
1028 1029
                let size = self.type_size(dest_ty)?.expect("dest type must be sized");
                self.memory.write_primval(dest, primval, size)
1030
            }
1031
            Value::ByValPair(a, b) => self.write_pair_to_ptr(a, b, dest, dest_ty),
1032 1033 1034
        }
    }

1035
    pub(super) fn write_pair_to_ptr(
1036 1037 1038 1039 1040
        &mut self,
        a: PrimVal,
        b: PrimVal,
        ptr: Pointer,
        ty: Ty<'tcx>
1041
    ) -> EvalResult<'tcx> {
1042
        assert_eq!(self.get_field_count(ty)?, 2);
1043 1044
        let field_0 = self.get_field_offset(ty, 0)?.bytes();
        let field_1 = self.get_field_offset(ty, 1)?.bytes();
1045 1046
        let field_0_ty = self.get_field_ty(ty, 0)?;
        let field_1_ty = self.get_field_ty(ty, 1)?;
1047 1048 1049 1050
        let field_0_size = self.type_size(field_0_ty)?.expect("pair element type must be sized");
        let field_1_size = self.type_size(field_1_ty)?.expect("pair element type must be sized");
        self.memory.write_primval(ptr.offset(field_0), a, field_0_size)?;
        self.memory.write_primval(ptr.offset(field_1), b, field_1_size)?;
1051 1052 1053
        Ok(())
    }

O
Oliver Schneider 已提交
1054
    pub fn ty_to_primval_kind(&self, ty: Ty<'tcx>) -> EvalResult<'tcx, PrimValKind> {
1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067
        use syntax::ast::FloatTy;

        let kind = match ty.sty {
            ty::TyBool => PrimValKind::Bool,
            ty::TyChar => PrimValKind::Char,

            ty::TyInt(int_ty) => {
                use syntax::ast::IntTy::*;
                let size = match int_ty {
                    I8 => 1,
                    I16 => 2,
                    I32 => 4,
                    I64 => 8,
O
Oliver Schneider 已提交
1068
                    I128 => 16,
1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080
                    Is => self.memory.pointer_size(),
                };
                PrimValKind::from_int_size(size)
            }

            ty::TyUint(uint_ty) => {
                use syntax::ast::UintTy::*;
                let size = match uint_ty {
                    U8 => 1,
                    U16 => 2,
                    U32 => 4,
                    U64 => 8,
O
Oliver Schneider 已提交
1081
                    U128 => 16,
1082 1083 1084 1085 1086 1087 1088 1089 1090 1091
                    Us => self.memory.pointer_size(),
                };
                PrimValKind::from_uint_size(size)
            }

            ty::TyFloat(FloatTy::F32) => PrimValKind::F32,
            ty::TyFloat(FloatTy::F64) => PrimValKind::F64,

            ty::TyFnPtr(_) => PrimValKind::FnPtr,

O
rustup  
Oliver Schneider 已提交
1092 1093 1094 1095
            ty::TyRef(_, ref tam) |
            ty::TyRawPtr(ref tam) if self.type_is_sized(tam.ty) => PrimValKind::Ptr,

            ty::TyAdt(ref def, _) if def.is_box() => PrimValKind::Ptr,
1096 1097 1098

            ty::TyAdt(..) => {
                use rustc::ty::layout::Layout::*;
1099 1100 1101 1102 1103 1104 1105 1106
                match *self.type_layout(ty)? {
                    CEnum { discr, signed, .. } => {
                        let size = discr.size().bytes();
                        if signed {
                            PrimValKind::from_int_size(size)
                        } else {
                            PrimValKind::from_uint_size(size)
                        }
1107
                    }
1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120

                    RawNullablePointer { value, .. } => {
                        use rustc::ty::layout::Primitive::*;
                        match value {
                            // TODO(solson): Does signedness matter here? What should the sign be?
                            Int(int) => PrimValKind::from_uint_size(int.size().bytes()),
                            F32 => PrimValKind::F32,
                            F64 => PrimValKind::F64,
                            Pointer => PrimValKind::Ptr,
                        }
                    }

                    _ => return Err(EvalError::TypeNotPrimitive(ty)),
1121
                }
1122
            }
1123

1124
            _ => return Err(EvalError::TypeNotPrimitive(ty)),
1125 1126 1127 1128 1129
        };

        Ok(kind)
    }

1130
    fn ensure_valid_value(&self, val: PrimVal, ty: Ty<'tcx>) -> EvalResult<'tcx> {
1131
        match ty.sty {
1132
            ty::TyBool if val.to_bytes()? > 1 => Err(EvalError::InvalidBool),
1133

1134
            ty::TyChar if ::std::char::from_u32(val.to_bytes()? as u32).is_none()
O
Oliver Schneider 已提交
1135
                => Err(EvalError::InvalidChar(val.to_bytes()? as u32 as u128)),
1136 1137 1138 1139 1140

            _ => Ok(()),
        }
    }

1141
    pub(super) fn read_value(&mut self, ptr: Pointer, ty: Ty<'tcx>) -> EvalResult<'tcx, Value> {
1142 1143 1144 1145 1146 1147 1148
        if let Some(val) = self.try_read_value(ptr, ty)? {
            Ok(val)
        } else {
            bug!("primitive read failed for type: {:?}", ty);
        }
    }

O
rustup  
Oliver Schneider 已提交
1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165
    fn read_ptr(&mut self, ptr: Pointer, pointee_ty: Ty<'tcx>) -> EvalResult<'tcx, Value> {
        let p = self.memory.read_ptr(ptr)?;
        if self.type_is_sized(pointee_ty) {
            Ok(Value::ByVal(PrimVal::Ptr(p)))
        } else {
            trace!("reading fat pointer extra of type {}", pointee_ty);
            let extra = ptr.offset(self.memory.pointer_size());
            let extra = match self.tcx.struct_tail(pointee_ty).sty {
                ty::TyDynamic(..) => PrimVal::Ptr(self.memory.read_ptr(extra)?),
                ty::TySlice(..) |
                ty::TyStr => PrimVal::from_u128(self.memory.read_usize(extra)? as u128),
                _ => bug!("unsized primval ptr read from {:?}", pointee_ty),
            };
            Ok(Value::ByValPair(PrimVal::Ptr(p), extra))
        }
    }

1166
    fn try_read_value(&mut self, ptr: Pointer, ty: Ty<'tcx>) -> EvalResult<'tcx, Option<Value>> {
1167 1168
        use syntax::ast::FloatTy;

S
Scott Olson 已提交
1169
        let val = match ty.sty {
S
Scott Olson 已提交
1170
            ty::TyBool => PrimVal::from_bool(self.memory.read_bool(ptr)?),
S
Scott Olson 已提交
1171
            ty::TyChar => {
O
Oliver Schneider 已提交
1172 1173
                let c = self.memory.read_uint(ptr, 4)? as u32;
                match ::std::char::from_u32(c) {
S
Scott Olson 已提交
1174
                    Some(ch) => PrimVal::from_char(ch),
O
Oliver Schneider 已提交
1175
                    None => return Err(EvalError::InvalidChar(c as u128)),
O
Oliver Schneider 已提交
1176 1177
                }
            }
1178

S
Scott Olson 已提交
1179
            ty::TyInt(int_ty) => {
1180 1181 1182 1183 1184 1185
                use syntax::ast::IntTy::*;
                let size = match int_ty {
                    I8 => 1,
                    I16 => 2,
                    I32 => 4,
                    I64 => 8,
O
Oliver Schneider 已提交
1186
                    I128 => 16,
1187 1188
                    Is => self.memory.pointer_size(),
                };
O
Oliver Schneider 已提交
1189
                PrimVal::from_i128(self.memory.read_int(ptr, size)?)
1190
            }
1191

S
Scott Olson 已提交
1192
            ty::TyUint(uint_ty) => {
1193 1194 1195 1196 1197 1198
                use syntax::ast::UintTy::*;
                let size = match uint_ty {
                    U8 => 1,
                    U16 => 2,
                    U32 => 4,
                    U64 => 8,
O
Oliver Schneider 已提交
1199
                    U128 => 16,
1200 1201
                    Us => self.memory.pointer_size(),
                };
O
Oliver Schneider 已提交
1202
                PrimVal::from_u128(self.memory.read_uint(ptr, size)?)
1203
            }
1204

S
Scott Olson 已提交
1205 1206
            ty::TyFloat(FloatTy::F32) => PrimVal::from_f32(self.memory.read_f32(ptr)?),
            ty::TyFloat(FloatTy::F64) => PrimVal::from_f64(self.memory.read_f64(ptr)?),
1207

1208
            ty::TyFnPtr(_) => self.memory.read_ptr(ptr).map(PrimVal::Ptr)?,
O
rustup  
Oliver Schneider 已提交
1209 1210
            ty::TyRef(_, ref tam) |
            ty::TyRawPtr(ref tam) => return self.read_ptr(ptr, tam.ty).map(Some),
1211

O
rustup  
Oliver Schneider 已提交
1212 1213 1214 1215
            ty::TyAdt(def, _) => {
                if def.is_box() {
                    return self.read_ptr(ptr, ty.boxed_ty()).map(Some);
                }
O
Oliver Schneider 已提交
1216
                use rustc::ty::layout::Layout::*;
1217
                if let CEnum { discr, signed, .. } = *self.type_layout(ty)? {
1218
                    let size = discr.size().bytes();
1219
                    if signed {
O
Oliver Schneider 已提交
1220
                        PrimVal::from_i128(self.memory.read_int(ptr, size)?)
1221
                    } else {
O
Oliver Schneider 已提交
1222
                        PrimVal::from_u128(self.memory.read_uint(ptr, size)?)
O
Oliver Schneider 已提交
1223 1224
                    }
                } else {
1225
                    return Ok(None);
O
Oliver Schneider 已提交
1226 1227 1228
                }
            },

1229
            _ => return Ok(None),
1230
        };
S
Scott Olson 已提交
1231

1232
        Ok(Some(Value::ByVal(val)))
1233 1234
    }

1235
    pub(super) fn frame(&self) -> &Frame<'tcx> {
1236 1237
        self.stack.last().expect("no call frames exist")
    }
1238

1239
    pub(super) fn frame_mut(&mut self) -> &mut Frame<'tcx> {
1240 1241
        self.stack.last_mut().expect("no call frames exist")
    }
1242

1243
    pub(super) fn mir(&self) -> MirRef<'tcx> {
1244
        Ref::clone(&self.frame().mir)
S
Scott Olson 已提交
1245
    }
O
Oliver Schneider 已提交
1246

1247
    pub(super) fn substs(&self) -> &'tcx Substs<'tcx> {
O
Oliver Schneider 已提交
1248 1249
        self.frame().substs
    }
1250

O
rustup  
Oliver Schneider 已提交
1251 1252 1253 1254 1255 1256 1257 1258
    fn unsize_into_ptr(
        &mut self,
        src: Value,
        src_ty: Ty<'tcx>,
        dest: Lvalue<'tcx>,
        dest_ty: Ty<'tcx>,
        sty: Ty<'tcx>,
        dty: Ty<'tcx>,
1259
    ) -> EvalResult<'tcx> {
O
rustup  
Oliver Schneider 已提交
1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289
        // A<Struct> -> A<Trait> conversion
        let (src_pointee_ty, dest_pointee_ty) = self.tcx.struct_lockstep_tails(sty, dty);

        match (&src_pointee_ty.sty, &dest_pointee_ty.sty) {
            (&ty::TyArray(_, length), &ty::TySlice(_)) => {
                let ptr = src.read_ptr(&self.memory)?;
                let len = PrimVal::from_u128(length as u128);
                let ptr = PrimVal::Ptr(ptr);
                self.write_value(Value::ByValPair(ptr, len), dest, dest_ty)
            }
            (&ty::TyDynamic(..), &ty::TyDynamic(..)) => {
                // For now, upcasts are limited to changes in marker
                // traits, and hence never actually require an actual
                // change to the vtable.
                self.write_value(src, dest, dest_ty)
            },
            (_, &ty::TyDynamic(ref data, _)) => {
                let trait_ref = data.principal().unwrap().with_self_ty(self.tcx, src_pointee_ty);
                let trait_ref = self.tcx.erase_regions(&trait_ref);
                let vtable = self.get_vtable(trait_ref)?;
                let ptr = src.read_ptr(&self.memory)?;
                let ptr = PrimVal::Ptr(ptr);
                let extra = PrimVal::Ptr(vtable);
                self.write_value(Value::ByValPair(ptr, extra), dest, dest_ty)
            },

            _ => bug!("invalid unsizing {:?} -> {:?}", src_ty, dest_ty),
        }
    }

1290 1291 1292 1293
    fn unsize_into(
        &mut self,
        src: Value,
        src_ty: Ty<'tcx>,
1294
        dest: Lvalue<'tcx>,
1295
        dest_ty: Ty<'tcx>,
1296
    ) -> EvalResult<'tcx> {
1297
        match (&src_ty.sty, &dest_ty.sty) {
O
rustup  
Oliver Schneider 已提交
1298 1299 1300 1301 1302 1303 1304
            (&ty::TyRef(_, ref s), &ty::TyRef(_, ref d)) |
            (&ty::TyRef(_, ref s), &ty::TyRawPtr(ref d)) |
            (&ty::TyRawPtr(ref s), &ty::TyRawPtr(ref d)) => self.unsize_into_ptr(src, src_ty, dest, dest_ty, s.ty, d.ty),
            (&ty::TyAdt(def_a, substs_a), &ty::TyAdt(def_b, substs_b)) => {
                if def_a.is_box() || def_b.is_box() {
                    if !def_a.is_box() || !def_b.is_box() {
                        panic!("invalid unsizing between {:?} -> {:?}", src_ty, dest_ty);
1305
                    }
O
rustup  
Oliver Schneider 已提交
1306
                    return self.unsize_into_ptr(src, src_ty, dest, dest_ty, src_ty.boxed_ty(), dest_ty.boxed_ty());
1307
                }
1308 1309
                // FIXME(solson)
                let dest = self.force_allocation(dest)?.to_ptr();
1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322
                // unsizing of generic struct with pointer fields
                // Example: `Arc<T>` -> `Arc<Trait>`
                // here we need to increase the size of every &T thin ptr field to a fat ptr

                assert_eq!(def_a, def_b);

                let src_fields = def_a.variants[0].fields.iter();
                let dst_fields = def_b.variants[0].fields.iter();

                //let src = adt::MaybeSizedValue::sized(src);
                //let dst = adt::MaybeSizedValue::sized(dst);
                let src_ptr = match src {
                    Value::ByRef(ptr) => ptr,
O
Oliver Schneider 已提交
1323
                    _ => bug!("expected pointer, got {:?}", src),
1324 1325 1326 1327
                };

                let iter = src_fields.zip(dst_fields).enumerate();
                for (i, (src_f, dst_f)) in iter {
1328 1329
                    let src_fty = monomorphize_field_ty(self.tcx, src_f, substs_a);
                    let dst_fty = monomorphize_field_ty(self.tcx, dst_f, substs_b);
1330
                    if self.type_size(dst_fty)? == Some(0) {
1331 1332
                        continue;
                    }
1333 1334
                    let src_field_offset = self.get_field_offset(src_ty, i)?.bytes();
                    let dst_field_offset = self.get_field_offset(dest_ty, i)?.bytes();
1335 1336 1337
                    let src_f_ptr = src_ptr.offset(src_field_offset);
                    let dst_f_ptr = dest.offset(dst_field_offset);
                    if src_fty == dst_fty {
1338
                        self.copy(src_f_ptr, dst_f_ptr, src_fty)?;
1339
                    } else {
1340
                        self.unsize_into(Value::ByRef(src_f_ptr), src_fty, Lvalue::from_ptr(dst_f_ptr), dst_fty)?;
1341 1342
                    }
                }
O
rustup  
Oliver Schneider 已提交
1343
                Ok(())
1344
            }
1345
            _ => bug!("unsize_into: invalid conversion: {:?} -> {:?}", src_ty, dest_ty),
1346 1347
        }
    }
S
Scott Olson 已提交
1348

1349
    pub(super) fn dump_local(&self, lvalue: Lvalue<'tcx>) {
1350 1351
        let mut allocs = Vec::new();

1352
        if let Lvalue::Local { frame, local } = lvalue {
1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365
            match self.stack[frame].get_local(local) {
                Value::ByRef(ptr) => {
                    trace!("frame[{}] {:?}:", frame, local);
                    allocs.push(ptr.alloc_id);
                }
                Value::ByVal(val) => {
                    trace!("frame[{}] {:?}: {:?}", frame, local, val);
                    if let PrimVal::Ptr(ptr) = val { allocs.push(ptr.alloc_id); }
                }
                Value::ByValPair(val1, val2) => {
                    trace!("frame[{}] {:?}: ({:?}, {:?})", frame, local, val1, val2);
                    if let PrimVal::Ptr(ptr) = val1 { allocs.push(ptr.alloc_id); }
                    if let PrimVal::Ptr(ptr) = val2 { allocs.push(ptr.alloc_id); }
1366 1367 1368
                }
            }
        }
1369 1370

        self.memory.dump_allocs(allocs);
1371
    }
1372

1373
    /// Convenience function to ensure correct usage of globals and code-sharing with locals.
1374
    pub fn modify_global<F>(&mut self, cid: GlobalId<'tcx>, f: F) -> EvalResult<'tcx>
1375 1376
        where F: FnOnce(&mut Self, Value) -> EvalResult<'tcx, Value>,
    {
1377 1378 1379 1380
        let mut val = *self.globals.get(&cid).expect("global not cached");
        if !val.mutable {
            return Err(EvalError::ModifiedConstantMemory);
        }
1381
        val.value = f(self, val.value)?;
1382 1383 1384 1385
        *self.globals.get_mut(&cid).expect("already checked") = val;
        Ok(())
    }

1386 1387
    /// Convenience function to ensure correct usage of locals and code-sharing with globals.
    pub fn modify_local<F>(
1388 1389 1390 1391
        &mut self,
        frame: usize,
        local: mir::Local,
        f: F,
1392
    ) -> EvalResult<'tcx>
1393 1394
        where F: FnOnce(&mut Self, Value) -> EvalResult<'tcx, Value>,
    {
1395
        let val = self.stack[frame].get_local(local);
1396 1397 1398 1399 1400 1401
        let new_val = f(self, val)?;
        self.stack[frame].set_local(local, new_val);
        // FIXME(solson): Run this when setting to Undef? (See previous version of this code.)
        // if let Value::ByRef(ptr) = self.stack[frame].get_local(local) {
        //     self.memory.deallocate(ptr)?;
        // }
1402 1403
        Ok(())
    }
1404 1405
}

1406
impl<'tcx> Frame<'tcx> {
1407
    pub fn get_local(&self, local: mir::Local) -> Value {
1408 1409 1410 1411 1412 1413
        // Subtract 1 because we don't store a value for the ReturnPointer, the local with index 0.
        self.locals[local.index() - 1]
    }

    fn set_local(&mut self, local: mir::Local, value: Value) {
        // Subtract 1 because we don't store a value for the ReturnPointer, the local with index 0.
1414
        self.locals[local.index() - 1] = value;
1415 1416 1417
    }
}

1418 1419
pub fn eval_main<'a, 'tcx: 'a>(
    tcx: TyCtxt<'a, 'tcx, 'tcx>,
S
Scott Olson 已提交
1420
    def_id: DefId,
S
Scott Olson 已提交
1421
    limits: ResourceLimits,
1422
) {
S
Scott Olson 已提交
1423
    let mut ecx = EvalContext::new(tcx, limits);
1424
    let mir = ecx.load_mir(def_id).expect("main function's MIR not found");
1425

1426 1427 1428
    ecx.push_stack_frame(
        def_id,
        mir.span,
1429
        mir,
1430
        tcx.intern_substs(&[]),
S
Scott Olson 已提交
1431
        Lvalue::from_ptr(Pointer::zst_ptr()),
1432
        StackPopCleanup::None,
1433
        Vec::new(),
1434
    ).expect("could not allocate first stack frame");
1435

1436
    loop {
1437
        match ecx.step() {
1438
            Ok(true) => {}
O
Oliver Schneider 已提交
1439
            Ok(false) => return,
1440 1441
            Err(e) => {
                report(tcx, &ecx, e);
O
Oliver Schneider 已提交
1442
                return;
1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457
            }
        }
    }
}

fn report(tcx: TyCtxt, ecx: &EvalContext, e: EvalError) {
    let frame = ecx.stack().last().expect("stackframe was empty");
    let block = &frame.mir.basic_blocks()[frame.block];
    let span = if frame.stmt < block.statements.len() {
        block.statements[frame.stmt].source_info.span
    } else {
        block.terminator().source_info.span
    };
    let mut err = tcx.sess.struct_span_err(span, &e.to_string());
    for &Frame { def_id, substs, span, .. } in ecx.stack().iter().rev() {
1458 1459 1460 1461
        if tcx.def_key(def_id).disambiguated_data.data == DefPathData::ClosureExpr {
            err.span_note(span, "inside call to closure");
            continue;
        }
1462 1463 1464 1465
        // FIXME(solson): Find a way to do this without this Display impl hack.
        use rustc::util::ppaux;
        use std::fmt;
        struct Instance<'tcx>(DefId, &'tcx subst::Substs<'tcx>);
1466 1467
        impl<'tcx> ::std::panic::UnwindSafe for Instance<'tcx> {}
        impl<'tcx> ::std::panic::RefUnwindSafe for Instance<'tcx> {}
1468 1469
        impl<'tcx> fmt::Display for Instance<'tcx> {
            fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1470
                ppaux::parameterized(f, self.1, self.0, &[])
1471 1472
            }
        }
O
Oliver Schneider 已提交
1473
        err.span_note(span, &format!("inside call to {}", Instance(def_id, substs)));
1474 1475 1476
    }
    err.emit();
}
1477

1478
pub fn run_mir_passes<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
1479 1480 1481
    let mut passes = ::rustc::mir::transform::Passes::new();
    passes.push_hook(Box::new(::rustc_mir::transform::dump_mir::DumpMir));
    passes.push_pass(Box::new(::rustc_mir::transform::no_landing_pads::NoLandingPads));
S
Scott Olson 已提交
1482
    passes.push_pass(Box::new(::rustc_mir::transform::simplify::SimplifyCfg::new("no-landing-pads")));
1483

S
Scott Olson 已提交
1484
    // From here on out, regions are gone.
1485 1486
    passes.push_pass(Box::new(::rustc_mir::transform::erase_regions::EraseRegions));

S
Scott Olson 已提交
1487
    passes.push_pass(Box::new(::rustc_mir::transform::add_call_guards::AddCallGuards));
1488 1489
    passes.push_pass(Box::new(::rustc_borrowck::ElaborateDrops));
    passes.push_pass(Box::new(::rustc_mir::transform::no_landing_pads::NoLandingPads));
S
Scott Olson 已提交
1490
    passes.push_pass(Box::new(::rustc_mir::transform::simplify::SimplifyCfg::new("elaborate-drops")));
S
Scott Olson 已提交
1491 1492 1493 1494 1495 1496 1497 1498

    // No lifetime analysis based on borrowing can be done from here on out.
    passes.push_pass(Box::new(::rustc_mir::transform::instcombine::InstCombine::new()));
    passes.push_pass(Box::new(::rustc_mir::transform::deaggregator::Deaggregator));
    passes.push_pass(Box::new(::rustc_mir::transform::copy_prop::CopyPropagation));

    passes.push_pass(Box::new(::rustc_mir::transform::simplify::SimplifyLocals));
    passes.push_pass(Box::new(::rustc_mir::transform::add_call_guards::AddCallGuards));
1499 1500
    passes.push_pass(Box::new(::rustc_mir::transform::dump_mir::Marker("PreMiri")));

1501
    passes.run_passes(tcx);
1502 1503
}

1504 1505
// TODO(solson): Upstream these methods into rustc::ty::layout.

1506
pub(super) trait IntegerExt {
1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517
    fn size(self) -> Size;
}

impl IntegerExt for layout::Integer {
    fn size(self) -> Size {
        use rustc::ty::layout::Integer::*;
        match self {
            I1 | I8 => Size::from_bits(8),
            I16 => Size::from_bits(16),
            I32 => Size::from_bits(32),
            I64 => Size::from_bits(64),
O
Oliver Schneider 已提交
1518
            I128 => Size::from_bits(128),
1519 1520 1521
        }
    }
}
1522 1523


O
rustup  
Oliver Schneider 已提交
1524
pub fn monomorphize_field_ty<'a, 'tcx:'a >(tcx: TyCtxt<'a, 'tcx, 'tcx>, f: &ty::FieldDef, substs: &'tcx Substs<'tcx>) -> Ty<'tcx> {
S
Scott Olson 已提交
1525
    let substituted = f.ty(tcx, substs);
1526 1527
    tcx.normalize_associated_type(&substituted)
}
1528 1529 1530 1531

pub fn is_inhabited<'a, 'tcx: 'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>, ty: Ty<'tcx>) -> bool {
    ty.uninhabited_from(&mut FxHashSet::default(), tcx).is_empty()
}
1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549

pub trait IntoValTyPair<'tcx> {
    fn into_val_ty_pair<'a>(self, ecx: &mut EvalContext<'a, 'tcx>) -> EvalResult<'tcx, (Value, Ty<'tcx>)> where 'tcx: 'a;
}

impl<'tcx> IntoValTyPair<'tcx> for (Value, Ty<'tcx>) {
    fn into_val_ty_pair<'a>(self, _: &mut EvalContext<'a, 'tcx>) -> EvalResult<'tcx, (Value, Ty<'tcx>)> where 'tcx: 'a {
        Ok(self)
    }
}

impl<'b, 'tcx: 'b> IntoValTyPair<'tcx> for &'b mir::Operand<'tcx> {
    fn into_val_ty_pair<'a>(self, ecx: &mut EvalContext<'a, 'tcx>) -> EvalResult<'tcx, (Value, Ty<'tcx>)> where 'tcx: 'a {
        let value = ecx.eval_operand(self)?;
        let value_ty = ecx.operand_ty(self);
        Ok((value, value_ty))
    }
}