]> git.lizzy.rs Git - rust.git/blob - src/interpreter/mod.rs
bb3d15f9e182ff15d53db02eff4fe0fe2f7b2cce
[rust.git] / src / interpreter / mod.rs
1 use rustc::middle::const_val;
2 use rustc::hir::def_id::DefId;
3 use rustc::mir::mir_map::MirMap;
4 use rustc::mir::repr as mir;
5 use rustc::traits::{self, ProjectionMode};
6 use rustc::ty::fold::TypeFoldable;
7 use rustc::ty::layout::{self, Layout, Size};
8 use rustc::ty::subst::{self, Subst, Substs};
9 use rustc::ty::{self, Ty, TyCtxt};
10 use rustc::util::nodemap::DefIdMap;
11 use rustc_data_structures::indexed_vec::Idx;
12 use std::cell::RefCell;
13 use std::ops::Deref;
14 use std::rc::Rc;
15 use std::{iter, mem};
16 use syntax::ast;
17 use syntax::attr;
18 use syntax::codemap::{self, DUMMY_SP};
19
20 use error::{EvalError, EvalResult};
21 use memory::{Memory, Pointer};
22 use primval::{self, PrimVal};
23
24 use std::collections::HashMap;
25
26 mod stepper;
27
28 pub fn step<'ecx, 'a: 'ecx, 'tcx: 'a>(ecx: &'ecx mut EvalContext<'a, 'tcx>) -> EvalResult<bool> {
29     stepper::Stepper::new(ecx).step()
30 }
31
32 pub struct EvalContext<'a, 'tcx: 'a> {
33     /// The results of the type checker, from rustc.
34     tcx: TyCtxt<'a, 'tcx, 'tcx>,
35
36     /// A mapping from NodeIds to Mir, from rustc. Only contains MIR for crate-local items.
37     mir_map: &'a MirMap<'tcx>,
38
39     /// A local cache from DefIds to Mir for non-crate-local items.
40     mir_cache: RefCell<DefIdMap<Rc<mir::Mir<'tcx>>>>,
41
42     /// The virtual memory system.
43     memory: Memory,
44
45     /// Precomputed statics, constants and promoteds
46     statics: HashMap<ConstantId<'tcx>, Pointer>,
47
48     /// The virtual call stack.
49     stack: Vec<Frame<'a, 'tcx>>,
50 }
51
52 /// A stack frame.
53 pub struct Frame<'a, 'tcx: 'a> {
54     /// The def_id of the current function
55     pub def_id: DefId,
56
57     /// The span of the call site
58     pub span: codemap::Span,
59
60     /// type substitutions for the current function invocation
61     pub substs: &'tcx Substs<'tcx>,
62
63     /// The MIR for the function called on this frame.
64     pub mir: CachedMir<'a, 'tcx>,
65
66     /// The block that is currently executed (or will be executed after the above call stacks return)
67     pub next_block: mir::BasicBlock,
68
69     /// A pointer for writing the return value of the current call if it's not a diverging call.
70     pub return_ptr: Option<Pointer>,
71
72     /// The list of locals for the current function, stored in order as
73     /// `[arguments..., variables..., temporaries...]`. The variables begin at `self.var_offset`
74     /// and the temporaries at `self.temp_offset`.
75     pub locals: Vec<Pointer>,
76
77     /// The offset of the first variable in `self.locals`.
78     pub var_offset: usize,
79
80     /// The offset of the first temporary in `self.locals`.
81     pub temp_offset: usize,
82
83     /// The index of the currently evaluated statment
84     pub stmt: usize,
85 }
86
87 #[derive(Copy, Clone, Debug, Eq, PartialEq)]
88 struct Lvalue {
89     ptr: Pointer,
90     extra: LvalueExtra,
91 }
92
93 #[derive(Copy, Clone, Debug, Eq, PartialEq)]
94 enum LvalueExtra {
95     None,
96     Length(u64),
97     // TODO(solson): Vtable(memory::AllocId),
98     DowncastVariant(usize),
99 }
100
101 #[derive(Clone)]
102 pub enum CachedMir<'mir, 'tcx: 'mir> {
103     Ref(&'mir mir::Mir<'tcx>),
104     Owned(Rc<mir::Mir<'tcx>>)
105 }
106
107 #[derive(Clone, Debug, Eq, PartialEq, Hash)]
108 /// Uniquely identifies a specific constant or static
109 struct ConstantId<'tcx> {
110     /// the def id of the constant/static or in case of promoteds, the def id of the function they belong to
111     def_id: DefId,
112     /// In case of statics and constants this is `Substs::empty()`, so only promoteds and associated
113     /// constants actually have something useful here. We could special case statics and constants,
114     /// but that would only require more branching when working with constants, and not bring any
115     /// real benefits.
116     substs: &'tcx Substs<'tcx>,
117     kind: ConstantKind,
118 }
119
120 #[derive(Clone, Debug, Eq, PartialEq, Hash)]
121 enum ConstantKind {
122     Promoted(mir::Promoted),
123     /// Statics, constants and associated constants
124     Global,
125 }
126
127 impl<'a, 'tcx> EvalContext<'a, 'tcx> {
128     pub fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>, mir_map: &'a MirMap<'tcx>) -> Self {
129         EvalContext {
130             tcx: tcx,
131             mir_map: mir_map,
132             mir_cache: RefCell::new(DefIdMap()),
133             memory: Memory::new(tcx.sess
134                                    .target
135                                    .uint_type
136                                    .bit_width()
137                                    .expect("Session::target::uint_type was usize")/8),
138             statics: HashMap::new(),
139             stack: Vec::new(),
140         }
141     }
142
143     pub fn alloc_ret_ptr(&mut self, output_ty: ty::FnOutput<'tcx>, substs: &'tcx Substs<'tcx>) -> Option<Pointer> {
144         match output_ty {
145             ty::FnConverging(ty) => {
146                 let size = self.type_size_with_substs(ty, substs);
147                 Some(self.memory.allocate(size))
148             }
149             ty::FnDiverging => None,
150         }
151     }
152
153     pub fn memory(&self) -> &Memory {
154         &self.memory
155     }
156
157     pub fn stack(&self) -> &[Frame] {
158         &self.stack
159     }
160
161     // TODO(solson): Try making const_to_primval instead.
162     fn const_to_ptr(&mut self, const_val: &const_val::ConstVal) -> EvalResult<Pointer> {
163         use rustc::middle::const_val::ConstVal::*;
164         match *const_val {
165             Float(_f) => unimplemented!(),
166             Integral(int) => {
167                 // TODO(solson): Check int constant type.
168                 let ptr = self.memory.allocate(8);
169                 self.memory.write_uint(ptr, int.to_u64_unchecked(), 8)?;
170                 Ok(ptr)
171             }
172             Str(ref s) => {
173                 let psize = self.memory.pointer_size;
174                 let static_ptr = self.memory.allocate(s.len());
175                 let ptr = self.memory.allocate(psize * 2);
176                 self.memory.write_bytes(static_ptr, s.as_bytes())?;
177                 self.memory.write_ptr(ptr, static_ptr)?;
178                 self.memory.write_usize(ptr.offset(psize as isize), s.len() as u64)?;
179                 Ok(ptr)
180             }
181             ByteStr(ref bs) => {
182                 let psize = self.memory.pointer_size;
183                 let static_ptr = self.memory.allocate(bs.len());
184                 let ptr = self.memory.allocate(psize);
185                 self.memory.write_bytes(static_ptr, bs)?;
186                 self.memory.write_ptr(ptr, static_ptr)?;
187                 Ok(ptr)
188             }
189             Bool(b) => {
190                 let ptr = self.memory.allocate(1);
191                 self.memory.write_bool(ptr, b)?;
192                 Ok(ptr)
193             }
194             Char(_c)          => unimplemented!(),
195             Struct(_node_id)  => unimplemented!(),
196             Tuple(_node_id)   => unimplemented!(),
197             Function(_def_id) => unimplemented!(),
198             Array(_, _)       => unimplemented!(),
199             Repeat(_, _)      => unimplemented!(),
200             Dummy             => unimplemented!(),
201         }
202     }
203
204     fn type_needs_drop(&self, ty: Ty<'tcx>) -> bool {
205         self.tcx.type_needs_drop_given_env(ty, &self.tcx.empty_parameter_environment())
206     }
207
208     fn type_is_sized(&self, ty: Ty<'tcx>) -> bool {
209         ty.is_sized(self.tcx, &self.tcx.empty_parameter_environment(), DUMMY_SP)
210     }
211
212     fn fulfill_obligation(&self, trait_ref: ty::PolyTraitRef<'tcx>) -> traits::Vtable<'tcx, ()> {
213         // Do the initial selection for the obligation. This yields the shallow result we are
214         // looking for -- that is, what specific impl.
215         self.tcx.normalizing_infer_ctxt(ProjectionMode::Any).enter(|infcx| {
216             let mut selcx = traits::SelectionContext::new(&infcx);
217
218             let obligation = traits::Obligation::new(
219                 traits::ObligationCause::misc(DUMMY_SP, ast::DUMMY_NODE_ID),
220                 trait_ref.to_poly_trait_predicate(),
221             );
222             let selection = selcx.select(&obligation).unwrap().unwrap();
223
224             // Currently, we use a fulfillment context to completely resolve all nested obligations.
225             // This is because they can inform the inference of the impl's type parameters.
226             let mut fulfill_cx = traits::FulfillmentContext::new();
227             let vtable = selection.map(|predicate| {
228                 fulfill_cx.register_predicate_obligation(&infcx, predicate);
229             });
230             infcx.drain_fulfillment_cx_or_panic(DUMMY_SP, &mut fulfill_cx, &vtable)
231         })
232     }
233
234     /// Trait method, which has to be resolved to an impl method.
235     pub fn trait_method(
236         &self,
237         def_id: DefId,
238         substs: &'tcx Substs<'tcx>
239     ) -> (DefId, &'tcx Substs<'tcx>) {
240         let method_item = self.tcx.impl_or_trait_item(def_id);
241         let trait_id = method_item.container().id();
242         let trait_ref = ty::Binder(substs.to_trait_ref(self.tcx, trait_id));
243         match self.fulfill_obligation(trait_ref) {
244             traits::VtableImpl(vtable_impl) => {
245                 let impl_did = vtable_impl.impl_def_id;
246                 let mname = self.tcx.item_name(def_id);
247                 // Create a concatenated set of substitutions which includes those from the impl
248                 // and those from the method:
249                 let impl_substs = vtable_impl.substs.with_method_from(substs);
250                 let substs = self.tcx.mk_substs(impl_substs);
251                 let mth = get_impl_method(self.tcx, impl_did, substs, mname);
252
253                 (mth.method.def_id, mth.substs)
254             }
255
256             traits::VtableClosure(vtable_closure) =>
257                 (vtable_closure.closure_def_id, vtable_closure.substs.func_substs),
258
259             traits::VtableFnPointer(_fn_ty) => {
260                 let _trait_closure_kind = self.tcx.lang_items.fn_trait_kind(trait_id).unwrap();
261                 unimplemented!()
262                 // let llfn = trans_fn_pointer_shim(ccx, trait_closure_kind, fn_ty);
263
264                 // let method_ty = def_ty(tcx, def_id, substs);
265                 // let fn_ptr_ty = match method_ty.sty {
266                 //     ty::TyFnDef(_, _, fty) => tcx.mk_ty(ty::TyFnPtr(fty)),
267                 //     _ => unreachable!("expected fn item type, found {}",
268                 //                       method_ty)
269                 // };
270                 // Callee::ptr(immediate_rvalue(llfn, fn_ptr_ty))
271             }
272
273             traits::VtableObject(ref _data) => {
274                 unimplemented!()
275                 // Callee {
276                 //     data: Virtual(traits::get_vtable_index_of_object_method(
277                 //                   tcx, data, def_id)),
278                 //                   ty: def_ty(tcx, def_id, substs)
279                 // }
280             }
281             vtable => unreachable!("resolved vtable bad vtable {:?} in trans", vtable),
282         }
283     }
284
285     fn load_mir(&self, def_id: DefId) -> CachedMir<'a, 'tcx> {
286         match self.tcx.map.as_local_node_id(def_id) {
287             Some(node_id) => CachedMir::Ref(self.mir_map.map.get(&node_id).unwrap()),
288             None => {
289                 let mut mir_cache = self.mir_cache.borrow_mut();
290                 if let Some(mir) = mir_cache.get(&def_id) {
291                     return CachedMir::Owned(mir.clone());
292                 }
293
294                 let cs = &self.tcx.sess.cstore;
295                 let mir = cs.maybe_get_item_mir(self.tcx, def_id).unwrap_or_else(|| {
296                     panic!("no mir for {:?}", def_id);
297                 });
298                 let cached = Rc::new(mir);
299                 mir_cache.insert(def_id, cached.clone());
300                 CachedMir::Owned(cached)
301             }
302         }
303     }
304
305     fn monomorphize(&self, ty: Ty<'tcx>, substs: &'tcx Substs<'tcx>) -> Ty<'tcx> {
306         let substituted = ty.subst(self.tcx, substs);
307         self.tcx.normalize_associated_type(&substituted)
308     }
309
310     fn type_size(&self, ty: Ty<'tcx>) -> usize {
311         self.type_size_with_substs(ty, self.substs())
312     }
313
314     fn type_size_with_substs(&self, ty: Ty<'tcx>, substs: &'tcx Substs<'tcx>) -> usize {
315         self.type_layout_with_substs(ty, substs).size(&self.tcx.data_layout).bytes() as usize
316     }
317
318     fn type_layout(&self, ty: Ty<'tcx>) -> &'tcx Layout {
319         self.type_layout_with_substs(ty, self.substs())
320     }
321
322     fn type_layout_with_substs(&self, ty: Ty<'tcx>, substs: &'tcx Substs<'tcx>) -> &'tcx Layout {
323         // TODO(solson): Is this inefficient? Needs investigation.
324         let ty = self.monomorphize(ty, substs);
325
326         self.tcx.normalizing_infer_ctxt(ProjectionMode::Any).enter(|infcx| {
327             // TODO(solson): Report this error properly.
328             ty.layout(&infcx).unwrap()
329         })
330     }
331
332     pub fn push_stack_frame(&mut self, def_id: DefId, span: codemap::Span, mir: CachedMir<'a, 'tcx>, substs: &'tcx Substs<'tcx>,
333         return_ptr: Option<Pointer>)
334     {
335         let arg_tys = mir.arg_decls.iter().map(|a| a.ty);
336         let var_tys = mir.var_decls.iter().map(|v| v.ty);
337         let temp_tys = mir.temp_decls.iter().map(|t| t.ty);
338
339         let num_args = mir.arg_decls.len();
340         let num_vars = mir.var_decls.len();
341
342         ::log_settings::settings().indentation += 1;
343
344         let locals: Vec<Pointer> = arg_tys.chain(var_tys).chain(temp_tys).map(|ty| {
345             let size = self.type_size_with_substs(ty, substs);
346             self.memory.allocate(size)
347         }).collect();
348
349         self.stack.push(Frame {
350             mir: mir.clone(),
351             next_block: mir::START_BLOCK,
352             return_ptr: return_ptr,
353             locals: locals,
354             var_offset: num_args,
355             temp_offset: num_args + num_vars,
356             span: span,
357             def_id: def_id,
358             substs: substs,
359             stmt: 0,
360         });
361     }
362
363     fn pop_stack_frame(&mut self) {
364         ::log_settings::settings().indentation -= 1;
365         let _frame = self.stack.pop().expect("tried to pop a stack frame, but there were none");
366         // TODO(solson): Deallocate local variables.
367     }
368
369     fn eval_terminator(&mut self, terminator: &mir::Terminator<'tcx>)
370             -> EvalResult<()> {
371         use rustc::mir::repr::TerminatorKind::*;
372         match terminator.kind {
373             Return => self.pop_stack_frame(),
374
375             Goto { target } => {
376                 self.frame_mut().next_block = target;
377             },
378
379             If { ref cond, targets: (then_target, else_target) } => {
380                 let cond_ptr = self.eval_operand(cond)?;
381                 let cond_val = self.memory.read_bool(cond_ptr)?;
382                 self.frame_mut().next_block = if cond_val { then_target } else { else_target };
383             }
384
385             SwitchInt { ref discr, ref values, ref targets, .. } => {
386                 let discr_ptr = self.eval_lvalue(discr)?.to_ptr();
387                 let discr_size = self
388                     .type_layout(self.lvalue_ty(discr))
389                     .size(&self.tcx.data_layout)
390                     .bytes() as usize;
391                 let discr_val = self.memory.read_uint(discr_ptr, discr_size)?;
392
393                 // Branch to the `otherwise` case by default, if no match is found.
394                 let mut target_block = targets[targets.len() - 1];
395
396                 for (index, val_const) in values.iter().enumerate() {
397                     let ptr = self.const_to_ptr(val_const)?;
398                     let val = self.memory.read_uint(ptr, discr_size)?;
399                     if discr_val == val {
400                         target_block = targets[index];
401                         break;
402                     }
403                 }
404
405                 self.frame_mut().next_block = target_block;
406             }
407
408             Switch { ref discr, ref targets, adt_def } => {
409                 let adt_ptr = self.eval_lvalue(discr)?.to_ptr();
410                 let adt_ty = self.lvalue_ty(discr);
411                 let discr_val = self.read_discriminant_value(adt_ptr, adt_ty)?;
412                 let matching = adt_def.variants.iter()
413                     .position(|v| discr_val == v.disr_val.to_u64_unchecked());
414
415                 match matching {
416                     Some(i) => {
417                         self.frame_mut().next_block = targets[i];
418                     },
419                     None => return Err(EvalError::InvalidDiscriminant),
420                 }
421             }
422
423             Call { ref func, ref args, ref destination, .. } => {
424                 let mut return_ptr = None;
425                 if let Some((ref lv, target)) = *destination {
426                     self.frame_mut().next_block = target;
427                     return_ptr = Some(self.eval_lvalue(lv)?.to_ptr());
428                 }
429
430                 let func_ty = self.operand_ty(func);
431                 match func_ty.sty {
432                     ty::TyFnDef(def_id, substs, fn_ty) => {
433                         use syntax::abi::Abi;
434                         match fn_ty.abi {
435                             Abi::RustIntrinsic => {
436                                 let name = self.tcx.item_name(def_id).as_str();
437                                 match fn_ty.sig.0.output {
438                                     ty::FnConverging(ty) => {
439                                         let size = self.type_size(ty);
440                                         let ret = return_ptr.unwrap();
441                                         self.call_intrinsic(&name, substs, args, ret, size)?
442                                     }
443                                     ty::FnDiverging => unimplemented!(),
444                                 }
445                             }
446
447                             Abi::C => {
448                                 match fn_ty.sig.0.output {
449                                     ty::FnConverging(ty) => {
450                                         let size = self.type_size(ty);
451                                         self.call_c_abi(def_id, args, return_ptr.unwrap(), size)?
452                                     }
453                                     ty::FnDiverging => unimplemented!(),
454                                 }
455                             }
456
457                             Abi::Rust | Abi::RustCall => {
458                                 // TODO(solson): Adjust the first argument when calling a Fn or
459                                 // FnMut closure via FnOnce::call_once.
460
461                                 // Only trait methods can have a Self parameter.
462                                 let (resolved_def_id, resolved_substs) = if substs.self_ty().is_some() {
463                                     self.trait_method(def_id, substs)
464                                 } else {
465                                     (def_id, substs)
466                                 };
467
468                                 let mut arg_srcs = Vec::new();
469                                 for arg in args {
470                                     let src = self.eval_operand(arg)?;
471                                     let src_ty = self.operand_ty(arg);
472                                     arg_srcs.push((src, src_ty));
473                                 }
474
475                                 if fn_ty.abi == Abi::RustCall && !args.is_empty() {
476                                     arg_srcs.pop();
477                                     let last_arg = args.last().unwrap();
478                                     let last = self.eval_operand(last_arg)?;
479                                     let last_ty = self.operand_ty(last_arg);
480                                     let last_layout = self.type_layout(last_ty);
481                                     match (&last_ty.sty, last_layout) {
482                                         (&ty::TyTuple(fields),
483                                          &Layout::Univariant { ref variant, .. }) => {
484                                             let offsets = iter::once(0)
485                                                 .chain(variant.offset_after_field.iter()
486                                                     .map(|s| s.bytes()));
487                                             for (offset, ty) in offsets.zip(fields) {
488                                                 let src = last.offset(offset as isize);
489                                                 arg_srcs.push((src, ty));
490                                             }
491                                         }
492                                         ty => panic!("expected tuple as last argument in function with 'rust-call' ABI, got {:?}", ty),
493                                     }
494                                 }
495
496                                 let mir = self.load_mir(resolved_def_id);
497                                 self.push_stack_frame(
498                                     def_id, terminator.source_info.span, mir, resolved_substs,
499                                     return_ptr
500                                 );
501
502                                 for (i, (src, src_ty)) in arg_srcs.into_iter().enumerate() {
503                                     let dest = self.frame().locals[i];
504                                     self.move_(src, dest, src_ty)?;
505                                 }
506                             }
507
508                             abi => return Err(EvalError::Unimplemented(format!("can't handle function with {:?} ABI", abi))),
509                         }
510                     }
511
512                     _ => return Err(EvalError::Unimplemented(format!("can't handle callee of type {:?}", func_ty))),
513                 }
514             }
515
516             Drop { ref location, target, .. } => {
517                 let ptr = self.eval_lvalue(location)?.to_ptr();
518                 let ty = self.lvalue_ty(location);
519                 self.drop(ptr, ty)?;
520                 self.frame_mut().next_block = target;
521             }
522
523             Assert { ref cond, expected, ref msg, target, cleanup } => {
524                 let actual_ptr = self.eval_operand(cond)?;
525                 let actual = self.memory.read_bool(actual_ptr)?;
526                 if actual == expected {
527                     self.frame_mut().next_block = target;
528                 } else {
529                     panic!("unimplemented: jump to {:?} and print {:?}", cleanup, msg);
530                 }
531             }
532
533             DropAndReplace { .. } => unimplemented!(),
534             Resume => unimplemented!(),
535             Unreachable => unimplemented!(),
536         }
537
538         Ok(())
539     }
540
541     fn drop(&mut self, ptr: Pointer, ty: Ty<'tcx>) -> EvalResult<()> {
542         if !self.type_needs_drop(ty) {
543             debug!("no need to drop {:?}", ty);
544             return Ok(());
545         }
546         trace!("-need to drop {:?}", ty);
547
548         // TODO(solson): Call user-defined Drop::drop impls.
549
550         match ty.sty {
551             ty::TyBox(contents_ty) => {
552                 match self.memory.read_ptr(ptr) {
553                     Ok(contents_ptr) => {
554                         self.drop(contents_ptr, contents_ty)?;
555                         trace!("-deallocating box");
556                         self.memory.deallocate(contents_ptr)?;
557                     }
558                     Err(EvalError::ReadBytesAsPointer) => {
559                         let size = self.memory.pointer_size;
560                         let possible_drop_fill = self.memory.read_bytes(ptr, size)?;
561                         if possible_drop_fill.iter().all(|&b| b == mem::POST_DROP_U8) {
562                             return Ok(());
563                         } else {
564                             return Err(EvalError::ReadBytesAsPointer);
565                         }
566                     }
567                     Err(e) => return Err(e),
568                 }
569             }
570
571             // TODO(solson): Implement drop for other relevant types (e.g. aggregates).
572             _ => {}
573         }
574
575         // Filling drop.
576         // FIXME(solson): Trait objects (with no static size) probably get filled, too.
577         let size = self.type_size(ty);
578         self.memory.drop_fill(ptr, size)?;
579
580         Ok(())
581     }
582
583     fn read_discriminant_value(&self, adt_ptr: Pointer, adt_ty: Ty<'tcx>) -> EvalResult<u64> {
584         use rustc::ty::layout::Layout::*;
585         let adt_layout = self.type_layout(adt_ty);
586
587         let discr_val = match *adt_layout {
588             General { discr, .. } | CEnum { discr, .. } => {
589                 let discr_size = discr.size().bytes();
590                 self.memory.read_uint(adt_ptr, discr_size as usize)?
591             }
592
593             RawNullablePointer { nndiscr, .. } => {
594                 self.read_nonnull_discriminant_value(adt_ptr, nndiscr)?
595             }
596
597             StructWrappedNullablePointer { nndiscr, ref discrfield, .. } => {
598                 let offset = self.nonnull_offset(adt_ty, nndiscr, discrfield)?;
599                 let nonnull = adt_ptr.offset(offset.bytes() as isize);
600                 self.read_nonnull_discriminant_value(nonnull, nndiscr)?
601             }
602
603             // The discriminant_value intrinsic returns 0 for non-sum types.
604             Array { .. } | FatPointer { .. } | Scalar { .. } | Univariant { .. } |
605             Vector { .. } => 0,
606         };
607
608         Ok(discr_val)
609     }
610
611     fn read_nonnull_discriminant_value(&self, ptr: Pointer, nndiscr: u64) -> EvalResult<u64> {
612         let not_null = match self.memory.read_usize(ptr) {
613             Ok(0) => false,
614             Ok(_) | Err(EvalError::ReadPointerAsBytes) => true,
615             Err(e) => return Err(e),
616         };
617         assert!(nndiscr == 0 || nndiscr == 1);
618         Ok(if not_null { nndiscr } else { 1 - nndiscr })
619     }
620
621     fn call_intrinsic(
622         &mut self,
623         name: &str,
624         substs: &'tcx Substs<'tcx>,
625         args: &[mir::Operand<'tcx>],
626         dest: Pointer,
627         dest_size: usize
628     ) -> EvalResult<()> {
629         let args_res: EvalResult<Vec<Pointer>> = args.iter()
630             .map(|arg| self.eval_operand(arg))
631             .collect();
632         let args = args_res?;
633
634         match name {
635             // FIXME(solson): Handle different integer types correctly.
636             "add_with_overflow" => {
637                 let ty = *substs.types.get(subst::FnSpace, 0);
638                 let size = self.type_size(ty);
639                 let left = self.memory.read_int(args[0], size)?;
640                 let right = self.memory.read_int(args[1], size)?;
641                 let (n, overflowed) = unsafe {
642                     ::std::intrinsics::add_with_overflow::<i64>(left, right)
643                 };
644                 self.memory.write_int(dest, n, size)?;
645                 self.memory.write_bool(dest.offset(size as isize), overflowed)?;
646             }
647
648             "assume" => {}
649
650             "copy_nonoverlapping" => {
651                 let elem_ty = *substs.types.get(subst::FnSpace, 0);
652                 let elem_size = self.type_size(elem_ty);
653                 let src = self.memory.read_ptr(args[0])?;
654                 let dest = self.memory.read_ptr(args[1])?;
655                 let count = self.memory.read_isize(args[2])?;
656                 self.memory.copy(src, dest, count as usize * elem_size)?;
657             }
658
659             "discriminant_value" => {
660                 let ty = *substs.types.get(subst::FnSpace, 0);
661                 let adt_ptr = self.memory.read_ptr(args[0])?;
662                 let discr_val = self.read_discriminant_value(adt_ptr, ty)?;
663                 self.memory.write_uint(dest, discr_val, dest_size)?;
664             }
665
666             "forget" => {
667                 let arg_ty = *substs.types.get(subst::FnSpace, 0);
668                 let arg_size = self.type_size(arg_ty);
669                 self.memory.drop_fill(args[0], arg_size)?;
670             }
671
672             "init" => self.memory.write_repeat(dest, 0, dest_size)?,
673
674             "min_align_of" => {
675                 self.memory.write_int(dest, 1, dest_size)?;
676             }
677
678             "move_val_init" => {
679                 let ty = *substs.types.get(subst::FnSpace, 0);
680                 let ptr = self.memory.read_ptr(args[0])?;
681                 self.move_(args[1], ptr, ty)?;
682             }
683
684             // FIXME(solson): Handle different integer types correctly.
685             "mul_with_overflow" => {
686                 let ty = *substs.types.get(subst::FnSpace, 0);
687                 let size = self.type_size(ty);
688                 let left = self.memory.read_int(args[0], size)?;
689                 let right = self.memory.read_int(args[1], size)?;
690                 let (n, overflowed) = unsafe {
691                     ::std::intrinsics::mul_with_overflow::<i64>(left, right)
692                 };
693                 self.memory.write_int(dest, n, size)?;
694                 self.memory.write_bool(dest.offset(size as isize), overflowed)?;
695             }
696
697             "offset" => {
698                 let pointee_ty = *substs.types.get(subst::FnSpace, 0);
699                 let pointee_size = self.type_size(pointee_ty) as isize;
700                 let ptr_arg = args[0];
701                 let offset = self.memory.read_isize(args[1])?;
702
703                 match self.memory.read_ptr(ptr_arg) {
704                     Ok(ptr) => {
705                         let result_ptr = ptr.offset(offset as isize * pointee_size);
706                         self.memory.write_ptr(dest, result_ptr)?;
707                     }
708                     Err(EvalError::ReadBytesAsPointer) => {
709                         let addr = self.memory.read_isize(ptr_arg)?;
710                         let result_addr = addr + offset * pointee_size as i64;
711                         self.memory.write_isize(dest, result_addr)?;
712                     }
713                     Err(e) => return Err(e),
714                 }
715             }
716
717             // FIXME(solson): Handle different integer types correctly. Use primvals?
718             "overflowing_sub" => {
719                 let ty = *substs.types.get(subst::FnSpace, 0);
720                 let size = self.type_size(ty);
721                 let left = self.memory.read_int(args[0], size)?;
722                 let right = self.memory.read_int(args[1], size)?;
723                 let n = left.wrapping_sub(right);
724                 self.memory.write_int(dest, n, size)?;
725             }
726
727             "size_of" => {
728                 let ty = *substs.types.get(subst::FnSpace, 0);
729                 let size = self.type_size(ty) as u64;
730                 self.memory.write_uint(dest, size, dest_size)?;
731             }
732
733             "size_of_val" => {
734                 let ty = *substs.types.get(subst::FnSpace, 0);
735                 if self.type_is_sized(ty) {
736                     let size = self.type_size(ty) as u64;
737                     self.memory.write_uint(dest, size, dest_size)?;
738                 } else {
739                     match ty.sty {
740                         ty::TySlice(_) | ty::TyStr => {
741                             let elem_ty = ty.sequence_element_type(self.tcx);
742                             let elem_size = self.type_size(elem_ty) as u64;
743                             let ptr_size = self.memory.pointer_size as isize;
744                             let n = self.memory.read_usize(args[0].offset(ptr_size))?;
745                             self.memory.write_uint(dest, n * elem_size, dest_size)?;
746                         }
747
748                         _ => return Err(EvalError::Unimplemented(format!("unimplemented: size_of_val::<{:?}>", ty))),
749                     }
750                 }
751             }
752
753             "transmute" => {
754                 let ty = *substs.types.get(subst::FnSpace, 0);
755                 self.move_(args[0], dest, ty)?;
756             }
757             "uninit" => self.memory.mark_definedness(dest, dest_size, false)?,
758
759             name => return Err(EvalError::Unimplemented(format!("unimplemented intrinsic: {}", name))),
760         }
761
762         // Since we pushed no stack frame, the main loop will act
763         // as if the call just completed and it's returning to the
764         // current frame.
765         Ok(())
766     }
767
768     fn call_c_abi(
769         &mut self,
770         def_id: DefId,
771         args: &[mir::Operand<'tcx>],
772         dest: Pointer,
773         dest_size: usize,
774     ) -> EvalResult<()> {
775         let name = self.tcx.item_name(def_id);
776         let attrs = self.tcx.get_attrs(def_id);
777         let link_name = match attr::first_attr_value_str_by_name(&attrs, "link_name") {
778             Some(ln) => ln.clone(),
779             None => name.as_str(),
780         };
781
782         let args_res: EvalResult<Vec<Pointer>> = args.iter()
783             .map(|arg| self.eval_operand(arg))
784             .collect();
785         let args = args_res?;
786
787         match &link_name[..] {
788             "__rust_allocate" => {
789                 let size = self.memory.read_usize(args[0])?;
790                 let ptr = self.memory.allocate(size as usize);
791                 self.memory.write_ptr(dest, ptr)?;
792             }
793
794             "__rust_reallocate" => {
795                 let ptr = self.memory.read_ptr(args[0])?;
796                 let size = self.memory.read_usize(args[2])?;
797                 self.memory.reallocate(ptr, size as usize)?;
798                 self.memory.write_ptr(dest, ptr)?;
799             }
800
801             "memcmp" => {
802                 let left = self.memory.read_ptr(args[0])?;
803                 let right = self.memory.read_ptr(args[1])?;
804                 let n = self.memory.read_usize(args[2])? as usize;
805
806                 let result = {
807                     let left_bytes = self.memory.read_bytes(left, n)?;
808                     let right_bytes = self.memory.read_bytes(right, n)?;
809
810                     use std::cmp::Ordering::*;
811                     match left_bytes.cmp(right_bytes) {
812                         Less => -1,
813                         Equal => 0,
814                         Greater => 1,
815                     }
816                 };
817
818                 self.memory.write_int(dest, result, dest_size)?;
819             }
820
821             _ => {
822                 return Err(EvalError::Unimplemented(format!("can't call C ABI function: {}", link_name)));
823             }
824         }
825
826         // Since we pushed no stack frame, the main loop will act
827         // as if the call just completed and it's returning to the
828         // current frame.
829         Ok(())
830     }
831
832     fn assign_fields<I: IntoIterator<Item = u64>>(
833         &mut self,
834         dest: Pointer,
835         offsets: I,
836         operands: &[mir::Operand<'tcx>],
837     ) -> EvalResult<()> {
838         for (offset, operand) in offsets.into_iter().zip(operands) {
839             let src = self.eval_operand(operand)?;
840             let src_ty = self.operand_ty(operand);
841             let field_dest = dest.offset(offset as isize);
842             self.move_(src, field_dest, src_ty)?;
843         }
844         Ok(())
845     }
846
847     fn eval_assignment(&mut self, lvalue: &mir::Lvalue<'tcx>, rvalue: &mir::Rvalue<'tcx>)
848         -> EvalResult<()>
849     {
850         let dest = self.eval_lvalue(lvalue)?.to_ptr();
851         let dest_ty = self.lvalue_ty(lvalue);
852         let dest_layout = self.type_layout(dest_ty);
853
854         use rustc::mir::repr::Rvalue::*;
855         match *rvalue {
856             Use(ref operand) => {
857                 let src = self.eval_operand(operand)?;
858                 self.move_(src, dest, dest_ty)?;
859             }
860
861             BinaryOp(bin_op, ref left, ref right) => {
862                 let left_ptr = self.eval_operand(left)?;
863                 let left_ty = self.operand_ty(left);
864                 let left_val = self.read_primval(left_ptr, left_ty)?;
865
866                 let right_ptr = self.eval_operand(right)?;
867                 let right_ty = self.operand_ty(right);
868                 let right_val = self.read_primval(right_ptr, right_ty)?;
869
870                 let val = primval::binary_op(bin_op, left_val, right_val)?;
871                 self.memory.write_primval(dest, val)?;
872             }
873
874             // FIXME(solson): Factor this out with BinaryOp.
875             CheckedBinaryOp(bin_op, ref left, ref right) => {
876                 let left_ptr = self.eval_operand(left)?;
877                 let left_ty = self.operand_ty(left);
878                 let left_val = self.read_primval(left_ptr, left_ty)?;
879
880                 let right_ptr = self.eval_operand(right)?;
881                 let right_ty = self.operand_ty(right);
882                 let right_val = self.read_primval(right_ptr, right_ty)?;
883
884                 let val = primval::binary_op(bin_op, left_val, right_val)?;
885                 self.memory.write_primval(dest, val)?;
886
887                 // FIXME(solson): Find the result type size properly. Perhaps refactor out
888                 // Projection calculations so we can do the equivalent of `dest.1` here.
889                 let s = self.type_size(left_ty);
890                 self.memory.write_bool(dest.offset(s as isize), false)?;
891             }
892
893             UnaryOp(un_op, ref operand) => {
894                 let ptr = self.eval_operand(operand)?;
895                 let ty = self.operand_ty(operand);
896                 let val = self.read_primval(ptr, ty)?;
897                 self.memory.write_primval(dest, primval::unary_op(un_op, val)?)?;
898             }
899
900             Aggregate(ref kind, ref operands) => {
901                 use rustc::ty::layout::Layout::*;
902                 match *dest_layout {
903                     Univariant { ref variant, .. } => {
904                         let offsets = iter::once(0)
905                             .chain(variant.offset_after_field.iter().map(|s| s.bytes()));
906                         self.assign_fields(dest, offsets, operands)?;
907                     }
908
909                     Array { .. } => {
910                         let elem_size = match dest_ty.sty {
911                             ty::TyArray(elem_ty, _) => self.type_size(elem_ty) as u64,
912                             _ => panic!("tried to assign {:?} to non-array type {:?}",
913                                         kind, dest_ty),
914                         };
915                         let offsets = (0..).map(|i| i * elem_size);
916                         self.assign_fields(dest, offsets, operands)?;
917                     }
918
919                     General { discr, ref variants, .. } => {
920                         if let mir::AggregateKind::Adt(adt_def, variant, _) = *kind {
921                             let discr_val = adt_def.variants[variant].disr_val.to_u64_unchecked();
922                             let discr_size = discr.size().bytes() as usize;
923                             self.memory.write_uint(dest, discr_val, discr_size)?;
924
925                             let offsets = variants[variant].offset_after_field.iter()
926                                 .map(|s| s.bytes());
927                             self.assign_fields(dest, offsets, operands)?;
928                         } else {
929                             panic!("tried to assign {:?} to Layout::General", kind);
930                         }
931                     }
932
933                     RawNullablePointer { nndiscr, .. } => {
934                         if let mir::AggregateKind::Adt(_, variant, _) = *kind {
935                             if nndiscr == variant as u64 {
936                                 assert_eq!(operands.len(), 1);
937                                 let operand = &operands[0];
938                                 let src = self.eval_operand(operand)?;
939                                 let src_ty = self.operand_ty(operand);
940                                 self.move_(src, dest, src_ty)?;
941                             } else {
942                                 assert_eq!(operands.len(), 0);
943                                 self.memory.write_isize(dest, 0)?;
944                             }
945                         } else {
946                             panic!("tried to assign {:?} to Layout::RawNullablePointer", kind);
947                         }
948                     }
949
950                     StructWrappedNullablePointer { nndiscr, ref nonnull, ref discrfield } => {
951                         if let mir::AggregateKind::Adt(_, variant, _) = *kind {
952                             if nndiscr == variant as u64 {
953                                 let offsets = iter::once(0)
954                                     .chain(nonnull.offset_after_field.iter().map(|s| s.bytes()));
955                                 try!(self.assign_fields(dest, offsets, operands));
956                             } else {
957                                 assert_eq!(operands.len(), 0);
958                                 let offset = self.nonnull_offset(dest_ty, nndiscr, discrfield)?;
959                                 let dest = dest.offset(offset.bytes() as isize);
960                                 try!(self.memory.write_isize(dest, 0));
961                             }
962                         } else {
963                             panic!("tried to assign {:?} to Layout::RawNullablePointer", kind);
964                         }
965                     }
966
967                     CEnum { discr, signed, .. } => {
968                         assert_eq!(operands.len(), 0);
969                         if let mir::AggregateKind::Adt(adt_def, variant, _) = *kind {
970                             let val = adt_def.variants[variant].disr_val.to_u64_unchecked();
971                             let size = discr.size().bytes() as usize;
972
973                             if signed {
974                                 self.memory.write_int(dest, val as i64, size)?;
975                             } else {
976                                 self.memory.write_uint(dest, val, size)?;
977                             }
978                         } else {
979                             panic!("tried to assign {:?} to Layout::CEnum", kind);
980                         }
981                     }
982
983                     _ => return Err(EvalError::Unimplemented(format!("can't handle destination layout {:?} when assigning {:?}", dest_layout, kind))),
984                 }
985             }
986
987             Repeat(ref operand, _) => {
988                 let (elem_size, length) = match dest_ty.sty {
989                     ty::TyArray(elem_ty, n) => (self.type_size(elem_ty), n),
990                     _ => panic!("tried to assign array-repeat to non-array type {:?}", dest_ty),
991                 };
992
993                 let src = self.eval_operand(operand)?;
994                 for i in 0..length {
995                     let elem_dest = dest.offset((i * elem_size) as isize);
996                     self.memory.copy(src, elem_dest, elem_size)?;
997                 }
998             }
999
1000             Len(ref lvalue) => {
1001                 let src = self.eval_lvalue(lvalue)?;
1002                 let ty = self.lvalue_ty(lvalue);
1003                 let len = match ty.sty {
1004                     ty::TyArray(_, n) => n as u64,
1005                     ty::TySlice(_) => if let LvalueExtra::Length(n) = src.extra {
1006                         n
1007                     } else {
1008                         panic!("Rvalue::Len of a slice given non-slice pointer: {:?}", src);
1009                     },
1010                     _ => panic!("Rvalue::Len expected array or slice, got {:?}", ty),
1011                 };
1012                 self.memory.write_usize(dest, len)?;
1013             }
1014
1015             Ref(_, _, ref lvalue) => {
1016                 let lv = self.eval_lvalue(lvalue)?;
1017                 self.memory.write_ptr(dest, lv.ptr)?;
1018                 match lv.extra {
1019                     LvalueExtra::None => {},
1020                     LvalueExtra::Length(len) => {
1021                         let len_ptr = dest.offset(self.memory.pointer_size as isize);
1022                         self.memory.write_usize(len_ptr, len)?;
1023                     }
1024                     LvalueExtra::DowncastVariant(..) =>
1025                         panic!("attempted to take a reference to an enum downcast lvalue"),
1026                 }
1027             }
1028
1029             Box(ty) => {
1030                 let size = self.type_size(ty);
1031                 let ptr = self.memory.allocate(size);
1032                 self.memory.write_ptr(dest, ptr)?;
1033             }
1034
1035             Cast(kind, ref operand, dest_ty) => {
1036                 let src = self.eval_operand(operand)?;
1037                 let src_ty = self.operand_ty(operand);
1038
1039                 use rustc::mir::repr::CastKind::*;
1040                 match kind {
1041                     Unsize => {
1042                         self.move_(src, dest, src_ty)?;
1043                         let src_pointee_ty = pointee_type(src_ty).unwrap();
1044                         let dest_pointee_ty = pointee_type(dest_ty).unwrap();
1045
1046                         match (&src_pointee_ty.sty, &dest_pointee_ty.sty) {
1047                             (&ty::TyArray(_, length), &ty::TySlice(_)) => {
1048                                 let len_ptr = dest.offset(self.memory.pointer_size as isize);
1049                                 self.memory.write_usize(len_ptr, length as u64)?;
1050                             }
1051
1052                             _ => return Err(EvalError::Unimplemented(format!("can't handle cast: {:?}", rvalue))),
1053                         }
1054                     }
1055
1056                     Misc => {
1057                         // FIXME(solson): Wrong for almost everything.
1058                         let dest_size = self.type_size(dest_ty);
1059                         let src_size = self.type_size(src_ty);
1060                         if dest_size == src_size {
1061                             warn!("performing fishy cast from {:?} to {:?}", src_ty, dest_ty);
1062                             self.memory.copy(src, dest, dest_size)?;
1063                         } else {
1064                             return Err(EvalError::Unimplemented(format!("can't handle cast: {:?}", rvalue)));
1065                         }
1066                     }
1067
1068                     _ => return Err(EvalError::Unimplemented(format!("can't handle cast: {:?}", rvalue))),
1069                 }
1070             }
1071
1072             InlineAsm { .. } => unimplemented!(),
1073         }
1074
1075         Ok(())
1076     }
1077
1078     fn nonnull_offset(&self, ty: Ty<'tcx>, nndiscr: u64, discrfield: &[u32]) -> EvalResult<Size> {
1079         // Skip the constant 0 at the start meant for LLVM GEP.
1080         let mut path = discrfield.iter().skip(1).map(|&i| i as usize);
1081
1082         // Handle the field index for the outer non-null variant.
1083         let inner_ty = match ty.sty {
1084             ty::TyEnum(adt_def, substs) => {
1085                 let variant = &adt_def.variants[nndiscr as usize];
1086                 let index = path.next().unwrap();
1087                 let field = &variant.fields[index];
1088                 field.ty(self.tcx, substs)
1089             }
1090             _ => panic!(
1091                 "non-enum for StructWrappedNullablePointer: {}",
1092                 ty,
1093             ),
1094         };
1095
1096         self.field_path_offset(inner_ty, path)
1097     }
1098
1099     fn field_path_offset<I: Iterator<Item = usize>>(&self, mut ty: Ty<'tcx>, path: I) -> EvalResult<Size> {
1100         let mut offset = Size::from_bytes(0);
1101
1102         // Skip the initial 0 intended for LLVM GEP.
1103         for field_index in path {
1104             let field_offset = self.get_field_offset(ty, field_index)?;
1105             ty = self.get_field_ty(ty, field_index)?;
1106             offset = offset.checked_add(field_offset, &self.tcx.data_layout).unwrap();
1107         }
1108
1109         Ok(offset)
1110     }
1111
1112     fn get_field_ty(&self, ty: Ty<'tcx>, field_index: usize) -> EvalResult<Ty<'tcx>> {
1113         match ty.sty {
1114             ty::TyStruct(adt_def, substs) => {
1115                 Ok(adt_def.struct_variant().fields[field_index].ty(self.tcx, substs))
1116             }
1117
1118             ty::TyRef(_, ty::TypeAndMut { ty, .. }) |
1119             ty::TyRawPtr(ty::TypeAndMut { ty, .. }) |
1120             ty::TyBox(ty) => {
1121                 assert_eq!(field_index, 0);
1122                 Ok(ty)
1123             }
1124             _ => Err(EvalError::Unimplemented(format!("can't handle type: {:?}", ty))),
1125         }
1126     }
1127
1128     fn get_field_offset(&self, ty: Ty<'tcx>, field_index: usize) -> EvalResult<Size> {
1129         let layout = self.type_layout(ty);
1130
1131         use rustc::ty::layout::Layout::*;
1132         match *layout {
1133             Univariant { .. } => {
1134                 assert_eq!(field_index, 0);
1135                 Ok(Size::from_bytes(0))
1136             }
1137             FatPointer { .. } => {
1138                 let bytes = layout::FAT_PTR_ADDR * self.memory.pointer_size;
1139                 Ok(Size::from_bytes(bytes as u64))
1140             }
1141             _ => Err(EvalError::Unimplemented(format!("can't handle type: {:?}, with layout: {:?}", ty, layout))),
1142         }
1143     }
1144
1145     fn eval_operand(&mut self, op: &mir::Operand<'tcx>) -> EvalResult<Pointer> {
1146         use rustc::mir::repr::Operand::*;
1147         match *op {
1148             Consume(ref lvalue) => Ok(self.eval_lvalue(lvalue)?.to_ptr()),
1149             Constant(mir::Constant { ref literal, ty, .. }) => {
1150                 use rustc::mir::repr::Literal::*;
1151                 match *literal {
1152                     Value { ref value } => Ok(self.const_to_ptr(value)?),
1153                     Item { def_id, substs } => {
1154                         if let ty::TyFnDef(..) = ty.sty {
1155                             Err(EvalError::Unimplemented("unimplemented: mentions of function items".to_string()))
1156                         } else {
1157                             let cid = ConstantId {
1158                                 def_id: def_id,
1159                                 substs: substs,
1160                                 kind: ConstantKind::Global,
1161                             };
1162                             Ok(*self.statics.get(&cid).expect("static should have been cached (rvalue)"))
1163                         }
1164                     },
1165                     Promoted { index } => {
1166                         let cid = ConstantId {
1167                             def_id: self.frame().def_id,
1168                             substs: self.substs(),
1169                             kind: ConstantKind::Promoted(index),
1170                         };
1171                         Ok(*self.statics.get(&cid).expect("a promoted constant hasn't been precomputed"))
1172                     },
1173                 }
1174             }
1175         }
1176     }
1177
1178     fn eval_lvalue(&mut self, lvalue: &mir::Lvalue<'tcx>) -> EvalResult<Lvalue> {
1179         use rustc::mir::repr::Lvalue::*;
1180         let ptr = match *lvalue {
1181             ReturnPointer => self.frame().return_ptr
1182                 .expect("ReturnPointer used in a function with no return value"),
1183             Arg(i) => self.frame().locals[i.index()],
1184             Var(i) => self.frame().locals[self.frame().var_offset + i.index()],
1185             Temp(i) => self.frame().locals[self.frame().temp_offset + i.index()],
1186
1187             Static(def_id) => {
1188                 let substs = self.tcx.mk_substs(subst::Substs::empty());
1189                 let cid = ConstantId {
1190                     def_id: def_id,
1191                     substs: substs,
1192                     kind: ConstantKind::Global,
1193                 };
1194                 *self.statics.get(&cid).expect("static should have been cached (lvalue)")
1195             },
1196
1197             Projection(ref proj) => {
1198                 let base = self.eval_lvalue(&proj.base)?;
1199                 let base_ty = self.lvalue_ty(&proj.base);
1200                 let base_layout = self.type_layout(base_ty);
1201
1202                 use rustc::mir::repr::ProjectionElem::*;
1203                 match proj.elem {
1204                     Field(field, _) => {
1205                         use rustc::ty::layout::Layout::*;
1206                         let variant = match *base_layout {
1207                             Univariant { ref variant, .. } => variant,
1208                             General { ref variants, .. } => {
1209                                 if let LvalueExtra::DowncastVariant(variant_idx) = base.extra {
1210                                     &variants[variant_idx]
1211                                 } else {
1212                                     panic!("field access on enum had no variant index");
1213                                 }
1214                             }
1215                             RawNullablePointer { .. } => {
1216                                 assert_eq!(field.index(), 0);
1217                                 return Ok(base);
1218                             }
1219                             StructWrappedNullablePointer { ref nonnull, .. } => nonnull,
1220                             _ => panic!("field access on non-product type: {:?}", base_layout),
1221                         };
1222
1223                         let offset = variant.field_offset(field.index()).bytes();
1224                         base.ptr.offset(offset as isize)
1225                     },
1226
1227                     Downcast(_, variant) => {
1228                         use rustc::ty::layout::Layout::*;
1229                         match *base_layout {
1230                             General { discr, .. } => {
1231                                 return Ok(Lvalue {
1232                                     ptr: base.ptr.offset(discr.size().bytes() as isize),
1233                                     extra: LvalueExtra::DowncastVariant(variant),
1234                                 });
1235                             }
1236                             RawNullablePointer { .. } | StructWrappedNullablePointer { .. } => {
1237                                 return Ok(base);
1238                             }
1239                             _ => panic!("variant downcast on non-aggregate: {:?}", base_layout),
1240                         }
1241                     },
1242
1243                     Deref => {
1244                         let pointee_ty = pointee_type(base_ty).expect("Deref of non-pointer");
1245                         let ptr = self.memory.read_ptr(base.ptr)?;
1246                         let extra = match pointee_ty.sty {
1247                             ty::TySlice(_) | ty::TyStr => {
1248                                 let len_ptr = base.ptr.offset(self.memory.pointer_size as isize);
1249                                 let len = self.memory.read_usize(len_ptr)?;
1250                                 LvalueExtra::Length(len)
1251                             }
1252                             ty::TyTrait(_) => unimplemented!(),
1253                             _ => LvalueExtra::None,
1254                         };
1255                         return Ok(Lvalue { ptr: ptr, extra: extra });
1256                     }
1257
1258                     Index(ref operand) => {
1259                         let elem_size = match base_ty.sty {
1260                             ty::TyArray(elem_ty, _) |
1261                             ty::TySlice(elem_ty) => self.type_size(elem_ty),
1262                             _ => panic!("indexing expected an array or slice, got {:?}", base_ty),
1263                         };
1264                         let n_ptr = self.eval_operand(operand)?;
1265                         let n = self.memory.read_usize(n_ptr)?;
1266                         base.ptr.offset(n as isize * elem_size as isize)
1267                     }
1268
1269                     ConstantIndex { .. } => unimplemented!(),
1270                     Subslice { .. } => unimplemented!(),
1271                 }
1272             }
1273         };
1274
1275         Ok(Lvalue { ptr: ptr, extra: LvalueExtra::None })
1276     }
1277
1278     fn lvalue_ty(&self, lvalue: &mir::Lvalue<'tcx>) -> Ty<'tcx> {
1279         self.monomorphize(self.mir().lvalue_ty(self.tcx, lvalue).to_ty(self.tcx), self.substs())
1280     }
1281
1282     fn operand_ty(&self, operand: &mir::Operand<'tcx>) -> Ty<'tcx> {
1283         self.monomorphize(self.mir().operand_ty(self.tcx, operand), self.substs())
1284     }
1285
1286     fn move_(&mut self, src: Pointer, dest: Pointer, ty: Ty<'tcx>) -> EvalResult<()> {
1287         let size = self.type_size(ty);
1288         self.memory.copy(src, dest, size)?;
1289         if self.type_needs_drop(ty) {
1290             self.memory.drop_fill(src, size)?;
1291         }
1292         Ok(())
1293     }
1294
1295     pub fn read_primval(&mut self, ptr: Pointer, ty: Ty<'tcx>) -> EvalResult<PrimVal> {
1296         use syntax::ast::{IntTy, UintTy};
1297         let val = match (self.memory.pointer_size, &ty.sty) {
1298             (_, &ty::TyBool)              => PrimVal::Bool(self.memory.read_bool(ptr)?),
1299             (_, &ty::TyInt(IntTy::I8))    => PrimVal::I8(self.memory.read_int(ptr, 1)? as i8),
1300             (2, &ty::TyInt(IntTy::Is)) |
1301             (_, &ty::TyInt(IntTy::I16))   => PrimVal::I16(self.memory.read_int(ptr, 2)? as i16),
1302             (4, &ty::TyInt(IntTy::Is)) |
1303             (_, &ty::TyInt(IntTy::I32))   => PrimVal::I32(self.memory.read_int(ptr, 4)? as i32),
1304             (8, &ty::TyInt(IntTy::Is)) |
1305             (_, &ty::TyInt(IntTy::I64))   => PrimVal::I64(self.memory.read_int(ptr, 8)? as i64),
1306             (_, &ty::TyUint(UintTy::U8))  => PrimVal::U8(self.memory.read_uint(ptr, 1)? as u8),
1307             (2, &ty::TyUint(UintTy::Us)) |
1308             (_, &ty::TyUint(UintTy::U16)) => PrimVal::U16(self.memory.read_uint(ptr, 2)? as u16),
1309             (4, &ty::TyUint(UintTy::Us)) |
1310             (_, &ty::TyUint(UintTy::U32)) => PrimVal::U32(self.memory.read_uint(ptr, 4)? as u32),
1311             (8, &ty::TyUint(UintTy::Us)) |
1312             (_, &ty::TyUint(UintTy::U64)) => PrimVal::U64(self.memory.read_uint(ptr, 8)? as u64),
1313
1314             (_, &ty::TyRef(_, ty::TypeAndMut { ty, .. })) |
1315             (_, &ty::TyRawPtr(ty::TypeAndMut { ty, .. })) => {
1316                 if self.type_is_sized(ty) {
1317                     match self.memory.read_ptr(ptr) {
1318                         Ok(p) => PrimVal::AbstractPtr(p),
1319                         Err(EvalError::ReadBytesAsPointer) => {
1320                             PrimVal::IntegerPtr(self.memory.read_usize(ptr)?)
1321                         }
1322                         Err(e) => return Err(e),
1323                     }
1324                 } else {
1325                     return Err(EvalError::Unimplemented(format!("unimplemented: primitive read of fat pointer type: {:?}", ty)));
1326                 }
1327             }
1328
1329             _ => panic!("primitive read of non-primitive type: {:?}", ty),
1330         };
1331         Ok(val)
1332     }
1333
1334     fn frame(&self) -> &Frame<'a, 'tcx> {
1335         self.stack.last().expect("no call frames exist")
1336     }
1337
1338     fn frame_mut(&mut self) -> &mut Frame<'a, 'tcx> {
1339         self.stack.last_mut().expect("no call frames exist")
1340     }
1341
1342     fn mir(&self) -> CachedMir<'a, 'tcx> {
1343         self.frame().mir.clone()
1344     }
1345
1346     fn substs(&self) -> &'tcx Substs<'tcx> {
1347         self.frame().substs
1348     }
1349 }
1350
1351 fn pointee_type(ptr_ty: ty::Ty) -> Option<ty::Ty> {
1352     match ptr_ty.sty {
1353         ty::TyRef(_, ty::TypeAndMut { ty, .. }) |
1354         ty::TyRawPtr(ty::TypeAndMut { ty, .. }) |
1355         ty::TyBox(ty) => {
1356             Some(ty)
1357         }
1358         _ => None,
1359     }
1360 }
1361
1362 impl Lvalue {
1363     fn to_ptr(self) -> Pointer {
1364         assert_eq!(self.extra, LvalueExtra::None);
1365         self.ptr
1366     }
1367 }
1368
1369 impl<'mir, 'tcx: 'mir> Deref for CachedMir<'mir, 'tcx> {
1370     type Target = mir::Mir<'tcx>;
1371     fn deref(&self) -> &mir::Mir<'tcx> {
1372         match *self {
1373             CachedMir::Ref(r) => r,
1374             CachedMir::Owned(ref rc) => rc,
1375         }
1376     }
1377 }
1378
1379 #[derive(Debug)]
1380 pub struct ImplMethod<'tcx> {
1381     pub method: Rc<ty::Method<'tcx>>,
1382     pub substs: &'tcx Substs<'tcx>,
1383     pub is_provided: bool,
1384 }
1385
1386 /// Locates the applicable definition of a method, given its name.
1387 pub fn get_impl_method<'a, 'tcx>(
1388     tcx: TyCtxt<'a, 'tcx, 'tcx>,
1389     impl_def_id: DefId,
1390     substs: &'tcx Substs<'tcx>,
1391     name: ast::Name,
1392 ) -> ImplMethod<'tcx> {
1393     assert!(!substs.types.needs_infer());
1394
1395     let trait_def_id = tcx.trait_id_of_impl(impl_def_id).unwrap();
1396     let trait_def = tcx.lookup_trait_def(trait_def_id);
1397
1398     match trait_def.ancestors(impl_def_id).fn_defs(tcx, name).next() {
1399         Some(node_item) => {
1400             let substs = tcx.normalizing_infer_ctxt(ProjectionMode::Any).enter(|infcx| {
1401                 let substs = traits::translate_substs(&infcx, impl_def_id,
1402                                                       substs, node_item.node);
1403                 tcx.lift(&substs).unwrap_or_else(|| {
1404                     bug!("trans::meth::get_impl_method: translate_substs \
1405                           returned {:?} which contains inference types/regions",
1406                          substs);
1407                 })
1408             });
1409             ImplMethod {
1410                 method: node_item.item,
1411                 substs: substs,
1412                 is_provided: node_item.node.is_from_trait(),
1413             }
1414         }
1415         None => {
1416             bug!("method {:?} not found in {:?}", name, impl_def_id)
1417         }
1418     }
1419 }
1420
1421 // TODO(solson): Upstream these methods into rustc::ty::layout.
1422
1423 trait IntegerExt {
1424     fn size(self) -> Size;
1425 }
1426
1427 impl IntegerExt for layout::Integer {
1428     fn size(self) -> Size {
1429         use rustc::ty::layout::Integer::*;
1430         match self {
1431             I1 | I8 => Size::from_bits(8),
1432             I16 => Size::from_bits(16),
1433             I32 => Size::from_bits(32),
1434             I64 => Size::from_bits(64),
1435         }
1436     }
1437 }
1438
1439 trait StructExt {
1440     fn field_offset(&self, index: usize) -> Size;
1441 }
1442
1443 impl StructExt for layout::Struct {
1444     fn field_offset(&self, index: usize) -> Size {
1445         if index == 0 {
1446             Size::from_bytes(0)
1447         } else {
1448             self.offset_after_field[index - 1]
1449         }
1450     }
1451 }