File: Semantics\PatternMatchingTests2.cs
Web Access
Project: src\src\Compilers\CSharp\Test\Emit3\Microsoft.CodeAnalysis.CSharp.Emit3.UnitTests.csproj (Microsoft.CodeAnalysis.CSharp.Emit3.UnitTests)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
 
#nullable disable
 
using System.Linq;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.CSharp.Test.Utilities;
using Microsoft.CodeAnalysis.Test.Utilities;
using Roslyn.Test.Utilities;
using Xunit;
 
namespace Microsoft.CodeAnalysis.CSharp.UnitTests
{
    [CompilerTrait(CompilerFeature.Patterns)]
    public class PatternMatchingTests2 : PatternMatchingTestBase
    {
        [Fact]
        public void Patterns2_00()
        {
            var source =
@"
using System;
class Program
{
    public static void Main()
    {
        Console.WriteLine(1 is int {} x ? x : -1);
    }
}
";
            var compilation = CreatePatternCompilation(source);
            compilation.VerifyDiagnostics(
                );
            var comp = CompileAndVerify(compilation, expectedOutput: @"1");
        }
 
        [Fact]
        public void Patterns2_01()
        {
            var source =
@"
using System;
class Program
{
    public static void Main()
    {
        Point p = new Point();
        Check(true, p is Point(3, 4) { Length: 5 } q1 && Check(p, q1));
        Check(false, p is Point(1, 4) { Length: 5 });
        Check(false, p is Point(3, 1) { Length: 5 });
        Check(false, p is Point(3, 4) { Length: 1 });
        Check(true, p is (3, 4) { Length: 5 } q2 && Check(p, q2));
        Check(false, p is (1, 4) { Length: 5 });
        Check(false, p is (3, 1) { Length: 5 });
        Check(false, p is (3, 4) { Length: 1 });
    }
    private static bool Check<T>(T expected, T actual)
    {
        if (!object.Equals(expected, actual)) throw new Exception($""expected: {expected}; actual: {actual}"");
        return true;
    }
}
public class Point
{
    public void Deconstruct(out int X, out int Y)
    {
        X = 3;
        Y = 4;
    }
    public int Length => 5;
}
";
            var compilation = CreatePatternCompilation(source);
            compilation.VerifyDiagnostics(
                );
            var comp = CompileAndVerify(compilation, expectedOutput: "");
        }
 
        [Fact]
        public void Patterns2_02()
        {
            var source =
@"
using System;
class Program
{
    public static void Main()
    {
        Point p = new Point();
        Check(true, p is Point(3, 4) { Length: 5 } q1 && Check(p, q1));
        Check(false, p is Point(1, 4) { Length: 5 });
        Check(false, p is Point(3, 1) { Length: 5 });
        Check(false, p is Point(3, 4) { Length: 1 });
        Check(true, p is (3, 4) { Length: 5 } q2 && Check(p, q2));
        Check(false, p is (1, 4) { Length: 5 });
        Check(false, p is (3, 1) { Length: 5 });
        Check(false, p is (3, 4) { Length: 1 });
    }
    private static bool Check<T>(T expected, T actual)
    {
        if (!object.Equals(expected, actual)) throw new Exception($""expected: {expected}; actual: {actual}"");
        return true;
    }
}
public class Point
{
    public int Length => 5;
}
public static class PointExtensions
{
    public static void Deconstruct(this Point p, out int X, out int Y)
    {
        X = 3;
        Y = 4;
    }
}
";
            // We use a compilation profile that provides System.Runtime.CompilerServices.ExtensionAttribute needed for this test
            var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugExe, parseOptions: TestOptions.RegularWithRecursivePatterns);
            compilation.VerifyDiagnostics(
                );
            var comp = CompileAndVerify(compilation, expectedOutput: "");
        }
 
        [Fact]
        public void Patterns2_03()
        {
            var source =
@"
using System;
class Program
{
    public static void Main()
    {
        var p = (x: 3, y: 4);
        Check(true, p is (3, 4) q1 && Check(p, q1));
        Check(false, p is (1, 4) { x: 3 });
        Check(false, p is (3, 1) { y: 4 });
        Check(false, p is (3, 4) { x: 1 });
        Check(true, p is (3, 4) { x: 3 } q2 && Check(p, q2));
        Check(false, p is (1, 4) { x: 3 });
        Check(false, p is (3, 1) { x: 3 });
        Check(false, p is (3, 4) { x: 1 });
    }
    private static bool Check<T>(T expected, T actual)
    {
        if (!object.Equals(expected, actual)) throw new Exception($""expected: {expected}; actual: {actual}"");
        return true;
    }
}";
            var compilation = CreatePatternCompilation(source);
            compilation.VerifyDiagnostics(
                // (9,22): error CS8415: An expression of type '(int x, int y)' can never match the provided pattern.
                //         Check(false, p is (1, 4) { x: 3 });
                Diagnostic(ErrorCode.ERR_IsPatternImpossible, "p is (1, 4) { x: 3 }").WithArguments("(int x, int y)").WithLocation(9, 22),
                // (10,22): error CS8415: An expression of type '(int x, int y)' can never match the provided pattern.
                //         Check(false, p is (3, 1) { y: 4 });
                Diagnostic(ErrorCode.ERR_IsPatternImpossible, "p is (3, 1) { y: 4 }").WithArguments("(int x, int y)").WithLocation(10, 22),
                // (11,22): error CS8415: An expression of type '(int x, int y)' can never match the provided pattern.
                //         Check(false, p is (3, 4) { x: 1 });
                Diagnostic(ErrorCode.ERR_IsPatternImpossible, "p is (3, 4) { x: 1 }").WithArguments("(int x, int y)").WithLocation(11, 22),
                // (13,22): error CS8415: An expression of type '(int x, int y)' can never match the provided pattern.
                //         Check(false, p is (1, 4) { x: 3 });
                Diagnostic(ErrorCode.ERR_IsPatternImpossible, "p is (1, 4) { x: 3 }").WithArguments("(int x, int y)").WithLocation(13, 22),
                // (15,22): error CS8415: An expression of type '(int x, int y)' can never match the provided pattern.
                //         Check(false, p is (3, 4) { x: 1 });
                Diagnostic(ErrorCode.ERR_IsPatternImpossible, "p is (3, 4) { x: 1 }").WithArguments("(int x, int y)").WithLocation(15, 22)
                );
        }
 
        [Fact]
        public void Patterns2_04b()
        {
            var source =
@"
using System;
class Program
{
    public static void Main()
    {
        var p = (x: 3, y: 4);
        Check(true, p is (3, 4) q1 && Check(p, q1));
        Check(true, p is (3, 4) { x: 3 } q2 && Check(p, q2));
        Check(false, p is (3, 1) { x: 3 });
    }
    private static bool Check<T>(T expected, T actual)
    {
        if (!object.Equals(expected, actual)) throw new Exception($""expected: {expected}; actual: {actual}"");
        return true;
    }
}";
            var compilation = CreatePatternCompilation(source);
            compilation.VerifyDiagnostics(
                );
            var comp = CompileAndVerify(compilation, expectedOutput: "");
        }
 
        [Fact]
        public void Patterns2_DiscardPattern_01()
        {
            var source =
@"
using System;
class Program
{
    public static void Main()
    {
        Point p = new Point();
        Check(true, p is Point(_, _) { Length: _ } q1 && Check(p, q1));
        Check(false, p is Point(1, _) { Length: _ });
        Check(false, p is Point(_, 1) { Length: _ });
        Check(false, p is Point(_, _) { Length: 1 });
        Check(true, p is (_, _) { Length: _ } q2 && Check(p, q2));
        Check(false, p is (1, _) { Length: _ });
        Check(false, p is (_, 1) { Length: _ });
        Check(false, p is (_, _) { Length: 1 });
    }
    private static bool Check<T>(T expected, T actual)
    {
        if (!object.Equals(expected, actual)) throw new Exception($""expected: {expected}; actual: {actual}"");
        return true;
    }
}
public class Point
{
    public void Deconstruct(out int X, out int Y)
    {
        X = 3;
        Y = 4;
    }
    public int Length => 5;
}
";
            var compilation = CreatePatternCompilation(source);
            compilation.VerifyDiagnostics(
                );
            var comp = CompileAndVerify(compilation, expectedOutput: "");
        }
 
        [Fact]
        public void Patterns2_Switch01()
        {
            var sourceTemplate =
@"
class Program
{{
    public static void Main()
    {{
        var p = (true, false);
        switch (p)
        {{
            {0}
            {1}
            {2}
            case (_, _): // error - subsumed
                break;
        }}
    }}
}}";
            void testErrorCase(string s1, string s2, string s3)
            {
                var source = string.Format(sourceTemplate, s1, s2, s3);
                var compilation = CreatePatternCompilation(source);
                compilation.VerifyDiagnostics(
                    // (12,18): error CS8120: The switch case is unreachable. It has already been handled by a previous case or it is impossible to match.
                    //             case (_, _): // error - subsumed
                    Diagnostic(ErrorCode.ERR_SwitchCaseSubsumed, "(_, _)").WithLocation(12, 18)
                    );
            }
            void testGoodCase(string s1, string s2)
            {
                var source = string.Format(sourceTemplate, s1, s2, string.Empty);
                var compilation = CreatePatternCompilation(source);
                compilation.VerifyDiagnostics(
                    );
            }
            var c1 = "case (true, _):";
            var c2 = "case (false, false):";
            var c3 = "case (_, true):";
            testErrorCase(c1, c2, c3);
            testErrorCase(c2, c3, c1);
            testErrorCase(c3, c1, c2);
            testErrorCase(c1, c3, c2);
            testErrorCase(c3, c2, c1);
            testErrorCase(c2, c1, c3);
            testGoodCase(c1, c2);
            testGoodCase(c1, c3);
            testGoodCase(c2, c3);
            testGoodCase(c2, c1);
            testGoodCase(c3, c1);
            testGoodCase(c3, c2);
        }
 
        [Fact]
        public void Patterns2_Switch02()
        {
            var source =
@"
class Program
{
    public static void Main()
    {
        Point p = new Point();
        switch (p)
        {
            case Point(3, 4) { Length: 5 }:
                System.Console.WriteLine(true);
                break;
            default:
                System.Console.WriteLine(false);
                break;
        }
    }
}
public class Point
{
    public void Deconstruct(out int X, out int Y)
    {
        X = 3;
        Y = 4;
    }
    public int Length => 5;
}
";
            var compilation = CreatePatternCompilation(source);
            compilation.VerifyDiagnostics(
                );
            var comp = CompileAndVerify(compilation, expectedOutput: "True");
        }
 
        [Fact]
        public void DefaultPattern()
        {
            var source =
@"class Program
{
    public static void Main()
    {
        int i = 12;
        if (i is default) {} // error 1
        if (i is (default)) {} // error 2
        switch (i) { case default: break; } // error 3
        switch (i) { case default when true: break; } // error 4
        switch ((1, 2)) { case (1, default): break; } // error 5
 
        if (i is < default) {} // error 6
        switch (i) { case < default: break; } // error 7
        if (i is < ((default))) {} // error 8
        switch (i) { case < ((default)): break; } // error 9
 
        if (i is default!) {} // error 10
        if (i is (default!)) {} // error 11
        if (i is < ((default)!)) {} // error 12
        if (i is default!!) {} // error 13
        if (i is (default!!)) {} // error 14
        if (i is < ((default)!!)) {} // error 15
 
        // These are not accepted by the parser. See https://github.com/dotnet/roslyn/issues/45387
        if (i is (default)!) {} // error 16
        if (i is ((default)!)) {} // error 17
    }
}";
            var compilation = CreatePatternCompilation(source);
            compilation.VerifyDiagnostics(
                // (6,18): error CS8505: A default literal 'default' is not valid as a pattern. Use another literal (e.g. '0' or 'null') as appropriate. To match everything, use a discard pattern '_'.
                //         if (i is default) {} // error 1
                Diagnostic(ErrorCode.ERR_DefaultPattern, "default").WithLocation(6, 18),
                // (7,19): error CS8505: A default literal 'default' is not valid as a pattern. Use another literal (e.g. '0' or 'null') as appropriate. To match everything, use a discard pattern '_'.
                //         if (i is (default)) {} // error 2
                Diagnostic(ErrorCode.ERR_DefaultPattern, "default").WithLocation(7, 19),
                // (8,27): error CS8505: A default literal 'default' is not valid as a pattern. Use another literal (e.g. '0' or 'null') as appropriate. To match everything, use a discard pattern '_'.
                //         switch (i) { case default: break; } // error 3
                Diagnostic(ErrorCode.ERR_DefaultPattern, "default").WithLocation(8, 27),
                // (9,27): error CS8505: A default literal 'default' is not valid as a pattern. Use another literal (e.g. '0' or 'null') as appropriate. To match everything, use a discard pattern '_'.
                //         switch (i) { case default when true: break; } // error 4
                Diagnostic(ErrorCode.ERR_DefaultPattern, "default").WithLocation(9, 27),
                // (10,36): error CS8505: A default literal 'default' is not valid as a pattern. Use another literal (e.g. '0' or 'null') as appropriate. To match everything, use a discard pattern '_'.
                //         switch ((1, 2)) { case (1, default): break; } // error 5
                Diagnostic(ErrorCode.ERR_DefaultPattern, "default").WithLocation(10, 36),
                // (12,20): error CS8505: A default literal 'default' is not valid as a pattern. Use another literal (e.g. '0' or 'null') as appropriate. To match everything, use a discard pattern '_'.
                //         if (i is < default) {} // error 6
                Diagnostic(ErrorCode.ERR_DefaultPattern, "default").WithLocation(12, 20),
                // (13,29): error CS8505: A default literal 'default' is not valid as a pattern. Use another literal (e.g. '0' or 'null') as appropriate. To match everything, use a discard pattern '_'.
                //         switch (i) { case < default: break; } // error 7
                Diagnostic(ErrorCode.ERR_DefaultPattern, "default").WithLocation(13, 29),
                // (14,22): error CS8505: A default literal 'default' is not valid as a pattern. Use another literal (e.g. '0' or 'null') as appropriate. To match everything, use a discard pattern '_'.
                //         if (i is < ((default))) {} // error 8
                Diagnostic(ErrorCode.ERR_DefaultPattern, "default").WithLocation(14, 22),
                // (15,31): error CS8505: A default literal 'default' is not valid as a pattern. Use another literal (e.g. '0' or 'null') as appropriate. To match everything, use a discard pattern '_'.
                //         switch (i) { case < ((default)): break; } // error 9
                Diagnostic(ErrorCode.ERR_DefaultPattern, "default").WithLocation(15, 31),
                // (17,18): error CS8598: The suppression operator is not allowed in this context
                //         if (i is default!) {} // error 10
                Diagnostic(ErrorCode.ERR_IllegalSuppression, "default!").WithLocation(17, 18),
                // (17,18): error CS8505: A default literal 'default' is not valid as a pattern. Use another literal (e.g. '0' or 'null') as appropriate. To match everything, use a discard pattern '_'.
                //         if (i is default!) {} // error 10
                Diagnostic(ErrorCode.ERR_DefaultPattern, "default").WithLocation(17, 18),
                // (18,19): error CS8598: The suppression operator is not allowed in this context
                //         if (i is (default!)) {} // error 11
                Diagnostic(ErrorCode.ERR_IllegalSuppression, "default!").WithLocation(18, 19),
                // (18,19): error CS8505: A default literal 'default' is not valid as a pattern. Use another literal (e.g. '0' or 'null') as appropriate. To match everything, use a discard pattern '_'.
                //         if (i is (default!)) {} // error 11
                Diagnostic(ErrorCode.ERR_DefaultPattern, "default").WithLocation(18, 19),
                // (19,21): error CS8598: The suppression operator is not allowed in this context
                //         if (i is < ((default)!)) {} // error 12
                Diagnostic(ErrorCode.ERR_IllegalSuppression, "(default)!").WithLocation(19, 21),
                // (19,22): error CS8505: A default literal 'default' is not valid as a pattern. Use another literal (e.g. '0' or 'null') as appropriate. To match everything, use a discard pattern '_'.
                //         if (i is < ((default)!)) {} // error 12
                Diagnostic(ErrorCode.ERR_DefaultPattern, "default").WithLocation(19, 22),
                // (20,18): error CS8598: The suppression operator is not allowed in this context
                //         if (i is default!!) {} // error 13
                Diagnostic(ErrorCode.ERR_IllegalSuppression, "default!!").WithLocation(20, 18),
                // (20,18): error CS8598: The suppression operator is not allowed in this context
                //         if (i is default!!) {} // error 13
                Diagnostic(ErrorCode.ERR_IllegalSuppression, "default!").WithLocation(20, 18),
                // (20,18): error CS8505: A default literal 'default' is not valid as a pattern. Use another literal (e.g. '0' or 'null') as appropriate. To match everything, use a discard pattern '_'.
                //         if (i is default!!) {} // error 13
                Diagnostic(ErrorCode.ERR_DefaultPattern, "default").WithLocation(20, 18),
                // (21,19): error CS8598: The suppression operator is not allowed in this context
                //         if (i is (default!!)) {} // error 14
                Diagnostic(ErrorCode.ERR_IllegalSuppression, "default!!").WithLocation(21, 19),
                // (21,19): error CS8598: The suppression operator is not allowed in this context
                //         if (i is (default!!)) {} // error 14
                Diagnostic(ErrorCode.ERR_IllegalSuppression, "default!").WithLocation(21, 19),
                // (21,19): error CS8505: A default literal 'default' is not valid as a pattern. Use another literal (e.g. '0' or 'null') as appropriate. To match everything, use a discard pattern '_'.
                //         if (i is (default!!)) {} // error 14
                Diagnostic(ErrorCode.ERR_DefaultPattern, "default").WithLocation(21, 19),
                // (22,21): error CS8598: The suppression operator is not allowed in this context
                //         if (i is < ((default)!!)) {} // error 15
                Diagnostic(ErrorCode.ERR_IllegalSuppression, "(default)!!").WithLocation(22, 21),
                // (22,21): error CS8598: The suppression operator is not allowed in this context
                //         if (i is < ((default)!!)) {} // error 15
                Diagnostic(ErrorCode.ERR_IllegalSuppression, "(default)!").WithLocation(22, 21),
                // (22,22): error CS8715: Duplicate null suppression operator ('!')
                //         if (i is < ((default)!!)) {} // error 15
                Diagnostic(ErrorCode.ERR_DuplicateNullSuppression, "default").WithLocation(22, 22),
                // (22,22): error CS8505: A default literal 'default' is not valid as a pattern. Use another literal (e.g. '0' or 'null') as appropriate. To match everything, use a discard pattern '_'.
                //         if (i is < ((default)!!)) {} // error 15
                Diagnostic(ErrorCode.ERR_DefaultPattern, "default").WithLocation(22, 22),
                // (25,19): error CS8505: A default literal 'default' is not valid as a pattern. Use another literal (e.g. '0' or 'null') as appropriate. To match everything, use a discard pattern '_'.
                //         if (i is (default)!) {} // error 16
                Diagnostic(ErrorCode.ERR_DefaultPattern, "default").WithLocation(25, 19),
                // (25,27): error CS1026: ) expected
                //         if (i is (default)!) {} // error 16
                Diagnostic(ErrorCode.ERR_CloseParenExpected, "!").WithLocation(25, 27),
                // (25,28): error CS1525: Invalid expression term ')'
                //         if (i is (default)!) {} // error 16
                Diagnostic(ErrorCode.ERR_InvalidExprTerm, ")").WithArguments(")").WithLocation(25, 28),
                // (25,28): error CS1002: ; expected
                //         if (i is (default)!) {} // error 16
                Diagnostic(ErrorCode.ERR_SemicolonExpected, ")").WithLocation(25, 28),
                // (25,28): error CS1513: } expected
                //         if (i is (default)!) {} // error 16
                Diagnostic(ErrorCode.ERR_RbraceExpected, ")").WithLocation(25, 28),
                // (26,18): error CS8129: No suitable 'Deconstruct' instance or extension method was found for type 'int', with 2 out parameters and a void return type.
                //         if (i is ((default)!)) {} // error 17
                Diagnostic(ErrorCode.ERR_MissingDeconstruct, "((default)!)").WithArguments("int", "2").WithLocation(26, 18),
                // (26,20): error CS8505: A default literal 'default' is not valid as a pattern. Use another literal (e.g. '0' or 'null') as appropriate. To match everything, use a discard pattern '_'.
                //         if (i is ((default)!)) {} // error 17
                Diagnostic(ErrorCode.ERR_DefaultPattern, "default").WithLocation(26, 20),
                // (26,28): error CS1003: Syntax error, ',' expected
                //         if (i is ((default)!)) {} // error 17
                Diagnostic(ErrorCode.ERR_SyntaxError, "!").WithArguments(",").WithLocation(26, 28),
                // (26,29): error CS1525: Invalid expression term ')'
                //         if (i is ((default)!)) {} // error 17
                Diagnostic(ErrorCode.ERR_InvalidExprTerm, ")").WithArguments(")").WithLocation(26, 29)
                );
        }
 
        [Fact]
        public void SwitchExpression_01()
        {
            // test appropriate language version or feature flag
            var source =
@"class Program
{
    public static void Main()
    {
        var r = 1 switch { _ => 0, };
    }
}";
            CreateCompilation(source, options: TestOptions.DebugExe, parseOptions: TestOptions.RegularWithoutRecursivePatterns).VerifyDiagnostics(
                // (5,19): error CS8370: Feature 'recursive patterns' is not available in C# 7.3. Please use language version 8.0 or greater.
                //         var r = 1 switch { _ => 0, };
                Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7_3, "switch").WithArguments("recursive patterns", "8.0").WithLocation(5, 19),
                // (5,28): error CS8370: Feature 'recursive patterns' is not available in C# 7.3. Please use language version 8.0 or greater.
                //         var r = 1 switch { _ => 0, };
                Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7_3, "_").WithArguments("recursive patterns", "8.0").WithLocation(5, 28));
 
            CreateCompilation(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular8).VerifyDiagnostics();
        }
 
        [Fact]
        public void SwitchExpression_02()
        {
            // test switch expression's governing expression has no type
            // test switch expression's governing expression has type void
            var source =
@"class Program
{
    public static void Main()
    {
        var r1 = (1, null) switch { _ => 0 };
        var r2 = System.Console.Write(1) switch { _ => 0 };
    }
}";
            CreatePatternCompilation(source).VerifyDiagnostics(
                // (5,18): error CS8117: Invalid operand for pattern match; value required, but found '(int, <null>)'.
                //         var r1 = (1, null) switch ( _ => 0 );
                Diagnostic(ErrorCode.ERR_BadPatternExpression, "(1, null)").WithArguments("(int, <null>)").WithLocation(5, 18),
                // (6,18): error CS8117: Invalid operand for pattern match; value required, but found 'void'.
                //         var r2 = System.Console.Write(1) switch ( _ => 0 );
                Diagnostic(ErrorCode.ERR_BadPatternExpression, "System.Console.Write(1)").WithArguments("void").WithLocation(6, 18)
                );
        }
 
        [Fact]
        public void SwitchExpression_03()
        {
            // test that a ternary expression is not at an appropriate precedence
            // for the constant expression of a constant pattern in a switch expression arm.
            var source =
@"class Program
{
    public static void Main()
    {
        bool b = true;
        var r1 = b switch { true ? true : true => true, false => false };
        var r2 = b switch { (true ? true : true) => true, false => false };
    }
}";
            // This is admittedly poor syntax error recovery (for the line declaring r2),
            // but this test demonstrates that it is a syntax error.
            CreatePatternCompilation(source).VerifyDiagnostics(
                // (6,34): error CS1003: Syntax error, '=>' expected
                //         var r1 = b switch { true ? true : true => true, false => false };
                Diagnostic(ErrorCode.ERR_SyntaxError, "?").WithArguments("=>").WithLocation(6, 34),
                // (6,34): error CS1525: Invalid expression term '?'
                //         var r1 = b switch { true ? true : true => true, false => false };
                Diagnostic(ErrorCode.ERR_InvalidExprTerm, "?").WithArguments("?").WithLocation(6, 34),
                // (6,48): error CS1003: Syntax error, ',' expected
                //         var r1 = b switch { true ? true : true => true, false => false };
                Diagnostic(ErrorCode.ERR_SyntaxError, "=>").WithArguments(",").WithLocation(6, 48),
                // (6,48): error CS8504: Pattern missing
                //         var r1 = b switch { true ? true : true => true, false => false };
                Diagnostic(ErrorCode.ERR_MissingPattern, "=>").WithLocation(6, 48)
                );
        }
 
        [Fact]
        public void SwitchExpression_04()
        {
            // test that a ternary expression is permitted as a constant pattern in recursive contexts and the case expression.
            var source =
@"class Program
{
    public static void Main()
    {
        var b = (true, false);
        var r1 = b switch { (true ? true : true, _) => true, _ => false, };
        var r2 = b is (true ? true : true, _);
        switch (b.Item1) { case true ? true : true: break; }
    }
}";
            CreatePatternCompilation(source).VerifyDiagnostics(
                );
        }
 
        [Fact]
        public void SwitchExpression_05()
        {
            // test throw expression in match arm.
            var source =
@"class Program
{
    public static void Main()
    {
        var x = 1 switch { 1 => 1, _ => throw null };
    }
}";
            CreatePatternCompilation(source).VerifyDiagnostics(
                );
        }
 
        [Fact]
        public void EmptySwitchExpression()
        {
            var source =
@"class Program
{
    public static void Main()
    {
        var r = 1 switch { };
    }
}";
            CreatePatternCompilation(source).VerifyDiagnostics(
                // (5,19): warning CS8509: The switch expression does not handle all possible values of its input type (it is not exhaustive). For example, the pattern '_' is not covered.
                //         var r = 1 switch { };
                Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustive, "switch").WithArguments("_").WithLocation(5, 19),
                // (5,19): error CS8506: No best type was found for the switch expression.
                //         var r = 1 switch { };
                Diagnostic(ErrorCode.ERR_SwitchExpressionNoBestType, "switch").WithLocation(5, 19));
        }
 
        [Fact]
        public void SwitchExpression_06()
        {
            // test common type vs delegate in match expression
            var source =
@"class Program
{
    public static void Main()
    {
        var x = 1 switch { 0 => M, 1 => new D(M), 2 => M };
        x();
    }
    public static void M() {}
    public delegate void D();
}";
            CreatePatternCompilation(source).VerifyDiagnostics(
                // (5,19): warning CS8509: The switch expression does not handle all possible values of its input type (it is not exhaustive). For example, the pattern '3' is not covered.
                //         var x = 1 switch { 0 => M, 1 => new D(M), 2 => M };
                Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustive, "switch").WithArguments("3").WithLocation(5, 19)
                );
        }
 
        [Fact]
        public void SwitchExpression_07()
        {
            // test flow analysis of the switch expression
            var source =
@"class Program
{
    public static void Main()
    {
        int q = 1;
        int u;
        var x = q switch { 0 => u=0, 1 => u=1, _ => u=2 };
        System.Console.WriteLine(u);
    }
}";
            CreatePatternCompilation(source).VerifyDiagnostics(
                );
        }
 
        [Fact]
        public void SwitchExpression_08()
        {
            // test flow analysis of the switch expression
            var source =
@"class Program
{
    public static void Main()
    {
        int q = 1;
        int u;
        var x = q switch { 0 => u=0, 1 => 1, _ => u=2 };
        System.Console.WriteLine(u);
    }
    static int M(int i) => i;
}";
            CreatePatternCompilation(source).VerifyDiagnostics(
                // (8,34): error CS0165: Use of unassigned local variable 'u'
                //         System.Console.WriteLine(u);
                Diagnostic(ErrorCode.ERR_UseDefViolation, "u").WithArguments("u").WithLocation(8, 34)
                );
        }
 
        [Fact]
        public void SwitchExpression_09()
        {
            // test flow analysis of the switch expression
            var source =
@"class Program
{
    public static void Main()
    {
        int q = 1;
        int u;
        var x = q switch { 0 => u=0, 1 => u=M(u), _ => u=2, };
        System.Console.WriteLine(u);
    }
    static int M(int i) => i;
}";
            CreatePatternCompilation(source).VerifyDiagnostics(
                // (7,47): error CS0165: Use of unassigned local variable 'u'
                //         var x = q switch { 0 => u=0, 1 => u=M(u), _ => u=2 };
                Diagnostic(ErrorCode.ERR_UseDefViolation, "u").WithArguments("u").WithLocation(7, 47)
                );
        }
 
        [Fact]
        public void SwitchExpression_10()
        {
            // test lazily inferring variables in the pattern
            // test lazily inferring variables in the when clause
            // test lazily inferring variables in the arrow expression
            var source =
@"class Program
{
    public static void Main()
    {
        int a = 1;
        var b = a switch { var x1 => x1, };
        var c = a switch { var x2 when x2 is var x3 => x3 };
        var d = a switch { var x4 => x4 is var x5 ? x5 : 1, };
    }
    static int M(int i) => i;
}";
            var compilation = CreatePatternCompilation(source);
            compilation.VerifyDiagnostics(
                // (7,19): warning CS8846: The switch expression does not handle all possible values of its input type (it is not exhaustive). For example, the pattern '_' is not covered. However, a pattern with a 'when' clause might successfully match this value.
                //         var c = a switch { var x2 when x2 is var x3 => x3 };
                Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustiveWithWhen, "switch").WithArguments("_").WithLocation(7, 19)
                );
            var names = new[] { "x1", "x2", "x3", "x4", "x5" };
            var tree = compilation.SyntaxTrees[0];
            foreach (var designation in tree.GetRoot().DescendantNodes().OfType<SingleVariableDesignationSyntax>())
            {
                var model = compilation.GetSemanticModel(tree);
                var symbol = model.GetDeclaredSymbol(designation);
                Assert.Equal(SymbolKind.Local, symbol.Kind);
                Assert.Equal("int", ((ILocalSymbol)symbol).Type.ToDisplayString());
            }
            foreach (var ident in tree.GetRoot().DescendantNodes().OfType<IdentifierNameSyntax>())
            {
                var model = compilation.GetSemanticModel(tree);
                var typeInfo = model.GetTypeInfo(ident);
                Assert.Equal("int", typeInfo.Type.ToDisplayString());
            }
        }
 
        [Fact]
        public void ShortDiscardInIsPattern()
        {
            // test that we forbid a short discard at the top level of an is-pattern expression
            var source =
@"class Program
{
    public static void Main()
    {
        int a = 1;
        if (a is _) { }
    }
}";
            var compilation = CreatePatternCompilation(source);
            compilation.VerifyDiagnostics(
                // (6,18): error CS0246: The type or namespace name '_' could not be found (are you missing a using directive or an assembly reference?)
                //         if (a is _) { }
                Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "_").WithArguments("_").WithLocation(6, 18)
                );
        }
 
        [Fact]
        public void Patterns2_04()
        {
            // Test that a single-element deconstruct pattern is an error if no further elements disambiguate.
            var source =
@"
using System;
class Program
{
    public static void Main()
    {
        var t = new System.ValueTuple<int>(1);
        if (t is (int x)) { }                           // error 1
        switch (t) { case (_): break; }                 // error 2
        var u = t switch { (int y) => y, _ => 2 };      // error 3
        if (t is (int z1) _) { }                        // ok
        if (t is (Item1: int z2)) { }                   // ok
        if (t is (int z3) { }) { }                      // ok
        if (t is ValueTuple<int>(int z4)) { }           // ok
    }
}";
            var compilation = CreateCompilation(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular8);
            compilation.VerifyDiagnostics(
                // (8,18): error CS8400: Feature 'parenthesized pattern' is not available in C# 8.0. Please use language version 9.0 or greater.
                //         if (t is (int x)) { }                           // error 1
                Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion8, "(").WithArguments("parenthesized pattern", "9.0").WithLocation(8, 18),
                // (8,19): error CS8121: An expression of type 'ValueTuple<int>' cannot be handled by a pattern of type 'int'.
                //         if (t is (int x)) { }                           // error 1
                Diagnostic(ErrorCode.ERR_PatternWrongType, "int").WithArguments("System.ValueTuple<int>", "int").WithLocation(8, 19),
                // (9,27): error CS8400: Feature 'parenthesized pattern' is not available in C# 8.0. Please use language version 9.0 or greater.
                //         switch (t) { case (_): break; }                 // error 2
                Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion8, "(").WithArguments("parenthesized pattern", "9.0").WithLocation(9, 27),
                // (10,28): error CS8400: Feature 'parenthesized pattern' is not available in C# 8.0. Please use language version 9.0 or greater.
                //         var u = t switch { (int y) => y, _ => 2 };      // error 3
                Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion8, "(").WithArguments("parenthesized pattern", "9.0").WithLocation(10, 28),
                // (10,29): error CS8121: An expression of type 'ValueTuple<int>' cannot be handled by a pattern of type 'int'.
                //         var u = t switch { (int y) => y, _ => 2 };      // error 3
                Diagnostic(ErrorCode.ERR_PatternWrongType, "int").WithArguments("System.ValueTuple<int>", "int").WithLocation(10, 29));
        }
 
        [Fact]
        public void Patterns2_05()
        {
            // Test parsing the var pattern
            // Test binding the var pattern
            // Test lowering the var pattern for the is-expression
            var source =
@"
using System;
class Program
{
    public static void Main()
    {
        var t = (1, 2);
        { Check(true, t is var (x, y) && x == 1 && y == 2); }
        { Check(false, t is var (x, y) && x == 1 && y == 3); }
    }
    private static void Check<T>(T expected, T actual)
    {
        if (!object.Equals(expected, actual)) throw new Exception($""Expected: '{expected}', Actual: '{actual}'"");
    }
}";
            var compilation = CreatePatternCompilation(source);
            compilation.VerifyDiagnostics(
                );
            var comp = CompileAndVerify(compilation, expectedOutput: @"");
        }
 
        [Fact]
        public void Patterns2_06()
        {
            // Test that 'var' does not bind to a type
            var source =
@"
using System;
namespace N
{
    class Program
    {
        public static void Main()
        {
            var t = (1, 2);
            { Check(true, t is var (x, y) && x == 1 && y == 2); }  // error 1
            { Check(false, t is var (x, y) && x == 1 && y == 3); } // error 2
            { Check(true, t is var x); }                           // error 3
        }
        private static void Check<T>(T expected, T actual)
        {
            if (!object.Equals(expected, actual)) throw new Exception($""Expected: '{expected}', Actual: '{actual}'"");
        }
    }
    class @var { }
}";
            var compilation = CreatePatternCompilation(source);
            compilation.VerifyDiagnostics(
                // (9,21): error CS0029: Cannot implicitly convert type '(int, int)' to 'N.var'
                //             var t = (1, 2);
                Diagnostic(ErrorCode.ERR_NoImplicitConv, "(1, 2)").WithArguments("(int, int)", "N.var").WithLocation(9, 21),
                // (10,32): error CS8508: The syntax 'var' for a pattern is not permitted to refer to a type, but 'N.var' is in scope here.
                //             { Check(true, t is var (x, y) && x == 1 && y == 2); }  // error 1
                Diagnostic(ErrorCode.ERR_VarMayNotBindToType, "var").WithArguments("N.var").WithLocation(10, 32),
                // (10,36): error CS1061: 'var' does not contain a definition for 'Deconstruct' and no accessible extension method 'Deconstruct' accepting a first argument of type 'var' could be found (are you missing a using directive or an assembly reference?)
                //             { Check(true, t is var (x, y) && x == 1 && y == 2); }  // error 1
                Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "(x, y)").WithArguments("N.var", "Deconstruct").WithLocation(10, 36),
                // (10,36): error CS8129: No suitable 'Deconstruct' instance or extension method was found for type 'var', with 2 out parameters and a void return type.
                //             { Check(true, t is var (x, y) && x == 1 && y == 2); }  // error 1
                Diagnostic(ErrorCode.ERR_MissingDeconstruct, "(x, y)").WithArguments("N.var", "2").WithLocation(10, 36),
                // (11,33): error CS8508: The syntax 'var' for a pattern is not permitted to refer to a type, but 'N.var' is in scope here.
                //             { Check(false, t is var (x, y) && x == 1 && y == 3); } // error 2
                Diagnostic(ErrorCode.ERR_VarMayNotBindToType, "var").WithArguments("N.var").WithLocation(11, 33),
                // (11,37): error CS1061: 'var' does not contain a definition for 'Deconstruct' and no accessible extension method 'Deconstruct' accepting a first argument of type 'var' could be found (are you missing a using directive or an assembly reference?)
                //             { Check(false, t is var (x, y) && x == 1 && y == 3); } // error 2
                Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "(x, y)").WithArguments("N.var", "Deconstruct").WithLocation(11, 37),
                // (11,37): error CS8129: No suitable 'Deconstruct' instance or extension method was found for type 'var', with 2 out parameters and a void return type.
                //             { Check(false, t is var (x, y) && x == 1 && y == 3); } // error 2
                Diagnostic(ErrorCode.ERR_MissingDeconstruct, "(x, y)").WithArguments("N.var", "2").WithLocation(11, 37),
                // (12,32): error CS8508: The syntax 'var' for a pattern is not permitted to refer to a type, but 'N.var' is in scope here.
                //             { Check(true, t is var x); }                           // error 3
                Diagnostic(ErrorCode.ERR_VarMayNotBindToType, "var").WithArguments("N.var").WithLocation(12, 32)
                );
        }
 
        [Fact]
        public void Patterns2_10()
        {
            var source =
@"
using System;
class Program
{
    public static void Main()
    {
        Console.Write(M((false, false)));
        Console.Write(M((false, true)));
        Console.Write(M((true, false)));
        Console.Write(M((true, true)));
    }
    private static int M((bool, bool) t)
    {
        switch (t)
        {
            case (false, false): return 0;
            case (false, _): return 1;
            case (_, false): return 2;
            case var _: return 3;
        }
    }
}
 
namespace System
{
    public struct ValueTuple<T1, T2>
    {
        public T1 Item1;
        public T2 Item2;
 
        public ValueTuple(T1 item1, T2 item2)
        {
            this.Item1 = item1;
            this.Item2 = item2;
        }
    }
}";
            var compilation = CreatePatternCompilation(source);
            compilation.VerifyDiagnostics(
                );
            var comp = CompileAndVerify(compilation, expectedOutput: @"0123");
        }
 
        [Fact]
        public void Patterns2_11()
        {
            var source =
@"
using System;
class Program
{
    public static void Main()
    {
        Console.Write(M((false, false)));
        Console.Write(M((false, true)));
        Console.Write(M((true, false)));
        Console.Write(M((true, true)));
    }
    private static int M((bool, bool) t)
    {
        switch (t)
        {
            case (false, false): return 0;
            case (false, _): return 1;
            case (_, false): return 2;
            case (true, true): return 3;
            case var _: return 4;
        }
    }
}
 
namespace System
{
    public struct ValueTuple<T1, T2>
    {
        public T1 Item1;
        public T2 Item2;
 
        public ValueTuple(T1 item1, T2 item2)
        {
            this.Item1 = item1;
            this.Item2 = item2;
        }
    }
}";
            var compilation = CreatePatternCompilation(source);
            compilation.VerifyDiagnostics(
                // (20,18): error CS8120: The switch case is unreachable. It has already been handled by a previous case or it is impossible to match.
                //             case var _: return 4;
                Diagnostic(ErrorCode.ERR_SwitchCaseSubsumed, "var _").WithLocation(20, 18)
                );
        }
 
        [Fact]
        public void Patterns2_12()
        {
            var source =
@"
using System;
class Program
{
    public static void Main()
    {
        Console.Write(M((false, false)));
        Console.Write(M((false, true)));
        Console.Write(M((true, false)));
        Console.Write(M((true, true)));
    }
    private static int M((bool, bool) t)
    {
        return t switch {
            (false, false) => 0,
            (false, _) => 1,
            (_, false) => 2,
            _ => 3
        };
    }
}
 
namespace System
{
    public struct ValueTuple<T1, T2>
    {
        public T1 Item1;
        public T2 Item2;
 
        public ValueTuple(T1 item1, T2 item2)
        {
            this.Item1 = item1;
            this.Item2 = item2;
        }
    }
}";
            var compilation = CreatePatternCompilation(source);
            compilation.VerifyDiagnostics(
                );
            var comp = CompileAndVerify(compilation, expectedOutput: @"0123");
        }
 
        [Fact]
        public void SwitchArmSubsumed()
        {
            var source =
@"public class X
{
    public static void Main()
    {
        string s = string.Empty;
        string s2 = s switch { null => null, string t => t, ""foo"" => null };
    }
}";
            var compilation = CreatePatternCompilation(source);
            compilation.VerifyDiagnostics(
                // (6,61): error CS8410: The pattern is unreachable. It has already been handled by a previous arm of the switch expression or it is impossible to match.
                //         string s2 = s switch { null => null, string t => t, "foo" => null };
                Diagnostic(ErrorCode.ERR_SwitchArmSubsumed, @"""foo""").WithLocation(6, 61)
                );
        }
 
        [Fact]
        public void LongTuples()
        {
            var source =
@"using System;
 
public class X
{
    public static void Main()
    {
        var t = (1, 2, 3, 4, 5, 6, 7, 8, 9);
        {
            Console.WriteLine(t is (_, _, _, _, _, _, _, _, var t9) ? t9 : 100);
        }
        switch (t)
        {
            case (_, _, _, _, _, _, _, _, var t9):
                Console.WriteLine(t9);
                break;
        }
        Console.WriteLine(t switch { (_, _, _, _, _, _, _, _, var t9) => t9 });
    }
}";
            var compilation = CreatePatternCompilation(source);
            compilation.VerifyDiagnostics(
                );
            var comp = CompileAndVerify(compilation, expectedOutput: @"9
9
9");
        }
 
        [Fact]
        public void TypeCheckInPropertyPattern()
        {
            var source =
@"using System;
 
class Program2
{
    public static void Main()
    {
        object o = new Frog(1, 2);
        if (o is Frog(1, 2))
        {
            Console.Write(1);
        }
        if (o is Frog { A: 1, B: 2 })
        {
            Console.Write(2);
        }
        if (o is Frog(1, 2) { A: 1, B: 2, C: 3 })
        {
            Console.Write(3);
        }
 
        if (o is Frog(9, 2) { A: 1, B: 2, C: 3 }) {} else
        {
            Console.Write(4);
        }
        if (o is Frog(1, 9) { A: 1, B: 2, C: 3 }) {} else
        {
            Console.Write(5);
        }
        if (o is Frog(1, 2) { A: 9, B: 2, C: 3 }) {} else
        {
            Console.Write(6);
        }
        if (o is Frog(1, 2) { A: 1, B: 9, C: 3 }) {} else
        {
            Console.Write(7);
        }
        if (o is Frog(1, 2) { A: 1, B: 2, C: 9 }) {} else
        {
            Console.Write(8);
        }
    }
}
 
class Frog
{
    public object A, B;
    public object C => (int)A + (int)B;
    public Frog(object A, object B) => (this.A, this.B) = (A, B);
    public void Deconstruct(out object A, out object B) => (A, B) = (this.A, this.B);
}
";
            var compilation = CreatePatternCompilation(source);
            compilation.VerifyDiagnostics(
                );
            var comp = CompileAndVerify(compilation, expectedOutput: @"12345678");
        }
 
        [Fact]
        public void OvereagerSubsumption()
        {
            var source =
@"class Program2
{
    public static int Main() => 0;
    public static void M(object o)
    {
        switch (o)
        {
            case (1, 2):
                break;
            case string s:
                break;
        }
    }
}
";
            var compilation = CreateCompilationWithMscorlib461(source); // doesn't have ITuple
            // Two errors below instead of one due to https://github.com/dotnet/roslyn/issues/25533
            compilation.VerifyDiagnostics(
                // (8,18): error CS1061: 'object' does not contain a definition for 'Deconstruct' and no accessible extension method 'Deconstruct' accepting a first argument of type 'object' could be found (are you missing a using directive or an assembly reference?)
                //             case (1, 2):
                Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "(1, 2)").WithArguments("object", "Deconstruct").WithLocation(8, 18),
                // (8,18): error CS8129: No suitable Deconstruct instance or extension method was found for type 'object', with 2 out parameters and a void return type.
                //             case (1, 2):
                Diagnostic(ErrorCode.ERR_MissingDeconstruct, "(1, 2)").WithArguments("object", "2").WithLocation(8, 18)
                );
        }
 
        [Fact]
        public void UnderscoreDeclaredAndDiscardPattern_01()
        {
            var source =
@"class Program0
{
    static int Main() => 0;
    private const int _ = 1;
    bool M1(object o) => o is _;
    bool M2(object o) => o switch { 1 => true, _ => false };
}
class Program1
{
    class _ {}
    bool M3(object o) => o is _;
    bool M4(object o) => o switch { 1 => true, _ => false };
}
";
            var expected = new[]
            {
                // (5,31): error CS0246: The type or namespace name '_' could not be found (are you missing a using directive or an assembly reference?)
                //     bool M1(object o) => o is _;
                Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "_").WithArguments("_").WithLocation(5, 31),
                // (11,31): warning CS8513: The name '_' refers to the type 'Program1._', not the discard pattern. Use '@_' for the type, or 'var _' to discard.
                //     bool M3(object o) => o is _;
                Diagnostic(ErrorCode.WRN_IsTypeNamedUnderscore, "_").WithArguments("Program1._").WithLocation(11, 31)
            };
 
            var compilation = CreatePatternCompilation(source);
            compilation.VerifyDiagnostics(expected);
 
            compilation = CreateCompilation(source, parseOptions: TestOptions.Regular8);
            compilation.VerifyDiagnostics(expected);
 
            compilation = CreateCompilation(source, parseOptions: TestOptions.Regular7_3);
            compilation.VerifyDiagnostics(
                // (5,31): error CS0246: The type or namespace name '_' could not be found (are you missing a using directive or an assembly reference?)
                //     bool M1(object o) => o is _;
                Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "_").WithArguments("_").WithLocation(5, 31),
                // (6,28): error CS8370: Feature 'recursive patterns' is not available in C# 7.3. Please use language version 8.0 or greater.
                //     bool M2(object o) => o switch { 1 => true, _ => false };
                Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7_3, "switch").WithArguments("recursive patterns", "8.0").WithLocation(6, 28),
                // (6,48): error CS8370: Feature 'recursive patterns' is not available in C# 7.3. Please use language version 8.0 or greater.
                //     bool M2(object o) => o switch { 1 => true, _ => false };
                Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7_3, "_").WithArguments("recursive patterns", "8.0").WithLocation(6, 48),
                // (12,28): error CS8370: Feature 'recursive patterns' is not available in C# 7.3. Please use language version 8.0 or greater.
                //     bool M4(object o) => o switch { 1 => true, _ => false };
                Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7_3, "switch").WithArguments("recursive patterns", "8.0").WithLocation(12, 28),
                // (12,48): error CS8370: Feature 'recursive patterns' is not available in C# 7.3. Please use language version 8.0 or greater.
                //     bool M4(object o) => o switch { 1 => true, _ => false };
                Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7_3, "_").WithArguments("recursive patterns", "8.0").WithLocation(12, 48));
        }
 
        [Fact]
        public void UnderscoreDeclaredAndDiscardPattern_02()
        {
            var source =
@"class Program0
{
    static int Main() => 0;
    private const int _ = 1;
}
class Program1 : Program0
{
    bool M2(object o) => o switch { 1 => true, _ => false }; // ok, private member not inherited
}
";
            var compilation = CreatePatternCompilation(source);
            compilation.VerifyDiagnostics(
                );
        }
 
        [Fact]
        public void UnderscoreDeclaredAndDiscardPattern_03()
        {
            var source =
@"class Program0
{
    static int Main() => 0;
    protected const int _ = 1;
}
class Program1 : Program0
{
    bool M2(object o) => o switch { 1 => true, _ => false };
}
class Program2
{
    bool _(object q) => true;
    bool M2(object o) => o switch { 1 => true, _ => false };
}
";
            var compilation = CreatePatternCompilation(source);
            compilation.VerifyDiagnostics(
                );
        }
 
        [Fact]
        public void UnderscoreDeclaredAndDiscardPattern_04()
        {
            var source =
@"using _ = System.Int32;
class Program
{
    static int Main() => 0;
    bool M2(object o) => o switch { 1 => true, _ => false };
}
";
            var compilation = CreatePatternCompilation(source);
            compilation.VerifyDiagnostics(
                // (1,1): hidden CS8019: Unnecessary using directive.
                // using _ = System.Int32;
                Diagnostic(ErrorCode.HDN_UnusedUsingDirective, "using _ = System.Int32;").WithLocation(1, 1)
                );
        }
 
        [Fact]
        public void EscapingUnderscoreDeclaredAndDiscardPattern_04()
        {
            var source =
@"class Program0
{
    static int Main() => 0;
    private const int _ = 2;
    bool M1(object o) => o is @_;
    int M2(object o) => o switch { 1 => 1, @_ => 2, var _ => 3 };
}
class Program1
{
    class _ {}
    bool M1(object o) => o is @_;
}
";
            var compilation = CreatePatternCompilation(source);
            compilation.VerifyDiagnostics(
                );
        }
 
        [Fact]
        public void ErroneousSwitchArmDefiniteAssignment()
        {
            // When a switch expression arm is erroneous, ensure that the expression is treated as unreachable (e.g. for definite assignment purposes).
            var source =
@"class Program2
{
    public static int Main() => 0;
    public static void M(string s)
    {
        int i;
        int j = s switch { ""frog"" => 1, 0 => i, _ => 2 };
    }
}
";
            var compilation = CreatePatternCompilation(source);
            compilation.VerifyDiagnostics(
                // (7,41): error CS0029: Cannot implicitly convert type 'int' to 'string'
                //         int j = s switch { "frog" => 1, 0 => i, _ => 2 };
                Diagnostic(ErrorCode.ERR_NoImplicitConv, "0").WithArguments("int", "string").WithLocation(7, 41)
                );
        }
 
        [Fact, WorkItem(9154, "https://github.com/dotnet/roslyn/issues/9154")]
        public void ErroneousIsPatternDefiniteAssignment()
        {
            var source =
@"class Program2
{
    public static int Main() => 0;
    void Dummy(object o) {}
    void Test5()
    {
        Dummy((System.Func<object, object, bool>) ((o1, o2) => o1 is int x5 && 
                                                               o2 is int x5 && 
                                                               x5 > 0));
    }
}
";
            var compilation = CreatePatternCompilation(source);
            compilation.VerifyDiagnostics(
                // (8,74): error CS0128: A local variable or function named 'x5' is already defined in this scope
                //                                                                o2 is int x5 && 
                Diagnostic(ErrorCode.ERR_LocalDuplicate, "x5").WithArguments("x5").WithLocation(8, 74)
                );
        }
 
        [Fact]
        public void ERR_IsPatternImpossible()
        {
            var source =
@"class Program
{
    public static void Main()
    {
        System.Console.WriteLine(""frog"" is string { Length: 4, Length: 5 });
    }
}
";
            var compilation = CreatePatternCompilation(source);
            compilation.VerifyDiagnostics(
                // (5,34): error CS8415: An expression of type 'string' can never match the provided pattern.
                //         System.Console.WriteLine("frog" is string { Length: 4, Length: 5 });
                Diagnostic(ErrorCode.ERR_IsPatternImpossible, @"""frog"" is string { Length: 4, Length: 5 }").WithArguments("string").WithLocation(5, 34)
                );
        }
 
        [Fact]
        public void WRN_GivenExpressionNeverMatchesPattern01()
        {
            var source =
@"class Program
{
    public static void Main()
    {
        System.Console.WriteLine(3 is 4);
    }
}
";
            var compilation = CreatePatternCompilation(source);
            compilation.VerifyDiagnostics(
                // (5,34): warning CS8416: The given expression never matches the provided pattern.
                //         System.Console.WriteLine(3 is 4);
                Diagnostic(ErrorCode.WRN_GivenExpressionNeverMatchesPattern, "3 is 4").WithLocation(5, 34)
                );
        }
 
        [Fact]
        public void WRN_GivenExpressionNeverMatchesPattern02()
        {
            var source =
@"class Program
{
    public static void Main()
    {
        const string s = null;
        System.Console.WriteLine(s is string { Length: 3 });
    }
}
";
            var compilation = CreatePatternCompilation(source);
            compilation.VerifyDiagnostics(
                // (6,34): warning CS8416: The given expression never matches the provided pattern.
                //         System.Console.WriteLine(s is string { Length: 3 });
                Diagnostic(ErrorCode.WRN_GivenExpressionNeverMatchesPattern, "s is string { Length: 3 }").WithLocation(6, 34)
                );
        }
 
        [Fact]
        public void DefiniteAssignmentForIsPattern01()
        {
            var source =
@"class Program
{
    public static void Main()
    {
        string s = 300.ToString();
        System.Console.WriteLine(s is string { Length: int j });
        System.Console.WriteLine(j);
    }
}
";
            var compilation = CreatePatternCompilation(source);
            compilation.VerifyDiagnostics(
                // (7,34): error CS0165: Use of unassigned local variable 'j'
                //         System.Console.WriteLine(j);
                Diagnostic(ErrorCode.ERR_UseDefViolation, "j").WithArguments("j").WithLocation(7, 34)
                );
        }
 
        [Fact]
        public void DefiniteAssignmentForIsPattern02()
        {
            var source =
@"class Program
{
    public static void Main()
    {
        const string s = ""300"";
        System.Console.WriteLine(s is string { Length: int j });
        System.Console.WriteLine(j);
    }
}
";
            var compilation = CreateCompilation(source, options: TestOptions.DebugExe, parseOptions: TestOptions.RegularWithRecursivePatterns);
            compilation.VerifyDiagnostics();
            var expectedOutput = @"True
3";
            var compVerifier = CompileAndVerify(compilation, expectedOutput: expectedOutput);
        }
 
        [Fact]
        public void DefiniteAssignmentForIsPattern03()
        {
            var source =
@"class Program
{
    public static void Main()
    {
        int j;
        const string s = null;
        if (s is string { Length: 3 })
        {
            System.Console.WriteLine(j);
        }
    }
}
";
            var compilation = CreatePatternCompilation(source);
            compilation.VerifyDiagnostics(
                // (7,13): warning CS8416: The given expression never matches the provided pattern.
                //         if (s is string { Length: 3 })
                Diagnostic(ErrorCode.WRN_GivenExpressionNeverMatchesPattern, "s is string { Length: 3 }").WithLocation(7, 13)
                );
        }
 
        [Fact]
        public void RefutableConstantPattern01()
        {
            var source =
@"class Program
{
    public static void Main()
    {
        int j;
        const int N = 3;
        const int M = 3;
        if (N is M)
        {
        }
        else
        {
            System.Console.WriteLine(j);
        }
    }
}
";
            var compilation = CreatePatternCompilation(source);
            compilation.VerifyDiagnostics(
                // (8,13): warning CS8417: The given expression always matches the provided constant.
                //         if (N is M)
                Diagnostic(ErrorCode.WRN_GivenExpressionAlwaysMatchesConstant, "N is M").WithLocation(8, 13)
                );
        }
 
        [Fact, WorkItem(25591, "https://github.com/dotnet/roslyn/issues/25591")]
        public void TupleSubsumptionError()
        {
            var source =
@"class Program2
{
    public static void Main()
    {
        M(new Fox());
        M(new Cat());
        M(new Program2());
    }
    static void M(object o)
    {
        switch ((o, 0))
        {
            case (Fox fox, _):
                System.Console.Write(""Fox "");
                break;
            case (Cat cat, _):
                System.Console.Write(""Cat"");
                break;
        }
    }
}
class Fox {}
class Cat {}
";
            var compilation = CreatePatternCompilation(source);
            compilation.VerifyDiagnostics(
                );
            var comp = CompileAndVerify(compilation, expectedOutput: @"Fox Cat");
        }
 
        [Fact, WorkItem(25934, "https://github.com/dotnet/roslyn/issues/25934")]
        public void NamesInPositionalPatterns01()
        {
            var source =
@"class Program
{
    static void Main()
    {
        switch (a: 1, b: 2)
        {
            case (c: 2, d: 3): // error: c and d not defined
                break;
        }
    }
}
";
            var compilation = CreatePatternCompilation(source);
            compilation.VerifyDiagnostics(
                // (7,19): error CS8416: The name 'c' does not identify tuple element 'Item1'.
                //             case (c: 2, d: 3): // error: c and d not defined
                Diagnostic(ErrorCode.ERR_TupleElementNameMismatch, "c").WithArguments("c", "Item1").WithLocation(7, 19),
                // (7,25): error CS8416: The name 'd' does not identify tuple element 'Item2'.
                //             case (c: 2, d: 3): // error: c and d not defined
                Diagnostic(ErrorCode.ERR_TupleElementNameMismatch, "d").WithArguments("d", "Item2").WithLocation(7, 25)
                );
        }
 
        [Fact, WorkItem(25934, "https://github.com/dotnet/roslyn/issues/25934")]
        public void NamesInPositionalPatterns02()
        {
            var source =
@"class Program
{
    static void Main()
    {
        switch (a: 1, b: 2)
        {
            case (a: 2, a: 3):
                break;
        }
    }
}
";
            var compilation = CreatePatternCompilation(source);
            compilation.VerifyDiagnostics(
                // (7,25): error CS8416: The name 'a' does not identify tuple element 'Item2'.
                //             case (a: 2, a: 3):
                Diagnostic(ErrorCode.ERR_TupleElementNameMismatch, "a").WithArguments("a", "Item2").WithLocation(7, 25)
                );
        }
 
        [Fact, WorkItem(25934, "https://github.com/dotnet/roslyn/issues/25934")]
        public void NamesInPositionalPatterns03()
        {
            var source =
@"class Program
{
    static void Main()
    {
        switch (a: 1, b: 2)
        {
            case (a: 2, Item2: 3):
                System.Console.WriteLine(666);
                break;
            case (a: 1, Item2: 2):
                System.Console.WriteLine(111);
                break;
        }
    }
}
";
            var compilation = CreatePatternCompilation(source);
            compilation.VerifyDiagnostics(
                );
            var comp = CompileAndVerify(compilation, expectedOutput: @"111");
        }
 
        [Fact, WorkItem(25934, "https://github.com/dotnet/roslyn/issues/25934")]
        public void NamesInPositionalPatterns04()
        {
            var source =
@"class Program
{
    static void Main()
    {
        switch (new T(a: 1, b: 2))
        {
            case (c: 2, d: 3):
                break;
        }
    }
}
class T
{
    public int A;
    public int B;
    public T(int a, int b) => (A, B) = (a, b);
    public void Deconstruct(out int a, out int b) => (a, b) = (A, B);
}
";
            var compilation = CreatePatternCompilation(source);
            compilation.VerifyDiagnostics(
                // (7,19): error CS8417: The name 'c' does not match the corresponding 'Deconstruct' parameter 'a'.
                //             case (c: 2, d: 3):
                Diagnostic(ErrorCode.ERR_DeconstructParameterNameMismatch, "c").WithArguments("c", "a").WithLocation(7, 19),
                // (7,25): error CS8417: The name 'd' does not match the corresponding 'Deconstruct' parameter 'b'.
                //             case (c: 2, d: 3):
                Diagnostic(ErrorCode.ERR_DeconstructParameterNameMismatch, "d").WithArguments("d", "b").WithLocation(7, 25)
                );
        }
 
        [Fact, WorkItem(25934, "https://github.com/dotnet/roslyn/issues/25934")]
        public void NamesInPositionalPatterns05()
        {
            var source =
@"class Program
{
    static void Main()
    {
        switch (new T(a: 1, b: 2))
        {
            case (c: 2, d: 3):
                break;
        }
    }
}
class T
{
    public int A;
    public int B;
    public T(int a, int b) => (A, B) = (a, b);
}
static class Extensions
{
    public static void Deconstruct(this T t, out int a, out int b) => (a, b) = (t.A, t.B);
}
";
            var compilation = CreatePatternCompilation(source);
            compilation.VerifyDiagnostics(
                // (7,19): error CS8417: The name 'c' does not match the corresponding 'Deconstruct' parameter 'a'.
                //             case (c: 2, d: 3):
                Diagnostic(ErrorCode.ERR_DeconstructParameterNameMismatch, "c").WithArguments("c", "a").WithLocation(7, 19),
                // (7,25): error CS8417: The name 'd' does not match the corresponding 'Deconstruct' parameter 'b'.
                //             case (c: 2, d: 3):
                Diagnostic(ErrorCode.ERR_DeconstructParameterNameMismatch, "d").WithArguments("d", "b").WithLocation(7, 25)
                );
        }
 
        [Fact, WorkItem(25934, "https://github.com/dotnet/roslyn/issues/25934")]
        public void NamesInPositionalPatterns06()
        {
            var source =
@"class Program
{
    static void Main()
    {
        switch (new T(a: 1, b: 2))
        {
            case (a: 2, a: 3):
                break;
        }
    }
}
class T
{
    public int A;
    public int B;
    public T(int a, int b) => (A, B) = (a, b);
    public void Deconstruct(out int a, out int b) => (a, b) = (A, B);
}
";
            var compilation = CreatePatternCompilation(source);
            compilation.VerifyDiagnostics(
                // (7,25): error CS8417: The name 'a' does not match the corresponding 'Deconstruct' parameter 'b'.
                //             case (a: 2, a: 3):
                Diagnostic(ErrorCode.ERR_DeconstructParameterNameMismatch, "a").WithArguments("a", "b").WithLocation(7, 25)
                );
        }
 
        [Fact, WorkItem(25934, "https://github.com/dotnet/roslyn/issues/25934")]
        public void NamesInPositionalPatterns07()
        {
            var source =
@"class Program
{
    static void Main()
    {
        switch (new T(a: 1, b: 2))
        {
            case (a: 2, a: 3):
                break;
        }
    }
}
class T
{
    public int A;
    public int B;
    public T(int a, int b) => (A, B) = (a, b);
}
static class Extensions
{
    public static void Deconstruct(this T t, out int a, out int b) => (a, b) = (t.A, t.B);
}
";
            var compilation = CreatePatternCompilation(source);
            compilation.VerifyDiagnostics(
                // (7,25): error CS8417: The name 'a' does not match the corresponding 'Deconstruct' parameter 'b'.
                //             case (a: 2, a: 3):
                Diagnostic(ErrorCode.ERR_DeconstructParameterNameMismatch, "a").WithArguments("a", "b").WithLocation(7, 25)
                );
        }
 
        [Fact, WorkItem(25934, "https://github.com/dotnet/roslyn/issues/25934")]
        public void NamesInPositionalPatterns08()
        {
            var source =
@"class Program
{
    static void Main()
    {
        switch (new T(a: 1, b: 2))
        {
            case (a: 2, b: 3):
                System.Console.WriteLine(666);
                break;
            case (a: 1, b: 2):
                System.Console.WriteLine(111);
                break;
        }
    }
}
class T
{
    public int A;
    public int B;
    public T(int a, int b) => (A, B) = (a, b);
    public void Deconstruct(out int a, out int b) => (a, b) = (A, B);
}
";
            var compilation = CreatePatternCompilation(source);
            compilation.VerifyDiagnostics(
                );
            var comp = CompileAndVerify(compilation, expectedOutput: @"111");
        }
 
        [Fact, WorkItem(25934, "https://github.com/dotnet/roslyn/issues/25934")]
        public void NamesInPositionalPatterns09()
        {
            var source =
@"class Program
{
    static void Main()
    {
        switch (new T(a: 1, b: 2))
        {
            case (a: 2, b: 3):
                System.Console.WriteLine(666);
                break;
            case (a: 1, b: 2):
                System.Console.WriteLine(111);
                break;
        }
    }
}
class T
{
    public int A;
    public int B;
    public T(int a, int b) => (A, B) = (a, b);
}
static class Extensions
{
    public static void Deconstruct(this T t, out int a, out int b) => (a, b) = (t.A, t.B);
}
";
            var compilation = CreatePatternCompilation(source);
            compilation.VerifyDiagnostics(
                );
            var comp = CompileAndVerify(compilation, expectedOutput: @"111");
        }
 
        [Fact, WorkItem(25934, "https://github.com/dotnet/roslyn/issues/25934")]
        public void NamesInPositionalPatterns10()
        {
            var source =
@"class Program
{
    static void Main()
    {
        switch (a: 1, b: 2)
        {
            case (Item2: 1, 2):
                break;
        }
    }
}
";
            var compilation = CreatePatternCompilation(source);
            compilation.VerifyDiagnostics(
                // (7,19): error CS8416: The name 'Item2' does not identify tuple element 'Item1'.
                //             case (Item2: 1, 2):
                Diagnostic(ErrorCode.ERR_TupleElementNameMismatch, "Item2").WithArguments("Item2", "Item1").WithLocation(7, 19)
                );
        }
 
        [Fact]
        public void PropertyPatternMemberMissing01()
        {
            var source =
@"class Program
{
    static void Main(string[] args)
    {
        Blah b = null;
        if (b is Blah { X: int i })
        {
        }
    }
}
 
class Blah
{
}";
            var compilation = CreatePatternCompilation(source);
            compilation.VerifyDiagnostics(
                // (6,25): error CS0117: 'Blah' does not contain a definition for 'X'
                //         if (b is Blah { X: int i })
                Diagnostic(ErrorCode.ERR_NoSuchMember, "X").WithArguments("Blah", "X").WithLocation(6, 25)
                );
        }
 
        [Fact]
        public void PropertyPatternMemberMissing02()
        {
            var source =
@"class Program
{
    static void Main(string[] args)
    {
        Blah b = null;
        if (b is Blah { X: int i })
        {
        }
    }
}
 
class Blah
{
    public int X { set {} }
}";
            var compilation = CreatePatternCompilation(source);
            compilation.VerifyDiagnostics(
                // (6,25): error CS0154: The property or indexer 'Blah.X' cannot be used in this context because it lacks the get accessor
                //         if (b is Blah { X: int i })
                Diagnostic(ErrorCode.ERR_PropertyLacksGet, "X:").WithArguments("Blah.X").WithLocation(6, 25)
                );
        }
 
        [Fact]
        public void PropertyPatternMemberMissing03()
        {
            var source =
@"class Program
{
    static void Main(string[] args)
    {
        Blah b = null;
        switch (b)
        {
            case Blah { X: int i }:
                break;
        }
    }
}
 
class Blah
{
}";
            var compilation = CreatePatternCompilation(source);
            compilation.VerifyDiagnostics(
                // (8,25): error CS0117: 'Blah' does not contain a definition for 'X'
                //             case Blah { X: int i }:
                Diagnostic(ErrorCode.ERR_NoSuchMember, "X").WithArguments("Blah", "X").WithLocation(8, 25)
                );
        }
 
        [Fact]
        public void PropertyPatternMemberMissing04()
        {
            var source =
@"class Program
{
    static void Main(string[] args)
    {
        Blah b = null;
        switch (b)
        {
            case Blah { X: int i }:
                break;
        }
    }
}
 
class Blah
{
    public int X { set {} }
}";
            var compilation = CreatePatternCompilation(source);
            compilation.VerifyDiagnostics(
                // (8,25): error CS0154: The property or indexer 'Blah.X' cannot be used in this context because it lacks the get accessor
                //             case Blah { X: int i }:
                Diagnostic(ErrorCode.ERR_PropertyLacksGet, "X:").WithArguments("Blah.X").WithLocation(8, 25)
                );
        }
 
        [Fact]
        [WorkItem(24550, "https://github.com/dotnet/roslyn/issues/24550")]
        [WorkItem(1284, "https://github.com/dotnet/csharplang/issues/1284")]
        public void ConstantPatternVsUnconstrainedTypeParameter03()
        {
            var source =
@"class C<T>
{
    internal struct S { }
    static bool Test(S s)
    {
        return s is null;
    }
}";
            var compilation = CreateCompilation(source, options: TestOptions.ReleaseDll);
            compilation.VerifyDiagnostics(
                // (6,21): error CS0037: Cannot convert null to 'C<T>.S' because it is a non-nullable value type
                //         return s is null;
                Diagnostic(ErrorCode.ERR_ValueCantBeNull, "null").WithArguments("C<T>.S").WithLocation(6, 21)
                );
        }
 
        [Fact]
        [WorkItem(24550, "https://github.com/dotnet/roslyn/issues/24550")]
        [WorkItem(1284, "https://github.com/dotnet/csharplang/issues/1284")]
        public void ConstantPatternVsUnconstrainedTypeParameter04()
        {
            var source =
@"class C<T>
{
    static bool Test(C<T> x)
    {
        return x is 1;
    }
}";
            var compilation = CreateCompilation(source, options: TestOptions.ReleaseDll);
            compilation.VerifyDiagnostics(
                // (5,21): error CS8121: An expression of type 'C<T>' cannot be handled by a pattern of type 'int'.
                //         return x is 1;
                Diagnostic(ErrorCode.ERR_PatternWrongType, "1").WithArguments("C<T>", "int").WithLocation(5, 21)
                );
        }
 
        [Fact]
        [WorkItem(20724, "https://github.com/dotnet/roslyn/issues/20724")]
        public void SpeculateWithNameConflict01()
        {
            var source =
@"public class Class1
    {
        int i = 1;
 
        public override int GetHashCode() => 1;
        public override bool Equals(object obj)
        {
            return obj is global::Class1 @class && this.i == @class.i;
        }
    }
";
            var compilation = CreateCompilation(source, options: TestOptions.ReleaseDll);
            compilation.VerifyDiagnostics(
                );
            var tree = compilation.SyntaxTrees[0];
            var model = (CSharpSemanticModel)compilation.GetSemanticModel(tree);
            var returnStatement = tree.GetRoot().DescendantNodes().OfType<ReturnStatementSyntax>().Single();
            Assert.Equal("return obj is global::Class1 @class && this.i == @class.i;", returnStatement.ToString());
            var modifiedReturnStatement = (ReturnStatementSyntax)new RemoveAliasQualifiers().Visit(returnStatement);
            Assert.Equal("return obj is Class1 @class && this.i == @class.i;", modifiedReturnStatement.ToString());
            var gotModel = model.TryGetSpeculativeSemanticModel(returnStatement.Location.SourceSpan.Start, modifiedReturnStatement, out var speculativeModel);
            Assert.True(gotModel);
            Assert.NotNull(speculativeModel);
            var typeInfo = speculativeModel.GetTypeInfo(modifiedReturnStatement.Expression);
            Assert.Equal(SpecialType.System_Boolean, typeInfo.Type.SpecialType);
        }
 
        /// <summary>
        /// Helper class to remove alias qualifications.
        /// </summary>
        class RemoveAliasQualifiers : CSharpSyntaxRewriter
        {
            public override SyntaxNode VisitAliasQualifiedName(AliasQualifiedNameSyntax node)
            {
                return node.Name;
            }
        }
 
        [Fact]
        [WorkItem(20724, "https://github.com/dotnet/roslyn/issues/20724")]
        public void SpeculateWithNameConflict02()
        {
            var source =
@"public class Class1
    {
        public override int GetHashCode() => 1;
        public override bool Equals(object obj)
        {
            return obj is global::Class1 @class;
        }
    }
";
            var compilation = CreateCompilation(source, options: TestOptions.ReleaseDll);
            compilation.VerifyDiagnostics(
                );
            var tree = compilation.SyntaxTrees[0];
            var model = (CSharpSemanticModel)compilation.GetSemanticModel(tree);
            var returnStatement = tree.GetRoot().DescendantNodes().OfType<ReturnStatementSyntax>().Single();
            Assert.Equal("return obj is global::Class1 @class;", returnStatement.ToString());
            var modifiedReturnStatement = (ReturnStatementSyntax)new RemoveAliasQualifiers().Visit(returnStatement);
            Assert.Equal("return obj is Class1 @class;", modifiedReturnStatement.ToString());
            var gotModel = model.TryGetSpeculativeSemanticModel(returnStatement.Location.SourceSpan.Start, modifiedReturnStatement, out var speculativeModel);
            Assert.True(gotModel);
            Assert.NotNull(speculativeModel);
            var typeInfo = speculativeModel.GetTypeInfo(modifiedReturnStatement.Expression);
            Assert.Equal(SpecialType.System_Boolean, typeInfo.Type.SpecialType);
        }
 
        [Fact]
        public void WrongArity()
        {
            var source =
@"class Program
{
    static void Main(string[] args)
    {
        Point p = new Point() { X = 3, Y = 4 };
        if (p is Point())
        {
        }
    }
}
 
class Point
{
    public int X, Y;
    public void Deconstruct(out int X, out int Y) => (X, Y) = (this.X, this.Y);
}
";
            var compilation = CreateCompilation(source, options: TestOptions.ReleaseDll);
            compilation.VerifyDiagnostics(
                // (6,23): error CS7036: There is no argument given that corresponds to the required parameter 'X' of 'Point.Deconstruct(out int, out int)'
                //         if (p is Point())
                Diagnostic(ErrorCode.ERR_NoCorrespondingArgument, "()").WithArguments("X", "Point.Deconstruct(out int, out int)").WithLocation(6, 23),
                // (6,23): error CS8129: No suitable Deconstruct instance or extension method was found for type 'Point', with 0 out parameters and a void return type.
                //         if (p is Point())
                Diagnostic(ErrorCode.ERR_MissingDeconstruct, "()").WithArguments("Point", "0").WithLocation(6, 23)
                );
        }
 
        [Fact]
        public void GetTypeInfo_01()
        {
            var source =
@"class Program
{
    static void Main(string[] args)
    {
        object o = null;
        Point p = null;
        if (o is Point(3, string { Length: 2 })) { }
        if (p is (_, { })) { }
        if (p is Point({ }, { }, { })) { }
        if (p is Point(, { })) { }
    }
}
 
class Point
{
    public object X, Y;
    public void Deconstruct(out object X, out object Y) => (X, Y) = (this.X, this.Y);
    public Point(object X, object Y) => (this.X, this.Y) = (X, Y);
}
";
            var expected = new[]
            {
                new { Source = "Point(3, string { Length: 2 })", Type = "System.Object", ConvertedType = "Point" },
                new { Source = "3", Type = "System.Object", ConvertedType = "System.Int32" },
                new { Source = "string { Length: 2 }", Type = "System.Object", ConvertedType = "System.String" },
                new { Source = "2", Type = "System.Int32", ConvertedType = "System.Int32" },
                new { Source = "(_, { })", Type = "Point", ConvertedType = "Point" },
                new { Source = "_", Type = "System.Object", ConvertedType = "System.Object" },
                new { Source = "{ }", Type = "System.Object", ConvertedType = "System.Object" },
                new { Source = "Point({ }, { }, { })", Type = "Point", ConvertedType = "Point" },
                new { Source = "{ }", Type = "?", ConvertedType = "?" },
                new { Source = "{ }", Type = "?", ConvertedType = "?" },
                new { Source = "{ }", Type = "?", ConvertedType = "?" },
                new { Source = "Point(, { })", Type = "Point", ConvertedType = "Point" },
                new { Source = "", Type = "System.Object", ConvertedType = "System.Object" },
                new { Source = "{ }", Type = "System.Object", ConvertedType = "System.Object" },
            };
            var compilation = CreateCompilation(source, options: TestOptions.ReleaseDll);
            compilation.VerifyDiagnostics(
                // (10,24): error CS8504: Pattern missing
                //         if (p is Point(, { })) { }
                Diagnostic(ErrorCode.ERR_MissingPattern, ",").WithLocation(10, 24),
                // (9,23): error CS1501: No overload for method 'Deconstruct' takes 3 arguments
                //         if (p is Point({ }, { }, { })) { }
                Diagnostic(ErrorCode.ERR_BadArgCount, "({ }, { }, { })").WithArguments("Deconstruct", "3").WithLocation(9, 23),
                // (9,23): error CS8129: No suitable 'Deconstruct' instance or extension method was found for type 'Point', with 3 out parameters and a void return type.
                //         if (p is Point({ }, { }, { })) { }
                Diagnostic(ErrorCode.ERR_MissingDeconstruct, "({ }, { }, { })").WithArguments("Point", "3").WithLocation(9, 23)
                );
            var tree = compilation.SyntaxTrees[0];
            var model = compilation.GetSemanticModel(tree);
            int i = 0;
            foreach (var pat in tree.GetRoot().DescendantNodesAndSelf().OfType<PatternSyntax>())
            {
                var typeInfo = model.GetTypeInfo(pat);
                var ex = expected[i++];
                Assert.Equal(ex.Source, pat.ToString());
                Assert.Equal(ex.Type, typeInfo.Type.ToTestDisplayString());
                Assert.Equal(ex.ConvertedType, typeInfo.ConvertedType.ToTestDisplayString());
            }
            Assert.Equal(expected.Length, i);
        }
 
        [Fact, WorkItem(26613, "https://github.com/dotnet/roslyn/issues/26613")]
        public void MissingDeconstruct_01()
        {
            var source =
@"using System;
public class C {
    public void M() {
        _ = this is (a: 1);
    }
}
";
            var compilation = CreateCompilation(source, options: TestOptions.ReleaseDll);
            compilation.VerifyDiagnostics(
                // (4,21): error CS1061: 'C' does not contain a definition for 'Deconstruct' and no accessible extension method 'Deconstruct' accepting a first argument of type 'C' could be found (are you missing a using directive or an assembly reference?)
                //         _ = this is (a: 1);
                Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "(a: 1)").WithArguments("C", "Deconstruct").WithLocation(4, 21),
                // (4,21): error CS8129: No suitable 'Deconstruct' instance or extension method was found for type 'C', with 1 out parameters and a void return type.
                //         _ = this is (a: 1);
                Diagnostic(ErrorCode.ERR_MissingDeconstruct, "(a: 1)").WithArguments("C", "1").WithLocation(4, 21)
                );
        }
 
        [Fact, WorkItem(26613, "https://github.com/dotnet/roslyn/issues/26613")]
        public void MissingDeconstruct_02()
        {
            var source =
@"using System;
public class C {
    public void M() {
        _ = this is C(a: 1);
    }
}
";
            var compilation = CreateCompilation(source, options: TestOptions.ReleaseDll);
            compilation.VerifyDiagnostics(
                // (4,22): error CS1061: 'C' does not contain a definition for 'Deconstruct' and no extension method 'Deconstruct' accepting a first argument of type 'C' could be found (are you missing a using directive or an assembly reference?)
                //         _ = this is C(a: 1);
                Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "(a: 1)").WithArguments("C", "Deconstruct").WithLocation(4, 22),
                // (4,22): error CS8129: No suitable Deconstruct instance or extension method was found for type 'C', with 1 out parameters and a void return type.
                //         _ = this is C(a: 1);
                Diagnostic(ErrorCode.ERR_MissingDeconstruct, "(a: 1)").WithArguments("C", "1").WithLocation(4, 22)
                );
        }
 
        [Fact]
        public void PatternTypeInfo_01()
        {
            var source = @"
public class C
{
    void M(T1 t1)
    {
        if (t1 is T2 (var t3, t4: T4 t4) { V5 : T6 t5 }) {}
    }
}
class T1
{
}
class T2 : T1
{
    public T5 V5 = null;
    public void Deconstruct(out T3 t3, out T4 t4) => throw null;
}
class T3
{
}
class T4
{
}
class T5
{
}
class T6 : T5
{
}
";
            var compilation = CreateCompilation(source);
            compilation.VerifyDiagnostics();
            var tree = compilation.SyntaxTrees[0];
            var model = compilation.GetSemanticModel(tree);
            var patterns = tree.GetRoot().DescendantNodesAndSelf().OfType<PatternSyntax>().ToArray();
            Assert.Equal(4, patterns.Length);
 
            Assert.Equal("T2 (var t3, t4: T4 t4) { V5 : T6 t5 }", patterns[0].ToString());
            var ti = model.GetTypeInfo(patterns[0]);
            Assert.Equal("T1", ti.Type.ToTestDisplayString());
            Assert.Equal("T2", ti.ConvertedType.ToTestDisplayString());
 
            Assert.Equal("var t3", patterns[1].ToString());
            ti = model.GetTypeInfo(patterns[1]);
            Assert.Equal("T3", ti.Type.ToTestDisplayString());
            Assert.Equal("T3", ti.ConvertedType.ToTestDisplayString());
 
            Assert.Equal("T4 t4", patterns[2].ToString());
            ti = model.GetTypeInfo(patterns[2]);
            Assert.Equal("T4", ti.Type.ToTestDisplayString());
            Assert.Equal("T4", ti.ConvertedType.ToTestDisplayString());
 
            Assert.Equal("T6 t5", patterns[3].ToString());
            ti = model.GetTypeInfo(patterns[3]);
            Assert.Equal("T5", ti.Type.ToTestDisplayString());
            Assert.Equal("T6", ti.ConvertedType.ToTestDisplayString());
        }
 
        [Fact]
        public void PatternTypeInfo_02()
        {
            var source = @"
public class C
{
    void M(object o)
    {
        if (o is Point(3, 4.0)) {}
    }
}
class Point
{
    public void Deconstruct(out object o1, out System.IComparable o2) => throw null;
}
";
            var compilation = CreateCompilation(source);
            compilation.VerifyDiagnostics();
            var tree = compilation.SyntaxTrees[0];
            var model = compilation.GetSemanticModel(tree);
            var patterns = tree.GetRoot().DescendantNodesAndSelf().OfType<PatternSyntax>().ToArray();
            Assert.Equal(3, patterns.Length);
 
            Assert.Equal("Point(3, 4.0)", patterns[0].ToString());
            var ti = model.GetTypeInfo(patterns[0]);
            Assert.Equal("System.Object", ti.Type.ToTestDisplayString());
            Assert.Equal("Point", ti.ConvertedType.ToTestDisplayString());
 
            Assert.Equal("3", patterns[1].ToString());
            ti = model.GetTypeInfo(patterns[1]);
            Assert.Equal("System.Object", ti.Type.ToTestDisplayString());
            Assert.Equal("System.Int32", ti.ConvertedType.ToTestDisplayString());
 
            Assert.Equal("4.0", patterns[2].ToString());
            ti = model.GetTypeInfo(patterns[2]);
            Assert.Equal("System.IComparable", ti.Type.ToTestDisplayString());
            Assert.Equal("System.Double", ti.ConvertedType.ToTestDisplayString());
        }
 
        [Fact]
        public void PatternTypeInfo_03()
        {
            var source = @"
public class C
{
    void M(object o)
    {
        if (o is Point(3, 4.0) { Missing: Xyzzy }) {}
        if (o is Q7 t) {}
    }
}
";
            var compilation = CreateCompilation(source);
            compilation.VerifyDiagnostics(
                // (6,18): error CS0246: The type or namespace name 'Point' could not be found (are you missing a using directive or an assembly reference?)
                //         if (o is Point(3, 4.0) { Missing: Xyzzy }) {}
                Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "Point").WithArguments("Point").WithLocation(6, 18),
                // (6,43): error CS0103: The name 'Xyzzy' does not exist in the current context
                //         if (o is Point(3, 4.0) { Missing: Xyzzy }) {}
                Diagnostic(ErrorCode.ERR_NameNotInContext, "Xyzzy").WithArguments("Xyzzy").WithLocation(6, 43),
                // (7,18): error CS0246: The type or namespace name 'Q7' could not be found (are you missing a using directive or an assembly reference?)
                //         if (o is Q7 t) {}
                Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "Q7").WithArguments("Q7").WithLocation(7, 18)
                );
            var tree = compilation.SyntaxTrees[0];
            var model = compilation.GetSemanticModel(tree);
            var patterns = tree.GetRoot().DescendantNodesAndSelf().OfType<PatternSyntax>().ToArray();
            Assert.Equal(5, patterns.Length);
 
            Assert.Equal("Point(3, 4.0) { Missing: Xyzzy }", patterns[0].ToString());
            var ti = model.GetTypeInfo(patterns[0]);
            Assert.Equal("System.Object", ti.Type.ToTestDisplayString());
            Assert.Equal("Point", ti.ConvertedType.ToTestDisplayString());
 
            Assert.Equal("3", patterns[1].ToString());
            ti = model.GetTypeInfo(patterns[1]);
            Assert.Equal("?", ti.Type.ToTestDisplayString());
            Assert.Equal(TypeKind.Error, ti.Type.TypeKind);
            Assert.Equal("System.Int32", ti.ConvertedType.ToTestDisplayString());
 
            Assert.Equal("4.0", patterns[2].ToString());
            ti = model.GetTypeInfo(patterns[2]);
            Assert.Equal("?", ti.Type.ToTestDisplayString());
            Assert.Equal(TypeKind.Error, ti.Type.TypeKind);
            Assert.Equal("System.Double", ti.ConvertedType.ToTestDisplayString());
 
            Assert.Equal("Xyzzy", patterns[3].ToString());
            ti = model.GetTypeInfo(patterns[3]);
            Assert.Equal("?", ti.Type.ToTestDisplayString());
            Assert.Equal(TypeKind.Error, ti.Type.TypeKind);
            Assert.Equal("?", ti.ConvertedType.ToTestDisplayString());
            Assert.Equal(TypeKind.Error, ti.ConvertedType.TypeKind);
 
            Assert.Equal("Q7 t", patterns[4].ToString());
            ti = model.GetTypeInfo(patterns[4]);
            Assert.Equal("System.Object", ti.Type.ToTestDisplayString());
            Assert.Equal("Q7", ti.ConvertedType.ToTestDisplayString());
            Assert.Equal(TypeKind.Error, ti.ConvertedType.TypeKind);
        }
 
        [Fact]
        [WorkItem(34678, "https://github.com/dotnet/roslyn/issues/34678")]
        public void ConstantPatternVsUnconstrainedTypeParameter05()
        {
            var source =
@"class C<T>
{
    static bool Test1(T t)
    {
        return t is null; // 1
    }
    static bool Test2(C<T> t)
    {
        return t is null; // ok
    }
    static bool Test3(T t)
    {
        return t is 1; // 2
    }
    static bool Test4(T t)
    {
        return t is ""frog""; // 3
    }
}";
            CreateCompilation(source, options: TestOptions.ReleaseDll).VerifyDiagnostics();
            CreateCompilation(source, options: TestOptions.ReleaseDll, parseOptions: TestOptions.Regular7_3).VerifyDiagnostics(
                // (5,21): error CS8511: An expression of type 'T' cannot be handled by a pattern of type '<null>'. Please use language version '8.0' or greater to match an open type with a constant pattern.
                //         return t is null; // 1
                Diagnostic(ErrorCode.ERR_ConstantPatternVsOpenType, "null").WithArguments("T", "<null>", "8.0").WithLocation(5, 21),
                // (13,21): error CS8511: An expression of type 'T' cannot be handled by a pattern of type 'int'. Please use language version '8.0' or greater to match an open type with a constant pattern.
                //         return t is 1; // 2
                Diagnostic(ErrorCode.ERR_ConstantPatternVsOpenType, "1").WithArguments("T", "int", "8.0").WithLocation(13, 21),
                // (17,21): error CS8511: An expression of type 'T' cannot be handled by a pattern of type 'string'. Please use language version '8.0' or greater to match an open type with a constant pattern.
                //         return t is "frog"; // 3
                Diagnostic(ErrorCode.ERR_ConstantPatternVsOpenType, @"""frog""").WithArguments("T", "string", "8.0").WithLocation(17, 21));
        }
 
        [Fact]
        [WorkItem(34905, "https://github.com/dotnet/roslyn/issues/34905")]
        public void ConstantPatternVsUnconstrainedTypeParameter06()
        {
            var source =
@"public class C<T>
{
    public enum E
    {
        V1, V2
    }
 
    public void M()
    {
        switch (default(E))
        {
            case E.V1:
                break;
        }
    }
}
";
            CreateCompilation(source, options: TestOptions.ReleaseDll).VerifyDiagnostics();
            CreateCompilation(source, options: TestOptions.ReleaseDll, parseOptions: TestOptions.Regular7_3).VerifyDiagnostics();
        }
 
        [Fact]
        public void WarnUnmatchedIsRelationalPattern()
        {
            var source =
@"public class C
{
    public void M()
    {
        _ = 1 is < 0; // 1
        _ = 1 is < 1; // 2
        _ = 1 is < 2; // 3
        _ = 1 is <= 0; // 4
        _ = 1 is <= 1; // 5
        _ = 1 is <= 2; // 6
        _ = 1 is > 0; // 7
        _ = 1 is > 1; // 8
        _ = 1 is > 2; // 9
        _ = 1 is >= 0; // 10
        _ = 1 is >= 1; // 11
        _ = 1 is >= 2; // 12
    }
}
";
            CreateCompilation(source, options: TestOptions.ReleaseDll, parseOptions: TestOptions.RegularWithPatternCombinators).VerifyDiagnostics(
                // (5,13): warning CS8519: The given expression never matches the provided pattern.
                //         _ = 1 is < 0; // 1
                Diagnostic(ErrorCode.WRN_GivenExpressionNeverMatchesPattern, "1 is < 0").WithLocation(5, 13),
                // (6,13): warning CS8519: The given expression never matches the provided pattern.
                //         _ = 1 is < 1; // 2
                Diagnostic(ErrorCode.WRN_GivenExpressionNeverMatchesPattern, "1 is < 1").WithLocation(6, 13),
                // (7,13): error CS8793: The given expression always matches the provided pattern.
                //         _ = 1 is < 2; // 3
                Diagnostic(ErrorCode.WRN_GivenExpressionAlwaysMatchesPattern, "1 is < 2").WithLocation(7, 13),
                // (8,13): warning CS8519: The given expression never matches the provided pattern.
                //         _ = 1 is <= 0; // 4
                Diagnostic(ErrorCode.WRN_GivenExpressionNeverMatchesPattern, "1 is <= 0").WithLocation(8, 13),
                // (9,13): error CS8793: The given expression always matches the provided pattern.
                //         _ = 1 is <= 1; // 5
                Diagnostic(ErrorCode.WRN_GivenExpressionAlwaysMatchesPattern, "1 is <= 1").WithLocation(9, 13),
                // (10,13): error CS8793: The given expression always matches the provided pattern.
                //         _ = 1 is <= 2; // 6
                Diagnostic(ErrorCode.WRN_GivenExpressionAlwaysMatchesPattern, "1 is <= 2").WithLocation(10, 13),
                // (11,13): error CS8793: The given expression always matches the provided pattern.
                //         _ = 1 is > 0; // 7
                Diagnostic(ErrorCode.WRN_GivenExpressionAlwaysMatchesPattern, "1 is > 0").WithLocation(11, 13),
                // (12,13): warning CS8519: The given expression never matches the provided pattern.
                //         _ = 1 is > 1; // 8
                Diagnostic(ErrorCode.WRN_GivenExpressionNeverMatchesPattern, "1 is > 1").WithLocation(12, 13),
                // (13,13): warning CS8519: The given expression never matches the provided pattern.
                //         _ = 1 is > 2; // 9
                Diagnostic(ErrorCode.WRN_GivenExpressionNeverMatchesPattern, "1 is > 2").WithLocation(13, 13),
                // (14,13): error CS8793: The given expression always matches the provided pattern.
                //         _ = 1 is >= 0; // 10
                Diagnostic(ErrorCode.WRN_GivenExpressionAlwaysMatchesPattern, "1 is >= 0").WithLocation(14, 13),
                // (15,13): error CS8793: The given expression always matches the provided pattern.
                //         _ = 1 is >= 1; // 11
                Diagnostic(ErrorCode.WRN_GivenExpressionAlwaysMatchesPattern, "1 is >= 1").WithLocation(15, 13),
                // (16,13): warning CS8519: The given expression never matches the provided pattern.
                //         _ = 1 is >= 2; // 12
                Diagnostic(ErrorCode.WRN_GivenExpressionNeverMatchesPattern, "1 is >= 2").WithLocation(16, 13)
                );
        }
 
        [Fact]
        public void RelationalPatternInSwitchWithConstantControllingExpression()
        {
            var source =
@"public class C
{
    public void M()
    {
        switch (1)
        {
            case < 0: break; // 1
            case < 1: break; // 2
            case < 2: break;
            case < 3: break; // 3
        }
    }
}
";
            CreateCompilation(source, options: TestOptions.ReleaseDll, parseOptions: TestOptions.RegularWithPatternCombinators).VerifyDiagnostics(
                // (7,23): warning CS0162: Unreachable code detected
                //             case < 0: break; // 1
                Diagnostic(ErrorCode.WRN_UnreachableCode, "break").WithLocation(7, 23),
                // (8,23): warning CS0162: Unreachable code detected
                //             case < 1: break; // 2
                Diagnostic(ErrorCode.WRN_UnreachableCode, "break").WithLocation(8, 23),
                // (10,23): warning CS0162: Unreachable code detected
                //             case < 3: break; // 3
                Diagnostic(ErrorCode.WRN_UnreachableCode, "break").WithLocation(10, 23)
                );
        }
 
        [Fact]
        public void RelationalPatternInSwitchWithOutOfRangeComparand()
        {
            var source =
@"public class C
{
    public void M(int i)
    {
        switch (i)
        {
            case < int.MinValue: break; // 1
            case <= int.MinValue: break;
            case > int.MaxValue: break; // 2
            case >= int.MaxValue: break;
        }
    }
    public void M(uint i)
    {
        switch (i)
        {
            case < 0: break; // 3
            case <= 0: break;
            case > uint.MaxValue: break; // 4
            case >= uint.MaxValue: break;
        }
    }
}
";
            CreateCompilation(source, options: TestOptions.ReleaseDll, parseOptions: TestOptions.RegularWithPatternCombinators).VerifyDiagnostics(
                    // (7,18): error CS8120: The switch case is unreachable. It has already been handled by a previous case or it is impossible to match.
                    //             case < int.MinValue: break; // 1
                    Diagnostic(ErrorCode.ERR_SwitchCaseSubsumed, "< int.MinValue").WithLocation(7, 18),
                    // (9,18): error CS8120: The switch case is unreachable. It has already been handled by a previous case or it is impossible to match.
                    //             case > int.MaxValue: break; // 2
                    Diagnostic(ErrorCode.ERR_SwitchCaseSubsumed, "> int.MaxValue").WithLocation(9, 18),
                    // (17,18): error CS8120: The switch case is unreachable. It has already been handled by a previous case or it is impossible to match.
                    //             case < 0: break; // 3
                    Diagnostic(ErrorCode.ERR_SwitchCaseSubsumed, "< 0").WithLocation(17, 18),
                    // (19,18): error CS8120: The switch case is unreachable. It has already been handled by a previous case or it is impossible to match.
                    //             case > uint.MaxValue: break; // 4
                    Diagnostic(ErrorCode.ERR_SwitchCaseSubsumed, "> uint.MaxValue").WithLocation(19, 18)
                );
        }
 
        [Fact]
        public void IsRelationalPatternWithOutOfRangeComparand()
        {
            var source =
@"public class C
{
    public void M(int i)
    {
        _ = i is < int.MinValue; // 1
        _ = i is <= int.MinValue;
        _ = i is > int.MaxValue; // 2
        _ = i is >= int.MaxValue;
    }
    public void M(uint i)
    {
        _ = i is < 0; // 3
        _ = i is <= 0;
        _ = i is > uint.MaxValue; // 4
        _ = i is >= uint.MaxValue;
    }
}
";
            CreateCompilation(source, options: TestOptions.ReleaseDll, parseOptions: TestOptions.RegularWithPatternCombinators).VerifyDiagnostics(
                    // (5,13): error CS8518: An expression of type 'int' can never match the provided pattern.
                    //         _ = i is < int.MinValue; // 1
                    Diagnostic(ErrorCode.ERR_IsPatternImpossible, "i is < int.MinValue").WithArguments("int").WithLocation(5, 13),
                    // (7,13): error CS8518: An expression of type 'int' can never match the provided pattern.
                    //         _ = i is > int.MaxValue; // 2
                    Diagnostic(ErrorCode.ERR_IsPatternImpossible, "i is > int.MaxValue").WithArguments("int").WithLocation(7, 13),
                    // (12,13): error CS8518: An expression of type 'uint' can never match the provided pattern.
                    //         _ = i is < 0; // 3
                    Diagnostic(ErrorCode.ERR_IsPatternImpossible, "i is < 0").WithArguments("uint").WithLocation(12, 13),
                    // (14,13): error CS8518: An expression of type 'uint' can never match the provided pattern.
                    //         _ = i is > uint.MaxValue; // 4
                    Diagnostic(ErrorCode.ERR_IsPatternImpossible, "i is > uint.MaxValue").WithArguments("uint").WithLocation(14, 13)
                );
        }
 
        [Fact]
        public void IsRelationalPatternWithAlwaysMatchingRange()
        {
            var source =
@"public class C
{
    public void M(int i)
    {
        _ = i is > int.MinValue;
        _ = i is >= int.MinValue; // 1
        _ = i is < int.MaxValue;
        _ = i is <= int.MaxValue; // 2
    }
    public void M(uint i)
    {
        _ = i is > 0;
        _ = i is >= 0; // 3
        _ = i is < uint.MaxValue;
        _ = i is <= uint.MaxValue; // 4
    }
}
";
            CreateCompilation(source, options: TestOptions.ReleaseDll, parseOptions: TestOptions.RegularWithPatternCombinators).VerifyDiagnostics(
                // (6,13): warning CS8794: An expression of type 'int' always matches the provided pattern.
                //         _ = i is >= int.MinValue; // 1
                Diagnostic(ErrorCode.WRN_IsPatternAlways, "i is >= int.MinValue").WithArguments("int").WithLocation(6, 13),
                // (8,13): warning CS8794: An expression of type 'int' always matches the provided pattern.
                //         _ = i is <= int.MaxValue; // 2
                Diagnostic(ErrorCode.WRN_IsPatternAlways, "i is <= int.MaxValue").WithArguments("int").WithLocation(8, 13),
                // (13,13): warning CS8794: An expression of type 'uint' always matches the provided pattern.
                //         _ = i is >= 0; // 3
                Diagnostic(ErrorCode.WRN_IsPatternAlways, "i is >= 0").WithArguments("uint").WithLocation(13, 13),
                // (15,13): warning CS8794: An expression of type 'uint' always matches the provided pattern.
                //         _ = i is <= uint.MaxValue; // 4
                Diagnostic(ErrorCode.WRN_IsPatternAlways, "i is <= uint.MaxValue").WithArguments("uint").WithLocation(15, 13)
                );
        }
 
        [Fact]
        public void IsImpossiblePatternKinds()
        {
            var source =
@"public class C
{
    public void M(string s)
    {
        _ = s is (System.Delegate); // impossible parenthesized type pattern
        _ = s is not _;             // impossible negated pattern
        _ = s is ""a"" and ""b"";   // impossible conjunctive pattern
    }
}
";
            CreateCompilation(source, options: TestOptions.ReleaseDll, parseOptions: TestOptions.RegularWithPatternCombinators).VerifyDiagnostics(
                // (5,19): error CS8121: An expression of type 'string' cannot be handled by a pattern of type 'Delegate'.
                //         _ = s is (System.Delegate); // impossible parenthesized type pattern
                Diagnostic(ErrorCode.ERR_PatternWrongType, "System.Delegate").WithArguments("string", "System.Delegate").WithLocation(5, 19),
                // (6,13): error CS8518: An expression of type 'string' can never match the provided pattern.
                //         _ = s is not _;             // impossible negated pattern
                Diagnostic(ErrorCode.ERR_IsPatternImpossible, "s is not _").WithArguments("string").WithLocation(6, 13),
                // (7,13): error CS8518: An expression of type 'string' can never match the provided pattern.
                //         _ = s is "a" and "b";   // impossible conjunctive pattern
                Diagnostic(ErrorCode.ERR_IsPatternImpossible, @"s is ""a"" and ""b""").WithArguments("string").WithLocation(7, 13)
                );
        }
 
        [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/72720")]
        public void IsNullableReferenceType_01()
        {
            var source =
@"#nullable enable
public class C {
    public void M1(object o) {
        var t = o is string? { };
    }
    public void M2(object o) {
        var t = o is (string? { });
    }
    public void M3(object o) {
        var t = o is string?;
    }
    public void M4(object o) {
        var t = o is string? _;
    }
    public void M5(object o) {
        var t = o is (string? _);
    }
}";
            CreateCompilation(source, parseOptions: TestOptions.RegularWithPatternCombinators).VerifyDiagnostics(
                // (4,22): error CS8116: It is not legal to use nullable type 'string?' in a pattern; use the underlying type 'string' instead.
                //         var t = o is string? { };
                Diagnostic(ErrorCode.ERR_PatternNullableType, "string?").WithArguments("string").WithLocation(4, 22),
                // (7,23): error CS8116: It is not legal to use nullable type 'string?' in a pattern; use the underlying type 'string' instead.
                //         var t = o is (string? { });
                Diagnostic(ErrorCode.ERR_PatternNullableType, "string?").WithArguments("string").WithLocation(7, 23),
                // (10,22): error CS8650: It is not legal to use nullable reference type 'string?' in an is-type expression; use the underlying type 'string' instead.
                //         var t = o is string?;
                Diagnostic(ErrorCode.ERR_IsNullableType, "string?").WithArguments("string").WithLocation(10, 22),
                // (13,22): error CS8116: It is not legal to use nullable type 'string?' in a pattern; use the underlying type 'string' instead.
                //         var t = o is string? _;
                Diagnostic(ErrorCode.ERR_PatternNullableType, "string?").WithArguments("string").WithLocation(13, 22),
                // (16,23): error CS8116: It is not legal to use nullable type 'string?' in a pattern; use the underlying type 'string' instead.
                //         var t = o is (string? _);
                Diagnostic(ErrorCode.ERR_PatternNullableType, "string?").WithArguments("string").WithLocation(16, 23));
        }
 
        [Fact]
        public void IsAlwaysPatternKinds()
        {
            var source =
@"public class C
{
    public void M(string s)
    {
        _ = s is (_);                   // always parenthesized discard pattern
        _ = s is not System.Delegate;   // always negated type pattern
        _ = s is string or null;        // always disjunctive pattern
    }
}
";
            CreateCompilation(source, options: TestOptions.ReleaseDll, parseOptions: TestOptions.RegularWithPatternCombinators).VerifyDiagnostics(
                // (6,22): error CS8121: An expression of type 'string' cannot be handled by a pattern of type 'Delegate'.
                //         _ = s is not System.Delegate;   // always negated type pattern
                Diagnostic(ErrorCode.ERR_PatternWrongType, "System.Delegate").WithArguments("string", "System.Delegate").WithLocation(6, 22),
                // (7,13): warning CS8794: An expression of type 'string' always matches the provided pattern.
                //         _ = s is string or null;        // always disjunctive pattern
                Diagnostic(ErrorCode.WRN_IsPatternAlways, "s is string or null").WithArguments("string").WithLocation(7, 13)
                );
        }
 
        [Fact]
        public void SemanticModelForSwitchExpression()
        {
            var source =
@"public class C
{
    void M(int i)
    {
        C x0 = i switch // 0
        {
            0 => new A(),
            1 => new B(),
            _ => throw null,
        };
        _ = i switch // 1
        {
            0 => new A(),
            1 => new B(),
            _ => throw null,
        };
        D x2 = i switch // 2
        {
            0 => new A(),
            1 => new B(),
            _ => throw null,
        };
        D x3 = i switch // 3
        {
            0 => new E(), // 3.1
            1 => new F(), // 3.2
            _ => throw null,
        };
        C x4 = i switch // 4
        {
            0 => new A(),
            1 => new B(),
            2 => new C(),
            _ => throw null,
        };
        D x5 = i switch // 5
        {
            0 => new A(),
            1 => new B(),
            2 => new C(),
            _ => throw null,
        };
        D x6 = i switch // 6
        {
            0 => 1,
            1 => 2,
            _ => throw null,
        };
        _ = (C)(i switch // 7
        {
            0 => new A(),
            1 => new B(),
            _ => throw null,
        });
        _ = (D)(i switch // 8
        {
            0 => new A(),
            1 => new B(),
            _ => throw null,
        });
        _ = (D)(i switch // 9
        {
            0 => new E(), // 9.1
            1 => new F(), // 9.2
            _ => throw null,
        });
        _ = (C)(i switch // 10
        {
            0 => new A(),
            1 => new B(),
            2 => new C(),
            _ => throw null,
        });
        _ = (D)(i switch // 11
        {
            0 => new A(),
            1 => new B(),
            2 => new C(),
            _ => throw null,
        });
        _ = (D)(i switch // 12
        {
            0 => 1,
            1 => 2,
            _ => throw null,
        });
    }
}
 
class A : C { }
class B : C { }
class D
{
    public static implicit operator D(C c) => throw null;
    public static implicit operator D(short s) => throw null;
}
class E
{
    public static implicit operator C(E c) => throw null;
}
class F
{
    public static implicit operator C(F c) => throw null;
}
";
            var comp = CreateCompilation(source, parseOptions: TestOptions.RegularWithPatternCombinators).VerifyDiagnostics(
                // (11,15): error CS8506: No best type was found for the switch expression.
                //         _ = i switch // 1
                Diagnostic(ErrorCode.ERR_SwitchExpressionNoBestType, "switch").WithLocation(11, 15),
                // (25,18): error CS0029: Cannot implicitly convert type 'E' to 'D'
                //             0 => new E(), // 3.1
                Diagnostic(ErrorCode.ERR_NoImplicitConv, "new E()").WithArguments("E", "D").WithLocation(25, 18),
                // (26,18): error CS0029: Cannot implicitly convert type 'F' to 'D'
                //             1 => new F(), // 3.2
                Diagnostic(ErrorCode.ERR_NoImplicitConv, "new F()").WithArguments("F", "D").WithLocation(26, 18),
                // (63,18): error CS0029: Cannot implicitly convert type 'E' to 'D'
                //             0 => new E(), // 9.1
                Diagnostic(ErrorCode.ERR_NoImplicitConv, "new E()").WithArguments("E", "D").WithLocation(63, 18),
                // (64,18): error CS0029: Cannot implicitly convert type 'F' to 'D'
                //             1 => new F(), // 9.2
                Diagnostic(ErrorCode.ERR_NoImplicitConv, "new F()").WithArguments("F", "D").WithLocation(64, 18)
                );
            var tree = comp.SyntaxTrees[0];
            var model = comp.GetSemanticModel(tree);
 
            void checkType(ExpressionSyntax expr, string expectedNaturalType, string expectedConvertedType, ConversionKind expectedConversionKind)
            {
                var typeInfo = model.GetTypeInfo(expr);
                var conversion = model.GetConversion(expr);
                Assert.Equal(expectedNaturalType, typeInfo.Type?.ToTestDisplayString());
                Assert.Equal(expectedConvertedType, typeInfo.ConvertedType?.ToTestDisplayString());
                Assert.Equal(expectedConversionKind, conversion.Kind);
            }
 
            var switches = tree.GetRoot().DescendantNodes().OfType<SwitchExpressionSyntax>().ToArray();
            for (int i = 0; i < switches.Length; i++)
            {
                var expr = switches[i];
                switch (i)
                {
                    case 0:
                        checkType(expr, null, "C", ConversionKind.SwitchExpression);
                        checkType(expr.Arms[0].Expression, "A", "C", ConversionKind.ImplicitReference);
                        checkType(expr.Arms[1].Expression, "B", "C", ConversionKind.ImplicitReference);
                        checkType(expr.Arms[2].Expression, null, "C", ConversionKind.ImplicitThrow);
                        break;
                    case 1:
                        checkType(expr, "?", "?", ConversionKind.Identity);
                        checkType(expr.Arms[0].Expression, "A", "?", ConversionKind.NoConversion);
                        checkType(expr.Arms[1].Expression, "B", "?", ConversionKind.NoConversion);
                        checkType(expr.Arms[2].Expression, null, "?", ConversionKind.ImplicitThrow);
                        break;
                    case 2:
                        checkType(expr, null, "D", ConversionKind.SwitchExpression);
                        checkType(expr.Arms[0].Expression, "A", "D", ConversionKind.ImplicitUserDefined);
                        checkType(expr.Arms[1].Expression, "B", "D", ConversionKind.ImplicitUserDefined);
                        checkType(expr.Arms[2].Expression, null, "D", ConversionKind.ImplicitThrow);
                        break;
                    case 3:
                        checkType(expr, "?", "D", ConversionKind.NoConversion);
                        checkType(expr.Arms[0].Expression, "E", "?", ConversionKind.NoConversion);
                        checkType(expr.Arms[1].Expression, "F", "?", ConversionKind.NoConversion);
                        checkType(expr.Arms[2].Expression, null, "?", ConversionKind.ImplicitThrow);
                        break;
                    case 4:
                    case 10:
                        checkType(expr, "C", "C", ConversionKind.Identity);
                        checkType(expr.Arms[0].Expression, "A", "C", ConversionKind.ImplicitReference);
                        checkType(expr.Arms[1].Expression, "B", "C", ConversionKind.ImplicitReference);
                        checkType(expr.Arms[2].Expression, "C", "C", ConversionKind.Identity);
                        checkType(expr.Arms[3].Expression, null, "C", ConversionKind.ImplicitThrow);
                        break;
                    case 5:
                        checkType(expr, "C", "D", ConversionKind.ImplicitUserDefined);
                        checkType(expr.Arms[0].Expression, "A", "C", ConversionKind.ImplicitReference);
                        checkType(expr.Arms[1].Expression, "B", "C", ConversionKind.ImplicitReference);
                        checkType(expr.Arms[2].Expression, "C", "C", ConversionKind.Identity);
                        checkType(expr.Arms[3].Expression, null, "C", ConversionKind.ImplicitThrow);
                        break;
                    case 11:
                        checkType(expr, "C", "C", ConversionKind.Identity);
                        checkType(expr.Arms[0].Expression, "A", "C", ConversionKind.ImplicitReference);
                        checkType(expr.Arms[1].Expression, "B", "C", ConversionKind.ImplicitReference);
                        checkType(expr.Arms[2].Expression, "C", "C", ConversionKind.Identity);
                        checkType(expr.Arms[3].Expression, null, "C", ConversionKind.ImplicitThrow);
                        break;
                    case 6:
                        checkType(expr, "System.Int32", "D", ConversionKind.SwitchExpression);
                        checkType(expr.Arms[0].Expression, "System.Int32", "D", ConversionKind.ImplicitUserDefined);
                        checkType(expr.Arms[1].Expression, "System.Int32", "D", ConversionKind.ImplicitUserDefined);
                        checkType(expr.Arms[2].Expression, null, "D", ConversionKind.ImplicitThrow);
                        break;
                    case 7:
                        checkType(expr, null, null, ConversionKind.Identity);
                        checkType(expr.Arms[0].Expression, "A", "C", ConversionKind.ImplicitReference);
                        checkType(expr.Arms[1].Expression, "B", "C", ConversionKind.ImplicitReference);
                        checkType(expr.Arms[2].Expression, null, "C", ConversionKind.ImplicitThrow);
                        checkType((CastExpressionSyntax)expr.Parent.Parent, "C", "C", ConversionKind.Identity);
                        break;
                    case 8:
                        checkType(expr, null, null, ConversionKind.Identity);
                        checkType(expr.Arms[0].Expression, "A", "D", ConversionKind.ImplicitUserDefined);
                        checkType(expr.Arms[1].Expression, "B", "D", ConversionKind.ImplicitUserDefined);
                        checkType(expr.Arms[2].Expression, null, "D", ConversionKind.ImplicitThrow);
                        checkType((CastExpressionSyntax)expr.Parent.Parent, "D", "D", ConversionKind.Identity);
                        break;
                    case 9:
                        checkType(expr, "?", "?", ConversionKind.Identity);
                        checkType(expr.Arms[0].Expression, "E", "?", ConversionKind.NoConversion);
                        checkType(expr.Arms[1].Expression, "F", "?", ConversionKind.NoConversion);
                        checkType(expr.Arms[2].Expression, null, "?", ConversionKind.ImplicitThrow);
                        checkType((CastExpressionSyntax)expr.Parent.Parent, "D", "D", ConversionKind.Identity);
                        break;
                    case 12:
                        checkType(expr, "System.Int32", "System.Int32", ConversionKind.Identity);
                        checkType(expr.Arms[0].Expression, "System.Int32", "D", ConversionKind.ImplicitUserDefined);
                        checkType(expr.Arms[1].Expression, "System.Int32", "D", ConversionKind.ImplicitUserDefined);
                        checkType(expr.Arms[2].Expression, null, "D", ConversionKind.ImplicitThrow);
                        checkType((CastExpressionSyntax)expr.Parent.Parent, "D", "D", ConversionKind.Identity);
                        break;
                    default:
                        Assert.False(true);
                        break;
                }
            }
        }
 
        [Fact, WorkItem(45946, "https://github.com/dotnet/roslyn/issues/45946")]
        public void VoidPattern_01()
        {
            var source = @"
class C
{
    void F(object o)
    {
        _ = is this.F(1);
    }
}";
            CreateCompilation(source).VerifyDiagnostics(
                // (6,13): error CS1525: Invalid expression term 'is'
                //         _ = is this.F(1);
                Diagnostic(ErrorCode.ERR_InvalidExprTerm, "is").WithArguments("is").WithLocation(6, 13)
                );
        }
 
        [Fact, WorkItem(45946, "https://github.com/dotnet/roslyn/issues/45946")]
        public void VoidPattern_02()
        {
            var source = @"
class C
{
    void F(object o)
    {
        _ = switch { this.F(1) => 1 };
    }
}";
            CreateCompilation(source).VerifyDiagnostics(
                // (6,13): error CS1525: Invalid expression term 'switch'
                //         _ = switch { this.F(1) => 1 };
                Diagnostic(ErrorCode.ERR_InvalidExprTerm, "switch").WithArguments("switch").WithLocation(6, 13),
                // (6,13): warning CS8848: Operator 'switch' cannot be used here due to precedence. Use parentheses to disambiguate.
                //         _ = switch { this.F(1) => 1 };
                Diagnostic(ErrorCode.WRN_PrecedenceInversion, "switch").WithArguments("switch").WithLocation(6, 13)
                );
        }
 
        [Fact, WorkItem(48112, "https://github.com/dotnet/roslyn/issues/48112")]
        public void NullableTypePattern()
        {
            var source = @"
class C
{
    void F(object o)
    {
        _ = o switch { (int?) => 1, _ => 0 };
        _ = o switch { int? => 1, _ => 0 };
    }
}";
            CreateCompilation(source).VerifyDiagnostics(
                // (6,25): error CS8116: It is not legal to use nullable type 'int?' in a pattern; use the underlying type 'int' instead.
                //         _ = o switch { (int?) => 1, _ => 0 };
                Diagnostic(ErrorCode.ERR_PatternNullableType, "int?").WithArguments("int").WithLocation(6, 25),
                // (7,24): error CS8116: It is not legal to use nullable type 'int?' in a pattern; use the underlying type 'int' instead.
                //         _ = o switch { int? => 1, _ => 0 };
                Diagnostic(ErrorCode.ERR_PatternNullableType, "int?").WithArguments("int").WithLocation(7, 24)
                );
        }
 
        [Fact, WorkItem(55668, "https://github.com/dotnet/roslyn/issues/55668")]
        public void SharedWhenExpression_SwitchExpression()
        {
            var source = @"
int count = 0;
foreach (var position in new[] { Position.First, Position.Last })
{
    foreach (var wrap in new[] { new Wrap { Sub = new Zero() }, new Wrap { Sub = new One() }, new Wrap { Sub = new Two() }, new Wrap { Sub = new object() } })
    {
        count++;
        if (M(position, wrap) != M2(position, wrap))
            throw null;
    }
}
 
System.Console.Write(count);
 
static string M(Position position, Wrap wrap)
{
    return position switch
    {
        not Position.First when wrap.Sub is Zero => ""Not First and Zero"",
        _ when wrap is { Sub: One or Two } => ""One or Two"",
        Position.First => ""First"",
        _ => ""Other""
    };
}
 
static string M2(Position position, Wrap wrap)
{
    if (position is not Position.First && wrap.Sub is Zero)
        return ""Not First and Zero"";
    if (wrap is { Sub: One or Two })
        return ""One or Two"";
    if (position is Position.First)
        return ""First"";
    return ""Other"";
}
 
enum Position
{
    First,
    Last,
}
 
class Zero { }
class One { }
class Two { }
 
class Wrap
{
    public object Sub;
}
";
 
            CompileAndVerify(source, expectedOutput: "8");
        }
 
        [Fact, WorkItem(55668, "https://github.com/dotnet/roslyn/issues/55668")]
        public void SharedWhenExpression_SwitchStatement()
        {
            var source = @"
M(Position.Last, new Wrap { Sub = new Zero() });
M(Position.Last, new Wrap { Sub = new One() });
M(Position.Last, new Wrap { Sub = new Two() });
M(Position.First, new Wrap { Sub = new Zero() });
M(Position.Last, new Wrap { Sub = new object() });
 
static void M(Position position, Wrap wrap)
{
    string text;
    switch (position)
    {
        case not Position.First when wrap.Sub is Zero: text = ""Not First and Zero""; break;
        case var _ when wrap is { Sub: One or Two }: text = ""One or Two""; break;
        case Position.First: text = ""First""; break;
        default: text = ""Other""; break;
    }
 
    System.Console.WriteLine((position, wrap.Sub, text));
}
 
enum Position
{
    First,
    Last,
}
 
class Zero { }
class One { }
class Two { }
 
class Wrap
{
    public object Sub;
}
";
 
            CompileAndVerify(source, expectedOutput: @"
(Last, Zero, Not First and Zero)
(Last, One, One or Two)
(Last, Two, One or Two)
(First, Zero, First)
(Last, System.Object, Other)");
        }
 
        [Fact, WorkItem(55668, "https://github.com/dotnet/roslyn/issues/55668")]
        public void SharedWhenExpression_SequencePoints()
        {
            var source = @"
C.M(0, false, false);
C.M(0, true, false);
C.M(0, false, true);
C.M(1, false, false);
C.M(1, false, true);
C.M(2, false, false);
 
public class C
{
    public static void M(int i, bool b1, bool b2)
    {
        string text;
        switch (i)
        {
            case not 1 when b1:
                text = ""b1"";
                break;
            case var _ when b2:
                text = ""b2"";
                break;
            case 1:
                text = ""1"";
                break;
            default:
                text = ""default"";
                break;
        }
 
        System.Console.WriteLine((i, b1, b2, text));
    }
}
";
 
            var verifier = CompileAndVerify(source, expectedOutput: @"
(0, False, False, default)
(0, True, False, b1)
(0, False, True, b2)
(1, False, False, 1)
(1, False, True, b2)
(2, False, False, default)
");
 
            verifier.VerifyIL("C.M", @"
{
  // Code size       73 (0x49)
  .maxstack  4
  .locals init (string V_0, //text
                int V_1)
  // sequence point: switch (i)
  IL_0000:  ldarg.0
  // sequence point: <hidden>
  IL_0001:  ldc.i4.1
  IL_0002:  beq.s      IL_000f
  // sequence point: when b1
  IL_0004:  ldarg.1
  IL_0005:  brfalse.s  IL_0013
  // sequence point: text = ""b1"";
  IL_0007:  ldstr      ""b1""
  IL_000c:  stloc.0
  // sequence point: break;
  IL_000d:  br.s       IL_0035
  // sequence point: <hidden>
  IL_000f:  ldc.i4.0
  IL_0010:  stloc.1
  IL_0011:  br.s       IL_0015
  IL_0013:  ldc.i4.2
  IL_0014:  stloc.1
  // sequence point: when b2
  IL_0015:  ldarg.2
  IL_0016:  brtrue.s   IL_001f
  // sequence point: <hidden>
  IL_0018:  ldloc.1
  IL_0019:  brfalse.s  IL_0027
  IL_001b:  ldloc.1
  IL_001c:  ldc.i4.2
  IL_001d:  beq.s      IL_002f
  // sequence point: text = ""b2"";
  IL_001f:  ldstr      ""b2""
  IL_0024:  stloc.0
  // sequence point: break;
  IL_0025:  br.s       IL_0035
  // sequence point: text = ""1"";
  IL_0027:  ldstr      ""1""
  IL_002c:  stloc.0
  // sequence point: break;
  IL_002d:  br.s       IL_0035
  // sequence point: text = ""default"";
  IL_002f:  ldstr      ""default""
  IL_0034:  stloc.0
  // sequence point: System.Console.WriteLine((i, b1, b2, text));
  IL_0035:  ldarg.0
  IL_0036:  ldarg.1
  IL_0037:  ldarg.2
  IL_0038:  ldloc.0
  IL_0039:  newobj     ""System.ValueTuple<int, bool, bool, string>..ctor(int, bool, bool, string)""
  IL_003e:  box        ""System.ValueTuple<int, bool, bool, string>""
  IL_0043:  call       ""void System.Console.WriteLine(object)""
  // sequence point: }
  IL_0048:  ret
}
", source: source, sequencePoints: "C.M");
        }
 
        [Fact, WorkItem(55668, "https://github.com/dotnet/roslyn/issues/55668")]
        public void SharedWhenExpression_MissingInt32Type()
        {
            var source = @"
class C
{
    static void M(string s, bool b1, bool b2)
    {
        switch (s)
        {
            case not ""one"" when b1:
                break;
            case var _ when b2:
                break;
            case ""one"":
                break;
            default:
                break;
        }
    }
}
";
            var comp = CreateCompilation(source);
            comp.MakeTypeMissing(SpecialType.System_Int32);
            comp.VerifyEmitDiagnostics(
                // error CS0518: Predefined type 'System.Int32' is not defined or imported
                Diagnostic(ErrorCode.ERR_PredefinedTypeNotFound).WithArguments("System.Int32").WithLocation(1, 1),
                // (6,9): error CS0518: Predefined type 'System.Int32' is not defined or imported
                //         switch (s)
                Diagnostic(ErrorCode.ERR_PredefinedTypeNotFound, @"switch (s)
        {
            case not ""one"" when b1:
                break;
            case var _ when b2:
                break;
            case ""one"":
                break;
            default:
                break;
        }").WithArguments("System.Int32").WithLocation(6, 9),
                // (6,9): error CS0518: Predefined type 'System.Int32' is not defined or imported
                //         switch (s)
                Diagnostic(ErrorCode.ERR_PredefinedTypeNotFound, @"switch (s)
        {
            case not ""one"" when b1:
                break;
            case var _ when b2:
                break;
            case ""one"":
                break;
            default:
                break;
        }").WithArguments("System.Int32").WithLocation(6, 9),
                // (8,13): error CS0518: Predefined type 'System.Int32' is not defined or imported
                //             case not "one" when b1:
                Diagnostic(ErrorCode.ERR_PredefinedTypeNotFound, @"case not ""one"" when b1:").WithArguments("System.Int32").WithLocation(8, 13)
                );
        }
 
        [Fact, WorkItem(55668, "https://github.com/dotnet/roslyn/issues/55668")]
        public void SharedWhenExpression_WithBindings()
        {
            var source = @"
C.M(""Alice"", false, true);
C.M(""Bob"", false, true);
 
public class C
{
    public static void M(string s, bool b1, bool b2)
    {
        switch (s)
        {
            case not ""x"" when b1:
                throw null;
            case { Length: var j and > 2 } when b2:
                System.Console.WriteLine((s, b1, b2, j.ToString()));
                break;
            case ""x"":
                throw null;
            default:
                throw null;
        }
    }
}
";
 
            var verifier = CompileAndVerify(source, expectedOutput: @"
(Alice, False, True, 5)
(Bob, False, True, 3)
");
 
            verifier.VerifyIL("C.M", @"
{
  // Code size       95 (0x5f)
  .maxstack  4
  .locals init (int V_0,
                int V_1, //j
                string V_2)
  // sequence point: switch (s)
  IL_0000:  ldarg.0
  IL_0001:  stloc.2
  // sequence point: <hidden>
  IL_0002:  ldloc.2
  IL_0003:  ldstr      ""x""
  IL_0008:  call       ""bool string.op_Equality(string, string)""
  IL_000d:  brfalse.s  IL_002c
  IL_000f:  ldloc.2
  IL_0010:  callvirt   ""int string.Length.get""
  IL_0015:  stloc.1
  // sequence point: <hidden>
  IL_0016:  ldloc.1
  IL_0017:  ldc.i4.2
  IL_0018:  bgt.s      IL_0031
  IL_001a:  br.s       IL_005b
  IL_001c:  ldloc.2
  IL_001d:  brfalse.s  IL_005d
  IL_001f:  ldloc.2
  IL_0020:  callvirt   ""int string.Length.get""
  IL_0025:  stloc.1
  // sequence point: <hidden>
  IL_0026:  ldloc.1
  IL_0027:  ldc.i4.2
  IL_0028:  bgt.s      IL_0035
  IL_002a:  br.s       IL_005d
  // sequence point: when b1
  IL_002c:  ldarg.1
  IL_002d:  brfalse.s  IL_001c
  // sequence point: throw null;
  IL_002f:  ldnull
  IL_0030:  throw
  // sequence point: <hidden>
  IL_0031:  ldc.i4.0
  IL_0032:  stloc.0
  IL_0033:  br.s       IL_0037
  IL_0035:  ldc.i4.2
  IL_0036:  stloc.0
  // sequence point: when b2
  IL_0037:  ldarg.2
  IL_0038:  brtrue.s   IL_0041
  // sequence point: <hidden>
  IL_003a:  ldloc.0
  IL_003b:  brfalse.s  IL_005b
  IL_003d:  ldloc.0
  IL_003e:  ldc.i4.2
  IL_003f:  beq.s      IL_005d
  // sequence point: System.Console.WriteLine((s, b1, b2, j.ToString()));
  IL_0041:  ldarg.0
  IL_0042:  ldarg.1
  IL_0043:  ldarg.2
  IL_0044:  ldloca.s   V_1
  IL_0046:  call       ""string int.ToString()""
  IL_004b:  newobj     ""System.ValueTuple<string, bool, bool, string>..ctor(string, bool, bool, string)""
  IL_0050:  box        ""System.ValueTuple<string, bool, bool, string>""
  IL_0055:  call       ""void System.Console.WriteLine(object)""
  // sequence point: break;
  IL_005a:  ret
  // sequence point: throw null;
  IL_005b:  ldnull
  IL_005c:  throw
  // sequence point: throw null;
  IL_005d:  ldnull
  IL_005e:  throw
}
", source: source, sequencePoints: "C.M");
        }
 
        [Fact, WorkItem(55668, "https://github.com/dotnet/roslyn/issues/55668")]
        public void SharedWhenExpression_Multiples()
        {
            // The `b3` condition ends up in the `when` clause on four leaves in the DAG
            // and `b1` ends up in two leaves
            var source = @"
int count = 0;
 
foreach (int i1 in new[] { 0, 1 })
    foreach (int i2 in new[] { 0, 1 })
        foreach (int i3 in new[] { 0, 1 })
            foreach (bool b0 in new[] { false, true })
                foreach (bool b1 in new[] { false, true })
                    foreach (bool b2 in new[] { false, true })
                        foreach (bool b3 in new[] { false, true })
                        {
                            count++;
                            if (M(i1, i2, i3, b0, b1, b2, b3) != M2(i1, i2, i3, b0, b1, b2, b3))
                                throw null;
                        }
 
System.Console.Write(count);
 
static string M(int i1, int i2, int i3, bool b0, bool b1, bool b2, bool b3)
{
    object o = null;
    switch (i1, i2, i3)
    {
        case (var x, var y, var z) when f(x, y, z):
            throw null;
        case (not 0, 0, _) when b0:
            return ""b0"";
        case (_, not 0, 0) when b1:
            return ""b1"";
        case (0, _, not 0) when b2:
            return ""b2"";
        case (_, _, _) when b3:
            return ""b3"";
        case (0, _, _):
            return ""first"";
        case (_, 0, _):
            return ""second"";
        case (_, _, 0):
            return ""third"";
    }
    return ""last"";
}
 
static string M2(int i1, int i2, int i3, bool b0, bool b1, bool b2, bool b3)
{
    if (i1 is not 0 && i2 is 0 && b0)
        return ""b0"";
    if (i2 is not 0 && i3 is 0 && b1)
        return ""b1"";
    if (i3 is not 0 && i1 is 0 && b2)
        return ""b2"";
    if (b3)
        return ""b3"";
    if (i1 is 0)
        return ""first"";
    if (i2 is 0)
        return ""second"";
    if (i3 is 0)
        return ""third"";
    return ""last"";
}
 
static bool f(int i1, int i2, int i3) => false;
";
 
            CompileAndVerify(source, expectedOutput: "128");
        }
 
        [Fact, WorkItem(55668, "https://github.com/dotnet/roslyn/issues/55668")]
        public void SharedWhenExpression_Multiples_LabelInSharedWhenExpression()
        {
            var source = @"
int count = 0;
var wrap = new Wrap { value = null };
 
foreach (int i1 in new[] { 0, 1 })
    foreach (int i2 in new[] { 0, 1 })
        foreach (int i3 in new[] { 0, 1 })
            foreach (bool b0 in new[] { false, true })
                foreach (bool b1 in new[] { false, true })
                    foreach (bool b2 in new[] { false, true })
                        foreach (bool b3 in new[] { false, true })
                        {
                            count++;
                            if (M(i1, i2, i3, b0, b1, b2, b3) != M2(i1, i2, i3, b0, b1, b2, b3))
                                throw null;
                        }
 
System.Console.Write(count);
 
string M(int i1, int i2, int i3, bool b0, bool b1, bool b2, bool b3)
{
    switch (i1, i2, i3)
    {
        case (var x, var y, var z) when f(x, y, z):
            throw null;
        case (not 0, 0, _) when b0 && wrap is { value: string or string[] }:
            throw null;
        case (_, not 0, 0) when b1 && wrap is { value: string or string[] }:
            throw null;
        case (0, _, not 0) when b2 && wrap is { value: string or string[] }:
            throw null;
        case (_, _, _) when b3:
            return ""b3"";
        case (0, _, _):
            return ""first"";
        case (_, 0, _):
            return ""second"";
        case (_, _, 0):
            return ""third"";
    }
    return ""last"";
}
 
static string M2(int i1, int i2, int i3, bool b0, bool b1, bool b2, bool b3)
{
    if (b3)
        return ""b3"";
    if (i1 is 0)
        return ""first"";
    if (i2 is 0)
        return ""second"";
    if (i3 is 0)
        return ""third"";
    return ""last"";
}
 
static bool f(int i1, int i2, int i3) => false;
 
public class Wrap
{
    public object value;
}
";
 
            CompileAndVerify(source, expectedOutput: "128");
        }
 
        [Theory, WorkItem(57148, "https://github.com/dotnet/roslyn/issues/57148")]
        [InlineData("(short)0", "True")]
        [InlineData("short.MinValue", "True")]
        [InlineData("short.MaxValue", "True")]
        [InlineData("-1", "False")]
        [InlineData("(object)null", "False")]
        [InlineData("string.Empty", "False")]
        public void ObviousTestAfterTypeTest(string value, string expected)
        {
            var source = $@"
System.Console.Write(Extenders.F({value}));
 
static class Extenders
{{
    public const short MaxValue = 0x7FFF;
 
    public static bool F<T>(T value)
        => value switch
        {{
            <= MaxValue => true,
            _ => false
        }};
}}";
            CompileAndVerify(source, expectedOutput: expected).VerifyDiagnostics();
        }
 
        [Theory, WorkItem(57148, "https://github.com/dotnet/roslyn/issues/57148")]
        [InlineData("(int)0", "1")]
        [InlineData("(int)255", "1")]
        [InlineData("int.MinValue", "1")]
        [InlineData("int.MaxValue", "4")]
        [InlineData("(short)0", "2")]
        [InlineData("(short)255", "2")]
        [InlineData("short.MinValue", "2")]
        [InlineData("short.MaxValue", "2")]
        [InlineData("(uint)0", "8")]
        public void ObviousTestAfterTypeTest2(string value, string expected)
        {
            var source = $@"
System.Console.Write(Extenders.F({value}));
 
public static class Extenders
{{
    public static int F<T>(this T value) where T : struct
    {{
        int elementSize = value switch
        {{
            <= 255 => 1,
            <= short.MaxValue => 2,
            <= int.MaxValue => 4,
            _ => 8
        }};
 
        return elementSize;
    }}
}}";
            var comp = CreateCompilationWithSpan(source);
            comp.VerifyDiagnostics();
            CompileAndVerify(comp, expectedOutput: expected);
        }
 
        [Theory, WorkItem(57148, "https://github.com/dotnet/roslyn/issues/57148")]
        [InlineData("(uint)0", "0")]
        [InlineData("uint.MaxValue", "0")]
        [InlineData("-1", "1")]
        [InlineData("(object)null", "1")]
        [InlineData("string.Empty", "1")]
        public void ObviousTestAfterTypeTest_UnsignedIntegerNonNegative(string value, string expected)
        {
            var source = $@"
System.Console.Write(M({value}));
 
int M<T>(T o)
{{
    return o switch
    {{
       >= (uint)0 => 0,
       _ => 1
    }};
}}";
            CompileAndVerify(source, expectedOutput: expected).VerifyDiagnostics();
        }
 
        [Fact, WorkItem(57148, "https://github.com/dotnet/roslyn/issues/57148")]
        public void ObviousTestAfterTypeTest_UnsignedIntegerNegative()
        {
            var source = @"
public class C
{
    public void M<T>(T o)
    {
        _ = o switch
        {
           < (uint)0 => 0,
           _ => 2
        };
    }
}";
            CreateCompilation(source).VerifyDiagnostics(
                // (8,12): error CS8510: The pattern is unreachable. It has already been handled by a previous arm of the switch expression or it is impossible to match.
                //            < (uint)0 => 0,
                Diagnostic(ErrorCode.ERR_SwitchArmSubsumed, "< (uint)0").WithLocation(8, 12)
                );
        }
    }
}