internal void Reference(LabelScopeInfo block)
 {
     _references.Add(block);
     if (_definitions.Count > 0)
     {
         ValidateJump(block);
     }
 }
        // Returns true if the label was successfully defined
        // or false if the label is now ambiguous
        internal void Define(LabelScopeInfo block)
        {
            // Prevent the label from being shadowed, which enforces cleaner
            // trees. Also we depend on this for simplicity (keeping only one
            // active IL Label per LabelInfo)
            for (var j = block; j != null; j = j.Parent)
            {
                if (j.ContainsTarget(_node))
                {
                    throw Error.LabelTargetAlreadyDefined(_node.Name);
                }
            }

            _definitions.Add(block);
            block.AddLabelInfo(_node, this);

            // Once defined, validate all jumps
            if (_definitions.Count == 1)
            {
                foreach (var r in _references)
                {
                    ValidateJump(r);
                }
            }
            else
            {
                // Was just redefined, if we had any across block jumps, they're
                // now invalid
                if (_acrossBlockJump)
                {
                    throw Error.AmbiguousJump(_node.Name);
                }
                // For local jumps, we need a new IL label
                // This is okay because:
                //   1. no across block jumps have been made or will be made
                //   2. we don't allow the label to be shadowed
                _labelDefined = false;
            }
        }
 private void PushLabelBlock(LabelScopeKind type)
 {
     _labelBlock = new LabelScopeInfo(_labelBlock, type);
 }
 internal LabelScopeInfo(LabelScopeInfo parent, LabelScopeKind kind)
 {
     Parent = parent;
     Kind   = kind;
 }
        private void ValidateJump(LabelScopeInfo reference)
        {
            // Assume we can do a ret/branch
            _opCode = _canReturn ? OpCodes.Ret : OpCodes.Br;

            // look for a simple jump out
            for (var j = reference; j != null; j = j.Parent)
            {
                if (_definitions.Contains(j))
                {
                    // found it, jump is valid!
                    return;
                }
                if (j.Kind == LabelScopeKind.Finally ||
                    j.Kind == LabelScopeKind.Filter)
                {
                    break;
                }
                if (j.Kind == LabelScopeKind.Try ||
                    j.Kind == LabelScopeKind.Catch)
                {
                    _opCode = OpCodes.Leave;
                }
            }

            _acrossBlockJump = true;
            if (_node != null && _node.Type != typeof(void))
            {
                throw Error.NonLocalJumpWithValue(_node.Name);
            }

            if (_definitions.Count > 1)
            {
                throw Error.AmbiguousJump(_node.Name);
            }

            // We didn't find an outward jump. Look for a jump across blocks
            var def    = _definitions.First();
            var common = Helpers.CommonNode(def, reference, b => b.Parent);

            // Assume we can do a ret/branch
            _opCode = _canReturn ? OpCodes.Ret : OpCodes.Br;

            // Validate that we aren't jumping across a finally
            for (var j = reference; j != common; j = j.Parent)
            {
                if (j.Kind == LabelScopeKind.Finally)
                {
                    throw Error.ControlCannotLeaveFinally();
                }
                if (j.Kind == LabelScopeKind.Filter)
                {
                    throw Error.ControlCannotLeaveFilterTest();
                }
                if (j.Kind == LabelScopeKind.Try ||
                    j.Kind == LabelScopeKind.Catch)
                {
                    _opCode = OpCodes.Leave;
                }
            }

            // Validate that we aren't jumping into a catch or an expression
            for (var j = def; j != common; j = j.Parent)
            {
                if (!j.CanJumpInto)
                {
                    if (j.Kind == LabelScopeKind.Expression)
                    {
                        throw Error.ControlCannotEnterExpression();
                    }
                    else
                    {
                        throw Error.ControlCannotEnterTry();
                    }
                }
            }
        }