private static int AddFlow(NullabilityNode node, NullabilityNode sink, int maxNewFlow)
 {
     if (maxNewFlow == 0 || node.Visited)
     {
         return(0);
     }
     node.Visited = true;
     if (node == sink)
     {
         return(maxNewFlow);
     }
     foreach (NullabilityEdge edge in node.OutgoingEdges)
     {
         int newFlow = AddFlow(edge.Target, sink, Math.Min(maxNewFlow, edge.Capacity));
         if (newFlow > 0)
         {
             edge.Capacity        -= newFlow;
             edge.ReverseCapacity += newFlow;
             return(newFlow);
         }
     }
     foreach (NullabilityEdge edge in node.IncomingEdges)
     {
         int newFlow = AddFlow(edge.Source, sink, Math.Min(maxNewFlow, edge.ReverseCapacity));
         if (newFlow > 0)
         {
             edge.ReverseCapacity -= newFlow;
             edge.Capacity        += newFlow;
             return(newFlow);
         }
     }
     return(0);
 }
        private TypeWithNode(ITypeSymbol?type, NullabilityNode node, IReadOnlyList <TypeWithNode>?typeArguments, string?flowLabel)
            : this(type, node, typeArguments)
        {
#if DEBUG
            this.FlowLabel = flowLabel;
#endif
        }
 public TypeWithNode(ITypeSymbol?type, NullabilityNode node, IReadOnlyList <TypeWithNode>?typeArguments = null)
 {
     this.Type          = type;
     this.Node          = node;
     this.TypeArguments = typeArguments ?? emptyTypeArguments;
     Debug.Assert(this.TypeArguments.Count == type.FullArity());
 }
        private static bool AddFlow(NullabilityNode node, NullabilityNode source)
        {
            if (node.Visited)
            {
                return(false);
            }
            node.Visited = true;
            if (node == source)
            {
                return(true);
            }
            var predecessors = node.ResidualGraphPredecessors;

            for (int i = 0; i < predecessors.Count; i++)
            {
                var prevNode = predecessors[i];
                if (AddFlow(prevNode, source))
                {
                    // Remove the edge from the residual graph
                    predecessors.SwapRemoveAt(i);
                    // and instead add the reverse edge
                    prevNode.ResidualGraphPredecessors.Add(node);
                    return(true);
                }
            }
            return(false);
        }
 private void InferNullable(NullabilityNode node)
 {
     Debug.Assert(node.NullType == NullType.Infer || node.NullType == NullType.Nullable);
     node.NullType = NullType.Nullable;
     foreach (var edge in node.OutgoingEdges)
     {
         if (edge.Target.NullType == NullType.Infer)
         {
             InferNullable(edge.Target);
         }
     }
 }
 private void InferNonNull(NullabilityNode node)
 {
     Debug.Assert(node.NullType == NullType.Infer || node.NullType == NullType.NonNull);
     node.NullType = NullType.NonNull;
     foreach (var edge in node.IncomingEdges)
     {
         if (edge.Source.NullType == NullType.Infer)
         {
             InferNonNull(edge.Source);
         }
     }
 }
 private void InferNonNullUsingResidualGraph(NullabilityNode node)
 {
     Debug.Assert(node.NullType == NullType.Infer || node.NullType == NullType.NonNull);
     node.NullType = NullType.NonNull;
     foreach (var pred in node.ResidualGraphPredecessors)
     {
         if (pred.NullType == NullType.Infer)
         {
             InferNonNullUsingResidualGraph(pred);
         }
     }
 }
        public static int Compute(IEnumerable <NullabilityNode> allNodes, NullabilityNode source, NullabilityNode sink, CancellationToken cancellationToken)
        {
            Debug.Assert(source != sink);
            int maxFlow = 0;

            ResetVisited(allNodes);
            while (AddFlow(sink, source))
            {
                cancellationToken.ThrowIfCancellationRequested();
                maxFlow += 1;
                ResetVisited(allNodes);
            }
            return(maxFlow);
        }
        public static int Compute(IEnumerable <NullabilityNode> allTypes, NullabilityNode source, NullabilityNode sink, CancellationToken cancellationToken)
        {
            Debug.Assert(source != sink);
            int maxFlow = 0;
            int newFlow;

            ResetVisited(allTypes);
            while ((newFlow = AddFlow(source, sink, int.MaxValue)) > 0)
            {
                cancellationToken.ThrowIfCancellationRequested();
                maxFlow += newFlow;
                ResetVisited(allTypes);
            }
            return(maxFlow);
        }
 private void InferNullable(NullabilityNode node, bool ignoreEdgesWithoutCapacity = false)
 {
     if (node.NullType != NullType.Infer)
     {
         return;
     }
     node.NullType = NullType.Nullable;
     foreach (var edge in node.OutgoingEdges)
     {
         if (ignoreEdgesWithoutCapacity == false || edge.Capacity > 0)
         {
             InferNullable(edge.Target, ignoreEdgesWithoutCapacity);
         }
     }
 }
 private void InferNonNull(NullabilityNode node, bool ignoreEdgesWithoutCapacity = false)
 {
     if (node.NullType != NullType.Infer)
     {
         return;
     }
     node.NullType = NullType.NonNull;
     foreach (var edge in node.IncomingEdges)
     {
         if (ignoreEdgesWithoutCapacity == false || edge.Capacity > 0)
         {
             InferNonNull(edge.Source, ignoreEdgesWithoutCapacity);
         }
     }
 }
 /// <summary>
 /// Replace with node with another node.
 /// All future attempts to create an edge involving this node, will instead create an edge with the other node.
 /// This method can only be used in the NodeBuilding phase, as otherwise there might already be edges registered;
 /// which will not be re-pointed.
 /// </summary>
 internal void ReplaceWith(NullabilityNode other)
 {
     if (this.replacement != null)
     {
         this.replacement.ReplaceWith(other);
         return;
     }
     while (other.replacement != null)
     {
         other = other.replacement;
     }
     Debug.Assert(this.NullType == other.NullType || this.NullType == NullType.Infer || other.NullType == NullType.Infer);
     // Replacements must be performed before the edges are registered.
     Debug.Assert(this.IncomingEdges.Count == 0);
     Debug.Assert(this.OutgoingEdges.Count == 0);
     this.replacement = other;
 }
Пример #13
0
        public void SetNode(AccessPath path, NullabilityNode newNode, bool clearMembers)
        {
            switch (path.Root)
            {
            case AccessPathRoot.This:
                thisPath = Visit(thisPath, 0);
                break;

            case AccessPathRoot.Local:
                if (!locals.TryGetValue(path.Symbols[0], out var localPathNode))
                {
                    localPathNode = new PathNode(typeSystem.NonNullNode, emptyMembers);
                }
                localPathNode           = Visit(localPathNode, 1);
                locals[path.Symbols[0]] = localPathNode;
                break;

            default:
                throw new NotSupportedException();
            }

            PathNode Visit(PathNode input, int index)
            {
                if (index == path.Symbols.Length)
                {
                    if (clearMembers)
                    {
                        return(new PathNode(newNode, emptyMembers));
                    }
                    else
                    {
                        return(new PathNode(newNode, input.Members));
                    }
                }
                var member = path.Symbols[index];

                if (!input.Members.TryGetValue(member, out var childNode))
                {
                    childNode = new PathNode(typeSystem.NonNullNode, emptyMembers);
                }
                childNode = Visit(childNode, index + 1);
                return(new PathNode(typeSystem.NonNullNode, input.Members.SetItem(member, childNode)));
            }
        }
Пример #14
0
 public PathNode(NullabilityNode nullability, ImmutableDictionary <ISymbol, PathNode> members)
 {
     this.Nullability = nullability;
     this.Members     = members;
 }
Пример #15
0
 public SpecialNodes(NullabilityNode nullableNode, NullabilityNode nonNullNode, NullabilityNode obliviousNode)
 {
     this.NullableNode  = nullableNode;
     this.NonNullNode   = nonNullNode;
     this.ObliviousNode = obliviousNode;
 }
 /// <summary>
 /// Replaces the top-level nullability.
 /// </summary>
 internal TypeWithNode WithNode(NullabilityNode newNode)
 {
     return(new TypeWithNode(Type, newNode, TypeArguments));
 }
 /// <summary>
 /// Represents the subtype relation "subType &lt;: superType".
 /// This means that values of type subType can be assigned to variables of type superType.
 /// </summary>
 public NullabilityEdge(NullabilityNode source, NullabilityNode target)
 {
     this.Source = source ?? throw new ArgumentNullException(nameof(source));
     this.Target = target ?? throw new ArgumentNullException(nameof(target));
 }
 internal TypeWithNode WithFlowState(NullabilityNode flowNode, string?flowLabel)
 {
     return(new TypeWithNode(Type, flowNode, TypeArguments, flowLabel));
 }