/// <summary>
        /// Generate a list containing the given field and all dependencies
        /// of that field that require evaluation. The list is ordered by
        /// dependencies, with fields with no dependencies first. Cycles are
        /// broken at the first field lexically in the cycle. If multiple threads
        /// call this method with the same field, the order of the fields
        /// returned should be the same, although some fields may be missing
        /// from the lists in some threads as other threads evaluate fields.
        /// </summary>
        internal static void OrderAllDependencies(
            this SourceFieldSymbol field,
            ArrayBuilder <FieldInfo> order,
            bool earlyDecodingWellKnownAttributes)
        {
            Debug.Assert(order.Count == 0);

            var graph = PooledDictionary <SourceFieldSymbol, Node <SourceFieldSymbol> > .GetInstance();

            CreateGraph(graph, field, earlyDecodingWellKnownAttributes);

            Debug.Assert(graph.Count >= 1);
            CheckGraph(graph);

#if DEBUG
            var fields = ArrayBuilder <SourceFieldSymbol> .GetInstance();

            fields.AddRange(graph.Keys);
#endif

            OrderGraph(graph, order);

#if DEBUG
            // Verify all entries in the graph are in the ordered list.
            var map = new HashSet <SourceFieldSymbol>(order.Select(o => o.Field).Distinct());
            Debug.Assert(fields.All(f => map.Contains(f)));
            fields.Free();
#endif

            graph.Free();
        }
Beispiel #2
0
        public static ConstantValue EvaluateFieldConstant(
            SourceFieldSymbol symbol,
            EqualsValueClauseSyntax equalsValueNode,
            HashSet <SourceFieldSymbolWithSyntaxReference> dependencies,
            bool earlyDecodingWellKnownAttributes,
            BindingDiagnosticBag diagnostics)
        {
            var compilation   = symbol.DeclaringCompilation;
            var binderFactory = compilation.GetBinderFactory((SyntaxTree)symbol.Locations[0].SourceTree);
            var binder        = binderFactory.GetBinder(equalsValueNode);

            if (earlyDecodingWellKnownAttributes)
            {
                binder = new EarlyWellKnownAttributeBinder(binder);
            }
            var inProgressBinder             = new ConstantFieldsInProgressBinder(new ConstantFieldsInProgress(symbol, dependencies), binder);
            BoundFieldEqualsValue boundValue = BindFieldOrEnumInitializer(inProgressBinder, symbol, equalsValueNode, diagnostics);
            var initValueNodeLocation        = equalsValueNode.Value.Location;

            var value = GetAndValidateConstantValue(boundValue.Value, symbol, symbol.Type, initValueNodeLocation, diagnostics);

            Debug.Assert(value != null);

            return(value);
        }
        private static void GetAllReachable(
            Dictionary <SourceFieldSymbol, Node <SourceFieldSymbol> > graph,
            ArrayBuilder <SourceFieldSymbol> fields,
            SourceFieldSymbol field)
        {
            Debug.Assert(fields.Count == 0);

            var set = PooledHashSet <SourceFieldSymbol> .GetInstance();

            var stack = ArrayBuilder <SourceFieldSymbol> .GetInstance();

            set.Add(field);
            stack.Push(field);

            while (stack.Count > 0)
            {
                field = stack.Pop();
                var node = graph[field];

                foreach (var dependency in node.Dependencies)
                {
                    if (!set.Contains(dependency))
                    {
                        set.Add(dependency);
                        stack.Push(dependency);
                    }
                }
            }

            fields.AddRange(set);
            stack.Free();
            set.Free();
        }
 internal ConstantFieldsInProgress(
     SourceFieldSymbol fieldOpt,
     HashSet<SourceFieldSymbol> dependencies)
 {
     this.fieldOpt = fieldOpt;
     this.dependencies = dependencies;
 }
 internal ConstantFieldsInProgress(
     SourceFieldSymbol fieldOpt,
     HashSet<SourceFieldSymbolWithSyntaxReference> dependencies)
 {
     _fieldOpt = fieldOpt;
     _dependencies = dependencies;
 }
        /// <summary>
        /// Build a dependency graph (a map from
        /// field to dependencies).
        /// </summary>
        private static void CreateGraph(
            Dictionary <SourceFieldSymbol, Node <SourceFieldSymbol> > graph,
            SourceFieldSymbol field,
            bool earlyDecodingWellKnownAttributes)
        {
            var pending = ArrayBuilder <SourceFieldSymbol> .GetInstance();

            pending.Push(field);

            while (pending.Count > 0)
            {
                field = pending.Pop();

                Node <SourceFieldSymbol> node;
                if (graph.TryGetValue(field, out node))
                {
                    if (node.Dependencies != null)
                    {
                        // Already visited node.
                        continue;
                    }
                }
                else
                {
                    node = new Node <SourceFieldSymbol>();
                    node.DependedOnBy = ImmutableHashSet <SourceFieldSymbol> .Empty;
                }

                var dependencies = field.GetConstantValueDependencies(earlyDecodingWellKnownAttributes);
                // GetConstantValueDependencies will return an empty set if
                // the constant value has already been calculated. That avoids
                // calculating the full graph repeatedly. For instance with
                // "enum E { M0 = 0, M1 = M0 + 1, ..., Mn = Mn-1 + 1 }", we'll calculate
                // the graph M0, ..., Mi for the first field we evaluate, Mi. But for
                // the next field, Mj, we should only calculate the graph Mi, ..., Mj.
                node.Dependencies = dependencies;
                graph[field]      = node;

                foreach (var dependency in dependencies)
                {
                    pending.Push(dependency);

                    if (!graph.TryGetValue(dependency, out node))
                    {
                        node = new Node <SourceFieldSymbol>();
                        node.DependedOnBy = ImmutableHashSet <SourceFieldSymbol> .Empty;
                    }

                    node.DependedOnBy = node.DependedOnBy.Add(field);
                    graph[dependency] = node;
                }
            }

            pending.Free();
        }
        public static ConstantValue EvaluateFieldConstant(
            SourceFieldSymbol symbol,
            EqualsValueClauseSyntax equalsValueNode,
            HashSet<SourceFieldSymbolWithSyntaxReference> dependencies,
            bool earlyDecodingWellKnownAttributes,
            DiagnosticBag diagnostics)
        {
            var compilation = symbol.DeclaringCompilation;
            var binderFactory = compilation.GetBinderFactory((SyntaxTree)symbol.Locations[0].SourceTree);
            var binder = binderFactory.GetBinder(equalsValueNode);
            if (earlyDecodingWellKnownAttributes)
            {
                binder = new EarlyWellKnownAttributeBinder(binder);
            }
            var inProgressBinder = new ConstantFieldsInProgressBinder(new ConstantFieldsInProgress(symbol, dependencies), binder);
            var boundValue = BindFieldOrEnumInitializer(inProgressBinder, symbol, equalsValueNode, diagnostics);
            var initValueNodeLocation = equalsValueNode.Value.Location;

            var value = GetAndValidateConstantValue(boundValue, symbol, symbol.Type, initValueNodeLocation, diagnostics);
            Debug.Assert(value != null);

            return value;
        }
 public FieldInfo(SourceFieldSymbol field, bool startsCycle)
 {
     this.Field       = field;
     this.StartsCycle = startsCycle;
 }
 internal void AddDependency(SourceFieldSymbol field)
 {
     this.dependencies.Add(field);
 }