]> git.lizzy.rs Git - rust.git/commitdiff
Handle promoted rvalues by recursing with call_nested.
authorScott Olson <scott@solson.me>
Tue, 10 May 2016 00:21:21 +0000 (18:21 -0600)
committerScott Olson <scott@solson.me>
Tue, 10 May 2016 00:21:52 +0000 (18:21 -0600)
src/interpreter.rs

index b9c9160015ea1cfc620d4d921b5c8351e1477dbd..a7a1ffb27b6032465b581922a3d21d81f0fea73f 100644 (file)
@@ -10,7 +10,7 @@
 use rustc::ty::{self, TyCtxt};
 use rustc::util::nodemap::DefIdMap;
 use std::cell::RefCell;
-use std::ops::Deref;
+use std::ops::{Deref, DerefMut};
 use std::rc::Rc;
 use std::{iter, mem};
 use syntax::ast;
@@ -23,7 +23,7 @@
 
 const TRACE_EXECUTION: bool = false;
 
-struct Interpreter<'a, 'tcx: 'a> {
+struct GlobalEvalContext<'a, 'tcx: 'a> {
     /// The results of the type checker, from rustc.
     tcx: &'a TyCtxt<'tcx>,
 
@@ -36,9 +36,6 @@ struct Interpreter<'a, 'tcx: 'a> {
     /// The virtual memory system.
     memory: Memory,
 
-    /// The virtual call stack.
-    stack: Vec<Frame<'a, 'tcx>>,
-
     /// Another stack containing the type substitutions for the current function invocation. It
     /// exists separately from `stack` because it must contain the `Substs` for a function while
     /// *creating* the `Frame` for that same function.
@@ -51,6 +48,26 @@ struct Interpreter<'a, 'tcx: 'a> {
     name_stack: Vec<(DefId, &'tcx Substs<'tcx>, codemap::Span)>,
 }
 
+struct FnEvalContext<'a, 'b: 'a + 'mir, 'mir, 'tcx: 'b> {
+    gecx: &'a mut GlobalEvalContext<'b, 'tcx>,
+
+    /// The virtual call stack.
+    stack: Vec<Frame<'mir, 'tcx>>,
+}
+
+impl<'a, 'b, 'mir, 'tcx> Deref for FnEvalContext<'a, 'b, 'mir, 'tcx> {
+    type Target = GlobalEvalContext<'b, 'tcx>;
+    fn deref(&self) -> &Self::Target {
+        self.gecx
+    }
+}
+
+impl<'a, 'b, 'mir, 'tcx> DerefMut for FnEvalContext<'a, 'b, 'mir, 'tcx> {
+    fn deref_mut(&mut self) -> &mut Self::Target {
+        self.gecx
+    }
+}
+
 /// A stack frame.
 struct Frame<'a, 'tcx: 'a> {
     /// The MIR for the function called on this frame.
@@ -106,18 +123,26 @@ enum TerminatorTarget {
     Return,
 }
 
-impl<'a, 'tcx: 'a> Interpreter<'a, 'tcx> {
+impl<'a, 'tcx> GlobalEvalContext<'a, 'tcx> {
     fn new(tcx: &'a TyCtxt<'tcx>, mir_map: &'a MirMap<'tcx>) -> Self {
-        Interpreter {
+        GlobalEvalContext {
             tcx: tcx,
             mir_map: mir_map,
             mir_cache: RefCell::new(DefIdMap()),
             memory: Memory::new(),
-            stack: Vec::new(),
             substs_stack: Vec::new(),
             name_stack: Vec::new(),
         }
     }
+}
+
+impl<'a, 'b, 'mir, 'tcx> FnEvalContext<'a, 'b, 'mir, 'tcx> {
+    fn new(gecx: &'a mut GlobalEvalContext<'b, 'tcx>) -> Self {
+        FnEvalContext {
+            gecx: gecx,
+            stack: Vec::new(),
+        }
+    }
 
     fn maybe_report<T>(&self, span: codemap::Span, r: EvalResult<T>) -> EvalResult<T> {
         if let Err(ref e) = r {
@@ -183,7 +208,24 @@ fn run(&mut self) -> EvalResult<()> {
         Ok(())
     }
 
-    fn push_stack_frame(&mut self, mir: CachedMir<'a, 'tcx>, substs: &'tcx Substs<'tcx>,
+    fn call_nested(&mut self, mir: &mir::Mir<'tcx>) -> EvalResult<Option<Pointer>> {
+        let mut nested_fecx = FnEvalContext::new(self.gecx);
+
+        let return_ptr = match mir.return_ty {
+            ty::FnConverging(ty) => {
+                let size = nested_fecx.type_size(ty);
+                Some(nested_fecx.memory.allocate(size))
+            }
+            ty::FnDiverging => None,
+        };
+
+        let substs = nested_fecx.substs();
+        nested_fecx.push_stack_frame(CachedMir::Ref(mir), substs, return_ptr);
+        try!(nested_fecx.run());
+        Ok(return_ptr)
+    }
+
+    fn push_stack_frame(&mut self, mir: CachedMir<'mir, 'tcx>, substs: &'tcx Substs<'tcx>,
         return_ptr: Option<Pointer>)
     {
         self.substs_stack.push(substs);
@@ -805,7 +847,11 @@ fn eval_operand(&mut self, op: &mir::Operand<'tcx>) -> EvalResult<Pointer> {
                 match *literal {
                     Value { ref value } => Ok(try!(self.const_to_ptr(value))),
                     Item { .. } => unimplemented!(),
-                    Promoted { .. } => unimplemented!(),
+                    Promoted { index } => {
+                        let current_mir = self.mir();
+                        let mir = &current_mir.promoted[index];
+                        self.call_nested(mir).map(Option::unwrap)
+                    }
                 }
             }
         }
@@ -1020,23 +1066,23 @@ pub fn read_primval(&mut self, ptr: Pointer, ty: ty::Ty<'tcx>) -> EvalResult<Pri
         Ok(val)
     }
 
-    fn frame(&self) -> &Frame<'a, 'tcx> {
+    fn frame(&self) -> &Frame<'mir, 'tcx> {
         self.stack.last().expect("no call frames exist")
     }
 
-    fn frame_mut(&mut self) -> &mut Frame<'a, 'tcx> {
+    fn frame_mut(&mut self) -> &mut Frame<'mir, 'tcx> {
         self.stack.last_mut().expect("no call frames exist")
     }
 
-    fn mir(&self) -> &mir::Mir<'tcx> {
-        &self.frame().mir
+    fn mir(&self) -> CachedMir<'mir, 'tcx> {
+        self.frame().mir.clone()
     }
 
     fn substs(&self) -> &'tcx Substs<'tcx> {
         self.substs_stack.last().cloned().unwrap_or_else(|| self.tcx.mk_substs(Substs::empty()))
     }
 
-    fn load_mir(&self, def_id: DefId) -> CachedMir<'a, 'tcx> {
+    fn load_mir(&self, def_id: DefId) -> CachedMir<'mir, 'tcx> {
         match self.tcx.map.as_local_node_id(def_id) {
             Some(node_id) => CachedMir::Ref(self.mir_map.map.get(&node_id).unwrap()),
             None => {
@@ -1200,22 +1246,17 @@ pub fn interpret_start_points<'tcx>(tcx: &TyCtxt<'tcx>, mir_map: &MirMap<'tcx>)
 
                 println!("Interpreting: {}", item.name);
 
-                let mut miri = Interpreter::new(tcx, mir_map);
-                let return_ptr = match mir.return_ty {
-                    ty::FnConverging(ty) => {
-                        let size = miri.type_size(ty);
-                        Some(miri.memory.allocate(size))
+                let mut gecx = GlobalEvalContext::new(tcx, mir_map);
+                let mut fecx = FnEvalContext::new(&mut gecx);
+                match fecx.call_nested(mir) {
+                    Ok(Some(return_ptr)) => fecx.memory.dump(return_ptr.alloc_id),
+                    Ok(None) => println!("(diverging function returned)"),
+                    Err(_e) => {
+                        // TODO(tsion): Detect whether the error was already reported or not.
+                        // tcx.sess.err(&e.to_string());
                     }
-                    ty::FnDiverging => None,
-                };
-                let substs = miri.tcx.mk_substs(Substs::empty());
-                miri.push_stack_frame(CachedMir::Ref(mir), substs, return_ptr);
-                if let Err(_e) = miri.run() {
-                    // TODO(tsion): Detect whether the error was already reported or not.
-                    // tcx.sess.err(&e.to_string());
-                } else if let Some(ret) = return_ptr {
-                    miri.memory.dump(ret.alloc_id);
                 }
+
                 println!("");
             }
         }