@@ -2360,6 +2360,160 @@ .maxstack 2
23602360");
23612361 }
23622362
2363+ [Fact]
2364+ public void UnionMatching_36_SwitchStatement()
2365+ {
2366+ var src = @"
2367+ struct S1 : System.Runtime.CompilerServices.IUnion
2368+ {
2369+ private readonly object _value;
2370+ public S1(int x) { _value = x; }
2371+ public S1(string x) { _value = x; }
2372+ object System.Runtime.CompilerServices.IUnion.Value => _value;
2373+ }
2374+
2375+ class Program
2376+ {
2377+ static void Main()
2378+ {
2379+ System.Console.Write(Test1(new S1(10)));
2380+ System.Console.Write(Test1(new S1(""10"")));
2381+ System.Console.Write(Test1(default));
2382+ System.Console.Write(Test1(new S1(11)));
2383+ System.Console.Write(Test1(new S1(""11"")));
2384+ System.Console.Write(Test1(new S1(0)));
2385+ }
2386+
2387+ static int Test1(S1 u)
2388+ {
2389+ switch (u)
2390+ {
2391+ case 10: return 1;
2392+ case ""11"": return 2;
2393+ }
2394+
2395+ return -1;
2396+ }
2397+ }
2398+ ";
2399+ var comp = CreateCompilation([src, IUnionSource], options: TestOptions.ReleaseExe);
2400+ CompileAndVerify(comp, expectedOutput: "1-1-1-12-1").VerifyDiagnostics();
2401+ }
2402+
2403+ [Fact]
2404+ public void UnionMatching_37_SwitchStatement()
2405+ {
2406+ var src = @"
2407+ struct S1 : System.Runtime.CompilerServices.IUnion
2408+ {
2409+ private readonly object _value;
2410+ public S1(int x) { _value = x; }
2411+ public S1(string x) { _value = x; }
2412+ object System.Runtime.CompilerServices.IUnion.Value => _value;
2413+ }
2414+
2415+ class Program
2416+ {
2417+ static void Main()
2418+ {
2419+ System.Console.Write(Test1(new S1(10)));
2420+ System.Console.Write(Test1(new S1(""10"")));
2421+ System.Console.Write(Test1(default));
2422+ System.Console.Write(Test1(new S1(11)));
2423+ System.Console.Write(Test1(new S1(""11"")));
2424+ System.Console.Write(Test1(new S1(0)));
2425+ }
2426+
2427+ static int Test1(S1 u)
2428+ {
2429+ switch (u)
2430+ {
2431+ case 10: goto case 44;
2432+ case ""11"": goto case ""55"";
2433+ case 44: return 44;
2434+ case ""55"": return 55;
2435+ }
2436+
2437+ return -1;
2438+ }
2439+ }
2440+ ";
2441+ var comp = CreateCompilation([src, IUnionSource], options: TestOptions.ReleaseExe);
2442+ CompileAndVerify(comp, expectedOutput: "44-1-1-155-1").VerifyDiagnostics();
2443+ }
2444+
2445+ [Fact]
2446+ public void UnionMatching_38_SwitchStatement()
2447+ {
2448+ var src = @"
2449+ struct S1 : System.Runtime.CompilerServices.IUnion
2450+ {
2451+ private readonly object _value;
2452+ public S1(int x) { _value = x; }
2453+ public S1(string x) { _value = x; }
2454+ object System.Runtime.CompilerServices.IUnion.Value => _value;
2455+ }
2456+
2457+ class Program
2458+ {
2459+ static int Test1(S1 u)
2460+ {
2461+ switch (u)
2462+ {
2463+ case 10: return 1;
2464+ case ""11"": return 2;
2465+ case true: return 3;
2466+ }
2467+
2468+ return -1;
2469+ }
2470+ }
2471+ ";
2472+ var comp = CreateCompilation([src, IUnionSource]);
2473+ comp.VerifyDiagnostics(
2474+ // (18,18): error CS8121: An expression of type 'S1' cannot be handled by a pattern of type 'bool'.
2475+ // case true: return 3;
2476+ Diagnostic(ErrorCode.ERR_PatternWrongType, "true").WithArguments("S1", "bool").WithLocation(18, 18)
2477+ );
2478+ }
2479+
2480+ [Fact]
2481+ public void UnionMatching_39_SwitchStatement()
2482+ {
2483+ var src = @"
2484+ struct S1 : System.Runtime.CompilerServices.IUnion
2485+ {
2486+ private readonly object _value;
2487+ public S1(int x) { _value = x; }
2488+ public S1(string x) { _value = x; }
2489+ object System.Runtime.CompilerServices.IUnion.Value => _value;
2490+ }
2491+
2492+ class Program
2493+ {
2494+ static int Test1(S1 u)
2495+ {
2496+ switch (u)
2497+ {
2498+ case 10: goto case true;
2499+ case ""11"": return 2;
2500+ }
2501+
2502+ return -1;
2503+ }
2504+ }
2505+ ";
2506+ var comp = CreateCompilation([src, IUnionSource]);
2507+ comp.VerifyDiagnostics(
2508+ // (16,13): error CS0163: Control cannot fall through from one case label ('case 10:') to another
2509+ // case 10: goto case true;
2510+ Diagnostic(ErrorCode.ERR_SwitchFallThrough, "case 10:").WithArguments("case 10:").WithLocation(16, 13),
2511+ // (16,22): error CS0029: Cannot implicitly convert type 'bool' to 'S1'
2512+ // case 10: goto case true;
2513+ Diagnostic(ErrorCode.ERR_NoImplicitConv, "goto case true;").WithArguments("bool", "S1").WithLocation(16, 22)
2514+ );
2515+ }
2516+
23632517 [Fact]
23642518 public void PatternWrongType_TypePattern_01_BindConstantPatternWithFallbackToTypePattern_UnionType_Out_UnionType_In()
23652519 {
@@ -3148,7 +3302,8 @@ static void Test1(S1 u)
31483302 // case 1:
31493303 Diagnostic(ErrorCode.ERR_SwitchFallOut, "case 1:").WithArguments("case 1:").WithLocation(102, 13),
31503304
3151- // PROTOTYPE: This doesn't look like a union matching error. Something is likely missing in implementation.
3305+ // The following error is expected per language specification (https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/statements.md#13104-the-goto-statement):
3306+ // "if the constant_expression is not implicitly convertible (§10.2) to the governing type of the nearest enclosing switch statement, a compile-time error occurs."
31523307
31533308 // (103,17): error CS0029: Cannot implicitly convert type 'string' to 'S1'
31543309 // goto case empty;
@@ -5222,8 +5377,6 @@ static S1 Test1(int? x)
52225377";
52235378 var comp = CreateCompilation([src, IUnionSource]);
52245379
5225- // PROTOTYPE: Confirm that there are no lifted forms.
5226-
52275380 comp.VerifyDiagnostics(
52285381 // (20,16): error CS0029: Cannot implicitly convert type 'int?' to 'S1'
52295382 // return x;
@@ -5781,11 +5934,6 @@ static S1 Test2(System.ValueType x)
57815934 var comp = CreateCompilation([src, IUnionSource], options: TestOptions.ReleaseExe);
57825935 var verifier = CompileAndVerify(comp, expectedOutput: "System.ValueType S1").VerifyDiagnostics();
57835936
5784- // PROTOTYPE: Confirm that we are fine with this conversion behavior. See previous test as well.
5785- // Cast performs unboxing conversion, but implicit conversion performs union conversion.
5786- // Might be too confusing.
5787- // Note, language disallows user-defined conversions like that, see errors below.
5788-
57895937 verifier.VerifyIL("Program.Test2", @"
57905938{
57915939 // Code size 7 (0x7)
@@ -5889,11 +6037,6 @@ static S1 Test2(I1 x)
58896037 var comp = CreateCompilation([src, IUnionSource], options: TestOptions.ReleaseExe);
58906038 var verifier = CompileAndVerify(comp, expectedOutput: "I1 S1").VerifyDiagnostics();
58916039
5892- // PROTOTYPE: Confirm that we are fine with this conversion behavior. See previous test as well.
5893- // Cast performs unboxing conversion, but implicit conversion performs union conversion.
5894- // Might be too confusing.
5895- // Note, language disallows user-defined conversions like that, see errors below.
5896-
58976040 verifier.VerifyIL("Program.Test2", @"
58986041{
58996042 // Code size 7 (0x7)
@@ -5968,10 +6111,6 @@ static S1 Test2(I1 x)
59686111 var comp = CreateCompilation([src, IUnionSource], options: TestOptions.ReleaseExe);
59696112 var verifier = CompileAndVerify(comp, expectedOutput: "I1 S1 I1 S1").VerifyDiagnostics();
59706113
5971- // PROTOTYPE: Confirm that we are fine with this conversion behavior.
5972- // Might be too confusing.
5973- // Note, language disallows user-defined conversions like that, see errors below.
5974-
59756114 verifier.VerifyIL("Program.Test1", @"
59766115{
59776116 // Code size 7 (0x7)
@@ -6054,11 +6193,6 @@ static S1 Test2(I1 x)
60546193 var comp = CreateCompilation([src, IUnionSource], options: TestOptions.ReleaseExe);
60556194 var verifier = CompileAndVerify(comp, expectedOutput: "I1 S1").VerifyDiagnostics();
60566195
6057- // PROTOTYPE: Confirm that we are fine with this conversion behavior.
6058- // Cast performs castclass conversion, but implicit conversion performs union conversion.
6059- // Might be too confusing.
6060- // Note, language disallows user-defined conversions like that, see errors below.
6061-
60626196 verifier.VerifyIL("Program.Test1", @"
60636197{
60646198 // Code size 7 (0x7)
0 commit comments