internal void GenerateMoveNextAndDispose(BoundStatement body, SynthesizedImplementationMethod moveNextMethod, SynthesizedImplementationMethod disposeMethod)
        {
            // scan body for yielding Trys
            _yieldsInTryAnalysis = new YieldsInTryAnalysis(body);
            if (_yieldsInTryAnalysis.ContainsYieldsInTrys())
            {
                // adjust for the method Try/Fault block that we will put around the body.
                _tryNestingLevel++;
            }

            /////////////////////////////////// 
            // Generate the body for MoveNext()
            ///////////////////////////////////

            F.CurrentMethod = moveNextMethod;
            int initialState;
            GeneratedLabelSymbol initialLabel;
            AddState(out initialState, out initialLabel);
            var newBody = (BoundStatement)Visit(body);

            // switch(cachedState) {
            //    case 0: goto state_0;
            //    case 1: goto state_1;
            //    //etc
            //    default: return false;
            // }
            // state_0:
            // state = -1;
            // [[rewritten body]]
            newBody = F.Block(ImmutableArray.Create(cachedState),
                    F.Block(
                        F.HiddenSequencePoint(),
                        F.Assignment(F.Local(cachedState), F.Field(F.This(), stateField))
                    ),
                    Dispatch(),
                    GenerateReturn(finished: true),
                    F.Label(initialLabel),
                    F.Assignment(F.Field(F.This(), stateField), F.Literal(StateMachineStates.NotStartedStateMachine)),
                    newBody);

            //
            // C# spec requires that iterators trap all exceptions and self-dispose eagerly.
            //
            // 10.14.4.1 The MoveNext method
            // . . .
            // When an exception is thrown and propagated out of the iterator block:
            // o   Appropriate finally blocks in the iterator body will have been executed by the exception propagation.
            // o   The state of the enumerator object is changed to after.
            // o   The exception propagation continues to the caller of the MoveNext method.
            // . . .
            //
            if (_yieldsInTryAnalysis.ContainsYieldsInTrys())
            {
                // try 
                // {
                //    body;
                // }
                // fault
                // {
                //    this.Dispose();
                // }

                var faultBlock = F.Block(F.ExpressionStatement(F.Call(F.This(), disposeMethod)));
                newBody = F.Fault((BoundBlock)newBody, faultBlock);
            }

            newBody = HandleReturn(newBody);
            F.CloseMethod(F.SequencePoint(body.Syntax, newBody));

            /////////////////////////////////// 
            // Generate the body for Dispose().
            ///////////////////////////////////
            F.CurrentMethod = disposeMethod;
            var rootFrame = _currentFinallyFrame;

            if (rootFrame.knownStates == null)
            {
                // nothing to finalize
                F.CloseMethod(F.Return());
            }
            else
            {
                var stateLocal = F.SynthesizedLocal(stateField.Type);
                var state = F.Local(stateLocal);

                var disposeBody = F.Block(
                                    ImmutableArray.Create<LocalSymbol>(stateLocal),
                                    F.Assignment(F.Local(stateLocal), F.Field(F.This(), stateField)),
                                    EmitFinallyFrame(rootFrame, state),
                                    F.Return());

                F.CloseMethod(disposeBody);
            }
        }
        internal void GenerateMoveNextAndDispose(BoundStatement body, SynthesizedImplementationMethod moveNextMethod, SynthesizedImplementationMethod disposeMethod)
        {
            // scan body for yielding try blocks
            _yieldsInTryAnalysis = new YieldsInTryAnalysis(body);
            if (_yieldsInTryAnalysis.ContainsYieldsInTrys())
            {
                // adjust for the method Try/Fault block that we will put around the body.
                _tryNestingLevel++;
            }

            ///////////////////////////////////
            // Generate the body for MoveNext()
            ///////////////////////////////////

            F.CurrentFunction = moveNextMethod;
            int initialState;
            GeneratedLabelSymbol initialLabel;

            AddState(out initialState, out initialLabel);
            var newBody = (BoundStatement)Visit(body);

            // switch(cachedState) {
            //    case 0: goto state_0;
            //    case 1: goto state_1;
            //    //etc
            //    default: return false;
            // }
            // state_0:
            // state = -1;
            // [optional: cachedThis = capturedThis;]
            // [[rewritten body]]
            newBody = F.Block((object)cachedThis == null ?
                              ImmutableArray.Create(cachedState) :
                              ImmutableArray.Create(cachedState, cachedThis),

                              F.HiddenSequencePoint(),
                              F.Assignment(F.Local(cachedState), F.Field(F.This(), stateField)),
                              CacheThisIfNeeded(),
                              Dispatch(),
                              GenerateReturn(finished: true),
                              F.Label(initialLabel),
                              F.Assignment(F.Field(F.This(), stateField), F.Literal(StateMachineStates.NotStartedStateMachine)),
                              newBody);

            //
            // C# spec requires that iterators trap all exceptions and self-dispose eagerly.
            //
            // 10.14.4.1 The MoveNext method
            // . . .
            // When an exception is thrown and propagated out of the iterator block:
            // o   Appropriate finally blocks in the iterator body will have been executed by the exception propagation.
            // o   The state of the enumerator object is changed to after.
            // o   The exception propagation continues to the caller of the MoveNext method.
            // . . .
            //
            if (_yieldsInTryAnalysis.ContainsYieldsInTrys())
            {
                // try
                // {
                //    body;
                // }
                // fault
                // {
                //    this.Dispose();
                // }

                var faultBlock = F.Block(F.ExpressionStatement(F.Call(F.This(), disposeMethod)));
                newBody = F.Fault((BoundBlock)newBody, faultBlock);
            }

            newBody = HandleReturn(newBody);
            F.CloseMethod(F.SequencePoint(body.Syntax, newBody));

            ///////////////////////////////////
            // Generate the body for Dispose().
            ///////////////////////////////////
            F.CurrentFunction = disposeMethod;
            var rootFrame = _currentFinallyFrame;

            if (rootFrame.knownStates == null)
            {
                // nothing to finalize
                F.CloseMethod(F.Return());
            }
            else
            {
                var stateLocal = F.SynthesizedLocal(stateField.Type.TypeSymbol);
                var state      = F.Local(stateLocal);

                var disposeBody = F.Block(
                    ImmutableArray.Create <LocalSymbol>(stateLocal),
                    F.Assignment(F.Local(stateLocal), F.Field(F.This(), stateField)),
                    EmitFinallyFrame(rootFrame, state),
                    F.Return());

                F.CloseMethod(disposeBody);
            }
        }