804 lines
29 KiB
C#
804 lines
29 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Collections.Immutable;
|
|
using System.Linq;
|
|
using System.Text;
|
|
using Microsoft.CodeAnalysis.CSharp.Symbols;
|
|
using Microsoft.CodeAnalysis.PooledObjects;
|
|
using Roslyn.Utilities;
|
|
|
|
namespace Microsoft.CodeAnalysis.CSharp;
|
|
|
|
internal static class PatternExplainer
|
|
{
|
|
private class NoRemainingValuesException : Exception
|
|
{
|
|
}
|
|
|
|
private static ImmutableArray<BoundDecisionDagNode> ShortestPathToNode(ImmutableArray<BoundDecisionDagNode> nodes, BoundDecisionDagNode node, bool nullPaths, out bool requiresFalseWhenClause)
|
|
{
|
|
PooledDictionary<BoundDecisionDagNode, (int distance, BoundDecisionDagNode next)> dist = PooledDictionary<BoundDecisionDagNode, (int, BoundDecisionDagNode)>.GetInstance();
|
|
int length = nodes.Length;
|
|
int infinity = 2 * length + 2;
|
|
PooledDictionary<BoundDecisionDagNode, (int, BoundDecisionDagNode)> val;
|
|
BoundDecisionDagNode key;
|
|
(int, BoundDecisionDagNode) value;
|
|
for (int num = length - 1; num >= 0; ((Dictionary<BoundDecisionDagNode, (int, BoundDecisionDagNode)>)(object)val).Add(key, value), num--)
|
|
{
|
|
BoundDecisionDagNode boundDecisionDagNode = nodes[num];
|
|
val = dist;
|
|
key = boundDecisionDagNode;
|
|
BoundDecisionDagNode boundDecisionDagNode2 = boundDecisionDagNode;
|
|
if (!(boundDecisionDagNode2 is BoundEvaluationDecisionDagNode boundEvaluationDecisionDagNode))
|
|
{
|
|
if (boundDecisionDagNode2 is BoundTestDecisionDagNode boundTestDecisionDagNode)
|
|
{
|
|
BoundDagTest test = boundTestDecisionDagNode.Test;
|
|
if (!(test is BoundDagNonNullTest))
|
|
{
|
|
if (test is BoundDagExplicitNullTest)
|
|
{
|
|
BoundTestDecisionDagNode boundTestDecisionDagNode2 = boundTestDecisionDagNode;
|
|
if (!nullPaths)
|
|
{
|
|
value = (1 + distance(boundTestDecisionDagNode2.WhenFalse), boundTestDecisionDagNode2.WhenFalse);
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
BoundTestDecisionDagNode boundTestDecisionDagNode3 = boundTestDecisionDagNode;
|
|
if (!nullPaths)
|
|
{
|
|
value = (1 + distance(boundTestDecisionDagNode3.WhenTrue), boundTestDecisionDagNode3.WhenTrue);
|
|
continue;
|
|
}
|
|
}
|
|
BoundTestDecisionDagNode boundTestDecisionDagNode4 = boundTestDecisionDagNode;
|
|
int num2 = distance(boundTestDecisionDagNode4.WhenTrue);
|
|
int num3 = distance(boundTestDecisionDagNode4.WhenFalse);
|
|
value = ((num2 <= num3) ? (1 + num2, boundTestDecisionDagNode4.WhenTrue) : (1 + num3, boundTestDecisionDagNode4.WhenFalse));
|
|
}
|
|
else if (boundDecisionDagNode2 is BoundWhenDecisionDagNode boundWhenDecisionDagNode)
|
|
{
|
|
BoundWhenDecisionDagNode boundWhenDecisionDagNode2 = boundWhenDecisionDagNode;
|
|
int num4 = distance(boundWhenDecisionDagNode2.WhenTrue);
|
|
int num5 = distance(boundWhenDecisionDagNode2.WhenFalse);
|
|
value = ((num4 <= num5) ? (1 + num4, boundWhenDecisionDagNode2.WhenTrue) : (1 + ((num5 < length) ? length : 0) + num5, boundWhenDecisionDagNode2.WhenFalse));
|
|
}
|
|
else
|
|
{
|
|
value = ((boundDecisionDagNode == node) ? 1 : infinity, null);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
BoundEvaluationDecisionDagNode boundEvaluationDecisionDagNode2 = boundEvaluationDecisionDagNode;
|
|
value = (distance(boundEvaluationDecisionDagNode2.Next), boundEvaluationDecisionDagNode2.Next);
|
|
}
|
|
}
|
|
int item = ((Dictionary<BoundDecisionDagNode, (int, BoundDecisionDagNode)>)(object)dist)[nodes[0]].Item1;
|
|
requiresFalseWhenClause = item > length;
|
|
ArrayBuilder<BoundDecisionDagNode> instance = ArrayBuilder<BoundDecisionDagNode>.GetInstance(item);
|
|
BoundDecisionDagNode boundDecisionDagNode3 = nodes[0];
|
|
while (boundDecisionDagNode3 != node)
|
|
{
|
|
instance.Add(boundDecisionDagNode3);
|
|
if (!(boundDecisionDagNode3 is BoundEvaluationDecisionDagNode boundEvaluationDecisionDagNode3))
|
|
{
|
|
if (!(boundDecisionDagNode3 is BoundTestDecisionDagNode key2))
|
|
{
|
|
if (!(boundDecisionDagNode3 is BoundWhenDecisionDagNode boundWhenDecisionDagNode3))
|
|
{
|
|
throw ExceptionUtilities.Unreachable("/_/src/Compilers/CSharp/Portable/Binder/PatternExplainer.cs", 93);
|
|
}
|
|
instance.RemoveLast();
|
|
boundDecisionDagNode3 = boundWhenDecisionDagNode3.WhenFalse;
|
|
}
|
|
else
|
|
{
|
|
boundDecisionDagNode3 = ((Dictionary<BoundDecisionDagNode, (int, BoundDecisionDagNode)>)(object)dist)[(BoundDecisionDagNode)key2].Item2;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
boundDecisionDagNode3 = boundEvaluationDecisionDagNode3.Next;
|
|
}
|
|
}
|
|
dist.Free();
|
|
return instance.ToImmutableAndFree();
|
|
int distance(BoundDecisionDagNode x)
|
|
{
|
|
if (x == null)
|
|
{
|
|
return infinity;
|
|
}
|
|
if (((Dictionary<BoundDecisionDagNode, (int, BoundDecisionDagNode)>)(object)dist).TryGetValue(x, out (int, BoundDecisionDagNode) value2))
|
|
{
|
|
return value2.Item1;
|
|
}
|
|
return infinity;
|
|
}
|
|
}
|
|
|
|
private static void VisitPathsToNode(BoundDecisionDagNode rootNode, BoundDecisionDagNode targetNode, bool nullPaths, Func<ImmutableArray<BoundDecisionDagNode>, bool, bool> handler)
|
|
{
|
|
ArrayBuilder<BoundDecisionDagNode> pathBuilder = ArrayBuilder<BoundDecisionDagNode>.GetInstance();
|
|
exploreToNode(rootNode, currentRequiresFalseWhenClause: false);
|
|
pathBuilder.Free();
|
|
bool exploreToNode(BoundDecisionDagNode currentNode, bool currentRequiresFalseWhenClause)
|
|
{
|
|
if (currentNode == targetNode)
|
|
{
|
|
return handler(pathBuilder.ToImmutable(), currentRequiresFalseWhenClause);
|
|
}
|
|
ArrayBuilderExtensions.Push<BoundDecisionDagNode>(pathBuilder, currentNode);
|
|
if (currentNode != null && !(currentNode is BoundLeafDecisionDagNode))
|
|
{
|
|
if (!(currentNode is BoundTestDecisionDagNode boundTestDecisionDagNode))
|
|
{
|
|
if (!(currentNode is BoundEvaluationDecisionDagNode boundEvaluationDecisionDagNode))
|
|
{
|
|
if (currentNode is BoundWhenDecisionDagNode boundWhenDecisionDagNode)
|
|
{
|
|
ArrayBuilderExtensions.Pop<BoundDecisionDagNode>(pathBuilder);
|
|
return exploreToNode(boundWhenDecisionDagNode.WhenFalse, currentRequiresFalseWhenClause: true);
|
|
}
|
|
throw ExceptionUtilities.UnexpectedValue((object)currentNode.Kind);
|
|
}
|
|
if (!exploreToNode(boundEvaluationDecisionDagNode.Next, currentRequiresFalseWhenClause))
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
bool flag = boundTestDecisionDagNode.Test is BoundDagExplicitNullTest && !nullPaths;
|
|
bool flag2 = boundTestDecisionDagNode.Test is BoundDagNonNullTest && !nullPaths;
|
|
if (!flag && !exploreToNode(boundTestDecisionDagNode.WhenTrue, currentRequiresFalseWhenClause))
|
|
{
|
|
return false;
|
|
}
|
|
if (!flag2 && !exploreToNode(boundTestDecisionDagNode.WhenFalse, currentRequiresFalseWhenClause))
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
ArrayBuilderExtensions.Pop<BoundDecisionDagNode>(pathBuilder);
|
|
return true;
|
|
}
|
|
}
|
|
|
|
internal static string SamplePatternForPathToDagNode(BoundDagTemp rootIdentifier, ImmutableArray<BoundDecisionDagNode> nodes, BoundDecisionDagNode targetNode, bool nullPaths, out bool requiresFalseWhenClause, out bool unnamedEnumValue)
|
|
{
|
|
unnamedEnumValue = false;
|
|
ImmutableArray<BoundDecisionDagNode> pathToNode = ShortestPathToNode(nodes, targetNode, nullPaths, out requiresFalseWhenClause);
|
|
gatherConstraintsAndEvaluations(targetNode, pathToNode, out var constraints, out var evaluations);
|
|
try
|
|
{
|
|
return SamplePatternForTemp(rootIdentifier, constraints, evaluations, requireExactType: false, ref unnamedEnumValue);
|
|
}
|
|
catch (NoRemainingValuesException)
|
|
{
|
|
}
|
|
return samplePatternFromOtherPaths(rootIdentifier, nodes[0], targetNode, nullPaths, out requiresFalseWhenClause, out unnamedEnumValue);
|
|
static void gatherConstraintsAndEvaluations(BoundDecisionDagNode boundDecisionDagNode3, ImmutableArray<BoundDecisionDagNode> immutableArray, out Dictionary<BoundDagTemp, ArrayBuilder<(BoundDagTest, bool)>> reference, out Dictionary<BoundDagTemp, ArrayBuilder<BoundDagEvaluation>> reference2)
|
|
{
|
|
reference = new Dictionary<BoundDagTemp, ArrayBuilder<(BoundDagTest, bool)>>();
|
|
reference2 = new Dictionary<BoundDagTemp, ArrayBuilder<BoundDagEvaluation>>();
|
|
int i = 0;
|
|
for (int length = immutableArray.Length; i < length; i++)
|
|
{
|
|
BoundDecisionDagNode boundDecisionDagNode = immutableArray[i];
|
|
if (!(boundDecisionDagNode is BoundTestDecisionDagNode boundTestDecisionDagNode))
|
|
{
|
|
if (boundDecisionDagNode is BoundEvaluationDecisionDagNode boundEvaluationDecisionDagNode)
|
|
{
|
|
BoundDagTemp input = boundEvaluationDecisionDagNode.Evaluation.Input;
|
|
if (!reference2.TryGetValue(input, out var value))
|
|
{
|
|
reference2.Add(input, value = new ArrayBuilder<BoundDagEvaluation>());
|
|
}
|
|
value.Add(boundEvaluationDecisionDagNode.Evaluation);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
BoundDecisionDagNode boundDecisionDagNode2 = ((i < length - 1) ? immutableArray[i + 1] : boundDecisionDagNode3);
|
|
bool flag = boundTestDecisionDagNode.WhenTrue == boundDecisionDagNode2 || (boundTestDecisionDagNode.WhenFalse != boundDecisionDagNode2 && boundTestDecisionDagNode.WhenTrue is BoundWhenDecisionDagNode);
|
|
BoundDagTest test = boundTestDecisionDagNode.Test;
|
|
BoundDagTemp input2 = test.Input;
|
|
if (!(test is BoundDagTypeTest) || flag)
|
|
{
|
|
if (!reference.TryGetValue(input2, out var value2))
|
|
{
|
|
reference.Add(input2, value2 = new ArrayBuilder<(BoundDagTest, bool)>());
|
|
}
|
|
value2.Add((test, flag));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
static string samplePatternFromOtherPaths(BoundDagTemp input, BoundDecisionDagNode rootNode, BoundDecisionDagNode targetNode2, bool nullPaths2, out bool reference2, out bool reference)
|
|
{
|
|
string altSamplePatternForTemp = null;
|
|
bool altRequiresFalseWhenClause = false;
|
|
bool altUnnamedEnumValue = false;
|
|
VisitPathsToNode(rootNode, targetNode2, nullPaths2, delegate(ImmutableArray<BoundDecisionDagNode> currentPathToNode, bool currentRequiresFalseWhenClause)
|
|
{
|
|
altRequiresFalseWhenClause = currentRequiresFalseWhenClause;
|
|
gatherConstraintsAndEvaluations(targetNode2, currentPathToNode, out var constraints2, out var evaluations2);
|
|
try
|
|
{
|
|
altUnnamedEnumValue = false;
|
|
altSamplePatternForTemp = SamplePatternForTemp(input, constraints2, evaluations2, requireExactType: false, ref altUnnamedEnumValue);
|
|
return false;
|
|
}
|
|
catch (NoRemainingValuesException)
|
|
{
|
|
return true;
|
|
}
|
|
});
|
|
if (altSamplePatternForTemp != null)
|
|
{
|
|
reference = altUnnamedEnumValue;
|
|
reference2 = altRequiresFalseWhenClause;
|
|
return altSamplePatternForTemp;
|
|
}
|
|
throw ExceptionUtilities.Unreachable("/_/src/Compilers/CSharp/Portable/Binder/PatternExplainer.cs", 241);
|
|
}
|
|
}
|
|
|
|
private static string SamplePatternForTemp(BoundDagTemp input, Dictionary<BoundDagTemp, ArrayBuilder<(BoundDagTest test, bool sense)>> constraintMap, Dictionary<BoundDagTemp, ArrayBuilder<BoundDagEvaluation>> evaluationMap, bool requireExactType, ref bool unnamedEnumValue)
|
|
{
|
|
ImmutableArray<(BoundDagTest test, bool sense)> constraints = getArray<(BoundDagTest, bool)>(constraintMap, input);
|
|
ImmutableArray<BoundDagEvaluation> evaluations = getArray<BoundDagEvaluation>(evaluationMap, input);
|
|
return tryHandleSingleTest() ?? tryHandleTypeTestAndTypeEvaluation(ref unnamedEnumValue) ?? tryHandleUnboxNullableValueType(ref unnamedEnumValue) ?? tryHandleTuplePattern(ref unnamedEnumValue) ?? tryHandleNumericLimits(ref unnamedEnumValue) ?? tryHandleRecursivePattern(ref unnamedEnumValue) ?? tryHandleListPattern(ref unnamedEnumValue) ?? produceFallbackPattern();
|
|
static IValueSet computeRemainingValues(IValueSetFactory fac, ImmutableArray<(BoundDagTest test, bool sense)> immutableArray)
|
|
{
|
|
IValueSet remainingValues = fac.AllValues;
|
|
ImmutableArray<(BoundDagTest, bool)>.Enumerator enumerator = immutableArray.GetEnumerator();
|
|
while (enumerator.MoveNext())
|
|
{
|
|
var (boundDagTest, sense) = enumerator.Current;
|
|
if (!(boundDagTest is BoundDagValueTest boundDagValueTest))
|
|
{
|
|
if (boundDagTest is BoundDagRelationalTest boundDagRelationalTest)
|
|
{
|
|
addRelation(boundDagRelationalTest.Relation, boundDagRelationalTest.Value);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
addRelation(BinaryOperatorKind.Equal, boundDagValueTest.Value);
|
|
}
|
|
void addRelation(BinaryOperatorKind relation, ConstantValue value)
|
|
{
|
|
if (!value.IsBad)
|
|
{
|
|
IValueSet valueSet = fac.Related(relation, value);
|
|
if (!sense)
|
|
{
|
|
valueSet = valueSet.Complement();
|
|
}
|
|
remainingValues = remainingValues.Intersect(valueSet);
|
|
}
|
|
}
|
|
}
|
|
return remainingValues;
|
|
}
|
|
static ImmutableArray<T> getArray<T>(Dictionary<BoundDagTemp, ArrayBuilder<T>> map, BoundDagTemp temp)
|
|
{
|
|
if (!map.TryGetValue(temp, out var value))
|
|
{
|
|
return ImmutableArray<T>.Empty;
|
|
}
|
|
return value.ToImmutable();
|
|
}
|
|
static bool isNotNullTest((BoundDagTest test, bool sense) constraint)
|
|
{
|
|
var (boundDagTest, _) = constraint;
|
|
if (boundDagTest is BoundDagNonNullTest)
|
|
{
|
|
if (constraint.sense)
|
|
{
|
|
goto IL_0029;
|
|
}
|
|
}
|
|
else if (boundDagTest is BoundDagExplicitNullTest && !constraint.sense)
|
|
{
|
|
goto IL_0029;
|
|
}
|
|
return false;
|
|
IL_0029:
|
|
return true;
|
|
}
|
|
static string makeConjunct(string oldPattern, string newPattern)
|
|
{
|
|
if (oldPattern == "_")
|
|
{
|
|
return newPattern;
|
|
}
|
|
if (newPattern == "_")
|
|
{
|
|
return oldPattern;
|
|
}
|
|
return oldPattern + " and " + newPattern;
|
|
}
|
|
string produceFallbackPattern()
|
|
{
|
|
if (!requireExactType)
|
|
{
|
|
return "_";
|
|
}
|
|
return input.Type.ToDisplayString();
|
|
}
|
|
string tryHandleListPattern(ref bool unnamedEnumValue2)
|
|
{
|
|
if (constraints.IsEmpty && evaluations.IsEmpty)
|
|
{
|
|
return null;
|
|
}
|
|
if (!constraints.All(isNotNullTest))
|
|
{
|
|
return null;
|
|
}
|
|
if (evaluations[0] is BoundDagPropertyEvaluation { IsLengthOrCount: not false } boundDagPropertyEvaluation)
|
|
{
|
|
BoundDagSliceEvaluation boundDagSliceEvaluation = null;
|
|
for (int i = 1; i < evaluations.Length; i++)
|
|
{
|
|
BoundDagEvaluation boundDagEvaluation = evaluations[i];
|
|
if (!(boundDagEvaluation is BoundDagIndexerEvaluation))
|
|
{
|
|
if (!(boundDagEvaluation is BoundDagSliceEvaluation boundDagSliceEvaluation2))
|
|
{
|
|
return null;
|
|
}
|
|
if (boundDagSliceEvaluation != null)
|
|
{
|
|
return null;
|
|
}
|
|
boundDagSliceEvaluation = boundDagSliceEvaluation2;
|
|
}
|
|
}
|
|
BoundDagTemp temp = new BoundDagTemp(boundDagPropertyEvaluation.Syntax, boundDagPropertyEvaluation.Property.Type, boundDagPropertyEvaluation);
|
|
IValueSet<int> valueSet = (IValueSet<int>)computeRemainingValues(ValueSetFactory.ForLength, getArray<(BoundDagTest, bool)>(constraintMap, temp));
|
|
int int32Value = valueSet.Sample.Int32Value;
|
|
if (boundDagSliceEvaluation != null)
|
|
{
|
|
if (valueSet.All(BinaryOperatorKind.Equal, int32Value))
|
|
{
|
|
return null;
|
|
}
|
|
if (boundDagSliceEvaluation.StartIndex - boundDagSliceEvaluation.EndIndex > int32Value)
|
|
{
|
|
return null;
|
|
}
|
|
}
|
|
ArrayBuilder<string> val = new ArrayBuilder<string>(int32Value);
|
|
val.AddMany("_", int32Value);
|
|
for (int j = 1; j < evaluations.Length; j++)
|
|
{
|
|
BoundDagEvaluation boundDagEvaluation2 = evaluations[j];
|
|
if (!(boundDagEvaluation2 is BoundDagIndexerEvaluation boundDagIndexerEvaluation))
|
|
{
|
|
if (!(boundDagEvaluation2 is BoundDagSliceEvaluation))
|
|
{
|
|
throw ExceptionUtilities.UnexpectedValue((object)boundDagEvaluation2);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
BoundDagTemp input2 = new BoundDagTemp(boundDagIndexerEvaluation.Syntax, boundDagIndexerEvaluation.IndexerType, boundDagIndexerEvaluation);
|
|
int index = boundDagIndexerEvaluation.Index;
|
|
int num = ((index < 0) ? (int32Value + index) : index);
|
|
if (num < 0 || num >= int32Value)
|
|
{
|
|
return null;
|
|
}
|
|
string oldPattern = val[num];
|
|
string newPattern = SamplePatternForTemp(input2, constraintMap, evaluationMap, requireExactType: false, ref unnamedEnumValue2);
|
|
val[num] = makeConjunct(oldPattern, newPattern);
|
|
}
|
|
}
|
|
if (boundDagSliceEvaluation != null)
|
|
{
|
|
string text = SamplePatternForTemp(new BoundDagTemp(boundDagSliceEvaluation.Syntax, boundDagSliceEvaluation.SliceType, boundDagSliceEvaluation), constraintMap, evaluationMap, requireExactType: false, ref unnamedEnumValue2);
|
|
if (text != "_")
|
|
{
|
|
val.Insert(boundDagSliceEvaluation.StartIndex, ".. " + text);
|
|
}
|
|
}
|
|
return "[" + string.Join(", ", (IEnumerable<string?>)val) + "]";
|
|
}
|
|
return null;
|
|
}
|
|
string tryHandleNumericLimits(ref bool unnamedEnumValue2)
|
|
{
|
|
if (evaluations.IsEmpty && constraints.All(delegate((BoundDagTest test, bool sense) t)
|
|
{
|
|
var (boundDagTest, _) = t;
|
|
if (boundDagTest is BoundDagValueTest)
|
|
{
|
|
return true;
|
|
}
|
|
if (boundDagTest is BoundDagRelationalTest)
|
|
{
|
|
return true;
|
|
}
|
|
if (boundDagTest is BoundDagExplicitNullTest)
|
|
{
|
|
if (!t.sense)
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
else if (boundDagTest is BoundDagNonNullTest && t.sense)
|
|
{
|
|
return true;
|
|
}
|
|
return false;
|
|
}))
|
|
{
|
|
IValueSetFactory valueSetFactory = ValueSetFactory.ForInput(input);
|
|
if (valueSetFactory != null)
|
|
{
|
|
IValueSet valueSet = computeRemainingValues(valueSetFactory, constraints);
|
|
if (valueSet.Complement().IsEmpty)
|
|
{
|
|
return "_";
|
|
}
|
|
return SampleValueString(valueSet, input.Type, requireExactType, ref unnamedEnumValue2);
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
string tryHandleRecursivePattern(ref bool unnamedEnumValue2)
|
|
{
|
|
if (constraints.IsEmpty && evaluations.IsEmpty)
|
|
{
|
|
return null;
|
|
}
|
|
if (!constraints.All(isNotNullTest))
|
|
{
|
|
return null;
|
|
}
|
|
string text = null;
|
|
Dictionary<Symbol, string> dictionary = new Dictionary<Symbol, string>();
|
|
bool flag = false;
|
|
ImmutableArray<BoundDagEvaluation>.Enumerator enumerator = evaluations.GetEnumerator();
|
|
while (enumerator.MoveNext())
|
|
{
|
|
BoundDagEvaluation current = enumerator.Current;
|
|
if (!(current is BoundDagDeconstructEvaluation boundDagDeconstructEvaluation))
|
|
{
|
|
if (!(current is BoundDagFieldEvaluation boundDagFieldEvaluation))
|
|
{
|
|
if (!(current is BoundDagPropertyEvaluation boundDagPropertyEvaluation))
|
|
{
|
|
return null;
|
|
}
|
|
string value = SamplePatternForTemp(new BoundDagTemp(boundDagPropertyEvaluation.Syntax, boundDagPropertyEvaluation.Property.Type, boundDagPropertyEvaluation), constraintMap, evaluationMap, requireExactType: false, ref unnamedEnumValue2);
|
|
dictionary.Add(boundDagPropertyEvaluation.Property, value);
|
|
}
|
|
else
|
|
{
|
|
string value2 = SamplePatternForTemp(new BoundDagTemp(boundDagFieldEvaluation.Syntax, boundDagFieldEvaluation.Field.Type, boundDagFieldEvaluation), constraintMap, evaluationMap, requireExactType: false, ref unnamedEnumValue2);
|
|
dictionary.Add(boundDagFieldEvaluation.Field, value2);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
MethodSymbol deconstructMethod = boundDagDeconstructEvaluation.DeconstructMethod;
|
|
int num = ((!deconstructMethod.RequiresInstanceReceiver) ? 1 : 0);
|
|
int num2 = deconstructMethod.Parameters.Length - num;
|
|
StringBuilder stringBuilder = new StringBuilder("(");
|
|
for (int i = 0; i < num2; i++)
|
|
{
|
|
string value3 = SamplePatternForTemp(new BoundDagTemp(boundDagDeconstructEvaluation.Syntax, deconstructMethod.Parameters[i + num].Type, boundDagDeconstructEvaluation, i), constraintMap, evaluationMap, requireExactType: false, ref unnamedEnumValue2);
|
|
if (i != 0)
|
|
{
|
|
stringBuilder.Append(", ");
|
|
}
|
|
stringBuilder.Append(value3);
|
|
}
|
|
stringBuilder.Append(")");
|
|
string text2 = stringBuilder.ToString();
|
|
if (text != null && flag)
|
|
{
|
|
text += " { }";
|
|
flag = dictionary.Count != 0;
|
|
}
|
|
text = ((text == null) ? text2 : (text + " and " + text2));
|
|
flag = flag || num2 == 1;
|
|
}
|
|
}
|
|
string text3 = (requireExactType ? input.Type.ToDisplayString() : null);
|
|
string text4 = ((flag | ((text == null && text3 == null) || dictionary.Count != 0)) ? (((text != null) ? " {" : "{") + string.Join(", ", dictionary.Select((KeyValuePair<Symbol, string> kvp) => " " + kvp.Key.Name + ": " + kvp.Value)) + " }") : null);
|
|
return text3 + text + text4;
|
|
}
|
|
string tryHandleSingleTest()
|
|
{
|
|
if (evaluations.IsEmpty && constraints.Length == 1)
|
|
{
|
|
(BoundDagTest, bool) tuple = constraints[0];
|
|
var (boundDagTest, _) = tuple;
|
|
if (boundDagTest is BoundDagNonNullTest)
|
|
{
|
|
if (tuple.Item2)
|
|
{
|
|
if (!requireExactType)
|
|
{
|
|
return "not null";
|
|
}
|
|
return input.Type.ToDisplayString();
|
|
}
|
|
return "null";
|
|
}
|
|
if (boundDagTest is BoundDagExplicitNullTest)
|
|
{
|
|
if (!tuple.Item2)
|
|
{
|
|
if (!requireExactType)
|
|
{
|
|
return "not null";
|
|
}
|
|
return input.Type.ToDisplayString();
|
|
}
|
|
return "null";
|
|
}
|
|
if (boundDagTest is BoundDagTypeTest boundDagTypeTest)
|
|
{
|
|
TypeSymbol type = boundDagTypeTest.Type;
|
|
bool item = tuple.Item2;
|
|
return type.ToDisplayString();
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
string tryHandleTuplePattern(ref bool unnamedEnumValue2)
|
|
{
|
|
if (input.Type.IsTupleType && constraints.IsEmpty && evaluations.All(delegate(BoundDagEvaluation e)
|
|
{
|
|
if (e is BoundDagFieldEvaluation boundDagFieldEvaluation2)
|
|
{
|
|
FieldSymbol field = boundDagFieldEvaluation2.Field;
|
|
return field.IsTupleElement();
|
|
}
|
|
return false;
|
|
}))
|
|
{
|
|
int length = input.Type.TupleElements.Length;
|
|
ArrayBuilder<string> val = new ArrayBuilder<string>(length);
|
|
val.AddMany("_", length);
|
|
ImmutableArray<BoundDagEvaluation>.Enumerator enumerator = evaluations.GetEnumerator();
|
|
while (enumerator.MoveNext())
|
|
{
|
|
BoundDagFieldEvaluation boundDagFieldEvaluation = (BoundDagFieldEvaluation)enumerator.Current;
|
|
BoundDagTemp input2 = new BoundDagTemp(boundDagFieldEvaluation.Syntax, boundDagFieldEvaluation.Field.Type, boundDagFieldEvaluation);
|
|
int tupleElementIndex = boundDagFieldEvaluation.Field.TupleElementIndex;
|
|
if (tupleElementIndex < 0 || tupleElementIndex >= length)
|
|
{
|
|
return null;
|
|
}
|
|
string oldPattern = val[tupleElementIndex];
|
|
string newPattern = SamplePatternForTemp(input2, constraintMap, evaluationMap, requireExactType: false, ref unnamedEnumValue2);
|
|
val[tupleElementIndex] = makeConjunct(oldPattern, newPattern);
|
|
}
|
|
return "(" + string.Join(", ", (IEnumerable<string?>)val) + ")" + ((val.Count == 1) ? " { }" : null);
|
|
}
|
|
return null;
|
|
}
|
|
string tryHandleTypeTestAndTypeEvaluation(ref bool unnamedEnumValue2)
|
|
{
|
|
if (evaluations.Length == 1 && constraints.Length == 1)
|
|
{
|
|
(BoundDagTest, bool) tuple = constraints[0];
|
|
if (tuple.Item1 is BoundDagTypeTest boundDagTypeTest)
|
|
{
|
|
TypeSymbol type = boundDagTypeTest.Type;
|
|
if (tuple.Item2 && evaluations[0] is BoundDagTypeEvaluation boundDagTypeEvaluation)
|
|
{
|
|
TypeSymbol type2 = boundDagTypeEvaluation.Type;
|
|
if (type.Equals(type2, (TypeCompareKind)63))
|
|
{
|
|
return SamplePatternForTemp(new BoundDagTemp(boundDagTypeEvaluation.Syntax, boundDagTypeEvaluation.Type, boundDagTypeEvaluation), constraintMap, evaluationMap, requireExactType: true, ref unnamedEnumValue2);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
string tryHandleUnboxNullableValueType(ref bool unnamedEnumValue2)
|
|
{
|
|
if (evaluations.Length == 1 && constraints.Length == 1)
|
|
{
|
|
(BoundDagTest, bool) tuple = constraints[0];
|
|
if (tuple.Item1 is BoundDagNonNullTest && tuple.Item2 && evaluations[0] is BoundDagTypeEvaluation boundDagTypeEvaluation)
|
|
{
|
|
TypeSymbol type = boundDagTypeEvaluation.Type;
|
|
if (input.Type.IsNullableType() && input.Type.GetNullableUnderlyingType().Equals(type, (TypeCompareKind)63))
|
|
{
|
|
string text = SamplePatternForTemp(new BoundDagTemp(boundDagTypeEvaluation.Syntax, boundDagTypeEvaluation.Type, boundDagTypeEvaluation), constraintMap, evaluationMap, requireExactType: false, ref unnamedEnumValue2);
|
|
if (!(text == "_"))
|
|
{
|
|
return text;
|
|
}
|
|
return "not null";
|
|
}
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
}
|
|
|
|
private static string SampleValueString(IValueSet remainingValues, TypeSymbol type, bool requireExactType, ref bool unnamedEnumValue)
|
|
{
|
|
//IL_001c: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_0022: Invalid comparison between Unknown and I4
|
|
//IL_00c0: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_00c7: Invalid comparison between Unknown and I4
|
|
//IL_0126: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_012d: Invalid comparison between Unknown and I4
|
|
//IL_0060: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_0066: Invalid comparison between Unknown and I4
|
|
if (remainingValues.IsEmpty)
|
|
{
|
|
throw new NoRemainingValuesException();
|
|
}
|
|
if (type is NamedTypeSymbol namedTypeSymbol && (int)type.TypeKind == 5)
|
|
{
|
|
ImmutableArray<Symbol>.Enumerator enumerator = namedTypeSymbol.GetMembers().GetEnumerator();
|
|
while (enumerator.MoveNext())
|
|
{
|
|
Symbol current = enumerator.Current;
|
|
if (current is FieldSymbol { IsConst: not false } fieldSymbol && current.IsStatic && (int)current.DeclaredAccessibility == 6)
|
|
{
|
|
ConstantValue constantValue = fieldSymbol.GetConstantValue(ConstantFieldsInProgress.Empty, earlyDecodingWellKnownAttributes: false);
|
|
if (constantValue != null && remainingValues.Any(BinaryOperatorKind.Equal, constantValue))
|
|
{
|
|
return fieldSymbol.ToDisplayString();
|
|
}
|
|
}
|
|
}
|
|
unnamedEnumValue = true;
|
|
}
|
|
ConstantValue sample = remainingValues.Sample;
|
|
if (sample != (ConstantValue)null)
|
|
{
|
|
return ValueString(sample, type, requireExactType);
|
|
}
|
|
TypeSymbol typeSymbol = type.EnumUnderlyingTypeOrSelf();
|
|
if ((int)typeSymbol.SpecialType == 21)
|
|
{
|
|
if (remainingValues.Any(BinaryOperatorKind.GreaterThan, ConstantValue.Create(int.MaxValue)))
|
|
{
|
|
return "> (" + type.ToDisplayString() + ")int.MaxValue";
|
|
}
|
|
if (remainingValues.Any(BinaryOperatorKind.LessThan, ConstantValue.Create(int.MinValue)))
|
|
{
|
|
return "< (" + type.ToDisplayString() + ")int.MinValue";
|
|
}
|
|
}
|
|
else if ((int)typeSymbol.SpecialType == 22 && remainingValues.Any(BinaryOperatorKind.GreaterThan, ConstantValue.Create(uint.MaxValue)))
|
|
{
|
|
return "> (" + type.ToDisplayString() + ")uint.MaxValue";
|
|
}
|
|
throw ExceptionUtilities.Unreachable("/_/src/Compilers/CSharp/Portable/Binder/PatternExplainer.cs", 688);
|
|
}
|
|
|
|
private static string ValueString(ConstantValue value, TypeSymbol type, bool requireExactType)
|
|
{
|
|
bool num = (type.IsEnumType() || requireExactType || type.IsNativeIntegerType) && (!typeHasExactTypeLiteral(type) || value.IsNull);
|
|
string text = PrimitiveValueString(value, type.EnumUnderlyingTypeOrSelf());
|
|
if (!num)
|
|
{
|
|
return text;
|
|
}
|
|
return "(" + type.ToDisplayString() + ")" + text;
|
|
static bool typeHasExactTypeLiteral(TypeSymbol typeSymbol)
|
|
{
|
|
//IL_0001: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_0006: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_0007: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_0009: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_0047: Expected I4, but got Unknown
|
|
SpecialType specialType = typeSymbol.SpecialType;
|
|
return (specialType - 7) switch
|
|
{
|
|
6 => true,
|
|
8 => true,
|
|
7 => true,
|
|
9 => true,
|
|
13 => true,
|
|
10 => true,
|
|
11 => true,
|
|
12 => true,
|
|
0 => true,
|
|
1 => true,
|
|
_ => false,
|
|
};
|
|
}
|
|
}
|
|
|
|
private static string PrimitiveValueString(ConstantValue value, TypeSymbol type)
|
|
{
|
|
//IL_000f: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_0014: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_0015: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_0017: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_005d: Expected I4, but got Unknown
|
|
if (value.IsNull)
|
|
{
|
|
return "null";
|
|
}
|
|
SpecialType specialType = type.SpecialType;
|
|
switch (specialType - 7)
|
|
{
|
|
case 14:
|
|
if (!type.IsNativeIntegerType)
|
|
{
|
|
break;
|
|
}
|
|
goto case 0;
|
|
case 15:
|
|
if (!type.IsNativeIntegerType)
|
|
{
|
|
break;
|
|
}
|
|
goto case 0;
|
|
case 0:
|
|
case 1:
|
|
case 2:
|
|
case 3:
|
|
case 4:
|
|
case 5:
|
|
case 6:
|
|
case 7:
|
|
case 8:
|
|
case 9:
|
|
case 10:
|
|
case 13:
|
|
return ObjectDisplay.FormatPrimitive(value.Value, (ObjectDisplayOptions)26);
|
|
case 11:
|
|
{
|
|
float singleValue = value.SingleValue;
|
|
if (!float.IsNaN(singleValue))
|
|
{
|
|
if (singleValue != float.NegativeInfinity)
|
|
{
|
|
if (singleValue == float.PositiveInfinity)
|
|
{
|
|
return "float.PositiveInfinity";
|
|
}
|
|
return ObjectDisplay.FormatPrimitive(singleValue, (ObjectDisplayOptions)2);
|
|
}
|
|
return "float.NegativeInfinity";
|
|
}
|
|
return "float.NaN";
|
|
}
|
|
case 12:
|
|
{
|
|
double doubleValue = value.DoubleValue;
|
|
if (!double.IsNaN(doubleValue))
|
|
{
|
|
if (doubleValue != double.NegativeInfinity)
|
|
{
|
|
if (doubleValue == double.PositiveInfinity)
|
|
{
|
|
return "double.PositiveInfinity";
|
|
}
|
|
return ObjectDisplay.FormatPrimitive(doubleValue, (ObjectDisplayOptions)2);
|
|
}
|
|
return "double.NegativeInfinity";
|
|
}
|
|
return "double.NaN";
|
|
}
|
|
}
|
|
return "_";
|
|
}
|
|
}
|