diff --git a/src/interpreter/iterator.rs b/src/interpreter/iterator.rs
new file mode 100644
index 00000000000..7793c0df282
--- /dev/null
+++ b/src/interpreter/iterator.rs
@@ -0,0 +1,92 @@
+use super::{
+    FnEvalContext,
+    CachedMir,
+    TerminatorTarget,
+};
+use error::EvalResult;
+use rustc::mir::repr as mir;
+
+pub enum Event<'a, 'tcx: 'a> {
+    Assignment(&'a mir::Statement<'tcx>),
+    Terminator(&'a mir::Terminator<'tcx>),
+    Done,
+}
+
+pub struct Stepper<'fncx, 'a: 'fncx, 'b: 'a + 'mir, 'mir: 'fncx, 'tcx: 'b>{
+    fncx: &'fncx mut FnEvalContext<'a, 'b, 'mir, 'tcx>,
+    block: mir::BasicBlock,
+    stmt: usize,
+    mir: CachedMir<'mir, 'tcx>,
+    process: fn (&mut Stepper<'fncx, 'a, 'b, 'mir, 'tcx>) -> EvalResult<()>,
+}
+
+impl<'fncx, 'a, 'b: 'a + 'mir, 'mir, 'tcx: 'b> Stepper<'fncx, 'a, 'b, 'mir, 'tcx> {
+    pub(super) fn new(fncx: &'fncx mut FnEvalContext<'a, 'b, 'mir, 'tcx>) -> Self {
+        Stepper {
+            block: fncx.frame().next_block,
+            mir: fncx.mir(),
+            fncx: fncx,
+            stmt: 0,
+            process: Self::dummy,
+        }
+    }
+    fn dummy(&mut self) -> EvalResult<()> { Ok(()) }
+    fn statement(&mut self) -> EvalResult<()> {
+        let block_data = self.mir.basic_block_data(self.block);
+        let stmt = &block_data.statements[self.stmt];
+        let mir::StatementKind::Assign(ref lvalue, ref rvalue) = stmt.kind;
+        let result = self.fncx.eval_assignment(lvalue, rvalue);
+        self.fncx.maybe_report(stmt.span, result)?;
+        self.stmt += 1;
+        Ok(())
+    }
+    fn terminator(&mut self) -> EvalResult<()> {
+        self.stmt = 0;
+        let term = {
+            let block_data = self.mir.basic_block_data(self.block);
+            let terminator = block_data.terminator();
+            let result = self.fncx.eval_terminator(terminator);
+            self.fncx.maybe_report(terminator.span, result)?
+        };
+        match term {
+            TerminatorTarget::Block(block) => {
+                self.block = block;
+            },
+            TerminatorTarget::Return => {
+                self.fncx.pop_stack_frame();
+                self.fncx.name_stack.pop();
+                if !self.fncx.stack.is_empty() {
+                    self.block = self.fncx.frame().next_block;
+                    self.mir = self.fncx.mir();
+                }
+            },
+            TerminatorTarget::Call => {
+                self.block = self.fncx.frame().next_block;
+                self.mir = self.fncx.mir();
+            },
+        }
+        Ok(())
+    }
+    pub fn step<'step>(&'step mut self) -> EvalResult<Event<'step, 'tcx>> {
+        (self.process)(self)?;
+
+        if self.fncx.stack.is_empty() {
+            // fuse the iterator
+            self.process = Self::dummy;
+            return Ok(Event::Done);
+        }
+
+        let basic_block = self.mir.basic_block_data(self.block);
+
+        if let Some(stmt) = basic_block.statements.get(self.stmt) {
+            self.process = Self::statement;
+            return Ok(Event::Assignment(&stmt));
+        }
+
+        self.process = Self::terminator;
+        Ok(Event::Terminator(basic_block.terminator()))
+    }
+    pub fn block(&self) -> mir::BasicBlock {
+        self.block
+    }
+}
diff --git a/src/interpreter.rs b/src/interpreter/mod.rs
similarity index 98%
rename from src/interpreter.rs
rename to src/interpreter/mod.rs
index c8e6d0bbe1f..8b93edd888c 100644
--- a/src/interpreter.rs
+++ b/src/interpreter/mod.rs
@@ -20,6 +20,8 @@ use error::{EvalError, EvalResult};
 use memory::{Memory, Pointer};
 use primval::{self, PrimVal};
 
+mod iterator;
+
 struct GlobalEvalContext<'a, 'tcx: 'a> {
     /// The results of the type checker, from rustc.
     tcx: TyCtxt<'a, 'tcx, 'tcx>,
@@ -184,38 +186,22 @@ impl<'a, 'b, 'mir, 'tcx> FnEvalContext<'a, 'b, 'mir, 'tcx> {
     }
 
     fn run(&mut self) -> EvalResult<()> {
-        'outer: while !self.stack.is_empty() {
-            let mut current_block = self.frame().next_block;
-            let current_mir = self.mir();
+        let mut stepper = iterator::Stepper::new(self);
+        'outer: loop {
+            use self::iterator::Event::*;
+            trace!("// {:?}", stepper.block());
 
             loop {
-                trace!("// {:?}", current_block);
-                let block_data = current_mir.basic_block_data(current_block);
-
-                for stmt in &block_data.statements {
-                    trace!("{:?}", stmt);
-                    let mir::StatementKind::Assign(ref lvalue, ref rvalue) = stmt.kind;
-                    let result = self.eval_assignment(lvalue, rvalue);
-                    self.maybe_report(stmt.span, result)?;
-                }
-
-                let terminator = block_data.terminator();
-                trace!("{:?}", terminator.kind);
-
-                let result = self.eval_terminator(terminator);
-                match self.maybe_report(terminator.span, result)? {
-                    TerminatorTarget::Block(block) => current_block = block,
-                    TerminatorTarget::Return => {
-                        self.pop_stack_frame();
-                        self.name_stack.pop();
+                match stepper.step()? {
+                    Assignment(statement) => trace!("{:?}", statement),
+                    Terminator(terminator) => {
+                        trace!("{:?}", terminator.kind);
                         continue 'outer;
-                    }
-                    TerminatorTarget::Call => continue 'outer,
+                    },
+                    Done => return Ok(()),
                 }
             }
         }
-
-        Ok(())
     }
 
     fn push_stack_frame(&mut self, mir: CachedMir<'mir, 'tcx>, substs: &'tcx Substs<'tcx>,
diff --git a/src/lib.rs b/src/lib.rs
index 80d89c164ac..4e06a3ce38d 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -6,6 +6,7 @@
     filling_drop,
     question_mark,
     rustc_private,
+    pub_restricted,
 )]
 
 // From rustc.