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

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 "_";
}
}