/// <summary>
        /// Produces a Try/Finally if frame has a handler (otherwise a regular block).
        /// Handler goes into the Finally.
        /// If there are nested frames, they are emitted into the try block.
        /// This way the handler for the current frame is guaranteed to run even if
        /// nested handlers throw exceptions.
        ///
        /// {
        ///     switch(state)
        ///     {
        ///         case state1:
        ///         case state2:
        ///         case state3:
        ///         case state4:
        ///             try
        ///             {
        ///                 switch(state)
        ///                 {
        ///                     case state3:
        ///                     case state4:
        ///                         try
        ///                         {
        ///                             ... more nested state dispatches if any ....
        ///                         }
        ///                         finally
        ///                         {
        ///                             // handler for a try where state3 and state4 can be observed
        ///                             handler_3_4()
        ///                         }
        ///                         break;
        ///                  }
        ///             }
        ///             finally
        ///             {
        ///                 // handler for a try where state1 and state2 can be observed
        ///                 handler_1_2()
        ///             }
        ///             break;
        ///
        ///         case state5:
        ///             ... another dispatch of nested states to their finally blocks ...
        ///             break;
        ///     }
        /// }
        ///
        /// </summary>
        private BoundStatement EmitFinallyFrame(IteratorFinallyFrame frame, BoundLocal state)
        {
            BoundStatement body = null;

            if (frame.knownStates != null)
            {
                var breakLabel = F.GenerateLabel("break");
                var sections   = from ft in frame.knownStates
                                 group ft.Key by ft.Value into g
                                 select F.SwitchSection(
                    new List <int>(g),
                    EmitFinallyFrame(g.Key, state),
                    F.Goto(breakLabel));

                body = F.Block(
                    F.Switch(state, sections.ToImmutableArray()),
                    F.Label(breakLabel));
            }

            if (!frame.IsRoot())
            {
                var tryBlock = body != null?F.Block(body) : F.Block();

                body = F.Try(
                    tryBlock,
                    ImmutableArray <BoundCatchBlock> .Empty,
                    F.Block(F.ExpressionStatement(F.Call(F.This(), frame.handler))));
            }

            Debug.Assert(body != null, "we should have either sub-dispatch or a handler");
            return(body);
        }
        private IteratorFinallyFrame PushFrame(BoundTryStatement statement)
        {
            var state = _nextFinalizeState--;

            var finallyMethod = MakeSynthesizedFinally(state);
            var newFrame      = new IteratorFinallyFrame(_currentFinallyFrame, state, finallyMethod, _yieldsInTryAnalysis.Labels(statement));

            newFrame.AddState(state);

            _currentFinallyFrame = newFrame;
            return(newFrame);
        }
            public IteratorFinallyFrame(
                IteratorFinallyFrame parent,
                int finalizeState,
                IteratorFinallyMethodSymbol handler,
                HashSet<LabelSymbol> labels)
            {
                Debug.Assert(parent != null, "non root frame must have a parent");
                Debug.Assert((object)handler != null, "non root frame must have a handler");

                this.parent = parent;
                this.finalizeState = finalizeState;
                this.handler = handler;
                this.labels = labels;
            }
            public IteratorFinallyFrame(
                IteratorFinallyFrame parent,
                int finalizeState,
                IteratorFinallyMethodSymbol handler,
                HashSet <LabelSymbol> labels)
            {
                Debug.Assert(parent != null, "non root frame must have a parent");
                Debug.Assert((object)handler != null, "non root frame must have a handler");

                this.parent        = parent;
                this.finalizeState = finalizeState;
                this.handler       = handler;
                this.labels        = labels;
            }
            // Notifies all parents about the state recursively. 
            // All parents need to know states they recursively contain and what 
            // immediate child can handle every particular state.
            private void AddState(int state, IteratorFinallyFrame innerHandler)
            {
                var knownStates = this.knownStates;
                if (knownStates == null)
                {
                    this.knownStates = knownStates = new Dictionary<int, IteratorFinallyFrame>();
                }

                knownStates.Add(state, innerHandler);

                if (parent != null)
                {
                    // Present ourselves to the parent as responsible for a handling a state.
                    parent.AddState(state, this);
                }
            }
            // Notifies all parents about the state recursively.
            // All parents need to know states they recursively contain and what
            // immediate child can handle every particular state.
            private void AddState(int state, IteratorFinallyFrame innerHandler)
            {
                var knownStates = this.knownStates;

                if (knownStates == null)
                {
                    this.knownStates = knownStates = new Dictionary <int, IteratorFinallyFrame>();
                }

                knownStates.Add(state, innerHandler);

                if (parent != null)
                {
                    // Present ourselves to the parent as responsible for a handling a state.
                    parent.AddState(state, this);
                }
            }
        private IteratorFinallyFrame PushFrame(BoundTryStatement statement)
        {
            var syntax = statement.Syntax;

            if (slotAllocatorOpt?.TryGetPreviousStateMachineState(syntax, out var finalizeState) != true)
            {
                finalizeState = _nextFinalizeState--;
            }

            AddStateDebugInfo(syntax, finalizeState);

            var finallyMethod = MakeSynthesizedFinally(finalizeState);
            var newFrame      = new IteratorFinallyFrame(_currentFinallyFrame, finalizeState, finallyMethod, _yieldsInTryAnalysis.Labels(statement));

            newFrame.AddState(finalizeState);

            _currentFinallyFrame = newFrame;
            return(newFrame);
        }
 private void PopFrame()
 {
     var result = _currentFinallyFrame;
     _currentFinallyFrame = result.parent;
 }
        private IteratorFinallyFrame PushFrame(BoundTryStatement statement)
        {
            var state = _nextFinalizeState--;

            var finallyMethod = MakeSynthesizedFinally(state);
            var newFrame = new IteratorFinallyFrame(_currentFinallyFrame, state, finallyMethod, _yieldsInTryAnalysis.Labels(statement));
            newFrame.AddState(state);

            _currentFinallyFrame = newFrame;
            return newFrame;
        }
        /// <summary>
        /// Produces a Try/Finally if frame has a handler (otherwise a regular block).
        /// Handler goes into the Finally.
        /// If there are nested frames, they are emitted into the try block.
        /// This way the handler for the current frame is guaranteed to run even if 
        /// nested handlers throw exceptions.
        /// 
        /// {
        ///     switch(state)
        ///     {
        ///         case state1:
        ///         case state2:
        ///         case state3:
        ///         case state4:
        ///             try
        ///             {
        ///                 switch(state)
        ///                 {
        ///                     case state3:
        ///                     case state4:
        ///                         try
        ///                         {
        ///                             ... more nested state dispatches if any ....
        ///                         }
        ///                         finally
        ///                         {
        ///                             // handler for a try where state3 and state4 can be observed
        ///                             handler_3_4()
        ///                         }
        ///                         break;
        ///                  }
        ///             }
        ///             finally
        ///             {
        ///                 // handler for a try where state1 and state2 can be observed
        ///                 handler_1_2()
        ///             }
        ///             break;
        ///             
        ///         case state5:
        ///             ... another dispatch of nested states to their finally blocks ...
        ///             break;
        ///     }
        /// }
        /// 
        /// </summary>
        private BoundStatement EmitFinallyFrame(IteratorFinallyFrame frame, BoundLocal state)
        {
            BoundStatement body = null;
            if (frame.knownStates != null)
            {
                var breakLabel = F.GenerateLabel("break");
                var sections = from ft in frame.knownStates
                               group ft.Key by ft.Value into g
                               select F.SwitchSection(
                                    new List<int>(g),
                                    EmitFinallyFrame(g.Key, state),
                                    F.Goto(breakLabel));

                body = F.Block(
                    F.Switch(state, sections),
                    F.Label(breakLabel));
            }

            if (!frame.IsRoot())
            {
                var tryBlock = body != null ? F.Block(body) : F.Block();
                body = F.Try(
                    tryBlock,
                    ImmutableArray<BoundCatchBlock>.Empty,
                    F.Block(F.ExpressionStatement(F.Call(F.This(), frame.handler))));
            }

            Debug.Assert(body != null, "we should have either sub-dispatch or a handler");
            return body;
        }
        private void PopFrame()
        {
            var result = _currentFinallyFrame;

            _currentFinallyFrame = result.parent;
        }