mirror of
https://github.com/icsharpcode/ILSpy.git
synced 2026-10-12 02:15:58 +00:00
Add xfailed pretty test for C# 9 pattern matching improvements
The fixture is the desired output for the C# 9 pattern forms the decompiler does not reconstruct yet: relational subpatterns printed with conventional spacing (currently emitted as 'I: >5', which the repo's own formatter rejects), 'and'/'or' combinators (type + value tests, constant alternatives, range checks in subpatterns), top-level 'is not' with designator, negated recursive patterns, 'null or ""', and switch statements/expressions with relational or combined arms (currently leaked as balanced-comparison if trees). It also pins two real bugs: a 'not' subpattern with a string constant decompiles to 'Text: 0' (uncompilable, CS0029 on recompile) and with a decimal constant to 'Dec: 0' (compiles but silently inverts and changes the matched value); the negation and the operand of the logic.not(call op_Equality) form are both dropped in ExpressionBuilder.TranslatePattern. The test is Assert.Ignore'd (#829); all six Roslyn 3.11/4.14/latest debug/opt configs compile the fixture and fail only at the output comparison. Assisted-by: Claude:claude-fable-5:Claude Code
This commit is contained in:
@@ -494,6 +494,13 @@ namespace ICSharpCode.Decompiler.Tests
|
||||
await RunForLibrary(cscOptions: cscOptions);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task PatternMatchingImprovements([ValueSource(nameof(roslyn3OrNewerOptions))] CompilerOptions cscOptions)
|
||||
{
|
||||
Assert.Ignore("C# 9 relational and combinator patterns are not yet fully supported by the decompiler. See https://github.com/icsharpcode/ILSpy/issues/829");
|
||||
await RunForLibrary(cscOptions: cscOptions);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task InitializerTests([ValueSource(nameof(defaultOptions))] CompilerOptions cscOptions)
|
||||
{
|
||||
|
||||
@@ -0,0 +1,183 @@
|
||||
using System;
|
||||
|
||||
namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
|
||||
{
|
||||
public class PatternMatchingImprovements
|
||||
{
|
||||
public enum Color
|
||||
{
|
||||
Red,
|
||||
Green,
|
||||
Blue
|
||||
}
|
||||
|
||||
public class X
|
||||
{
|
||||
public int I { get; set; }
|
||||
public char Ch { get; set; }
|
||||
public double D { get; set; }
|
||||
public decimal Dec { get; set; }
|
||||
public Color Col { get; set; }
|
||||
public string Text { get; set; }
|
||||
public object Obj { get; set; }
|
||||
public X Next { get; set; }
|
||||
}
|
||||
|
||||
public void RelationalSubpatternInt(object x)
|
||||
{
|
||||
if (x is X { I: > 5 } x2)
|
||||
{
|
||||
Console.WriteLine(x2.Text);
|
||||
}
|
||||
}
|
||||
|
||||
public void RelationalSubpatternChar(object x)
|
||||
{
|
||||
if (x is X { Ch: >= 'a' } x2)
|
||||
{
|
||||
Console.WriteLine(x2.Text);
|
||||
}
|
||||
}
|
||||
|
||||
public void RelationalSubpatternDouble(object x)
|
||||
{
|
||||
if (x is X { D: <= 2.5 } x2)
|
||||
{
|
||||
Console.WriteLine(x2.Text);
|
||||
}
|
||||
}
|
||||
|
||||
public void RelationalSubpatternEnum(object x)
|
||||
{
|
||||
if (x is X { Col: > Color.Red } x2)
|
||||
{
|
||||
Console.WriteLine(x2.Text);
|
||||
}
|
||||
}
|
||||
|
||||
public void RelationalSubpatternNested(object x)
|
||||
{
|
||||
if (x is X { Next: { I: < 10 } } x2)
|
||||
{
|
||||
Console.WriteLine(x2.Text);
|
||||
}
|
||||
}
|
||||
|
||||
public void RelationalSubpatternTwoProperties(object x)
|
||||
{
|
||||
if (x is X { I: > 5, Ch: < 'x' } x2)
|
||||
{
|
||||
Console.WriteLine(x2.Text);
|
||||
}
|
||||
}
|
||||
|
||||
public void NotStringConstant(object x)
|
||||
{
|
||||
if (x is X { Text: not "abc" } x2)
|
||||
{
|
||||
Console.WriteLine(x2.I);
|
||||
}
|
||||
}
|
||||
|
||||
public void NotDecimalConstant(object x)
|
||||
{
|
||||
if (x is X { Dec: not 3.5m } x2)
|
||||
{
|
||||
Console.WriteLine(x2.Text);
|
||||
}
|
||||
}
|
||||
|
||||
public bool TypeAndRelational(object x)
|
||||
{
|
||||
return x is int and > 5;
|
||||
}
|
||||
|
||||
public bool TypeAndRelationalRange(object x)
|
||||
{
|
||||
return x is int and > 0 and < 10;
|
||||
}
|
||||
|
||||
public bool SubpatternOrConstants(object x)
|
||||
{
|
||||
return x is X { I: 1 or 2 };
|
||||
}
|
||||
|
||||
public bool SubpatternRelationalRange(object x)
|
||||
{
|
||||
return x is X { I: > 0 and < 10 };
|
||||
}
|
||||
|
||||
public bool TypeOrType(object x)
|
||||
{
|
||||
return x is int or double;
|
||||
}
|
||||
|
||||
public bool NullOrEmptyString(string s)
|
||||
{
|
||||
return s is null or "";
|
||||
}
|
||||
|
||||
public string NegatedTypePatternWithDesignator(object x)
|
||||
{
|
||||
if (x is not string text)
|
||||
{
|
||||
return "no";
|
||||
}
|
||||
return text;
|
||||
}
|
||||
|
||||
public bool NegatedRecursivePattern(object x)
|
||||
{
|
||||
return x is not X { I: 5 };
|
||||
}
|
||||
|
||||
public string SwitchStatementRelational(int i)
|
||||
{
|
||||
switch (i)
|
||||
{
|
||||
case < 0:
|
||||
return "negative";
|
||||
case 0:
|
||||
return "zero";
|
||||
case > 100:
|
||||
return "big";
|
||||
default:
|
||||
return "small";
|
||||
}
|
||||
}
|
||||
|
||||
public string SwitchStatementTypeAndRelational(object o)
|
||||
{
|
||||
switch (o)
|
||||
{
|
||||
case int and > 5:
|
||||
return "big int";
|
||||
case int:
|
||||
return "int";
|
||||
case string { Length: > 3 } text:
|
||||
return text;
|
||||
default:
|
||||
return "other";
|
||||
}
|
||||
}
|
||||
|
||||
public string SwitchExpressionRelational(int i)
|
||||
{
|
||||
return i switch {
|
||||
< 0 => "negative",
|
||||
0 => "zero",
|
||||
> 100 => "big",
|
||||
_ => "small"
|
||||
};
|
||||
}
|
||||
|
||||
public string SwitchExpressionCharRange(char c)
|
||||
{
|
||||
return c switch {
|
||||
>= 'a' and <= 'z' => "lower",
|
||||
>= 'A' and <= 'Z' => "upper",
|
||||
_ => "other"
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user