about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/librustc_mir/build/expr/as_rvalue.rs3
-rw-r--r--src/librustc_mir/transform/generator.rs56
-rw-r--r--src/librustc_mir/util/elaborate_drops.rs5
-rw-r--r--src/librustc_typeck/check/generator_interior.rs5
4 files changed, 64 insertions, 5 deletions
diff --git a/src/librustc_mir/build/expr/as_rvalue.rs b/src/librustc_mir/build/expr/as_rvalue.rs
index 188f54f519e..da375e791bc 100644
--- a/src/librustc_mir/build/expr/as_rvalue.rs
+++ b/src/librustc_mir/build/expr/as_rvalue.rs
@@ -191,7 +191,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                           .map(|upvar| unpack!(block = this.as_operand(block, scope, upvar)))
                           .collect();
                 let result = if let Some(interior) = interior {
-                    // Add the state operand
+                    // Add the state operand since it follows the upvars in the generator
+                    // struct. See librustc_mir/transform/generator.rs for more details.
                     operands.push(Operand::Constant(box Constant {
                         span: expr_span,
                         ty: this.hir.tcx().types.u32,
diff --git a/src/librustc_mir/transform/generator.rs b/src/librustc_mir/transform/generator.rs
index f774b748112..9bc572c66b6 100644
--- a/src/librustc_mir/transform/generator.rs
+++ b/src/librustc_mir/transform/generator.rs
@@ -8,7 +8,57 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-//! Transforms generators into state machines
+//! This is the implementation of the pass which transforms generators into state machines.
+//!
+//! MIR generation for generators creates a function which has a self argument which
+//! passes by value. This argument is effectively a generator type which only contains upvars and
+//! is only used for this argument inside the MIR for the generator.
+//! It is passed by value to enable upvars to be moved out of it. Drop elaboration runs on that
+//! MIR before this pass and creates drop flags for MIR locals.
+//! It will also drop the generator argument (which only consists of upvars) if any of the upvars
+//! are moved out of. This pass elaborates the drops of upvars / generator argument in the case
+//! that none of the upvars were moved out of. This is because we cannot have any drops of this
+//! generator in the MIR, since it is used to create the drop glue for the generator. We'd get
+//! infinite recursion otherwise.
+//!
+//! This pass creates the implementation for the Generator::resume function and the drop shim
+//! for the generator based on the MIR input. It converts the generator argument from Self to
+//! &mut Self adding derefs in the MIR as needed. It computes the final layout of the generator
+//! struct which looks like this:
+//!     First upvars are stored
+//!     It is followed by the generator state field.
+//!     Then finally the MIR locals which are live across a suspension point are stored.
+//!
+//!     struct Generator {
+//!         upvars...,
+//!         state: u32,
+//!         mir_locals...,
+//!     }
+//!
+//! This pass computes the meaning of the state field and the MIR locals which are live
+//! across a suspension point. There are however two hardcoded generator states:
+//!     0 - Generator have not been resumed yet
+//!     1 - Generator has been poisoned
+//!
+//! It also rewrites `return x` and `yield y` as setting a new generator state and returning
+//! GeneratorState::Complete(x) and GeneratorState::Yielded(y) respectively.
+//! MIR locals which are live across a suspension point are moved to the generator struct
+//! with references to them being updated with references to the generator struct.
+//!
+//! The pass creates two functions which have a switch on the generator state giving
+//! the action to take.
+//!
+//! One of them is the implementation of Generator::resume.
+//! For generators which have already returned it panics.
+//! For generators with state 0 (unresumed) it starts the execution of the generator.
+//! For generators with state 1 (poisoned) it panics.
+//! Otherwise it continues the execution from the last suspension point.
+//!
+//! The other function is the drop glue for the generator.
+//! For generators which have already returned it does nothing.
+//! For generators with state 0 (unresumed) it drops the upvars of the generator.
+//! For generators with state 1 (poisoned) it does nothing.
+//! Otherwise it drops all the values in scope at the last suspension point.
 
 use rustc::hir;
 use rustc::hir::def_id::DefId;
@@ -515,7 +565,7 @@ fn insert_panic_on_resume_after_return<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
     });
 }
 
-fn creator_generator_resume_function<'a, 'tcx>(
+fn create_generator_resume_function<'a, 'tcx>(
         tcx: TyCtxt<'a, 'tcx, 'tcx>,
         mut transform: TransformVisitor<'a, 'tcx>,
         def_id: DefId,
@@ -731,6 +781,6 @@ impl MirPass for StateTransform {
         mir.generator_drop = Some(box drop_shim);
 
         // Create the Generator::resume function
-        creator_generator_resume_function(tcx, transform, def_id, source, mir);
+        create_generator_resume_function(tcx, transform, def_id, source, mir);
     }
 }
diff --git a/src/librustc_mir/util/elaborate_drops.rs b/src/librustc_mir/util/elaborate_drops.rs
index e1a52ab9723..41618960337 100644
--- a/src/librustc_mir/util/elaborate_drops.rs
+++ b/src/librustc_mir/util/elaborate_drops.rs
@@ -752,10 +752,13 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D>
     fn open_drop<'a>(&mut self) -> BasicBlock {
         let ty = self.lvalue_ty(self.lvalue);
         match ty.sty {
+            ty::TyClosure(def_id, substs) |
             // Note that `elaborate_drops` only drops the upvars of a generator,
             // and this is ok because `open_drop` here can only be reached
             // within that own generator's resume function.
-            ty::TyClosure(def_id, substs) |
+            // This should only happen for the self argument on the resume function.
+            // It effetively only contains upvars until the generator transformation runs.
+            // See librustc_mir/transform/generator.rs for more details.
             ty::TyGenerator(def_id, substs, _) => {
                 let tys : Vec<_> = substs.upvar_tys(def_id, self.tcx()).collect();
                 self.open_drop_for_tuple(&tys)
diff --git a/src/librustc_typeck/check/generator_interior.rs b/src/librustc_typeck/check/generator_interior.rs
index 7b25a3739c3..e9d400c6439 100644
--- a/src/librustc_typeck/check/generator_interior.rs
+++ b/src/librustc_typeck/check/generator_interior.rs
@@ -8,6 +8,11 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+//! This calculates the types which has storage which lives across a suspension point in a
+//! generator from the perspective of typeck. The actual types used at runtime
+//! is calculated in `rustc_mir::transform::generator` and may be a subset of the
+//! types computed here.
+
 use log;
 use rustc::hir::def_id::DefId;
 use rustc::hir::intravisit::{self, Visitor, NestedVisitorMap};