Add pretty test for C# 9 pattern combinator round-trips

Pins which C# 9 pattern-matching-improvement forms the decompiler
already reconstructs or canonicalizes today. Green round-trips: 'not
<constant>' subpatterns (int, char, enum, float, double), nested and
mixed with 'not null'. EXPECTED_OUTPUT pins document deliberate
canonical forms whose IL is indistinguishable from the pattern source:
'is not null' prints as '!= null' (or '.HasValue' on nullables), 'is
not T' as '!(x is T)', 'x is > c' on a typed value as a plain
comparison, 'B: not true' as 'B: false', and 'case 1 or 2 or 3:' as
separate case labels.

Assisted-by: Claude:claude-fable-5:Claude Code
This commit is contained in:
Siegfried Pammer
2026-07-29 07:19:30 +02:00
parent d7bbf17e2e
commit 3d057d4bcd
2 changed files with 167 additions and 0 deletions
@@ -488,6 +488,12 @@ namespace ICSharpCode.Decompiler.Tests
await RunForLibrary(cscOptions: cscOptions);
}
[Test]
public async Task PatternMatchingCombinators([ValueSource(nameof(roslyn3OrNewerOptions))] CompilerOptions cscOptions)
{
await RunForLibrary(cscOptions: cscOptions);
}
[Test]
public async Task InitializerTests([ValueSource(nameof(defaultOptions))] CompilerOptions cscOptions)
{
@@ -0,0 +1,161 @@
using System;
namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
{
public class PatternMatchingCombinators
{
public enum Color
{
Red,
Green,
Blue
}
public class X
{
public int I { get; set; }
public char Ch { get; set; }
public bool B { get; set; }
public float F { get; set; }
public double D { get; set; }
public Color Col { get; set; }
public string Text { get; set; }
public object Obj { get; set; }
public X Next { get; set; }
}
public void NotConstantInt(object x)
{
if (x is X { I: not 5 } x2)
{
Console.WriteLine(x2.Text);
}
}
public void NotConstantChar(object x)
{
if (x is X { Ch: not 'a' } x2)
{
Console.WriteLine(x2.Text);
}
}
public void NotConstantEnum(object x)
{
if (x is X { Col: not Color.Red } x2)
{
Console.WriteLine(x2.Text);
}
}
public void NotConstantFloat(object x)
{
if (x is X { F: not 1.5f } x2)
{
Console.WriteLine(x2.Text);
}
}
public void NotConstantDouble(object x)
{
if (x is X { D: not 2.5 } x2)
{
Console.WriteLine(x2.Text);
}
}
public void NotConstantNested(object x)
{
if (x is X { Next: { I: not 5 } } x2)
{
Console.WriteLine(x2.Text);
}
}
public void NotConstantAndNotNull(object x)
{
if (x is X { I: not 0, Obj: not null } x2)
{
Console.WriteLine(x2.Text);
}
}
public void NotTruePrintsAsFalse(object x)
{
#if EXPECTED_OUTPUT
if (x is X { B: false } x2)
#else
if (x is X { B: not true } x2)
#endif
{
Console.WriteLine(x2.Text);
}
}
public bool IsNotNull(object x)
{
#if EXPECTED_OUTPUT
return x != null;
#else
return x is not null;
#endif
}
public bool IsNotNullNullableInt(int? x)
{
#if EXPECTED_OUTPUT
return x.HasValue;
#else
return x is not null;
#endif
}
public bool IsNotType(object x)
{
#if EXPECTED_OUTPUT
return !(x is string);
#else
return x is not string;
#endif
}
public bool RelationalOnInt(int i)
{
#if EXPECTED_OUTPUT
return i > 5;
#else
return i is > 5;
#endif
}
public bool RelationalOnEnum(Color c)
{
#if EXPECTED_OUTPUT
return c > Color.Red;
#else
return c is > Color.Red;
#endif
}
public string OrPatternMergesToCaseLabels(int i)
{
switch (i)
{
#if EXPECTED_OUTPUT
case 1:
case 2:
case 3:
return "small";
#else
case 1 or 2 or 3:
return "small";
#endif
case 4:
case 5:
return "medium";
default:
return "other";
}
}
}
}