text:
// 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 PatternSwitchTests : PatternMatchingTestBase
    {
        [Fact]
        public void EqualConstant()
        {
            var source =
@"public class X
{
    public static void Main()
    {
        switch (1)
        {
            case 1:
                break;
            case var i when ((i&1) == 0):
                break; // warning: unreachable (1)
            case 1: // error: duplicate case label
                break;
        }
    }
}";
            var compilation = CreateCompilation(source, options: TestOptions.DebugExe);
            Assert.True(compilation.GetDiagnostics().HasAnyErrors());
            compilation.VerifyDiagnostics(
                // (11,13): error CS0152: The switch statement contains multiple cases with the label value '1'
                //             case 1: // error: duplicate case label
                Diagnostic(ErrorCode.ERR_DuplicateCaseLabel, "case 1:").WithArguments("1").WithLocation(11, 13),
                // (10,17): warning CS0162: Unreachable code detected
                //                 break; // warning: unreachable (1)
                Diagnostic(ErrorCode.WRN_UnreachableCode, "break").WithLocation(10, 17)
                );
        }

        [Fact]
        public void EqualConstant02()
        {
            var source =
@"public class X
{
    public static void Main(string[] args)
    {
        switch (args.Length)
        {
            case 1 when true:
                break;
            case 1 when true: // error: subsumed
                break;
        }
    }
}";
            var compilation = CreateCompilation(source, options: TestOptions.DebugExe);
            Assert.True(compilation.GetDiagnostics().HasAnyErrors());
            compilation.VerifyDiagnostics(
                // (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 1 when true: // error: subsumed
                Diagnostic(ErrorCode.ERR_SwitchCaseSubsumed, "1").WithLocation(9, 18)
                );
        }

        [Fact]
        public void UnEqualConstant()
        {
            var source =
@"public class X
{
    public static void Main()
    {
        switch (1)
        {
            case 2 when true:
                break; // warning: unreachable code (impossible given the value)
            case 1 when true:
                break;
            case 1: // error: handled previously
                break; // warning?
        }
    }
}";
            var compilation = CreateCompilation(source, options: TestOptions.DebugExe);
            compilation.VerifyDiagnostics(
                // (11,18): error CS8120: The switch case is unreachable. It has already been handled by a previous case or it is impossible to match.
                //             case 1: // error: handled previously
                Diagnostic(ErrorCode.ERR_SwitchCaseSubsumed, "1").WithLocation(11, 18),
                // (8,17): warning CS0162: Unreachable code detected
                //                 break; // warning: unreachable code (impossible given the value)
                Diagnostic(ErrorCode.WRN_UnreachableCode, "break").WithLocation(8, 17)
                );
        }

        [Fact]
        public void SimpleSubsumption01()
        {
            var source =
@"public class X
{
    public static void Main()
    {
        string s = nameof(Main);
        switch (s)
        {
            case var n:
                break;
            case ""goo"": ; // error: subsumed by previous case
            case null: ; // error: subsumed by previous case
        }
    }
}";
            var compilation = CreateCompilation(source, options: TestOptions.DebugExe);
            Assert.True(compilation.GetDiagnostics().HasAnyErrors());
            compilation.VerifyDiagnostics(
                // (10,18): error CS8120: The switch case is unreachable. It has already been handled by a previous case or it is impossible to match.
                //             case "goo": ; // error: subsumed by previous case
                Diagnostic(ErrorCode.ERR_SwitchCaseSubsumed, @"""goo""").WithLocation(10, 18),
                // (11,18): error CS8120: The switch case is unreachable. It has already been handled by a previous case or it is impossible to match.
                //             case null: ; // error: subsumed by previous case
                Diagnostic(ErrorCode.ERR_SwitchCaseSubsumed, "null").WithLocation(11, 18),
                // (10,13): error CS0163: Control cannot fall through from one case label ('case "goo":') to another
                //             case "goo": ; // error: subsumed by previous case
                Diagnostic(ErrorCode.ERR_SwitchFallThrough, @"case ""goo"":").WithArguments("case \"goo\":").WithLocation(10, 13),
                // (11,13): error CS8070: Control cannot fall out of switch from final case label ('case null:')
                //             case null: ; // error: subsumed by previous case
                Diagnostic(ErrorCode.ERR_SwitchFallOut, "case null:").WithArguments("case null:").WithLocation(11, 13)
                );
        }

        [Fact]
        public void SimpleSubsumption02()
        {
            var source =
@"public class X
{
    public static void Main()
    {
        bool b = false;
        switch (b)
        {
            case bool n:
                break;
            case ""goo"": // wrong type
                break; // unreachable?
        }
    }
}";
            var compilation = CreateCompilation(source, options: TestOptions.DebugExe);
            Assert.True(compilation.GetDiagnostics().HasAnyErrors());
            compilation.VerifyDiagnostics(
                // (10,18): error CS0029: Cannot implicitly convert type 'string' to 'bool'
                //             case "goo": // wrong type
                Diagnostic(ErrorCode.ERR_NoImplicitConv, @"""goo""").WithArguments("string", "bool").WithLocation(10, 18)
                );
        }

        [Fact]
        public void SimpleSubsumption03()
        {
            var source =
@"using System;
public class X
{
    public static void Main()
    {
        object o = null;
        switch (o)
        {
            case IComparable i1:
                break;
            case string s: // error: subsumed by previous case
                break;
        }
    }
}";
            var compilation = CreateCompilation(source, options: TestOptions.DebugExe);
            Assert.True(compilation.GetDiagnostics().HasAnyErrors());
            compilation.VerifyDiagnostics(
                // (11,18): error CS8120: The switch case is unreachable. It has already been handled by a previous case or it is impossible to match.
                //             case string s: // error: subsumed by previous case
                Diagnostic(ErrorCode.ERR_SwitchCaseSubsumed, "string s").WithLocation(11, 18)
                );
        }

        [Fact]
        public void SimpleSubsumption04()
        {
            var source =
@"using System.Collections;
using System.Collections.Generic;
public class X
{
    public static void Main()
    {
        object o = null;
        switch (o)
        {
            case IEnumerable i:
                break;
            case IEnumerable<string> i: // error: subsumed by previous case
                break;
        }
    }
}";
            var compilation = CreateCompilationWithMscorlib40AndSystemCore(source, options: TestOptions.DebugExe);
            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 IEnumerable<string> i: // error: subsumed by previous case
                Diagnostic(ErrorCode.ERR_SwitchCaseSubsumed, "IEnumerable<string> i").WithLocation(12, 18)
                );
        }

        [Fact]
        public void SimpleSubsumption05()
        {
            var source =
@"using System.Collections.Generic;
public class X : List<string>
{
    public static void Main()
    {
        object o = null;
        switch (o)
        {
            case List<string> list:
                break;
            case X list: // error: subsumed by previous case
                break;
        }
    }
}";
            var compilation = CreateCompilationWithMscorlib40AndSystemCore(source, options: TestOptions.DebugExe);
            Assert.True(compilation.GetDiagnostics().HasAnyErrors());
            compilation.VerifyDiagnostics(
                // (11,18): error CS8120: The switch case is unreachable. It has already been handled by a previous case or it is impossible to match.
                //             case X list: // error: subsumed by previous case
                Diagnostic(ErrorCode.ERR_SwitchCaseSubsumed, "X list").WithLocation(11, 18)
                );
        }

        [Fact]
        public void JointSubsumption01()
        {
            var source =
@"public class X
{
    public static void Main()
    {
        bool b = true;
        switch (b)
        {
            case true:
            case false:
                break;
            case var x: // error: subsumed
                break; // unreachable?
        }
    }
}";
            var compilation = CreateCompilation(source, options: TestOptions.DebugExe);
            compilation.VerifyDiagnostics(
                // (11,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 x: // error: subsumed
                Diagnostic(ErrorCode.ERR_SwitchCaseSubsumed, "var x").WithLocation(11, 18)
                );
        }

        [Fact]
        public void JointSubsumption02()
        {
            var source =
@"public class X
{
    public static void Main()
    {
        bool? b = true;
        switch (b)
        {
            case bool b2:
            case null:
                break;
            case var x: // error: subsumed by previous cases
                break; // unreachable?
        }
    }
}";
            var compilation = CreateCompilation(source, options: TestOptions.DebugExe);
            compilation.VerifyDiagnostics(
                // (11,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 x: // error: subsumed by previous cases
                Diagnostic(ErrorCode.ERR_SwitchCaseSubsumed, "var x").WithLocation(11, 18)
                );
        }

        [Fact]
        public void JointSubsumption02b()
        {
            var source =
@"public class X
{
    public static void Main()
    {
        bool? b = true;
        switch (b)
        {
            case bool b2 when b==true:
            case null:
                break;
            case var x:
                break;
        }
    }
}";
            var compilation = CreateCompilation(source, options: TestOptions.DebugExe);
            compilation.VerifyDiagnostics(
                );
        }

        [Fact]
        public void TypeMismatch()
        {
            var source =
@"public class X
{
    public static void Main()
    {
        string s = null;
        switch (s)
        {
            case int i: // error: type mismatch.
                break;
        }
    }
}";
            var compilation = CreateCompilation(source, options: TestOptions.DebugExe);
            compilation.VerifyDiagnostics(
                // (8,18): error CS8121: An expression of type 'string' cannot be handled by a pattern of type 'int'.
                //             case int i: // error: type mismatch.
                Diagnostic(ErrorCode.ERR_PatternWrongType, "int").WithArguments("string", "int").WithLocation(8, 18)
                );
        }

        [Fact]
        public void JointNonSubsumption02()
        {
            var source =
@"public class X
{
    public static void Main()
    {
        M(true);
        M(false);
        M(null);
    }
    public static void M(bool? b)
    {
        switch (b)
        {
            case false:
            case null:
                break;
            case var x: // catches `true`
                System.Console.WriteLine(true.ToString());
                break;
        }
        switch (b)
        {
            case true:
            case null:
                break;
            case var x: // catches `false`
                System.Console.WriteLine(false.ToString());
                break;
        }
        switch (b)
        {
            case true:
            case false:
                break;
            case var x: // catches `null`
                System.Console.WriteLine(""null"");
                break;
        }
    }
}";
            var compilation = CreateCompilation(source, options: TestOptions.DebugExe);
            compilation.VerifyDiagnostics();
            var expectedOutput =
@"True
False
null";
            var comp = CompileAndVerify(compilation, expectedOutput: expectedOutput);
        }

        [Fact, WorkItem(10601, "https://github.com/dotnet/roslyn/issues/10601")]
        public void NullMismatch01()
        {
            var source =
@"public class X
{
    public static void Main()
    {
        bool b = true;
        switch (b)
        {
            case true when true:
                break;
            case null: // error: impossible given the type
                break;
        }
    }
}";
            var compilation = CreateCompilation(source, options: TestOptions.DebugExe);
            compilation.VerifyDiagnostics(
                // (10,18): error CS0037: Cannot convert null to 'bool' because it is a non-nullable value type
                //             case null: // error: impossible given the type
                Diagnostic(ErrorCode.ERR_ValueCantBeNull, "null").WithArguments("bool").WithLocation(10, 18)
                );
        }

        [Fact, WorkItem(10632, "https://github.com/dotnet/roslyn/issues/10632")]
        public void TypeMismatch01()
        {
            var source =
@"public class X
{
    public static void Main()
    {
        bool b = true;
        switch (b)
        {
            case true when true:
                break;
            case 3: // error: impossible given the type
                break;
        }
    }
}";
            var compilation = CreateCompilation(source, options: TestOptions.DebugExe);
            compilation.VerifyDiagnostics(
                // (10,18): error CS0029: Cannot implicitly convert type 'int' to 'bool'
                //             case 3: // error: impossible given the type
                Diagnostic(ErrorCode.ERR_NoImplicitConv, "3").WithArguments("int", "bool").WithLocation(10, 18)
                );
        }

        [Fact, WorkItem(10601, "https://github.com/dotnet/roslyn/issues/10601")]
        public void ValueMismatch01()
        {
            var source =
@"public class X
{
    public static void Main()
    {
        byte b = 1;
        switch (b)
        {
            case 1 when true:
                break;
            case 1000: // error: impossible given the type
                break;
        }
    }
}";
            var compilation = CreateCompilation(source, options: TestOptions.DebugExe);
            compilation.VerifyDiagnostics(
                // (10,18): error CS0031: Constant value '1000' cannot be converted to a 'byte'
                //             case 1000: // error: impossible given the type
                Diagnostic(ErrorCode.ERR_ConstOutOfRange, "1000").WithArguments("1000", "byte").WithLocation(10, 18)
                );
        }

        [Fact]
        public void Subsumption01()
        {
            var source =
@"public class X
{
    public static void Main(string[] args)
    {
        switch (args.Length)
        {
            case int i:
                break;
            case 11: // error: subsumed
                break;
        }
    }
}";
            var compilation = CreateCompilation(source, options: TestOptions.DebugExe);
            compilation.VerifyDiagnostics(
                // (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 11: // error: subsumed
                Diagnostic(ErrorCode.ERR_SwitchCaseSubsumed, "11").WithLocation(9, 18)
                );
        }

        [Fact]
        public void Subsumption02()
        {
            var source =
@"public class X
{
    public static void Main(string[] args)
    {
        switch (args.Length == 1)
        {
            case true:
            case false:
                break;
            case bool b: // error: subsumed
                break;
            default: //ok
                break; // unreachable because a single case handles all input
        }
    }
}";
            var compilation = CreateCompilation(source, options: TestOptions.DebugExe);
            compilation.VerifyDiagnostics(
                // (10,18): error CS8120: The switch case is unreachable. It has already been handled by a previous case or it is impossible to match.
                //             case bool b: // error: subsumed
                Diagnostic(ErrorCode.ERR_SwitchCaseSubsumed, "bool b").WithLocation(10, 18),
                // (13,17): warning CS0162: Unreachable code detected
                //                 break; // unreachable because a single case handles all input
                Diagnostic(ErrorCode.WRN_UnreachableCode, "break").WithLocation(13, 17)
                );
        }

        [Fact]
        public void Subsumption03()
        {
            var source =
@"public class X
{
    public static void Main(string[] args)
    {
        switch (1)
        {
            case 2 when true:
                break; // unreachable
        }
    }
}";
            var compilation = CreateCompilation(source, options: TestOptions.DebugExe);
            compilation.VerifyDiagnostics(
                // (8,17): warning CS0162: Unreachable code detected
                //                 break; // unreachable
                Diagnostic(ErrorCode.WRN_UnreachableCode, "break").WithLocation(8, 17)
                );
        }

        [Fact]
        public void Subsumption04()
        {
            var source =
@"public class X
{
    public static void Main(string[] args)
    {
        switch ((object)null)
        {
            case object o:
                break; // unreachable
        }
    }
}";
            var compilation = CreateCompilation(source, options: TestOptions.DebugExe);
            compilation.VerifyDiagnostics(
                // (8,17): warning CS0162: Unreachable code detected
                //                 break; // unreachable
                Diagnostic(ErrorCode.WRN_UnreachableCode, "break").WithLocation(8, 17)
                );
        }

        [Fact]
        public void Subsumption04b()
        {
            var source =
@"public class X
{
    public static void Main(string[] args)
    {
        switch ((string)null)
        {
            case object o:
                break; // unreachable
        }
    }
}";
            var compilation = CreateCompilation(source, options: TestOptions.DebugExe);
            compilation.VerifyDiagnostics(
                // (8,17): warning CS0162: Unreachable code detected
                //                 break; // unreachable
                Diagnostic(ErrorCode.WRN_UnreachableCode, "break").WithLocation(8, 17)
                );
        }

        [Fact]
        public void Subsumption05()
        {
            var source =
@"public class X
{
    public static void Main(string[] args)
    {
        switch (""silly"")
        {
            case null when true:
                break; // unreachable
        }
    }
}";
            var compilation = CreateCompilation(source, options: TestOptions.DebugExe);
            compilation.VerifyDiagnostics(
                // (8,17): warning CS0162: Unreachable code detected
                //                 break; // unreachable
                Diagnostic(ErrorCode.WRN_UnreachableCode, "break").WithLocation(8, 17)
                );
        }

        [Fact]
        public void Subsumption06()
        {
            var source =
@"public class X
{
    public static void Main(string[] args)
    {
        switch (new object())
        {
            case null when true:
                break;
        }
    }
}";
            var compilation = CreateCompilation(source, options: TestOptions.DebugExe);
            compilation.VerifyDiagnostics(
                );
        }

        [Fact]
        public void Subsumption07()
        {
            var source =
@"public class X
{
    public static void Main(string[] args)
    {
        switch ((bool?)null)
        {
            case null when true:
                break;
        }
    }
}";
            var compilation = CreateCompilation(source, options: TestOptions.DebugExe);
            compilation.VerifyDiagnostics(
                );
        }

        [Fact]
        public void Subsumption08()
        {
            var source =
@"public class X
{
    public static void Main(string[] args)
    {
        switch (""goo"")
        {
            case null when true:
                break; // unreachable
            case null: // subsumed
                break;
        }
    }
}";
            var compilation = CreateCompilation(source, options: TestOptions.DebugExe);
            compilation.VerifyDiagnostics(
                // (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 null: // subsumed
                Diagnostic(ErrorCode.ERR_SwitchCaseSubsumed, "null").WithLocation(9, 18),
                // (8,17): warning CS0162: Unreachable code detected
                //                 break; // unreachable
                Diagnostic(ErrorCode.WRN_UnreachableCode, "break").WithLocation(8, 17)
                );
        }

        [Fact]
        [WorkItem(51192, "https://github.com/dotnet/roslyn/issues/51192")]
        public void Subsumption09()
        {
            var source =
@"using System;
public class X
{
    public static void Main()
    {
        object o = null;
        switch (o)
        {
            case I1 and Base:
                break;
            case Derived s: // 1
                break;
        }

        switch (o)
        {
            case Base and I1:
                break;
            case Derived s: // 2
                break;
        }

        switch (o)
        {
            case Base and not null:
                break;
            case Derived s: // 3
                break;
        }

        switch (o) {
            case ValueType and int and 1:
                break;
            case int and 1: // 4
                break;
        }

        switch (o) {
            case int and 1:
                break;
            case ValueType and int and 1: // 5
                break;
        }

        switch (o)
        {
            case I2 and Base:
                break;
            case Derived s: // 6
                break;
        }

        switch (o)
        {
            case I2 and Base { F1: 1 }:
                break;
            case Derived { F2: 1 }:
                break;
            case Derived { P1: 1 }:
                break;
            case Derived { F1: 1 } s: // 7
                break;
        }

        switch (o)
        {
            case I2 and Base { P1: 1 }:
                break;
            case Derived { F1: 1 }:
                break;
            case Derived { P2: 1 }:
                break;
            case Derived { P1: 1 } s: // 8
                break;
        }

        switch (o)
        {
            case I2 and Base(1, _):
                break;
            case Derived(2, _):
                break;
            case Derived(1, _, _):
                break;
            case Derived(1, _) s: // 9
                break;
        }

        switch (o)
        {
            case I2 and Base { F3: (1, _) }:
                break;
            case Derived { F3: (_, 1) }:
                break;
            case Derived { F3: (1, _) } s: // 10
                break;
        }

        switch (o)
        {
            case I2 and Base:
                break;
            case Base and I2: // 11
                break;
        }

        switch (o)
        {
            case Base and I2:
                break;
            case I2 and Base: // 12
                break;
        }
    }
}

interface I1 {}
interface I2 {}

class Base : I1
{
    public int F1 = 0;
    public int F2 = 0;
    public object F3 = null;
    public int P1 {get; set;}
    public int P2 {get; set;}
    public void Deconstruct(out int x, out int y) => throw null;
    public void Deconstruct(out int x, out int y, out int z) => throw null;
}

class Derived : Base, I2
{
}
";
            var compilation = CreateCompilation(new[] { source, _iTupleSource }, options: TestOptions.DebugExe);
            compilation.VerifyDiagnostics(
                // (11,18): error CS8120: The switch case is unreachable. It has already been handled by a previous case or it is impossible to match.
                //             case Derived s: // 1
                Diagnostic(ErrorCode.ERR_SwitchCaseSubsumed, "Derived s").WithLocation(11, 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 Derived s: // 2
                Diagnostic(ErrorCode.ERR_SwitchCaseSubsumed, "Derived s").WithLocation(19, 18),
                // (27,18): error CS8120: The switch case is unreachable. It has already been handled by a previous case or it is impossible to match.
                //             case Derived s: // 3
                Diagnostic(ErrorCode.ERR_SwitchCaseSubsumed, "Derived s").WithLocation(27, 18),
                // (34,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 and 1: // 4
                Diagnostic(ErrorCode.ERR_SwitchCaseSubsumed, "int and 1").WithLocation(34, 18),
                // (41,18): error CS8120: The switch case is unreachable. It has already been handled by a previous case or it is impossible to match.
                //             case ValueType and int and 1: // 5
                Diagnostic(ErrorCode.ERR_SwitchCaseSubsumed, "ValueType and int and 1").WithLocation(41, 18),
                // (49,18): error CS8120: The switch case is unreachable. It has already been handled by a previous case or it is impossible to match.
                //             case Derived s: // 6
                Diagnostic(ErrorCode.ERR_SwitchCaseSubsumed, "Derived s").WithLocation(49, 18),
                // (61,18): error CS8120: The switch case is unreachable. It has already been handled by a previous case or it is impossible to match.
                //             case Derived { F1: 1 } s: // 7
                Diagnostic(ErrorCode.ERR_SwitchCaseSubsumed, "Derived { F1: 1 } s").WithLocation(61, 18),
                // (73,18): error CS8120: The switch case is unreachable. It has already been handled by a previous case or it is impossible to match.
                //             case Derived { P1: 1 } s: // 8
                Diagnostic(ErrorCode.ERR_SwitchCaseSubsumed, "Derived { P1: 1 } s").WithLocation(73, 18),
                // (85,18): error CS8120: The switch case is unreachable. It has already been handled by a previous case or it is impossible to match.
                //             case Derived(1, _) s: // 9
                Diagnostic(ErrorCode.ERR_SwitchCaseSubsumed, "Derived(1, _) s").WithLocation(85, 18),
                // (95,18): error CS8120: The switch case is unreachable. It has already been handled by a previous case or it is impossible to match.
                //             case Derived { F3: (1, _) } s: // 10
                Diagnostic(ErrorCode.ERR_SwitchCaseSubsumed, "Derived { F3: (1, _) } s").WithLocation(95, 18),
                // (103,18): error CS8120: The switch case is unreachable. It has already been handled by a previous case or it is impossible to match.
                //             case Base and I2: // 11
                Diagnostic(ErrorCode.ERR_SwitchCaseSubsumed, "Base and I2").WithLocation(103, 18),
                // (111,18): error CS8120: The switch case is unreachable. It has already been handled by a previous case or it is impossible to match.
                //             case I2 and Base: // 12
                Diagnostic(ErrorCode.ERR_SwitchCaseSubsumed, "I2 and Base").WithLocation(111, 18)
                );
        }

        [Fact]
        [WorkItem(51192, "https://github.com/dotnet/roslyn/issues/51192")]
        public void Subsumption10()
        {
            var source =
@"
using System;
public class C {
    public void M1(object o) {
        switch (o) {
            case IConvertible and IComparable:
                break;
            case int:
                break;
        }
    }
}
";
            var compilation = CreateCompilation(source, options: TestOptions.DebugDll);
            compilation.VerifyDiagnostics(
                // (8,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:
                Diagnostic(ErrorCode.ERR_SwitchCaseSubsumed, "int").WithLocation(8, 18)
                );
        }

        [Fact]
        [WorkItem(51192, "https://github.com/dotnet/roslyn/issues/51192")]
        public void Subsumption11()
        {
            var source =
@"using System;
public class X
{
    public static void Main()
    {
        object o = null;
        switch (o)
        {
            case IComparable and object:
                break;
            case string s: // error: subsumed by previous case
                break;
        }
    }
}";
            var compilation = CreateCompilation(source, options: TestOptions.DebugExe);
            compilation.VerifyDiagnostics(
                // (11,18): error CS8120: The switch case is unreachable. It has already been handled by a previous case or it is impossible to match.
                //             case string s: // error: subsumed by previous case
                Diagnostic(ErrorCode.ERR_SwitchCaseSubsumed, "string s").WithLocation(11, 18)
                );
        }

        [Fact]
        public void EqualConstant03()
        {
            var source =
@"public class X
{
    public static void Main()
    {
        bool _false = false;
        switch (1)
        {
            case 1 when _false:
                break;
            case var i:
                break; // reachable because previous case does not handle all inputs
        }
    }
}";
            var compilation = CreateCompilation(source, options: TestOptions.DebugExe);
            compilation.VerifyDiagnostics(
                );
        }

        [Fact]
        public void CascadedUnreachableDiagnostic()
        {
            var source =
@"public class X
{
    public static void Main()
    {
        bool b = false;
        switch (b)
        {
            case true:
            case false:
                break;
            case ""goo"": // wrong type
                break;
        }
    }
}";
            CreateCompilation(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular6).VerifyDiagnostics(
                // (10,18): error CS0029: Cannot implicitly convert type 'string' to 'bool'
                //             case "goo": // wrong type
                Diagnostic(ErrorCode.ERR_NoImplicitConv, @"""goo""").WithArguments("string", "bool").WithLocation(11, 18)
                );
            CreateCompilation(source, options: TestOptions.DebugExe).VerifyDiagnostics(
                // (10,18): error CS0029: Cannot implicitly convert type 'string' to 'bool'
                //             case "goo": // wrong type
                Diagnostic(ErrorCode.ERR_NoImplicitConv, @"""goo""").WithArguments("string", "bool").WithLocation(11, 18)
                );
        }

        [Fact]
        public void EnumConversions01()
        {
            var source =
@"enum Color { Red=0, Blue=1, Green=2, Mauve=3 }

class Program
{
    public static void Main()
    {
        Color color = Color.Red;
        switch (color)
        {
            case Color.Blue:
                goto case 1; // warning CS0469: The 'goto case' value is not implicitly convertible to type 'Color'
            case 0:
                break;
            case 2:          // error CS0266: Cannot implicitly convert type 'int' to 'Color'. An explicit conversion exists (are you missing a cast?)
                goto case 3; // warning CS0469: The 'goto case' value is not implicitly convertible to type 'Color'
                             // error CS0159: No such label 'case 3:' within the scope of the goto statement
                break;       // (optional) warning CS0162: Unreachable code detected
            case Color x when false:
                {}
        }
    }
}";
            CreateCompilation(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular6).VerifyDiagnostics(
                // (11,17): warning CS0469: The 'goto case' value is not implicitly convertible to type 'Color'
                //                 goto case 1; // warning CS0469: The 'goto case' value is not implicitly convertible to type 'Color'
                Diagnostic(ErrorCode.WRN_GotoCaseShouldConvert, "goto case 1;").WithArguments("Color").WithLocation(11, 17),
                // (14,18): error CS0266: Cannot implicitly convert type 'int' to 'Color'. An explicit conversion exists (are you missing a cast?)
                //             case 2:          // error CS0266: Cannot implicitly convert type 'int' to 'Color'. An explicit conversion exists (are you missing a cast?)
                Diagnostic(ErrorCode.ERR_NoImplicitConvCast, "2").WithArguments("int", "Color").WithLocation(14, 18),
                // (15,17): warning CS0469: The 'goto case' value is not implicitly convertible to type 'Color'
                //                 goto case 3; // warning CS0469: The 'goto case' value is not implicitly convertible to type 'Color'
                Diagnostic(ErrorCode.WRN_GotoCaseShouldConvert, "goto case 3;").WithArguments("Color").WithLocation(15, 17),
                // (15,17): error CS0159: No such label 'case 3:' within the scope of the goto statement
                //                 goto case 3; // warning CS0469: The 'goto case' value is not implicitly convertible to type 'Color'
                Diagnostic(ErrorCode.ERR_LabelNotFound, "goto case 3;").WithArguments("case 3:").WithLocation(15, 17),
                // (18,13): error CS8059: Feature 'pattern matching' is not available in C# 6. Please use language version 7.0 or greater.
                //             case Color x when false:
                Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion6, "case").WithArguments("pattern matching", "7.0").WithLocation(18, 13));
            var compilation = CreateCompilation(source, options: TestOptions.DebugExe);
            compilation.VerifyDiagnostics(
                // (11,17): warning CS0469: The 'goto case' value is not implicitly convertible to type 'Color'
                //                 goto case 1; // warning CS0469: The 'goto case' value is not implicitly convertible to type 'Color'
                Diagnostic(ErrorCode.WRN_GotoCaseShouldConvert, "goto case 1;").WithArguments("Color").WithLocation(11, 17),
                // (14,18): error CS0266: Cannot implicitly convert type 'int' to 'Color'. An explicit conversion exists (are you missing a cast?)
                //             case 2:          // error CS0266: Cannot implicitly convert type 'int' to 'Color'. An explicit conversion exists (are you missing a cast?)
                Diagnostic(ErrorCode.ERR_NoImplicitConvCast, "2").WithArguments("int", "Color").WithLocation(14, 18),
                // (15,17): warning CS0469: The 'goto case' value is not implicitly convertible to type 'Color'
                //                 goto case 3; // warning CS0469: The 'goto case' value is not implicitly convertible to type 'Color'
                Diagnostic(ErrorCode.WRN_GotoCaseShouldConvert, "goto case 3;").WithArguments("Color").WithLocation(15, 17),
                // (15,17): error CS0159: No such label 'case 3:' within the scope of the goto statement
                //                 goto case 3; // warning CS0469: The 'goto case' value is not implicitly convertible to type 'Color'
                Diagnostic(ErrorCode.ERR_LabelNotFound, "goto case 3;").WithArguments("case 3:").WithLocation(15, 17)
                );
        }

        [Fact]
        public void EnumConversions02()
        {
            var source =
@"using System;

enum Color { Red=0, Blue=1, Green=2, Mauve=3 }

class Program
{
    public static void Main()
    {
        Color color = Color.Green;
        switch (color)
        {
            case Color.Red:
                goto default;
            case Color.Blue:
                goto case 0;
            case Color.Green:
                goto case 1;
            case Color.Mauve when true:
                break;
            default:
                Console.WriteLine(""done"");
                break;
        }
    }
}";
            var compilation = CreateCompilation(source, options: TestOptions.DebugExe);
            compilation.VerifyDiagnostics(
                // (17,17): warning CS0469: The 'goto case' value is not implicitly convertible to type 'Color'
                //                 goto case 1;
                Diagnostic(ErrorCode.WRN_GotoCaseShouldConvert, "goto case 1;").WithArguments("Color").WithLocation(17, 17)
                );
            var expectedOutput = @"done";
            var comp = CompileAndVerify(compilation, expectedOutput: expectedOutput);
        }

        [Fact]
        public void WhenClause01()
        {
            // This test exercises a tricky aspect of lowering: the variables of a switch section
            // (such as i and j below) need to be in scope, from the point of view of the IL, both
            // in the when clause and in the body of the switch block. But those two bodies of
            // code are separate from each other: the when clause is part of the decision tree,
            // while the switch blocks are emitted after the entire decision tree has been emitted.
            // To get the scoping right (from the point-of-view of emit and the debugger), the compiler
            // organizes the code so that the when clauses and the section bodies are co-located
            // within the block that defines the variables of the switch section. We branch to a
            // label within the when clause, where the pattern variables are assigned followed by
            // evaluating the when condition. If it fails we branch back into the decision tree. If
            // it succeeds we branch to the user-written body of the switch block.
            var source =
@"using System;

class Program
{
    public static void Main()
    {
        M(1);
        M(""sasquatch"");
    }
    public static void M(object o)
    {
        switch (o)
        {
            case int i when i is int j:
                Console.WriteLine(j);
                break;
            case string s when s is string t:
                Console.WriteLine(t);
                break;
        }
    }
}";
            var compilation = CreateCompilation(source, options: TestOptions.DebugExe);
            compilation.VerifyDiagnostics();
            var expectedOutput =
@"1
sasquatch";
            var comp = CompileAndVerify(compilation, expectedOutput: expectedOutput);
        }

        [Fact]
        public void WhenClause02()
        {
            var source =
@"using System;

class Program
{
    public static void Main()
    {
        M(0.0);
        M(-0.0);
        M(2.1);
        M(1.0);
        M(double.NaN);
        M(-double.NaN);
        M(0.0f);
        M(-0.0f);
        M(2.1f);
        M(1.0f);
        M(float.NaN);
        M(-float.NaN);
        M(0.0m);
        M(0m);
        M(2.1m);
        M(1.0m);
        M(null);
    }
    public static void M(object o)
    {
        switch (o)
        {
            case 0.0f:
                Console.WriteLine(""0.0f !"");
                break;
            case 0.0d:
                Console.WriteLine(""0.0d !"");
                break;
            case 0.0m:
                Console.WriteLine(""0.0m !"");
                break;
            case 1.0f:
                Console.WriteLine(""1.0f !"");
                break;
            case 1.0d:
                Console.WriteLine(""1.0d !"");
                break;
            case 1.0m:
                Console.WriteLine(""1.0m !"");
                break;
            case 2.0f:
                Console.WriteLine(""2.0f !"");
                break;
            case 2.0d:
                Console.WriteLine(""2.0d !"");
                break;
            case 2.0m:
                Console.WriteLine(""2.0m !"");
                break;
            case float.NaN:
                Console.WriteLine(""float.NaN !"");
                break;
            case double.NaN:
                Console.WriteLine(""double.NaN !"");
                break;
            case float f when f is float g:
                Console.WriteLine(""float "" + g);
                break;
            case double d when d is double e:
                Console.WriteLine(""double "" + e);
                break;
            case decimal d when d is decimal e:
                Console.WriteLine(""decimal "" + e);
                break;
            case null:
                Console.WriteLine(""null"");
                break;
            case object k:
                Console.WriteLine(k.GetType() + "" + "" + k);
                break;
        }
    }
}";
            var compilation = CreateCompilation(source, options: TestOptions.DebugExe);
            compilation.VerifyDiagnostics();
            var expectedOutput =
$@"0.0d !
0.0d !
double {2.1}
1.0d !
double.NaN !
double.NaN !
0.0f !
0.0f !
float {2.1f}
1.0f !
float.NaN !
float.NaN !
0.0m !
0.0m !
decimal {2.1m}
1.0m !
null";
            var comp = CompileAndVerify(compilation, expectedOutput: expectedOutput);
        }

        [ConditionalFact(typeof(IsEnglishLocal))]
        [WorkItem(25846, "https://github.com/dotnet/roslyn/issues/25846")]
        public void DuplicateDouble()
        {
            var source =
@"class Program
{
    public static void Main()
    {
    }
    public static void M(double d)
    {
        switch (d)
        {
            case 0.0:
            case double.NaN:
            case 1.01:
            case 1.01: // duplicate
            case 2.0:
            case 3.0:
            case 1.1:
            case 1.2:
            case 2.1:
            case 3.1:
            case 11.01:
            case 12.0:
            case 13.0:
            case 11.1:
            case 11.2:
            case 12.1:
            case 13.1:
            case 21.01:
            case 22.0:
            case 23.0:
            case 21.1:
            case 21.2:
            case 22.1:
            case 23.1:
            case -0.0: // duplicate
            case -double.NaN: // duplicate
                break;
        }
    }
    public static void M(float d)
    {
        switch (d)
        {
            case 0.0f:
            case float.NaN:
            case 1.01f:
            case 1.01f: // duplicate
            case 2.0f:
            case 3.0f:
            case 1.1f:
            case 1.2f:
            case 2.1f:
            case 3.1f:
            case 11.01f:
            case 12.0f:
            case 13.0f:
            case 11.1f:
            case 11.2f:
            case 12.1f:
            case 13.1f:
            case 21.01f:
            case 22.0f:
            case 23.0f:
            case 21.1f:
            case 21.2f:
            case 22.1f:
            case 23.1f:
            case -0.0f: // duplicate
            case -float.NaN: // duplicate
                break;
        }
    }
    public static void M(decimal d)
    {
        switch (d)
        {
            case 0.0m:
            case 1.01m:
            case 1.01m: // duplicate
            case 2.0m:
            case 3.0m:
            case 1.1m:
            case 1.2m:
            case 2.1m:
            case 3.1m:
            case 11.01m:
            case 12.0m:
            case 13.0m:
            case 11.1m:
            case 11.2m:
            case 12.1m:
            case 13.1m:
            case 21.01m:
            case 22.0m:
            case 23.0m:
            case 21.1m:
            case 21.2m:
            case 22.1m:
            case 23.1m:
            case -0.0m: // duplicate
                break;
        }
    }
}";
            var compilation = CreateCompilation(source, options: TestOptions.DebugExe);
            compilation.VerifyDiagnostics(
                // (13,13): error CS0152: The switch statement contains multiple cases with the label value '1.01'
                //             case 1.01: // duplicate
                Diagnostic(ErrorCode.ERR_DuplicateCaseLabel, "case 1.01:").WithArguments(1.01.ToString()).WithLocation(13, 13),
                // (34,13): error CS0152: The switch statement contains multiple cases with the label value '0'
                //             case -0.0: // duplicate
                Diagnostic(ErrorCode.ERR_DuplicateCaseLabel, "case -0.0:").WithArguments((-0.0).ToString()).WithLocation(34, 13),
                // (35,13): error CS0152: The switch statement contains multiple cases with the label value 'NaN'
                //             case -double.NaN: // duplicate
                Diagnostic(ErrorCode.ERR_DuplicateCaseLabel, "case -double.NaN:").WithArguments((-double.NaN).ToString()).WithLocation(35, 13),
                // (46,13): error CS0152: The switch statement contains multiple cases with the label value '1.01'
                //             case 1.01f: // duplicate
                Diagnostic(ErrorCode.ERR_DuplicateCaseLabel, "case 1.01f:").WithArguments(1.01f.ToString()).WithLocation(46, 13),
                // (67,13): error CS0152: The switch statement contains multiple cases with the label value '0'
                //             case -0.0f: // duplicate
                Diagnostic(ErrorCode.ERR_DuplicateCaseLabel, "case -0.0f:").WithArguments((-0.0f).ToString()).WithLocation(67, 13),
                // (68,13): error CS0152: The switch statement contains multiple cases with the label value 'NaN'
                //             case -float.NaN: // duplicate
                Diagnostic(ErrorCode.ERR_DuplicateCaseLabel, "case -float.NaN:").WithArguments((-float.NaN).ToString()).WithLocation(68, 13),
                // (78,13): error CS0152: The switch statement contains multiple cases with the label value '1.01'
                //             case 1.01m: // duplicate
                Diagnostic(ErrorCode.ERR_DuplicateCaseLabel, "case 1.01m:").WithArguments(1.01m.ToString()).WithLocation(78, 13),
                // (99,13): error CS0152: The switch statement contains multiple cases with the label value '0.0'
                //             case -0.0m: // duplicate
                Diagnostic(ErrorCode.ERR_DuplicateCaseLabel, "case -0.0m:").WithArguments((-0.0m).ToString()).WithLocation(99, 13)
                );
        }

        [Fact]
        public void NanValuesAreEqual()
        {
            var source =
@"using System;

class Program
{
    public static void Main()
    {
        M(0.0);
        M(-0.0);
        M(MakeNaN(0));
        M(MakeNaN(1));
        M(float.NaN);
    }
    public static void M(object d)
    {
        switch (d)
        {
            case 0.0:
                Console.WriteLine(""zero"");
                break;
            case double.NaN:
                Console.WriteLine(""double.NaN"");
                break;
            case float.NaN:
                Console.WriteLine(""float.NaN"");
                break;
            case 1.0: case 2.0: case 3.0: case 4.0: case 5.0:
            case 6.0: case 7.0: case 8.0: case 9.0: case 10.0:
                Console.WriteLine(""unexpected"");
                break;
            default:
                Console.WriteLine(""other"");
                break;
        }
    }
    public static double MakeNaN(int x)
    {
        return BitConverter.Int64BitsToDouble(BitConverter.DoubleToInt64Bits(double.NaN) ^ x);
    }
}";
            var compilation = CreateCompilation(source, options: TestOptions.DebugExe);
            compilation.VerifyDiagnostics();
            var expectedOutput =
@"zero
zero
double.NaN
double.NaN
float.NaN";
            var comp = CompileAndVerify(compilation, expectedOutput: expectedOutput);
        }

        [Fact, WorkItem(12573, "https://github.com/dotnet/roslyn/issues/12573")]
        public void EnumAndUnderlyingType()
        {
            var source =
@"using System;

class Program
{
    public static void Main(string[] args)
    {
        M(0);
        M(0L);
        M((byte)0);
        M(EnumA.ValueA);
        M(2);
    }

    public static void M(object value)
    {
        switch (value)
        {
            case 0:
                Console.WriteLine(""0"");
                break;
            case 0L:
                Console.WriteLine(""0L"");
                break;
            case (byte)0:
                Console.WriteLine(""(byte)0"");
                break;
            case EnumA.ValueA:
                Console.WriteLine(""EnumA.ValueA"");
                break;
            default:
                Console.WriteLine(""Default"");
                break;
        }
    }
}

public enum EnumA
{
    ValueA,
    ValueB,
    ValueC
}
";
            var compilation = CreateCompilation(source, options: TestOptions.DebugExe);
            compilation.VerifyDiagnostics();
            var expectedOutput =
@"0
0L
(byte)0
EnumA.ValueA
Default";
            var comp = CompileAndVerify(compilation, expectedOutput: expectedOutput);
        }

        [Fact, WorkItem(10446, "https://github.com/dotnet/roslyn/issues/10446")]
        public void InferenceInSwitch()
        {
            var source =
@"
public class X
{
    public static void Main()
    {
        object o = 1;
        switch (o)
        {
            case var i when i.ToString() is var s:
                Console.WriteLine(s);
                break;
            case var i2:
                var s2 =  i2.ToString();
                Console.WriteLine(s2);
                break;
        }
    }
}
";
            var compilation = CreateCompilation(source);
            var tree = compilation.SyntaxTrees.Single();
            var model = compilation.GetSemanticModel(tree);
            var sRef = tree.GetCompilationUnitRoot().DescendantNodes().OfType<IdentifierNameSyntax>().Where(n => n.ToString() == "s").Single();
            Assert.Equal("System.String", model.GetTypeInfo(sRef).Type.ToTestDisplayString());
            var iRef = tree.GetCompilationUnitRoot().DescendantNodes().OfType<IdentifierNameSyntax>().Where(n => n.ToString() == "i").Single();
            Assert.Equal("System.Object", model.GetTypeInfo(iRef).Type.ToTestDisplayString());
            var s2Ref = tree.GetCompilationUnitRoot().DescendantNodes().OfType<IdentifierNameSyntax>().Where(n => n.ToString() == "s2").Single();
            Assert.Equal("System.String", model.GetTypeInfo(s2Ref).Type.ToTestDisplayString());
            var i2Ref = tree.GetCompilationUnitRoot().DescendantNodes().OfType<IdentifierNameSyntax>().Where(n => n.ToString() == "i2").Single();
            Assert.Equal("System.Object", model.GetTypeInfo(i2Ref).Type.ToTestDisplayString());
        }

        [Fact, WorkItem(13395, "https://github.com/dotnet/roslyn/issues/13395")]
        public void CodeGenSwitchInLoop()
        {
            var source =
@"using System;

class Program
{
    public static void Main(string[] args)
    {
        bool hasB = false;
        foreach (var c in ""ab"")
        {
           switch (c)
           {
              case char b when IsB(b):
                 hasB = true;
                 break;

              default:
                 hasB = false;
                 break;
           }
        }
        Console.WriteLine(hasB);
    }

    public static bool IsB(char value)
    {
        return value == 'b';
    }
}
";
            var compilation = CreateCompilation(source, options: TestOptions.DebugExe);
            compilation.VerifyDiagnostics();
            var expectedOutput =
@"True";
            var comp = CompileAndVerify(compilation, expectedOutput: expectedOutput);
        }

        [Fact, WorkItem(13520, "https://github.com/dotnet/roslyn/issues/13520")]
        public void ConditionalPatternsCannotSubsume()
        {
            var source =
@"class Program
{
    public static void Main(string[] args)
    {
        object value = false;
        switch (value)
        {
            case true: break;
            case object o when args.Length == -1: break;
            case false: break;
            case bool b: throw null; // error: bool already handled by previous cases.
        }
    }
    public static bool IsB(char value)
    {
        return value == 'b';
    }
}
";
            var compilation = CreateCompilation(source, options: TestOptions.DebugExe);
            compilation.VerifyDiagnostics(
                // (11,18): error CS8120: The switch case is unreachable. It has already been handled by a previous case or it is impossible to match.
                //             case bool b: throw null; // error: bool already handled by previous cases.
                Diagnostic(ErrorCode.ERR_SwitchCaseSubsumed, "bool b").WithLocation(11, 18)
                );
        }

        [Fact, WorkItem(273713, "https://devdiv.visualstudio.com/DevDiv/_workitems?id=273713")]
        public void ExplicitTupleConversion_Crash()
        {
            var source =
@"class Program
{
    public static void Main(string[] args)
    {
        object[] oa = new object[] {
            (1, 2),
            (3L, 4L)
        };
        foreach (var o in oa)
        {
            switch (o)
            {
                case System.ValueTuple<int, int> z1:
                    System.Console.Write(z1.Item1);
                    break;
                case System.ValueTuple<long, long> z3:
                    System.Console.Write(z3.Item1);
                    break;
            }
        }
    }
}
";
            var compilation = CreateCompilation(source, options: TestOptions.DebugExe);
            compilation.VerifyDiagnostics();
            CompileAndVerify(compilation, expectedOutput: "13");
        }

        [Fact, WorkItem(273713, "https://devdiv.visualstudio.com/DevDiv/_workitems?id=273713")]
        public void TupleInPattern()
        {
            var source =
@"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;
        }
    }
}
class Program
{
    static void M(object o)
    {
        switch (o)
        {
            case (int, int):
            case (int x, int y):
            case (int, int) z:
            case (int a, int b) c:
            case (long, long) d:
                break;
        }
        switch (o)
        {
            case (int, int) z:
                break;
            case (long, long) d:
                break;
        }
        switch (o)
        {
            case (System.Int32, System.Int32) z:
                break;
            case (System.Int64, System.Int64) d:
                break;
        }
        {
            if (o is (int, int)) {}
            if (o is (int x, int y)) {}
            if (o is (int, int) z) {}
            if (o is (int a, int b) c) {}
        }
        {
            if (o is (System.Int32, System.Int32)) {}
            if (o is (System.Int32 x, System.Int32 y)) {}
            if (o is (System.Int32, System.Int32) z) {}
            if (o is (System.Int32 a, System.Int32 b) c) {}
        }
    }
}
";
            var compilation = CreateCompilation(source, options: TestOptions.DebugDll, parseOptions: TestOptions.Regular8);
            compilation.VerifyDiagnostics(
                // (21,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 (int, int):
                Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "(int, int)").WithArguments("object", "Deconstruct").WithLocation(21, 18),
                // (21,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 (int, int):
                Diagnostic(ErrorCode.ERR_MissingDeconstruct, "(int, int)").WithArguments("object", "2").WithLocation(21, 18),
                // (21,19): error CS8400: Feature 'type pattern' is not available in C# 8.0. Please use language version 9.0 or greater.
                //             case (int, int):
                Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion8, "int").WithArguments("type pattern", "9.0").WithLocation(21, 19),
                // (21,24): error CS8400: Feature 'type pattern' is not available in C# 8.0. Please use language version 9.0 or greater.
                //             case (int, int):
                Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion8, "int").WithArguments("type pattern", "9.0").WithLocation(21, 24),
                // (22,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 (int x, int y):
                Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "(int x, int y)").WithArguments("object", "Deconstruct").WithLocation(22, 18),
                // (22,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 (int x, int y):
                Diagnostic(ErrorCode.ERR_MissingDeconstruct, "(int x, int y)").WithArguments("object", "2").WithLocation(22, 18),
                // (23,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 (int, int) z:
                Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "(int, int)").WithArguments("object", "Deconstruct").WithLocation(23, 18),
                // (23,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 (int, int) z:
                Diagnostic(ErrorCode.ERR_MissingDeconstruct, "(int, int)").WithArguments("object", "2").WithLocation(23, 18),
                // (23,19): error CS8400: Feature 'type pattern' is not available in C# 8.0. Please use language version 9.0 or greater.
                //             case (int, int) z:
                Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion8, "int").WithArguments("type pattern", "9.0").WithLocation(23, 19),
                // (23,24): error CS8400: Feature 'type pattern' is not available in C# 8.0. Please use language version 9.0 or greater.
                //             case (int, int) z:
                Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion8, "int").WithArguments("type pattern", "9.0").WithLocation(23, 24),
                // (24,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 (int a, int b) c:
                Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "(int a, int b)").WithArguments("object", "Deconstruct").WithLocation(24, 18),
                // (24,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 (int a, int b) c:
                Diagnostic(ErrorCode.ERR_MissingDeconstruct, "(int a, int b)").WithArguments("object", "2").WithLocation(24, 18),
                // (25,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 (long, long) d:
                Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "(long, long)").WithArguments("object", "Deconstruct").WithLocation(25, 18),
                // (25,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 (long, long) d:
                Diagnostic(ErrorCode.ERR_MissingDeconstruct, "(long, long)").WithArguments("object", "2").WithLocation(25, 18),
                // (25,19): error CS8400: Feature 'type pattern' is not available in C# 8.0. Please use language version 9.0 or greater.
                //             case (long, long) d:
                Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion8, "long").WithArguments("type pattern", "9.0").WithLocation(25, 19),
                // (25,25): error CS8400: Feature 'type pattern' is not available in C# 8.0. Please use language version 9.0 or greater.
                //             case (long, long) d:
                Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion8, "long").WithArguments("type pattern", "9.0").WithLocation(25, 25),
                // (30,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 (int, int) z:
                Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "(int, int)").WithArguments("object", "Deconstruct").WithLocation(30, 18),
                // (30,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 (int, int) z:
                Diagnostic(ErrorCode.ERR_MissingDeconstruct, "(int, int)").WithArguments("object", "2").WithLocation(30, 18),
                // (30,19): error CS8400: Feature 'type pattern' is not available in C# 8.0. Please use language version 9.0 or greater.
                //             case (int, int) z:
                Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion8, "int").WithArguments("type pattern", "9.0").WithLocation(30, 19),
                // (30,24): error CS8400: Feature 'type pattern' is not available in C# 8.0. Please use language version 9.0 or greater.
                //             case (int, int) z:
                Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion8, "int").WithArguments("type pattern", "9.0").WithLocation(30, 24),
                // (32,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 (long, long) d:
                Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "(long, long)").WithArguments("object", "Deconstruct").WithLocation(32, 18),
                // (32,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 (long, long) d:
                Diagnostic(ErrorCode.ERR_MissingDeconstruct, "(long, long)").WithArguments("object", "2").WithLocation(32, 18),
                // (32,19): error CS8400: Feature 'type pattern' is not available in C# 8.0. Please use language version 9.0 or greater.
                //             case (long, long) d:
                Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion8, "long").WithArguments("type pattern", "9.0").WithLocation(32, 19),
                // (32,25): error CS8400: Feature 'type pattern' is not available in C# 8.0. Please use language version 9.0 or greater.
                //             case (long, long) d:
                Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion8, "long").WithArguments("type pattern", "9.0").WithLocation(32, 25),
                // (37,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 (System.Int32, System.Int32) z:
                Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "(System.Int32, System.Int32)").WithArguments("object", "Deconstruct").WithLocation(37, 18),
                // (37,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 (System.Int32, System.Int32) z:
                Diagnostic(ErrorCode.ERR_MissingDeconstruct, "(System.Int32, System.Int32)").WithArguments("object", "2").WithLocation(37, 18),
                // (39,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 (System.Int64, System.Int64) d:
                Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "(System.Int64, System.Int64)").WithArguments("object", "Deconstruct").WithLocation(39, 18),
                // (39,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 (System.Int64, System.Int64) d:
                Diagnostic(ErrorCode.ERR_MissingDeconstruct, "(System.Int64, System.Int64)").WithArguments("object", "2").WithLocation(39, 18),
                // (43,22): 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?)
                //             if (o is (int, int)) {}
                Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "(int, int)").WithArguments("object", "Deconstruct").WithLocation(43, 22),
                // (43,22): error CS8129: No suitable 'Deconstruct' instance or extension method was found for type 'object', with 2 out parameters and a void return type.
                //             if (o is (int, int)) {}
                Diagnostic(ErrorCode.ERR_MissingDeconstruct, "(int, int)").WithArguments("object", "2").WithLocation(43, 22),
                // (43,23): error CS8400: Feature 'type pattern' is not available in C# 8.0. Please use language version 9.0 or greater.
                //             if (o is (int, int)) {}
                Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion8, "int").WithArguments("type pattern", "9.0").WithLocation(43, 23),
                // (43,28): error CS8400: Feature 'type pattern' is not available in C# 8.0. Please use language version 9.0 or greater.
                //             if (o is (int, int)) {}
                Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion8, "int").WithArguments("type pattern", "9.0").WithLocation(43, 28),
                // (44,22): 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?)
                //             if (o is (int x, int y)) {}
                Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "(int x, int y)").WithArguments("object", "Deconstruct").WithLocation(44, 22),
                // (44,22): error CS8129: No suitable 'Deconstruct' instance or extension method was found for type 'object', with 2 out parameters and a void return type.
                //             if (o is (int x, int y)) {}
                Diagnostic(ErrorCode.ERR_MissingDeconstruct, "(int x, int y)").WithArguments("object", "2").WithLocation(44, 22),
                // (45,22): 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?)
                //             if (o is (int, int) z) {}
                Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "(int, int)").WithArguments("object", "Deconstruct").WithLocation(45, 22),
                // (45,22): error CS8129: No suitable 'Deconstruct' instance or extension method was found for type 'object', with 2 out parameters and a void return type.
                //             if (o is (int, int) z) {}
                Diagnostic(ErrorCode.ERR_MissingDeconstruct, "(int, int)").WithArguments("object", "2").WithLocation(45, 22),
                // (45,23): error CS8400: Feature 'type pattern' is not available in C# 8.0. Please use language version 9.0 or greater.
                //             if (o is (int, int) z) {}
                Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion8, "int").WithArguments("type pattern", "9.0").WithLocation(45, 23),
                // (45,28): error CS8400: Feature 'type pattern' is not available in C# 8.0. Please use language version 9.0 or greater.
                //             if (o is (int, int) z) {}
                Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion8, "int").WithArguments("type pattern", "9.0").WithLocation(45, 28),
                // (46,22): 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?)
                //             if (o is (int a, int b) c) {}
                Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "(int a, int b)").WithArguments("object", "Deconstruct").WithLocation(46, 22),
                // (46,22): error CS8129: No suitable 'Deconstruct' instance or extension method was found for type 'object', with 2 out parameters and a void return type.
                //             if (o is (int a, int b) c) {}
                Diagnostic(ErrorCode.ERR_MissingDeconstruct, "(int a, int b)").WithArguments("object", "2").WithLocation(46, 22),
                // (49,22): 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?)
                //             if (o is (System.Int32, System.Int32)) {}
                Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "(System.Int32, System.Int32)").WithArguments("object", "Deconstruct").WithLocation(49, 22),
                // (49,22): error CS8129: No suitable 'Deconstruct' instance or extension method was found for type 'object', with 2 out parameters and a void return type.
                //             if (o is (System.Int32, System.Int32)) {}
                Diagnostic(ErrorCode.ERR_MissingDeconstruct, "(System.Int32, System.Int32)").WithArguments("object", "2").WithLocation(49, 22),
                // (50,22): 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?)
                //             if (o is (System.Int32 x, System.Int32 y)) {}
                Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "(System.Int32 x, System.Int32 y)").WithArguments("object", "Deconstruct").WithLocation(50, 22),
                // (50,22): error CS8129: No suitable 'Deconstruct' instance or extension method was found for type 'object', with 2 out parameters and a void return type.
                //             if (o is (System.Int32 x, System.Int32 y)) {}
                Diagnostic(ErrorCode.ERR_MissingDeconstruct, "(System.Int32 x, System.Int32 y)").WithArguments("object", "2").WithLocation(50, 22),
                // (51,22): 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?)
                //             if (o is (System.Int32, System.Int32) z) {}
                Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "(System.Int32, System.Int32)").WithArguments("object", "Deconstruct").WithLocation(51, 22),
                // (51,22): error CS8129: No suitable 'Deconstruct' instance or extension method was found for type 'object', with 2 out parameters and a void return type.
                //             if (o is (System.Int32, System.Int32) z) {}
                Diagnostic(ErrorCode.ERR_MissingDeconstruct, "(System.Int32, System.Int32)").WithArguments("object", "2").WithLocation(51, 22),
                // (52,22): 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?)
                //             if (o is (System.Int32 a, System.Int32 b) c) {}
                Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "(System.Int32 a, System.Int32 b)").WithArguments("object", "Deconstruct").WithLocation(52, 22),
                // (52,22): error CS8129: No suitable 'Deconstruct' instance or extension method was found for type 'object', with 2 out parameters and a void return type.
                //             if (o is (System.Int32 a, System.Int32 b) c) {}
                Diagnostic(ErrorCode.ERR_MissingDeconstruct, "(System.Int32 a, System.Int32 b)").WithArguments("object", "2").WithLocation(52, 22));
        }

        [Fact, WorkItem(273713, "https://devdiv.visualstudio.com/DevDiv/_workitems?id=273713")]
        public void PointerConversion_Crash()
        {
            var source =
@"class Program
{
    public static void Main(string[] args)
    {
        System.IntPtr ip = (System.IntPtr)1;
        int i = 2;
        object[] oa = new object[] { ip, i };
        foreach (object o in oa)
        {
            switch (o)
            {
                case System.IntPtr a:
                    System.Console.Write((int)a);
                    break;
                case int b:
                    System.Console.Write(b);
                    break;
            }
        }
    }
}
";
            var compilation = CreateCompilation(source, options: TestOptions.DebugExe);
            compilation.VerifyDiagnostics();
            CompileAndVerify(compilation, expectedOutput: "12");
        }

        [Fact, WorkItem(14717, "https://github.com/dotnet/roslyn/issues/14717")]
        public void ExpressionVariableInCase_1()
        {
            string source =
@"
class Program
{
    static void Main(string[] args)
    {
        switch (true)
        {
            case new object() is int x1:
                System.Console.WriteLine(x1);
                break;
        }
    }
}
";
            var compilation = CreateCompilation(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular);
            // The point of this test is that it should not crash.
            compilation.VerifyDiagnostics(
                // (8,18): error CS0150: A constant value is expected
                //             case new object() is int x1:
                Diagnostic(ErrorCode.ERR_ConstantExpected, "new object() is int x1").WithLocation(8, 18),
                // (9,42): error CS0165: Use of unassigned local variable 'x1'
                //                 System.Console.WriteLine(x1);
                Diagnostic(ErrorCode.ERR_UseDefViolation, "x1").WithArguments("x1").WithLocation(9, 42)
                );

            var tree = compilation.SyntaxTrees.Single();
            var model = compilation.GetSemanticModel(tree);
            var x1Decl = GetPatternDeclarations(tree, "x1").Single();
            var x1Ref = GetReferences(tree, "x1").Single();
            VerifyModelForDeclarationOrVarSimplePattern(model, x1Decl, x1Ref);
        }

        [Fact, WorkItem(14717, "https://github.com/dotnet/roslyn/issues/14717")]
        public void ExpressionVariableInCase_2()
        {
            string source =
@"class Program
{
    static void Main(string[] args)
    {
        switch (args)
        {
            case is EnvDTE.Project x1:
                System.Console.WriteLine(x1);
                break;
        }
    }
}
";
            var compilation = CreateCompilation(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular);
            // The point of this test is that it should not crash.
            compilation.VerifyDiagnostics(
                // (7,18): error CS1525: Invalid expression term 'is'
                //             case is EnvDTE.Project x1:
                Diagnostic(ErrorCode.ERR_InvalidExprTerm, "is").WithArguments("is").WithLocation(7, 18),
                // (7,21): error CS0246: The type or namespace name 'EnvDTE' could not be found (are you missing a using directive or an assembly reference?)
                //             case is EnvDTE.Project x1:
                Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "EnvDTE").WithArguments("EnvDTE").WithLocation(7, 21)
                );

            var tree = compilation.SyntaxTrees.Single();
            var model = compilation.GetSemanticModel(tree);
            var x1Decl = GetPatternDeclarations(tree, "x1").Single();
            var x1Ref = GetReferences(tree, "x1").Single();
            VerifyModelForDeclarationOrVarSimplePattern(model, x1Decl, x1Ref);
        }

        [Fact, WorkItem(14296, "https://github.com/dotnet/roslyn/issues/14296")]
        public void PatternSwitchInLocalFunctionInGenericMethod()
        {
            var source =
@"using System;
class Program
{
    public static void Main(string[] args)
    {
        Console.WriteLine(Is<string>(string.Empty));
        Console.WriteLine(Is<int>(string.Empty));
        Console.WriteLine(Is<int>(1));
        Console.WriteLine(Is<string>(1));
    }
    public static bool Is<T>(object o1)
    {
        bool Local(object o2)
        {
            switch (o2)
            {
                case T t: return true;
                default: return false;
            }
        };
        return Local(o1);
    }
}
";
            var compilation = CreateCompilation(source, options: TestOptions.DebugExe);
            compilation.VerifyDiagnostics();
            var expectedOutput =
@"True
False
True
False";
            var comp = CompileAndVerify(compilation, expectedOutput: expectedOutput);
        }

        [Fact]
        public void CopySwitchExpression()
        {
            // This test ensures that we switch on a *copy* of the switch expression,
            // so that it is not affected by subsequent assignment to a variable appearing
            // in the switch expression.
            var source =
@"using System;
class Program
{
    public static void Main(string[] args)
    {
        int i = 1;
        switch (i)
        {
            case 1 when BP(false, i = 2): break;
            case int j when BP(false, i = 3): break;
            case 1 when BP(true, i = 4):
                Console.WriteLine(""Correct"");
                Console.WriteLine(i);
                break;
        }
    }
    static bool BP(bool b, int print)
    {
        Console.WriteLine(print);
        return b;
    }
}
";
            var compilation = CreateCompilation(source, options: TestOptions.ReleaseExe);
            compilation.VerifyDiagnostics();
            var expectedOutput =
@"2
3
4
Correct
4";
            var comp = CompileAndVerify(compilation, expectedOutput: expectedOutput);
        }

        [Fact, WorkItem(14707, "https://github.com/dotnet/roslyn/issues/14707")]
        public void ParenthesizedGuardClause()
        {
            var source =
@"class Program
{
    public static void Main(string[] args)
    {
        object[] oa = { null, new Rectangle(1, 1), new Rectangle(1, 2) };
        foreach (object o in oa)
        {
            switch (o)
            {
                case Rectangle s when (s.Length == s.Height):
                    System.Console.WriteLine($""S {s.Length}"");
                    break;
                case Rectangle r when ((true && (r.Length != r.Height))):
                    System.Console.WriteLine($""R {r.Height} {r.Length}"");
                    break;
                default:
                    System.Console.WriteLine($""other"");
                    break;
            }
        }
    }
}
class Rectangle
{
    public int Height, Length;
    public Rectangle(int x, int y) { Height = x; Length = y; }
}
";
            var compilation = CreateCompilation(source, options: TestOptions.DebugExe);
            compilation.VerifyDiagnostics();
            CompileAndVerify(compilation, expectedOutput: @"other
S 1
R 1 2");
        }

        [Fact, WorkItem(14721, "https://github.com/dotnet/roslyn/issues/14721")]
        public void NullTest_Crash()
        {
            var source =
@"using System;

static class Program {
    static void Test(object o) {
        switch (o) {
            case var value when value != null:
                Console.WriteLine(""not null"");
                break;
            case null:
                Console.WriteLine(""null"");
            break;
        }
    }

    static void Main()
    {
        Test(1);
        Test(null);
    }
}";
            var compilation = CreateCompilation(source, options: TestOptions.DebugExe);
            compilation.VerifyDiagnostics();
            CompileAndVerify(compilation, expectedOutput:
@"not null
null");
        }

        [Fact]
        [WorkItem(16066, "https://github.com/dotnet/roslyn/issues/16066")]
        public void SwitchSectionWithLambda_01()
        {
            var source =
@"
class Program
{
    static void Main(string[] args)
    {
        switch((object)new A())
        {
            case A a:
                System.Action print = () => System.Console.WriteLine(a);
                print();
                break;
        }
    }
}

class A{}
";
            var compilation = CreateCompilation(source, options: TestOptions.DebugExe);
            compilation.VerifyDiagnostics();
            var expectedOutput = "A";
            var comp = CompileAndVerify(compilation, expectedOutput: expectedOutput);
        }

        [Fact]
        [WorkItem(16066, "https://github.com/dotnet/roslyn/issues/16066")]
        public void SwitchSectionWithLambda_02()
        {
            var source =
@"
class Program
{
    static void Main(string[] args)
    {
        int val = 3;
        var l = new System.Collections.Generic.List<System.Action>();
        int i = 1;
        switch(val)
        {
            case int a when a == 3:
            case 1:
                System.Console.WriteLine(""case 1: {0}"", i);
                a = i++;
                l.Add(() => System.Console.WriteLine(a));
                goto case 2;
            case int a when a == 4:
            case 2:
                System.Console.WriteLine(""case 2: {0}"", i);
                a = i++;
                l.Add(() => System.Console.WriteLine(a));

                if (i < 4)
                {
                    goto case 1;
                }
                break;
        }

        foreach (var a in l)
        {
            a();
        }
    }
}
";
            var compilation = CreateCompilation(source, options: TestOptions.DebugExe);
            compilation.VerifyDiagnostics();
            var comp = CompileAndVerify(compilation, expectedOutput:
@"case 1: 1
case 2: 2
case 1: 3
case 2: 4
3
4
3
4");
        }

        [Fact]
        [WorkItem(16066, "https://github.com/dotnet/roslyn/issues/16066")]
        public void SwitchSectionWithYield_01()
        {
            var source =
@"
class Program
{
    static void Main()
    {
        foreach (var a in Test())
        {
            System.Console.WriteLine(a);
        }
    }

    static System.Collections.Generic.IEnumerable<string> Test()
    {
        int val = 3;
        var l = new System.Collections.Generic.List<System.Action>();
        int i = 1;
        switch(val)
        {
            case int a when a == 3:
            case 1:
                yield return string.Format(""case 1: {0}"", i);
                a = i++;
                l.Add(() => System.Console.WriteLine(a));
                goto case 2;
            case int a when a == 4:
            case 2:
                yield return string.Format(""case 2: {0}"", i);
                a = i++;
                l.Add(() => System.Console.WriteLine(a));

                if (i < 4)
                {
                    goto case 1;
                }
                break;
        }

        foreach (var a in l)
        {
            a();
        }
    }
}
";
            var compilation = CreateCompilation(source, options: TestOptions.DebugExe);
            compilation.VerifyDiagnostics();
            var comp = CompileAndVerify(compilation, expectedOutput:
@"case 1: 1
case 2: 2
case 1: 3
case 2: 4
3
4
3
4");
        }

        [Fact]
        [WorkItem(16066, "https://github.com/dotnet/roslyn/issues/16066")]
        public void SwitchSectionWithYield_02()
        {
            var source =
@"
class Program
{
    static void Main()
    {
        foreach (var a in Test())
        {
            System.Console.WriteLine(a);
        }
    }

    static System.Collections.Generic.IEnumerable<string> Test()
    {
        int val = 3;
        int i = 1;
        switch(val)
        {
            case int a when a == 3:
            case 1:
                yield return string.Format(""case 1: {0}"", i);
                a = i++;
                System.Console.WriteLine(a);
                goto case 2;
            case int a when a == 4:
            case 2:
                yield return string.Format(""case 2: {0}"", i);
                a = i++;
                System.Console.WriteLine(a);

                if (i < 4)
                {
                    goto case 1;
                }
                break;
        }
    }
}
";
            var compilation = CreateCompilation(source, options: TestOptions.DebugExe);
            compilation.VerifyDiagnostics();
            var comp = CompileAndVerify(compilation, expectedOutput:
@"case 1: 1
1
case 2: 2
2
case 1: 3
3
case 2: 4
4");
        }

        [Fact]
        [WorkItem(16066, "https://github.com/dotnet/roslyn/issues/16066")]
        public void SwitchSectionWithYield_03()
        {
            var source =
@"
class Program
{
    static void Main()
    {
        foreach (var a in Test())
        {
            System.Console.WriteLine(a);
        }
    }

    static System.Collections.Generic.IEnumerable<int> Test()
    {
        int val = 3;
        int i = 1;
        switch(val)
        {
            case int a when a == 3:
            case 1:
                System.Console.WriteLine(""case 1: {0}"", i);
                a = i++;
                System.Console.WriteLine(a);
                goto case 2;
            case int a when a == 4:
            case 2:
                System.Console.WriteLine(""case 2: {0}"", i);
                a = i++;
                System.Console.WriteLine(a);

                if (i < 4)
                {
                    goto case 1;
                }
                break;
        }

        yield return i;
    }
}
";
            var compilation = CreateCompilation(source, options: TestOptions.ReleaseExe);
            compilation.VerifyDiagnostics();
            var comp = CompileAndVerify(compilation, expectedOutput:
@"case 1: 1
1
case 2: 2
2
case 1: 3
3
case 2: 4
4
5");
        }

        [Fact]
        [WorkItem(16066, "https://github.com/dotnet/roslyn/issues/16066")]
        public void SwitchSectionWithYield_04()
        {
            var source =
@"
class Program
{
    static void Main()
    {
        foreach (var a in Test())
        {
            System.Console.WriteLine(a);
        }
    }

    static System.Collections.Generic.IEnumerable<string> Test()
    {
        int val = 3;
        switch(val)
        {
            case int a when TakeOutVar(out var b) && a == b:
                yield return string.Format(""case: {0}"", val);
                System.Console.WriteLine(a);
                break;
        }
    }

    static bool TakeOutVar(out int x)
    {
        x = 3;
        return true;
    }
}
";
            var compilation = CreateCompilation(source, options: TestOptions.ReleaseExe);
            compilation.VerifyDiagnostics();
            var comp = CompileAndVerify(compilation, expectedOutput:
@"case: 3
3");
        }

        [Fact]
        [WorkItem(16066, "https://github.com/dotnet/roslyn/issues/16066")]
        public void SwitchSectionWithAwait_01()
        {
            var source =
@"
using System.Threading.Tasks;

class Program
{
    static void Main()
    {
        System.Console.WriteLine(Test().Result);
    }

    static async Task<int> Test()
    {
        int val = 3;
        var l = new System.Collections.Generic.List<System.Action>();
        int i = 1;
        switch(val)
        {
            case int a when a == 3:
            case 1:
                System.Console.WriteLine(await GetTask(string.Format(""case 1: {0}"", i)));
                a = i++;
                l.Add(() => System.Console.WriteLine(a));
                goto case 2;
            case int a when a == 4:
            case 2:
                System.Console.WriteLine(await GetTask(string.Format(""case 2: {0}"", i)));
                a = i++;
                l.Add(() => System.Console.WriteLine(a));

                if (i < 4)
                {
                    goto case 1;
                }
                break;
        }

        foreach (var a in l)
        {
            a();
        }

        return i;
    }

    static async Task<string> GetTask(string val)
    {
        await Task.Yield();
        return val;
    }
}
";
            // Use a compilation profile that supports Task<T>.
            var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe);
            compilation.VerifyDiagnostics();
            var comp = CompileAndVerify(compilation, expectedOutput:
@"case 1: 1
case 2: 2
case 1: 3
case 2: 4
3
4
3
4
5");
        }

        [Fact]
        [WorkItem(16066, "https://github.com/dotnet/roslyn/issues/16066")]
        public void SwitchSectionWithAwait_02()
        {
            var source =
@"
using System.Threading.Tasks;

class Program
{
    static void Main()
    {
        System.Console.WriteLine(Test().Result);
    }

    static async Task<int> Test()
    {
        int val = 3;
        int i = 1;
        switch(val)
        {
            case int a when a == 3:
            case 1:
                System.Console.WriteLine(await GetTask(string.Format(""case 1: {0}"", i)));
                a = i++;
                System.Console.WriteLine(a);
                goto case 2;
            case int a when a == 4:
            case 2:
                System.Console.WriteLine(await GetTask(string.Format(""case 2: {0}"", i)));
                a = i++;
                System.Console.WriteLine(a);

                if (i < 4)
                {
                    goto case 1;
                }
                break;
        }

        return i;
    }

    static async Task<string> GetTask(string val)
    {
        await Task.Yield();
        return val;
    }
}
";
            // Use a compilation profile that supports Task<T>.
            var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe);
            compilation.VerifyDiagnostics();
            var comp = CompileAndVerify(compilation, expectedOutput:
@"case 1: 1
1
case 2: 2
2
case 1: 3
3
case 2: 4
4
5");
        }

        [Fact]
        [WorkItem(16066, "https://github.com/dotnet/roslyn/issues/16066")]
        public void SwitchSectionWithAwait_03()
        {
            var source =
@"
using System.Threading.Tasks;

class Program
{
    static void Main()
    {
        System.Console.WriteLine(Test().Result);
    }

    static async Task<int> Test()
    {
        int val = 3;
        int i = 1;
        switch(val)
        {
            case int a when a == 3:
            case 1:
                System.Console.WriteLine(""case 1: {0}"", i);
                a = i++;
                System.Console.WriteLine(a);
                goto case 2;
            case int a when a == 4:
            case 2:
                System.Console.WriteLine(""case 2: {0}"", i);
                a = i++;
                System.Console.WriteLine(a);

                if (i < 4)
                {
                    goto case 1;
                }
                break;
        }

        await Task.Yield();
        return i;
    }
}
";
            // Use a compilation profile that supports Task<T>.
            var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe);
            compilation.VerifyDiagnostics();
            var comp = CompileAndVerify(compilation, expectedOutput:
@"case 1: 1
1
case 2: 2
2
case 1: 3
3
case 2: 4
4
5");
        }

        [Fact]
        [WorkItem(16066, "https://github.com/dotnet/roslyn/issues/16066")]
        public void SwitchSectionWithAwait_04()
        {
            var source =
@"
using System.Threading.Tasks;

class Program
{
    static void Main()
    {
        System.Console.WriteLine(Test().Result);
    }

    static async Task<int> Test()
    {
        int val = 3;
        switch(val)
        {
            case int a when TakeOutVar(out var b) && a == b:
                System.Console.WriteLine(await GetTask(string.Format(""case: {0}"", val)));
                return a;
        }

        return 0;
    }

    static bool TakeOutVar(out int x)
    {
        x = 3;
        return true;
    }

    static async Task<string> GetTask(string val)
    {
        await Task.Yield();
        return val;
    }
}
";
            // Use a compilation profile that supports Task<T>.
            var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe);
            compilation.VerifyDiagnostics();
            var comp = CompileAndVerify(compilation, expectedOutput:
@"case: 3
3");
        }

        [Fact]
        [WorkItem(16066, "https://github.com/dotnet/roslyn/issues/16066")]
        [WorkItem(401335, "https://devdiv.visualstudio.com/DevDiv/_workitems?id=401335")]
        public void SwitchAwaitGenericsAndOptimization()
        {
            var source =
@"
using System.Threading.Tasks;

class Test
{
    static void Main()
    {
        System.Console.WriteLine(SendMessageAsync<string>(""a"").Result);
        System.Console.WriteLine(SendMessageAsync<string>('a').Result);
    }

    public static async Task<string> SendMessageAsync<T>(object response)
    {
        switch (response)
        {
            case T expected:
                return ""T"";
            default:
                return ""default"";
        }
    }
}
";
            // Use a compilation profile that supports Task<T>.
            var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe);
            compilation.VerifyDiagnostics(
                // (12,38): warning CS1998: This async method lacks 'await' operators and will run synchronously. Consider using the 'await' operator to await non-blocking API calls, or 'await Task.Run(...)' to do CPU-bound work on a background thread.
                //     public static async Task<string> SendMessageAsync<T>(object response)
                Diagnostic(ErrorCode.WRN_AsyncLacksAwaits, "SendMessageAsync").WithLocation(12, 38)
                );
            var comp = CompileAndVerify(compilation, expectedOutput:
@"T
default");
        }

        [Fact]
        [WorkItem(16066, "https://github.com/dotnet/roslyn/issues/16066")]
        [WorkItem(401335, "https://devdiv.visualstudio.com/DevDiv/_workitems?id=401335")]
        public void SwitchLambdaGenericsAndOptimization()
        {
            var source =
@"
class Test
{
    static void Main()
    {
        System.Console.WriteLine(SendMessage<string>(""a""));
        System.Console.WriteLine(SendMessage<string>('a'));
    }

    public static string SendMessage<T>(object input)
    {
        System.Func<object, string> f = (response) =>
        {
            switch (response)
            {
                case T expected:
                    return ""T"";
                default:
                    return ""default"";
            }
        };

        return f(input);
    }
}
";
            var compilation = CreateCompilation(source, options: TestOptions.ReleaseExe);
            compilation.VerifyDiagnostics();
            var comp = CompileAndVerify(compilation, expectedOutput:
@"T
default");
        }

        [Fact]
        [WorkItem(16066, "https://github.com/dotnet/roslyn/issues/16066")]
        [WorkItem(401335, "https://devdiv.visualstudio.com/DevDiv/_workitems?id=401335")]
        public void SwitchIteratorGenericsAndOptimization()
        {
            var source =
@"
class Test
{
    static void Main()
    {
        foreach (var s in SendMessage<string>(""a""))
        {
            System.Console.WriteLine(s);
        }
        foreach (var s in SendMessage<string>('a'))
        {
            System.Console.WriteLine(s);
        }
    }

    public static System.Collections.Generic.IEnumerable<string> SendMessage<T>(object response)
    {
        switch (response)
        {
            case T expected:
                yield return ""T"";
                yield break;
            default:
                yield return ""default"";
                yield break;
        }
    }
}
";
            var compilation = CreateCompilation(source, options: TestOptions.ReleaseExe);
            compilation.VerifyDiagnostics();
            var comp = CompileAndVerify(compilation, expectedOutput:
@"T
default");
        }

        [Fact]
        [WorkItem(17088, "https://github.com/dotnet/roslyn/issues/17088")]
        public void TupleNameDifferences_01()
        {
            var source =
@"
using System.Collections.Generic;

class Program
{
    static void Main()
    {
        var list = new List<(int a, int b)>();
        switch (list)
        {
            case List<(int x, int y)> list1:
                break;
            case List<(int z, int w)> list2: // subsumed
                break;
        }
    }
}
";
            var compilation = CreateCompilation(source, options: TestOptions.ReleaseExe);
            compilation.VerifyDiagnostics(
                // (13,18): error CS8120: The switch case is unreachable. It has already been handled by a previous case or it is impossible to match.
                //             case List<(int z, int w)> list2: // subsumed
                Diagnostic(ErrorCode.ERR_SwitchCaseSubsumed, "List<(int z, int w)> list2").WithLocation(13, 18)
                );
        }

        [Fact]
        [WorkItem(17088, "https://github.com/dotnet/roslyn/issues/17088")]
        public void TupleNameDifferences_02()
        {
            var source =
@"
using System;
using System.Collections.Generic;

class Program
{
    static void Main()
    {
        var list = new List<(int a, int b)>();
        switch (list)
        {
            case List<(int x, int y)> list1:
                Console.WriteLine(""pass"");
                break;
        }
    }
}
";
            var compilation = CreateCompilation(source, options: TestOptions.ReleaseExe);
            compilation.VerifyDiagnostics(
                );
            var comp = CompileAndVerify(compilation, expectedOutput: @"pass");
        }

        [Fact]
        [WorkItem(17088, "https://github.com/dotnet/roslyn/issues/17088")]
        public void TupleNameDifferences_03()
        {
            var source =
@"
using System;

class Program
{
    static void Main()
    {
        var t = (a: 1, b: 2);
        switch (t)
        {
            case ValueTuple<int, int> x:
                Console.WriteLine(""pass"");
                break;
        }
    }
}
";
            var compilation = CreateCompilation(source, options: TestOptions.ReleaseExe);
            compilation.VerifyDiagnostics(
                );
            var comp = CompileAndVerify(compilation, expectedOutput: @"pass");
        }

        [Fact]
        [WorkItem(17088, "https://github.com/dotnet/roslyn/issues/17088")]
        public void TupleNameDifferences_04()
        {
            var source =
@"
using System;

class Program
{
    static void Main()
    {
        var t = (a: 1, b: 2);
        switch (t)
        {
            case var x:
                Console.WriteLine(x.a);
                break;
        }
    }
}
";
            var compilation = CreateCompilation(source, options: TestOptions.ReleaseExe);
            compilation.VerifyDiagnostics(
                );
            var comp = CompileAndVerify(compilation, expectedOutput: @"1");
        }

        [Fact]
        [WorkItem(17088, "https://github.com/dotnet/roslyn/issues/17088")]
        public void TupleNameDifferences_05()
        {
            var source =
@"
using System;

class Program
{
    static void Main()
    {
        var t = (a: 1, b: 2);
        switch (t)
        {
            case ValueTuple<int, int> x:
                break;
            case var x:
                break;
        }
    }
}
";
            var compilation = CreateCompilation(source, options: TestOptions.ReleaseExe);
            compilation.VerifyDiagnostics(
                // (13,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 x:
                Diagnostic(ErrorCode.ERR_SwitchCaseSubsumed, "var x").WithLocation(13, 18)
                );
        }

        [Fact]
        [WorkItem(17088, "https://github.com/dotnet/roslyn/issues/17088")]
        public void DynamicDifferences_01()
        {
            var source =
@"
using System.Collections.Generic;

class Program
{
    static void Main()
    {
        var list = new List<dynamic>();
        switch (list)
        {
            case List<object> list1:
                break;
            case List<dynamic> list2: // subsumed
                break;
        }
    }
}
";
            var compilation = CreateCompilation(source, options: TestOptions.ReleaseExe);
            compilation.VerifyDiagnostics(
                // (13,18): error CS8120: The switch case is unreachable. It has already been handled by a previous case or it is impossible to match.
                //             case List<dynamic> list2: // subsumed
                Diagnostic(ErrorCode.ERR_SwitchCaseSubsumed, "List<dynamic> list2").WithLocation(13, 18)
                );
        }

        [Fact]
        [WorkItem(17088, "https://github.com/dotnet/roslyn/issues/17088")]
        public void DynamicDifferences_02()
        {
            var source =
@"
using System;
using System.Collections.Generic;

class Program
{
    static void Main()
    {
        var list = new List<dynamic>();
        switch (list)
        {
            case List<object> list1:
                Console.WriteLine(""pass"");
                break;
        }
    }
}
";
            var compilation = CreateCompilation(source, options: TestOptions.ReleaseExe);
            compilation.VerifyDiagnostics(
                );
            var comp = CompileAndVerify(compilation, expectedOutput: @"pass");
        }

        [Fact]
        [WorkItem(17089, "https://github.com/dotnet/roslyn/issues/17089")]
        public void Dynamic_01()
        {
            var source =
@"
class Program
{
    static void Main()
    {
        dynamic d = 1;
        switch (d)
        {
            case dynamic x: // error 1
                break;
        }
        if (d is dynamic y) {} // error 2
        if (d is var z) // ok
        {
            long l = z;
            string s = z;
        }
    }
}
";
            var compilation = CreateCompilation(source, options: TestOptions.ReleaseExe);
            compilation.VerifyDiagnostics(
                // (9,18): error CS8330: It is not legal to use the type 'dynamic' in a pattern.
                //             case dynamic x: // error 1
                Diagnostic(ErrorCode.ERR_PatternDynamicType, "dynamic"),
                // (12,18): error CS8330: It is not legal to use the type 'dynamic' in a pattern.
                //         if (d is dynamic y) {} // error 2
                Diagnostic(ErrorCode.ERR_PatternDynamicType, "dynamic").WithLocation(12, 18)
                );
        }

        [Fact]
        [WorkItem(17089, "https://github.com/dotnet/roslyn/issues/17089")]
        public void Dynamic_02()
        {
            var source =
@"
class Program
{
    static void Main()
    {
        dynamic d = 1;
        switch (d)
        {
            case object x:
            case var y: // OK, catches null
            case var z: // error: subsumed
                break;
        }
        switch (d)
        {
            case object x:
            case null:
            case var y: // error: subsumed
                break;
        }
        switch (d)
        {
            case object x:
            case 1: // error: subsumed
                break;
        }
        switch (d)
        {
            case object x:
            case int y: // error: subsumed
                break;
        }
        switch (d)
        {
            case object x:
            case (dynamic)null:
            case (string)null: // error: subsumed
                break;
        }
        switch (d)
        {
            case int i:
            case long l:
            case object o:
            case var v:
                break;
        }
    }
}
";
            var compilation = CreateCompilation(source, options: TestOptions.ReleaseExe);
            compilation.VerifyDiagnostics(
                // (11,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 z: // error: subsumed
                Diagnostic(ErrorCode.ERR_SwitchCaseSubsumed, "var z").WithLocation(11, 18),
                // (18,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 y: // error: subsumed
                Diagnostic(ErrorCode.ERR_SwitchCaseSubsumed, "var y").WithLocation(18, 18),
                // (24,18): error CS8120: The switch case is unreachable. It has already been handled by a previous case or it is impossible to match.
                //             case 1: // error: subsumed
                Diagnostic(ErrorCode.ERR_SwitchCaseSubsumed, "1").WithLocation(24, 18),
                // (30,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 y: // error: subsumed
                Diagnostic(ErrorCode.ERR_SwitchCaseSubsumed, "int y").WithLocation(30, 18),
                // (37,13): error CS0152: The switch statement contains multiple cases with the label value 'null'
                //             case (string)null: // error: subsumed
                Diagnostic(ErrorCode.ERR_DuplicateCaseLabel, "case (string)null:").WithArguments("null").WithLocation(37, 13)
                );
        }

        [Fact]
        public void SubsumedCasesAreUnreachable_01()
        {
            var source =
@"
class Program
{
    static void Main(string[] args)
    {
        switch (args.Length)
        {
            case 1:
                break;
            case System.IComparable c:
                break;
            case 2: // error: subsumed
                break; // unreachable (1)?
            case int n: // error: subsumed
                break; // unreachable (2)?
            case var i: // error: subsumed
                break; // unreachable (3)?
            default:
                break; // unreachable, because `var i` would catch all
        }
    }
}
";
            var compilation = CreateCompilation(source, options: TestOptions.ReleaseExe);
            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 2: // error: subsumed
                Diagnostic(ErrorCode.ERR_SwitchCaseSubsumed, "2").WithLocation(12, 18),
                // (14,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 n: // error: subsumed
                Diagnostic(ErrorCode.ERR_SwitchCaseSubsumed, "int n").WithLocation(14, 18),
                // (16,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 i: // error: subsumed
                Diagnostic(ErrorCode.ERR_SwitchCaseSubsumed, "var i").WithLocation(16, 18),
                // (19,17): warning CS0162: Unreachable code detected
                //                 break; // unreachable, because `var i` would catch all
                Diagnostic(ErrorCode.WRN_UnreachableCode, "break").WithLocation(19, 17)
                );
        }

        [Fact]
        public void SwitchTuple()
        {
            var source =
@"
class Program
{
    static void Main(string[] args)
    {
        switch ((x: 1, y: 2))
        {
            case System.IComparable c:
                break;
            case System.ValueTuple<int, int> x: // error: subsumed
                break;
            default:
                break; // unreachable because a single case handles all input
        }
    }
}
";
            var compilation = CreateCompilation(source, options: TestOptions.ReleaseExe);
            compilation.VerifyDiagnostics(
                // (10,18): error CS8120: The switch case is unreachable. It has already been handled by a previous case or it is impossible to match.
                //             case System.ValueTuple<int, int> x: // error: subsumed
                Diagnostic(ErrorCode.ERR_SwitchCaseSubsumed, "System.ValueTuple<int, int> x").WithLocation(10, 18),
                // (13,17): warning CS0162: Unreachable code detected
                //                 break; // unreachable because a single case handles all input
                Diagnostic(ErrorCode.WRN_UnreachableCode, "break").WithLocation(13, 17)
               );
        }

        [Fact]
        public void ByValueThenByTypeTwice()
        {
            var source =
@"
class Program
{
    static bool b = false;
    static int i = 2;
    static void Main(string[] args)
    {
        switch (i)
        {
            case 1:
                break;
            case System.IComparable c when b:
                break;
            case System.IFormattable f when b:
                break;
            default:
                System.Console.WriteLine(nameof(Main));
                break;
        }
    }
}
";
            var compilation = CreateCompilationWithMscorlib40(
                source, options: TestOptions.ReleaseExe, references: new[] { SystemRuntimeFacadeRef, ValueTupleRef });
            compilation.VerifyDiagnostics();
            var comp = CompileAndVerify(compilation, expectedOutput: "Main");
        }

        [Fact, WorkItem(18948, "https://github.com/dotnet/roslyn/issues/18948")]
        public void AsyncGenericPatternCrash()
        {
            var source =
@"
using System.Threading.Tasks;

static class Ex
{
    public static async Task<T> SwitchWithAwaitInPatternFails<T>(Task self, T defaultValue)
    {
        switch (self)
        {
            case Task<T> resultTask:
                return await resultTask.ConfigureAwait(false);

            default:
                await self.ConfigureAwait(false);
                return default(T);
        }
    }
}
";
            // Use a compilation profile that supports Task<T>.
            var compilation = CreateCompilationWithMscorlib45(
                source, options: TestOptions.ReleaseDll.WithOptimizationLevel(OptimizationLevel.Release), references: new[] { SystemCoreRef, CSharpRef });
            compilation.VerifyDiagnostics();
            var comp = CompileAndVerify(compilation);
        }

        [Fact, WorkItem(388743, "https://devdiv.visualstudio.com/DefaultCollection/DevDiv/_workitems?_a=edit&id=388743")]
        public void SemanticModelForBrokenSwitch_01()
        {
            // a syntax error that happens to look like a pattern switch if you squint
            var source =
@"class Sample
{
    void M()
    {
        bool x = true;

        switch (x) {
            case

        var q = 3;
        var y = q/*BIND*/;
    }
}";
            var compilation = CreateCompilation(source, options: TestOptions.ReleaseDll, parseOptions: TestOptions.Regular6);
            compilation.VerifyDiagnostics(
                // (10,15): error CS1003: Syntax error, ':' expected
                //         var q = 3;
                Diagnostic(ErrorCode.ERR_SyntaxError, "=").WithArguments(":").WithLocation(10, 15),
                // (10,15): error CS1525: Invalid expression term '='
                //         var q = 3;
                Diagnostic(ErrorCode.ERR_InvalidExprTerm, "=").WithArguments("=").WithLocation(10, 15),
                // (13,2): error CS1513: } expected
                // }
                Diagnostic(ErrorCode.ERR_RbraceExpected, "").WithLocation(13, 2),
                // (8,13): error CS8059: Feature 'pattern matching' is not available in C# 6. Please use language version 7.0 or greater.
                //             case
                Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion6, "case").WithArguments("pattern matching", "7.0").WithLocation(8, 13),
                // (8,13): error CS8070: Control cannot fall out of switch from final case label ('case
                //             case
                Diagnostic(ErrorCode.ERR_SwitchFallOut, @"case

        var q ").WithArguments(@"case

        var q ").WithLocation(8, 13));
            var tree = compilation.SyntaxTrees[0];
            var model = compilation.GetSemanticModel(tree);
            var node = tree.GetRoot().DescendantNodes()
                .OfType<IdentifierNameSyntax>()
                .Where(n => n.Identifier.ValueText == "q" && n.ToFullString().Contains("/*BIND*/"))
                .Single();
            var type = model.GetTypeInfo(node);
        }

        [Fact, WorkItem(388743, "https://devdiv.visualstudio.com/DefaultCollection/DevDiv/_workitems?_a=edit&id=388743")]
        public void SemanticModelForBrokenSwitch_02()
        {
            // a simple legal pattern switch but run in language version 6
            var source =
@"class Sample
{
    void M()
    {
        bool b = true;
        switch (b) {
            case var q:
                System.Console.WriteLine(q/*BIND*/);
                break;
        }
    }
}";
            var compilation = CreateCompilation(source, options: TestOptions.ReleaseDll, parseOptions: TestOptions.Regular6);
            compilation.VerifyDiagnostics(
                // (7,13): error CS8059: Feature 'pattern matching' is not available in C# 6. Please use language version 7.0 or greater.
                //             case var q:
                Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion6, "case").WithArguments("pattern matching", "7.0").WithLocation(7, 13));
            var tree = compilation.SyntaxTrees[0];
            var model = compilation.GetSemanticModel(tree);
            var node = tree.GetRoot().DescendantNodes()
                .OfType<IdentifierNameSyntax>()
                .Where(n => n.Identifier.ValueText == "q" && n.ToFullString().Contains("/*BIND*/"))
                .Single();
            var type = model.GetTypeInfo(node);
            Assert.Equal(SpecialType.System_Boolean, type.Type.SpecialType);
            Assert.Equal(SpecialType.System_Boolean, type.ConvertedType.SpecialType);
        }

        [Fact]
        [WorkItem(46593, "https://github.com/dotnet/roslyn/issues/46593")]
        public void NameofInWhenClause()
        {
            var source =
@"struct Outer
{
    struct S
    {
        static void M(string q)
        {
            S s = new S();
            System.Console.Write(s switch
            {
                { P: 1 } when nameof(Q) == q => 1,
                { P: 2 } => 2,
                _ => 3,
            });
        }

        int P => 1;
    }

    public int Q => 1;
}
";
            var compilation = CreateCompilation(source, options: TestOptions.ReleaseDll);
            compilation.VerifyEmitDiagnostics(
                );
        }

        [Fact, WorkItem(20210, "https://github.com/dotnet/roslyn/issues/20210")]
        public void SwitchOnNull_20210()
        {
            var source =
@"class Sample
{
    void M()
    {
        switch (default(object))
        {
          case bool _:
          case true:     // error: subsumed (1 of 12)
          case false:    // error: subsumed (2 of 12)
            break;
        }

        switch (new object())
        {
          case bool _:
          case true:     // error: subsumed (3 of 12)
          case false:    // error: subsumed (4 of 12)
            break;
        }

        switch ((object)null)
        {
          case bool _:
          case true:     // error: subsumed (5 of 12)
          case false:    // error: subsumed (6 of 12)
            break;
        }

        switch ((bool?)null)
        {
          case bool _:
          case true:     // error: subsumed (7 of 12)
          case false:    // error: subsumed (8 of 12)
            break;
        }

        switch (default(bool?))
        {
          case bool _:
          case true:     // error: subsumed (9 of 12)
          case false:    // error: subsumed (10 of 12)
            break;
        }

        switch (default(bool))
        {
          case bool _:
          case true:     // error: subsumed (11 of 12)
          case false:    // error: subsumed (12 of 12)
            break;
        }
    }
}";
            var compilation = CreateCompilation(source, options: TestOptions.ReleaseDll);
            compilation.VerifyDiagnostics(
                // (8,16): error CS8120: The switch case is unreachable. It has already been handled by a previous case or it is impossible to match.
                //           case true:     // error: subsumed (1 of 12)
                Diagnostic(ErrorCode.ERR_SwitchCaseSubsumed, "true").WithLocation(8, 16),
                // (9,16): error CS8120: The switch case is unreachable. It has already been handled by a previous case or it is impossible to match.
                //           case false:    // error: subsumed (2 of 12)
                Diagnostic(ErrorCode.ERR_SwitchCaseSubsumed, "false").WithLocation(9, 16),
                // (16,16): error CS8120: The switch case is unreachable. It has already been handled by a previous case or it is impossible to match.
                //           case true:     // error: subsumed (3 of 12)
                Diagnostic(ErrorCode.ERR_SwitchCaseSubsumed, "true").WithLocation(16, 16),
                // (17,16): error CS8120: The switch case is unreachable. It has already been handled by a previous case or it is impossible to match.
                //           case false:    // error: subsumed (4 of 12)
                Diagnostic(ErrorCode.ERR_SwitchCaseSubsumed, "false").WithLocation(17, 16),
                // (24,16): error CS8120: The switch case is unreachable. It has already been handled by a previous case or it is impossible to match.
                //           case true:     // error: subsumed (5 of 12)
                Diagnostic(ErrorCode.ERR_SwitchCaseSubsumed, "true").WithLocation(24, 16),
                // (25,16): error CS8120: The switch case is unreachable. It has already been handled by a previous case or it is impossible to match.
                //           case false:    // error: subsumed (6 of 12)
                Diagnostic(ErrorCode.ERR_SwitchCaseSubsumed, "false").WithLocation(25, 16),
                // (32,16): error CS8120: The switch case is unreachable. It has already been handled by a previous case or it is impossible to match.
                //           case true:     // error: subsumed (7 of 12)
                Diagnostic(ErrorCode.ERR_SwitchCaseSubsumed, "true").WithLocation(32, 16),
                // (33,16): error CS8120: The switch case is unreachable. It has already been handled by a previous case or it is impossible to match.
                //           case false:    // error: subsumed (8 of 12)
                Diagnostic(ErrorCode.ERR_SwitchCaseSubsumed, "false").WithLocation(33, 16),
                // (40,16): error CS8120: The switch case is unreachable. It has already been handled by a previous case or it is impossible to match.
                //           case true:     // error: subsumed (9 of 12)
                Diagnostic(ErrorCode.ERR_SwitchCaseSubsumed, "true").WithLocation(40, 16),
                // (41,16): error CS8120: The switch case is unreachable. It has already been handled by a previous case or it is impossible to match.
                //           case false:    // error: subsumed (10 of 12)
                Diagnostic(ErrorCode.ERR_SwitchCaseSubsumed, "false").WithLocation(41, 16),
                // (48,16): error CS8120: The switch case is unreachable. It has already been handled by a previous case or it is impossible to match.
                //           case true:     // error: subsumed (11 of 12)
                Diagnostic(ErrorCode.ERR_SwitchCaseSubsumed, "true").WithLocation(48, 16),
                // (49,16): error CS8120: The switch case is unreachable. It has already been handled by a previous case or it is impossible to match.
                //           case false:    // error: subsumed (12 of 12)
                Diagnostic(ErrorCode.ERR_SwitchCaseSubsumed, "false").WithLocation(49, 16)
                );
        }

        [Fact, WorkItem(47164, "https://github.com/dotnet/roslyn/issues/47164")]
        public void MultipleWhenClausesToFailure_01()
        {
            var source =
@"class Sample
{
    void M(int q)
    {
        _ = q switch
        {
            4 => 1,
            5 => 2,
            6 => 3,
            int i when i % 2 == 1 => 4,
            int i when i % 2 == 0 => 5,
        };
    }
}";
            var compilation = CreateCompilation(source, options: TestOptions.ReleaseDll);
            compilation.VerifyEmitDiagnostics(
                // (5,15): warning CS8846: The switch expression does not handle all possible values of its input type (it is not exhaustive). For example, the pattern '0' is not covered. However, a pattern with a 'when' clause might successfully match this value.
                //         _ = q switch
                Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustiveWithWhen, "switch").WithArguments("0").WithLocation(5, 15)
                );
        }

        [Fact, WorkItem(47164, "https://github.com/dotnet/roslyn/issues/47164")]
        public void MultipleWhenClausesToFailure_02()
        {
            var source =
@"class Sample
{
    void M(int q)
    {
        _ = q switch
        {
            4 => 1,
            5 => 2,
            6 => 3,
            int i when i % 2 == 1 => 4,
        };
    }
}";
            var compilation = CreateCompilation(source, options: TestOptions.ReleaseDll);
            compilation.VerifyEmitDiagnostics(
                // (5,15): warning CS8846: The switch expression does not handle all possible values of its input type (it is not exhaustive). For example, the pattern '0' is not covered. However, a pattern with a 'when' clause might successfully match this value.
                //         _ = q switch
                Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustiveWithWhen, "switch").WithArguments("0").WithLocation(5, 15)
                );
        }

        [Fact, WorkItem(47164, "https://github.com/dotnet/roslyn/issues/47164")]
        public void MultipleWhenClausesToFailure_03()
        {
            var source =
@"class Sample
{
    void M(int q)
    {
        _ = q switch
        {
            4 => 1,
            5 => 2,
            6 => 3,
            int i when i % 3 == 0 => 4,
            int i when i % 3 == 1 => 5,
            int i when i % 3 == 2 => 6,
        };
    }
}";
            var compilation = CreateCompilation(source, options: TestOptions.ReleaseDll);
            compilation.VerifyEmitDiagnostics(
                // (5,15): warning CS8846: The switch expression does not handle all possible values of its input type (it is not exhaustive). For example, the pattern '0' is not covered. However, a pattern with a 'when' clause might successfully match this value.
                //         _ = q switch
                Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustiveWithWhen, "switch").WithArguments("0").WithLocation(5, 15)
                );
        }

        [Fact]
        public void MultiplePathsToState_01()
        {
            var source =
@"class Sample
{
    void M(int a, int b)
    {
        _ = (a, b) switch
        {
            (0, 0) => 0,
            (0, 1) => 1,
            (0, 2) => 2,

            (1, 0) => 5,
            (1, 1) => 6,
            (1, 2) => 7,

            _ => 10,
        };
    }
}";
            var compilation = CreateCompilation(source, options: TestOptions.ReleaseDll);
            compilation.VerifyEmitDiagnostics(
                );
        }

        [Fact, WorkItem(51930, "https://github.com/dotnet/roslyn/issues/51930")]
        public void AssignSwitchToRefReturningMethod()
        {
            var source = @"
GetRef() = 1 switch { _ => await System.Threading.Tasks.Task.FromResult(1) };
ref int GetRef() => throw null;";

            var comp = CreateCompilation(source, options: TestOptions.DebugExe);
            comp.VerifyEmitDiagnostics(
                // (2,1): error CS8178: 'await' cannot be used in an expression containing a call to 'Program.<<Main>$>g__GetRef|0_0()' because it returns by reference
                // GetRef() = 1 switch { _ => await System.Threading.Tasks.Task.FromResult(1) };
                Diagnostic(ErrorCode.ERR_RefReturningCallAndAwait, "GetRef()").WithArguments("Program.<<Main>$>g__GetRef|0_0()").WithLocation(2, 1)
            );
        }
    }
}