private void ValidateJump(LabelScopeInfo reference)
        {
            // look for a simple jump out
            for (LabelScopeInfo?j = reference; j != null; j = j.Parent)
            {
                if (DefinedIn(j))
                {
                    // found it, jump is valid!
                    return;
                }
                if (j.Kind == LabelScopeKind.Finally || j.Kind == LabelScopeKind.Filter)
                {
                    break;
                }
            }

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

            if (HasMultipleDefinitions)
            {
                throw Error.AmbiguousJump(_node !.Name);
            }

            // We didn't find an outward jump. Look for a jump across blocks
            LabelScopeInfo def    = FirstDefinition();
            LabelScopeInfo?common = CommonNode(def, reference, b => b.Parent !);

            // Validate that we aren't jumping across a finally
            for (LabelScopeInfo?j = reference; j != common; j = j.Parent)
            {
                if (j !.Kind == LabelScopeKind.Finally)
                {
                    throw Error.ControlCannotLeaveFinally();
                }
                if (j.Kind == LabelScopeKind.Filter)
                {
                    throw Error.ControlCannotLeaveFilterTest();
                }
            }

            // Validate that we aren't jumping into a catch or an expression
            for (LabelScopeInfo?j = def; j != common; j = j.Parent)
            {
                if (!j !.CanJumpInto)
                {
                    if (j.Kind == LabelScopeKind.Expression)
                    {
                        throw Error.ControlCannotEnterExpression();
                    }
                    else
                    {
                        throw Error.ControlCannotEnterTry();
                    }
                }
            }
        }
示例#2
0
 internal void Reference(LabelScopeInfo block)
 {
     _references.Add(block);
     if (HasDefinitions)
     {
         ValidateJump(block);
     }
 }
示例#3
0
        private void ValidateJump(LabelScopeInfo reference)
        {
            // look for a simple jump out
            for (var j = reference; j != null; j = j.Parent)
            {
                if (DefinedIn(j))
                {
                    // found it, jump is valid!
                    return;
                }
                if (j.Kind == LabelScopeKind.Finally || j.Kind == LabelScopeKind.Filter)
                {
                    break;
                }
            }

            _acrossBlockJump = true;

            if (HasMultipleDefinitions)
            {
                throw new InvalidOperationException(string.Format(CultureInfo.InvariantCulture, "Ambiguous jump {0}", _node.Name));
            }

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

            // Validate that we aren't jumping across a finally
            for (var j = reference; j != common; j = j.Parent)
            {
                if (j.Kind == LabelScopeKind.Finally)
                {
                    throw new InvalidOperationException("Control cannot leave finally");
                }
                if (j.Kind == LabelScopeKind.Filter)
                {
                    throw new InvalidOperationException("Control cannot leave filter test");
                }
            }

            // Valdiate 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 new InvalidOperationException("Control cannot enter an expression");
                    }
                    else
                    {
                        throw new InvalidOperationException("Control cannot enter try");
                    }
                }
            }
        }
        private bool DefinedIn(LabelScopeInfo scope)
        {
            if (_definitions == scope)
            {
                return(true);
            }

            if (_definitions is HashSet <LabelScopeInfo> definitions)
            {
                return(definitions.Contains(scope));
            }
            return(false);
        }
示例#5
0
        private LabelScopeInfo FirstDefinition()
        {
            LabelScopeInfo scope = _definitions as LabelScopeInfo;

            if (scope != null)
            {
                return(scope);
            }
            foreach (var x in (HashSet <LabelScopeInfo>)_definitions)
            {
                return(x);
            }
            throw new InvalidOperationException();
        }
示例#6
0
        private bool DefinedIn(LabelScopeInfo scope)
        {
            if (_definitions == scope)
            {
                return(true);
            }

            var definitions = _definitions as HashSet <LabelScopeInfo>;

            if (definitions != null)
            {
                return(definitions.Contains(scope));
            }
            return(false);
        }
示例#7
0
 private void AddDefinition(LabelScopeInfo scope)
 {
     if (_definitions == null)
     {
         _definitions = scope;
     }
     else
     {
         if (!(_definitions is HashSet <LabelScopeInfo> set))
         {
             _definitions = set = new HashSet <LabelScopeInfo> {
                 (LabelScopeInfo)_definitions
             };
         }
         set.Add(scope);
     }
 }
示例#8
0
 private void AddDefinition(LabelScopeInfo scope)
 {
     if (_definitions == null)
     {
         _definitions = scope;
     }
     else
     {
         var set = _definitions as HashSet <LabelScopeInfo>;
         if (set == null)
         {
             _definitions = set = new HashSet <LabelScopeInfo> {
                 (LabelScopeInfo)_definitions
             };
         }
         set.Add(scope);
     }
 }
示例#9
0
        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 new InvalidOperationException($"Cannot redefine label '{_node.Name}' in an inner block.");
                }
            }

            AddDefinition(block);
            block.AddLabelInfo(_node, this);

            // Once defined, validate all jumps
            if (HasDefinitions && !HasMultipleDefinitions)
            {
                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 new InvalidOperationException($"Cannot jump to ambiguous label '{_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
                _label = null;
            }
        }
示例#10
0
        private HybridReferenceDictionary <LabelTarget, LabelInfo> _labels; // lazily allocated, we typically use this only once every 6th-7th block

        internal LabelScopeInfo(LabelScopeInfo parent, LabelScopeKind kind)
        {
            Parent = parent;
            Kind   = kind;
        }
示例#11
0
        private void ValidateJump(LabelScopeInfo reference)
        {
            // look for a simple jump out
            for (var j = reference; j != null; j = j.Parent)
            {
                if (DefinedIn(j))
                {
                    // found it, jump is valid!
                    return;
                }

                if (j.Kind == LabelScopeKind.Finally || j.Kind == LabelScopeKind.Filter)
                {
                    break;
                }
            }

            _acrossBlockJump = true;
            if (_node != null && _node.Type != typeof(void))
            {
                throw new InvalidOperationException($"Cannot jump to non-local label '{_node.Name}' with a value. Only jumps to labels defined in outer blocks can pass values.");
            }

            if (HasMultipleDefinitions)
            {
                throw new InvalidOperationException($"Cannot jump to ambiguous label '{_node?.Name}'.");
            }

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

            // Validate that we aren't jumping across a finally
            for (var j = reference; j != common; j = j.Parent)
            {
                switch (j.Kind)
                {
                case LabelScopeKind.Finally:
                    throw new InvalidOperationException("Control cannot leave a finally block.");

                case LabelScopeKind.Filter:
                    throw new InvalidOperationException("Control cannot leave a filter test.");

                default:
                    break;
                }
            }

            // Validate that we aren't jumping into a catch or an expression
            for (var j = def; j != common; j = j.Parent)
            {
                if (j.CanJumpInto)
                {
                    continue;
                }

                if (j.Kind == LabelScopeKind.Expression)
                {
                    throw new InvalidOperationException("Control cannot enter an expression--only statements can be jumped into.");
                }

                throw new InvalidOperationException("Control cannot enter a try block.");
            }
        }
示例#12
0
 public LabelScopeChangeInfo(LabelScopeInfo parent, LabelScopeKind kind, IList <Expression>?nodes)
 {
     Parent = parent;
     Kind   = kind;
     Nodes  = nodes;
 }