Browse Source

Support recursive pattern for value types

pull/3049/head
Siegfried Pammer 2 years ago
parent
commit
8cb3a67c0c
  1. 65
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/PatternMatching.cs
  2. 2
      ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs
  3. 2
      ICSharpCode.Decompiler/CSharp/OutputVisitor/CSharpOutputVisitor.cs
  4. 4
      ICSharpCode.Decompiler/IL/Transforms/PatternMatchingTransform.cs

65
ICSharpCode.Decompiler.Tests/TestCases/Pretty/PatternMatching.cs

@ -6,14 +6,17 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
{ {
public class X public class X
{ {
public int A { get; set; } public int I { get; set; }
public string B { get; set; } public string Text { get; set; }
public object C { get; set; } public object Obj { get; set; }
public S CustomStruct { get; set; }
} }
public struct S public struct S
{ {
public int I; public int I;
public string Text { get; set; }
public object Obj { get; set; }
} }
public void SimpleTypePattern(object x) public void SimpleTypePattern(object x)
@ -318,9 +321,9 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
#if CS80 #if CS80
public void RecursivePattern_Type(object x) public void RecursivePattern_Type(object x)
{ {
if (x is X { C: string c }) if (x is X { Obj: string obj })
{ {
Console.WriteLine("Test " + c); Console.WriteLine("Test " + obj);
} }
else else
{ {
@ -330,7 +333,7 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
public void RecursivePattern_Constant(object obj) public void RecursivePattern_Constant(object obj)
{ {
if (obj is X { C: null } x) if (obj is X { Obj: null } x)
{ {
Console.WriteLine("Test " + x); Console.WriteLine("Test " + x);
} }
@ -342,7 +345,7 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
public void RecursivePattern_StringConstant(object obj) public void RecursivePattern_StringConstant(object obj)
{ {
if (obj is X { B: "Hello" } x) if (obj is X { Text: "Hello" } x)
{ {
Console.WriteLine("Test " + x); Console.WriteLine("Test " + x);
} }
@ -354,7 +357,7 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
public void RecursivePattern_MultipleConstants(object obj) public void RecursivePattern_MultipleConstants(object obj)
{ {
if (obj is X { A: 42, B: "Hello" } x) if (obj is X { I: 42, Text: "Hello" } x)
{ {
Console.WriteLine("Test " + x); Console.WriteLine("Test " + x);
} }
@ -378,9 +381,9 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
public void RecursivePattern_MultipleConstantsMixedWithVar(object x) public void RecursivePattern_MultipleConstantsMixedWithVar(object x)
{ {
if (x is X { A: 42, C: var c, B: "Hello" }) if (x is X { I: 42, Obj: var obj, Text: "Hello" })
{ {
Console.WriteLine("Test " + c); Console.WriteLine("Test " + obj);
} }
else else
{ {
@ -390,7 +393,7 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
public void RecursivePattern_NonTypePattern(object obj) public void RecursivePattern_NonTypePattern(object obj)
{ {
if (obj is X { A: 42, B: { Length: 0 } } x) if (obj is X { I: 42, Text: { Length: 0 } } x)
{ {
Console.WriteLine("Test " + x); Console.WriteLine("Test " + x);
} }
@ -400,11 +403,47 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
} }
} }
public void RecursivePatternValueType_NonTypePatternTwoProps(object obj)
{
if (obj is X { I: 42, CustomStruct: { I: 0, Text: "Test" } } x)
{
Console.WriteLine("Test " + x);
}
else
{
Console.WriteLine("not Test");
}
}
public void RecursivePattern_NonTypePatternNotNull(object o)
{
if (o is X { I: 42, Text: not null, Obj: var obj } x)
{
Console.WriteLine("Test " + x.I + " " + obj.GetType());
}
else
{
Console.WriteLine("not Test");
}
}
public void RecursivePattern_VarLengthPattern(object obj) public void RecursivePattern_VarLengthPattern(object obj)
{ {
if (obj is X { A: 42, B: { Length: var length } } x) if (obj is X { I: 42, Text: { Length: var length } } x)
{
Console.WriteLine("Test " + x.I + ": " + length);
}
else
{
Console.WriteLine("not Test");
}
}
public void RecursivePatternValueType_VarLengthPattern(object obj)
{
if (obj is S { I: 42, Text: { Length: var length } } s)
{ {
Console.WriteLine("Test " + x.A + ": " + length); Console.WriteLine("Test " + s.I + ": " + length);
} }
else else
{ {

2
ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs

@ -4571,7 +4571,7 @@ namespace ICSharpCode.Decompiler.CSharp
} }
else else
{ {
Debug.Assert(matchInstruction.CheckNotNull); Debug.Assert(matchInstruction.CheckNotNull || matchInstruction.Variable.Type.IsReferenceType == false);
} }
foreach (var subPattern in matchInstruction.SubPatterns) foreach (var subPattern in matchInstruction.SubPatterns)
{ {

2
ICSharpCode.Decompiler/CSharp/OutputVisitor/CSharpOutputVisitor.cs

@ -1302,7 +1302,7 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor
StartNode(unaryOperatorExpression); StartNode(unaryOperatorExpression);
UnaryOperatorType opType = unaryOperatorExpression.Operator; UnaryOperatorType opType = unaryOperatorExpression.Operator;
var opSymbol = UnaryOperatorExpression.GetOperatorRole(opType); var opSymbol = UnaryOperatorExpression.GetOperatorRole(opType);
if (opType == UnaryOperatorType.Await) if (opType is UnaryOperatorType.Await or UnaryOperatorType.PatternNot)
{ {
WriteKeyword(opSymbol); WriteKeyword(opSymbol);
Space(); Space();

4
ICSharpCode.Decompiler/IL/Transforms/PatternMatchingTransform.cs

@ -268,6 +268,10 @@ namespace ICSharpCode.Decompiler.IL.Transforms
targetVariable.Kind = VariableKind.PatternLocal; targetVariable.Kind = VariableKind.PatternLocal;
if (!MatchNullCheckPattern(block, varPattern, parentFalseInst, context, ref cfg)) if (!MatchNullCheckPattern(block, varPattern, parentFalseInst, context, ref cfg))
{ {
if (targetVariable.Type.IsReferenceType == false)
{
DetectPropertySubPatterns(varPattern, block, parentFalseInst, context, ref cfg);
}
DetectPropertySubPatterns(parentPattern, block, parentFalseInst, context, ref cfg); DetectPropertySubPatterns(parentPattern, block, parentFalseInst, context, ref cfg);
} }
} }

Loading…
Cancel
Save