/
githubmirror
/
roslyn
Обзор
Документация
Войти
/
githubmirror
/
roslyn
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
src/Compilers/CSharp/Test/Emit3/Semantics/PatternSwitchTests.cs
4 063 строки
152 KB
AlekseyTs
Unions: Implement Try-Both approach for type pattern (#84323)
01 июл 2026, 23:05
Не верифицирован
01 июл 2026, 23:05
c3ee6e5
Код
Авторство
О чём код?
// 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; 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; using System.Globalization; 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.ToString(CultureInfo.InvariantCulture)); break; case double d when d is double e: Console.WriteLine(""double "" + e.ToString(CultureInfo.InvariantCulture)); break; case decimal d when d is decimal e: Console.WriteLine(""decimal "" + e.ToString(CultureInfo.InvariantCulture)); 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 = FormattableString.Invariant( $@"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), // (37,19): error CS8400: Feature 'type pattern' is not available in C# 8.0. Please use language version 9.0 or greater. // case (System.Int32, System.Int32) z: Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion8, "System.Int32").WithArguments("type pattern", "9.0").WithLocation(37, 19), // (37,33): error CS8400: Feature 'type pattern' is not available in C# 8.0. Please use language version 9.0 or greater. // case (System.Int32, System.Int32) z: Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion8, "System.Int32").WithArguments("type pattern", "9.0").WithLocation(37, 33), // (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), // (39,19): error CS8400: Feature 'type pattern' is not available in C# 8.0. Please use language version 9.0 or greater. // case (System.Int64, System.Int64) d: Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion8, "System.Int64").WithArguments("type pattern", "9.0").WithLocation(39, 19), // (39,33): error CS8400: Feature 'type pattern' is not available in C# 8.0. Please use language version 9.0 or greater. // case (System.Int64, System.Int64) d: Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion8, "System.Int64").WithArguments("type pattern", "9.0").WithLocation(39, 33), // (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), // (49,23): error CS8400: Feature 'type pattern' is not available in C# 8.0. Please use language version 9.0 or greater. // if (o is (System.Int32, System.Int32)) {} Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion8, "System.Int32").WithArguments("type pattern", "9.0").WithLocation(49, 23), // (49,37): error CS8400: Feature 'type pattern' is not available in C# 8.0. Please use language version 9.0 or greater. // if (o is (System.Int32, System.Int32)) {} Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion8, "System.Int32").WithArguments("type pattern", "9.0").WithLocation(49, 37), // (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), // (51,23): error CS8400: Feature 'type pattern' is not available in C# 8.0. Please use language version 9.0 or greater. // if (o is (System.Int32, System.Int32) z) {} Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion8, "System.Int32").WithArguments("type pattern", "9.0").WithLocation(51, 23), // (51,37): error CS8400: Feature 'type pattern' is not available in C# 8.0. Please use language version 9.0 or greater. // if (o is (System.Int32, System.Int32) z) {} Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion8, "System.Int32").WithArguments("type pattern", "9.0").WithLocation(51, 37), // (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 CS9133: A constant value of type 'bool' is expected // case new object() is int x1: Diagnostic(ErrorCode.ERR_ConstantValueOfTypeExpected, "new object() is int x1").WithArguments("bool").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 = CreateCompilationWithMscorlib461(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 = CreateCompilationWithMscorlib461(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 = CreateCompilationWithMscorlib461(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 = CreateCompilationWithMscorlib461(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 = CreateCompilationWithMscorlib461(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 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 = CreateCompilationWithMscorlib461( 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: A reference returned by a call to 'Program.<<Main>$>g__GetRef|0_0()' cannot be preserved across 'await' or 'yield' boundary. // 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) ); } [Theory] [WorkItem("https://github.com/dotnet/roslyn/issues/81784")] [CombinatorialData] public void GotoCase_01( [CombinatorialValues("byte", "sbyte", "short", "ushort", "int", "uint", "long", "ulong", "nint", "nuint")] string type1, [CombinatorialValues("byte", "sbyte", "short", "ushort", "int", "uint", "long", "ulong", "nint", "nuint")] string type2) { if (type1 == type2) { return; } var source = $$$""" class Program { static void Main() { int count = 0; switch ((object)({{{type1}}})2) { case ({{{type2}}})2: break; case ({{{type1}}})2: System.Console.Write("Case 2"); count++; if (count == 3) break; goto case ({{{type1}}})2; } } } """; CompileAndVerify(source, expectedOutput: "Case 2Case 2Case 2").VerifyDiagnostics(); CompileAndVerify(source, targetFramework: TargetFramework.Net100, expectedOutput: ExecutionConditionUtil.IsMonoOrCoreClr ? "Case 2Case 2Case 2" : null, verify: Verification.FailsPEVerify).VerifyDiagnostics(); } [Fact] [WorkItem("https://github.com/dotnet/roslyn/issues/81784")] public void GotoCase_02() { var source = $$$""" class Program { static void Main() { int count = 0; switch ((object)(System.IntPtr)2) { case (nint)2: break; case (System.IntPtr)2: System.Console.Write("Case 2"); count++; if (count == 3) break; goto case (System.IntPtr)2; } } } """; var expected1 = new[] { // (11,18): error CS0150: A constant value is expected // case (System.IntPtr)2: Diagnostic(ErrorCode.ERR_ConstantExpected, "(System.IntPtr)2").WithLocation(11, 18), // (16,17): error CS0150: A constant value is expected // goto case (System.IntPtr)2; Diagnostic(ErrorCode.ERR_ConstantExpected, "goto case (System.IntPtr)2;").WithLocation(16, 17), // (11,13): error CS8070: Control cannot fall out of switch from final case label ('case (System.IntPtr)2:') // case (System.IntPtr)2: Diagnostic(ErrorCode.ERR_SwitchFallOut, "case (System.IntPtr)2:").WithArguments("case (System.IntPtr)2:").WithLocation(11, 13) }; CreateCompilation(source).VerifyDiagnostics(expected1); CreateCompilation(source, parseOptions: TestOptions.Regular10).VerifyDiagnostics(expected1); CreateCompilation(source, parseOptions: TestOptions.Regular11).VerifyDiagnostics(expected1); var expected2 = new[] { // (11,13): error CS0152: The switch statement contains multiple cases with the label value '2' // case (System.IntPtr)2: Diagnostic(ErrorCode.ERR_DuplicateCaseLabel, "case (System.IntPtr)2:").WithArguments("2").WithLocation(11, 13) }; CreateCompilation(source, targetFramework: TargetFramework.Net100).VerifyDiagnostics(expected2); CreateCompilation(source, targetFramework: TargetFramework.Net100, parseOptions: TestOptions.Regular10).VerifyDiagnostics(expected2); CreateCompilation(source, targetFramework: TargetFramework.Net100, parseOptions: TestOptions.Regular11).VerifyDiagnostics(expected2); } [Fact] [WorkItem("https://github.com/dotnet/roslyn/issues/81784")] public void GotoCase_03() { var source = $$$""" class Program { static void Main() { int count = 0; switch ((object)(nint)2) { case (System.IntPtr)2: break; case (nint)2: System.Console.Write("Case 2"); count++; if (count == 3) break; goto case (nint)2; } } } """; var expected1 = new[] { // (9,18): error CS0150: A constant value is expected // case (System.IntPtr)2: Diagnostic(ErrorCode.ERR_ConstantExpected, "(System.IntPtr)2").WithLocation(9, 18) }; CreateCompilation(source).VerifyDiagnostics(expected1); CreateCompilation(source, parseOptions: TestOptions.Regular10).VerifyDiagnostics(expected1); CreateCompilation(source, parseOptions: TestOptions.Regular11).VerifyDiagnostics(expected1); var expected2 = new[] { // (11,13): error CS0152: The switch statement contains multiple cases with the label value '2' // case (nint)2: Diagnostic(ErrorCode.ERR_DuplicateCaseLabel, "case (nint)2:").WithArguments("2").WithLocation(11, 13) }; CreateCompilation(source, targetFramework: TargetFramework.Net100).VerifyDiagnostics(expected2); CreateCompilation(source, targetFramework: TargetFramework.Net100, parseOptions: TestOptions.Regular10).VerifyDiagnostics(expected2); CreateCompilation(source, targetFramework: TargetFramework.Net100, parseOptions: TestOptions.Regular11).VerifyDiagnostics(expected2); } [Fact] [WorkItem("https://github.com/dotnet/roslyn/issues/81784")] public void GotoCase_04() { var source = $$$""" class Program { static void Main() { int count = 0; switch ((object)(System.UIntPtr)2) { case (nuint)2: break; case (System.UIntPtr)2: System.Console.Write("Case 2"); count++; if (count == 3) break; goto case (System.UIntPtr)2; } } } """; var expected1 = new[] { // (11,18): error CS0150: A constant value is expected // case (System.UIntPtr)2: Diagnostic(ErrorCode.ERR_ConstantExpected, "(System.UIntPtr)2").WithLocation(11, 18), // (16,17): error CS0150: A constant value is expected // goto case (System.UIntPtr)2; Diagnostic(ErrorCode.ERR_ConstantExpected, "goto case (System.UIntPtr)2;").WithLocation(16, 17), // (11,13): error CS8070: Control cannot fall out of switch from final case label ('case (System.UIntPtr)2:') // case (System.UIntPtr)2: Diagnostic(ErrorCode.ERR_SwitchFallOut, "case (System.UIntPtr)2:").WithArguments("case (System.UIntPtr)2:").WithLocation(11, 13) }; CreateCompilation(source).VerifyDiagnostics(expected1); CreateCompilation(source, parseOptions: TestOptions.Regular10).VerifyDiagnostics(expected1); CreateCompilation(source, parseOptions: TestOptions.Regular11).VerifyDiagnostics(expected1); var expected2 = new[] { // (11,13): error CS0152: The switch statement contains multiple cases with the label value '2' // case (System.UIntPtr)2: Diagnostic(ErrorCode.ERR_DuplicateCaseLabel, "case (System.UIntPtr)2:").WithArguments("2").WithLocation(11, 13) }; CreateCompilation(source, targetFramework: TargetFramework.Net100).VerifyDiagnostics(expected2); CreateCompilation(source, targetFramework: TargetFramework.Net100, parseOptions: TestOptions.Regular10).VerifyDiagnostics(expected2); CreateCompilation(source, targetFramework: TargetFramework.Net100, parseOptions: TestOptions.Regular11).VerifyDiagnostics(expected2); } [Fact] [WorkItem("https://github.com/dotnet/roslyn/issues/81784")] public void GotoCase_05() { var source = $$$""" class Program { static void Main() { int count = 0; switch ((object)(nuint)2) { case (System.UIntPtr)2: break; case (nuint)2: System.Console.Write("Case 2"); count++; if (count == 3) break; goto case (nuint)2; } } } """; var expected1 = new[] { // (9,18): error CS0150: A constant value is expected // case (System.UIntPtr)2: Diagnostic(ErrorCode.ERR_ConstantExpected, "(System.UIntPtr)2").WithLocation(9, 18) }; CreateCompilation(source).VerifyDiagnostics(expected1); CreateCompilation(source, parseOptions: TestOptions.Regular10).VerifyDiagnostics(expected1); CreateCompilation(source, parseOptions: TestOptions.Regular11).VerifyDiagnostics(expected1); var expected2 = new[] { // (11,13): error CS0152: The switch statement contains multiple cases with the label value '2' // case (nuint)2: Diagnostic(ErrorCode.ERR_DuplicateCaseLabel, "case (nuint)2:").WithArguments("2").WithLocation(11, 13) }; CreateCompilation(source, targetFramework: TargetFramework.Net100).VerifyDiagnostics(expected2); CreateCompilation(source, targetFramework: TargetFramework.Net100, parseOptions: TestOptions.Regular10).VerifyDiagnostics(expected2); CreateCompilation(source, targetFramework: TargetFramework.Net100, parseOptions: TestOptions.Regular11).VerifyDiagnostics(expected2); } [Fact] [WorkItem("https://github.com/dotnet/roslyn/issues/81784")] public void GotoCase_06() { var source = $$$""" class Program { static void Main() { int count = 0; switch ((object)(nint)2) { case (int)2: break; case (nint)2: System.Console.Write("Case 2"); count++; if (count == 3) break; goto case (System.IntPtr)2; } } } """; var expected1 = new[] { // (16,17): error CS0150: A constant value is expected // goto case (System.IntPtr)2; Diagnostic(ErrorCode.ERR_ConstantExpected, "goto case (System.IntPtr)2;").WithLocation(16, 17), // (11,13): error CS8070: Control cannot fall out of switch from final case label ('case (nint)2:') // case (nint)2: Diagnostic(ErrorCode.ERR_SwitchFallOut, "case (nint)2:").WithArguments("case (nint)2:").WithLocation(11, 13) }; CreateCompilation(source).VerifyDiagnostics(expected1); CreateCompilation(source, parseOptions: TestOptions.Regular10).VerifyDiagnostics(expected1); CreateCompilation(source, parseOptions: TestOptions.Regular11).VerifyDiagnostics(expected1); CompileAndVerify(source, targetFramework: TargetFramework.Net100, expectedOutput: ExecutionConditionUtil.IsMonoOrCoreClr ? "Case 2Case 2Case 2" : null, verify: Verification.FailsPEVerify).VerifyDiagnostics(); CompileAndVerify(source, targetFramework: TargetFramework.Net100, parseOptions: TestOptions.Regular10, expectedOutput: ExecutionConditionUtil.IsMonoOrCoreClr ? "Case 2Case 2Case 2" : null, verify: Verification.FailsPEVerify).VerifyDiagnostics(); CompileAndVerify(source, targetFramework: TargetFramework.Net100, parseOptions: TestOptions.Regular11, expectedOutput: ExecutionConditionUtil.IsMonoOrCoreClr ? "Case 2Case 2Case 2" : null, verify: Verification.FailsPEVerify).VerifyDiagnostics(); } [Fact] [WorkItem("https://github.com/dotnet/roslyn/issues/81784")] public void GotoCase_07() { var source = $$$""" class Program { static void Main() { int count = 0; switch ((object)(nint)2) { case (int)2: break; case (System.IntPtr)2: System.Console.Write("Case 2"); count++; if (count == 3) break; goto case (nint)2; } } } """; var expected1 = new[] { // (11,18): error CS0150: A constant value is expected // case (System.IntPtr)2: Diagnostic(ErrorCode.ERR_ConstantExpected, "(System.IntPtr)2").WithLocation(11, 18), // (16,17): error CS0159: No such label 'case 2:' within the scope of the goto statement // goto case (nint)2; Diagnostic(ErrorCode.ERR_LabelNotFound, "goto case (nint)2;").WithArguments("case 2:").WithLocation(16, 17), // (11,13): error CS8070: Control cannot fall out of switch from final case label ('case (System.IntPtr)2:') // case (System.IntPtr)2: Diagnostic(ErrorCode.ERR_SwitchFallOut, "case (System.IntPtr)2:").WithArguments("case (System.IntPtr)2:").WithLocation(11, 13) }; CreateCompilation(source).VerifyDiagnostics(expected1); CreateCompilation(source, parseOptions: TestOptions.Regular10).VerifyDiagnostics(expected1); CreateCompilation(source, parseOptions: TestOptions.Regular11).VerifyDiagnostics(expected1); CompileAndVerify(source, targetFramework: TargetFramework.Net100, expectedOutput: ExecutionConditionUtil.IsMonoOrCoreClr ? "Case 2Case 2Case 2" : null, verify: Verification.FailsPEVerify).VerifyDiagnostics(); CompileAndVerify(source, targetFramework: TargetFramework.Net100, parseOptions: TestOptions.Regular10, expectedOutput: ExecutionConditionUtil.IsMonoOrCoreClr ? "Case 2Case 2Case 2" : null, verify: Verification.FailsPEVerify).VerifyDiagnostics(); CompileAndVerify(source, targetFramework: TargetFramework.Net100, parseOptions: TestOptions.Regular11, expectedOutput: ExecutionConditionUtil.IsMonoOrCoreClr ? "Case 2Case 2Case 2" : null, verify: Verification.FailsPEVerify).VerifyDiagnostics(); } [Fact] [WorkItem("https://github.com/dotnet/roslyn/issues/81784")] public void GotoCase_08() { var source = $$$""" class Program { static void Main() { int count = 0; switch ((object)(nint)2) { case (int)2: break; case (System.IntPtr)2: System.Console.Write("Case 2"); count++; if (count == 3) break; goto case (System.IntPtr)2; } } } """; var expected1 = new[] { // (11,18): error CS0150: A constant value is expected // case (System.IntPtr)2: Diagnostic(ErrorCode.ERR_ConstantExpected, "(System.IntPtr)2").WithLocation(11, 18), // (16,17): error CS0150: A constant value is expected // goto case (System.IntPtr)2; Diagnostic(ErrorCode.ERR_ConstantExpected, "goto case (System.IntPtr)2;").WithLocation(16, 17), // (11,13): error CS8070: Control cannot fall out of switch from final case label ('case (System.IntPtr)2:') // case (System.IntPtr)2: Diagnostic(ErrorCode.ERR_SwitchFallOut, "case (System.IntPtr)2:").WithArguments("case (System.IntPtr)2:").WithLocation(11, 13) }; CreateCompilation(source).VerifyDiagnostics(expected1); CreateCompilation(source, parseOptions: TestOptions.Regular10).VerifyDiagnostics(expected1); CreateCompilation(source, parseOptions: TestOptions.Regular11).VerifyDiagnostics(expected1); CompileAndVerify(source, targetFramework: TargetFramework.Net100, expectedOutput: ExecutionConditionUtil.IsMonoOrCoreClr ? "Case 2Case 2Case 2" : null, verify: Verification.FailsPEVerify).VerifyDiagnostics(); CompileAndVerify(source, targetFramework: TargetFramework.Net100, parseOptions: TestOptions.Regular10, expectedOutput: ExecutionConditionUtil.IsMonoOrCoreClr ? "Case 2Case 2Case 2" : null, verify: Verification.FailsPEVerify).VerifyDiagnostics(); CompileAndVerify(source, targetFramework: TargetFramework.Net100, parseOptions: TestOptions.Regular11, expectedOutput: ExecutionConditionUtil.IsMonoOrCoreClr ? "Case 2Case 2Case 2" : null, verify: Verification.FailsPEVerify).VerifyDiagnostics(); } [Fact] [WorkItem("https://github.com/dotnet/roslyn/issues/81784")] public void GotoCase_09() { var source = $$$""" class Program { static void Main() { int count = 0; switch ((object)(nuint)2) { case (uint)2: break; case (nuint)2: System.Console.Write("Case 2"); count++; if (count == 3) break; goto case (System.UIntPtr)2; } } } """; var expected1 = new[] { // (16,17): error CS0150: A constant value is expected // goto case (System.UIntPtr)2; Diagnostic(ErrorCode.ERR_ConstantExpected, "goto case (System.UIntPtr)2;").WithLocation(16, 17), // (11,13): error CS8070: Control cannot fall out of switch from final case label ('case (nuint)2:') // case (nuint)2: Diagnostic(ErrorCode.ERR_SwitchFallOut, "case (nuint)2:").WithArguments("case (nuint)2:").WithLocation(11, 13) }; CreateCompilation(source).VerifyDiagnostics(expected1); CreateCompilation(source, parseOptions: TestOptions.Regular10).VerifyDiagnostics(expected1); CreateCompilation(source, parseOptions: TestOptions.Regular11).VerifyDiagnostics(expected1); CompileAndVerify(source, targetFramework: TargetFramework.Net100, expectedOutput: ExecutionConditionUtil.IsMonoOrCoreClr ? "Case 2Case 2Case 2" : null, verify: Verification.FailsPEVerify).VerifyDiagnostics(); CompileAndVerify(source, targetFramework: TargetFramework.Net100, parseOptions: TestOptions.Regular10, expectedOutput: ExecutionConditionUtil.IsMonoOrCoreClr ? "Case 2Case 2Case 2" : null, verify: Verification.FailsPEVerify).VerifyDiagnostics(); CompileAndVerify(source, targetFramework: TargetFramework.Net100, parseOptions: TestOptions.Regular11, expectedOutput: ExecutionConditionUtil.IsMonoOrCoreClr ? "Case 2Case 2Case 2" : null, verify: Verification.FailsPEVerify).VerifyDiagnostics(); } [Fact] [WorkItem("https://github.com/dotnet/roslyn/issues/81784")] public void GotoCase_10() { var source = $$$""" class Program { static void Main() { int count = 0; switch ((object)(nuint)2) { case (uint)2: break; case (System.UIntPtr)2: System.Console.Write("Case 2"); count++; if (count == 3) break; goto case (nuint)2; } } } """; var expected1 = new[] { // (11,18): error CS0150: A constant value is expected // case (System.UIntPtr)2: Diagnostic(ErrorCode.ERR_ConstantExpected, "(System.UIntPtr)2").WithLocation(11, 18), // (16,17): error CS0159: No such label 'case 2:' within the scope of the goto statement // goto case (nuint)2; Diagnostic(ErrorCode.ERR_LabelNotFound, "goto case (nuint)2;").WithArguments("case 2:").WithLocation(16, 17), // (11,13): error CS8070: Control cannot fall out of switch from final case label ('case (System.UIntPtr)2:') // case (System.UIntPtr)2: Diagnostic(ErrorCode.ERR_SwitchFallOut, "case (System.UIntPtr)2:").WithArguments("case (System.UIntPtr)2:").WithLocation(11, 13) }; CreateCompilation(source).VerifyDiagnostics(expected1); CreateCompilation(source, parseOptions: TestOptions.Regular10).VerifyDiagnostics(expected1); CreateCompilation(source, parseOptions: TestOptions.Regular11).VerifyDiagnostics(expected1); CompileAndVerify(source, targetFramework: TargetFramework.Net100, expectedOutput: ExecutionConditionUtil.IsMonoOrCoreClr ? "Case 2Case 2Case 2" : null, verify: Verification.FailsPEVerify).VerifyDiagnostics(); CompileAndVerify(source, targetFramework: TargetFramework.Net100, parseOptions: TestOptions.Regular10, expectedOutput: ExecutionConditionUtil.IsMonoOrCoreClr ? "Case 2Case 2Case 2" : null, verify: Verification.FailsPEVerify).VerifyDiagnostics(); CompileAndVerify(source, targetFramework: TargetFramework.Net100, parseOptions: TestOptions.Regular11, expectedOutput: ExecutionConditionUtil.IsMonoOrCoreClr ? "Case 2Case 2Case 2" : null, verify: Verification.FailsPEVerify).VerifyDiagnostics(); } [Fact] [WorkItem("https://github.com/dotnet/roslyn/issues/81784")] public void GotoCase_11() { var source = $$$""" class Program { static void Main() { int count = 0; switch ((object)(nuint)2) { case (uint)2: break; case (System.UIntPtr)2: System.Console.Write("Case 2"); count++; if (count == 3) break; goto case (System.UIntPtr)2; } } } """; var expected1 = new[] { // (11,18): error CS0150: A constant value is expected // case (System.UIntPtr)2: Diagnostic(ErrorCode.ERR_ConstantExpected, "(System.UIntPtr)2").WithLocation(11, 18), // (16,17): error CS0150: A constant value is expected // goto case (System.UIntPtr)2; Diagnostic(ErrorCode.ERR_ConstantExpected, "goto case (System.UIntPtr)2;").WithLocation(16, 17), // (11,13): error CS8070: Control cannot fall out of switch from final case label ('case (System.UIntPtr)2:') // case (System.UIntPtr)2: Diagnostic(ErrorCode.ERR_SwitchFallOut, "case (System.UIntPtr)2:").WithArguments("case (System.UIntPtr)2:").WithLocation(11, 13) }; CreateCompilation(source).VerifyDiagnostics(expected1); CreateCompilation(source, parseOptions: TestOptions.Regular10).VerifyDiagnostics(expected1); CreateCompilation(source, parseOptions: TestOptions.Regular11).VerifyDiagnostics(expected1); CompileAndVerify(source, targetFramework: TargetFramework.Net100, expectedOutput: ExecutionConditionUtil.IsMonoOrCoreClr ? "Case 2Case 2Case 2" : null, verify: Verification.FailsPEVerify).VerifyDiagnostics(); CompileAndVerify(source, targetFramework: TargetFramework.Net100, parseOptions: TestOptions.Regular10, expectedOutput: ExecutionConditionUtil.IsMonoOrCoreClr ? "Case 2Case 2Case 2" : null, verify: Verification.FailsPEVerify).VerifyDiagnostics(); CompileAndVerify(source, targetFramework: TargetFramework.Net100, parseOptions: TestOptions.Regular11, expectedOutput: ExecutionConditionUtil.IsMonoOrCoreClr ? "Case 2Case 2Case 2" : null, verify: Verification.FailsPEVerify).VerifyDiagnostics(); } } }