From c71153113b965b6dfd265590a4d20a73d08ee4d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20K=C3=A5re=20Alsaker?= Date: Fri, 25 Aug 2017 00:57:08 +0200 Subject: [PATCH] Add some comments and fix a typo --- src/librustc_mir/build/expr/as_rvalue.rs | 3 +- src/librustc_mir/transform/generator.rs | 56 ++++++++++++++++++- src/librustc_mir/util/elaborate_drops.rs | 5 +- .../check/generator_interior.rs | 5 ++ 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 188f54f519eb..da375e791bc4 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 f774b748112a..9bc572c66b6f 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 e1a52ab9723c..41618960337b 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 7b25a3739c3d..e9d400c64393 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};