Files
2026-08-27 10:56:38 -06:00

204 lines
6.9 KiB
C#

using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Diagnostics;
using System.Linq;
using Microsoft.CodeAnalysis.CSharp.Symbols;
using Microsoft.CodeAnalysis.PooledObjects;
using Microsoft.CodeAnalysis.Shared.Collections;
using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis.CSharp;
internal sealed class BoundDecisionDag : BoundNode
{
private ImmutableHashSet<LabelSymbol> _reachableLabels;
private ImmutableArray<BoundDecisionDagNode> _topologicallySortedNodes;
public ImmutableHashSet<LabelSymbol> ReachableLabels
{
get
{
if (_reachableLabels == null)
{
ImmutableHashSet<LabelSymbol>.Builder builder = ImmutableHashSet.CreateBuilder((IEqualityComparer<LabelSymbol>?)SymbolEqualityComparer.ConsiderEverything);
ImmutableArray<BoundDecisionDagNode>.Enumerator enumerator = TopologicallySortedNodes.GetEnumerator();
while (enumerator.MoveNext())
{
if (enumerator.Current is BoundLeafDecisionDagNode boundLeafDecisionDagNode)
{
builder.Add(boundLeafDecisionDagNode.Label);
}
}
_reachableLabels = builder.ToImmutableHashSet();
}
return _reachableLabels;
}
}
public ImmutableArray<BoundDecisionDagNode> TopologicallySortedNodes
{
get
{
if (_topologicallySortedNodes.IsDefault)
{
TopologicalSort.TryIterativeSort<BoundDecisionDagNode>(RootNode, (TopologicalSortAddSuccessors<BoundDecisionDagNode>)AddSuccessors, ref _topologicallySortedNodes);
}
return _topologicallySortedNodes;
}
}
public BoundDecisionDagNode RootNode { get; }
internal static void AddSuccessors(ref TemporaryArray<BoundDecisionDagNode> builder, BoundDecisionDagNode node)
{
if (!(node is BoundEvaluationDecisionDagNode boundEvaluationDecisionDagNode))
{
if (!(node is BoundTestDecisionDagNode boundTestDecisionDagNode))
{
if (!(node is BoundLeafDecisionDagNode))
{
if (!(node is BoundWhenDecisionDagNode boundWhenDecisionDagNode))
{
throw ExceptionUtilities.UnexpectedValue((object)node.Kind);
}
builder.Add(boundWhenDecisionDagNode.WhenTrue);
TemporaryArrayExtensions.AddIfNotNull<BoundDecisionDagNode>(ref builder, boundWhenDecisionDagNode.WhenFalse);
}
}
else
{
builder.Add(boundTestDecisionDagNode.WhenFalse);
builder.Add(boundTestDecisionDagNode.WhenTrue);
}
}
else
{
builder.Add(boundEvaluationDecisionDagNode.Next);
}
}
public BoundDecisionDag Rewrite(Func<BoundDecisionDagNode, IReadOnlyDictionary<BoundDecisionDagNode, BoundDecisionDagNode>, BoundDecisionDagNode> makeReplacement)
{
ImmutableArray<BoundDecisionDagNode> topologicallySortedNodes = TopologicallySortedNodes;
PooledDictionary<BoundDecisionDagNode, BoundDecisionDagNode> instance = PooledDictionary<BoundDecisionDagNode, BoundDecisionDagNode>.GetInstance();
for (int num = topologicallySortedNodes.Length - 1; num >= 0; num--)
{
BoundDecisionDagNode boundDecisionDagNode = topologicallySortedNodes[num];
BoundDecisionDagNode value = makeReplacement(boundDecisionDagNode, (IReadOnlyDictionary<BoundDecisionDagNode, BoundDecisionDagNode>)instance);
((Dictionary<BoundDecisionDagNode, BoundDecisionDagNode>)(object)instance).Add(boundDecisionDagNode, value);
}
BoundDecisionDagNode rootNode = ((Dictionary<BoundDecisionDagNode, BoundDecisionDagNode>)(object)instance)[RootNode];
instance.Free();
return Update(rootNode);
}
public static BoundDecisionDagNode TrivialReplacement(BoundDecisionDagNode dag, IReadOnlyDictionary<BoundDecisionDagNode, BoundDecisionDagNode> replacement)
{
if (!(dag is BoundEvaluationDecisionDagNode boundEvaluationDecisionDagNode))
{
if (!(dag is BoundTestDecisionDagNode boundTestDecisionDagNode))
{
if (!(dag is BoundWhenDecisionDagNode boundWhenDecisionDagNode))
{
if (dag is BoundLeafDecisionDagNode result)
{
return result;
}
throw ExceptionUtilities.UnexpectedValue((object)dag);
}
return boundWhenDecisionDagNode.Update(boundWhenDecisionDagNode.Bindings, boundWhenDecisionDagNode.WhenExpression, replacement[boundWhenDecisionDagNode.WhenTrue], (boundWhenDecisionDagNode.WhenFalse != null) ? replacement[boundWhenDecisionDagNode.WhenFalse] : null);
}
return boundTestDecisionDagNode.Update(boundTestDecisionDagNode.Test, replacement[boundTestDecisionDagNode.WhenTrue], replacement[boundTestDecisionDagNode.WhenFalse]);
}
return boundEvaluationDecisionDagNode.Update(boundEvaluationDecisionDagNode.Evaluation, replacement[boundEvaluationDecisionDagNode.Next]);
}
public BoundDecisionDag SimplifyDecisionDagIfConstantInput(BoundExpression input)
{
if (input.ConstantValueOpt == (ConstantValue)null)
{
return this;
}
ConstantValue inputConstant = input.ConstantValueOpt;
return Rewrite(makeReplacement);
bool? knownResult(BoundDagTest choice)
{
if (!choice.Input.IsOriginalInput)
{
return null;
}
if (choice is BoundDagExplicitNullTest)
{
return inputConstant.IsNull;
}
if (choice is BoundDagNonNullTest)
{
return !inputConstant.IsNull;
}
if (choice is BoundDagValueTest boundDagValueTest)
{
return boundDagValueTest.Value == inputConstant;
}
if (choice is BoundDagTypeTest)
{
if (!inputConstant.IsNull)
{
return null;
}
return false;
}
if (choice is BoundDagRelationalTest boundDagRelationalTest)
{
return ValueSetFactory.ForType(input.Type)?.Related(boundDagRelationalTest.Relation.Operator(), inputConstant, boundDagRelationalTest.Value);
}
throw ExceptionUtilities.UnexpectedValue((object)choice);
}
BoundDecisionDagNode makeReplacement(BoundDecisionDagNode dag, IReadOnlyDictionary<BoundDecisionDagNode, BoundDecisionDagNode> replacement)
{
if (dag is BoundTestDecisionDagNode boundTestDecisionDagNode)
{
bool? flag = knownResult(boundTestDecisionDagNode.Test);
if (flag.HasValue)
{
if (flag == true)
{
return replacement[boundTestDecisionDagNode.WhenTrue];
}
return replacement[boundTestDecisionDagNode.WhenFalse];
}
}
return TrivialReplacement(dag, replacement);
}
}
public bool ContainsAnySynthesizedNodes()
{
return TopologicallySortedNodes.Any((BoundDecisionDagNode node) => node is BoundEvaluationDecisionDagNode boundEvaluationDecisionDagNode && boundEvaluationDecisionDagNode.Evaluation.Kind == BoundKind.DagAssignmentEvaluation);
}
public BoundDecisionDag(SyntaxNode syntax, BoundDecisionDagNode rootNode, bool hasErrors = false)
: base(BoundKind.DecisionDag, syntax, hasErrors || rootNode.HasErrors())
{
RootNode = rootNode;
}
[DebuggerStepThrough]
public override BoundNode? Accept(BoundTreeVisitor visitor)
{
return visitor.VisitDecisionDag(this);
}
public BoundDecisionDag Update(BoundDecisionDagNode rootNode)
{
if (rootNode != RootNode)
{
BoundDecisionDag boundDecisionDag = new BoundDecisionDag(Syntax, rootNode, base.HasErrors);
boundDecisionDag.CopyAttributes(this);
return boundDecisionDag;
}
return this;
}
}