/
githubmirror
/
roslyn
Обзор
Документация
Войти
/
githubmirror
/
roslyn
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
src/Compilers/CSharp/Test/CSharp15/UnionsTests.cs
61 049 строк
2 MB
Fred Silberberg
Add C# 15 language version (#84799)
11 авг 2026, 23:51
Не верифицирован
11 авг 2026, 23:51
1284a4a
Код
Авторство
О чём код?
// 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.Collections.Immutable; using System.Linq; using System.Threading; using Microsoft.CodeAnalysis.CSharp.Symbols; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.CSharp.Test.Utilities; using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.Operations; using Microsoft.CodeAnalysis.Test.Utilities; using Roslyn.Test.Utilities; using Xunit; namespace Microsoft.CodeAnalysis.CSharp.UnitTests { public class UnionsTests : CSharpTestBase { [Fact] public void UnionType_01() { var src = @" [System.Runtime.CompilerServices.Union] public interface IUnion { #nullable enable object? Value { get; } #nullable disable } [System.Runtime.CompilerServices.Union] interface I1; [System.Runtime.CompilerServices.Union] struct S1 { public S1(int x) {} public object Value => null; } struct S2 : IUnion { public object Value => null; } [System.Runtime.CompilerServices.Union] class C1 { public C1(int x) {} public object Value => null; } [System.Runtime.CompilerServices.Union] sealed class C2 { public C2(int x) {} public object Value => null; } sealed class C3 : IUnion { public object Value => null; } sealed class C4 : C1 { public C4() : base(0) {} } "; var comp = CreateCompilation([src, UnionAttributeSource]); comp.VerifyEmitDiagnostics(); NamedTypeSymbol s1 = comp.GetTypeByMetadataName("S1"); Assert.True(s1.IsUnionType); Assert.True(s1.GetPublicSymbol().IsUnion); AssertEx.SequenceEqual(["System.Int32"], s1.GetPublicSymbol().UnionCaseTypes.ToTestDisplayStrings()); Assert.True(comp.GetTypeByMetadataName("C1").IsUnionType); Assert.True(comp.GetTypeByMetadataName("C2").IsUnionType); Assert.False(comp.GetTypeByMetadataName("C4").IsUnionType); NamedTypeSymbol i1 = comp.GetTypeByMetadataName("I1"); Assert.False(i1.IsUnionType); Assert.False(i1.GetPublicSymbol().IsUnion); Assert.Empty(i1.GetPublicSymbol().UnionCaseTypes); Assert.False(comp.GetTypeByMetadataName("S2").IsUnionType); Assert.False(comp.GetTypeByMetadataName("C3").IsUnionType); var vbComp = CreateVisualBasicCompilation("", referencedAssemblies: TargetFrameworkUtil.GetReferences(TargetFramework.Standard).Concat(comp.EmitToImageReference())); INamedTypeSymbol s1VB = vbComp.GetTypeByMetadataName("S1"); Assert.False(s1VB.IsUnion); Assert.Empty(s1VB.UnionCaseTypes); INamedTypeSymbol i1VB = vbComp.GetTypeByMetadataName("I1"); Assert.False(i1VB.IsUnion); Assert.Empty(i1VB.UnionCaseTypes); } [Fact] public void UnionType_02_UnionNotPublic() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 { public S1(int x) {} public object Value => null; } namespace System.Runtime.CompilerServices { public class UnionAttribute : System.Attribute { } } "; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics(); Assert.True(comp.GetTypeByMetadataName("S1").IsUnionType); } [Fact] public void UnionType_03_ManyUnionAttributeTypes() { var src1 = @" [System.Runtime.CompilerServices.Union] public struct S1 { public S1(int x) {} public object Value => null; } "; var comp1 = CreateCompilation([src1, UnionAttributeSource]); comp1.VerifyEmitDiagnostics(); Assert.True(comp1.GetTypeByMetadataName("S1").IsUnionType); var src2 = @" #pragma warning disable CS0436 // The type 'UnionAttribute' in '' conflicts with the imported type 'UnionAttribute' ... [System.Runtime.CompilerServices.Union] struct S2 { public S2(int x) {} public object Value => null; } "; var comp2 = CreateCompilation([src2, UnionAttributeSource], references: [comp1.EmitToImageReference()]); comp2.VerifyEmitDiagnostics(); Assert.True(comp2.GetTypeByMetadataName("S1").IsUnionType); Assert.True(comp2.GetTypeByMetadataName("S2").IsUnionType); } [Fact] public void CaseTypes_01() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 { public object Value => null; } [System.Runtime.CompilerServices.Union] struct S2 { public S2(int x){} public S2(string x){} public object Value => null; } [System.Runtime.CompilerServices.Union] struct S3 { private S3(int x){} internal S3(string x){} public object Value => null; } [System.Runtime.CompilerServices.Union] struct S4 { public S4(int x, string y){} public object Value => null; } [System.Runtime.CompilerServices.Union] class C5 { protected C5(int x){} protected internal C5(string x){} private protected C5(decimal x){} public object Value => null; } "; var comp = CreateCompilation([src, UnionAttributeSource]); comp.VerifyEmitDiagnostics( // (3,8): error CS9385: A union type must have at least one union creation member. // struct S1 Diagnostic(ErrorCode.ERR_MissingUnionCaseTypes, "S1").WithLocation(3, 8), // (17,8): error CS9385: A union type must have at least one union creation member. // struct S3 Diagnostic(ErrorCode.ERR_MissingUnionCaseTypes, "S3").WithLocation(17, 8), // (25,8): error CS9385: A union type must have at least one union creation member. // struct S4 Diagnostic(ErrorCode.ERR_MissingUnionCaseTypes, "S4").WithLocation(25, 8), // (32,7): error CS9385: A union type must have at least one union creation member. // class C5 Diagnostic(ErrorCode.ERR_MissingUnionCaseTypes, "C5").WithLocation(32, 7) ); VerifyCaseTypes(comp, "S1", []); VerifyCaseTypes(comp, "S2", ["System.Int32", "System.String"]); VerifyCaseTypes(comp, "S3", []); VerifyCaseTypes(comp, "S4", []); VerifyCaseTypes(comp, "C5", []); } private static void VerifyCaseTypes(CSharpCompilation comp, string typeName, string[] caseTypes) { VerifyCaseTypes(comp, typeName, [], caseTypes); } private static void VerifyCaseTypes(CSharpCompilation comp, string typeName, string[] typeArguments, string[] caseTypes) { var type = comp.GetTypeByMetadataName(typeName); if (typeArguments is [_, ..]) { var typeArgs = typeArguments.Select(t => comp.GetTypeByMetadataName(t)).ToArray(); type = type.Construct(typeArgs); } Assert.True(type.IsUnionType); AssertEx.SequenceEqual(caseTypes, type.UnionCaseTypesNoUseSiteDiagnostics.ToTestDisplayStrings()); } [Fact] public void CaseTypes_02() { var src = @" [System.Runtime.CompilerServices.Union] #line 2 struct S2 { public static S2(int x){} public object Value => null; } "; var comp = CreateCompilation([src, UnionAttributeSource]); comp.VerifyDiagnostics( // (2,8): error CS9385: A union type must have at least one union creation member. // struct S2 Diagnostic(ErrorCode.ERR_MissingUnionCaseTypes, "S2").WithLocation(2, 8), // (4,19): error CS0515: 'S2.S2(int)': access modifiers are not allowed on static constructors // public static S2(int x){} Diagnostic(ErrorCode.ERR_StaticConstructorWithAccessModifiers, "S2").WithArguments("S2.S2(int)").WithLocation(4, 19), // (4,19): error CS0132: 'S2.S2(int)': a static constructor must be parameterless // public static S2(int x){} Diagnostic(ErrorCode.ERR_StaticConstParam, "S2").WithArguments("S2.S2(int)").WithLocation(4, 19) ); VerifyCaseTypes(comp, "S2", []); } [Fact] public void CaseTypes_03() { var src = @" struct S2 : S2.IUnionMembers { public S2(int x){} public S2(string x){} public object Value => null; public interface IUnionMembers { public static S2 Create(long x) => throw null; } } "; var comp = CreateCompilation(src, targetFramework: TargetFramework.NetCoreApp); comp.VerifyEmitDiagnostics(); var type = comp.GetTypeByMetadataName("S2"); Assert.False(type.IsUnionType); AssertEx.SequenceEqual([], type.UnionCaseTypesNoUseSiteDiagnostics.ToTestDisplayStrings()); } [Fact] public void CaseTypes_04() { var src = @" [System.Runtime.CompilerServices.Union] class C1 { public C1(int x){} public object Value => null; } [System.Runtime.CompilerServices.Union] sealed class C2 : C1 { public C2(string x) : base(0) {} public new object Value => null; } class C3 { public C3(int x){} } [System.Runtime.CompilerServices.Union] sealed class C4 : C3 { public C4(string x) : base(0) {} public object Value => null; } sealed class C5 : C1 { public C5(string x) : base(0) {} } "; var comp = CreateCompilation([src, UnionAttributeSource]); comp.VerifyEmitDiagnostics(); VerifyCaseTypes(comp, "C1", ["System.Int32"]); VerifyCaseTypes(comp, "C2", ["System.String"]); VerifyCaseTypes(comp, "C4", ["System.String"]); var c5 = comp.GetTypeByMetadataName("C5"); Assert.False(c5.IsUnionType); AssertEx.SequenceEqual([], c5.UnionCaseTypesNoUseSiteDiagnostics.ToTestDisplayStrings()); } [Fact] public void CaseTypes_05() { var src = @" #nullable enable [System.Runtime.CompilerServices.Union] struct S2 { public S2(string?[] x){} #line 6 public S2(string[] x){} public S2((int a, int b) x){} public S2((int, int) x){} public object Value => null!; } "; var comp = CreateCompilation([src, UnionAttributeSource]); comp.VerifyDiagnostics( // (6,12): error CS0111: Type 'S2' already defines a member called 'S2' with the same parameter types // public S2(string? x){} Diagnostic(ErrorCode.ERR_MemberAlreadyExists, "S2").WithArguments("S2", "S2").WithLocation(6, 12), // (8,12): error CS0111: Type 'S2' already defines a member called 'S2' with the same parameter types // public S2((int, int) x){} Diagnostic(ErrorCode.ERR_MemberAlreadyExists, "S2").WithArguments("S2", "S2").WithLocation(8, 12) ); VerifyCaseTypes(comp, "S2", ["System.String?[]", "(System.Int32 a, System.Int32 b)"]); } [Fact] public void CaseTypes_06() { var src = @" #nullable enable [System.Runtime.CompilerServices.Union] struct S1 { public S1(int? x){} public S1(string? x){} public object? Value => null; } "; var comp = CreateCompilation([src, UnionAttributeSource]); comp.VerifyEmitDiagnostics(); VerifyCaseTypes(comp, "S1", ["System.Int32?", "System.String"]); } [Fact] public void CaseTypes_07_MemberProvider() { var src = @" [System.Runtime.CompilerServices.Union] struct S2 : S2.IUnionMembers { public S2(byte x){} public interface IUnionMembers { public static S2 Create(int x) => throw null; public static virtual S2 Create(string x) => throw null; public static abstract S2 Create(long x); public object Value { get; } } public static S2 Create(long x) => throw null; object IUnionMembers.Value => throw null; } "; var comp = CreateCompilation([src, UnionAttributeSource], targetFramework: TargetFramework.NetCoreApp); comp.VerifyEmitDiagnostics(); VerifyCaseTypes(comp, "S2", ["System.Int32", "System.String", "System.Int64"]); } [Fact] public void CaseTypes_08_MemberProvider() { var src = @" [System.Runtime.CompilerServices.Union] #line 3 struct S1 : S1.IUnionMembers { public S1(byte x){} public interface IUnionMembers { public object Value { get; } } object IUnionMembers.Value => throw null; } [System.Runtime.CompilerServices.Union] #line 12 struct S3 : S3.IUnionMembers { public S3(byte x){} public interface IUnionMembers { private static S3 Create(int x) => throw null; internal static S3 Create(string x) => throw null; public object Value { get; } } object IUnionMembers.Value => throw null; } [System.Runtime.CompilerServices.Union] #line 24 struct S4 : S4.IUnionMembers { public S4(byte y){} public interface IUnionMembers { public static S4 Create(int x, string y) => throw null; public object Value { get; } } object IUnionMembers.Value => throw null; } [System.Runtime.CompilerServices.Union] #line 35 class C5 : C5.IUnionMembers { public C5(int x){} public interface IUnionMembers { protected static C5 Create(int x) => throw null; protected internal static C5 Create(string x) => throw null; private protected static C5 Create(decimal x) => throw null; public object Value { get; } } object IUnionMembers.Value => throw null; } "; var comp = CreateCompilation([src, UnionAttributeSource], targetFramework: TargetFramework.NetCoreApp); comp.VerifyEmitDiagnostics( // (3,8): error CS9385: A union type must have at least one union creation member. // struct S1 : S1.IUnionMembers Diagnostic(ErrorCode.ERR_MissingUnionCaseTypes, "S1").WithLocation(3, 8), // (12,8): error CS9385: A union type must have at least one union creation member. // struct S3 : S3.IUnionMembers Diagnostic(ErrorCode.ERR_MissingUnionCaseTypes, "S3").WithLocation(12, 8), // (24,8): error CS9385: A union type must have at least one union creation member. // struct S4 : S4.IUnionMembers Diagnostic(ErrorCode.ERR_MissingUnionCaseTypes, "S4").WithLocation(24, 8), // (35,7): error CS9385: A union type must have at least one union creation member. // class C5 : C5.IUnionMembers Diagnostic(ErrorCode.ERR_MissingUnionCaseTypes, "C5").WithLocation(35, 7) ); VerifyCaseTypes(comp, "S1", []); VerifyCaseTypes(comp, "S3", []); VerifyCaseTypes(comp, "S4", []); VerifyCaseTypes(comp, "C5", []); } [Fact] public void CaseTypes_09_MemberProvider_Generic() { var src = @" [System.Runtime.CompilerServices.Union] struct S2 : S2.IUnionMembers<string> { public S2(byte x){} public object Value => throw null; public interface IUnionMembers<T> { public static S2 Create(int x) => throw null; public static S2 Create(T x) => throw null; } } [System.Runtime.CompilerServices.Union] struct S3 : S3.IUnionMembers { public S3(byte x){} object IUnionMembers.Value => throw null; public interface IUnionMembers<T>; public interface IUnionMembers { public static S3 Create(int x) => throw null; public static S3 Create(string x) => throw null; public object Value { get; } } public interface IUnionMembers<T, S>; } "; var comp = CreateCompilation([src, UnionAttributeSource], targetFramework: TargetFramework.NetCoreApp); comp.VerifyEmitDiagnostics(); VerifyCaseTypes(comp, "S2", ["System.Byte"]); VerifyCaseTypes(comp, "S3", ["System.Int32", "System.String"]); } [Fact] public void CaseTypes_10_MemberProvider_InGenericUnion() { var src = @" [System.Runtime.CompilerServices.Union] struct S2<T> : S2<T>.IUnionMembers { public S2(byte x){} object IUnionMembers.Value => throw null; public interface IUnionMembers { public static S2<T> Create(int x) => throw null; public static S2<T> Create(T x) => throw null; public object Value { get; } } } "; var comp = CreateCompilation([src, UnionAttributeSource], targetFramework: TargetFramework.NetCoreApp); comp.VerifyEmitDiagnostics(); VerifyCaseTypes(comp, "S2`1", ["System.Int32", "T"]); VerifyCaseTypes(comp, "S2`1", ["System.String"], ["System.Int32", "System.String"]); } [Fact] public void CaseTypes_11_MemberProvider_WrongGenericSubstitution() { var src = @" [System.Runtime.CompilerServices.Union] struct S2<T> : S2<string>.IUnionMembers { public S2(byte x){} public object Value => throw null; public interface IUnionMembers { public static S2<T> Create(int x) => throw null; public static S2<T> Create(T x) => throw null; } } "; var comp = CreateCompilation([src, UnionAttributeSource], targetFramework: TargetFramework.NetCoreApp); comp.VerifyEmitDiagnostics(); VerifyCaseTypes(comp, "S2`1", ["System.Byte"]); VerifyCaseTypes(comp, "S2`1", ["System.String"], ["System.Byte"]); } [Theory] [CombinatorialData] public void CaseTypes_12_MemberProvider_NotPublic([CombinatorialValues("", "private", "internal", "protected", "internal protected", "private protected")] string accessibility) { var src = @" [System.Runtime.CompilerServices.Union] class S2 : S2.IUnionMembers { public S2(byte x){} public object Value => throw null; " + accessibility + @" interface IUnionMembers { public static S2 Create(int x) => throw null; public static S2 Create(string x) => throw null; } } "; var comp = CreateCompilation([src, UnionAttributeSource], targetFramework: TargetFramework.NetCoreApp); comp.VerifyEmitDiagnostics(); VerifyCaseTypes(comp, "S2", ["System.Byte"]); } [Fact] public void CaseTypes_13_MemberProvider_WrongReturnType() { var src = @" [System.Runtime.CompilerServices.Union] struct S2 : S2.IUnionMembers { public S2(byte x){} public interface IUnionMembers { public static int Create(int x) => throw null; public static void Create(string x) => throw null; public object Value { get; } } object IUnionMembers.Value => throw null; } "; var comp = CreateCompilation([src, UnionAttributeSource], targetFramework: TargetFramework.NetCoreApp); comp.VerifyEmitDiagnostics( // (3,8): error CS9385: A union type must have at least one union creation member. // struct S2 : S2.IUnionMembers Diagnostic(ErrorCode.ERR_MissingUnionCaseTypes, "S2").WithLocation(3, 8) ); VerifyCaseTypes(comp, "S2", []); } [Fact] public void CaseTypes_14_MemberProvider_WrongReturnType() { var src = @" [System.Runtime.CompilerServices.Union] struct S2<T> : S2<T>.IUnionMembers { public S2(byte x){} public interface IUnionMembers { public static S2<T> Create(int x) => throw null; public static S2<string> Create(T x) => throw null; public object Value { get; } } object IUnionMembers.Value => throw null; } "; var comp = CreateCompilation([src, UnionAttributeSource], targetFramework: TargetFramework.NetCoreApp); comp.VerifyEmitDiagnostics(); VerifyCaseTypes(comp, "S2`1", ["System.Int32"]); VerifyCaseTypes(comp, "S2`1", ["System.String"], ["System.Int32"]); } [Fact] public void CaseTypes_15_MemberProvider_WrongReturnRefKind() { var src = @" [System.Runtime.CompilerServices.Union] struct S2 : S2.IUnionMembers { public S2(byte x){} public interface IUnionMembers { public static ref S2 Create(int x) => throw null; public static ref S2 Create(string x) => throw null; public object Value { get; } } object IUnionMembers.Value => throw null; } "; var comp = CreateCompilation([src, UnionAttributeSource], targetFramework: TargetFramework.NetCoreApp); comp.VerifyEmitDiagnostics( // (3,8): error CS9385: A union type must have at least one union creation member. // struct S2 : S2.IUnionMembers Diagnostic(ErrorCode.ERR_MissingUnionCaseTypes, "S2").WithLocation(3, 8) ); VerifyCaseTypes(comp, "S2", []); } [Fact] public void CaseTypes_16_MemberProvider_NotStatic() { var src = @" [System.Runtime.CompilerServices.Union] struct S2 : S2.IUnionMembers { public S2(byte x){} public interface IUnionMembers { public S2 Create(int x) => throw null; public virtual S2 Create(string x) => throw null; public abstract S2 Create(byte x); public object Value { get; } } object IUnionMembers.Value => throw null; public S2 Create(byte x) => throw null; } "; var comp = CreateCompilation([src, UnionAttributeSource], targetFramework: TargetFramework.NetCoreApp); comp.VerifyEmitDiagnostics( // (3,8): error CS9385: A union type must have at least one union creation member. // struct S2 : S2.IUnionMembers Diagnostic(ErrorCode.ERR_MissingUnionCaseTypes, "S2").WithLocation(3, 8) ); VerifyCaseTypes(comp, "S2", []); } [Fact] public void CaseTypes_17_MemberProvider_NotInterface() { var src = @" [System.Runtime.CompilerServices.Union] struct S2 : S2.IUnionMembers { public S2(byte x){} public object Value => throw null; public class IUnionMembers { public static S2 Create(int x) => throw null; } } "; var comp = CreateCompilation([src, UnionAttributeSource], targetFramework: TargetFramework.NetCoreApp); comp.VerifyEmitDiagnostics( // (3,13): error CS0527: Type 'S2.IUnionMembers' in interface list is not an interface // struct S2 : S2.IUnionMembers Diagnostic(ErrorCode.ERR_NonInterfaceInInterfaceList, "S2.IUnionMembers").WithArguments("S2.IUnionMembers").WithLocation(3, 13) ); VerifyCaseTypes(comp, "S2", ["System.Byte"]); } [Fact] public void CaseTypes_18_MemberProvider_NotInterface() { var src = @" [System.Runtime.CompilerServices.Union] struct S2 : S2.IUnionMembers { public S2(byte x){} public object Value => throw null; public struct IUnionMembers { public static S2 Create(int x) => throw null; } } "; var comp = CreateCompilation([src, UnionAttributeSource], targetFramework: TargetFramework.NetCoreApp); comp.VerifyEmitDiagnostics( // (3,13): error CS0527: Type 'S2.IUnionMembers' in interface list is not an interface // struct S2 : S2.IUnionMembers Diagnostic(ErrorCode.ERR_NonInterfaceInInterfaceList, "S2.IUnionMembers").WithArguments("S2.IUnionMembers").WithLocation(3, 13) ); VerifyCaseTypes(comp, "S2", ["System.Byte"]); } [Fact] public void CaseTypes_19_MemberProvider_NotInterface() { var src = @" [System.Runtime.CompilerServices.Union] struct S2 : S2.IUnionMembers { public S2(byte x){} public object Value => throw null; public enum IUnionMembers { } } "; var comp = CreateCompilation([src, UnionAttributeSource], targetFramework: TargetFramework.NetCoreApp); comp.VerifyEmitDiagnostics( // (3,13): error CS0527: Type 'S2.IUnionMembers' in interface list is not an interface // struct S2 : S2.IUnionMembers Diagnostic(ErrorCode.ERR_NonInterfaceInInterfaceList, "S2.IUnionMembers").WithArguments("S2.IUnionMembers").WithLocation(3, 13) ); VerifyCaseTypes(comp, "S2", ["System.Byte"]); } [Fact] public void CaseTypes_20_MemberProvider_NotInterface() { var src = @" [System.Runtime.CompilerServices.Union] struct S2 : S2.IUnionMembers { public S2(byte x){} public object Value => throw null; public delegate void IUnionMembers(); } "; var comp = CreateCompilation([src, UnionAttributeSource], targetFramework: TargetFramework.NetCoreApp); comp.VerifyEmitDiagnostics( // (3,13): error CS0527: Type 'S2.IUnionMembers' in interface list is not an interface // struct S2 : S2.IUnionMembers Diagnostic(ErrorCode.ERR_NonInterfaceInInterfaceList, "S2.IUnionMembers").WithArguments("S2.IUnionMembers").WithLocation(3, 13) ); VerifyCaseTypes(comp, "S2", ["System.Byte"]); } [Fact] public void CaseTypes_21_MemberProvider_NotImplemented() { var src = @" [System.Runtime.CompilerServices.Union] struct S2 { public S2(byte x){} public object Value => throw null; public interface IUnionMembers { public static S2 Create(int x) => throw null; } } "; var comp = CreateCompilation([src, UnionAttributeSource], targetFramework: TargetFramework.NetCoreApp); comp.VerifyEmitDiagnostics(); VerifyCaseTypes(comp, "S2", ["System.Byte"]); } [Fact] public void CaseTypes_22_MemberProvider_ImplementedIndirectly() { var src = @" [System.Runtime.CompilerServices.Union] struct S2 : I1 { public S2(byte x){} public interface IUnionMembers { public static S2 Create(int x) => throw null; public static virtual S2 Create(string x) => throw null; public static abstract S2 Create(byte x); public object Value { get; } } object IUnionMembers.Value => throw null; public static S2 Create(byte x) => throw null; } interface I1 : S2.IUnionMembers; "; var comp = CreateCompilation([src, UnionAttributeSource], targetFramework: TargetFramework.NetCoreApp); comp.VerifyEmitDiagnostics(); VerifyCaseTypes(comp, "S2", ["System.Int32", "System.String", "System.Byte"]); } [Fact] public void CaseTypes_23_MemberProvider_ImplementedIndirectly() { var src = @" [System.Runtime.CompilerServices.Union] class S2 : S1 { public S2(byte x){} public interface IUnionMembers { public static S2 Create(int x) => throw null; public static virtual S2 Create(string x) => throw null; public static abstract S2 Create(byte x); public object Value { get; } } } class S1 : S2.IUnionMembers { public static S2 Create(byte x) => throw null; object S2.IUnionMembers.Value => throw null; } "; var comp = CreateCompilation([src, UnionAttributeSource], targetFramework: TargetFramework.NetCoreApp); comp.VerifyEmitDiagnostics(); VerifyCaseTypes(comp, "S2", ["System.Int32", "System.String", "System.Byte"]); } [Fact] public void CaseTypes_24_MemberProvider_NotNested() { var src = @" [System.Runtime.CompilerServices.Union] public struct S2 : IUnionMembers { public S2(byte x){} public object Value => throw null; } public interface IUnionMembers { public static S2 Create(int x) => throw null; } "; var comp = CreateCompilation([src, UnionAttributeSource], targetFramework: TargetFramework.NetCoreApp); comp.VerifyEmitDiagnostics(); VerifyCaseTypes(comp, "S2", ["System.Byte"]); } [Fact] public void CaseTypes_25_MemberProvider_NotNested() { var src = @" [System.Runtime.CompilerServices.Union] class S2 : S1, S1.IUnionMembers { public S2(byte x){} public object Value => throw null; } class S1 : S1.IUnionMembers { public interface IUnionMembers { public static S2 Create(int x) => throw null; } } "; var comp = CreateCompilation([src, UnionAttributeSource], targetFramework: TargetFramework.NetCoreApp); comp.VerifyEmitDiagnostics(); VerifyCaseTypes(comp, "S2", ["System.Byte"]); } [Fact] public void CaseTypes_26_MemberProvider_NotNested() { var src = @" [System.Runtime.CompilerServices.Union] struct S2 : S2.C.IUnionMembers { public S2(byte x){} public object Value => throw null; public class C { public interface IUnionMembers { public static S2 Create(int x) => throw null; } } } "; var comp = CreateCompilation([src, UnionAttributeSource], targetFramework: TargetFramework.NetCoreApp); comp.VerifyEmitDiagnostics(); VerifyCaseTypes(comp, "S2", ["System.Byte"]); } [Fact] public void CaseTypes_27_MemberProvider_NoDefaultInterfaceMembersSupport() { var src = @" [System.Runtime.CompilerServices.Union] struct S2 : S2.IUnionMembers { public S2(byte x){} public interface IUnionMembers { public static S2 Create(int x) => throw null; public object Value { get; } } object IUnionMembers.Value => throw null; public static S2 Create(long x) => throw null; } "; var comp = CreateCompilation([src, UnionAttributeSource], targetFramework: TargetFramework.NetFramework); comp.VerifyEmitDiagnostics(); VerifyCaseTypes(comp, "S2", ["System.Int32"]); } [Fact] public void CaseTypes_28_MemberProvider() { var src = @" #nullable enable [System.Runtime.CompilerServices.Union] struct S2 : S2.IUnionMembers { public S2(byte x){} public interface IUnionMembers { public static S2 Create(int x) => throw null!; public static S2 Create(int? x) => throw null!; public static S2 Create(long? x) => throw null!; public static S2 Create(string? x) => throw null!; public object Value { get; } } object IUnionMembers.Value => throw null!; } "; var comp = CreateCompilation([src, UnionAttributeSource], targetFramework: TargetFramework.NetCoreApp); comp.VerifyEmitDiagnostics(); VerifyCaseTypes(comp, "S2", ["System.Int32", "System.Int32?", "System.Int64?", "System.String"]); } [Fact] public void CaseTypes_29_MemberProvider_ParameterRefKind() { var src = @" [System.Runtime.CompilerServices.Union] struct S2 : S2.IUnionMembers { public S2(byte x){} public interface IUnionMembers { public static S2 Create(in int x) => throw null; public static S2 Create(ref readonly string x) => throw null; public static S2 Create(ref long x) => throw null; public static S2 Create(out char x) => throw null; public object Value { get; } } object IUnionMembers.Value => throw null; } "; var comp = CreateCompilation([src, UnionAttributeSource], targetFramework: TargetFramework.NetCoreApp); comp.VerifyEmitDiagnostics(); VerifyCaseTypes(comp, "S2", ["System.Int32"]); } [Fact] public void CaseTypes_30_MemberProvider_MembersInherited() { var src = @" [System.Runtime.CompilerServices.Union] struct S2 : S2.IUnionMembers { public S2(byte x){} public interface IUnionMembers : IUnionMembersBase { public static S2 Create(int x) => throw null; public object Value { get; } } object IUnionMembers.Value => throw null; public interface IUnionMembersBase { public static S2 Create(char x) => throw null; } } [System.Runtime.CompilerServices.Union] struct S3 : S3.IUnionMembers { public S3(byte x){} public interface IUnionMembers : IBase2 { public object Value { get; } } object IUnionMembers.Value => throw null; public interface IBase2 : IBase1 { public static S3 Create(int x) => throw null; } public interface IBase1 { public static S3 Create(char x) => throw null; } } "; var comp = CreateCompilation([src, UnionAttributeSource], targetFramework: TargetFramework.NetCoreApp); comp.VerifyEmitDiagnostics(); VerifyCaseTypes(comp, "S2", ["System.Int32", "System.Char"]); VerifyCaseTypes(comp, "S3", ["System.Int32", "System.Char"]); } [Fact] public void CaseTypes_31_MemberProvider_Generic_Method() { var src = @" [System.Runtime.CompilerServices.Union] struct S2 : S2.IUnionMembers { public S2(byte x){} public interface IUnionMembers { public static S2 Create(int x) => throw null; public static S2 Create<T>(string x) => throw null; public object Value { get; } } object IUnionMembers.Value => throw null; } "; var comp = CreateCompilation([src, UnionAttributeSource], targetFramework: TargetFramework.NetCoreApp); comp.VerifyEmitDiagnostics(); VerifyCaseTypes(comp, "S2", ["System.Int32"]); } [Fact] public void CaseTypes_32_MemberProvider_Inheritance_Generic() { var src = @" [System.Runtime.CompilerServices.Union] struct S2 : S2.IUnionMembers { public S2(byte x){} public object Value => throw null; public interface IUnionMembers : IBase<string> { public object Value { get; } } public interface IBase<T> { public static S2 Create(int x) => throw null; public static S2 Create(T x) => throw null; } } [System.Runtime.CompilerServices.Union] struct S3 : S3.IUnionMembers { public S3(byte x){} public object Value => throw null; public interface IUnionMembers : IBase2<int> { public object Value { get; } } public interface IBase2<T> : IBase1<string> { public static S3 Create(T x) => throw null; } public interface IBase1<T> { public static S3 Create(T x) => throw null; } } "; var comp = CreateCompilation([src, UnionAttributeSource], targetFramework: TargetFramework.NetCoreApp); comp.VerifyEmitDiagnostics(); VerifyCaseTypes(comp, "S2", ["System.Int32", "System.String"]); VerifyCaseTypes(comp, "S3", ["System.Int32", "System.String"]); } [Fact] public void CaseTypes_33_MemberProvider_Inheritance_InGenericUnion() { var src = @" [System.Runtime.CompilerServices.Union] struct S2<T> : S2<T>.IUnionMembers { public S2(byte x){} object IUnionMembers.Value => throw null; public interface IUnionMembers : IBase<int, T> { public object Value { get; } } public interface IBase<S1, S2> { public static S2<T> Create(S1 x) => throw null; public static S2<T> Create(S2 x) => throw null; } } "; var comp = CreateCompilation([src, UnionAttributeSource], targetFramework: TargetFramework.NetCoreApp); comp.VerifyEmitDiagnostics(); VerifyCaseTypes(comp, "S2`1", ["System.Int32", "T"]); VerifyCaseTypes(comp, "S2`1", ["System.String"], ["System.Int32", "System.String"]); } [Theory] [CombinatorialData] public void CaseTypes_34_MemberProvider_Inheritance_NotPublic([CombinatorialValues("", "private", "internal", "protected", "internal protected", "private protected")] string accessibility) { var src = @" [System.Runtime.CompilerServices.Union] public class S2 : S2.IUnionMembers { public S2(byte x){} public object Value => throw null; public interface IUnionMembers : IBase { public object Value { get; } } " + accessibility + @" interface IBase { public static S2 Create(int x) => throw null; public static S2 Create(string x) => throw null; } } "; var comp = CreateCompilation([src, UnionAttributeSource], targetFramework: TargetFramework.NetCoreApp); comp.VerifyEmitDiagnostics( // (8,22): error CS0061: Inconsistent accessibility: base interface 'S2.IBase' is less accessible than interface 'S2.IUnionMembers' // public interface IUnionMembers : IBase Diagnostic(ErrorCode.ERR_BadVisBaseInterface, "IUnionMembers").WithArguments("S2.IUnionMembers", "S2.IBase").WithLocation(8, 22) ); VerifyCaseTypes(comp, "S2", ["System.Int32", "System.String"]); } [Fact] public void CaseTypes_35_MemberProvider_Inheritance_NotPublic() { var src = @" [System.Runtime.CompilerServices.Union] public class S2 : S2.IUnionMembers { public S2(byte x){} public object Value => throw null; public interface IUnionMembers : IBase { public object Value { get; } } } interface IBase { public static S2 Create(int x) => throw null; public static S2 Create(string x) => throw null; } "; var comp = CreateCompilation([src, UnionAttributeSource], targetFramework: TargetFramework.NetCoreApp); comp.VerifyEmitDiagnostics( // (8,22): error CS0061: Inconsistent accessibility: base interface 'IBase' is less accessible than interface 'S2.IUnionMembers' // public interface IUnionMembers : IBase Diagnostic(ErrorCode.ERR_BadVisBaseInterface, "IUnionMembers").WithArguments("S2.IUnionMembers", "IBase").WithLocation(8, 22) ); VerifyCaseTypes(comp, "S2", ["System.Int32", "System.String"]); } [Fact] public void CaseTypes_36_MemberProvider_Inheritance_WrongReturnType() { var src = @" [System.Runtime.CompilerServices.Union] struct S2 : S2.IUnionMembers { public S2(byte x){} public interface IUnionMembers : IBase { public object Value { get; } } public interface IBase { public static int Create(int x) => throw null; public static void Create(string x) => throw null; public static S2 Create(long x) => throw null; } object IUnionMembers.Value => throw null; } "; var comp = CreateCompilation([src, UnionAttributeSource], targetFramework: TargetFramework.NetCoreApp); comp.VerifyEmitDiagnostics(); VerifyCaseTypes(comp, "S2", ["System.Int64"]); } [Fact] public void CaseTypes_37_MemberProvider_Inheritance_WrongReturnType() { var src = @" [System.Runtime.CompilerServices.Union] struct S2<T> : S2<T>.IUnionMembers { public S2(byte x){} public interface IUnionMembers : IBase { public object Value { get; } } public interface IBase { public static S2<T> Create(int x) => throw null; public static S2<string> Create(T x) => throw null; } object IUnionMembers.Value => throw null; } "; var comp = CreateCompilation([src, UnionAttributeSource], targetFramework: TargetFramework.NetCoreApp); comp.VerifyEmitDiagnostics(); VerifyCaseTypes(comp, "S2`1", ["System.Int32"]); VerifyCaseTypes(comp, "S2`1", ["System.String"], ["System.Int32"]); } [Fact] public void CaseTypes_38_MemberProvider_Inheritance_WrongReturnRefKind() { var src = @" [System.Runtime.CompilerServices.Union] struct S2 : S2.IUnionMembers { public S2(byte x){} public interface IUnionMembers : IBase { public object Value { get; } } public interface IBase { public static ref S2 Create(int x) => throw null; public static ref S2 Create(string x) => throw null; public static S2 Create(long x) => throw null; } object IUnionMembers.Value => throw null; } "; var comp = CreateCompilation([src, UnionAttributeSource], targetFramework: TargetFramework.NetCoreApp); comp.VerifyEmitDiagnostics(); VerifyCaseTypes(comp, "S2", ["System.Int64"]); } [Fact] public void CaseTypes_39_MemberProvider_Inheritance_NotStatic() { var src = @" [System.Runtime.CompilerServices.Union] struct S2 : S2.IUnionMembers { public S2(byte x){} public interface IUnionMembers : IBase { public object Value { get; } } public interface IBase { public S2 Create(int x) => throw null; public virtual S2 Create(string x) => throw null; public abstract S2 Create(byte x); public static S2 Create(long x) => throw null; } object IUnionMembers.Value => throw null; public S2 Create(byte x) => throw null; } "; var comp = CreateCompilation([src, UnionAttributeSource], targetFramework: TargetFramework.NetCoreApp); comp.VerifyEmitDiagnostics(); VerifyCaseTypes(comp, "S2", ["System.Int64"]); } [Fact] public void CaseTypes_40_MemberProvider_Inheritance_ParameterRefKind() { var src = @" [System.Runtime.CompilerServices.Union] struct S2 : S2.IUnionMembers { public S2(byte x){} public interface IUnionMembers : IBase { public object Value { get; } } public interface IBase { public static S2 Create(in int x) => throw null; public static S2 Create(ref readonly string x) => throw null; public static S2 Create(ref long x) => throw null; public static S2 Create(out char x) => throw null; } object IUnionMembers.Value => throw null; } "; var comp = CreateCompilation([src, UnionAttributeSource], targetFramework: TargetFramework.NetCoreApp); comp.VerifyEmitDiagnostics(); VerifyCaseTypes(comp, "S2", ["System.Int32"]); } [Fact] public void CaseTypes_41_MemberProvider_Inheritance_Generic_Method() { var src = @" [System.Runtime.CompilerServices.Union] struct S2 : S2.IUnionMembers { public S2(byte x){} public interface IUnionMembers : IBase { public object Value { get; } } public interface IBase { public static S2 Create(int x) => throw null; public static S2 Create<T>(string x) => throw null; } object IUnionMembers.Value => throw null; } "; var comp = CreateCompilation([src, UnionAttributeSource], targetFramework: TargetFramework.NetCoreApp); comp.VerifyEmitDiagnostics(); VerifyCaseTypes(comp, "S2", ["System.Int32"]); } [Theory] [CombinatorialData] public void CaseTypes_42_MemberProvider_Inheritance_NotPublic_Method([CombinatorialValues("private", "internal", "protected", "internal protected", "private protected")] string accessibility) { var src = @" [System.Runtime.CompilerServices.Union] public class S2 : S2.IUnionMembers { public S2(byte x){} public object Value => throw null; public interface IUnionMembers : IBase { public object Value { get; } } public interface IBase { public static S2 Create(int x) => throw null; " + accessibility + @" static S2 Create(string x) => throw null; } } "; var comp = CreateCompilation([src, UnionAttributeSource], targetFramework: TargetFramework.NetCoreApp); comp.VerifyEmitDiagnostics(); VerifyCaseTypes(comp, "S2", ["System.Int32"]); } [Fact] public void CaseTypes_43_MemberProvider_Inheritance() { var src1 = @" public interface IBase1 { } "; var comp1 = CreateCompilation(src1, assemblyName: "lib1"); var comp1Ref = comp1.EmitToImageReference(); var src2 = @" public interface IBase2 : IBase1 { } "; var comp2 = CreateCompilation(src2, references: [comp1Ref]); var comp2Ref = comp2.EmitToImageReference(); var src3 = @" [System.Runtime.CompilerServices.Union] public class S2 : S2.IUnionMembers { public S2(byte x){} public object Value => throw null; public interface IUnionMembers : IBase2 { public static global::S2 Create(int x) => throw null; public object Value { get; } } } "; var comp3 = CreateCompilation([src3, UnionAttributeSource], references: [comp2Ref]); comp3.VerifyEmitDiagnostics( // (3,19): error CS0012: The type 'IBase1' is defined in an assembly that is not referenced. You must add a reference to assembly 'lib1, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null'. // public class S2 : S2.IUnionMembers Diagnostic(ErrorCode.ERR_NoTypeDef, "S2.IUnionMembers").WithArguments("IBase1", "lib1, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null").WithLocation(3, 19), // (3,19): error CS0012: The type 'IBase1' is defined in an assembly that is not referenced. You must add a reference to assembly 'lib1, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null'. // public class S2 : S2.IUnionMembers Diagnostic(ErrorCode.ERR_NoTypeDef, "S2.IUnionMembers").WithArguments("IBase1", "lib1, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null").WithLocation(3, 19), // (8,22): error CS0012: The type 'IBase1' is defined in an assembly that is not referenced. You must add a reference to assembly 'lib1, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null'. // public interface IUnionMembers : IBase2 Diagnostic(ErrorCode.ERR_NoTypeDef, "IUnionMembers").WithArguments("IBase1", "lib1, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null").WithLocation(8, 22) ); comp3 = CreateCompilation([src3, UnionAttributeSource], references: [comp1Ref, comp2Ref]); var comp3Ref = comp3.EmitToImageReference(); var src4 = @" class Program { static bool Test1(S2 u) { return u is null; } static bool Test2(S2 u) { return u is 11; } static bool Test3(S2 u) { return u is int; } } "; var comp4 = CreateCompilation(src4, references: [comp2Ref, comp3Ref]); comp4.VerifyEmitDiagnostics( // (11,21): error CS0012: The type 'IBase1' is defined in an assembly that is not referenced. You must add a reference to assembly 'lib1, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null'. // return u is 11; Diagnostic(ErrorCode.ERR_NoTypeDef, "11").WithArguments("IBase1", "lib1, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null").WithLocation(11, 21), // (16,21): error CS0012: The type 'IBase1' is defined in an assembly that is not referenced. You must add a reference to assembly 'lib1, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null'. // return u is int; Diagnostic(ErrorCode.ERR_NoTypeDef, "int").WithArguments("IBase1", "lib1, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null").WithLocation(16, 21) ); var src5 = @" class Program { static S2 Test1() { return 10; } } "; var comp5 = CreateCompilation(src5, references: [comp2Ref, comp3Ref]); comp5.VerifyEmitDiagnostics( // (6,9): error CS0012: The type 'IBase1' is defined in an assembly that is not referenced. You must add a reference to assembly 'lib1, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null'. // return 10; Diagnostic(ErrorCode.ERR_NoTypeDef, "return 10;").WithArguments("IBase1", "lib1, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null").WithLocation(6, 9) ); } [Fact] public void UnionMatching_01_Discard_01() { var src = @" [System.Runtime.CompilerServices.Union] class S1 { public S1() { Value = null; } public S1(int x) { Value = x; } public S1(string x) { Value = x; } public object Value { get; } } class Program { static void Main() { System.Console.Write(Test(new S1(10))); System.Console.Write(Test(null)); System.Console.Write(Test(new S1())); } static bool Test(S1 u) { if (u switch {_ => true }) { return true; } return false; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); var verifier = CompileAndVerify(comp, expectedOutput: "TrueTrueTrue").VerifyDiagnostics(); verifier.VerifyIL("Program.Test", @" { // Code size 7 (0x7) .maxstack 1 IL_0000: ldc.i4.1 IL_0001: brfalse.s IL_0005 IL_0003: ldc.i4.1 IL_0004: ret IL_0005: ldc.i4.0 IL_0006: ret } "); } [Fact] public void UnionMatching_01_Discard_02() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 { public S1() { Value = null; } public S1(int x) { Value = x; } public S1(string x) { Value = x; } public object Value { get; } } class Program { static void Main() { System.Console.Write(Test1(new S1(10))); System.Console.Write(Test1(default(S1))); System.Console.Write(Test1(new S1())); System.Console.Write(' '); System.Console.Write(Test2(new S1(10))); System.Console.Write(Test2(default(S1))); System.Console.Write(Test2(new S1())); System.Console.Write(Test2(null)); } static bool Test1(S1 u) { if (u switch {_ => true }) { return true; } return false; } static bool Test2(S1? u) { if (u switch {_ => true }) { return true; } return false; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); var verifier = CompileAndVerify(comp, expectedOutput: "TrueTrueTrue TrueTrueTrueTrue").VerifyDiagnostics(); verifier.VerifyIL("Program.Test1", @" { // Code size 7 (0x7) .maxstack 1 IL_0000: ldc.i4.1 IL_0001: brfalse.s IL_0005 IL_0003: ldc.i4.1 IL_0004: ret IL_0005: ldc.i4.0 IL_0006: ret } "); verifier.VerifyIL("Program.Test2", @" { // Code size 7 (0x7) .maxstack 1 IL_0000: ldc.i4.1 IL_0001: brfalse.s IL_0005 IL_0003: ldc.i4.1 IL_0004: ret IL_0005: ldc.i4.0 IL_0006: ret } "); } [Fact] public void UnionMatching_02_Var_01() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 { public S1(int x) { Value = x; } public S1(string x) { Value = x; } public object Value { get; } public int Int => 123; } class Program { static void Main() { System.Console.Write(Test1(new S1(10))); System.Console.Write(Test1(default)); System.Console.Write(' '); System.Console.Write(Test2(new S1(10))); System.Console.Write(Test2(default(S1))); System.Console.Write(Test2(null) is null); } static int Test1(S1 u) { return (u switch {var v => v }).Int; } static int? Test2(S1? u) { return (u switch {var v => v })?.Int; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); CompileAndVerify(comp, expectedOutput: "123123 123123True").VerifyDiagnostics(); } [Fact] public void UnionMatching_02_Var_02() { var src = @" [System.Runtime.CompilerServices.Union] class S1 { public S1(int x) { Value = x; } public S1(string x) { Value = x; } public object Value { get; } public int Int => 123; } class Program { static void Main() { System.Console.Write(Test1(new S1(10))); System.Console.Write(Test1(null) is null); } static int? Test1(S1 u) { return (u switch {var v => v })?.Int; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); CompileAndVerify(comp, expectedOutput: "123True").VerifyDiagnostics(); } [Fact] public void UnionMatching_03_Var_Deconstruct_01() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 { public S1(int x) { Value = x; } public S1(string x) { Value = x; } public object Value { get; } public void Deconstruct(out int x, out int y) { x = 1; y = 2; } } class Program { static void Main() { System.Console.Write(Test2(new S1(10))); System.Console.Write(Test2(default(S1))); System.Console.Write(Test2(null)); } static int Test2(S1? u) { #line 200 return (u switch {var (a, b) => a * 1000 + b * 10, _ => -1 } ); } } static class Extensions { public static void Deconstruct(this object o, out int x, out int y) => throw null; } "; var comp = CreateCompilation([src, UnionAttributeSource], targetFramework: TargetFramework.NetLatest, options: TestOptions.ReleaseExe); CompileAndVerify(comp, expectedOutput: "10201020-1").VerifyDiagnostics(); } [Fact] public void UnionMatching_03_Var_Deconstruct_02() { var src = @" [System.Runtime.CompilerServices.Union] class S1 { public S1(int x) { Value = x; } public S1(string x) { Value = x; } public object Value { get; } public void Deconstruct(out int x, out int y) { x = 1; y = 2; } } class Program { static void Main() { System.Console.Write(Test2(new S1(10))); System.Console.Write(Test2(null)); } static int Test2(S1 u) { return (u switch {var (a, b) => a * 1000 + b * 10, _ => -1 } ); } } static class Extensions { public static void Deconstruct(this object o, out int x, out int y) => throw null; } "; var comp = CreateCompilation([src, UnionAttributeSource], targetFramework: TargetFramework.NetLatest, options: TestOptions.ReleaseExe); CompileAndVerify(comp, expectedOutput: "1020-1").VerifyDiagnostics(); } [Fact] public void UnionMatching_04_Var_ITuple_01() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 { private readonly object _value; public S1(int x) { _value = x; } public S1(C x) { _value = x; } public object Value => _value; } class Program { static void Main() { System.Console.Write(Test1(new S1(10))); System.Console.Write(Test1(default)); System.Console.Write(Test1(new S1(new C()))); System.Console.Write(' '); System.Console.Write(Test2((new S1(10), -1))); System.Console.Write(Test2((default, -1))); System.Console.Write(Test2((new S1(new C()), -1))); System.Console.Write(' '); System.Console.Write(Test3(new C2(new S1(10)))); System.Console.Write(Test3(new C2(default))); System.Console.Write(Test3(new C2(new S1(new C())))); } static bool Test1(S1 u) { #line 100 return u is var (_, i) && (int)i == 10; } static bool Test2((S1, int) u) { #line 200 return u is var ((_, i), _) && (int)i == 10; } static bool Test3(C2 u) { #line 300 return u is var (_, ((_, i), _, _)) && (int)i == 10; } } public class C : System.Runtime.CompilerServices.ITuple { int System.Runtime.CompilerServices.ITuple.Length => 2; object System.Runtime.CompilerServices.ITuple.this[int i] => i * 10; } class C2 : System.Runtime.CompilerServices.ITuple { private readonly S1 _value; public C2(S1 x) { _value = x; } int System.Runtime.CompilerServices.ITuple.Length => 2; object System.Runtime.CompilerServices.ITuple.this[int i] => _value; } static class Extensions { public static void Deconstruct(this object o, out S1 x, out int y, out int z) { x = (S1)o; y = 2; z = 3; } } "; var comp = CreateCompilation([src, UnionAttributeSource], targetFramework: TargetFramework.NetCoreApp, options: TestOptions.ReleaseExe); comp.VerifyDiagnostics( // (100,25): error CS7036: There is no argument given that corresponds to the required parameter 'z' of 'Extensions.Deconstruct(object, out S1, out int, out int)' // return u is var (_, i) && (int)i == 10; Diagnostic(ErrorCode.ERR_NoCorrespondingArgument, "(_, i)").WithArguments("z", "Extensions.Deconstruct(object, out S1, out int, out int)").WithLocation(100, 25), // (100,25): error CS8129: No suitable 'Deconstruct' instance or extension method was found for type 'S1', with 2 out parameters and a void return type. // return u is var (_, i) && (int)i == 10; Diagnostic(ErrorCode.ERR_MissingDeconstruct, "(_, i)").WithArguments("S1", "2").WithLocation(100, 25), // (200,26): error CS7036: There is no argument given that corresponds to the required parameter 'z' of 'Extensions.Deconstruct(object, out S1, out int, out int)' // return u is var ((_, i), _) && (int)i == 10; Diagnostic(ErrorCode.ERR_NoCorrespondingArgument, "(_, i)").WithArguments("z", "Extensions.Deconstruct(object, out S1, out int, out int)").WithLocation(200, 26), // (200,26): error CS8129: No suitable 'Deconstruct' instance or extension method was found for type 'S1', with 2 out parameters and a void return type. // return u is var ((_, i), _) && (int)i == 10; Diagnostic(ErrorCode.ERR_MissingDeconstruct, "(_, i)").WithArguments("S1", "2").WithLocation(200, 26), // (300,30): error CS7036: There is no argument given that corresponds to the required parameter 'z' of 'Extensions.Deconstruct(object, out S1, out int, out int)' // return u is var (_, ((_, i), _, _)) && (int)i == 10; Diagnostic(ErrorCode.ERR_NoCorrespondingArgument, "(_, i)").WithArguments("z", "Extensions.Deconstruct(object, out S1, out int, out int)").WithLocation(300, 30), // (300,30): error CS8129: No suitable 'Deconstruct' instance or extension method was found for type 'S1', with 2 out parameters and a void return type. // return u is var (_, ((_, i), _, _)) && (int)i == 10; Diagnostic(ErrorCode.ERR_MissingDeconstruct, "(_, i)").WithArguments("S1", "2").WithLocation(300, 30) ); } [Fact] public void UnionMatching_04_Var_ITuple_02() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 { private readonly object _value; public S1(int x) { _value = x; } public S1(C x) { _value = x; } public object Value => _value; } class Program { static void Main() { System.Console.Write(Test1(new S1(10))); System.Console.Write(Test1(default(S1))); System.Console.Write(Test1(new S1(new C()))); System.Console.Write(Test1(null)); System.Console.Write(' '); System.Console.Write(Test2((new S1(10), -1))); System.Console.Write(Test2((default(S1), -1))); System.Console.Write(Test2((new S1(new C()), -1))); System.Console.Write(Test2((null, -1))); System.Console.Write(' '); System.Console.Write(Test3(new C2(new S1(10)))); System.Console.Write(Test3(new C2(default(S1)))); System.Console.Write(Test3(new C2(new S1(new C())))); System.Console.Write(Test3(new C2(null))); } static bool Test1(S1? u) { #line 100 return u is var (_, i) && (int)i == 10; } static bool Test2((S1?, int) u) { #line 200 return u is var ((_, i), _) && (int)i == 10; } static bool Test3(C2 u) { #line 300 return u is var (_, ((_, i), _, _)) && (int)i == 10; } } public class C : System.Runtime.CompilerServices.ITuple { int System.Runtime.CompilerServices.ITuple.Length => 2; object System.Runtime.CompilerServices.ITuple.this[int i] => i * 10; } class C2 : System.Runtime.CompilerServices.ITuple { private readonly S1? _value; public C2(S1? x) { _value = x; } int System.Runtime.CompilerServices.ITuple.Length => 2; object System.Runtime.CompilerServices.ITuple.this[int i] => _value; } static class Extensions { public static void Deconstruct(this object o, out S1? x, out int y, out int z) { x = (S1?)o; y = 2; z = 3; } } "; var comp = CreateCompilation([src, UnionAttributeSource], targetFramework: TargetFramework.NetCoreApp, options: TestOptions.ReleaseExe); comp.VerifyDiagnostics( // (100,25): error CS7036: There is no argument given that corresponds to the required parameter 'z' of 'Extensions.Deconstruct(object, out S1?, out int, out int)' // return u is var (_, i) && (int)i == 10; Diagnostic(ErrorCode.ERR_NoCorrespondingArgument, "(_, i)").WithArguments("z", "Extensions.Deconstruct(object, out S1?, out int, out int)").WithLocation(100, 25), // (100,25): error CS8129: No suitable 'Deconstruct' instance or extension method was found for type 'S1', with 2 out parameters and a void return type. // return u is var (_, i) && (int)i == 10; Diagnostic(ErrorCode.ERR_MissingDeconstruct, "(_, i)").WithArguments("S1", "2").WithLocation(100, 25), // (200,26): error CS7036: There is no argument given that corresponds to the required parameter 'z' of 'Extensions.Deconstruct(object, out S1?, out int, out int)' // return u is var ((_, i), _) && (int)i == 10; Diagnostic(ErrorCode.ERR_NoCorrespondingArgument, "(_, i)").WithArguments("z", "Extensions.Deconstruct(object, out S1?, out int, out int)").WithLocation(200, 26), // (200,26): error CS8129: No suitable 'Deconstruct' instance or extension method was found for type 'S1', with 2 out parameters and a void return type. // return u is var ((_, i), _) && (int)i == 10; Diagnostic(ErrorCode.ERR_MissingDeconstruct, "(_, i)").WithArguments("S1", "2").WithLocation(200, 26), // (300,30): error CS7036: There is no argument given that corresponds to the required parameter 'z' of 'Extensions.Deconstruct(object, out S1?, out int, out int)' // return u is var (_, ((_, i), _, _)) && (int)i == 10; Diagnostic(ErrorCode.ERR_NoCorrespondingArgument, "(_, i)").WithArguments("z", "Extensions.Deconstruct(object, out S1?, out int, out int)").WithLocation(300, 30), // (300,30): error CS8129: No suitable 'Deconstruct' instance or extension method was found for type 'S1', with 2 out parameters and a void return type. // return u is var (_, ((_, i), _, _)) && (int)i == 10; Diagnostic(ErrorCode.ERR_MissingDeconstruct, "(_, i)").WithArguments("S1", "2").WithLocation(300, 30) ); } [Fact] public void UnionMatching_04_Var_ITuple_03() { var src = @" [System.Runtime.CompilerServices.Union] class S1 { private readonly object _value; public S1(int x) { _value = x; } public S1(C x) { _value = x; } public object Value => _value; } class Program { static void Main() { System.Console.Write(Test1(new S1(10))); System.Console.Write(Test1(new S1(new C()))); System.Console.Write(Test1(null)); System.Console.Write(' '); System.Console.Write(Test2((new S1(10), -1))); System.Console.Write(Test2((new S1(new C()), -1))); System.Console.Write(Test2((null, -1))); System.Console.Write(' '); System.Console.Write(Test3(new C2(new S1(10)))); System.Console.Write(Test3(new C2(new S1(new C())))); System.Console.Write(Test3(new C2(null))); } static bool Test1(S1 u) { #line 100 return u is var (_, i) && (int)i == 10; } static bool Test2((S1, int) u) { #line 200 return u is var ((_, i), _) && (int)i == 10; } static bool Test3(C2 u) { #line 300 return u is var (_, ((_, i), _, _)) && (int)i == 10; } } public class C : System.Runtime.CompilerServices.ITuple { int System.Runtime.CompilerServices.ITuple.Length => 2; object System.Runtime.CompilerServices.ITuple.this[int i] => i * 10; } class C2 : System.Runtime.CompilerServices.ITuple { private readonly S1 _value; public C2(S1 x) { _value = x; } int System.Runtime.CompilerServices.ITuple.Length => 2; object System.Runtime.CompilerServices.ITuple.this[int i] => _value; } static class Extensions { public static void Deconstruct(this object o, out S1 x, out int y, out int z) { x = (S1)o; y = 2; z = 3; } } "; var comp = CreateCompilation([src, UnionAttributeSource], targetFramework: TargetFramework.NetCoreApp, options: TestOptions.ReleaseExe); comp.VerifyDiagnostics( // (100,25): error CS7036: There is no argument given that corresponds to the required parameter 'z' of 'Extensions.Deconstruct(object, out S1, out int, out int)' // return u is var (_, i) && (int)i == 10; Diagnostic(ErrorCode.ERR_NoCorrespondingArgument, "(_, i)").WithArguments("z", "Extensions.Deconstruct(object, out S1, out int, out int)").WithLocation(100, 25), // (100,25): error CS8129: No suitable 'Deconstruct' instance or extension method was found for type 'S1', with 2 out parameters and a void return type. // return u is var (_, i) && (int)i == 10; Diagnostic(ErrorCode.ERR_MissingDeconstruct, "(_, i)").WithArguments("S1", "2").WithLocation(100, 25), // (200,26): error CS7036: There is no argument given that corresponds to the required parameter 'z' of 'Extensions.Deconstruct(object, out S1, out int, out int)' // return u is var ((_, i), _) && (int)i == 10; Diagnostic(ErrorCode.ERR_NoCorrespondingArgument, "(_, i)").WithArguments("z", "Extensions.Deconstruct(object, out S1, out int, out int)").WithLocation(200, 26), // (200,26): error CS8129: No suitable 'Deconstruct' instance or extension method was found for type 'S1', with 2 out parameters and a void return type. // return u is var ((_, i), _) && (int)i == 10; Diagnostic(ErrorCode.ERR_MissingDeconstruct, "(_, i)").WithArguments("S1", "2").WithLocation(200, 26), // (300,30): error CS7036: There is no argument given that corresponds to the required parameter 'z' of 'Extensions.Deconstruct(object, out S1, out int, out int)' // return u is var (_, ((_, i), _, _)) && (int)i == 10; Diagnostic(ErrorCode.ERR_NoCorrespondingArgument, "(_, i)").WithArguments("z", "Extensions.Deconstruct(object, out S1, out int, out int)").WithLocation(300, 30), // (300,30): error CS8129: No suitable 'Deconstruct' instance or extension method was found for type 'S1', with 2 out parameters and a void return type. // return u is var (_, ((_, i), _, _)) && (int)i == 10; Diagnostic(ErrorCode.ERR_MissingDeconstruct, "(_, i)").WithArguments("S1", "2").WithLocation(300, 30) ); } [Fact] public void UnionMatching_04_Var_ITuple_04() { var src = @" [System.Runtime.CompilerServices.Union] class S1 : System.Runtime.CompilerServices.ITuple { private readonly object _value; public S1(int x) { _value = x; } public S1(C x) { _value = x; } public object Value => _value; int System.Runtime.CompilerServices.ITuple.Length => 1; object System.Runtime.CompilerServices.ITuple.this[int i] => _value; } class Program { static void Main() { System.Console.Write(Test1(new S1(10))); System.Console.Write(Test1(new S1(11))); System.Console.Write(Test1(new S1(new C()))); System.Console.Write(Test1(null)); } static bool Test1(S1 u) { return u is var (i) && i is 10; } } public class C; "; var comp = CreateCompilation([src, UnionAttributeSource], targetFramework: TargetFramework.NetCoreApp, options: TestOptions.ReleaseExe); CompileAndVerify(comp, expectedOutput: ExecutionConditionUtil.IsMonoOrCoreClr ? "TrueFalseFalseFalse" : null, verify: Verification.FailsPEVerify).VerifyDiagnostics(); } [Fact] public void UnionMatching_05_Constant_01() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } public object Value => _value; } class Program { static void Main() { System.Console.Write(Test1(new S1(10))); System.Console.Write(Test1(default)); System.Console.Write(Test1(new S1(""11""))); System.Console.Write(Test1(new S1(0))); System.Console.Write(' '); System.Console.Write(Test2(new S1(10))); System.Console.Write(Test2(default)); System.Console.Write(Test2(new S1(""11""))); System.Console.Write(Test2(new S1(0))); System.Console.Write(Test2(new S1(11))); System.Console.Write(' '); System.Console.Write(Test3(new S1(11))); System.Console.Write(Test3(default)); System.Console.Write(Test3(new S1(""11""))); System.Console.Write(' '); System.Console.Write(Test4(new S1(11))); System.Console.Write(Test4(default)); System.Console.Write(Test4(new S1(""11""))); System.Console.Write(' '); System.Console.Write(Test5(new S1(10))); System.Console.Write(Test5(default(S1))); System.Console.Write(Test5(new S1(""11""))); System.Console.Write(Test5(new S1(0))); System.Console.Write(Test5(null)); } static bool Test1(S1 u) { return u is 10; } static bool Test2(S1 u) { return u is 10 or 11; } static bool Test3(S1 u) { return u is ""11"" and ['1', '1']; } static bool Test4(S1 u) { return u is null; } static bool Test5(S1? u) { return u is 10; } } "; var comp = CreateCompilation([src, UnionAttributeSource], targetFramework: TargetFramework.NetCoreApp, options: TestOptions.ReleaseExe); var verifier = CompileAndVerify(comp, expectedOutput: ExecutionConditionUtil.IsMonoOrCoreClr ? "TrueFalseFalseFalse TrueFalseFalseFalseTrue FalseFalseTrue FalseTrueFalse TrueFalseFalseFalseFalse" : null, verify: Verification.FailsPEVerify).VerifyDiagnostics(); verifier.VerifyIL("Program.Test1", @" { // Code size 29 (0x1d) .maxstack 2 .locals init (object V_0) IL_0000: ldarga.s V_0 IL_0002: call ""object S1.Value.get"" IL_0007: stloc.0 IL_0008: ldloc.0 IL_0009: isinst ""int"" IL_000e: brfalse.s IL_001b IL_0010: ldloc.0 IL_0011: unbox.any ""int"" IL_0016: ldc.i4.s 10 IL_0018: ceq IL_001a: ret IL_001b: ldc.i4.0 IL_001c: ret } "); verifier.VerifyIL("Program.Test5", @" { // Code size 46 (0x2e) .maxstack 2 .locals init (S1 V_0, object V_1) IL_0000: ldarga.s V_0 IL_0002: call ""readonly bool S1?.HasValue.get"" IL_0007: brfalse.s IL_002c IL_0009: ldarga.s V_0 IL_000b: call ""readonly S1 S1?.GetValueOrDefault()"" IL_0010: stloc.0 IL_0011: ldloca.s V_0 IL_0013: call ""object S1.Value.get"" IL_0018: stloc.1 IL_0019: ldloc.1 IL_001a: isinst ""int"" IL_001f: brfalse.s IL_002c IL_0021: ldloc.1 IL_0022: unbox.any ""int"" IL_0027: ldc.i4.s 10 IL_0029: ceq IL_002b: ret IL_002c: ldc.i4.0 IL_002d: ret } "); comp = CreateCompilation([src, UnionAttributeSource], targetFramework: TargetFramework.NetCoreApp, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular15); CompileAndVerify(comp, expectedOutput: ExecutionConditionUtil.IsMonoOrCoreClr ? "TrueFalseFalseFalse TrueFalseFalseFalseTrue FalseFalseTrue FalseTrueFalse TrueFalseFalseFalseFalse" : null, verify: Verification.FailsPEVerify).VerifyDiagnostics(); comp = CreateCompilation([src, UnionAttributeSource], targetFramework: TargetFramework.NetCoreApp, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular14); comp.VerifyDiagnostics( // (47,21): error CS9327: Feature 'unions' is not available in C# 14.0. Please use language version 15.0 or greater. // return u is 10; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion14, "10").WithArguments("unions", "15.0").WithLocation(47, 21), // (52,21): error CS9327: Feature 'unions' is not available in C# 14.0. Please use language version 15.0 or greater. // return u is 10 or 11; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion14, "10").WithArguments("unions", "15.0").WithLocation(52, 21), // (52,27): error CS9327: Feature 'unions' is not available in C# 14.0. Please use language version 15.0 or greater. // return u is 10 or 11; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion14, "11").WithArguments("unions", "15.0").WithLocation(52, 27), // (57,21): error CS9327: Feature 'unions' is not available in C# 14.0. Please use language version 15.0 or greater. // return u is "11" and ['1', '1']; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion14, @"""11""").WithArguments("unions", "15.0").WithLocation(57, 21), // (62,21): error CS9327: Feature 'unions' is not available in C# 14.0. Please use language version 15.0 or greater. // return u is null; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion14, "null").WithArguments("unions", "15.0").WithLocation(62, 21), // (67,21): error CS9327: Feature 'unions' is not available in C# 14.0. Please use language version 15.0 or greater. // return u is 10; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion14, "10").WithArguments("unions", "15.0").WithLocation(67, 21) ); } [Fact] public void UnionMatching_05_Constant_02() { var src = @" [System.Runtime.CompilerServices.Union] class S1 { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } public object Value => _value; } class Program { static void Main() { System.Console.Write(Test1(new S1(10))); System.Console.Write(Test1(default)); System.Console.Write(Test1(new S1(""11""))); System.Console.Write(Test1(new S1(0))); System.Console.Write(' '); System.Console.Write(Test2(new S1(10))); System.Console.Write(Test2(default)); System.Console.Write(Test2(new S1(""11""))); System.Console.Write(Test2(new S1(0))); System.Console.Write(Test2(new S1(11))); System.Console.Write(' '); System.Console.Write(Test3(new S1(11))); System.Console.Write(Test3(default)); System.Console.Write(Test3(new S1(""11""))); System.Console.Write(' '); System.Console.Write(Test4(new S1(11))); System.Console.Write(Test4(default)); System.Console.Write(Test4(new S1(""11""))); } static bool Test1(S1 u) { return u is 10; } static bool Test2(S1 u) { return u is 10 or 11; } static bool Test3(S1 u) { return u is ""11"" and ['1', '1']; } static bool Test4(S1 u) { return u is null; } } "; var comp = CreateCompilation([src, UnionAttributeSource], targetFramework: TargetFramework.NetCoreApp, options: TestOptions.ReleaseExe); var verifier = CompileAndVerify(comp, expectedOutput: ExecutionConditionUtil.IsMonoOrCoreClr ? "TrueFalseFalseFalse TrueFalseFalseFalseTrue FalseFalseTrue FalseTrueFalse" : null, verify: Verification.FailsPEVerify).VerifyDiagnostics(); verifier.VerifyIL("Program.Test1", @" { // Code size 31 (0x1f) .maxstack 2 .locals init (object V_0) IL_0000: ldarg.0 IL_0001: brfalse.s IL_001d IL_0003: ldarg.0 IL_0004: callvirt ""object S1.Value.get"" IL_0009: stloc.0 IL_000a: ldloc.0 IL_000b: isinst ""int"" IL_0010: brfalse.s IL_001d IL_0012: ldloc.0 IL_0013: unbox.any ""int"" IL_0018: ldc.i4.s 10 IL_001a: ceq IL_001c: ret IL_001d: ldc.i4.0 IL_001e: ret } "); } [Fact] public void UnionMatching_06_Constant_01() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } public object Value => _value; } [System.Runtime.CompilerServices.Union] class C1 { private readonly object _value; public C1() {} public C1(int x) { _value = x; } public C1(string x) { _value = x; } public object Value => _value; } class Program { static void Main() { System.Console.Write(Test1(new S1(11))); System.Console.Write(Test1(new S1())); System.Console.Write(Test1(new S1(""11""))); System.Console.Write(Test1(null)); System.Console.Write(' '); System.Console.Write(Test2(new C1(11))); System.Console.Write(Test2(new C1())); System.Console.Write(Test2(new C1(""11""))); System.Console.Write(Test2(null)); } static bool Test1(S1? u) { return u is null; } static bool Test2(C1 u) { return u is null; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); var verifier = CompileAndVerify(comp, expectedOutput: "FalseTrueFalseTrue FalseTrueFalseTrue").VerifyDiagnostics(); verifier.VerifyIL("Program.Test2", @" { // Code size 19 (0x13) .maxstack 1 .locals init (bool V_0) IL_0000: ldarg.0 IL_0001: brfalse.s IL_000b IL_0003: ldarg.0 IL_0004: callvirt ""object C1.Value.get"" IL_0009: brtrue.s IL_000f IL_000b: ldc.i4.1 IL_000c: stloc.0 IL_000d: br.s IL_0011 IL_000f: ldc.i4.0 IL_0010: stloc.0 IL_0011: ldloc.0 IL_0012: ret } "); verifier.VerifyIL("Program.Test1", @" { // Code size 34 (0x22) .maxstack 1 .locals init (S1 V_0, bool V_1) IL_0000: ldarga.s V_0 IL_0002: call ""bool S1?.HasValue.get"" IL_0007: brfalse.s IL_001a IL_0009: ldarga.s V_0 IL_000b: call ""S1 S1?.GetValueOrDefault()"" IL_0010: stloc.0 IL_0011: ldloca.s V_0 IL_0013: call ""object S1.Value.get"" IL_0018: brtrue.s IL_001e IL_001a: ldc.i4.1 IL_001b: stloc.1 IL_001c: br.s IL_0020 IL_001e: ldc.i4.0 IL_001f: stloc.1 IL_0020: ldloc.1 IL_0021: ret } "); } [Fact] public void UnionMatching_06_Constant_02() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 { private readonly object _value; public S1(int x) { _value = x; } public S1(C2 x) { _value = x; } public object Value => _value; } [System.Runtime.CompilerServices.Union] class C1 { private readonly object _value; public C1() {} public C1(int x) { _value = x; } public C1(C2 x) { _value = x; } public object Value => _value; } class C2; [System.Runtime.CompilerServices.Union] struct S2 { private readonly object _value; public S2(int x) { _value = x; } public S2(string x) { _value = x; } public object Value => _value; } class Program { static bool Test1(S1? u) { #line 100 return u is (string)null; } static bool Test2(C1 u) { #line 200 return u is (string)null; } static bool Test3(S1 u) { #line 300 return u is (string)null; } static bool Test4(C2 u) { #line 400 return u is (string)null; } static bool Test5(S2 u) { #line 500 return u is null; } static bool Test6(C2 u) { #line 600 return u is (object)null; } static bool Test7(string u) { #line 700 return u is (object)null; } static bool Test8(S2 u) { #line 800 return u is (object)null; } } "; var comp = CreateCompilation([src, UnionAttributeSource]); comp.VerifyDiagnostics( // (100,21): error CS9372: An expression of type 'S1' cannot be handled by this pattern, see additional errors at this location. // return u is (string)null; Diagnostic(ErrorCode.ERR_UnionMatchingWrongPattern, "(string)null").WithArguments("S1").WithLocation(100, 21), // (100,21): error CS0029: Cannot implicitly convert type 'string' to 'int' // return u is (string)null; Diagnostic(ErrorCode.ERR_NoImplicitConv, "(string)null").WithArguments("string", "int").WithLocation(100, 21), // (100,21): error CS0029: Cannot implicitly convert type 'string' to 'C2' // return u is (string)null; Diagnostic(ErrorCode.ERR_NoImplicitConv, "(string)null").WithArguments("string", "C2").WithLocation(100, 21), // (200,21): error CS9372: An expression of type 'C1' cannot be handled by this pattern, see additional errors at this location. // return u is (string)null; Diagnostic(ErrorCode.ERR_UnionMatchingWrongPattern, "(string)null").WithArguments("C1").WithLocation(200, 21), // (200,21): error CS0029: Cannot implicitly convert type 'string' to 'int' // return u is (string)null; Diagnostic(ErrorCode.ERR_NoImplicitConv, "(string)null").WithArguments("string", "int").WithLocation(200, 21), // (200,21): error CS0029: Cannot implicitly convert type 'string' to 'C2' // return u is (string)null; Diagnostic(ErrorCode.ERR_NoImplicitConv, "(string)null").WithArguments("string", "C2").WithLocation(200, 21), // (300,21): error CS9372: An expression of type 'S1' cannot be handled by this pattern, see additional errors at this location. // return u is (string)null; Diagnostic(ErrorCode.ERR_UnionMatchingWrongPattern, "(string)null").WithArguments("S1").WithLocation(300, 21), // (300,21): error CS0029: Cannot implicitly convert type 'string' to 'int' // return u is (string)null; Diagnostic(ErrorCode.ERR_NoImplicitConv, "(string)null").WithArguments("string", "int").WithLocation(300, 21), // (300,21): error CS0029: Cannot implicitly convert type 'string' to 'C2' // return u is (string)null; Diagnostic(ErrorCode.ERR_NoImplicitConv, "(string)null").WithArguments("string", "C2").WithLocation(300, 21), // (400,21): error CS0029: Cannot implicitly convert type 'string' to 'C2' // return u is (string)null; Diagnostic(ErrorCode.ERR_NoImplicitConv, "(string)null").WithArguments("string", "C2").WithLocation(400, 21), // (600,21): error CS0266: Cannot implicitly convert type 'object' to 'C2'. An explicit conversion exists (are you missing a cast?) // return u is (object)null; Diagnostic(ErrorCode.ERR_NoImplicitConvCast, "(object)null").WithArguments("object", "C2").WithLocation(600, 21), // (700,21): error CS0266: Cannot implicitly convert type 'object' to 'string'. An explicit conversion exists (are you missing a cast?) // return u is (object)null; Diagnostic(ErrorCode.ERR_NoImplicitConvCast, "(object)null").WithArguments("object", "string").WithLocation(700, 21), // (800,21): error CS9372: An expression of type 'S2' cannot be handled by this pattern, see additional errors at this location. // return u is (object)null; Diagnostic(ErrorCode.ERR_UnionMatchingWrongPattern, "(object)null").WithArguments("S2").WithLocation(800, 21), // (800,21): error CS0266: Cannot implicitly convert type 'object' to 'int'. An explicit conversion exists (are you missing a cast?) // return u is (object)null; Diagnostic(ErrorCode.ERR_NoImplicitConvCast, "(object)null").WithArguments("object", "int").WithLocation(800, 21), // (800,21): error CS0266: Cannot implicitly convert type 'object' to 'string'. An explicit conversion exists (are you missing a cast?) // return u is (object)null; Diagnostic(ErrorCode.ERR_NoImplicitConvCast, "(object)null").WithArguments("object", "string").WithLocation(800, 21) ); } [Fact] public void UnionMatching_07_Constant_01() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } public object Value => _value; } class Program { static void Main() { System.Console.Write(Test1(new S1(10))); System.Console.Write(Test1(default)); System.Console.Write(Test1(new S1(""11""))); System.Console.Write(Test1(new S1(0))); System.Console.Write(' '); System.Console.Write(Test4(new S1(11))); System.Console.Write(Test4(default)); System.Console.Write(Test4(new S1(""11""))); System.Console.Write(' '); System.Console.Write(Test10(new S1(10))); System.Console.Write(Test10(default)); System.Console.Write(Test10(new S1(""11""))); System.Console.Write(Test10(new S1(0))); System.Console.Write(' '); System.Console.Write(Test40(new S1(11))); System.Console.Write(Test40(default)); System.Console.Write(Test40(new S1(""11""))); System.Console.Write(' '); System.Console.Write(Test100(new S1(10))); System.Console.Write(Test100(default)); System.Console.Write(Test100(new S1(""11""))); System.Console.Write(Test100(new S1(0))); System.Console.Write(' '); System.Console.Write(Test400(new S1(11))); System.Console.Write(Test400(default)); System.Console.Write(Test400(new S1(""11""))); } const int _int_10 = 10; const string _string_null = null; const object _object_null = null; static bool Test1(S1 u) { return u switch { _int_10 => true, _ => false }; } static bool Test4(S1 u) { return u switch { _string_null => true, _ => false }; } static bool Test10(S1 u) { return u is _int_10; } static bool Test40(S1 u) { return u is _string_null; } static bool Test100(S1 u) { switch (u) { case _int_10: return true; }; return false; } static bool Test400(S1 u) { switch (u) { case _string_null: return true; }; return false; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); CompileAndVerify(comp, expectedOutput: "TrueFalseFalseFalse FalseTrueFalse TrueFalseFalseFalse FalseTrueFalse TrueFalseFalseFalse FalseTrueFalse").VerifyDiagnostics(); var src2 = @" [System.Runtime.CompilerServices.Union] struct S1 { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } public object Value => _value; } class Program { const int _int_10 = 10; static bool Test10(S1 u) { return u is _int_10; } } "; comp = CreateCompilation([src2, UnionAttributeSource], options: TestOptions.ReleaseDll, parseOptions: TestOptions.Regular15); comp.VerifyEmitDiagnostics(); comp = CreateCompilation([src2, UnionAttributeSource], options: TestOptions.ReleaseDll, parseOptions: TestOptions.Regular14); comp.VerifyDiagnostics( // (17,16): error CS9327: Feature 'unions' is not available in C# 14.0. Please use language version 15.0 or greater. // return u is _int_10; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion14, "u is _int_10").WithArguments("unions", "15.0").WithLocation(17, 16) ); comp = CreateCompilation([src2, UnionAttributeSource], options: TestOptions.ReleaseDll, parseOptions: TestOptions.Regular6); comp.VerifyDiagnostics( // (17,21): error CS0246: The type or namespace name '_int_10' could not be found (are you missing a using directive or an assembly reference?) // return u is _int_10; Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "_int_10").WithArguments("_int_10").WithLocation(17, 21) ); } [Fact] public void UnionMatching_07_Constant_02() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } public object Value => _value; } class Program { const object _object_null = null; static bool Test5(S1 u) { return u switch { _object_null => true, _ => false }; } static bool Test50(S1 u) { return u is _object_null; } static bool Test500(S1 u) { switch (u) { case _object_null: return true; }; return false; } } "; var comp = CreateCompilation([src, UnionAttributeSource]); comp.VerifyDiagnostics( // (17,27): error CS9372: An expression of type 'S1' cannot be handled by this pattern, see additional errors at this location. // return u switch { _object_null => true, _ => false }; Diagnostic(ErrorCode.ERR_UnionMatchingWrongPattern, "_object_null").WithArguments("S1").WithLocation(17, 27), // (17,27): error CS0266: Cannot implicitly convert type 'object' to 'int'. An explicit conversion exists (are you missing a cast?) // return u switch { _object_null => true, _ => false }; Diagnostic(ErrorCode.ERR_NoImplicitConvCast, "_object_null").WithArguments("object", "int").WithLocation(17, 27), // (17,27): error CS0266: Cannot implicitly convert type 'object' to 'string'. An explicit conversion exists (are you missing a cast?) // return u switch { _object_null => true, _ => false }; Diagnostic(ErrorCode.ERR_NoImplicitConvCast, "_object_null").WithArguments("object", "string").WithLocation(17, 27), // (22,21): error CS9372: An expression of type 'S1' cannot be handled by this pattern, see additional errors at this location. // return u is _object_null; Diagnostic(ErrorCode.ERR_UnionMatchingWrongPattern, "_object_null").WithArguments("S1").WithLocation(22, 21), // (22,21): error CS0266: Cannot implicitly convert type 'object' to 'int'. An explicit conversion exists (are you missing a cast?) // return u is _object_null; Diagnostic(ErrorCode.ERR_NoImplicitConvCast, "_object_null").WithArguments("object", "int").WithLocation(22, 21), // (22,21): error CS0266: Cannot implicitly convert type 'object' to 'string'. An explicit conversion exists (are you missing a cast?) // return u is _object_null; Diagnostic(ErrorCode.ERR_NoImplicitConvCast, "_object_null").WithArguments("object", "string").WithLocation(22, 21), // (29,18): error CS9372: An expression of type 'S1' cannot be handled by this pattern, see additional errors at this location. // case _object_null: return true; Diagnostic(ErrorCode.ERR_UnionMatchingWrongPattern, "_object_null").WithArguments("S1").WithLocation(29, 18), // (29,18): error CS0266: Cannot implicitly convert type 'object' to 'int'. An explicit conversion exists (are you missing a cast?) // case _object_null: return true; Diagnostic(ErrorCode.ERR_NoImplicitConvCast, "_object_null").WithArguments("object", "int").WithLocation(29, 18), // (29,18): error CS0266: Cannot implicitly convert type 'object' to 'string'. An explicit conversion exists (are you missing a cast?) // case _object_null: return true; Diagnostic(ErrorCode.ERR_NoImplicitConvCast, "_object_null").WithArguments("object", "string").WithLocation(29, 18) ); } [Fact] public void UnionMatching_07_Constant_03() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } public object Value => _value; } class Program { static void Main() { System.Console.Write(Test1(new S1(10))); System.Console.Write(Test1(default(S1))); System.Console.Write(Test1(new S1(""11""))); System.Console.Write(Test1(new S1(0))); System.Console.Write(Test1(null)); System.Console.Write(' '); System.Console.Write(Test10(new S1(10))); System.Console.Write(Test10(default(S1))); System.Console.Write(Test10(new S1(""11""))); System.Console.Write(Test10(new S1(0))); System.Console.Write(Test10(null)); System.Console.Write(' '); System.Console.Write(Test100(new S1(10))); System.Console.Write(Test100(default(S1))); System.Console.Write(Test100(new S1(""11""))); System.Console.Write(Test100(new S1(0))); System.Console.Write(Test100(null)); } const int _int_10 = 10; static bool Test1(S1? u) { return u switch { _int_10 => true, _ => false }; } static bool Test10(S1? u) { return u is _int_10; } static bool Test100(S1? u) { switch (u) { case _int_10: return true; }; return false; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); CompileAndVerify(comp, expectedOutput: "TrueFalseFalseFalseFalse TrueFalseFalseFalseFalse TrueFalseFalseFalseFalse").VerifyDiagnostics(); } [Fact] public void UnionMatching_07_Constant_04() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } public object Value => _value; } class Program { const string _string_null = null; const object _object_null = null; static bool Test4(S1? u) { return u switch { _string_null => true, _ => false }; } static bool Test5(S1? u) { return u switch { _object_null => true, _ => false }; } static bool Test40(S1? u) { return u is _string_null; } static bool Test50(S1? u) { return u is _object_null; } static bool Test400(S1? u) { switch (u) { case _string_null: return true; }; return false; } static bool Test500(S1? u) { switch (u) { case _object_null: return true; }; return false; } } "; var comp = CreateCompilation([src, UnionAttributeSource]); comp.VerifyDiagnostics( // (18,27): error CS9135: A constant value of type 'S1' is expected // return u switch { _string_null => true, _ => false }; Diagnostic(ErrorCode.ERR_ConstantValueOfTypeExpected, "_string_null").WithArguments("S1").WithLocation(18, 27), // (23,27): error CS9372: An expression of type 'S1' cannot be handled by this pattern, see additional errors at this location. // return u switch { _object_null => true, _ => false }; Diagnostic(ErrorCode.ERR_UnionMatchingWrongPattern, "_object_null").WithArguments("S1").WithLocation(23, 27), // (23,27): error CS0266: Cannot implicitly convert type 'object' to 'int'. An explicit conversion exists (are you missing a cast?) // return u switch { _object_null => true, _ => false }; Diagnostic(ErrorCode.ERR_NoImplicitConvCast, "_object_null").WithArguments("object", "int").WithLocation(23, 27), // (23,27): error CS0266: Cannot implicitly convert type 'object' to 'string'. An explicit conversion exists (are you missing a cast?) // return u switch { _object_null => true, _ => false }; Diagnostic(ErrorCode.ERR_NoImplicitConvCast, "_object_null").WithArguments("object", "string").WithLocation(23, 27), // (28,21): error CS9135: A constant value of type 'S1' is expected // return u is _string_null; Diagnostic(ErrorCode.ERR_ConstantValueOfTypeExpected, "_string_null").WithArguments("S1").WithLocation(28, 21), // (33,21): error CS9372: An expression of type 'S1' cannot be handled by this pattern, see additional errors at this location. // return u is _object_null; Diagnostic(ErrorCode.ERR_UnionMatchingWrongPattern, "_object_null").WithArguments("S1").WithLocation(33, 21), // (33,21): error CS0266: Cannot implicitly convert type 'object' to 'int'. An explicit conversion exists (are you missing a cast?) // return u is _object_null; Diagnostic(ErrorCode.ERR_NoImplicitConvCast, "_object_null").WithArguments("object", "int").WithLocation(33, 21), // (33,21): error CS0266: Cannot implicitly convert type 'object' to 'string'. An explicit conversion exists (are you missing a cast?) // return u is _object_null; Diagnostic(ErrorCode.ERR_NoImplicitConvCast, "_object_null").WithArguments("object", "string").WithLocation(33, 21), // (40,18): error CS9135: A constant value of type 'S1' is expected // case _string_null: return true; Diagnostic(ErrorCode.ERR_ConstantValueOfTypeExpected, "_string_null").WithArguments("S1").WithLocation(40, 18), // (50,18): error CS9372: An expression of type 'S1' cannot be handled by this pattern, see additional errors at this location. // case _object_null: return true; Diagnostic(ErrorCode.ERR_UnionMatchingWrongPattern, "_object_null").WithArguments("S1").WithLocation(50, 18), // (50,18): error CS0266: Cannot implicitly convert type 'object' to 'int'. An explicit conversion exists (are you missing a cast?) // case _object_null: return true; Diagnostic(ErrorCode.ERR_NoImplicitConvCast, "_object_null").WithArguments("object", "int").WithLocation(50, 18), // (50,18): error CS0266: Cannot implicitly convert type 'object' to 'string'. An explicit conversion exists (are you missing a cast?) // case _object_null: return true; Diagnostic(ErrorCode.ERR_NoImplicitConvCast, "_object_null").WithArguments("object", "string").WithLocation(50, 18) ); } [Fact] public void UnionMatching_07_Constant_05() { var src = @" [System.Runtime.CompilerServices.Union] class S1 { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } public S1(S1 x) { _value = x; } public object Value => _value; } class Program { static void Main() { System.Console.Write(Test1(new S1(10))); System.Console.Write(Test1(null)); System.Console.Write(Test1(new S1(""11""))); System.Console.Write(Test1(new S1(0))); System.Console.Write(' '); System.Console.Write(Test4(new S1(11))); System.Console.Write(Test4(null)); System.Console.Write(Test4(new S1(""11""))); System.Console.Write(Test4(new S1((string)null))); System.Console.Write(' '); System.Console.Write(Test10(new S1(10))); System.Console.Write(Test10(null)); System.Console.Write(Test10(new S1(""11""))); System.Console.Write(Test10(new S1(0))); System.Console.Write(' '); System.Console.Write(Test40(new S1(11))); System.Console.Write(Test40(null)); System.Console.Write(Test40(new S1(""11""))); System.Console.Write(Test40(new S1((string)null))); System.Console.Write(' '); System.Console.Write(Test100(new S1(10))); System.Console.Write(Test100(null)); System.Console.Write(Test100(new S1(""11""))); System.Console.Write(Test100(new S1(0))); System.Console.Write(' '); System.Console.Write(Test400(new S1(11))); System.Console.Write(Test400(null)); System.Console.Write(Test400(new S1(""11""))); System.Console.Write(Test400(new S1((string)null))); } const int _int_10 = 10; const S1 _S1_null = null; static bool Test1(S1 u) { return u switch { _int_10 => true, _ => false }; } static bool Test4(S1 u) { return u switch { _S1_null => true, _ => false }; } static bool Test10(S1 u) { return u is _int_10; } static bool Test40(S1 u) { return u is _S1_null; } static bool Test100(S1 u) { switch (u) { case _int_10: return true; }; return false; } static bool Test400(S1 u) { switch (u) { case _S1_null: return true; }; return false; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); var verifier = CompileAndVerify(comp, expectedOutput: "TrueFalseFalseFalse FalseTrueFalseTrue TrueFalseFalseFalse FalseTrueFalseTrue TrueFalseFalseFalse FalseTrueFalseTrue").VerifyDiagnostics(); verifier.VerifyIL("Program.Test4", @" { // Code size 19 (0x13) .maxstack 1 .locals init (bool V_0) IL_0000: ldarg.0 IL_0001: brfalse.s IL_000b IL_0003: ldarg.0 IL_0004: callvirt ""object S1.Value.get"" IL_0009: brtrue.s IL_000f IL_000b: ldc.i4.1 IL_000c: stloc.0 IL_000d: br.s IL_0011 IL_000f: ldc.i4.0 IL_0010: stloc.0 IL_0011: ldloc.0 IL_0012: ret } "); verifier.VerifyIL("Program.Test40", @" { // Code size 19 (0x13) .maxstack 1 .locals init (bool V_0) IL_0000: ldarg.0 IL_0001: brfalse.s IL_000b IL_0003: ldarg.0 IL_0004: callvirt ""object S1.Value.get"" IL_0009: brtrue.s IL_000f IL_000b: ldc.i4.1 IL_000c: stloc.0 IL_000d: br.s IL_0011 IL_000f: ldc.i4.0 IL_0010: stloc.0 IL_0011: ldloc.0 IL_0012: ret } "); verifier.VerifyIL("Program.Test400", @" { // Code size 15 (0xf) .maxstack 1 IL_0000: ldarg.0 IL_0001: brfalse.s IL_000b IL_0003: ldarg.0 IL_0004: callvirt ""object S1.Value.get"" IL_0009: brtrue.s IL_000d IL_000b: ldc.i4.1 IL_000c: ret IL_000d: ldc.i4.0 IL_000e: ret } "); } [Fact] public void UnionMatching_07_Constant_06() { var src = @" [System.Runtime.CompilerServices.Union] class S1 { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } public object Value => _value; } class Program { const string _string_null = null; const object _object_null = null; static bool Test4(S1 u) { return u switch { _string_null => true, _ => false }; } static bool Test5(S1 u) { return u switch { _object_null => true, _ => false }; } static bool Test40(S1 u) { return u is _string_null; } static bool Test50(S1 u) { return u is _object_null; } static bool Test400(S1 u) { switch (u) { case _string_null: return true; }; return false; } static bool Test500(S1 u) { switch (u) { case _object_null: return true; }; return false; } } "; var comp = CreateCompilation([src, UnionAttributeSource]); comp.VerifyDiagnostics( // (18,27): error CS9135: A constant value of type 'S1' is expected // return u switch { _string_null => true, _ => false }; Diagnostic(ErrorCode.ERR_ConstantValueOfTypeExpected, "_string_null").WithArguments("S1").WithLocation(18, 27), // (23,27): error CS9372: An expression of type 'S1' cannot be handled by this pattern, see additional errors at this location. // return u switch { _object_null => true, _ => false }; Diagnostic(ErrorCode.ERR_UnionMatchingWrongPattern, "_object_null").WithArguments("S1").WithLocation(23, 27), // (23,27): error CS0266: Cannot implicitly convert type 'object' to 'int'. An explicit conversion exists (are you missing a cast?) // return u switch { _object_null => true, _ => false }; Diagnostic(ErrorCode.ERR_NoImplicitConvCast, "_object_null").WithArguments("object", "int").WithLocation(23, 27), // (23,27): error CS0266: Cannot implicitly convert type 'object' to 'string'. An explicit conversion exists (are you missing a cast?) // return u switch { _object_null => true, _ => false }; Diagnostic(ErrorCode.ERR_NoImplicitConvCast, "_object_null").WithArguments("object", "string").WithLocation(23, 27), // (28,21): error CS9135: A constant value of type 'S1' is expected // return u is _string_null; Diagnostic(ErrorCode.ERR_ConstantValueOfTypeExpected, "_string_null").WithArguments("S1").WithLocation(28, 21), // (33,21): error CS9372: An expression of type 'S1' cannot be handled by this pattern, see additional errors at this location. // return u is _object_null; Diagnostic(ErrorCode.ERR_UnionMatchingWrongPattern, "_object_null").WithArguments("S1").WithLocation(33, 21), // (33,21): error CS0266: Cannot implicitly convert type 'object' to 'int'. An explicit conversion exists (are you missing a cast?) // return u is _object_null; Diagnostic(ErrorCode.ERR_NoImplicitConvCast, "_object_null").WithArguments("object", "int").WithLocation(33, 21), // (33,21): error CS0266: Cannot implicitly convert type 'object' to 'string'. An explicit conversion exists (are you missing a cast?) // return u is _object_null; Diagnostic(ErrorCode.ERR_NoImplicitConvCast, "_object_null").WithArguments("object", "string").WithLocation(33, 21), // (40,18): error CS9135: A constant value of type 'S1' is expected // case _string_null: return true; Diagnostic(ErrorCode.ERR_ConstantValueOfTypeExpected, "_string_null").WithArguments("S1").WithLocation(40, 18), // (50,18): error CS9372: An expression of type 'S1' cannot be handled by this pattern, see additional errors at this location. // case _object_null: return true; Diagnostic(ErrorCode.ERR_UnionMatchingWrongPattern, "_object_null").WithArguments("S1").WithLocation(50, 18), // (50,18): error CS0266: Cannot implicitly convert type 'object' to 'int'. An explicit conversion exists (are you missing a cast?) // case _object_null: return true; Diagnostic(ErrorCode.ERR_NoImplicitConvCast, "_object_null").WithArguments("object", "int").WithLocation(50, 18), // (50,18): error CS0266: Cannot implicitly convert type 'object' to 'string'. An explicit conversion exists (are you missing a cast?) // case _object_null: return true; Diagnostic(ErrorCode.ERR_NoImplicitConvCast, "_object_null").WithArguments("object", "string").WithLocation(50, 18) ); } [Fact] public void UnionMatching_08_Recursive_Property_01() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 { private readonly object _value; public S1(S2<int> x) { _value = x; } public S1(S2<string> x) { _value = x; } public S1(S2<object> x) { _value = x; } public object Value => _value; } struct S2<T> { public T Value; } class A; class B; class Program { static void Main() { System.Console.Write(Test1(new S1(new S2<int>() { Value = 10 }))); System.Console.Write(Test1(default)); System.Console.Write(Test1(new S1(new S2<string>() { Value = ""11"" }))); System.Console.Write(Test1(new S1(new S2<int>() { Value = 0 }))); System.Console.Write(' '); System.Console.Write(Test2(new S1(new S2<int>() { Value = 10 }))); System.Console.Write(Test2(default)); System.Console.Write(Test2(new S1(new S2<string>() { Value = ""11"" }))); System.Console.Write(Test2(new S1(new S2<int>() { Value = 0 }))); System.Console.Write(Test2(new S1(new S2<int>() { Value = 11 }))); System.Console.Write(' '); System.Console.Write(Test3(new S1(new S2<int>() { Value = 11 }))); System.Console.Write(Test3(default)); System.Console.Write(Test3(new S1(new S2<string>() { Value = ""11"" }))); } static bool Test1(S1 u) { return u is S2<int> { Value: 10 }; } static bool Test2(S1 u) { return u is S2<int> { Value: 10 or 11 }; } static bool Test3(S1 u) { return u is S2<string> { Value: ""11"" } and { Value: ['1', '1'] }; } static bool Test4(S1 u) { #line 58 return u is S2<object> { Value: not A or B }; } } "; var comp = CreateCompilation([src, UnionAttributeSource], targetFramework: TargetFramework.NetCoreApp, options: TestOptions.ReleaseExe); CompileAndVerify(comp, expectedOutput: ExecutionConditionUtil.IsMonoOrCoreClr ? "TrueFalseFalseFalse TrueFalseFalseFalseTrue FalseFalseTrue" : null, verify: Verification.FailsPEVerify).VerifyDiagnostics( // (58,50): warning CS9336: The pattern is redundant. // return u is S2<object> { Value: not A or B }; Diagnostic(ErrorCode.WRN_RedundantPattern, "B").WithLocation(58, 50) ); comp = CreateCompilation([src, UnionAttributeSource], targetFramework: TargetFramework.NetCoreApp, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular15); CompileAndVerify(comp, expectedOutput: ExecutionConditionUtil.IsMonoOrCoreClr ? "TrueFalseFalseFalse TrueFalseFalseFalseTrue FalseFalseTrue" : null, verify: Verification.FailsPEVerify).VerifyDiagnostics( // (58,50): warning CS9336: The pattern is redundant. // return u is S2<object> { Value: not A or B }; Diagnostic(ErrorCode.WRN_RedundantPattern, "B").WithLocation(58, 50) ); comp = CreateCompilation([src, UnionAttributeSource], targetFramework: TargetFramework.NetCoreApp, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular14); comp.VerifyDiagnostics( // (44,21): error CS9327: Feature 'unions' is not available in C# 14.0. Please use language version 15.0 or greater. // return u is S2<int> { Value: 10 }; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion14, "S2<int> { Value: 10 }").WithArguments("unions", "15.0").WithLocation(44, 21), // (49,21): error CS9327: Feature 'unions' is not available in C# 14.0. Please use language version 15.0 or greater. // return u is S2<int> { Value: 10 or 11 }; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion14, "S2<int> { Value: 10 or 11 }").WithArguments("unions", "15.0").WithLocation(49, 21), // (54,21): error CS9327: Feature 'unions' is not available in C# 14.0. Please use language version 15.0 or greater. // return u is S2<string> { Value: "11" } and { Value: ['1', '1'] }; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion14, @"S2<string> { Value: ""11"" }").WithArguments("unions", "15.0").WithLocation(54, 21), // (58,21): error CS9327: Feature 'unions' is not available in C# 14.0. Please use language version 15.0 or greater. // return u is S2<object> { Value: not A or B }; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion14, "S2<object> { Value: not A or B }").WithArguments("unions", "15.0").WithLocation(58, 21), // (58,50): warning CS9336: The pattern is redundant. // return u is S2<object> { Value: not A or B }; Diagnostic(ErrorCode.WRN_RedundantPattern, "B").WithLocation(58, 50) ); } [Fact] public void UnionMatching_08_Recursive_Property_02() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 { private readonly object _value; public S1(S2<int> x) { _value = x; } public S1(S2<string> x) { _value = x; } public S1(S2<object> x) { _value = x; } public object Value => _value; } struct S2<T> { public T Value; } class A; class B; class Program { static void Main() { System.Console.Write(Test1(new S1(new S2<int>() { Value = 10 }))); System.Console.Write(Test1(default(S1))); System.Console.Write(Test1(new S1(new S2<string>() { Value = ""11"" }))); System.Console.Write(Test1(new S1(new S2<int>() { Value = 0 }))); System.Console.Write(Test1(null)); System.Console.Write(' '); System.Console.Write(Test2(new S1(new S2<int>() { Value = 10 }))); System.Console.Write(Test2(default(S1))); System.Console.Write(Test2(new S1(new S2<string>() { Value = ""11"" }))); System.Console.Write(Test2(new S1(new S2<int>() { Value = 0 }))); System.Console.Write(Test2(new S1(new S2<int>() { Value = 11 }))); System.Console.Write(Test2(null)); System.Console.Write(' '); System.Console.Write(Test3(new S1(new S2<int>() { Value = 11 }))); System.Console.Write(Test3(default(S1))); System.Console.Write(Test3(new S1(new S2<string>() { Value = ""11"" }))); System.Console.Write(Test3(null)); } static bool Test1(S1? u) { return u is S2<int> { Value: 10 }; } static bool Test2(S1? u) { return u is S2<int> { Value: 10 or 11 }; } static bool Test3(S1? u) { return u is S2<string> { Value: ""11"" } and { Value: ['1', '1'] }; } static bool Test4(S1? u) { #line 58 return u is S2<object> { Value: not A or B }; } } "; var comp = CreateCompilation([src, UnionAttributeSource], targetFramework: TargetFramework.NetCoreApp, options: TestOptions.ReleaseExe); CompileAndVerify(comp, expectedOutput: ExecutionConditionUtil.IsMonoOrCoreClr ? "TrueFalseFalseFalseFalse TrueFalseFalseFalseTrueFalse FalseFalseTrueFalse" : null, verify: Verification.FailsPEVerify).VerifyDiagnostics( // (58,50): warning CS9336: The pattern is redundant. // return u is S2<object> { Value: not A or B }; Diagnostic(ErrorCode.WRN_RedundantPattern, "B").WithLocation(58, 50) ); comp = CreateCompilation([src, UnionAttributeSource], targetFramework: TargetFramework.NetCoreApp, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular15); CompileAndVerify(comp, expectedOutput: ExecutionConditionUtil.IsMonoOrCoreClr ? "TrueFalseFalseFalseFalse TrueFalseFalseFalseTrueFalse FalseFalseTrueFalse" : null, verify: Verification.FailsPEVerify).VerifyDiagnostics( // (58,50): warning CS9336: The pattern is redundant. // return u is S2<object> { Value: not A or B }; Diagnostic(ErrorCode.WRN_RedundantPattern, "B").WithLocation(58, 50) ); comp = CreateCompilation([src, UnionAttributeSource], targetFramework: TargetFramework.NetCoreApp, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular14); comp.VerifyDiagnostics( // (47,21): error CS9327: Feature 'unions' is not available in C# 14.0. Please use language version 15.0 or greater. // return u is S2<int> { Value: 10 }; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion14, "S2<int> { Value: 10 }").WithArguments("unions", "15.0").WithLocation(47, 21), // (52,21): error CS9327: Feature 'unions' is not available in C# 14.0. Please use language version 15.0 or greater. // return u is S2<int> { Value: 10 or 11 }; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion14, "S2<int> { Value: 10 or 11 }").WithArguments("unions", "15.0").WithLocation(52, 21), // (57,21): error CS9327: Feature 'unions' is not available in C# 14.0. Please use language version 15.0 or greater. // return u is S2<string> { Value: "11" } and { Value: ['1', '1'] }; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion14, @"S2<string> { Value: ""11"" }").WithArguments("unions", "15.0").WithLocation(57, 21), // (58,21): error CS9327: Feature 'unions' is not available in C# 14.0. Please use language version 15.0 or greater. // return u is S2<object> { Value: not A or B }; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion14, "S2<object> { Value: not A or B }").WithArguments("unions", "15.0").WithLocation(58, 21), // (58,50): warning CS9336: The pattern is redundant. // return u is S2<object> { Value: not A or B }; Diagnostic(ErrorCode.WRN_RedundantPattern, "B").WithLocation(58, 50) ); } [Fact] public void UnionMatching_08_Recursive_Property_03() { var src = @" [System.Runtime.CompilerServices.Union] class S1 { private readonly object _value; public S1(S2<int> x) { _value = x; } public S1(S2<string> x) { _value = x; } public S1(S2<object> x) { _value = x; } public object Value => _value; } struct S2<T> { public T Value; } class A; class B; class Program { static void Main() { System.Console.Write(Test1(new S1(new S2<int>() { Value = 10 }))); System.Console.Write(Test1(new S1(new S2<string>() { Value = ""11"" }))); System.Console.Write(Test1(new S1(new S2<int>() { Value = 0 }))); System.Console.Write(Test1(null)); System.Console.Write(' '); System.Console.Write(Test2(new S1(new S2<int>() { Value = 10 }))); System.Console.Write(Test2(new S1(new S2<string>() { Value = ""11"" }))); System.Console.Write(Test2(new S1(new S2<int>() { Value = 0 }))); System.Console.Write(Test2(new S1(new S2<int>() { Value = 11 }))); System.Console.Write(Test2(null)); System.Console.Write(' '); System.Console.Write(Test3(new S1(new S2<int>() { Value = 11 }))); System.Console.Write(Test3(new S1(new S2<string>() { Value = ""11"" }))); System.Console.Write(Test3(null)); } static bool Test1(S1 u) { return u is S2<int> { Value: 10 }; } static bool Test2(S1 u) { return u is S2<int> { Value: 10 or 11 }; } static bool Test3(S1 u) { return u is S2<string> { Value: ""11"" } and { Value: ['1', '1'] }; } static bool Test4(S1 u) { #line 58 return u is S2<object> { Value: not A or B }; } } "; var comp = CreateCompilation([src, UnionAttributeSource], targetFramework: TargetFramework.NetCoreApp, options: TestOptions.ReleaseExe); CompileAndVerify(comp, expectedOutput: ExecutionConditionUtil.IsMonoOrCoreClr ? "TrueFalseFalseFalse TrueFalseFalseTrueFalse FalseTrueFalse" : null, verify: Verification.FailsPEVerify).VerifyDiagnostics( // (58,50): warning CS9336: The pattern is redundant. // return u is S2<object> { Value: not A or B }; Diagnostic(ErrorCode.WRN_RedundantPattern, "B").WithLocation(58, 50) ); } [Fact] public void UnionMatching_09_Recursive_ITuple() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 { private readonly object _value; public S1(int x) { _value = x; } public S1(C x) { _value = x; } public object Value => _value; } class Program { static void Main() { System.Console.Write(Test1(new S1(10))); System.Console.Write(Test1(default)); System.Console.Write(Test1(new S1(new C()))); System.Console.Write(' '); System.Console.Write(Test2(new S1(10))); System.Console.Write(Test2(default(S1))); System.Console.Write(Test2(new S1(new C()))); System.Console.Write(Test2(null)); } static bool Test1(S1 u) { return u is (_, 10); } static bool Test2(S1? u) { return u is (_, 10); } } public class C : System.Runtime.CompilerServices.ITuple { int System.Runtime.CompilerServices.ITuple.Length => 2; object System.Runtime.CompilerServices.ITuple.this[int i] => i * 10; } "; var comp = CreateCompilation([src, UnionAttributeSource], targetFramework: TargetFramework.NetCoreApp, options: TestOptions.ReleaseExe); comp.VerifyDiagnostics( // (27,21): error CS1061: 'S1' does not contain a definition for 'Deconstruct' and no accessible extension method 'Deconstruct' accepting a first argument of type 'S1' could be found (are you missing a using directive or an assembly reference?) // return u is (_, 10); Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "(_, 10)").WithArguments("S1", "Deconstruct").WithLocation(27, 21), // (27,21): error CS8129: No suitable 'Deconstruct' instance or extension method was found for type 'S1', with 2 out parameters and a void return type. // return u is (_, 10); Diagnostic(ErrorCode.ERR_MissingDeconstruct, "(_, 10)").WithArguments("S1", "2").WithLocation(27, 21), // (32,21): error CS1061: 'S1' does not contain a definition for 'Deconstruct' and no accessible extension method 'Deconstruct' accepting a first argument of type 'S1' could be found (are you missing a using directive or an assembly reference?) // return u is (_, 10); Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "(_, 10)").WithArguments("S1", "Deconstruct").WithLocation(32, 21), // (32,21): error CS8129: No suitable 'Deconstruct' instance or extension method was found for type 'S1', with 2 out parameters and a void return type. // return u is (_, 10); Diagnostic(ErrorCode.ERR_MissingDeconstruct, "(_, 10)").WithArguments("S1", "2").WithLocation(32, 21) ); } [Fact] public void UnionMatching_10_Recursive_Deconstruct_01() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 { private readonly object _value; public S1(S2<int> x) { _value = x; } public S1(S2<string> x) { _value = x; } public S1(S2<object> x) { _value = x; } public object Value => _value; } struct S2<T> { public T Value; public void Deconstruct(out T value, out int x) { value = Value; x = 0; } } class A; class B; class Program { static void Main() { System.Console.Write(Test1(new S1(new S2<int>() { Value = 10 }))); System.Console.Write(Test1(default)); System.Console.Write(Test1(new S1(new S2<string>() { Value = ""11"" }))); System.Console.Write(Test1(new S1(new S2<int>() { Value = 0 }))); System.Console.Write(' '); System.Console.Write(Test2(new S1(new S2<int>() { Value = 10 }))); System.Console.Write(Test2(default)); System.Console.Write(Test2(new S1(new S2<string>() { Value = ""11"" }))); System.Console.Write(Test2(new S1(new S2<int>() { Value = 0 }))); System.Console.Write(Test2(new S1(new S2<int>() { Value = 11 }))); System.Console.Write(' '); System.Console.Write(Test3(new S1(new S2<int>() { Value = 11 }))); System.Console.Write(Test3(default)); System.Console.Write(Test3(new S1(new S2<string>() { Value = ""11"" }))); } static bool Test1(S1 u) { return u is S2<int> (10, _); } static bool Test2(S1 u) { return u is S2<int> (10 or 11, _); } static bool Test3(S1 u) { return u is S2<string> (""11"", _) and (['1', '1'], _); } } "; var comp = CreateCompilation([src, UnionAttributeSource], targetFramework: TargetFramework.NetCoreApp, options: TestOptions.ReleaseExe); CompileAndVerify(comp, expectedOutput: ExecutionConditionUtil.IsMonoOrCoreClr ? "TrueFalseFalseFalse TrueFalseFalseFalseTrue FalseFalseTrue" : null, verify: Verification.FailsPEVerify).VerifyDiagnostics(); comp = CreateCompilation([src, UnionAttributeSource], targetFramework: TargetFramework.NetCoreApp, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular15); CompileAndVerify(comp, expectedOutput: ExecutionConditionUtil.IsMonoOrCoreClr ? "TrueFalseFalseFalse TrueFalseFalseFalseTrue FalseFalseTrue" : null, verify: Verification.FailsPEVerify).VerifyDiagnostics(); comp = CreateCompilation([src, UnionAttributeSource], targetFramework: TargetFramework.NetCoreApp, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular14); comp.VerifyDiagnostics( // (50,21): error CS9327: Feature 'unions' is not available in C# 14.0. Please use language version 15.0 or greater. // return u is S2<int> (10, _); Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion14, "S2<int> (10, _)").WithArguments("unions", "15.0").WithLocation(50, 21), // (55,21): error CS9327: Feature 'unions' is not available in C# 14.0. Please use language version 15.0 or greater. // return u is S2<int> (10 or 11, _); Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion14, "S2<int> (10 or 11, _)").WithArguments("unions", "15.0").WithLocation(55, 21), // (60,21): error CS9327: Feature 'unions' is not available in C# 14.0. Please use language version 15.0 or greater. // return u is S2<string> ("11", _) and (['1', '1'], _); Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion14, @"S2<string> (""11"", _)").WithArguments("unions", "15.0").WithLocation(60, 21) ); } [Fact] public void UnionMatching_10_Recursive_Deconstruct_02() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 { private readonly object _value; public S1(S2<int> x) { _value = x; } public S1(S2<string> x) { _value = x; } public S1(S2<object> x) { _value = x; } public object Value => _value; } struct S2<T> { public T Value; public void Deconstruct(out T value, out int x) { value = Value; x = 0; } } class A; class B; class Program { static void Main() { System.Console.Write(Test1(new S1(new S2<int>() { Value = 10 }))); System.Console.Write(Test1(default(S1))); System.Console.Write(Test1(new S1(new S2<string>() { Value = ""11"" }))); System.Console.Write(Test1(new S1(new S2<int>() { Value = 0 }))); System.Console.Write(Test1(null)); System.Console.Write(' '); System.Console.Write(Test2(new S1(new S2<int>() { Value = 10 }))); System.Console.Write(Test2(default(S1))); System.Console.Write(Test2(new S1(new S2<string>() { Value = ""11"" }))); System.Console.Write(Test2(new S1(new S2<int>() { Value = 0 }))); System.Console.Write(Test2(new S1(new S2<int>() { Value = 11 }))); System.Console.Write(Test2(null)); System.Console.Write(' '); System.Console.Write(Test3(new S1(new S2<int>() { Value = 11 }))); System.Console.Write(Test3(default(S1))); System.Console.Write(Test3(new S1(new S2<string>() { Value = ""11"" }))); System.Console.Write(Test3(null)); } static bool Test1(S1? u) { return u is S2<int> (10, _); } static bool Test2(S1? u) { return u is S2<int> (10 or 11, _); } static bool Test3(S1? u) { return u is S2<string> (""11"", _) and (['1', '1'], _); } } "; var comp = CreateCompilation([src, UnionAttributeSource], targetFramework: TargetFramework.NetCoreApp, options: TestOptions.ReleaseExe); CompileAndVerify(comp, expectedOutput: ExecutionConditionUtil.IsMonoOrCoreClr ? "TrueFalseFalseFalseFalse TrueFalseFalseFalseTrueFalse FalseFalseTrueFalse" : null, verify: Verification.FailsPEVerify).VerifyDiagnostics(); comp = CreateCompilation([src, UnionAttributeSource], targetFramework: TargetFramework.NetCoreApp, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular15); CompileAndVerify(comp, expectedOutput: ExecutionConditionUtil.IsMonoOrCoreClr ? "TrueFalseFalseFalseFalse TrueFalseFalseFalseTrueFalse FalseFalseTrueFalse" : null, verify: Verification.FailsPEVerify).VerifyDiagnostics(); comp = CreateCompilation([src, UnionAttributeSource], targetFramework: TargetFramework.NetCoreApp, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular14); comp.VerifyDiagnostics( // (53,21): error CS9327: Feature 'unions' is not available in C# 14.0. Please use language version 15.0 or greater. // return u is S2<int> (10, _); Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion14, "S2<int> (10, _)").WithArguments("unions", "15.0").WithLocation(53, 21), // (58,21): error CS9327: Feature 'unions' is not available in C# 14.0. Please use language version 15.0 or greater. // return u is S2<int> (10 or 11, _); Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion14, "S2<int> (10 or 11, _)").WithArguments("unions", "15.0").WithLocation(58, 21), // (63,21): error CS9327: Feature 'unions' is not available in C# 14.0. Please use language version 15.0 or greater. // return u is S2<string> ("11", _) and (['1', '1'], _); Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion14, @"S2<string> (""11"", _)").WithArguments("unions", "15.0").WithLocation(63, 21) ); } [Fact] public void UnionMatching_11_Type() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } public object Value => _value; } class Program { static void Main() { System.Console.Write(Test1(new S1(10))); System.Console.Write(Test1(default(S1))); System.Console.Write(Test1(new S1(""11""))); System.Console.Write(Test1(new S1(0))); System.Console.Write(' '); System.Console.Write(Test2(new S1(10))); System.Console.Write(Test2(default(S1))); System.Console.Write(Test2(new S1(""11""))); System.Console.Write(Test2(new S1(0))); System.Console.Write(Test2(null)); } static bool Test1(S1 u) { return u is int; } static bool Test2(S1? u) { return u is int; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); var verifier = CompileAndVerify(comp, expectedOutput: "TrueFalseFalseTrue TrueFalseFalseTrueFalse").VerifyDiagnostics(); var tree = comp.SyntaxTrees[0]; AssertEx.Equal(["u is int", "u is int"], tree.GetRoot().DescendantNodes().OfType<BinaryExpressionSyntax>().Select(b => b.ToString())); verifier.VerifyIL("Program.Test1", @" { // Code size 16 (0x10) .maxstack 2 IL_0000: ldarga.s V_0 IL_0002: call ""object S1.Value.get"" IL_0007: isinst ""int"" IL_000c: ldnull IL_000d: cgt.un IL_000f: ret } "); verifier.VerifyIL("Program.Test2", @" { // Code size 35 (0x23) .maxstack 2 .locals init (S1 V_0) IL_0000: ldarga.s V_0 IL_0002: call ""bool S1?.HasValue.get"" IL_0007: brfalse.s IL_0021 IL_0009: ldarga.s V_0 IL_000b: call ""S1 S1?.GetValueOrDefault()"" IL_0010: stloc.0 IL_0011: ldloca.s V_0 IL_0013: call ""object S1.Value.get"" IL_0018: isinst ""int"" IL_001d: ldnull IL_001e: cgt.un IL_0020: ret IL_0021: ldc.i4.0 IL_0022: ret } "); comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular15); CompileAndVerify(comp, expectedOutput: "TrueFalseFalseTrue TrueFalseFalseTrueFalse").VerifyDiagnostics(); comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular14); comp.VerifyDiagnostics( // (29,16): error CS9327: Feature 'unions' is not available in C# 14.0. Please use language version 15.0 or greater. // return u is int; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion14, "u is int").WithArguments("unions", "15.0").WithLocation(29, 16), // (34,16): error CS9327: Feature 'unions' is not available in C# 14.0. Please use language version 15.0 or greater. // return u is int; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion14, "u is int").WithArguments("unions", "15.0").WithLocation(34, 16) ); comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular6); comp.VerifyDiagnostics( // (29,16): warning CS0184: The given expression is never of the provided ('int') type // return u is int; Diagnostic(ErrorCode.WRN_IsAlwaysFalse, "u is int").WithArguments("int").WithLocation(29, 16), // (34,16): warning CS0184: The given expression is never of the provided ('int') type // return u is int; Diagnostic(ErrorCode.WRN_IsAlwaysFalse, "u is int").WithArguments("int").WithLocation(34, 16) ); } [Fact] public void UnionMatching_12_Type_01() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } public object Value => _value; } class Program { static void Main() { System.Console.Write(Test1(new S1(10))); System.Console.Write(Test1(default)); System.Console.Write(Test1(new S1(""11""))); System.Console.Write(Test1(new S1(0))); System.Console.Write(' '); System.Console.Write(Test3(new S1(11))); System.Console.Write(Test3(default)); System.Console.Write(Test3(new S1(""11""))); } static bool Test1(S1 u) { return u switch { int => true, _ => false }; } static bool Test3(S1 u) { return u is string and ['1', '1']; } } "; var comp = CreateCompilation([src, UnionAttributeSource], targetFramework: TargetFramework.NetCoreApp, options: TestOptions.ReleaseExe); CompileAndVerify(comp, expectedOutput: ExecutionConditionUtil.IsMonoOrCoreClr ? "TrueFalseFalseTrue FalseFalseTrue" : null, verify: Verification.FailsPEVerify).VerifyDiagnostics(); comp = CreateCompilation([src, UnionAttributeSource], targetFramework: TargetFramework.NetCoreApp, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular15); CompileAndVerify(comp, expectedOutput: ExecutionConditionUtil.IsMonoOrCoreClr ? "TrueFalseFalseTrue FalseFalseTrue" : null, verify: Verification.FailsPEVerify).VerifyDiagnostics(); comp = CreateCompilation([src, UnionAttributeSource], targetFramework: TargetFramework.NetCoreApp, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular14); comp.VerifyDiagnostics( // (28,27): error CS9327: Feature 'unions' is not available in C# 14.0. Please use language version 15.0 or greater. // return u switch { int => true, _ => false }; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion14, "int").WithArguments("unions", "15.0").WithLocation(28, 27), // (33,21): error CS9327: Feature 'unions' is not available in C# 14.0. Please use language version 15.0 or greater. // return u is string and ['1', '1']; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion14, "string").WithArguments("unions", "15.0").WithLocation(33, 21) ); } [Fact] public void UnionMatching_12_Type_02() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } public object Value => _value; } class Program { static void Main() { System.Console.Write(Test1(new S1(10))); System.Console.Write(Test1(default(S1))); System.Console.Write(Test1(new S1(""11""))); System.Console.Write(Test1(new S1(0))); System.Console.Write(Test1(null)); System.Console.Write(' '); System.Console.Write(Test3(new S1(11))); System.Console.Write(Test3(default(S1))); System.Console.Write(Test3(new S1(""11""))); System.Console.Write(Test3(null)); } static bool Test1(S1? u) { return u switch { int => true, _ => false }; } static bool Test3(S1? u) { return u is string and ['1', '1']; } } "; var comp = CreateCompilation([src, UnionAttributeSource], targetFramework: TargetFramework.NetCoreApp, options: TestOptions.ReleaseExe); CompileAndVerify(comp, expectedOutput: ExecutionConditionUtil.IsMonoOrCoreClr ? "TrueFalseFalseTrueFalse FalseFalseTrueFalse" : null, verify: Verification.FailsPEVerify).VerifyDiagnostics(); comp = CreateCompilation([src, UnionAttributeSource], targetFramework: TargetFramework.NetCoreApp, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular15); CompileAndVerify(comp, expectedOutput: ExecutionConditionUtil.IsMonoOrCoreClr ? "TrueFalseFalseTrueFalse FalseFalseTrueFalse" : null, verify: Verification.FailsPEVerify).VerifyDiagnostics(); comp = CreateCompilation([src, UnionAttributeSource], targetFramework: TargetFramework.NetCoreApp, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular14); comp.VerifyDiagnostics( // (30,27): error CS9327: Feature 'unions' is not available in C# 14.0. Please use language version 15.0 or greater. // return u switch { int => true, _ => false }; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion14, "int").WithArguments("unions", "15.0").WithLocation(30, 27), // (35,21): error CS9327: Feature 'unions' is not available in C# 14.0. Please use language version 15.0 or greater. // return u is string and ['1', '1']; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion14, "string").WithArguments("unions", "15.0").WithLocation(35, 21) ); } [Fact] public void UnionMatching_13_Declaration_01() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } public object Value => _value; } class Program { static void Main() { System.Console.Write(Test1(new S1(10))); System.Console.Write(Test1(default)); System.Console.Write(Test1(new S1(""11""))); System.Console.Write(Test1(new S1(0))); System.Console.Write(' '); System.Console.Write(Test2(new S1(10))); System.Console.Write(Test2(default)); System.Console.Write(Test2(new S1(""11""))); System.Console.Write(Test2(new S1(0))); System.Console.Write(Test2(new S1(11))); } static bool Test1(S1 u) { return u is int x; } static bool Test2(S1 u) { return u is int x ? (x == 10 || x == 11) : false; } } "; var comp = CreateCompilation([src, UnionAttributeSource], targetFramework: TargetFramework.NetLatest, options: TestOptions.ReleaseExe); CompileAndVerify(comp, expectedOutput: "TrueFalseFalseTrue TrueFalseFalseFalseTrue").VerifyDiagnostics(); comp = CreateCompilation([src, UnionAttributeSource], targetFramework: TargetFramework.NetLatest, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular15); CompileAndVerify(comp, expectedOutput: "TrueFalseFalseTrue TrueFalseFalseFalseTrue").VerifyDiagnostics(); comp = CreateCompilation([src, UnionAttributeSource], targetFramework: TargetFramework.NetLatest, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular14); comp.VerifyDiagnostics( // (30,21): error CS9327: Feature 'unions' is not available in C# 14.0. Please use language version 15.0 or greater. // return u is int x; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion14, "int x").WithArguments("unions", "15.0").WithLocation(30, 21), // (35,21): error CS9327: Feature 'unions' is not available in C# 14.0. Please use language version 15.0 or greater. // return u is int x ? (x == 10 || x == 11) : false; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion14, "int x").WithArguments("unions", "15.0").WithLocation(35, 21) ); } [Fact] public void UnionMatching_13_Declaration_02() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } public object Value => _value; } class Program { static void Main() { System.Console.Write(Test1(new S1(10))); System.Console.Write(Test1(default(S1))); System.Console.Write(Test1(new S1(""11""))); System.Console.Write(Test1(new S1(0))); System.Console.Write(Test1(null)); System.Console.Write(' '); System.Console.Write(Test2(new S1(10))); System.Console.Write(Test2(default(S1))); System.Console.Write(Test2(new S1(""11""))); System.Console.Write(Test2(new S1(0))); System.Console.Write(Test2(new S1(11))); System.Console.Write(Test2(null)); } static bool Test1(S1? u) { return u is int x; } static bool Test2(S1? u) { return u is int x ? (x == 10 || x == 11) : false; } } "; var comp = CreateCompilation([src, UnionAttributeSource], targetFramework: TargetFramework.NetLatest, options: TestOptions.ReleaseExe); CompileAndVerify(comp, expectedOutput: "TrueFalseFalseTrueFalse TrueFalseFalseFalseTrueFalse").VerifyDiagnostics(); comp = CreateCompilation([src, UnionAttributeSource], targetFramework: TargetFramework.NetLatest, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular15); CompileAndVerify(comp, expectedOutput: "TrueFalseFalseTrueFalse TrueFalseFalseFalseTrueFalse").VerifyDiagnostics(); comp = CreateCompilation([src, UnionAttributeSource], targetFramework: TargetFramework.NetLatest, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular14); comp.VerifyDiagnostics( // (32,21): error CS9327: Feature 'unions' is not available in C# 14.0. Please use language version 15.0 or greater. // return u is int x; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion14, "int x").WithArguments("unions", "15.0").WithLocation(32, 21), // (37,21): error CS9327: Feature 'unions' is not available in C# 14.0. Please use language version 15.0 or greater. // return u is int x ? (x == 10 || x == 11) : false; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion14, "int x").WithArguments("unions", "15.0").WithLocation(37, 21) ); } [Fact] public void UnionMatching_14_Negated_01() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } public object Value => _value; } class Program { static void Main() { System.Console.Write(Test1(new S1(10))); System.Console.Write(Test1(default)); System.Console.Write(Test1(new S1(""11""))); System.Console.Write(Test1(new S1(0))); System.Console.Write(' '); System.Console.Write(Test2(new S1(10))); System.Console.Write(Test2(default)); System.Console.Write(Test2(new S1(""11""))); System.Console.Write(Test2(new S1(0))); System.Console.Write(Test2(new S1(11))); System.Console.Write(' '); System.Console.Write(Test3(new S1(11))); System.Console.Write(Test3(default)); System.Console.Write(Test3(new S1(""11""))); System.Console.Write(' '); System.Console.Write(Test4(new S1(11))); System.Console.Write(Test4(default)); System.Console.Write(Test4(new S1(""11""))); System.Console.Write(' '); System.Console.Write(Test5(new S1(10))); System.Console.Write(Test5(default)); System.Console.Write(Test5(new S1(""11""))); System.Console.Write(Test5(new S1(0))); } static bool Test1(S1 u) { return u is not 10; } static bool Test2(S1 u) { return u is not (10 or 11); } static bool Test3(S1 u) { return u is not (""11"" and ['1', '1']); } static bool Test4(S1 u) { return u is not null; } static bool Test5(S1 u) { #line 66 return u is not ({ } and int); } } "; var comp = CreateCompilation([src, UnionAttributeSource], targetFramework: TargetFramework.NetCoreApp, options: TestOptions.ReleaseExe); CompileAndVerify(comp, expectedOutput: ExecutionConditionUtil.IsMonoOrCoreClr ? "FalseTrueTrueTrue FalseTrueTrueTrueFalse TrueTrueFalse TrueFalseTrue FalseTrueTrueFalse" : null, verify: Verification.FailsPEVerify).VerifyDiagnostics( ); comp = CreateCompilation([src, UnionAttributeSource], targetFramework: TargetFramework.NetCoreApp, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular15); CompileAndVerify(comp, expectedOutput: ExecutionConditionUtil.IsMonoOrCoreClr ? "FalseTrueTrueTrue FalseTrueTrueTrueFalse TrueTrueFalse TrueFalseTrue FalseTrueTrueFalse" : null, verify: Verification.FailsPEVerify).VerifyDiagnostics( ); comp = CreateCompilation([src, UnionAttributeSource], targetFramework: TargetFramework.NetCoreApp, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular14); comp.VerifyDiagnostics( // (46,25): error CS9327: Feature 'unions' is not available in C# 14.0. Please use language version 15.0 or greater. // return u is not 10; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion14, "10").WithArguments("unions", "15.0").WithLocation(46, 25), // (51,26): error CS9327: Feature 'unions' is not available in C# 14.0. Please use language version 15.0 or greater. // return u is not (10 or 11); Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion14, "10").WithArguments("unions", "15.0").WithLocation(51, 26), // (51,32): error CS9327: Feature 'unions' is not available in C# 14.0. Please use language version 15.0 or greater. // return u is not (10 or 11); Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion14, "11").WithArguments("unions", "15.0").WithLocation(51, 32), // (56,26): error CS9327: Feature 'unions' is not available in C# 14.0. Please use language version 15.0 or greater. // return u is not ("11" and ['1', '1']); Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion14, @"""11""").WithArguments("unions", "15.0").WithLocation(56, 26), // (61,25): error CS9327: Feature 'unions' is not available in C# 14.0. Please use language version 15.0 or greater. // return u is not null; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion14, "null").WithArguments("unions", "15.0").WithLocation(61, 25), // (66,34): error CS9327: Feature 'unions' is not available in C# 14.0. Please use language version 15.0 or greater. // return u is not ({ } and int); Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion14, "int").WithArguments("unions", "15.0").WithLocation(66, 34) ); } [Fact] public void UnionMatching_14_Negated_02() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } public object Value => _value; } class Program { static void Main() { System.Console.Write(Test1(new S1(10))); System.Console.Write(Test1(default(S1))); System.Console.Write(Test1(new S1(""11""))); System.Console.Write(Test1(new S1(0))); System.Console.Write(Test1(null)); System.Console.Write(' '); System.Console.Write(Test2(new S1(10))); System.Console.Write(Test2(default(S1))); System.Console.Write(Test2(new S1(""11""))); System.Console.Write(Test2(new S1(0))); System.Console.Write(Test2(new S1(11))); System.Console.Write(Test2(null)); System.Console.Write(' '); System.Console.Write(Test3(new S1(11))); System.Console.Write(Test3(default(S1))); System.Console.Write(Test3(new S1(""11""))); System.Console.Write(Test3(null)); System.Console.Write(' '); System.Console.Write(Test4(new S1(11))); System.Console.Write(Test4(default(S1))); System.Console.Write(Test4(new S1(""11""))); System.Console.Write(Test4(null)); System.Console.Write(' '); System.Console.Write(Test5(new S1(10))); System.Console.Write(Test5(default(S1))); System.Console.Write(Test5(new S1(""11""))); System.Console.Write(Test5(new S1(0))); System.Console.Write(Test5(null)); } static bool Test1(S1? u) { return u is not 10; } static bool Test2(S1? u) { return u is not (10 or 11); } static bool Test3(S1? u) { return u is not (""11"" and ['1', '1']); } static bool Test4(S1? u) { return u is not null; } static bool Test5(S1? u) { return u is not ({ } and int); } } "; var comp = CreateCompilation([src, UnionAttributeSource], targetFramework: TargetFramework.NetCoreApp, options: TestOptions.ReleaseExe); CompileAndVerify(comp, expectedOutput: ExecutionConditionUtil.IsMonoOrCoreClr ? "FalseTrueTrueTrueTrue FalseTrueTrueTrueFalseTrue TrueTrueFalseTrue TrueFalseTrueFalse FalseTrueTrueFalseTrue" : null, verify: Verification.FailsPEVerify).VerifyDiagnostics(); comp = CreateCompilation([src, UnionAttributeSource], targetFramework: TargetFramework.NetCoreApp, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular15); CompileAndVerify(comp, expectedOutput: ExecutionConditionUtil.IsMonoOrCoreClr ? "FalseTrueTrueTrueTrue FalseTrueTrueTrueFalseTrue TrueTrueFalseTrue TrueFalseTrueFalse FalseTrueTrueFalseTrue" : null, verify: Verification.FailsPEVerify).VerifyDiagnostics(); comp = CreateCompilation([src, UnionAttributeSource], targetFramework: TargetFramework.NetCoreApp, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular14); comp.VerifyDiagnostics( // (51,25): error CS9327: Feature 'unions' is not available in C# 14.0. Please use language version 15.0 or greater. // return u is not 10; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion14, "10").WithArguments("unions", "15.0").WithLocation(51, 25), // (56,26): error CS9327: Feature 'unions' is not available in C# 14.0. Please use language version 15.0 or greater. // return u is not (10 or 11); Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion14, "10").WithArguments("unions", "15.0").WithLocation(56, 26), // (56,32): error CS9327: Feature 'unions' is not available in C# 14.0. Please use language version 15.0 or greater. // return u is not (10 or 11); Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion14, "11").WithArguments("unions", "15.0").WithLocation(56, 32), // (61,26): error CS9327: Feature 'unions' is not available in C# 14.0. Please use language version 15.0 or greater. // return u is not ("11" and ['1', '1']); Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion14, @"""11""").WithArguments("unions", "15.0").WithLocation(61, 26), // (66,25): error CS9327: Feature 'unions' is not available in C# 14.0. Please use language version 15.0 or greater. // return u is not null; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion14, "null").WithArguments("unions", "15.0").WithLocation(66, 25), // (71,34): error CS9327: Feature 'unions' is not available in C# 14.0. Please use language version 15.0 or greater. // return u is not ({ } and int); Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion14, "int").WithArguments("unions", "15.0").WithLocation(71, 34) ); } [Fact] public void UnionMatching_15_Negated_01() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } public object Value => _value; } class Program { static void Main() { System.Console.Write(Test5(new S1(11))); System.Console.Write(Test5(default)); System.Console.Write(Test5(new S1(""11""))); System.Console.Write(' '); System.Console.Write(Test6(new S1(11))); System.Console.Write(Test6(default)); System.Console.Write(Test6(new S1(""11""))); } static int Test5(S1 u) { if (u is not int x) { return -1; } return x; } static int Test6(S1 u) { if (u is not not not int x) { return -1; } return x; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); CompileAndVerify(comp, expectedOutput: "11-1-1 11-1-1").VerifyDiagnostics(); } [Fact] public void UnionMatching_15_Negated_02() { var src = @" [System.Runtime.CompilerServices.Union] class S1 { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } public object Value => _value; } class Program { static void Main() { System.Console.Write(Test5(new S1(11))); System.Console.Write(Test5(default)); System.Console.Write(Test5(new S1(""11""))); System.Console.Write(Test5(null)); System.Console.Write(' '); System.Console.Write(Test6(new S1(11))); System.Console.Write(Test6(default)); System.Console.Write(Test6(new S1(""11""))); System.Console.Write(Test6(null)); } static int Test5(S1 u) { if (u is not int x) { return -1; } return x; } static int Test6(S1 u) { if (u is not not not int x) { return -1; } return x; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); CompileAndVerify(comp, expectedOutput: "11-1-1-1 11-1-1-1").VerifyDiagnostics(); } [Fact] public void UnionMatching_15_Negated_03() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } public object Value => _value; } class Program { static void Main() { System.Console.Write(Test5(new S1(11))); System.Console.Write(Test5(default)); System.Console.Write(Test5(new S1(""11""))); System.Console.Write(Test5(null)); System.Console.Write(' '); System.Console.Write(Test6(new S1(11))); System.Console.Write(Test6(default)); System.Console.Write(Test6(new S1(""11""))); System.Console.Write(Test6(null)); } static int Test5(S1? u) { if (u is not int x) { return -1; } return x; } static int Test6(S1? u) { if (u is not not not int x) { return -1; } return x; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); CompileAndVerify(comp, expectedOutput: "11-1-1-1 11-1-1-1").VerifyDiagnostics(); } [Fact] public void UnionMatching_16_Negated_01() { var src = @" [System.Runtime.CompilerServices.Union] sealed class C1 { private readonly object _value; public C1(int x) { _value = x; } public C1(string x) { _value = x; } public object Value => _value; } class Program { static int Test6(S1 u) { if (u is not not int y) { return y - 1; } #line 29 return y; } static bool Test8(S1 u) { #line 44 return u is not (S1 and int); } static bool Test9(S1? u) { #line 49 return u is not (S1 and int); } static int Test10(C1 u) { if (u is not not int y) { return y - 1; } #line 100 return y; } } [System.Runtime.CompilerServices.Union] struct S1 { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } public object Value => _value; } "; var comp = CreateCompilation([src, UnionAttributeSource]); // There is an implicit null check for class union types and for Nullable<Union>. comp.VerifyDiagnostics( // (29,16): error CS0165: Use of unassigned local variable 'y' // return y; Diagnostic(ErrorCode.ERR_UseDefViolation, "y").WithArguments("y").WithLocation(29, 16), // (100,16): error CS0165: Use of unassigned local variable 'y' // return y; Diagnostic(ErrorCode.ERR_UseDefViolation, "y").WithArguments("y").WithLocation(100, 16) ); } [Fact] public void UnionMatching_16_Negated_02() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } public object Value => _value; } [System.Runtime.CompilerServices.Union] class C1 { private readonly object _value; public C1() {} public C1(int x) { _value = x; } public C1(string x) { _value = x; } public object Value => _value; } class Program { static void Main() { System.Console.Write(Test1(new S1(11))); System.Console.Write(Test1(new S1())); System.Console.Write(Test1(new S1(""11""))); System.Console.Write(Test1(null)); System.Console.Write(' '); System.Console.Write(Test2(new C1(11))); System.Console.Write(Test2(new C1())); System.Console.Write(Test2(new C1(""11""))); System.Console.Write(Test2(null)); System.Console.Write(' '); System.Console.Write(Test3(new S1(11))); System.Console.Write(Test3(new S1())); System.Console.Write(Test3(new S1(""11""))); System.Console.Write(Test3(null)); System.Console.Write(' '); System.Console.Write(Test4(new C1(11))); System.Console.Write(Test4(new C1())); System.Console.Write(Test4(new C1(""11""))); System.Console.Write(Test4(null)); System.Console.Write(' '); System.Console.Write(Test5(new S1(11))); System.Console.Write(Test5(new S1())); System.Console.Write(Test5(new S1(""11""))); System.Console.Write(Test5(null)); System.Console.Write(' '); System.Console.Write(Test6(new C1(11))); System.Console.Write(Test6(new C1())); System.Console.Write(Test6(new C1(""11""))); System.Console.Write(Test6(null)); } static bool Test1(S1? u) { return u is not null; } static bool Test2(C1 u) { return u is not null; } static bool Test3(S1? u) { return u is not not null; } static bool Test4(C1 u) { return u is not not null; } static bool Test5(S1? u) { return u is null; } static bool Test6(C1 u) { return u is null; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); var verifier = CompileAndVerify(comp, expectedOutput: "TrueFalseTrueFalse TrueFalseTrueFalse FalseTrueFalseTrue FalseTrueFalseTrue FalseTrueFalseTrue FalseTrueFalseTrue").VerifyDiagnostics(); verifier.VerifyIL("Program.Test1", @" { // Code size 37 (0x25) .maxstack 2 .locals init (S1 V_0, bool V_1) IL_0000: ldarga.s V_0 IL_0002: call ""bool S1?.HasValue.get"" IL_0007: brfalse.s IL_001a IL_0009: ldarga.s V_0 IL_000b: call ""S1 S1?.GetValueOrDefault()"" IL_0010: stloc.0 IL_0011: ldloca.s V_0 IL_0013: call ""object S1.Value.get"" IL_0018: brtrue.s IL_001e IL_001a: ldc.i4.1 IL_001b: stloc.1 IL_001c: br.s IL_0020 IL_001e: ldc.i4.0 IL_001f: stloc.1 IL_0020: ldloc.1 IL_0021: ldc.i4.0 IL_0022: ceq IL_0024: ret } "); verifier.VerifyIL("Program.Test2", @" { // Code size 22 (0x16) .maxstack 2 .locals init (bool V_0) IL_0000: ldarg.0 IL_0001: brfalse.s IL_000b IL_0003: ldarg.0 IL_0004: callvirt ""object C1.Value.get"" IL_0009: brtrue.s IL_000f IL_000b: ldc.i4.1 IL_000c: stloc.0 IL_000d: br.s IL_0011 IL_000f: ldc.i4.0 IL_0010: stloc.0 IL_0011: ldloc.0 IL_0012: ldc.i4.0 IL_0013: ceq IL_0015: ret } "); var test3 = @" { // Code size 34 (0x22) .maxstack 1 .locals init (S1 V_0, bool V_1) IL_0000: ldarga.s V_0 IL_0002: call ""bool S1?.HasValue.get"" IL_0007: brfalse.s IL_001a IL_0009: ldarga.s V_0 IL_000b: call ""S1 S1?.GetValueOrDefault()"" IL_0010: stloc.0 IL_0011: ldloca.s V_0 IL_0013: call ""object S1.Value.get"" IL_0018: brtrue.s IL_001e IL_001a: ldc.i4.1 IL_001b: stloc.1 IL_001c: br.s IL_0020 IL_001e: ldc.i4.0 IL_001f: stloc.1 IL_0020: ldloc.1 IL_0021: ret } "; var test4 = @" { // Code size 19 (0x13) .maxstack 1 .locals init (bool V_0) IL_0000: ldarg.0 IL_0001: brfalse.s IL_000b IL_0003: ldarg.0 IL_0004: callvirt ""object C1.Value.get"" IL_0009: brtrue.s IL_000f IL_000b: ldc.i4.1 IL_000c: stloc.0 IL_000d: br.s IL_0011 IL_000f: ldc.i4.0 IL_0010: stloc.0 IL_0011: ldloc.0 IL_0012: ret } "; verifier.VerifyIL("Program.Test3", test3); verifier.VerifyIL("Program.Test5", test3); verifier.VerifyIL("Program.Test4", test4); verifier.VerifyIL("Program.Test6", test4); } [Fact] public void UnionMatching_16_Negated_03() { var src = @" [System.Runtime.CompilerServices.Union] class C1 { private readonly object _value; public C1() {} public C1(int x) { _value = x; } public C1(string x) { _value = x; } public object Value => _value; } class Program { static void Main() { System.Console.WriteLine(); System.Console.Write(""Test1: ""); System.Console.Write(Test1(new C1(11))); System.Console.Write(Test1(new C1())); System.Console.Write(Test1(new C1(""11""))); System.Console.Write(Test1(null)); System.Console.WriteLine(); System.Console.Write(""Test2: ""); System.Console.Write(Test2(new C1(11))); System.Console.Write(Test2(new C1())); System.Console.Write(Test2(new C1(""11""))); System.Console.Write(Test2(null)); System.Console.WriteLine(); System.Console.Write(""Test3: ""); System.Console.Write(Test3(new C1(11))); System.Console.Write(Test3(new C1())); System.Console.Write(Test3(new C1(""11""))); System.Console.Write(Test3(null)); } static bool Test1(C1 u) { return u is 11; } static bool Test2(C1 u) { return u is not 11; } static bool Test3(C1 u) { return u is not not 11; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); CompileAndVerify(comp, expectedOutput: @" Test1: TrueFalseFalseFalse Test2: FalseTrueTrueTrue Test3: TrueFalseFalseFalse ").VerifyDiagnostics(); } [Fact] public void UnionMatching_16_Negated_04() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } public object Value => _value; } [System.Runtime.CompilerServices.Union] class C1 { private readonly object _value; public C1() {} public C1(int x) { _value = x; } public C1(string x) { _value = x; } public object Value => _value; } class Program { static void Main() { System.Console.Write(Test1(new S1(11))); System.Console.Write(Test1(new S1())); System.Console.Write(Test1(new S1(""11""))); System.Console.Write(Test1(null)); System.Console.Write(' '); System.Console.Write(Test2(new C1(11))); System.Console.Write(Test2(new C1())); System.Console.Write(Test2(new C1(""11""))); System.Console.Write(Test2(null)); } static bool Test1(S1? u) { #line 100 return u is not (string)null; } static bool Test2(C1 u) { #line 200 return u is not (string)null; } static bool Test3(S1? u) { #line 300 return u is (string)null; } static bool Test4(C1 u) { #line 400 return u is (string)null; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); comp.VerifyDiagnostics( // (100,25): error CS9135: A constant value of type 'S1' is expected // return u is not (string)null; Diagnostic(ErrorCode.ERR_ConstantValueOfTypeExpected, "(string)null").WithArguments("S1").WithLocation(100, 25), // (200,25): error CS9135: A constant value of type 'C1' is expected // return u is not (string)null; Diagnostic(ErrorCode.ERR_ConstantValueOfTypeExpected, "(string)null").WithArguments("C1").WithLocation(200, 25), // (300,21): error CS9135: A constant value of type 'S1' is expected // return u is (string)null; Diagnostic(ErrorCode.ERR_ConstantValueOfTypeExpected, "(string)null").WithArguments("S1").WithLocation(300, 21), // (400,21): error CS9135: A constant value of type 'C1' is expected // return u is (string)null; Diagnostic(ErrorCode.ERR_ConstantValueOfTypeExpected, "(string)null").WithArguments("C1").WithLocation(400, 21) ); } [Fact] public void UnionMatching_16_Negated_05() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 { private readonly object _value; public S1(int x) { _value = x; } public S1(C2 x) { _value = x; } public object Value => _value; } [System.Runtime.CompilerServices.Union] class C1 { private readonly object _value; public C1() {} public C1(int x) { _value = x; } public C1(C2 x) { _value = x; } public object Value => _value; } class C2; class Program { static bool Test1(S1? u) { return u is not (string)null; } static bool Test2(C1 u) { return u is not (string)null; } } "; var comp = CreateCompilation([src, UnionAttributeSource]); comp.VerifyDiagnostics( // (27,25): error CS9372: An expression of type 'S1' cannot be handled by this pattern, see additional errors at this location. // return u is not (string)null; Diagnostic(ErrorCode.ERR_UnionMatchingWrongPattern, "(string)null").WithArguments("S1").WithLocation(27, 25), // (27,25): error CS0029: Cannot implicitly convert type 'string' to 'int' // return u is not (string)null; Diagnostic(ErrorCode.ERR_NoImplicitConv, "(string)null").WithArguments("string", "int").WithLocation(27, 25), // (27,25): error CS0029: Cannot implicitly convert type 'string' to 'C2' // return u is not (string)null; Diagnostic(ErrorCode.ERR_NoImplicitConv, "(string)null").WithArguments("string", "C2").WithLocation(27, 25), // (32,25): error CS9372: An expression of type 'C1' cannot be handled by this pattern, see additional errors at this location. // return u is not (string)null; Diagnostic(ErrorCode.ERR_UnionMatchingWrongPattern, "(string)null").WithArguments("C1").WithLocation(32, 25), // (32,25): error CS0029: Cannot implicitly convert type 'string' to 'int' // return u is not (string)null; Diagnostic(ErrorCode.ERR_NoImplicitConv, "(string)null").WithArguments("string", "int").WithLocation(32, 25), // (32,25): error CS0029: Cannot implicitly convert type 'string' to 'C2' // return u is not (string)null; Diagnostic(ErrorCode.ERR_NoImplicitConv, "(string)null").WithArguments("string", "C2").WithLocation(32, 25) ); } [Fact] public void UnionMatching_17_BinaryOr() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } public object Value => _value; } class Program { static void Main() { System.Console.Write(Test2(new S1(10))); System.Console.Write(Test2(default)); System.Console.Write(Test2(new S1(""11""))); System.Console.Write(Test2(new S1(0))); System.Console.Write(Test2(new S1(11))); System.Console.Write(Test2(new S1(""111""))); System.Console.Write(' '); System.Console.Write(Test3(new S1(10))); System.Console.Write(Test3(default(S1))); System.Console.Write(Test3(new S1(""11""))); System.Console.Write(Test3(new S1(0))); System.Console.Write(Test3(new S1(11))); System.Console.Write(Test3(new S1(""111""))); System.Console.Write(Test3(null)); } static bool Test2(S1 u) { return u is 10 or ""11""; } static bool Test3(S1? u) { return u is 10 or ""11""; } } "; var comp = CreateCompilation([src, UnionAttributeSource], targetFramework: TargetFramework.NetLatest, options: TestOptions.ReleaseExe); CompileAndVerify(comp, expectedOutput: "TrueFalseTrueFalseFalseFalse TrueFalseTrueFalseFalseFalseFalse").VerifyDiagnostics(); comp = CreateCompilation([src, UnionAttributeSource], targetFramework: TargetFramework.NetLatest, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular15); CompileAndVerify(comp, expectedOutput: "TrueFalseTrueFalseFalseFalse TrueFalseTrueFalseFalseFalseFalse").VerifyDiagnostics(); comp = CreateCompilation([src, UnionAttributeSource], targetFramework: TargetFramework.NetLatest, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular14); comp.VerifyDiagnostics( // (33,21): error CS9327: Feature 'unions' is not available in C# 14.0. Please use language version 15.0 or greater. // return u is 10 or "11"; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion14, "10").WithArguments("unions", "15.0").WithLocation(33, 21), // (33,27): error CS9327: Feature 'unions' is not available in C# 14.0. Please use language version 15.0 or greater. // return u is 10 or "11"; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion14, @"""11""").WithArguments("unions", "15.0").WithLocation(33, 27), // (38,21): error CS9327: Feature 'unions' is not available in C# 14.0. Please use language version 15.0 or greater. // return u is 10 or "11"; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion14, "10").WithArguments("unions", "15.0").WithLocation(38, 21), // (38,27): error CS9327: Feature 'unions' is not available in C# 14.0. Please use language version 15.0 or greater. // return u is 10 or "11"; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion14, @"""11""").WithArguments("unions", "15.0").WithLocation(38, 27) ); } [Fact] public void UnionMatching_18_BinaryAnd() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } public object Value => _value; } class Program { static void Main() { System.Console.Write(Test2(new S1(10))); System.Console.Write(Test2(null)); System.Console.Write(Test2(new S1())); System.Console.Write(Test2(new S1(""11""))); } static string Test2(object u) { if (u is S1 and int x) { return x.ToString(); } return ""_""; } } "; var comp = CreateCompilation([src, UnionAttributeSource], targetFramework: TargetFramework.NetLatest, options: TestOptions.ReleaseExe); CompileAndVerify(comp, expectedOutput: "10___").VerifyDiagnostics(); } [Fact] public void UnionMatching_19_BinaryAnd() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } public object Value => _value; } class Program { static void Main() { System.Console.Write(Test2(new S1(10))); System.Console.Write(Test2(default)); System.Console.Write(Test2(new S1(""11""))); System.Console.Write(' '); System.Console.Write(Test3(new S1(10))); System.Console.Write(Test3(default(S1))); System.Console.Write(Test3(new S1(""11""))); System.Console.Write(Test3(null)); } static string Test2(S1 u) { if (u is 10 and var x) { return x.GetType().ToString(); } return ""_""; } static string Test3(S1? u) { if (u is 10 and var x) { return x.GetType().ToString(); } return ""_""; } } "; var comp = CreateCompilation([src, UnionAttributeSource], targetFramework: TargetFramework.NetLatest, options: TestOptions.ReleaseExe); CompileAndVerify(comp, expectedOutput: "System.Int32__ System.Int32___").VerifyDiagnostics(); comp = CreateCompilation([src, UnionAttributeSource], targetFramework: TargetFramework.NetLatest, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular15); CompileAndVerify(comp, expectedOutput: "System.Int32__ System.Int32___").VerifyDiagnostics(); comp = CreateCompilation([src, UnionAttributeSource], targetFramework: TargetFramework.NetLatest, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular14); comp.VerifyDiagnostics( // (27,18): error CS9327: Feature 'unions' is not available in C# 14.0. Please use language version 15.0 or greater. // if (u is 10 and var x) Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion14, "10").WithArguments("unions", "15.0").WithLocation(27, 18), // (37,18): error CS9327: Feature 'unions' is not available in C# 14.0. Please use language version 15.0 or greater. // if (u is 10 and var x) Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion14, "10").WithArguments("unions", "15.0").WithLocation(37, 18) ); } [Fact] public void UnionMatching_20_BinaryAnd() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 { private readonly object _value; public S1(S2 x) { _value = x; } public S1(string x) { _value = x; } public object Value => _value; } [System.Runtime.CompilerServices.Union] struct S2 { private readonly object _value; public S2(int x) { _value = x; } public S2(string x) { _value = x; } public object Value => _value; } class Program { static void Main() { System.Console.Write(Test2(new S1(new S2(10)))); System.Console.Write(Test2(new S1(new S2(11)))); System.Console.Write(Test2(null)); System.Console.Write(Test2(new S1())); System.Console.Write(Test2(new S1(new S2()))); System.Console.Write(Test2(new S1(""11""))); System.Console.Write(Test2(new S1(new S2(""11"")))); System.Console.Write(' '); System.Console.Write(Test3(new S1(new S2(10)))); System.Console.Write(Test3(new S1(new S2(11)))); System.Console.Write(Test3(null)); System.Console.Write(Test3(new S1())); System.Console.Write(Test3(new S1(new S2()))); System.Console.Write(Test3(new S1(""11""))); System.Console.Write(Test3(new S1(new S2(""11"")))); } static bool Test2(object u) { return u is S1 and S2 and 10; } static bool Test3(object u) { return u is S1 and (S2 and 10); } } "; var comp = CreateCompilation([src, UnionAttributeSource], targetFramework: TargetFramework.NetLatest, options: TestOptions.ReleaseExe); CompileAndVerify(comp, expectedOutput: "TrueFalseFalseFalseFalseFalseFalse TrueFalseFalseFalseFalseFalseFalse").VerifyDiagnostics(); } [Fact] public void UnionMatching_21_BinaryAnd() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 { private readonly object _value; public S1(S2 x) { _value = x; } public S1(string x) { _value = x; } public object Value => _value; } [System.Runtime.CompilerServices.Union] struct S2 { private readonly object _value; public S2(S3 x) { _value = x; } public S2(int x) { _value = x; } public object Value => _value; } [System.Runtime.CompilerServices.Union] struct S3 { private readonly object _value; public S3(int x) { _value = x; } public S3(string x) { _value = x; } public object Value => _value; } class Program { static void Main() { System.Console.Write(Test2(new S1(new S2(new S3(10))))); System.Console.Write(Test2(new S1(new S2(new S3(11))))); System.Console.Write(Test2(null)); System.Console.Write(Test2(new S1())); System.Console.Write(Test2(new S1(new S2()))); System.Console.Write(Test2(new S1(new S2(new S3())))); System.Console.Write(Test2(new S1(""11""))); System.Console.Write(Test2(new S1(new S2(10)))); System.Console.Write(Test2(new S1(new S2(11)))); System.Console.Write(Test2(new S1(new S2(new S3(""11""))))); System.Console.WriteLine(); System.Console.Write(Test3(new S1(new S2(new S3(10))))); System.Console.Write(Test3(new S1(new S2(new S3(11))))); System.Console.Write(Test3(null)); System.Console.Write(Test3(new S1())); System.Console.Write(Test3(new S1(new S2()))); System.Console.Write(Test3(new S1(new S2(new S3())))); System.Console.Write(Test3(new S1(""11""))); System.Console.Write(Test3(new S1(new S2(10)))); System.Console.Write(Test3(new S1(new S2(11)))); System.Console.Write(Test3(new S1(new S2(new S3(""11""))))); System.Console.WriteLine(); System.Console.Write(Test4(new S1(new S2(new S3(10))))); System.Console.Write(Test4(new S1(new S2(new S3(11))))); System.Console.Write(Test4(null)); System.Console.Write(Test4(new S1())); System.Console.Write(Test4(new S1(new S2()))); System.Console.Write(Test4(new S1(new S2(new S3())))); System.Console.Write(Test4(new S1(""11""))); System.Console.Write(Test4(new S1(new S2(10)))); System.Console.Write(Test4(new S1(new S2(11)))); System.Console.Write(Test4(new S1(new S2(new S3(""11""))))); System.Console.WriteLine(); System.Console.Write(Test5(new S1(new S2(new S3(10))))); System.Console.Write(Test5(new S1(new S2(new S3(11))))); System.Console.Write(Test5(null)); System.Console.Write(Test5(new S1())); System.Console.Write(Test5(new S1(new S2()))); System.Console.Write(Test5(new S1(new S2(new S3())))); System.Console.Write(Test5(new S1(""11""))); System.Console.Write(Test5(new S1(new S2(10)))); System.Console.Write(Test5(new S1(new S2(11)))); System.Console.Write(Test5(new S1(new S2(new S3(""11""))))); System.Console.WriteLine(); System.Console.Write(Test6(new S1(new S2(new S3(10))))); System.Console.Write(Test6(new S1(new S2(new S3(11))))); System.Console.Write(Test6(null)); System.Console.Write(Test6(new S1())); System.Console.Write(Test6(new S1(new S2()))); System.Console.Write(Test6(new S1(new S2(new S3())))); System.Console.Write(Test6(new S1(""11""))); System.Console.Write(Test6(new S1(new S2(10)))); System.Console.Write(Test6(new S1(new S2(11)))); System.Console.Write(Test6(new S1(new S2(new S3(""11""))))); } static bool Test2(object u) { return u is ((S1 and S2) and S3) and 10; } static bool Test3(object u) { return u is (S1 and S2) and (S3 and 10); } static bool Test4(object u) { return u is (S1 and (S2 and S3)) and 10; } static bool Test5(object u) { return u is S1 and (S2 and S3 and 10); } static bool Test6(object u) { return u is S1 and (S2 and (S3 and 10)); } } "; var comp = CreateCompilation([src, UnionAttributeSource], targetFramework: TargetFramework.NetLatest, options: TestOptions.ReleaseExe); CompileAndVerify(comp, expectedOutput: @" TrueFalseFalseFalseFalseFalseFalseFalseFalseFalse TrueFalseFalseFalseFalseFalseFalseFalseFalseFalse TrueFalseFalseFalseFalseFalseFalseFalseFalseFalse TrueFalseFalseFalseFalseFalseFalseFalseFalseFalse TrueFalseFalseFalseFalseFalseFalseFalseFalseFalse ").VerifyDiagnostics(); } [Fact] public void UnionMatching_22_BinaryAnd() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 { private readonly object _value; public S1(S2 x) { _value = x; } public S1(string x) { _value = x; } public object Value => _value; } [System.Runtime.CompilerServices.Union] struct S2 { private readonly object _value; public S2(S3 x) { _value = x; } public S2(int x) { _value = x; } public object Value => _value; } [System.Runtime.CompilerServices.Union] struct S3 { private readonly object _value; public S3(int x) { _value = x; } public S3(string x) { _value = x; } public object Value => _value; } class Program { static void Main() { System.Console.Write(Test2(new S1(new S2(new S3(10))))); System.Console.Write(Test2(new S1(new S2(new S3(11))))); System.Console.Write(Test2(null)); System.Console.Write(Test2(new S1())); System.Console.Write(Test2(new S1(new S2()))); System.Console.Write(Test2(new S1(new S2(new S3())))); System.Console.Write(Test2(new S1(""11""))); System.Console.Write(Test2(new S1(new S2(10)))); System.Console.Write(Test2(new S1(new S2(11)))); System.Console.Write(Test2(new S1(new S2(new S3(""11""))))); System.Console.WriteLine(); System.Console.Write(Test3(new S1(new S2(new S3(10))))); System.Console.Write(Test3(new S1(new S2(new S3(11))))); System.Console.Write(Test3(null)); System.Console.Write(Test3(new S1())); System.Console.Write(Test3(new S1(new S2()))); System.Console.Write(Test3(new S1(new S2(new S3())))); System.Console.Write(Test3(new S1(""11""))); System.Console.Write(Test3(new S1(new S2(10)))); System.Console.Write(Test3(new S1(new S2(11)))); System.Console.Write(Test3(new S1(new S2(new S3(""11""))))); System.Console.WriteLine(); System.Console.Write(Test4(new S1(new S2(new S3(10))))); System.Console.Write(Test4(new S1(new S2(new S3(11))))); System.Console.Write(Test4(null)); System.Console.Write(Test4(new S1())); System.Console.Write(Test4(new S1(new S2()))); System.Console.Write(Test4(new S1(new S2(new S3())))); System.Console.Write(Test4(new S1(""11""))); System.Console.Write(Test4(new S1(new S2(10)))); System.Console.Write(Test4(new S1(new S2(11)))); System.Console.Write(Test4(new S1(new S2(new S3(""11""))))); System.Console.WriteLine(); System.Console.Write(Test5(new S1(new S2(new S3(10))))); System.Console.Write(Test5(new S1(new S2(new S3(11))))); System.Console.Write(Test5(null)); System.Console.Write(Test5(new S1())); System.Console.Write(Test5(new S1(new S2()))); System.Console.Write(Test5(new S1(new S2(new S3())))); System.Console.Write(Test5(new S1(""11""))); System.Console.Write(Test5(new S1(new S2(10)))); System.Console.Write(Test5(new S1(new S2(11)))); System.Console.Write(Test5(new S1(new S2(new S3(""11""))))); System.Console.WriteLine(); System.Console.Write(Test6(new S1(new S2(new S3(10))))); System.Console.Write(Test6(new S1(new S2(new S3(11))))); System.Console.Write(Test6(null)); System.Console.Write(Test6(new S1())); System.Console.Write(Test6(new S1(new S2()))); System.Console.Write(Test6(new S1(new S2(new S3())))); System.Console.Write(Test6(new S1(""11""))); System.Console.Write(Test6(new S1(new S2(10)))); System.Console.Write(Test6(new S1(new S2(11)))); System.Console.Write(Test6(new S1(new S2(new S3(""11""))))); } static bool Test2(object u) { return u is ((S1 and S2) and S3) and var x and 10; } static bool Test3(object u) { return u is (S1 and S2) and (var x and S3 and 10); } static bool Test4(object u) { return u is (S1 and (var x and S2 and S3)) and 10; } static bool Test5(object u) { return u is S1 and (S2 and var x and S3 and 10); } static bool Test6(object u) { return u is S1 and (S2 and (var x and S3 and 10)); } } "; var comp = CreateCompilation([src, UnionAttributeSource], targetFramework: TargetFramework.NetLatest, options: TestOptions.ReleaseExe); CompileAndVerify(comp, expectedOutput: @" TrueFalseFalseFalseFalseFalseFalseFalseFalseFalse TrueFalseFalseFalseFalseFalseFalseFalseFalseFalse TrueFalseFalseFalseFalseFalseFalseFalseFalseFalse TrueFalseFalseFalseFalseFalseFalseFalseFalseFalse TrueFalseFalseFalseFalseFalseFalseFalseFalseFalse ").VerifyDiagnostics(); } [Fact] public void UnionMatching_23_Parenthesized_01() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } public object Value => _value; } class Program { static void Main() { System.Console.Write(Test1(new S1(10))); System.Console.Write(Test1(default)); System.Console.Write(Test1(new S1(""11""))); System.Console.Write(Test1(new S1(0))); System.Console.Write(' '); System.Console.Write(Test2(new S1(10))); System.Console.Write(Test2(default)); System.Console.Write(Test2(new S1(""11""))); System.Console.Write(Test2(new S1(0))); System.Console.Write(Test2(new S1(11))); System.Console.Write(' '); System.Console.Write(Test3(new S1(11))); System.Console.Write(Test3(default)); System.Console.Write(Test3(new S1(""11""))); System.Console.Write(' '); System.Console.Write(Test4(new S1(11))); System.Console.Write(Test4(default)); System.Console.Write(Test4(new S1(""11""))); } static bool Test1(S1 u) { return u is (10); } static bool Test2(S1 u) { return u is (10 or 11); } static bool Test3(S1 u) { return u is (""11"" and ['1', '1']); } static bool Test4(S1 u) { return u is (null); } } "; var comp = CreateCompilation([src, UnionAttributeSource], targetFramework: TargetFramework.NetCoreApp, options: TestOptions.ReleaseExe); CompileAndVerify(comp, expectedOutput: ExecutionConditionUtil.IsMonoOrCoreClr ? "TrueFalseFalseFalse TrueFalseFalseFalseTrue FalseFalseTrue FalseTrueFalse" : null, verify: Verification.FailsPEVerify).VerifyDiagnostics(); comp = CreateCompilation([src, UnionAttributeSource], targetFramework: TargetFramework.NetCoreApp, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular15); CompileAndVerify(comp, expectedOutput: ExecutionConditionUtil.IsMonoOrCoreClr ? "TrueFalseFalseFalse TrueFalseFalseFalseTrue FalseFalseTrue FalseTrueFalse" : null, verify: Verification.FailsPEVerify).VerifyDiagnostics(); comp = CreateCompilation([src, UnionAttributeSource], targetFramework: TargetFramework.NetCoreApp, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular14); comp.VerifyDiagnostics( // (40,21): error CS9327: Feature 'unions' is not available in C# 14.0. Please use language version 15.0 or greater. // return u is (10); Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion14, "(10)").WithArguments("unions", "15.0").WithLocation(40, 21), // (45,22): error CS9327: Feature 'unions' is not available in C# 14.0. Please use language version 15.0 or greater. // return u is (10 or 11); Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion14, "10").WithArguments("unions", "15.0").WithLocation(45, 22), // (45,28): error CS9327: Feature 'unions' is not available in C# 14.0. Please use language version 15.0 or greater. // return u is (10 or 11); Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion14, "11").WithArguments("unions", "15.0").WithLocation(45, 28), // (50,22): error CS9327: Feature 'unions' is not available in C# 14.0. Please use language version 15.0 or greater. // return u is ("11" and ['1', '1']); Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion14, @"""11""").WithArguments("unions", "15.0").WithLocation(50, 22), // (55,21): error CS9327: Feature 'unions' is not available in C# 14.0. Please use language version 15.0 or greater. // return u is (null); Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion14, "(null)").WithArguments("unions", "15.0").WithLocation(55, 21) ); } [Fact] public void UnionMatching_23_Parenthesized_02() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } public object Value => _value; } class Program { static void Main() { System.Console.Write(Test1(new S1(10))); System.Console.Write(Test1(default(S1))); System.Console.Write(Test1(new S1(""11""))); System.Console.Write(Test1(new S1(0))); System.Console.Write(Test1(null)); System.Console.Write(' '); System.Console.Write(Test2(new S1(10))); System.Console.Write(Test2(default(S1))); System.Console.Write(Test2(new S1(""11""))); System.Console.Write(Test2(new S1(0))); System.Console.Write(Test2(new S1(11))); System.Console.Write(Test2(null)); System.Console.Write(' '); System.Console.Write(Test3(new S1(11))); System.Console.Write(Test3(default(S1))); System.Console.Write(Test3(new S1(""11""))); System.Console.Write(Test3(null)); System.Console.Write(' '); System.Console.Write(Test4(new S1(11))); System.Console.Write(Test4(default(S1))); System.Console.Write(Test4(new S1(""11""))); System.Console.Write(Test4(null)); } static bool Test1(S1? u) { return u is (10); } static bool Test2(S1? u) { return u is (10 or 11); } static bool Test3(S1? u) { return u is (""11"" and ['1', '1']); } static bool Test4(S1? u) { return u is (null); } } "; var comp = CreateCompilation([src, UnionAttributeSource], targetFramework: TargetFramework.NetCoreApp, options: TestOptions.ReleaseExe); CompileAndVerify(comp, expectedOutput: ExecutionConditionUtil.IsMonoOrCoreClr ? "TrueFalseFalseFalseFalse TrueFalseFalseFalseTrueFalse FalseFalseTrueFalse FalseTrueFalseTrue" : null, verify: Verification.FailsPEVerify).VerifyDiagnostics(); comp = CreateCompilation([src, UnionAttributeSource], targetFramework: TargetFramework.NetCoreApp, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular15); CompileAndVerify(comp, expectedOutput: ExecutionConditionUtil.IsMonoOrCoreClr ? "TrueFalseFalseFalseFalse TrueFalseFalseFalseTrueFalse FalseFalseTrueFalse FalseTrueFalseTrue" : null, verify: Verification.FailsPEVerify).VerifyDiagnostics(); comp = CreateCompilation([src, UnionAttributeSource], targetFramework: TargetFramework.NetCoreApp, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular14); comp.VerifyDiagnostics( // (44,21): error CS9327: Feature 'unions' is not available in C# 14.0. Please use language version 15.0 or greater. // return u is (10); Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion14, "(10)").WithArguments("unions", "15.0").WithLocation(44, 21), // (49,22): error CS9327: Feature 'unions' is not available in C# 14.0. Please use language version 15.0 or greater. // return u is (10 or 11); Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion14, "10").WithArguments("unions", "15.0").WithLocation(49, 22), // (49,28): error CS9327: Feature 'unions' is not available in C# 14.0. Please use language version 15.0 or greater. // return u is (10 or 11); Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion14, "11").WithArguments("unions", "15.0").WithLocation(49, 28), // (54,22): error CS9327: Feature 'unions' is not available in C# 14.0. Please use language version 15.0 or greater. // return u is ("11" and ['1', '1']); Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion14, @"""11""").WithArguments("unions", "15.0").WithLocation(54, 22), // (59,21): error CS9327: Feature 'unions' is not available in C# 14.0. Please use language version 15.0 or greater. // return u is (null); Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion14, "(null)").WithArguments("unions", "15.0").WithLocation(59, 21) ); } [Fact] public void UnionMatching_24_Relational_01() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } public object Value => _value; } class Program { static void Main() { System.Console.Write(Test1(new S1(10))); System.Console.Write(Test1(default)); System.Console.Write(Test1(new S1(""11""))); System.Console.Write(Test1(new S1(0))); System.Console.Write(' '); System.Console.Write(Test2(new S1(10))); System.Console.Write(Test2(default)); System.Console.Write(Test2(new S1(""11""))); System.Console.Write(Test2(new S1(0))); System.Console.Write(Test2(new S1(11))); } static bool Test1(S1 u) { return u is >=10; } static bool Test2(S1 u) { return u is <10 or 11; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); CompileAndVerify(comp, expectedOutput: "TrueFalseFalseFalse FalseFalseFalseTrueTrue").VerifyDiagnostics(); comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular15); CompileAndVerify(comp, expectedOutput: "TrueFalseFalseFalse FalseFalseFalseTrueTrue").VerifyDiagnostics(); comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular14); comp.VerifyDiagnostics( // (30,21): error CS9327: Feature 'unions' is not available in C# 14.0. Please use language version 15.0 or greater. // return u is >=10; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion14, ">=10").WithArguments("unions", "15.0").WithLocation(30, 21), // (35,21): error CS9327: Feature 'unions' is not available in C# 14.0. Please use language version 15.0 or greater. // return u is <10 or 11; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion14, "<10").WithArguments("unions", "15.0").WithLocation(35, 21), // (35,28): error CS9327: Feature 'unions' is not available in C# 14.0. Please use language version 15.0 or greater. // return u is <10 or 11; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion14, "11").WithArguments("unions", "15.0").WithLocation(35, 28) ); } [Fact] public void UnionMatching_24_Relational_02() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } public object Value => _value; } class Program { static void Main() { System.Console.Write(Test1(new S1(10))); System.Console.Write(Test1(default(S1))); System.Console.Write(Test1(new S1(""11""))); System.Console.Write(Test1(new S1(0))); System.Console.Write(Test1(null)); System.Console.Write(' '); System.Console.Write(Test2(new S1(10))); System.Console.Write(Test2(default(S1))); System.Console.Write(Test2(new S1(""11""))); System.Console.Write(Test2(new S1(0))); System.Console.Write(Test2(new S1(11))); System.Console.Write(Test2(null)); } static bool Test1(S1? u) { return u is >=10; } static bool Test2(S1? u) { return u is <10 or 11; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); CompileAndVerify(comp, expectedOutput: "TrueFalseFalseFalseFalse FalseFalseFalseTrueTrueFalse").VerifyDiagnostics(); comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular15); CompileAndVerify(comp, expectedOutput: "TrueFalseFalseFalseFalse FalseFalseFalseTrueTrueFalse").VerifyDiagnostics(); comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular14); comp.VerifyDiagnostics( // (32,21): error CS9327: Feature 'unions' is not available in C# 14.0. Please use language version 15.0 or greater. // return u is >=10; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion14, ">=10").WithArguments("unions", "15.0").WithLocation(32, 21), // (37,21): error CS9327: Feature 'unions' is not available in C# 14.0. Please use language version 15.0 or greater. // return u is <10 or 11; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion14, "<10").WithArguments("unions", "15.0").WithLocation(37, 21), // (37,28): error CS9327: Feature 'unions' is not available in C# 14.0. Please use language version 15.0 or greater. // return u is <10 or 11; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion14, "11").WithArguments("unions", "15.0").WithLocation(37, 28) ); } [Fact] public void UnionMatching_25_List() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 { private readonly object _value; public S1(int[] x) { _value = x; } public S1(string[] x) { _value = x; } public object Value => _value; public int Length => 0; } class Program { static bool Test1(S1 u) { #line 14 return u is [10]; } static bool Test2(S1? u) { #line 19 return u is [10]; } } "; var comp = CreateCompilation([src, UnionAttributeSource], targetFramework: TargetFramework.NetCoreApp); comp.VerifyDiagnostics( // (14,21): error CS0021: Cannot apply indexing with [] to an expression of type 'S1' // return u is [10]; Diagnostic(ErrorCode.ERR_BadIndexLHS, "[10]").WithArguments("S1").WithLocation(14, 21), // (19,21): error CS0021: Cannot apply indexing with [] to an expression of type 'S1' // return u is [10]; Diagnostic(ErrorCode.ERR_BadIndexLHS, "[10]").WithArguments("S1").WithLocation(19, 21) ); } [Fact] public void UnionMatching_25_List_Success() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 { private readonly object _value; public S1(int[] x) { _value = x; } public S1(string[] x) { _value = x; } public object Value => _value; public int Length => 1; public int this[System.Index i] => 10; } class Program { static void Main() { S1 s1 = new int[] { }; System.Console.Write(Test1(s1)); System.Console.Write(Test2(s1)); System.Console.Write(' '); s1 = new string[] { }; System.Console.Write(Test1(s1)); System.Console.Write(Test2(s1)); System.Console.Write(' '); s1 = default; System.Console.Write(Test1(s1)); System.Console.Write(Test2(s1)); System.Console.Write(Test2(null)); } static bool Test1(S1 u) { return u is [10]; } static bool Test2(S1? u) { return u is [10]; } } "; var comp = CreateCompilation([src, UnionAttributeSource], targetFramework: TargetFramework.NetCoreApp, options: TestOptions.DebugExe); var verifier = CompileAndVerify(comp, expectedOutput: ExecutionConditionUtil.IsMonoOrCoreClr ? "TrueTrue TrueTrue TrueTrueFalse" : null, verify: Verification.FailsPEVerify).VerifyDiagnostics(); verifier.VerifyIL("Program.Test1", """ { // Code size 37 (0x25) .maxstack 3 .locals init (bool V_0) IL_0000: nop IL_0001: ldarga.s V_0 IL_0003: call "int S1.Length.get" IL_0008: ldc.i4.1 IL_0009: bne.un.s IL_001f IL_000b: ldarga.s V_0 IL_000d: ldc.i4.0 IL_000e: ldc.i4.0 IL_000f: newobj "System.Index..ctor(int, bool)" IL_0014: call "int S1.this[System.Index].get" IL_0019: ldc.i4.s 10 IL_001b: ceq IL_001d: br.s IL_0020 IL_001f: ldc.i4.0 IL_0020: stloc.0 IL_0021: br.s IL_0023 IL_0023: ldloc.0 IL_0024: ret } """); verifier.VerifyIL("Program.Test2", """ { // Code size 54 (0x36) .maxstack 3 .locals init (S1 V_0, bool V_1) IL_0000: nop IL_0001: ldarga.s V_0 IL_0003: call "readonly bool S1?.HasValue.get" IL_0008: brfalse.s IL_0030 IL_000a: ldarga.s V_0 IL_000c: call "readonly S1 S1?.GetValueOrDefault()" IL_0011: stloc.0 IL_0012: ldloca.s V_0 IL_0014: call "int S1.Length.get" IL_0019: ldc.i4.1 IL_001a: bne.un.s IL_0030 IL_001c: ldloca.s V_0 IL_001e: ldc.i4.0 IL_001f: ldc.i4.0 IL_0020: newobj "System.Index..ctor(int, bool)" IL_0025: call "int S1.this[System.Index].get" IL_002a: ldc.i4.s 10 IL_002c: ceq IL_002e: br.s IL_0031 IL_0030: ldc.i4.0 IL_0031: stloc.1 IL_0032: br.s IL_0034 IL_0034: ldloc.1 IL_0035: ret } """); } [Fact] public void UnionMatching_26_List_Subpattern_01() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } public object Value => _value; } struct S2 { private S1 _value; public S2(S1 x) {_value = x;} public int Length => 2; public S1 this[int i] => _value; } class Program { static void Main() { System.Console.Write(Test1(new S2(new S1(10)))); System.Console.Write(Test1(new S2(default))); System.Console.Write(Test1(new S2(new S1(""11"")))); System.Console.Write(Test1(new S2(new S1(0)))); } static bool Test1(S2 u) { return u is [10, _]; } } "; var comp = CreateCompilation([src, UnionAttributeSource], targetFramework: TargetFramework.NetCoreApp, options: TestOptions.ReleaseExe); CompileAndVerify(comp, expectedOutput: ExecutionConditionUtil.IsMonoOrCoreClr ? "TrueFalseFalseFalse" : null, verify: Verification.FailsPEVerify).VerifyDiagnostics(); comp = CreateCompilation([src, UnionAttributeSource], targetFramework: TargetFramework.NetCoreApp, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular15); CompileAndVerify(comp, expectedOutput: ExecutionConditionUtil.IsMonoOrCoreClr ? "TrueFalseFalseFalse" : null, verify: Verification.FailsPEVerify).VerifyDiagnostics(); comp = CreateCompilation([src, UnionAttributeSource], targetFramework: TargetFramework.NetCoreApp, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular14); comp.VerifyDiagnostics( // (31,22): error CS9327: Feature 'unions' is not available in C# 14.0. Please use language version 15.0 or greater. // return u is [10, _]; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion14, "10").WithArguments("unions", "15.0").WithLocation(31, 22) ); } [Fact] public void UnionMatching_26_List_Subpattern_02() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } public object Value => _value; } struct S2 { private S1? _value; public S2(S1? x) {_value = x;} public int Length => 2; public S1? this[int i] => _value; } class Program { static void Main() { System.Console.Write(Test1(new S2(new S1(10)))); System.Console.Write(Test1(new S2(default(S1)))); System.Console.Write(Test1(new S2(new S1(""11"")))); System.Console.Write(Test1(new S2(new S1(0)))); System.Console.Write(Test1(new S2(null))); } static bool Test1(S2 u) { return u is [10, _]; } } "; var comp = CreateCompilation([src, UnionAttributeSource], targetFramework: TargetFramework.NetCoreApp, options: TestOptions.ReleaseExe); CompileAndVerify(comp, expectedOutput: ExecutionConditionUtil.IsMonoOrCoreClr ? "TrueFalseFalseFalseFalse" : null, verify: Verification.FailsPEVerify).VerifyDiagnostics(); } [Fact] public void UnionMatching_27_Slice_Subpattern_01() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } public object Value => _value; } struct S2 { private S1 _value; public S2(S1 x) {_value = x;} public int Length => 2; public int this[int i] => 0; public S1 this[System.Range r] => _value; } class Program { static void Main() { System.Console.Write(Test1(new S2(new S1(10)))); System.Console.Write(Test1(new S2(default))); System.Console.Write(Test1(new S2(new S1(""11"")))); System.Console.Write(Test1(new S2(new S1(0)))); } static bool Test1(S2 u) { return u is [0, ..10]; } } "; var comp = CreateCompilation([src, UnionAttributeSource], targetFramework: TargetFramework.NetCoreApp, options: TestOptions.ReleaseExe); CompileAndVerify(comp, expectedOutput: ExecutionConditionUtil.IsMonoOrCoreClr ? "TrueFalseFalseFalse" : null, verify: Verification.FailsPEVerify).VerifyDiagnostics(); comp = CreateCompilation([src, UnionAttributeSource], targetFramework: TargetFramework.NetCoreApp, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular15); CompileAndVerify(comp, expectedOutput: ExecutionConditionUtil.IsMonoOrCoreClr ? "TrueFalseFalseFalse" : null, verify: Verification.FailsPEVerify).VerifyDiagnostics(); comp = CreateCompilation([src, UnionAttributeSource], targetFramework: TargetFramework.NetCoreApp, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular14); comp.VerifyDiagnostics( // (32,27): error CS9327: Feature 'unions' is not available in C# 14.0. Please use language version 15.0 or greater. // return u is [0, ..10]; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion14, "10").WithArguments("unions", "15.0").WithLocation(32, 27) ); } [Fact] public void UnionMatching_27_Slice_Subpattern_02() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } public object Value => _value; } struct S2 { private S1? _value; public S2(S1? x) {_value = x;} public int Length => 2; public int this[int i] => 0; public S1? this[System.Range r] => _value; } class Program { static void Main() { System.Console.Write(Test1(new S2(new S1(10)))); System.Console.Write(Test1(new S2(default(S1)))); System.Console.Write(Test1(new S2(new S1(""11"")))); System.Console.Write(Test1(new S2(new S1(0)))); System.Console.Write(Test1(new S2(null))); } static bool Test1(S2 u) { return u is [0, ..10]; } } "; var comp = CreateCompilation([src, UnionAttributeSource], targetFramework: TargetFramework.NetCoreApp, options: TestOptions.ReleaseExe); CompileAndVerify(comp, expectedOutput: ExecutionConditionUtil.IsMonoOrCoreClr ? "TrueFalseFalseFalseFalse" : null, verify: Verification.FailsPEVerify).VerifyDiagnostics(); } [Fact] public void UnionMatching_28_Tuple_Deconstruction_Subpattern() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } public object Value => _value; } class Program { static void Main() { System.Console.Write(Test1((new S1(10), -1))); System.Console.Write(Test1((default, -1))); System.Console.Write(Test1((new S1(""11""), -1))); System.Console.Write(Test1((new S1(0), -1))); System.Console.Write(' '); System.Console.Write(Test2((new S1(10), -1))); System.Console.Write(Test2((default(S1), -1))); System.Console.Write(Test2((new S1(""11""), -1))); System.Console.Write(Test2((new S1(0), -1))); System.Console.Write(Test2((null, -1))); } static bool Test1((S1, int) u) { return u is (10, _); } static bool Test2((S1?, int) u) { return u is (10, _); } } "; var comp = CreateCompilation([src, UnionAttributeSource], targetFramework: TargetFramework.NetCoreApp, options: TestOptions.ReleaseExe); CompileAndVerify(comp, expectedOutput: ExecutionConditionUtil.IsMonoOrCoreClr ? "TrueFalseFalseFalse TrueFalseFalseFalseFalse" : null, verify: Verification.FailsPEVerify).VerifyDiagnostics(); comp = CreateCompilation([src, UnionAttributeSource], targetFramework: TargetFramework.NetCoreApp, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular15); CompileAndVerify(comp, expectedOutput: ExecutionConditionUtil.IsMonoOrCoreClr ? "TrueFalseFalseFalse TrueFalseFalseFalseFalse" : null, verify: Verification.FailsPEVerify).VerifyDiagnostics(); comp = CreateCompilation([src, UnionAttributeSource], targetFramework: TargetFramework.NetCoreApp, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular14); comp.VerifyDiagnostics( // (29,22): error CS9327: Feature 'unions' is not available in C# 14.0. Please use language version 15.0 or greater. // return u is (10, _); Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion14, "10").WithArguments("unions", "15.0").WithLocation(29, 22), // (34,22): error CS9327: Feature 'unions' is not available in C# 14.0. Please use language version 15.0 or greater. // return u is (10, _); Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion14, "10").WithArguments("unions", "15.0").WithLocation(34, 22) ); } [Fact] public void UnionMatching_29_ITuple_Deconstruction_Subpattern() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } public object Value => _value; } class Program { static void Main() { System.Console.Write(Test1(new C(new S1(10)))); System.Console.Write(Test1(new C(default))); System.Console.Write(Test1(new C(new S1(11)))); System.Console.Write(Test1(new C(new S1(""10"")))); } static bool Test1(C u) { return u is (S1 and 10, _); } } class C : System.Runtime.CompilerServices.ITuple { private readonly S1 _value; public C(S1 x) { _value = x; } int System.Runtime.CompilerServices.ITuple.Length => 2; object System.Runtime.CompilerServices.ITuple.this[int i] => _value; } "; var comp = CreateCompilation([src, UnionAttributeSource], targetFramework: TargetFramework.NetCoreApp, options: TestOptions.ReleaseExe); CompileAndVerify(comp, expectedOutput: ExecutionConditionUtil.IsMonoOrCoreClr ? "TrueFalseFalseFalse" : null, verify: Verification.FailsPEVerify).VerifyDiagnostics(); comp = CreateCompilation([src, UnionAttributeSource], targetFramework: TargetFramework.NetCoreApp, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular15); CompileAndVerify(comp, expectedOutput: ExecutionConditionUtil.IsMonoOrCoreClr ? "TrueFalseFalseFalse" : null, verify: Verification.FailsPEVerify).VerifyDiagnostics(); comp = CreateCompilation([src, UnionAttributeSource], targetFramework: TargetFramework.NetCoreApp, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular14); comp.VerifyDiagnostics( // (23,29): error CS9327: Feature 'unions' is not available in C# 14.0. Please use language version 15.0 or greater. // return u is (S1 and 10, _); Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion14, "10").WithArguments("unions", "15.0").WithLocation(23, 29) ); } [Fact] public void UnionMatching_30_Deconstruction_Subpattern_01() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } public object Value => _value; } class Program { static void Main() { System.Console.Write(Test1(new C(new S1(10)))); System.Console.Write(Test1(new C(default))); System.Console.Write(Test1(new C(new S1(11)))); System.Console.Write(Test1(new C(new S1(""10"")))); } static bool Test1(C u) { return u is (10, _); } } class C { private readonly S1 _value; public C(S1 x) { _value = x; } public void Deconstruct(out S1 a, out int b) { a = _value; b = -1; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); CompileAndVerify(comp, expectedOutput: "TrueFalseFalseFalse").VerifyDiagnostics(); comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular15); CompileAndVerify(comp, expectedOutput: "TrueFalseFalseFalse").VerifyDiagnostics(); comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular14); comp.VerifyDiagnostics( // (23,22): error CS9327: Feature 'unions' is not available in C# 14.0. Please use language version 15.0 or greater. // return u is (10, _); Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion14, "10").WithArguments("unions", "15.0").WithLocation(23, 22) ); } [Fact] public void UnionMatching_30_Deconstruction_Subpattern_02() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } public object Value => _value; } class Program { static void Main() { System.Console.Write(Test1(new C(new S1(10)))); System.Console.Write(Test1(new C(default(S1)))); System.Console.Write(Test1(new C(new S1(11)))); System.Console.Write(Test1(new C(new S1(""10"")))); System.Console.Write(Test1(new C(null))); } static bool Test1(C u) { return u is (10, _); } } class C { private readonly S1? _value; public C(S1? x) { _value = x; } public void Deconstruct(out S1? a, out int b) { a = _value; b = -1; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); CompileAndVerify(comp, expectedOutput: "TrueFalseFalseFalseFalse").VerifyDiagnostics(); } [Fact] public void UnionMatching_31_Property_Subpattern_01() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } public object Value => _value; } class Program { static void Main() { System.Console.Write(Test1(new C(new S1(10)))); System.Console.Write(Test1(new C(default))); System.Console.Write(Test1(new C(new S1(11)))); System.Console.Write(Test1(new C(new S1(""10"")))); } static bool Test1(C u) { return u is { P: 10 }; } } class C { private readonly S1 _value; public C(S1 x) { _value = x; } public S1 P => _value; } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); CompileAndVerify(comp, expectedOutput: "TrueFalseFalseFalse").VerifyDiagnostics(); comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular15); CompileAndVerify(comp, expectedOutput: "TrueFalseFalseFalse").VerifyDiagnostics(); comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular14); comp.VerifyDiagnostics( // (23,26): error CS9327: Feature 'unions' is not available in C# 14.0. Please use language version 15.0 or greater. // return u is { P: 10 }; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion14, "10").WithArguments("unions", "15.0").WithLocation(23, 26) ); } [Fact] public void UnionMatching_31_Property_Subpattern_02() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } public object Value => _value; } class Program { static void Main() { System.Console.Write(Test1(new C(new S1(10)))); System.Console.Write(Test1(new C(default(S1)))); System.Console.Write(Test1(new C(new S1(11)))); System.Console.Write(Test1(new C(new S1(""10"")))); System.Console.Write(Test1(new C(null))); } static bool Test1(C u) { return u is { P: 10 }; } } class C { private readonly S1? _value; public C(S1? x) { _value = x; } public S1? P => _value; } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); CompileAndVerify(comp, expectedOutput: "TrueFalseFalseFalseFalse").VerifyDiagnostics(); } [Fact] public void UnionMatching_32_Negated_Subpattern() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } public object Value => _value; } class Program { static void Main() { System.Console.Write(Test1(new S1(10))); System.Console.Write(Test1(new S1())); System.Console.Write(Test1(new S1(11))); System.Console.Write(Test1(new S1(""10""))); System.Console.Write(Test1(null)); } static bool Test1(object u) { return u is not (S1 and 10); } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); CompileAndVerify(comp, expectedOutput: "FalseTrueTrueTrueTrue").VerifyDiagnostics(); comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular15); CompileAndVerify(comp, expectedOutput: "FalseTrueTrueTrueTrue").VerifyDiagnostics(); comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular14); comp.VerifyDiagnostics( // (24,33): error CS9327: Feature 'unions' is not available in C# 14.0. Please use language version 15.0 or greater. // return u is not (S1 and 10); Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion14, "10").WithArguments("unions", "15.0").WithLocation(24, 33) ); } [Fact] public void UnionMatching_33_SwitchLabel_01() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } public object Value => _value; } class Program { static void Main() { System.Console.Write(Test1(new S1(10))); System.Console.Write(Test1(default)); System.Console.Write(Test1(new S1(""11""))); System.Console.Write(Test1(new S1(0))); System.Console.Write(' '); System.Console.Write(Test2(new S1(10))); System.Console.Write(Test2(default)); System.Console.Write(Test2(new S1(""10""))); System.Console.Write(Test2(new S1(0))); } static bool Test1(S1 u) { switch (u) { case int: return true; default: return false; } } static bool Test2(S1 u) { switch (u) { case 10: return true; default: return false; } } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); CompileAndVerify(comp, expectedOutput: "TrueFalseFalseTrue TrueFalseFalseFalse").VerifyDiagnostics(); } [Fact] public void UnionMatching_33_SwitchLabel_02() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } public object Value => _value; } class Program { static void Main() { System.Console.Write(Test1(new S1(10))); System.Console.Write(Test1(default(S1))); System.Console.Write(Test1(new S1(""11""))); System.Console.Write(Test1(new S1(0))); System.Console.Write(Test1(null)); System.Console.Write(' '); System.Console.Write(Test2(new S1(10))); System.Console.Write(Test2(default(S1))); System.Console.Write(Test2(new S1(""10""))); System.Console.Write(Test2(new S1(0))); System.Console.Write(Test2(null)); } static bool Test1(S1? u) { switch (u) { case int: return true; default: return false; } } static bool Test2(S1? u) { switch (u) { case 10: return true; default: return false; } } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); CompileAndVerify(comp, expectedOutput: "TrueFalseFalseTrueFalse TrueFalseFalseFalseFalse").VerifyDiagnostics(); } [Fact] public void UnionMatching_34_BinaryAnd() { var src = @" [System.Runtime.CompilerServices.Union] struct S0 { private readonly object _value; public S0(S1 x) { _value = x; } public S0(string x) { _value = x; } public object Value => _value; } [System.Runtime.CompilerServices.Union] struct S1 { private readonly object _value; public S1(S2 x) { _value = x; } public S1(string x) { _value = x; } public object Value => _value; } [System.Runtime.CompilerServices.Union] struct S2 { private readonly object _value; public S2(int x) { _value = x; } public S2(string x) { _value = x; } public object Value => _value; } class Program { static void Main() { System.Console.Write(Test2(new S0(new S1(new S2(10))))); System.Console.Write(Test2(new S0(new S1(new S2(11))))); System.Console.Write(Test2(new S0(null))); System.Console.Write(Test2(new S0(new S1()))); System.Console.Write(Test2(new S0(new S1(new S2())))); System.Console.Write(Test2(new S0(new S1(""11"")))); System.Console.Write(Test2(new S0(new S1(new S2(""11""))))); System.Console.Write(' '); System.Console.Write(Test3(new S0(new S1(new S2(10))))); System.Console.Write(Test3(new S0(new S1(new S2(11))))); System.Console.Write(Test3(new S0(null))); System.Console.Write(Test3(new S0(new S1()))); System.Console.Write(Test3(new S0(new S1(new S2())))); System.Console.Write(Test3(new S0(new S1(""11"")))); System.Console.Write(Test3(new S0(new S1(new S2(""11""))))); } static bool Test2(S0 u) { return u is S1 and S2 and 10; } static bool Test3(S0 u) { return u is S1 and (S2 and 10); } } "; var comp = CreateCompilation([src, UnionAttributeSource], targetFramework: TargetFramework.NetLatest, options: TestOptions.ReleaseExe); CompileAndVerify(comp, expectedOutput: "TrueFalseFalseFalseFalseFalseFalse TrueFalseFalseFalseFalseFalseFalse").VerifyDiagnostics(); } [Fact] public void UnionMatching_35_TypeParameter() { var src = @" [System.Runtime.CompilerServices.Union] class C1 { private readonly object _value; public C1(int x) { _value = x; } public C1(string x) { _value = x; } public object Value => _value; } class Program { static void Main() { System.Console.Write(Test1(new C1(1))); System.Console.Write(Test2(new C1(""2""))); System.Console.Write(Test3(new C1(3))); System.Console.Write(Test4(new C1(4))); } static bool Test1<T>(T u) where T : C1 { return u is int; } static bool Test2<T>(T u) where T : C1 { return u is string; } static bool Test3<T>(T u) where T : C1 { return u is long; } static bool Test4<T>(T u) where T : C1 { return u is C1; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); var verifier = CompileAndVerify(comp, expectedOutput: "FalseFalseFalseTrue").VerifyDiagnostics(); verifier.VerifyIL("Program.Test1<T>(T)", @" { // Code size 15 (0xf) .maxstack 2 IL_0000: ldarg.0 IL_0001: box ""T"" IL_0006: isinst ""int"" IL_000b: ldnull IL_000c: cgt.un IL_000e: ret } "); verifier.VerifyIL("Program.Test2<T>(T)", @" { // Code size 15 (0xf) .maxstack 2 IL_0000: ldarg.0 IL_0001: box ""T"" IL_0006: isinst ""string"" IL_000b: ldnull IL_000c: cgt.un IL_000e: ret } "); verifier.VerifyIL("Program.Test3<T>(T)", @" { // Code size 15 (0xf) .maxstack 2 IL_0000: ldarg.0 IL_0001: box ""T"" IL_0006: isinst ""long"" IL_000b: ldnull IL_000c: cgt.un IL_000e: ret } "); verifier.VerifyIL("Program.Test4<T>(T)", @" { // Code size 10 (0xa) .maxstack 2 IL_0000: ldarg.0 IL_0001: box ""T"" IL_0006: ldnull IL_0007: cgt.un IL_0009: ret } "); } [Fact] public void UnionMatching_36_SwitchStatement() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } public object Value => _value; } class Program { static void Main() { System.Console.Write(Test1(new S1(10))); System.Console.Write(Test1(new S1(""10""))); System.Console.Write(Test1(default)); System.Console.Write(Test1(new S1(11))); System.Console.Write(Test1(new S1(""11""))); System.Console.Write(Test1(new S1(0))); System.Console.Write(' '); System.Console.Write(Test2(new S1(10))); System.Console.Write(Test2(new S1(""10""))); System.Console.Write(Test2(default(S1))); System.Console.Write(Test2(new S1(11))); System.Console.Write(Test2(new S1(""11""))); System.Console.Write(Test2(new S1(0))); System.Console.Write(Test2(null)); } static int Test1(S1 u) { switch (u) { case 10: return 1; case ""11"": return 2; } return -1; } static int Test2(S1? u) { switch (u) { case 10: return 1; case ""11"": return 2; } return -1; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); CompileAndVerify(comp, expectedOutput: "1-1-1-12-1 1-1-1-12-1-1").VerifyDiagnostics(); comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular15); CompileAndVerify(comp, expectedOutput: "1-1-1-12-1 1-1-1-12-1-1").VerifyDiagnostics(); comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular14); comp.VerifyDiagnostics( // (35,18): error CS9327: Feature 'unions' is not available in C# 14.0. Please use language version 15.0 or greater. // case 10: return 1; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion14, "10").WithArguments("unions", "15.0").WithLocation(35, 18), // (36,18): error CS9327: Feature 'unions' is not available in C# 14.0. Please use language version 15.0 or greater. // case "11": return 2; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion14, @"""11""").WithArguments("unions", "15.0").WithLocation(36, 18), // (46,18): error CS9327: Feature 'unions' is not available in C# 14.0. Please use language version 15.0 or greater. // case 10: return 1; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion14, "10").WithArguments("unions", "15.0").WithLocation(46, 18), // (47,18): error CS9327: Feature 'unions' is not available in C# 14.0. Please use language version 15.0 or greater. // case "11": return 2; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion14, @"""11""").WithArguments("unions", "15.0").WithLocation(47, 18) ); } [Fact] public void UnionMatching_37_SwitchStatement_01() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } public object Value => _value; } class Program { static void Main() { System.Console.Write(Test1(new S1(10))); System.Console.Write(Test1(new S1(""10""))); System.Console.Write(Test1(default)); System.Console.Write(Test1(new S1(11))); System.Console.Write(Test1(new S1(""11""))); System.Console.Write(Test1(new S1(0))); System.Console.Write(' '); System.Console.Write(Test2(new S1(10))); System.Console.Write(Test2(new S1(""10""))); System.Console.Write(Test2(default(S1))); System.Console.Write(Test2(new S1(11))); System.Console.Write(Test2(new S1(""11""))); System.Console.Write(Test2(new S1(0))); System.Console.Write(Test2(null)); System.Console.Write(' '); System.Console.Write(Test3(new S1(10))); System.Console.Write(Test3(new S1(""10""))); System.Console.Write(Test3(new S1(11))); System.Console.Write(Test3(new S1(""11""))); System.Console.Write(Test3(new S1(0))); } static int Test1(S1 u) { switch (u) { case null: return 66; case 10: goto case 44; case ""11"": goto case ""55""; case 44: return 44; case ""55"": return 55; case 11: goto case null; } return -1; } static int Test2(S1? u) { switch (u) { case null: return 66; case 10: goto case 44; case ""11"": goto case ""55""; case 44: return 44; case ""55"": return 55; } return -1; } static int Test3(S1? u) { switch (u) { case null: return 66; case 10: goto case null; case ""11"": goto case ""55""; case ""55"": return 55; } return -1; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); CompileAndVerify(comp, expectedOutput: "44-1666655-1 44-166-155-166 66-1-155-1").VerifyDiagnostics(); } [Fact] public void UnionMatching_37_SwitchStatement_02() { var src = @" [System.Runtime.CompilerServices.Union] class S1 { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } public object Value => _value; } class Program { static void Main() { System.Console.Write(Test2(new S1(10))); System.Console.Write(Test2(new S1(""10""))); System.Console.Write(Test2(new S1(11))); System.Console.Write(Test2(new S1(""11""))); System.Console.Write(Test2(new S1(0))); System.Console.Write(Test2(null)); System.Console.Write(' '); System.Console.Write(Test3(new S1(10))); System.Console.Write(Test3(new S1(""10""))); System.Console.Write(Test3(new S1(11))); System.Console.Write(Test3(new S1(""11""))); System.Console.Write(Test3(new S1(0))); } static int Test2(S1 u) { switch (u) { case null: return 66; case 10: goto case 44; case ""11"": goto case ""55""; case 44: return 44; case ""55"": return 55; } return -1; } static int Test3(S1 u) { switch (u) { case null: return 66; case 10: goto case null; case ""11"": goto case ""55""; case ""55"": return 55; } return -1; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); CompileAndVerify(comp, expectedOutput: "44-1-155-166 66-1-155-1").VerifyDiagnostics(); } [Fact] public void UnionMatching_37_SwitchStatement_03() { var src = @" [System.Runtime.CompilerServices.Union] class S1 { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } public S1(S1 x) { _value = x; } public object Value => _value; } class Program { static void Main() { System.Console.Write(Test2(new S1(10))); System.Console.Write(Test2(new S1(""10""))); System.Console.Write(Test2(new S1(11))); System.Console.Write(Test2(new S1(""11""))); System.Console.Write(Test2(new S1(0))); System.Console.Write(Test2(null)); System.Console.Write(' '); System.Console.Write(Test3(new S1(10))); System.Console.Write(Test3(new S1(""10""))); System.Console.Write(Test3(new S1(11))); System.Console.Write(Test3(new S1(""11""))); System.Console.Write(Test3(new S1(0))); } const S1 _S1_null = null; static int Test2(S1 u) { switch (u) { case _S1_null: return 66; case 10: goto case 44; case ""11"": goto case ""55""; case 44: return 44; case ""55"": return 55; } return -1; } static int Test3(S1 u) { switch (u) { case _S1_null: return 66; case 10: goto case _S1_null; case ""11"": goto case ""55""; case ""55"": return 55; } return -1; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); CompileAndVerify(comp, expectedOutput: "44-1-155-166 66-1-155-1").VerifyDiagnostics(); } [Fact] public void UnionMatching_38_SwitchStatement() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } public object Value => _value; } class Program { static int Test1(S1 u) { switch (u) { case 10: return 1; case ""11"": return 2; #line 18 case true: return 3; } return -1; } static int Test2(S1? u) { switch (u) { case 10: return 1; case ""11"": return 2; #line 30 case true: return 3; } return -1; } } "; var comp = CreateCompilation([src, UnionAttributeSource]); comp.VerifyDiagnostics( // (18,18): error CS9372: An expression of type 'S1' cannot be handled by this pattern, see additional errors at this location. // case true: return 3; Diagnostic(ErrorCode.ERR_UnionMatchingWrongPattern, "true").WithArguments("S1").WithLocation(18, 18), // (18,18): error CS0029: Cannot implicitly convert type 'bool' to 'int' // case true: return 3; Diagnostic(ErrorCode.ERR_NoImplicitConv, "true").WithArguments("bool", "int").WithLocation(18, 18), // (18,18): error CS0029: Cannot implicitly convert type 'bool' to 'string' // case true: return 3; Diagnostic(ErrorCode.ERR_NoImplicitConv, "true").WithArguments("bool", "string").WithLocation(18, 18), // (30,18): error CS9372: An expression of type 'S1' cannot be handled by this pattern, see additional errors at this location. // case true: return 3; Diagnostic(ErrorCode.ERR_UnionMatchingWrongPattern, "true").WithArguments("S1").WithLocation(30, 18), // (30,18): error CS0029: Cannot implicitly convert type 'bool' to 'int' // case true: return 3; Diagnostic(ErrorCode.ERR_NoImplicitConv, "true").WithArguments("bool", "int").WithLocation(30, 18), // (30,18): error CS0029: Cannot implicitly convert type 'bool' to 'string' // case true: return 3; Diagnostic(ErrorCode.ERR_NoImplicitConv, "true").WithArguments("bool", "string").WithLocation(30, 18) ); } [Fact] public void UnionMatching_39_SwitchStatement() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } public object Value => _value; } class Program { static int Test1(S1 u) { switch (u) { #line 16 case 10: goto case true; case ""11"": return 2; } return -1; } static int Test2(S1? u) { switch (u) { #line 27 case 10: goto case true; case ""11"": return 2; } return -1; } } "; var comp = CreateCompilation([src, UnionAttributeSource]); comp.VerifyDiagnostics( // (16,13): error CS0163: Control cannot fall through from one case label ('case 10:') to another // case 10: goto case true; Diagnostic(ErrorCode.ERR_SwitchFallThrough, "case 10:").WithArguments("case 10:").WithLocation(16, 13), // (16,22): error CS0029: Cannot implicitly convert type 'bool' to 'S1' // case 10: goto case true; Diagnostic(ErrorCode.ERR_NoImplicitConv, "goto case true;").WithArguments("bool", "S1").WithLocation(16, 22), // (27,13): error CS0163: Control cannot fall through from one case label ('case 10:') to another // case 10: goto case true; Diagnostic(ErrorCode.ERR_SwitchFallThrough, "case 10:").WithArguments("case 10:").WithLocation(27, 13), // (27,22): error CS0029: Cannot implicitly convert type 'bool' to 'S1?' // case 10: goto case true; Diagnostic(ErrorCode.ERR_NoImplicitConv, "goto case true;").WithArguments("bool", "S1?").WithLocation(27, 22) ); } [Fact] public void UnionMatching_40_Constant_PatternVsUnconstrainedTypeParameter05() { var source = @" [System.Runtime.CompilerServices.Union] class C<T> { public C(T x) { } public C(bool x) { } public object Value => throw null; static bool Test2(C<T> t) { return t is null; } static bool Test3(C<T> t) { return t is 1; } static bool Test4(C<T> t) { return t is ""frog""; } }"; var comp = CreateCompilation([source, UnionAttributeSource], options: TestOptions.ReleaseDll); var verifier = CompileAndVerify(comp).VerifyDiagnostics(); verifier.VerifyIL("C<T>.Test2(C<T>)", @" { // Code size 19 (0x13) .maxstack 1 .locals init (bool V_0) IL_0000: ldarg.0 IL_0001: brfalse.s IL_000b IL_0003: ldarg.0 IL_0004: callvirt ""object C<T>.Value.get"" IL_0009: brtrue.s IL_000f IL_000b: ldc.i4.1 IL_000c: stloc.0 IL_000d: br.s IL_0011 IL_000f: ldc.i4.0 IL_0010: stloc.0 IL_0011: ldloc.0 IL_0012: ret } "); verifier.VerifyIL("C<T>.Test3(C<T>)", @" { // Code size 30 (0x1e) .maxstack 2 .locals init (object V_0) IL_0000: ldarg.0 IL_0001: brfalse.s IL_001c IL_0003: ldarg.0 IL_0004: callvirt ""object C<T>.Value.get"" IL_0009: stloc.0 IL_000a: ldloc.0 IL_000b: isinst ""int"" IL_0010: brfalse.s IL_001c IL_0012: ldloc.0 IL_0013: unbox.any ""int"" IL_0018: ldc.i4.1 IL_0019: ceq IL_001b: ret IL_001c: ldc.i4.0 IL_001d: ret } "); verifier.VerifyIL("C<T>.Test4(C<T>)", @" { // Code size 32 (0x20) .maxstack 2 .locals init (string V_0) IL_0000: ldarg.0 IL_0001: brfalse.s IL_001e IL_0003: ldarg.0 IL_0004: callvirt ""object C<T>.Value.get"" IL_0009: isinst ""string"" IL_000e: stloc.0 IL_000f: ldloc.0 IL_0010: brfalse.s IL_001e IL_0012: ldloc.0 IL_0013: ldstr ""frog"" IL_0018: call ""bool string.op_Equality(string, string)"" IL_001d: ret IL_001e: ldc.i4.0 IL_001f: ret } "); } [Fact] public void UnionMatching_41_Constant_PatternVsUnconstrainedTypeParameter05() { var source = @" [System.Runtime.CompilerServices.Union] struct C<T> { public C(T x) { } public C(bool x) { } public object Value => throw null; static bool Test1(C<T>? t) { return t is null; } static bool Test2(C<T> t) { return t is null; } static bool Test3(C<T>? t) { return t is 1; } static bool Test4(C<T> t) { return t is ""frog""; } static bool Test5(C<T> t) { return t is (string)null; } }"; var comp = CreateCompilation([source, UnionAttributeSource], options: TestOptions.ReleaseDll); var verifier = CompileAndVerify(comp).VerifyDiagnostics(); verifier.VerifyIL("C<T>.Test1(C<T>?)", @" { // Code size 34 (0x22) .maxstack 1 .locals init (C<T> V_0, bool V_1) IL_0000: ldarga.s V_0 IL_0002: call ""bool C<T>?.HasValue.get"" IL_0007: brfalse.s IL_001a IL_0009: ldarga.s V_0 IL_000b: call ""C<T> C<T>?.GetValueOrDefault()"" IL_0010: stloc.0 IL_0011: ldloca.s V_0 IL_0013: call ""object C<T>.Value.get"" IL_0018: brtrue.s IL_001e IL_001a: ldc.i4.1 IL_001b: stloc.1 IL_001c: br.s IL_0020 IL_001e: ldc.i4.0 IL_001f: stloc.1 IL_0020: ldloc.1 IL_0021: ret } "); verifier.VerifyIL("C<T>.Test2(C<T>)", @" { // Code size 11 (0xb) .maxstack 2 IL_0000: ldarga.s V_0 IL_0002: call ""object C<T>.Value.get"" IL_0007: ldnull IL_0008: ceq IL_000a: ret } "); verifier.VerifyIL("C<T>.Test3(C<T>?)", @" { // Code size 45 (0x2d) .maxstack 2 .locals init (C<T> V_0, object V_1) IL_0000: ldarga.s V_0 IL_0002: call ""bool C<T>?.HasValue.get"" IL_0007: brfalse.s IL_002b IL_0009: ldarga.s V_0 IL_000b: call ""C<T> C<T>?.GetValueOrDefault()"" IL_0010: stloc.0 IL_0011: ldloca.s V_0 IL_0013: call ""object C<T>.Value.get"" IL_0018: stloc.1 IL_0019: ldloc.1 IL_001a: isinst ""int"" IL_001f: brfalse.s IL_002b IL_0021: ldloc.1 IL_0022: unbox.any ""int"" IL_0027: ldc.i4.1 IL_0028: ceq IL_002a: ret IL_002b: ldc.i4.0 IL_002c: ret } "); verifier.VerifyIL("C<T>.Test4(C<T>)", @" { // Code size 30 (0x1e) .maxstack 2 .locals init (string V_0) IL_0000: ldarga.s V_0 IL_0002: call ""object C<T>.Value.get"" IL_0007: isinst ""string"" IL_000c: stloc.0 IL_000d: ldloc.0 IL_000e: brfalse.s IL_001c IL_0010: ldloc.0 IL_0011: ldstr ""frog"" IL_0016: call ""bool string.op_Equality(string, string)"" IL_001b: ret IL_001c: ldc.i4.0 IL_001d: ret } "); verifier.VerifyIL("C<T>.Test5(C<T>)", @" { // Code size 11 (0xb) .maxstack 2 IL_0000: ldarga.s V_0 IL_0002: call ""object C<T>.Value.get"" IL_0007: ldnull IL_0008: ceq IL_000a: ret } "); } [Fact] public void UnionMatching_42_Constant_PatternVsUnconstrainedTypeParameter05() { var source = @" [System.Runtime.CompilerServices.Union] class C<T> { public C(T x) { } public C(bool x) { } public object Value => throw null; static bool Test2(C<T> t) { return t is (string)null; } static bool Test3(C<T> t) { const string s_null = null; return t is s_null; } static bool Test4(C<T> t) { const C<int> C_null = null; return t is C_null; } } "; var comp = CreateCompilation([source, UnionAttributeSource], options: TestOptions.ReleaseDll); comp.VerifyDiagnostics( // (11,21): error CS9135: A constant value of type 'C<T>' is expected // return t is (string)null; Diagnostic(ErrorCode.ERR_ConstantValueOfTypeExpected, "(string)null").WithArguments("C<T>").WithLocation(11, 21), // (17,21): error CS9135: A constant value of type 'C<T>' is expected // return t is s_null; Diagnostic(ErrorCode.ERR_ConstantValueOfTypeExpected, "s_null").WithArguments("C<T>").WithLocation(17, 21), // (23,21): error CS9135: A constant value of type 'C<T>' is expected // return t is C_null; Diagnostic(ErrorCode.ERR_ConstantValueOfTypeExpected, "C_null").WithArguments("C<T>").WithLocation(23, 21) ); } [Fact] public void UnionMatching_43_Constant_PatternVsUnconstrainedTypeParameter05() { var source = @" [System.Runtime.CompilerServices.Union] class C<T> { public C(C<T> x) { } public C(bool x) { } public object Value => throw null; static bool Test2(C<T> t) { const C<T> C_null = null; return t is C_null; } }"; var comp = CreateCompilation([source, UnionAttributeSource], options: TestOptions.ReleaseDll); var verifier = CompileAndVerify(comp).VerifyDiagnostics(); verifier.VerifyIL("C<T>.Test2(C<T>)", @" { // Code size 19 (0x13) .maxstack 1 .locals init (bool V_0) IL_0000: ldarg.0 IL_0001: brfalse.s IL_000b IL_0003: ldarg.0 IL_0004: callvirt ""object C<T>.Value.get"" IL_0009: brtrue.s IL_000f IL_000b: ldc.i4.1 IL_000c: stloc.0 IL_000d: br.s IL_0011 IL_000f: ldc.i4.0 IL_0010: stloc.0 IL_0011: ldloc.0 IL_0012: ret } "); } [Fact] public void UnionMatching_44_Constant_PatternVsUnconstrainedTypeParameter05() { var source = @" [System.Runtime.CompilerServices.Union] struct C<T> { public C(T x) { } public C(bool x) { } public object Value => throw null; static bool Test1(C<T>? t) { return t is (string)null; } static bool Test2(C<T>? t) { const string s_null = null; return t is s_null; } }"; var comp = CreateCompilation([source, UnionAttributeSource], options: TestOptions.ReleaseDll); comp.VerifyDiagnostics( // (11,21): error CS9135: A constant value of type 'C<T>' is expected // return t is (string)null; Diagnostic(ErrorCode.ERR_ConstantValueOfTypeExpected, "(string)null").WithArguments("C<T>").WithLocation(11, 21), // (17,21): error CS9135: A constant value of type 'C<T>' is expected // return t is s_null; Diagnostic(ErrorCode.ERR_ConstantValueOfTypeExpected, "s_null").WithArguments("C<T>").WithLocation(17, 21) ); } [Theory] [InlineData("(short)0", "True")] [InlineData("short.MinValue", "True")] [InlineData("short.MaxValue", "True")] [InlineData("-1", "False")] [InlineData("(object)null", "False")] [InlineData("string.Empty", "False")] public void UnionMatching_45_Constant_ObviousTestAfterTypeTest(string value, string expected) { var source = $@" System.Console.Write(Extenders.F(Extenders.GetUnion({value}))); static class Extenders {{ public const short MaxValue = 0x7FFF; public static bool F<T>(U1<T> value) => value switch {{ <= MaxValue => true, _ => false }}; public static U1<T> GetUnion<T>(T x) => new U1<T>(x); }} [System.Runtime.CompilerServices.Union] struct U1<T> {{ private readonly object _value; public U1(T x) {{ _value = x; }} public object Value => _value; }} "; CompileAndVerify([source, UnionAttributeSource], expectedOutput: expected).VerifyDiagnostics(); } [Theory] [InlineData("(short)0", "True")] [InlineData("short.MinValue", "True")] [InlineData("short.MaxValue", "True")] [InlineData("-1", "False")] [InlineData("(object)null", "False")] [InlineData("string.Empty", "False")] public void UnionMatching_46_Constant_ObviousTestAfterTypeTest(string value, string expected) { var source = $@" System.Console.Write(Extenders.F(Extenders.GetUnion({value}))); static class Extenders {{ public const short MaxValue = 0x7FFF; public static bool F<T>(U1<T> value) => value switch {{ <= MaxValue => true, _ => false }}; public static U1<T> GetUnion<T>(T x) => new U1<T>(x); }} [System.Runtime.CompilerServices.Union] class U1<T> {{ private readonly object _value; public U1(T x) {{ _value = x; }} public object Value => _value; }} "; CompileAndVerify([source, UnionAttributeSource], expectedOutput: expected).VerifyDiagnostics(); } [Fact] public void UnionMatching_47_Constant_ObviousTestAfterTypeTest_UnsignedIntegerNegative() { var source = @" public class C { void M<T>(U<T> o) { _ = o switch { < (uint)0 => 0, _ => 2 }; } } [System.Runtime.CompilerServices.Union] struct U<T> { private readonly object _value; public U(T x) { _value = x; } public object Value => _value; } "; CreateCompilation([source, UnionAttributeSource]).VerifyDiagnostics( // (8,12): error CS8510: The pattern is unreachable. It has already been handled by a previous arm of the switch expression or it is impossible to match. // < (uint)0 => 0, Diagnostic(ErrorCode.ERR_SwitchArmSubsumed, "< (uint)0").WithLocation(8, 12) ); } [Theory] [InlineData("(uint)0", "0")] [InlineData("uint.MaxValue", "0")] [InlineData("-1", "1")] [InlineData("(object)null", "1")] [InlineData("string.Empty", "1")] public void UnionMatching_48_Constant_ObviousTestAfterTypeTest_UnsignedIntegerNonNegative(string value, string expected) { var source = $@" System.Console.Write(M(GetUnion({value}))); int M<T>(U<T> o) {{ return o switch {{ >= (uint)0 => 0, _ => 1 }}; }} U<T> GetUnion<T>(T x) => new U<T>(x); [System.Runtime.CompilerServices.Union] class U<T> {{ private readonly object _value; public U(T x) {{ _value = x; }} public object Value => _value; }} "; CompileAndVerify([source, UnionAttributeSource], expectedOutput: expected).VerifyDiagnostics(); } [Theory] [InlineData("(int)0", "1")] [InlineData("(int)255", "1")] [InlineData("int.MinValue", "1")] [InlineData("int.MaxValue", "4")] [InlineData("(short)0", "2")] [InlineData("(short)255", "2")] [InlineData("short.MinValue", "2")] [InlineData("short.MaxValue", "2")] [InlineData("(uint)0", "8")] public void UnionMatching_49_Constant_ObviousTestAfterTypeTest2(string value, string expected) { var source = $@" System.Console.Write(Extenders.F(Extenders.GetUnion({value}))); public static class Extenders {{ public static int F<T>(this U<T> value) where T : struct {{ int elementSize = value switch {{ <= 255 => 1, <= short.MaxValue => 2, <= int.MaxValue => 4, _ => 8 }}; return elementSize; }} public static U<T> GetUnion<T>(T x) => new U<T>(x); }} [System.Runtime.CompilerServices.Union] public class U<T> {{ private readonly object _value; public U(T x) {{ _value = x; }} public object Value => _value; }} "; var comp = CreateCompilationWithSpan([source, UnionAttributeSource]); comp.VerifyDiagnostics(); CompileAndVerify(comp, expectedOutput: expected); } [Fact] public void UnionMatching_50_Direct_Value_Matching() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } public object Value => _value; } class Program { static void Main() { System.Console.Write(Test1(new S1(10))); System.Console.Write(Test1(default(S1))); System.Console.Write(Test1(new S1(""11""))); System.Console.Write(Test1(new S1(0))); System.Console.Write(Test1(null)); System.Console.Write(' '); System.Console.Write(Test2(new S1(10))); System.Console.Write(Test2(default(S1))); System.Console.Write(Test2(new S1(""11""))); System.Console.Write(Test2(new S1(0))); System.Console.Write(Test2(new S1(11))); System.Console.Write(' '); System.Console.Write(Test3(new S1(11))); System.Console.Write(Test3(default(S1))); System.Console.Write(Test3(new S1(""11""))); System.Console.Write(' '); System.Console.Write(Test4(new S1(11))); System.Console.Write(Test4(default(S1))); System.Console.Write(Test4(new S1(""11""))); } static bool Test1(object u) { #line 41 return u is S1 { Value: 10 }; } static bool Test2(object u) { #line 46 return u is S1 { Value: 10 or 11 }; } static bool Test3(object u) { #line 51 return u is S1 { Value: ""11"" and ['1', '1'] }; } static bool Test4(object u) { #line 56 return u is S1 { Value: null }; } } "; var comp = CreateCompilation([src, UnionAttributeSource], targetFramework: TargetFramework.NetCoreApp, options: TestOptions.ReleaseExe); var verifier = CompileAndVerify(comp, expectedOutput: ExecutionConditionUtil.IsMonoOrCoreClr ? "TrueFalseFalseFalseFalse TrueFalseFalseFalseTrue FalseFalseTrue FalseTrueFalse" : null, verify: Verification.FailsPEVerify).VerifyDiagnostics(); verifier.VerifyIL("Program.Test1", @" { // Code size 44 (0x2c) .maxstack 2 .locals init (S1 V_0, object V_1) IL_0000: ldarg.0 IL_0001: isinst ""S1"" IL_0006: brfalse.s IL_002a IL_0008: ldarg.0 IL_0009: unbox.any ""S1"" IL_000e: stloc.0 IL_000f: ldloca.s V_0 IL_0011: call ""object S1.Value.get"" IL_0016: stloc.1 IL_0017: ldloc.1 IL_0018: isinst ""int"" IL_001d: brfalse.s IL_002a IL_001f: ldloc.1 IL_0020: unbox.any ""int"" IL_0025: ldc.i4.s 10 IL_0027: ceq IL_0029: ret IL_002a: ldc.i4.0 IL_002b: ret } "); comp = CreateCompilation([src, UnionAttributeSource], targetFramework: TargetFramework.NetCoreApp, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular15); CompileAndVerify(comp, expectedOutput: ExecutionConditionUtil.IsMonoOrCoreClr ? "TrueFalseFalseFalseFalse TrueFalseFalseFalseTrue FalseFalseTrue FalseTrueFalse" : null, verify: Verification.FailsPEVerify).VerifyDiagnostics(); comp = CreateCompilation([src, UnionAttributeSource], targetFramework: TargetFramework.NetCoreApp, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular14); comp.VerifyEmitDiagnostics( // (41,26): error CS9327: Feature 'unions' is not available in C# 14.0. Please use language version 15.0 or greater. // return u is S1 { Value: 10 }; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion14, "Value").WithArguments("unions", "15.0").WithLocation(41, 26), // (46,26): error CS9327: Feature 'unions' is not available in C# 14.0. Please use language version 15.0 or greater. // return u is S1 { Value: 10 or 11 }; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion14, "Value").WithArguments("unions", "15.0").WithLocation(46, 26), // (51,26): error CS9327: Feature 'unions' is not available in C# 14.0. Please use language version 15.0 or greater. // return u is S1 { Value: "11" and ['1', '1'] }; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion14, "Value").WithArguments("unions", "15.0").WithLocation(51, 26), // (56,26): error CS9327: Feature 'unions' is not available in C# 14.0. Please use language version 15.0 or greater. // return u is S1 { Value: null }; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion14, "Value").WithArguments("unions", "15.0").WithLocation(56, 26) ); } [Theory] [CombinatorialData] public void UnionMatching_51_Direct_Value_Matching(bool field) { var src = @" [System.Runtime.CompilerServices.Union] struct S1 { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } public object Value => _value; } struct S2 { public S2(S1 s1) { S1 = s1; } public S1 S1" + (field ? ";" : " { get; }") + @" } class Program { static void Main() { System.Console.Write(Test1(new S2(new S1(10)))); System.Console.Write(Test1(new S2(default(S1)))); System.Console.Write(Test1(new S2(new S1(""11"")))); System.Console.Write(Test1(new S2(new S1(0)))); System.Console.Write(Test1(new S2(new S1(null)))); System.Console.Write(' '); System.Console.Write(Test2(new S2(new S1(10)))); System.Console.Write(Test2(new S2(default(S1)))); System.Console.Write(Test2(new S2(new S1(""11"")))); System.Console.Write(Test2(new S2(new S1(0)))); System.Console.Write(Test2(new S2(new S1(11)))); System.Console.Write(' '); System.Console.Write(Test3(new S2(new S1(11)))); System.Console.Write(Test3(new S2(default(S1)))); System.Console.Write(Test3(new S2(new S1(""11"")))); System.Console.Write(' '); System.Console.Write(Test4(new S2(new S1(11)))); System.Console.Write(Test4(new S2(default(S1)))); System.Console.Write(Test4(new S2(new S1(""11"")))); } static bool Test1(S2 u) { #line 41 return u is { S1.Value: 10 }; } static bool Test2(S2 u) { #line 46 return u is { S1.Value: 10 or 11 }; } static bool Test3(S2 u) { #line 51 return u is { S1.Value: ""11"" and ['1', '1'] }; } static bool Test4(S2 u) { #line 56 return u is { S1.Value: null }; } } "; var comp = CreateCompilation([src, UnionAttributeSource], targetFramework: TargetFramework.NetCoreApp, options: TestOptions.ReleaseExe); CompileAndVerify(comp, expectedOutput: ExecutionConditionUtil.IsMonoOrCoreClr ? "TrueFalseFalseFalseFalse TrueFalseFalseFalseTrue FalseFalseTrue FalseTrueFalse" : null, verify: Verification.FailsPEVerify).VerifyDiagnostics(); comp = CreateCompilation([src, UnionAttributeSource], targetFramework: TargetFramework.NetCoreApp, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular15); CompileAndVerify(comp, expectedOutput: ExecutionConditionUtil.IsMonoOrCoreClr ? "TrueFalseFalseFalseFalse TrueFalseFalseFalseTrue FalseFalseTrue FalseTrueFalse" : null, verify: Verification.FailsPEVerify).VerifyDiagnostics(); comp = CreateCompilation([src, UnionAttributeSource], targetFramework: TargetFramework.NetCoreApp, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular14); comp.VerifyEmitDiagnostics( // (41,26): error CS9327: Feature 'unions' is not available in C# 14.0. Please use language version 15.0 or greater. // return u is { S1.Value: 10 }; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion14, "Value").WithArguments("unions", "15.0").WithLocation(41, 26), // (46,26): error CS9327: Feature 'unions' is not available in C# 14.0. Please use language version 15.0 or greater. // return u is { S1.Value: 10 or 11 }; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion14, "Value").WithArguments("unions", "15.0").WithLocation(46, 26), // (51,26): error CS9327: Feature 'unions' is not available in C# 14.0. Please use language version 15.0 or greater. // return u is { S1.Value: "11" and ['1', '1'] }; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion14, "Value").WithArguments("unions", "15.0").WithLocation(51, 26), // (56,26): error CS9327: Feature 'unions' is not available in C# 14.0. Please use language version 15.0 or greater. // return u is { S1.Value: null }; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion14, "Value").WithArguments("unions", "15.0").WithLocation(56, 26) ); } [Theory] [CombinatorialData] public void UnionMatching_52_Direct_Value_Matching(bool field) { var src = @" [System.Runtime.CompilerServices.Union] struct S1 { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } public object Value => _value; } struct S2 { public S2(S1? s1) { S1 = s1; } public S1? S1" + (field ? ";" : " { get; }") + @" } class Program { static void Main() { System.Console.Write(Test1(new S2(new S1(10)))); System.Console.Write(Test1(new S2(default(S1)))); System.Console.Write(Test1(new S2(new S1(""11"")))); System.Console.Write(Test1(new S2(new S1(0)))); System.Console.Write(Test1(new S2(null))); System.Console.Write(' '); System.Console.Write(Test2(new S2(new S1(10)))); System.Console.Write(Test2(new S2(default(S1)))); System.Console.Write(Test2(new S2(new S1(""11"")))); System.Console.Write(Test2(new S2(new S1(0)))); System.Console.Write(Test2(new S2(new S1(11)))); System.Console.Write(Test2(new S2(null))); System.Console.Write(' '); System.Console.Write(Test3(new S2(new S1(11)))); System.Console.Write(Test3(new S2(default(S1)))); System.Console.Write(Test3(new S2(new S1(""11"")))); System.Console.Write(Test3(new S2(null))); System.Console.Write(' '); System.Console.Write(Test4(new S2(new S1(11)))); System.Console.Write(Test4(new S2(default(S1)))); System.Console.Write(Test4(new S2(new S1(""11"")))); System.Console.Write(Test4(new S2(null))); System.Console.Write(' '); System.Console.Write(Test5(new S2(new S1(10)))); System.Console.Write(Test5(new S2(default(S1)))); System.Console.Write(Test5(new S2(new S1(""11"")))); System.Console.Write(Test5(new S2(new S1(0)))); System.Console.Write(Test5(new S2(null))); } static bool Test1(S2 u) { #line 41 return u is { S1.Value: 10 }; } static bool Test2(S2 u) { #line 46 return u is { S1.Value: 10 or 11 }; } static bool Test3(S2 u) { #line 51 return u is { S1.Value: ""11"" and ['1', '1'] }; } static bool Test4(S2 u) { #line 56 return u is { S1.Value: null }; } static bool Test5(S2 u) { #line 500 return u is { S1: { Value: 10 } }; } } "; var comp = CreateCompilation([src, UnionAttributeSource], targetFramework: TargetFramework.NetCoreApp, options: TestOptions.ReleaseExe); CompileAndVerify(comp, expectedOutput: ExecutionConditionUtil.IsMonoOrCoreClr ? "TrueFalseFalseFalseFalse TrueFalseFalseFalseTrueFalse FalseFalseTrueFalse FalseTrueFalseFalse TrueFalseFalseFalseFalse" : null, verify: Verification.FailsPEVerify).VerifyDiagnostics(); comp = CreateCompilation([src, UnionAttributeSource], targetFramework: TargetFramework.NetCoreApp, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular15); CompileAndVerify(comp, expectedOutput: ExecutionConditionUtil.IsMonoOrCoreClr ? "TrueFalseFalseFalseFalse TrueFalseFalseFalseTrueFalse FalseFalseTrueFalse FalseTrueFalseFalse TrueFalseFalseFalseFalse" : null, verify: Verification.FailsPEVerify).VerifyDiagnostics(); comp = CreateCompilation([src, UnionAttributeSource], targetFramework: TargetFramework.NetCoreApp, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular14); comp.VerifyEmitDiagnostics( // (41,26): error CS9327: Feature 'unions' is not available in C# 14.0. Please use language version 15.0 or greater. // return u is { S1.Value: 10 }; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion14, "Value").WithArguments("unions", "15.0").WithLocation(41, 26), // (46,26): error CS9327: Feature 'unions' is not available in C# 14.0. Please use language version 15.0 or greater. // return u is { S1.Value: 10 or 11 }; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion14, "Value").WithArguments("unions", "15.0").WithLocation(46, 26), // (51,26): error CS9327: Feature 'unions' is not available in C# 14.0. Please use language version 15.0 or greater. // return u is { S1.Value: "11" and ['1', '1'] }; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion14, "Value").WithArguments("unions", "15.0").WithLocation(51, 26), // (56,26): error CS9327: Feature 'unions' is not available in C# 14.0. Please use language version 15.0 or greater. // return u is { S1.Value: null }; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion14, "Value").WithArguments("unions", "15.0").WithLocation(56, 26), // (500,29): error CS9327: Feature 'unions' is not available in C# 14.0. Please use language version 15.0 or greater. // return u is { S1: { Value: 10 } }; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion14, "Value").WithArguments("unions", "15.0").WithLocation(500, 29) ); } [Fact] public void UnionMatching_54_Direct_Value_Matching() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } public object Value => _value; } class Program { static void Main() { System.Console.Write(Test1(new S1(10))); System.Console.Write(Test1(default(S1))); System.Console.Write(Test1(new S1(""11""))); System.Console.Write(Test1(new S1(0))); System.Console.Write(Test1(null)); } static bool Test1(object u) { #line 100 return u is S1 { Value.P: 10 }; } static bool Test2(object u) { #line 200 return u is S1 { Value.P: long }; } } static class Ext { extension (object o) { public object P => o; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); CompileAndVerify(comp, expectedOutput: "TrueFalseFalseFalseFalse").VerifyDiagnostics(); comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular15); CompileAndVerify(comp, expectedOutput: "TrueFalseFalseFalseFalse").VerifyDiagnostics(); comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular14); CompileAndVerify(comp, expectedOutput: "TrueFalseFalseFalseFalse").VerifyDiagnostics(); } [Fact] public void PatternWrongType_TypePattern_01_BindConstantPatternWithFallbackToTypePattern_UnionType_In_But_Not_Out() { var src1 = @" [System.Runtime.CompilerServices.Union] struct S1 { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } public S1(C2 x) { _value = x; } public S1(C3 x) { _value = x; } public object Value => _value; } class C1; class C2 : C1; class C3; class C4 : C1; class C5 : C2; "; var src2 = @" class Program { static void Test1(S1 u) { #line 100 _ = u is C1 and C2; _ = u is C1 and C3; _ = u is C1 and C4; _ = u switch { C4 => 1, _ => 0 }; C2 x = new C5(); _ = x is C1 and C4; } static void Test2(S1? u) { #line 200 _ = u is C1 and C2; _ = u is C1 and C3; _ = u is C1 and C4; _ = u switch { C4 => 1, _ => 0 }; } } "; var comp = CreateCompilation([src2, src1, UnionAttributeSource], targetFramework: TargetFramework.NetCoreApp); comp.VerifyDiagnostics( // (101,25): error CS8121: An expression of type 'C1' cannot be handled by a pattern of type 'C3'. // _ = u is C1 and C3; Diagnostic(ErrorCode.ERR_PatternWrongType, "C3").WithArguments("C1", "C3").WithLocation(101, 25), // (103,24): error CS8121: An expression of type 'S1' cannot be handled by a pattern of type 'C4'. // _ = u switch { C4 => 1, _ => 0 }; Diagnostic(ErrorCode.ERR_PatternWrongType, "C4").WithArguments("S1", "C4").WithLocation(103, 24), // (201,25): error CS8121: An expression of type 'C1' cannot be handled by a pattern of type 'C3'. // _ = u is C1 and C3; Diagnostic(ErrorCode.ERR_PatternWrongType, "C3").WithArguments("C1", "C3").WithLocation(201, 25), // (203,24): error CS8121: An expression of type 'S1' cannot be handled by a pattern of type 'C4'. // _ = u switch { C4 => 1, _ => 0 }; Diagnostic(ErrorCode.ERR_PatternWrongType, "C4").WithArguments("S1", "C4").WithLocation(203, 24) ); } [Fact] public void PatternWrongType_TypePattern_02_BindTypePattern_UnionType_In_But_Not_Out() { var src1 = @" [System.Runtime.CompilerServices.Union] struct S1 { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } public S1(C2 x) { _value = x; } public S1(C3 x) { _value = x; } public object Value => _value; } class C1; class C2 : C1; class C3; class C4 : C1; class C5 : C2; "; var src2 = @" class Program { static void Test4(S1 u) { #line 400 _ = u is System.IComparable and string; _ = u is string and int; _ = u is System.IComparable and byte; _ = u switch { byte => 1, _ => 0 }; int x = 0; #line 450 _ = x is System.IComparable and byte; } static void Test5(S1? u) { #line 500 _ = u is System.IComparable and string; _ = u is string and int; _ = u is System.IComparable and byte; _ = u switch { byte => 1, _ => 0 }; int? x = 0; #line 550 _ = x is System.IComparable and byte; } } "; var comp = CreateCompilation([src2, src1, UnionAttributeSource], targetFramework: TargetFramework.NetCoreApp); comp.VerifyDiagnostics( // (401,29): error CS8121: An expression of type 'string' cannot be handled by a pattern of type 'int'. // _ = u is string and int; Diagnostic(ErrorCode.ERR_PatternWrongType, "int").WithArguments("string", "int").WithLocation(401, 29), // (403,24): error CS8121: An expression of type 'S1' cannot be handled by a pattern of type 'byte'. // _ = u switch { byte => 1, _ => 0 }; Diagnostic(ErrorCode.ERR_PatternWrongType, "byte").WithArguments("S1", "byte").WithLocation(403, 24), // (501,29): error CS8121: An expression of type 'string' cannot be handled by a pattern of type 'int'. // _ = u is string and int; Diagnostic(ErrorCode.ERR_PatternWrongType, "int").WithArguments("string", "int").WithLocation(501, 29), // (503,24): error CS8121: An expression of type 'S1' cannot be handled by a pattern of type 'byte'. // _ = u switch { byte => 1, _ => 0 }; Diagnostic(ErrorCode.ERR_PatternWrongType, "byte").WithArguments("S1", "byte").WithLocation(503, 24) ); } [Fact] public void PatternWrongType_TypePattern_03() { var src1 = @" [System.Runtime.CompilerServices.Union] struct S1 { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } public S1(C2 x) { _value = x; } public S1(C3 x) { _value = x; } public object Value => _value; } class C1; class C2 : C1; class C3; class C4 : C1; class C5 : C2; "; var src2 = @" class Program { static void Test4(S1 u) { #line 400 switch (u) { case string: break; case byte: break; } } static void Test5(S1? u) { #line 500 switch (u) { case string: break; case byte: break; } } } "; var comp = CreateCompilation([src2, src1, UnionAttributeSource], targetFramework: TargetFramework.NetCoreApp); comp.VerifyDiagnostics( // (404,18): error CS8121: An expression of type 'S1' cannot be handled by a pattern of type 'byte'. // case byte: Diagnostic(ErrorCode.ERR_PatternWrongType, "byte").WithArguments("S1", "byte").WithLocation(404, 18), // (504,18): error CS8121: An expression of type 'S1' cannot be handled by a pattern of type 'byte'. // case byte: Diagnostic(ErrorCode.ERR_PatternWrongType, "byte").WithArguments("S1", "byte").WithLocation(504, 18) ); } [Fact] public void PatternWrongType_TypePattern_04_BindIsOperator() { var src1 = @" [System.Runtime.CompilerServices.Union] struct S1 { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } public object Value => _value; } "; var src2 = @" class Program { static void Test4(S1 u) { _ = u is System.IComparable; _ = u is int; _ = u is string; #line 300 _ = u is object; #line 400 _ = u is long; } static void Test5(S1? u) { _ = u is System.IComparable; _ = u is int; _ = u is string; _ = u is object; #line 500 _ = u is long; } static void Test6(S2 u) { #line 600 _ = u is object; #line 700 _ = u is long; } static void Test7(S2? u) { _ = u is object; #line 800 _ = u is long; } } struct S2; "; var comp = CreateCompilation([src2, src1, UnionAttributeSource], targetFramework: TargetFramework.NetCoreApp); comp.VerifyDiagnostics( // (300,13): warning CS0183: The given expression is always of the provided ('object') type // _ = u is object; Diagnostic(ErrorCode.WRN_IsAlwaysTrue, "u is object").WithArguments("object").WithLocation(300, 13), // (400,13): warning CS0184: The given expression is never of the provided ('long') type // _ = u is long; Diagnostic(ErrorCode.WRN_IsAlwaysFalse, "u is long").WithArguments("long").WithLocation(400, 13), // (500,13): warning CS0184: The given expression is never of the provided ('long') type // _ = u is long; Diagnostic(ErrorCode.WRN_IsAlwaysFalse, "u is long").WithArguments("long").WithLocation(500, 13), // (600,13): warning CS0183: The given expression is always of the provided ('object') type // _ = u is object; Diagnostic(ErrorCode.WRN_IsAlwaysTrue, "u is object").WithArguments("object").WithLocation(600, 13), // (700,13): warning CS0184: The given expression is never of the provided ('long') type // _ = u is long; Diagnostic(ErrorCode.WRN_IsAlwaysFalse, "u is long").WithArguments("long").WithLocation(700, 13), // (800,13): warning CS0184: The given expression is never of the provided ('long') type // _ = u is long; Diagnostic(ErrorCode.WRN_IsAlwaysFalse, "u is long").WithArguments("long").WithLocation(800, 13) ); } [Fact] public void PatternWrongType_RecursivePattern_01_BindRecursivePattern_UnionType_In() { var src1 = @" [System.Runtime.CompilerServices.Union] struct S1 { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } public S1(C2 x) { _value = x; } public S1(C3 x) { _value = x; } public object Value => _value; } class C1; class C2 : C1; class C3; class C4 : C1; class C5 : C2; "; var src2 = @" class Program { static void Test2(S1 u) { #line 200 _ = u is {} and C2 {}; _ = u is {} and C3 {}; _ = u is {} and C4 {}; _ = u is C4 {}; } static void Test3(S1? u) { #line 300 _ = u is {} and C2 {}; _ = u is {} and C3 {}; _ = u is {} and C4 {}; _ = u is C4 {}; } } "; var comp = CreateCompilation([src2, src1, UnionAttributeSource], targetFramework: TargetFramework.NetCoreApp); comp.VerifyDiagnostics( // (202,25): error CS8121: An expression of type 'S1' cannot be handled by a pattern of type 'C4'. // _ = u is {} and C4 {}; Diagnostic(ErrorCode.ERR_PatternWrongType, "C4").WithArguments("S1", "C4").WithLocation(202, 25), // (203,18): error CS8121: An expression of type 'S1' cannot be handled by a pattern of type 'C4'. // _ = u is C4 {}; Diagnostic(ErrorCode.ERR_PatternWrongType, "C4").WithArguments("S1", "C4").WithLocation(203, 18), // (302,25): error CS8121: An expression of type 'S1' cannot be handled by a pattern of type 'C4'. // _ = u is {} and C4 {}; Diagnostic(ErrorCode.ERR_PatternWrongType, "C4").WithArguments("S1", "C4").WithLocation(302, 25), // (303,18): error CS8121: An expression of type 'S1' cannot be handled by a pattern of type 'C4'. // _ = u is C4 {}; Diagnostic(ErrorCode.ERR_PatternWrongType, "C4").WithArguments("S1", "C4").WithLocation(303, 18) ); } [Fact] public void PatternWrongType_RecursivePattern_02_BindRecursivePattern_UnionType_Out() { var src1 = @" [System.Runtime.CompilerServices.Union] struct S1 { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } public S1(C2 x) { _value = x; } public S1(C3 x) { _value = x; } public object Value => _value; } class C1; class C2 : C1; class C3; class C4 : C1; class C5 : C2; "; var src2 = @" class Program { static void Test10(S1 u) { #line 1000 _ = u is C1 {} and C2; _ = u is C1 {} and C3; _ = u is {} and C4; _ = u is C1 {} and C4; C2 x = new C5(); _ = x is C1 {} and C4; } static void Test20(S1? u) { #line 2000 _ = u is C1 {} and C2; _ = u is C1 {} and C3; _ = u is {} and C4; _ = u is C1 {} and C4; } } "; var comp = CreateCompilation([src2, src1, UnionAttributeSource], targetFramework: TargetFramework.NetCoreApp); comp.VerifyDiagnostics( // (1001,28): error CS8121: An expression of type 'C1' cannot be handled by a pattern of type 'C3'. // _ = u is C1 {} and C3; Diagnostic(ErrorCode.ERR_PatternWrongType, "C3").WithArguments("C1", "C3").WithLocation(1001, 28), // (1002,25): error CS8121: An expression of type 'S1' cannot be handled by a pattern of type 'C4'. // _ = u is {} and C4; Diagnostic(ErrorCode.ERR_PatternWrongType, "C4").WithArguments("S1", "C4").WithLocation(1002, 25), // (2001,28): error CS8121: An expression of type 'C1' cannot be handled by a pattern of type 'C3'. // _ = u is C1 {} and C3; Diagnostic(ErrorCode.ERR_PatternWrongType, "C3").WithArguments("C1", "C3").WithLocation(2001, 28), // (2002,25): error CS8121: An expression of type 'S1' cannot be handled by a pattern of type 'C4'. // _ = u is {} and C4; Diagnostic(ErrorCode.ERR_PatternWrongType, "C4").WithArguments("S1", "C4").WithLocation(2002, 25) ); } [Fact] public void PatternWrongType_RecursivePattern_03_BindRecursivePattern_ITuple_UnionType_Not_Out() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 { private readonly object _value; public S1(int x) { _value = x; } public S1(C x) { _value = x; } public object Value => _value; } class Program { static void Test1(S1 u) { _ = u is (_, 10) and D; C x = new C(); _ = x is (_, 10) and D; } } public class C : System.Runtime.CompilerServices.ITuple { int System.Runtime.CompilerServices.ITuple.Length => 2; object System.Runtime.CompilerServices.ITuple.this[int i] => i * 10; } class D; "; var comp = CreateCompilation([src, UnionAttributeSource], targetFramework: TargetFramework.NetCoreApp); comp.VerifyDiagnostics( // (15,18): error CS1061: 'S1' does not contain a definition for 'Deconstruct' and no accessible extension method 'Deconstruct' accepting a first argument of type 'S1' could be found (are you missing a using directive or an assembly reference?) // _ = u is (_, 10) and D; Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "(_, 10)").WithArguments("S1", "Deconstruct").WithLocation(15, 18), // (15,18): error CS8129: No suitable 'Deconstruct' instance or extension method was found for type 'S1', with 2 out parameters and a void return type. // _ = u is (_, 10) and D; Diagnostic(ErrorCode.ERR_MissingDeconstruct, "(_, 10)").WithArguments("S1", "2").WithLocation(15, 18), // (15,30): error CS8121: An expression of type 'S1' cannot be handled by a pattern of type 'D'. // _ = u is (_, 10) and D; Diagnostic(ErrorCode.ERR_PatternWrongType, "D").WithArguments("S1", "D").WithLocation(15, 30) ); } [Fact] public void PatternWrongType_DeclarationPattern_01_BindDeclarationPattern_UnionType_In() { var src1 = @" [System.Runtime.CompilerServices.Union] struct S1 { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } public S1(C2 x) { _value = x; } public S1(C3 x) { _value = x; } public object Value => _value; } class C1; class C2 : C1; class C3; class C4 : C1; class C5 : C2; "; var src2 = @" class Program { static void Test3(S1 u) { #line 300 _ = u is {} and C2 a; _ = u is {} and C3 b; _ = u is {} and C4 c; _ = u is C4 d; } static void Test4(S1? u) { #line 400 _ = u is {} and C2 a; _ = u is {} and C3 b; _ = u is {} and C4 c; _ = u is C4 d; } } "; var comp = CreateCompilation([src2, src1, UnionAttributeSource], targetFramework: TargetFramework.NetCoreApp); comp.VerifyDiagnostics( // (302,25): error CS8121: An expression of type 'S1' cannot be handled by a pattern of type 'C4'. // _ = u is {} and C4 c; Diagnostic(ErrorCode.ERR_PatternWrongType, "C4").WithArguments("S1", "C4").WithLocation(302, 25), // (303,18): error CS8121: An expression of type 'S1' cannot be handled by a pattern of type 'C4'. // _ = u is C4 d; Diagnostic(ErrorCode.ERR_PatternWrongType, "C4").WithArguments("S1", "C4").WithLocation(303, 18), // (402,25): error CS8121: An expression of type 'S1' cannot be handled by a pattern of type 'C4'. // _ = u is {} and C4 c; Diagnostic(ErrorCode.ERR_PatternWrongType, "C4").WithArguments("S1", "C4").WithLocation(402, 25), // (403,18): error CS8121: An expression of type 'S1' cannot be handled by a pattern of type 'C4'. // _ = u is C4 d; Diagnostic(ErrorCode.ERR_PatternWrongType, "C4").WithArguments("S1", "C4").WithLocation(403, 18) ); } [Fact] public void PatternWrongType_DeclarationPattern_02_BindDeclarationPattern_UnionType_Not_Out() { var src1 = @" [System.Runtime.CompilerServices.Union] struct S1 { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } public S1(C2 x) { _value = x; } public S1(C3 x) { _value = x; } public object Value => _value; } class C1; class C2 : C1; class C3; class C4 : C1; class C5 : C2; "; var src2 = @" class Program { static void Test9(S1 u) { #line 900 _ = u is C1 a and C2; _ = u is C1 b and C3; _ = u is C1 c and C4; C2 x = new C5(); _ = x is C1 d and C4; } static void Test10(S1? u) { #line 950 _ = u is C1 a and C2; _ = u is C1 b and C3; _ = u is C1 c and C4; } } "; var comp = CreateCompilation([src2, src1, UnionAttributeSource], targetFramework: TargetFramework.NetCoreApp); comp.VerifyDiagnostics( // (901,27): error CS8121: An expression of type 'C1' cannot be handled by a pattern of type 'C3'. // _ = u is C1 b and C3; Diagnostic(ErrorCode.ERR_PatternWrongType, "C3").WithArguments("C1", "C3").WithLocation(901, 27), // (951,27): error CS8121: An expression of type 'C1' cannot be handled by a pattern of type 'C3'. // _ = u is C1 b and C3; Diagnostic(ErrorCode.ERR_PatternWrongType, "C3").WithArguments("C1", "C3").WithLocation(951, 27) ); } [Fact] public void PatternWrongType_NegatedPattern_01_BindUnaryPattern_UnionType_Out() { var src1 = @" [System.Runtime.CompilerServices.Union] struct S1 { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } public S1(C2 x) { _value = x; } public S1(C3 x) { _value = x; } public object Value => _value; } class C1; class C2 : C1; class C3; class C4 : C1; class C5 : C2; "; var src2 = @" class Program { static void Test5(S1 u) { #line 500 _ = u is not C5 and C2; _ = u is not C5 and C4; } static void Test6(S1? u) { #line 600 _ = u is not C5 and C2; _ = u is not C5 and C4; } } "; var comp = CreateCompilation([src2, src1, UnionAttributeSource], targetFramework: TargetFramework.NetCoreApp); comp.VerifyDiagnostics( // (501,29): error CS8121: An expression of type 'S1' cannot be handled by a pattern of type 'C4'. // _ = u is not C5 and C4; Diagnostic(ErrorCode.ERR_PatternWrongType, "C4").WithArguments("S1", "C4").WithLocation(501, 29), // (601,29): error CS8121: An expression of type 'S1' cannot be handled by a pattern of type 'C4'. // _ = u is not C5 and C4; Diagnostic(ErrorCode.ERR_PatternWrongType, "C4").WithArguments("S1", "C4").WithLocation(601, 29) ); } [Fact] public void PatternWrongType_NegatedPattern_02_BindUnaryPattern_UnionType_In() { var src1 = @" [System.Runtime.CompilerServices.Union] struct S1 { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } public S1(C2 x) { _value = x; } public S1(C3 x) { _value = x; } public object Value => _value; } class C1; class C2 : C1; class C3; class C4 : C1; class C5 : C2; "; var src2 = @" class Program { static void Test7(S1 u) { #line 700 _ = u is {} and not C5; _ = u is {} and not C3; _ = u is {} and not C4; _ = u is not C4; } static void Test8(S1? u) { #line 800 _ = u is {} and not C5; _ = u is {} and not C3; _ = u is {} and not C4; _ = u is not C4; } } "; var comp = CreateCompilation([src2, src1, UnionAttributeSource], targetFramework: TargetFramework.NetCoreApp); comp.VerifyDiagnostics( // (702,29): error CS8121: An expression of type 'S1' cannot be handled by a pattern of type 'C4'. // _ = u is {} and not C4; Diagnostic(ErrorCode.ERR_PatternWrongType, "C4").WithArguments("S1", "C4").WithLocation(702, 29), // (703,22): error CS8121: An expression of type 'S1' cannot be handled by a pattern of type 'C4'. // _ = u is not C4; Diagnostic(ErrorCode.ERR_PatternWrongType, "C4").WithArguments("S1", "C4").WithLocation(703, 22), // (802,29): error CS8121: An expression of type 'S1' cannot be handled by a pattern of type 'C4'. // _ = u is {} and not C4; Diagnostic(ErrorCode.ERR_PatternWrongType, "C4").WithArguments("S1", "C4").WithLocation(802, 29), // (803,22): error CS8121: An expression of type 'S1' cannot be handled by a pattern of type 'C4'. // _ = u is not C4; Diagnostic(ErrorCode.ERR_PatternWrongType, "C4").WithArguments("S1", "C4").WithLocation(803, 22) ); } [Fact] public void PatternWrongType_ParenthesizedPattern_01_BindParenthesizedPattern_UnionType_Out() { var src1 = @" [System.Runtime.CompilerServices.Union] struct S1 { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } public S1(C2 x) { _value = x; } public S1(C3 x) { _value = x; } public object Value => _value; } class C1; class C2 : C1; class C3; class C4 : C1; class C5 : C2; "; var src2 = @" class Program { static void Test6(S1 u) { #line 600 _ = u is (not C5) and C2; _ = u is (not C5) and C4; } static void Test7(S1? u) { #line 700 _ = u is (not C5) and C2; _ = u is (not C5) and C4; } } "; var comp = CreateCompilation([src2, src1, UnionAttributeSource], targetFramework: TargetFramework.NetCoreApp); comp.VerifyDiagnostics( // (601,31): error CS8121: An expression of type 'S1' cannot be handled by a pattern of type 'C4'. // _ = u is (not C5) and C4; Diagnostic(ErrorCode.ERR_PatternWrongType, "C4").WithArguments("S1", "C4").WithLocation(601, 31), // (701,31): error CS8121: An expression of type 'S1' cannot be handled by a pattern of type 'C4'. // _ = u is (not C5) and C4; Diagnostic(ErrorCode.ERR_PatternWrongType, "C4").WithArguments("S1", "C4").WithLocation(701, 31) ); } [Fact] public void PatternWrongType_ParenthesizedPattern_01_BindParenthesizedPattern_UnionType_In() { var src1 = @" [System.Runtime.CompilerServices.Union] struct S1 { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } public S1(C2 x) { _value = x; } public S1(C3 x) { _value = x; } public object Value => _value; } class C1; class C2 : C1; class C3; class C4 : C1; class C5 : C2; "; var src2 = @" class Program { static void Test8(S1 u) { #line 800 _ = u is C1 and (not C2); _ = u is C1 and (not C3); _ = u is C1 and (not C4); _ = u is (not C4); C2 x = new C5(); _ = x is C1 and (not C4); } static void Test9(S1? u) { #line 900 _ = u is C1 and (not C2); _ = u is C1 and (not C3); _ = u is C1 and (not C4); _ = u is (not C4); } } "; var comp = CreateCompilation([src2, src1, UnionAttributeSource], targetFramework: TargetFramework.NetCoreApp); comp.VerifyDiagnostics( // (801,30): error CS8121: An expression of type 'C1' cannot be handled by a pattern of type 'C3'. // _ = u is C1 and (not C3); Diagnostic(ErrorCode.ERR_PatternWrongType, "C3").WithArguments("C1", "C3").WithLocation(801, 30), // (803,23): error CS8121: An expression of type 'S1' cannot be handled by a pattern of type 'C4'. // _ = u is (not C4); Diagnostic(ErrorCode.ERR_PatternWrongType, "C4").WithArguments("S1", "C4").WithLocation(803, 23), // (901,30): error CS8121: An expression of type 'C1' cannot be handled by a pattern of type 'C3'. // _ = u is C1 and (not C3); Diagnostic(ErrorCode.ERR_PatternWrongType, "C3").WithArguments("C1", "C3").WithLocation(901, 30), // (903,23): error CS8121: An expression of type 'S1' cannot be handled by a pattern of type 'C4'. // _ = u is (not C4); Diagnostic(ErrorCode.ERR_PatternWrongType, "C4").WithArguments("S1", "C4").WithLocation(903, 23) ); } [Fact] public void PatternWrongType_ListPattern_01_BindListPattern_UnionType_Out() { var src1 = @" [System.Runtime.CompilerServices.Union] struct S1 { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } public S1(C2 x) { _value = x; } public S1(C3 x) { _value = x; } public object Value => _value; } class C1; class C2 : C1; class C3; class C4 : C1; class C5 : C2; "; var src2 = @" class Program { static void Test11(S1 u) { #line 1100 _ = u is [] and C2; _ = u is [] and C4; _ = u is string and ['a']; } static void Test21(S1? u) { #line 2100 _ = u is [] and C2; _ = u is [] and C4; _ = u is string and ['a']; } } "; var comp = CreateCompilation([src2, src1, UnionAttributeSource], targetFramework: TargetFramework.NetCoreApp); comp.VerifyDiagnostics( // (1100,18): error CS8985: List patterns may not be used for a value of type 'S1'. No suitable 'Length' or 'Count' property was found. // _ = u is [] and C2; Diagnostic(ErrorCode.ERR_ListPatternRequiresLength, "[]").WithArguments("S1").WithLocation(1100, 18), // (1100,18): error CS0021: Cannot apply indexing with [] to an expression of type 'S1' // _ = u is [] and C2; Diagnostic(ErrorCode.ERR_BadIndexLHS, "[]").WithArguments("S1").WithLocation(1100, 18), // (1101,18): error CS8985: List patterns may not be used for a value of type 'S1'. No suitable 'Length' or 'Count' property was found. // _ = u is [] and C4; Diagnostic(ErrorCode.ERR_ListPatternRequiresLength, "[]").WithArguments("S1").WithLocation(1101, 18), // (1101,18): error CS0021: Cannot apply indexing with [] to an expression of type 'S1' // _ = u is [] and C4; Diagnostic(ErrorCode.ERR_BadIndexLHS, "[]").WithArguments("S1").WithLocation(1101, 18), // (1101,25): error CS8121: An expression of type 'S1' cannot be handled by a pattern of type 'C4'. // _ = u is [] and C4; Diagnostic(ErrorCode.ERR_PatternWrongType, "C4").WithArguments("S1", "C4").WithLocation(1101, 25), // (2100,18): error CS8985: List patterns may not be used for a value of type 'S1'. No suitable 'Length' or 'Count' property was found. // _ = u is [] and C2; Diagnostic(ErrorCode.ERR_ListPatternRequiresLength, "[]").WithArguments("S1").WithLocation(2100, 18), // (2100,18): error CS0021: Cannot apply indexing with [] to an expression of type 'S1' // _ = u is [] and C2; Diagnostic(ErrorCode.ERR_BadIndexLHS, "[]").WithArguments("S1").WithLocation(2100, 18), // (2101,18): error CS8985: List patterns may not be used for a value of type 'S1'. No suitable 'Length' or 'Count' property was found. // _ = u is [] and C4; Diagnostic(ErrorCode.ERR_ListPatternRequiresLength, "[]").WithArguments("S1").WithLocation(2101, 18), // (2101,18): error CS0021: Cannot apply indexing with [] to an expression of type 'S1' // _ = u is [] and C4; Diagnostic(ErrorCode.ERR_BadIndexLHS, "[]").WithArguments("S1").WithLocation(2101, 18), // (2101,25): error CS8121: An expression of type 'S1' cannot be handled by a pattern of type 'C4'. // _ = u is [] and C4; Diagnostic(ErrorCode.ERR_PatternWrongType, "C4").WithArguments("S1", "C4").WithLocation(2101, 25) ); } [Fact] public void PatternWrongType_VarDeconstructionPattern_01_UnionType_Out() { var src1 = @" [System.Runtime.CompilerServices.Union] struct S1 { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } public S1(C2 x) { _value = x; } public S1(C3 x) { _value = x; } public object Value => _value; } class C1; class C2 : C1; class C3; class C4 : C1; class C5 : C2; "; var src2 = @" class Program { static void Test1(S1 u) { #line 100 _ = u is var (a, b) and C2; _ = u is var (c, d) and C4; } static void Test2(S1? u) { #line 200 _ = u is var (a, b) and C2; _ = u is var (c, d) and C4; } } static class Extensions { public static void Deconstruct(this object o, out int x, out int y) { x = 1; y = 2; } } "; var comp = CreateCompilation([src2, src1, UnionAttributeSource], targetFramework: TargetFramework.NetCoreApp); comp.VerifyDiagnostics( // (101,33): error CS8121: An expression of type 'S1' cannot be handled by a pattern of type 'C4'. // _ = u is var (c, d) and C4; Diagnostic(ErrorCode.ERR_PatternWrongType, "C4").WithArguments("S1", "C4").WithLocation(101, 33), // (201,33): error CS8121: An expression of type 'S1' cannot be handled by a pattern of type 'C4'. // _ = u is var (c, d) and C4; Diagnostic(ErrorCode.ERR_PatternWrongType, "C4").WithArguments("S1", "C4").WithLocation(201, 33) ); } [Fact] public void PatternWrongType_VarDeconstructionPattern_02_ITuple_UnionType_Not_Out() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 { private readonly object _value; public S1(int x) { _value = x; } public S1(C x) { _value = x; } public object Value => _value; } class Program { static void Test1(S1 u) { _ = u is var (_, a) and D; C x = new C(); _ = x is var (_, b) and D; } } public class C : System.Runtime.CompilerServices.ITuple { int System.Runtime.CompilerServices.ITuple.Length => 2; object System.Runtime.CompilerServices.ITuple.this[int i] => i * 10; } class D; "; var comp = CreateCompilation([src, UnionAttributeSource], targetFramework: TargetFramework.NetCoreApp); comp.VerifyDiagnostics( // (15,22): error CS1061: 'S1' does not contain a definition for 'Deconstruct' and no accessible extension method 'Deconstruct' accepting a first argument of type 'S1' could be found (are you missing a using directive or an assembly reference?) // _ = u is var (_, a) and D; Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "(_, a)").WithArguments("S1", "Deconstruct").WithLocation(15, 22), // (15,22): error CS8129: No suitable 'Deconstruct' instance or extension method was found for type 'S1', with 2 out parameters and a void return type. // _ = u is var (_, a) and D; Diagnostic(ErrorCode.ERR_MissingDeconstruct, "(_, a)").WithArguments("S1", "2").WithLocation(15, 22), // (15,33): error CS8121: An expression of type 'S1' cannot be handled by a pattern of type 'D'. // _ = u is var (_, a) and D; Diagnostic(ErrorCode.ERR_PatternWrongType, "D").WithArguments("S1", "D").WithLocation(15, 33) ); } [Fact] public void PatternWrongType_ConstantPattern_01_BindConstantPatternWithFallbackToTypePattern_UnionType_In_01() { var src1 = @" [System.Runtime.CompilerServices.Union] struct S1 { private readonly object _value; public S1(int x) { _value = x; } public S1(C1 x) { _value = x; } public object Value => _value; } class C1 { public static implicit operator C1(string c) => null; } class C2; "; var src2 = @" class Program { static void Test1(S1 u) { #line 100 _ = u is {} and ""1""; _ = u is {} and (C2)null; _ = u is ""1""; } } "; var comp = CreateCompilation([src2, src1, UnionAttributeSource], targetFramework: TargetFramework.NetCoreApp); comp.VerifyDiagnostics( // (100,25): error CS9372: An expression of type 'S1' cannot be handled by this pattern, see additional errors at this location. // _ = u is {} and "1"; Diagnostic(ErrorCode.ERR_UnionMatchingWrongPattern, @"""1""").WithArguments("S1").WithLocation(100, 25), // (100,25): error CS8121: An expression of type 'C1' cannot be handled by a pattern of type 'string'. // _ = u is {} and "1"; Diagnostic(ErrorCode.ERR_PatternWrongType, @"""1""").WithArguments("C1", "string").WithLocation(100, 25), // (100,25): error CS0029: Cannot implicitly convert type 'string' to 'int' // _ = u is {} and "1"; Diagnostic(ErrorCode.ERR_NoImplicitConv, @"""1""").WithArguments("string", "int").WithLocation(100, 25), // (101,25): error CS9372: An expression of type 'S1' cannot be handled by this pattern, see additional errors at this location. // _ = u is {} and (C2)null; Diagnostic(ErrorCode.ERR_UnionMatchingWrongPattern, "(C2)null").WithArguments("S1").WithLocation(101, 25), // (101,25): error CS0029: Cannot implicitly convert type 'C2' to 'int' // _ = u is {} and (C2)null; Diagnostic(ErrorCode.ERR_NoImplicitConv, "(C2)null").WithArguments("C2", "int").WithLocation(101, 25), // (101,25): error CS0029: Cannot implicitly convert type 'C2' to 'C1' // _ = u is {} and (C2)null; Diagnostic(ErrorCode.ERR_NoImplicitConv, "(C2)null").WithArguments("C2", "C1").WithLocation(101, 25), // (102,18): error CS9372: An expression of type 'S1' cannot be handled by this pattern, see additional errors at this location. // _ = u is "1"; Diagnostic(ErrorCode.ERR_UnionMatchingWrongPattern, @"""1""").WithArguments("S1").WithLocation(102, 18), // (102,18): error CS8121: An expression of type 'C1' cannot be handled by a pattern of type 'string'. // _ = u is "1"; Diagnostic(ErrorCode.ERR_PatternWrongType, @"""1""").WithArguments("C1", "string").WithLocation(102, 18), // (102,18): error CS0029: Cannot implicitly convert type 'string' to 'int' // _ = u is "1"; Diagnostic(ErrorCode.ERR_NoImplicitConv, @"""1""").WithArguments("string", "int").WithLocation(102, 18) ); } [Fact] public void PatternWrongType_ConstantPattern_01_BindConstantPatternWithFallbackToTypePattern_UnionType_In_02() { var src1 = @" [System.Runtime.CompilerServices.Union] struct S1 { private readonly object _value; public S1(int x) { _value = x; } public S1(C1 x) { _value = x; } public object Value => _value; } class C1 { public static implicit operator C1(string c) => null; } class C2; "; var src2 = @" class Program { static void Test1(S1? u) { #line 100 _ = u is {} and ""1""; _ = u is {} and (C2)null; _ = u is ""1""; } } "; var comp = CreateCompilation([src2, src1, UnionAttributeSource], targetFramework: TargetFramework.NetCoreApp); comp.VerifyDiagnostics( // (100,25): error CS9372: An expression of type 'S1' cannot be handled by this pattern, see additional errors at this location. // _ = u is {} and "1"; Diagnostic(ErrorCode.ERR_UnionMatchingWrongPattern, @"""1""").WithArguments("S1").WithLocation(100, 25), // (100,25): error CS8121: An expression of type 'C1' cannot be handled by a pattern of type 'string'. // _ = u is {} and "1"; Diagnostic(ErrorCode.ERR_PatternWrongType, @"""1""").WithArguments("C1", "string").WithLocation(100, 25), // (100,25): error CS0029: Cannot implicitly convert type 'string' to 'int' // _ = u is {} and "1"; Diagnostic(ErrorCode.ERR_NoImplicitConv, @"""1""").WithArguments("string", "int").WithLocation(100, 25), // (101,25): error CS9372: An expression of type 'S1' cannot be handled by this pattern, see additional errors at this location. // _ = u is {} and (C2)null; Diagnostic(ErrorCode.ERR_UnionMatchingWrongPattern, "(C2)null").WithArguments("S1").WithLocation(101, 25), // (101,25): error CS0029: Cannot implicitly convert type 'C2' to 'int' // _ = u is {} and (C2)null; Diagnostic(ErrorCode.ERR_NoImplicitConv, "(C2)null").WithArguments("C2", "int").WithLocation(101, 25), // (101,25): error CS0029: Cannot implicitly convert type 'C2' to 'C1' // _ = u is {} and (C2)null; Diagnostic(ErrorCode.ERR_NoImplicitConv, "(C2)null").WithArguments("C2", "C1").WithLocation(101, 25), // (102,18): error CS9372: An expression of type 'S1' cannot be handled by this pattern, see additional errors at this location. // _ = u is "1"; Diagnostic(ErrorCode.ERR_UnionMatchingWrongPattern, @"""1""").WithArguments("S1").WithLocation(102, 18), // (102,18): error CS8121: An expression of type 'C1' cannot be handled by a pattern of type 'string'. // _ = u is "1"; Diagnostic(ErrorCode.ERR_PatternWrongType, @"""1""").WithArguments("C1", "string").WithLocation(102, 18), // (102,18): error CS0029: Cannot implicitly convert type 'string' to 'int' // _ = u is "1"; Diagnostic(ErrorCode.ERR_NoImplicitConv, @"""1""").WithArguments("string", "int").WithLocation(102, 18) ); } [Fact] public void PatternWrongType_ConstantPattern_02_BindConstantPatternWithFallbackToTypePattern_UnionType_Out() { var src1 = @" [System.Runtime.CompilerServices.Union] struct S1 { private readonly object _value; public S1(int x) { _value = x; } public S1(byte x) { _value = x; } public object Value => _value; } class C2; "; var src2 = @" class Program { static void Test1(S1 u) { #line 100 _ = u is null and C2; _ = u is 1 and byte; } static void Test2(S1? u) { #line 200 _ = u is null and C2; _ = u is 1 and byte; } } "; var comp = CreateCompilation([src2, src1, UnionAttributeSource], targetFramework: TargetFramework.NetCoreApp); comp.VerifyDiagnostics( // (100,27): error CS8121: An expression of type 'S1' cannot be handled by a pattern of type 'C2'. // _ = u is null and C2; Diagnostic(ErrorCode.ERR_PatternWrongType, "C2").WithArguments("S1", "C2").WithLocation(100, 27), // (101,24): error CS8121: An expression of type 'int' cannot be handled by a pattern of type 'byte'. // _ = u is 1 and byte; Diagnostic(ErrorCode.ERR_PatternWrongType, "byte").WithArguments("int", "byte").WithLocation(101, 24), // (200,27): error CS8121: An expression of type 'S1' cannot be handled by a pattern of type 'C2'. // _ = u is null and C2; Diagnostic(ErrorCode.ERR_PatternWrongType, "C2").WithArguments("S1", "C2").WithLocation(200, 27), // (201,24): error CS8121: An expression of type 'int' cannot be handled by a pattern of type 'byte'. // _ = u is 1 and byte; Diagnostic(ErrorCode.ERR_PatternWrongType, "byte").WithArguments("int", "byte").WithLocation(201, 24) ); } [Fact] public void PatternWrongType_ConstantPattern_03_BindIsOperator_UnionType_In() { var src1 = @" [System.Runtime.CompilerServices.Union] struct S1 { private readonly object _value; public S1(int x) { _value = x; } public S1(byte x) { _value = x; } public object Value => _value; } "; var src2 = @" class Program { static void Test1(S1 u) { const string empty =""""; #line 100 _ = u is empty; } static void Test2(S1? u) { const string empty =""""; #line 200 _ = u is empty; } } "; var comp = CreateCompilation([src2, src1, UnionAttributeSource], targetFramework: TargetFramework.NetCoreApp); comp.VerifyDiagnostics( // (100,18): error CS9372: An expression of type 'S1' cannot be handled by this pattern, see additional errors at this location. // _ = u is empty; Diagnostic(ErrorCode.ERR_UnionMatchingWrongPattern, "empty").WithArguments("S1").WithLocation(100, 18), // (100,18): error CS0029: Cannot implicitly convert type 'string' to 'int' // _ = u is empty; Diagnostic(ErrorCode.ERR_NoImplicitConv, "empty").WithArguments("string", "int").WithLocation(100, 18), // (100,18): error CS0029: Cannot implicitly convert type 'string' to 'byte' // _ = u is empty; Diagnostic(ErrorCode.ERR_NoImplicitConv, "empty").WithArguments("string", "byte").WithLocation(100, 18), // (200,18): error CS9372: An expression of type 'S1' cannot be handled by this pattern, see additional errors at this location. // _ = u is empty; Diagnostic(ErrorCode.ERR_UnionMatchingWrongPattern, "empty").WithArguments("S1").WithLocation(200, 18), // (200,18): error CS0029: Cannot implicitly convert type 'string' to 'int' // _ = u is empty; Diagnostic(ErrorCode.ERR_NoImplicitConv, "empty").WithArguments("string", "int").WithLocation(200, 18), // (200,18): error CS0029: Cannot implicitly convert type 'string' to 'byte' // _ = u is empty; Diagnostic(ErrorCode.ERR_NoImplicitConv, "empty").WithArguments("string", "byte").WithLocation(200, 18) ); } [Fact] public void PatternWrongType_ConstantPattern_04_UnionType_In() { var src1 = @" [System.Runtime.CompilerServices.Union] struct S1 { private readonly object _value; public S1(int x) { _value = x; } public S1(byte x) { _value = x; } public object Value => _value; } "; var src2 = @" class Program { static void Test1(S1 u) { const string empty =""""; #line 100 switch (u) { case 1: goto case empty; } } static void Test2(S1? u) { const string empty =""""; #line 200 switch (u) { case 1: goto case empty; } } } "; var comp = CreateCompilation([src2, src1, UnionAttributeSource], targetFramework: TargetFramework.NetCoreApp); comp.VerifyDiagnostics( // (102,13): error CS8070: Control cannot fall out of switch from final case label ('case 1:') // case 1: Diagnostic(ErrorCode.ERR_SwitchFallOut, "case 1:").WithArguments("case 1:").WithLocation(102, 13), // The following error is expected per language specification (https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/statements.md#13104-the-goto-statement): // "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." // (103,17): error CS0029: Cannot implicitly convert type 'string' to 'S1' // goto case empty; Diagnostic(ErrorCode.ERR_NoImplicitConv, "goto case empty;").WithArguments("string", "S1").WithLocation(103, 17), // (202,13): error CS8070: Control cannot fall out of switch from final case label ('case 1:') // case 1: Diagnostic(ErrorCode.ERR_SwitchFallOut, "case 1:").WithArguments("case 1:").WithLocation(202, 13), // The following error is expected per language specification (https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/statements.md#13104-the-goto-statement): // "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." // (203,17): error CS0029: Cannot implicitly convert type 'string' to 'S1?' // goto case empty; Diagnostic(ErrorCode.ERR_NoImplicitConv, "goto case empty;").WithArguments("string", "S1?").WithLocation(203, 17) ); } [Fact] public void PatternWrongType_RelationalPattern_01_BindRelationalPattern_UnionType_In_01() { var src1 = @" [System.Runtime.CompilerServices.Union] struct S1 { private readonly object _value; public S1(string x) { _value = x; } public S1(C1 x) { _value = x; } public object Value => _value; } class C1 { public static implicit operator C1(int c) => null; } class C2; "; var src2 = @" class Program { static void Test1(S1 u) { #line 100 _ = u is {} and > 1; _ = u is C1 and > 1; _ = u is System.IComparable and > 1; _ = u is > 1; object o = u; #line 200 _ = o is S1 { Value: > 1 }; string x = """"; _ = x is System.IComparable and > 1; } } "; var comp = CreateCompilation([src2, src1, UnionAttributeSource], targetFramework: TargetFramework.NetCoreApp); comp.VerifyDiagnostics( // (100,27): error CS9372: An expression of type 'S1' cannot be handled by this pattern, see additional errors at this location. // _ = u is {} and > 1; Diagnostic(ErrorCode.ERR_UnionMatchingWrongPattern, "1").WithArguments("S1").WithLocation(100, 27), // (100,27): error CS8121: An expression of type 'C1' cannot be handled by a pattern of type 'int'. // _ = u is {} and > 1; Diagnostic(ErrorCode.ERR_PatternWrongType, "1").WithArguments("C1", "int").WithLocation(100, 27), // (100,27): error CS0029: Cannot implicitly convert type 'int' to 'string' // _ = u is {} and > 1; Diagnostic(ErrorCode.ERR_NoImplicitConv, "1").WithArguments("int", "string").WithLocation(100, 27), // (101,27): error CS9135: A constant value of type 'C1' is expected // _ = u is C1 and > 1; Diagnostic(ErrorCode.ERR_ConstantValueOfTypeExpected, "1").WithArguments("C1").WithLocation(101, 27), // (103,20): error CS9372: An expression of type 'S1' cannot be handled by this pattern, see additional errors at this location. // _ = u is > 1; Diagnostic(ErrorCode.ERR_UnionMatchingWrongPattern, "1").WithArguments("S1").WithLocation(103, 20), // (103,20): error CS8121: An expression of type 'C1' cannot be handled by a pattern of type 'int'. // _ = u is > 1; Diagnostic(ErrorCode.ERR_PatternWrongType, "1").WithArguments("C1", "int").WithLocation(103, 20), // (103,20): error CS0029: Cannot implicitly convert type 'int' to 'string' // _ = u is > 1; Diagnostic(ErrorCode.ERR_NoImplicitConv, "1").WithArguments("int", "string").WithLocation(103, 20), // (200,32): error CS9372: An expression of type 'S1' cannot be handled by this pattern, see additional errors at this location. // _ = o is S1 { Value: > 1 }; Diagnostic(ErrorCode.ERR_UnionMatchingWrongPattern, "1").WithArguments("S1").WithLocation(200, 32), // (200,32): error CS8121: An expression of type 'C1' cannot be handled by a pattern of type 'int'. // _ = o is S1 { Value: > 1 }; Diagnostic(ErrorCode.ERR_PatternWrongType, "1").WithArguments("C1", "int").WithLocation(200, 32), // (200,32): error CS0029: Cannot implicitly convert type 'int' to 'string' // _ = o is S1 { Value: > 1 }; Diagnostic(ErrorCode.ERR_NoImplicitConv, "1").WithArguments("int", "string").WithLocation(200, 32) ); } [Fact] public void PatternWrongType_RelationalPattern_01_BindRelationalPattern_UnionType_In_02() { var src1 = @" [System.Runtime.CompilerServices.Union] struct S1 { private readonly object _value; public S1(string x) { _value = x; } public S1(C1 x) { _value = x; } public object Value => _value; } class C1 { public static implicit operator C1(int c) => null; } class C2; "; var src2 = @" class Program { static void Test1(S1? u) { #line 100 _ = u is {} and > 1; _ = u is C1 and > 1; _ = u is System.IComparable and > 1; _ = u is > 1; object o = u; #line 200 _ = o is S1 { Value: > 1 }; string x = """"; _ = x is System.IComparable and > 1; } } "; var comp = CreateCompilation([src2, src1, UnionAttributeSource], targetFramework: TargetFramework.NetCoreApp); comp.VerifyDiagnostics( // (100,27): error CS9372: An expression of type 'S1' cannot be handled by this pattern, see additional errors at this location. // _ = u is {} and > 1; Diagnostic(ErrorCode.ERR_UnionMatchingWrongPattern, "1").WithArguments("S1").WithLocation(100, 27), // (100,27): error CS8121: An expression of type 'C1' cannot be handled by a pattern of type 'int'. // _ = u is {} and > 1; Diagnostic(ErrorCode.ERR_PatternWrongType, "1").WithArguments("C1", "int").WithLocation(100, 27), // (100,27): error CS0029: Cannot implicitly convert type 'int' to 'string' // _ = u is {} and > 1; Diagnostic(ErrorCode.ERR_NoImplicitConv, "1").WithArguments("int", "string").WithLocation(100, 27), // (101,27): error CS9135: A constant value of type 'C1' is expected // _ = u is C1 and > 1; Diagnostic(ErrorCode.ERR_ConstantValueOfTypeExpected, "1").WithArguments("C1").WithLocation(101, 27), // (103,20): error CS9372: An expression of type 'S1' cannot be handled by this pattern, see additional errors at this location. // _ = u is > 1; Diagnostic(ErrorCode.ERR_UnionMatchingWrongPattern, "1").WithArguments("S1").WithLocation(103, 20), // (103,20): error CS8121: An expression of type 'C1' cannot be handled by a pattern of type 'int'. // _ = u is > 1; Diagnostic(ErrorCode.ERR_PatternWrongType, "1").WithArguments("C1", "int").WithLocation(103, 20), // (103,20): error CS0029: Cannot implicitly convert type 'int' to 'string' // _ = u is > 1; Diagnostic(ErrorCode.ERR_NoImplicitConv, "1").WithArguments("int", "string").WithLocation(103, 20), // (200,32): error CS9372: An expression of type 'S1' cannot be handled by this pattern, see additional errors at this location. // _ = o is S1 { Value: > 1 }; Diagnostic(ErrorCode.ERR_UnionMatchingWrongPattern, "1").WithArguments("S1").WithLocation(200, 32), // (200,32): error CS8121: An expression of type 'C1' cannot be handled by a pattern of type 'int'. // _ = o is S1 { Value: > 1 }; Diagnostic(ErrorCode.ERR_PatternWrongType, "1").WithArguments("C1", "int").WithLocation(200, 32), // (200,32): error CS0029: Cannot implicitly convert type 'int' to 'string' // _ = o is S1 { Value: > 1 }; Diagnostic(ErrorCode.ERR_NoImplicitConv, "1").WithArguments("int", "string").WithLocation(200, 32) ); } [Fact] public void PatternWrongType_RelationalPattern_02_BindRelationalPattern_UnionType_Out() { var src1 = @" [System.Runtime.CompilerServices.Union] struct S1 { private readonly object _value; public S1(int x) { _value = x; } public S1(byte x) { _value = x; } public object Value => _value; } class C2; "; var src2 = @" class Program { static void Test1(S1 u) { #line 100 _ = u is > 1 and byte; } static void Test2(S1? u) { #line 200 _ = u is > 1 and byte; } } "; var comp = CreateCompilation([src2, src1, UnionAttributeSource], targetFramework: TargetFramework.NetCoreApp); comp.VerifyDiagnostics( // (100,26): error CS8121: An expression of type 'int' cannot be handled by a pattern of type 'byte'. // _ = u is > 1 and byte; Diagnostic(ErrorCode.ERR_PatternWrongType, "byte").WithArguments("int", "byte").WithLocation(100, 26), // (200,26): error CS8121: An expression of type 'int' cannot be handled by a pattern of type 'byte'. // _ = u is > 1 and byte; Diagnostic(ErrorCode.ERR_PatternWrongType, "byte").WithArguments("int", "byte").WithLocation(200, 26) ); } [Fact] public void PatternWrongType_BinaryPattern_01_Disjunction_Snap_To_Previous_UnionType_01() { var src1 = @" [System.Runtime.CompilerServices.Union] struct S1 { private readonly object _value; public S1(C1 x) { _value = x; } public S1(C2 x) { _value = x; } public object Value => _value; } class C1; class C2; class C3; "; var src2 = @" class Program { static void Test1(S1 u) { #line 100 _ = u is int or string or C3; _ = u is int or (string or C3); _ = u is C1 or string or C3; _ = u is int or C2 or C3; _ = u is int or string or C1; _ = u is int or (C2 or C3); _ = u is int or (string or C1); _ = u is (int or string) or C3; } } "; var comp = CreateCompilation([src2, src1, UnionAttributeSource], targetFramework: TargetFramework.NetCoreApp); comp.VerifyDiagnostics( // (100,18): error CS8121: An expression of type 'S1' cannot be handled by a pattern of type 'int'. // _ = u is int or string or C3; Diagnostic(ErrorCode.ERR_PatternWrongType, "int").WithArguments("S1", "int").WithLocation(100, 18), // (100,25): error CS8121: An expression of type 'S1' cannot be handled by a pattern of type 'string'. // _ = u is int or string or C3; Diagnostic(ErrorCode.ERR_PatternWrongType, "string").WithArguments("S1", "string").WithLocation(100, 25), // (100,35): error CS8121: An expression of type 'S1' cannot be handled by a pattern of type 'C3'. // _ = u is int or string or C3; Diagnostic(ErrorCode.ERR_PatternWrongType, "C3").WithArguments("S1", "C3").WithLocation(100, 35), // (101,18): error CS8121: An expression of type 'S1' cannot be handled by a pattern of type 'int'. // _ = u is int or (string or C3); Diagnostic(ErrorCode.ERR_PatternWrongType, "int").WithArguments("S1", "int").WithLocation(101, 18), // (101,26): error CS8121: An expression of type 'S1' cannot be handled by a pattern of type 'string'. // _ = u is int or (string or C3); Diagnostic(ErrorCode.ERR_PatternWrongType, "string").WithArguments("S1", "string").WithLocation(101, 26), // (101,36): error CS8121: An expression of type 'S1' cannot be handled by a pattern of type 'C3'. // _ = u is int or (string or C3); Diagnostic(ErrorCode.ERR_PatternWrongType, "C3").WithArguments("S1", "C3").WithLocation(101, 36), // (102,24): error CS8121: An expression of type 'S1' cannot be handled by a pattern of type 'string'. // _ = u is C1 or string or C3; Diagnostic(ErrorCode.ERR_PatternWrongType, "string").WithArguments("S1", "string").WithLocation(102, 24), // (102,34): error CS8121: An expression of type 'S1' cannot be handled by a pattern of type 'C3'. // _ = u is C1 or string or C3; Diagnostic(ErrorCode.ERR_PatternWrongType, "C3").WithArguments("S1", "C3").WithLocation(102, 34), // (103,18): error CS8121: An expression of type 'S1' cannot be handled by a pattern of type 'int'. // _ = u is int or C2 or C3; Diagnostic(ErrorCode.ERR_PatternWrongType, "int").WithArguments("S1", "int").WithLocation(103, 18), // (103,31): error CS8121: An expression of type 'S1' cannot be handled by a pattern of type 'C3'. // _ = u is int or C2 or C3; Diagnostic(ErrorCode.ERR_PatternWrongType, "C3").WithArguments("S1", "C3").WithLocation(103, 31), // (104,18): error CS8121: An expression of type 'S1' cannot be handled by a pattern of type 'int'. // _ = u is int or string or C1; Diagnostic(ErrorCode.ERR_PatternWrongType, "int").WithArguments("S1", "int").WithLocation(104, 18), // (104,25): error CS8121: An expression of type 'S1' cannot be handled by a pattern of type 'string'. // _ = u is int or string or C1; Diagnostic(ErrorCode.ERR_PatternWrongType, "string").WithArguments("S1", "string").WithLocation(104, 25), // (105,18): error CS8121: An expression of type 'S1' cannot be handled by a pattern of type 'int'. // _ = u is int or (C2 or C3); Diagnostic(ErrorCode.ERR_PatternWrongType, "int").WithArguments("S1", "int").WithLocation(105, 18), // (105,32): error CS8121: An expression of type 'S1' cannot be handled by a pattern of type 'C3'. // _ = u is int or (C2 or C3); Diagnostic(ErrorCode.ERR_PatternWrongType, "C3").WithArguments("S1", "C3").WithLocation(105, 32), // (106,18): error CS8121: An expression of type 'S1' cannot be handled by a pattern of type 'int'. // _ = u is int or (string or C1); Diagnostic(ErrorCode.ERR_PatternWrongType, "int").WithArguments("S1", "int").WithLocation(106, 18), // (106,26): error CS8121: An expression of type 'S1' cannot be handled by a pattern of type 'string'. // _ = u is int or (string or C1); Diagnostic(ErrorCode.ERR_PatternWrongType, "string").WithArguments("S1", "string").WithLocation(106, 26), // (107,19): error CS8121: An expression of type 'S1' cannot be handled by a pattern of type 'int'. // _ = u is (int or string) or C3; Diagnostic(ErrorCode.ERR_PatternWrongType, "int").WithArguments("S1", "int").WithLocation(107, 19), // (107,26): error CS8121: An expression of type 'S1' cannot be handled by a pattern of type 'string'. // _ = u is (int or string) or C3; Diagnostic(ErrorCode.ERR_PatternWrongType, "string").WithArguments("S1", "string").WithLocation(107, 26), // (107,37): error CS8121: An expression of type 'S1' cannot be handled by a pattern of type 'C3'. // _ = u is (int or string) or C3; Diagnostic(ErrorCode.ERR_PatternWrongType, "C3").WithArguments("S1", "C3").WithLocation(107, 37) ); } [Fact] public void PatternWrongType_BinaryPattern_01_Disjunction_Snap_To_Previous_UnionType_02() { var src1 = @" [System.Runtime.CompilerServices.Union] struct S1 { private readonly object _value; public S1(C1 x) { _value = x; } public S1(C2 x) { _value = x; } public object Value => _value; } class C1; class C2; class C3; "; var src2 = @" class Program { static void Test1(S1? u) { #line 100 _ = u is int or string or C3; _ = u is int or (string or C3); _ = u is C1 or string or C3; _ = u is int or C2 or C3; _ = u is int or string or C1; _ = u is int or (C2 or C3); _ = u is int or (string or C1); _ = u is (int or string) or C3; } } "; var comp = CreateCompilation([src2, src1, UnionAttributeSource], targetFramework: TargetFramework.NetCoreApp); comp.VerifyDiagnostics( // (100,18): error CS8121: An expression of type 'S1' cannot be handled by a pattern of type 'int'. // _ = u is int or string or C3; Diagnostic(ErrorCode.ERR_PatternWrongType, "int").WithArguments("S1", "int").WithLocation(100, 18), // (100,25): error CS8121: An expression of type 'S1' cannot be handled by a pattern of type 'string'. // _ = u is int or string or C3; Diagnostic(ErrorCode.ERR_PatternWrongType, "string").WithArguments("S1", "string").WithLocation(100, 25), // (100,35): error CS8121: An expression of type 'S1' cannot be handled by a pattern of type 'C3'. // _ = u is int or string or C3; Diagnostic(ErrorCode.ERR_PatternWrongType, "C3").WithArguments("S1", "C3").WithLocation(100, 35), // (101,18): error CS8121: An expression of type 'S1' cannot be handled by a pattern of type 'int'. // _ = u is int or (string or C3); Diagnostic(ErrorCode.ERR_PatternWrongType, "int").WithArguments("S1", "int").WithLocation(101, 18), // (101,26): error CS8121: An expression of type 'S1' cannot be handled by a pattern of type 'string'. // _ = u is int or (string or C3); Diagnostic(ErrorCode.ERR_PatternWrongType, "string").WithArguments("S1", "string").WithLocation(101, 26), // (101,36): error CS8121: An expression of type 'S1' cannot be handled by a pattern of type 'C3'. // _ = u is int or (string or C3); Diagnostic(ErrorCode.ERR_PatternWrongType, "C3").WithArguments("S1", "C3").WithLocation(101, 36), // (102,24): error CS8121: An expression of type 'S1' cannot be handled by a pattern of type 'string'. // _ = u is C1 or string or C3; Diagnostic(ErrorCode.ERR_PatternWrongType, "string").WithArguments("S1", "string").WithLocation(102, 24), // (102,34): error CS8121: An expression of type 'S1' cannot be handled by a pattern of type 'C3'. // _ = u is C1 or string or C3; Diagnostic(ErrorCode.ERR_PatternWrongType, "C3").WithArguments("S1", "C3").WithLocation(102, 34), // (103,18): error CS8121: An expression of type 'S1' cannot be handled by a pattern of type 'int'. // _ = u is int or C2 or C3; Diagnostic(ErrorCode.ERR_PatternWrongType, "int").WithArguments("S1", "int").WithLocation(103, 18), // (103,31): error CS8121: An expression of type 'S1' cannot be handled by a pattern of type 'C3'. // _ = u is int or C2 or C3; Diagnostic(ErrorCode.ERR_PatternWrongType, "C3").WithArguments("S1", "C3").WithLocation(103, 31), // (104,18): error CS8121: An expression of type 'S1' cannot be handled by a pattern of type 'int'. // _ = u is int or string or C1; Diagnostic(ErrorCode.ERR_PatternWrongType, "int").WithArguments("S1", "int").WithLocation(104, 18), // (104,25): error CS8121: An expression of type 'S1' cannot be handled by a pattern of type 'string'. // _ = u is int or string or C1; Diagnostic(ErrorCode.ERR_PatternWrongType, "string").WithArguments("S1", "string").WithLocation(104, 25), // (105,18): error CS8121: An expression of type 'S1' cannot be handled by a pattern of type 'int'. // _ = u is int or (C2 or C3); Diagnostic(ErrorCode.ERR_PatternWrongType, "int").WithArguments("S1", "int").WithLocation(105, 18), // (105,32): error CS8121: An expression of type 'S1' cannot be handled by a pattern of type 'C3'. // _ = u is int or (C2 or C3); Diagnostic(ErrorCode.ERR_PatternWrongType, "C3").WithArguments("S1", "C3").WithLocation(105, 32), // (106,18): error CS8121: An expression of type 'S1' cannot be handled by a pattern of type 'int'. // _ = u is int or (string or C1); Diagnostic(ErrorCode.ERR_PatternWrongType, "int").WithArguments("S1", "int").WithLocation(106, 18), // (106,26): error CS8121: An expression of type 'S1' cannot be handled by a pattern of type 'string'. // _ = u is int or (string or C1); Diagnostic(ErrorCode.ERR_PatternWrongType, "string").WithArguments("S1", "string").WithLocation(106, 26), // (107,19): error CS8121: An expression of type 'S1' cannot be handled by a pattern of type 'int'. // _ = u is (int or string) or C3; Diagnostic(ErrorCode.ERR_PatternWrongType, "int").WithArguments("S1", "int").WithLocation(107, 19), // (107,26): error CS8121: An expression of type 'S1' cannot be handled by a pattern of type 'string'. // _ = u is (int or string) or C3; Diagnostic(ErrorCode.ERR_PatternWrongType, "string").WithArguments("S1", "string").WithLocation(107, 26), // (107,37): error CS8121: An expression of type 'S1' cannot be handled by a pattern of type 'C3'. // _ = u is (int or string) or C3; Diagnostic(ErrorCode.ERR_PatternWrongType, "C3").WithArguments("S1", "C3").WithLocation(107, 37) ); } [Fact] public void PatternWrongType_BinaryPattern_02_Disjunction_Snap_To_Previous_UnionType_01() { var src1 = @" [System.Runtime.CompilerServices.Union] struct S1 { private readonly object _value; public S1(C1 x) { _value = x; } public S1(C2 x) { _value = x; } public object Value => _value; } class C1; class C2; class C3; "; var src2 = @" class Program { static void Test1(S1 u) { #line 100 _ = u is {} and (int or string or C3); _ = u is {} and (int or (string or C3)); _ = u is {} and (C1 or string or C3); _ = u is {} and (int or C2 or C3); _ = u is {} and (int or string or C1); _ = u is {} and (int or (C2 or C3)); _ = u is {} and (int or (string or C1)); _ = u is {} and ((int or string) or C3); } } "; var comp = CreateCompilation([src2, src1, UnionAttributeSource], targetFramework: TargetFramework.NetCoreApp); comp.VerifyDiagnostics( // (100,26): error CS8121: An expression of type 'S1' cannot be handled by a pattern of type 'int'. // _ = u is {} and (int or string or C3); Diagnostic(ErrorCode.ERR_PatternWrongType, "int").WithArguments("S1", "int").WithLocation(100, 26), // (100,33): error CS8121: An expression of type 'S1' cannot be handled by a pattern of type 'string'. // _ = u is {} and (int or string or C3); Diagnostic(ErrorCode.ERR_PatternWrongType, "string").WithArguments("S1", "string").WithLocation(100, 33), // (100,43): error CS8121: An expression of type 'S1' cannot be handled by a pattern of type 'C3'. // _ = u is {} and (int or string or C3); Diagnostic(ErrorCode.ERR_PatternWrongType, "C3").WithArguments("S1", "C3").WithLocation(100, 43), // (101,26): error CS8121: An expression of type 'S1' cannot be handled by a pattern of type 'int'. // _ = u is {} and (int or (string or C3)); Diagnostic(ErrorCode.ERR_PatternWrongType, "int").WithArguments("S1", "int").WithLocation(101, 26), // (101,34): error CS8121: An expression of type 'S1' cannot be handled by a pattern of type 'string'. // _ = u is {} and (int or (string or C3)); Diagnostic(ErrorCode.ERR_PatternWrongType, "string").WithArguments("S1", "string").WithLocation(101, 34), // (101,44): error CS8121: An expression of type 'S1' cannot be handled by a pattern of type 'C3'. // _ = u is {} and (int or (string or C3)); Diagnostic(ErrorCode.ERR_PatternWrongType, "C3").WithArguments("S1", "C3").WithLocation(101, 44), // (102,32): error CS8121: An expression of type 'S1' cannot be handled by a pattern of type 'string'. // _ = u is {} and (C1 or string or C3); Diagnostic(ErrorCode.ERR_PatternWrongType, "string").WithArguments("S1", "string").WithLocation(102, 32), // (102,42): error CS8121: An expression of type 'S1' cannot be handled by a pattern of type 'C3'. // _ = u is {} and (C1 or string or C3); Diagnostic(ErrorCode.ERR_PatternWrongType, "C3").WithArguments("S1", "C3").WithLocation(102, 42), // (103,26): error CS8121: An expression of type 'S1' cannot be handled by a pattern of type 'int'. // _ = u is {} and (int or C2 or C3); Diagnostic(ErrorCode.ERR_PatternWrongType, "int").WithArguments("S1", "int").WithLocation(103, 26), // (103,39): error CS8121: An expression of type 'S1' cannot be handled by a pattern of type 'C3'. // _ = u is {} and (int or C2 or C3); Diagnostic(ErrorCode.ERR_PatternWrongType, "C3").WithArguments("S1", "C3").WithLocation(103, 39), // (104,26): error CS8121: An expression of type 'S1' cannot be handled by a pattern of type 'int'. // _ = u is {} and (int or string or C1); Diagnostic(ErrorCode.ERR_PatternWrongType, "int").WithArguments("S1", "int").WithLocation(104, 26), // (104,33): error CS8121: An expression of type 'S1' cannot be handled by a pattern of type 'string'. // _ = u is {} and (int or string or C1); Diagnostic(ErrorCode.ERR_PatternWrongType, "string").WithArguments("S1", "string").WithLocation(104, 33), // (105,26): error CS8121: An expression of type 'S1' cannot be handled by a pattern of type 'int'. // _ = u is {} and (int or (C2 or C3)); Diagnostic(ErrorCode.ERR_PatternWrongType, "int").WithArguments("S1", "int").WithLocation(105, 26), // (105,40): error CS8121: An expression of type 'S1' cannot be handled by a pattern of type 'C3'. // _ = u is {} and (int or (C2 or C3)); Diagnostic(ErrorCode.ERR_PatternWrongType, "C3").WithArguments("S1", "C3").WithLocation(105, 40), // (106,26): error CS8121: An expression of type 'S1' cannot be handled by a pattern of type 'int'. // _ = u is {} and (int or (string or C1)); Diagnostic(ErrorCode.ERR_PatternWrongType, "int").WithArguments("S1", "int").WithLocation(106, 26), // (106,34): error CS8121: An expression of type 'S1' cannot be handled by a pattern of type 'string'. // _ = u is {} and (int or (string or C1)); Diagnostic(ErrorCode.ERR_PatternWrongType, "string").WithArguments("S1", "string").WithLocation(106, 34), // (107,27): error CS8121: An expression of type 'S1' cannot be handled by a pattern of type 'int'. // _ = u is {} and ((int or string) or C3); Diagnostic(ErrorCode.ERR_PatternWrongType, "int").WithArguments("S1", "int").WithLocation(107, 27), // (107,34): error CS8121: An expression of type 'S1' cannot be handled by a pattern of type 'string'. // _ = u is {} and ((int or string) or C3); Diagnostic(ErrorCode.ERR_PatternWrongType, "string").WithArguments("S1", "string").WithLocation(107, 34), // (107,45): error CS8121: An expression of type 'S1' cannot be handled by a pattern of type 'C3'. // _ = u is {} and ((int or string) or C3); Diagnostic(ErrorCode.ERR_PatternWrongType, "C3").WithArguments("S1", "C3").WithLocation(107, 45) ); } [Fact] public void PatternWrongType_BinaryPattern_02_Disjunction_Snap_To_Previous_UnionType_02() { var src1 = @" [System.Runtime.CompilerServices.Union] struct S1 { private readonly object _value; public S1(C1 x) { _value = x; } public S1(C2 x) { _value = x; } public object Value => _value; } class C1; class C2; class C3; "; var src2 = @" class Program { static void Test1(S1? u) { #line 100 _ = u is {} and (int or string or C3); _ = u is {} and (int or (string or C3)); _ = u is {} and (C1 or string or C3); _ = u is {} and (int or C2 or C3); _ = u is {} and (int or string or C1); _ = u is {} and (int or (C2 or C3)); _ = u is {} and (int or (string or C1)); _ = u is {} and ((int or string) or C3); } } "; var comp = CreateCompilation([src2, src1, UnionAttributeSource], targetFramework: TargetFramework.NetCoreApp); comp.VerifyDiagnostics( // (100,26): error CS8121: An expression of type 'S1' cannot be handled by a pattern of type 'int'. // _ = u is {} and (int or string or C3); Diagnostic(ErrorCode.ERR_PatternWrongType, "int").WithArguments("S1", "int").WithLocation(100, 26), // (100,33): error CS8121: An expression of type 'S1' cannot be handled by a pattern of type 'string'. // _ = u is {} and (int or string or C3); Diagnostic(ErrorCode.ERR_PatternWrongType, "string").WithArguments("S1", "string").WithLocation(100, 33), // (100,43): error CS8121: An expression of type 'S1' cannot be handled by a pattern of type 'C3'. // _ = u is {} and (int or string or C3); Diagnostic(ErrorCode.ERR_PatternWrongType, "C3").WithArguments("S1", "C3").WithLocation(100, 43), // (101,26): error CS8121: An expression of type 'S1' cannot be handled by a pattern of type 'int'. // _ = u is {} and (int or (string or C3)); Diagnostic(ErrorCode.ERR_PatternWrongType, "int").WithArguments("S1", "int").WithLocation(101, 26), // (101,34): error CS8121: An expression of type 'S1' cannot be handled by a pattern of type 'string'. // _ = u is {} and (int or (string or C3)); Diagnostic(ErrorCode.ERR_PatternWrongType, "string").WithArguments("S1", "string").WithLocation(101, 34), // (101,44): error CS8121: An expression of type 'S1' cannot be handled by a pattern of type 'C3'. // _ = u is {} and (int or (string or C3)); Diagnostic(ErrorCode.ERR_PatternWrongType, "C3").WithArguments("S1", "C3").WithLocation(101, 44), // (102,32): error CS8121: An expression of type 'S1' cannot be handled by a pattern of type 'string'. // _ = u is {} and (C1 or string or C3); Diagnostic(ErrorCode.ERR_PatternWrongType, "string").WithArguments("S1", "string").WithLocation(102, 32), // (102,42): error CS8121: An expression of type 'S1' cannot be handled by a pattern of type 'C3'. // _ = u is {} and (C1 or string or C3); Diagnostic(ErrorCode.ERR_PatternWrongType, "C3").WithArguments("S1", "C3").WithLocation(102, 42), // (103,26): error CS8121: An expression of type 'S1' cannot be handled by a pattern of type 'int'. // _ = u is {} and (int or C2 or C3); Diagnostic(ErrorCode.ERR_PatternWrongType, "int").WithArguments("S1", "int").WithLocation(103, 26), // (103,39): error CS8121: An expression of type 'S1' cannot be handled by a pattern of type 'C3'. // _ = u is {} and (int or C2 or C3); Diagnostic(ErrorCode.ERR_PatternWrongType, "C3").WithArguments("S1", "C3").WithLocation(103, 39), // (104,26): error CS8121: An expression of type 'S1' cannot be handled by a pattern of type 'int'. // _ = u is {} and (int or string or C1); Diagnostic(ErrorCode.ERR_PatternWrongType, "int").WithArguments("S1", "int").WithLocation(104, 26), // (104,33): error CS8121: An expression of type 'S1' cannot be handled by a pattern of type 'string'. // _ = u is {} and (int or string or C1); Diagnostic(ErrorCode.ERR_PatternWrongType, "string").WithArguments("S1", "string").WithLocation(104, 33), // (105,26): error CS8121: An expression of type 'S1' cannot be handled by a pattern of type 'int'. // _ = u is {} and (int or (C2 or C3)); Diagnostic(ErrorCode.ERR_PatternWrongType, "int").WithArguments("S1", "int").WithLocation(105, 26), // (105,40): error CS8121: An expression of type 'S1' cannot be handled by a pattern of type 'C3'. // _ = u is {} and (int or (C2 or C3)); Diagnostic(ErrorCode.ERR_PatternWrongType, "C3").WithArguments("S1", "C3").WithLocation(105, 40), // (106,26): error CS8121: An expression of type 'S1' cannot be handled by a pattern of type 'int'. // _ = u is {} and (int or (string or C1)); Diagnostic(ErrorCode.ERR_PatternWrongType, "int").WithArguments("S1", "int").WithLocation(106, 26), // (106,34): error CS8121: An expression of type 'S1' cannot be handled by a pattern of type 'string'. // _ = u is {} and (int or (string or C1)); Diagnostic(ErrorCode.ERR_PatternWrongType, "string").WithArguments("S1", "string").WithLocation(106, 34), // (107,27): error CS8121: An expression of type 'S1' cannot be handled by a pattern of type 'int'. // _ = u is {} and ((int or string) or C3); Diagnostic(ErrorCode.ERR_PatternWrongType, "int").WithArguments("S1", "int").WithLocation(107, 27), // (107,34): error CS8121: An expression of type 'S1' cannot be handled by a pattern of type 'string'. // _ = u is {} and ((int or string) or C3); Diagnostic(ErrorCode.ERR_PatternWrongType, "string").WithArguments("S1", "string").WithLocation(107, 34), // (107,45): error CS8121: An expression of type 'S1' cannot be handled by a pattern of type 'C3'. // _ = u is {} and ((int or string) or C3); Diagnostic(ErrorCode.ERR_PatternWrongType, "C3").WithArguments("S1", "C3").WithLocation(107, 45) ); } [Fact] public void PatternWrongType_BinaryPattern_03_Disjunction_Snap_To_Previous_UnionType() { var src1 = @" [System.Runtime.CompilerServices.Union] struct S1 { private readonly object _value; public S1(C1 x) { _value = x; } public S1(C2 x) { _value = x; } public object Value => _value; } class C1; class C2; class C3; "; var src2 = @" class Program { static void Test1(object u) { #line 100 _ = u is (S1 and int) or string or C3; _ = u is (S1 and int) or (string or C3); _ = u is int or (S1 and C2) or C3; _ = u is int or ((S1 and C2) or C3); _ = u is ((S1 and int) or string) or C3; _ = u is S1 and int or string or C3; } } "; var comp = CreateCompilation([src2, src1, UnionAttributeSource], targetFramework: TargetFramework.NetCoreApp); comp.VerifyDiagnostics( // (100,26): error CS8121: An expression of type 'S1' cannot be handled by a pattern of type 'int'. // _ = u is (S1 and int) or string or C3; Diagnostic(ErrorCode.ERR_PatternWrongType, "int").WithArguments("S1", "int").WithLocation(100, 26), // (101,26): error CS8121: An expression of type 'S1' cannot be handled by a pattern of type 'int'. // _ = u is (S1 and int) or (string or C3); Diagnostic(ErrorCode.ERR_PatternWrongType, "int").WithArguments("S1", "int").WithLocation(101, 26), // (104,27): error CS8121: An expression of type 'S1' cannot be handled by a pattern of type 'int'. // _ = u is ((S1 and int) or string) or C3; Diagnostic(ErrorCode.ERR_PatternWrongType, "int").WithArguments("S1", "int").WithLocation(104, 27), // (105,25): error CS8121: An expression of type 'S1' cannot be handled by a pattern of type 'int'. // _ = u is S1 and int or string or C3; Diagnostic(ErrorCode.ERR_PatternWrongType, "int").WithArguments("S1", "int").WithLocation(105, 25) ); } [Fact] public void PatternWrongType_BinaryPattern_04_Disjunction_Snap_To_Previous_UnionType_01() { var src1 = @" [System.Runtime.CompilerServices.Union] struct S0 { private readonly object _value; public S0(byte x) { _value = x; } public S0(S1 x) { _value = x; } public object Value => _value; } [System.Runtime.CompilerServices.Union] struct S1 { private readonly object _value; public S1(C1 x) { _value = x; } public S1(C2 x) { _value = x; } public object Value => _value; } class C1; class C2; class C3; "; var src2 = @" class Program { static void Test1(S0 u) { #line 100 _ = u is {} and ((S1 and int) or string or C3); _ = u is {} and ((S1 and int) or (string or C3)); _ = u is {} and (int or (S1 and C2) or C3); _ = u is {} and (int or ((S1 and C2) or C3)); _ = u is {} and (((S1 and int) or string) or C3); _ = u is {} and (S1 and int or string or C3); } } "; var comp = CreateCompilation([src2, src1, UnionAttributeSource], targetFramework: TargetFramework.NetCoreApp); comp.VerifyDiagnostics( // (100,34): error CS8121: An expression of type 'S1' cannot be handled by a pattern of type 'int'. // _ = u is {} and ((S1 and int) or string or C3); Diagnostic(ErrorCode.ERR_PatternWrongType, "int").WithArguments("S1", "int").WithLocation(100, 34), // (100,42): error CS8121: An expression of type 'S0' cannot be handled by a pattern of type 'string'. // _ = u is {} and ((S1 and int) or string or C3); Diagnostic(ErrorCode.ERR_PatternWrongType, "string").WithArguments("S0", "string").WithLocation(100, 42), // (100,52): error CS8121: An expression of type 'S0' cannot be handled by a pattern of type 'C3'. // _ = u is {} and ((S1 and int) or string or C3); Diagnostic(ErrorCode.ERR_PatternWrongType, "C3").WithArguments("S0", "C3").WithLocation(100, 52), // (101,34): error CS8121: An expression of type 'S1' cannot be handled by a pattern of type 'int'. // _ = u is {} and ((S1 and int) or (string or C3)); Diagnostic(ErrorCode.ERR_PatternWrongType, "int").WithArguments("S1", "int").WithLocation(101, 34), // (101,43): error CS8121: An expression of type 'S0' cannot be handled by a pattern of type 'string'. // _ = u is {} and ((S1 and int) or (string or C3)); Diagnostic(ErrorCode.ERR_PatternWrongType, "string").WithArguments("S0", "string").WithLocation(101, 43), // (101,53): error CS8121: An expression of type 'S0' cannot be handled by a pattern of type 'C3'. // _ = u is {} and ((S1 and int) or (string or C3)); Diagnostic(ErrorCode.ERR_PatternWrongType, "C3").WithArguments("S0", "C3").WithLocation(101, 53), // (102,26): error CS8121: An expression of type 'S0' cannot be handled by a pattern of type 'int'. // _ = u is {} and (int or (S1 and C2) or C3); Diagnostic(ErrorCode.ERR_PatternWrongType, "int").WithArguments("S0", "int").WithLocation(102, 26), // (102,48): error CS8121: An expression of type 'S0' cannot be handled by a pattern of type 'C3'. // _ = u is {} and (int or (S1 and C2) or C3); Diagnostic(ErrorCode.ERR_PatternWrongType, "C3").WithArguments("S0", "C3").WithLocation(102, 48), // (103,26): error CS8121: An expression of type 'S0' cannot be handled by a pattern of type 'int'. // _ = u is {} and (int or ((S1 and C2) or C3)); Diagnostic(ErrorCode.ERR_PatternWrongType, "int").WithArguments("S0", "int").WithLocation(103, 26), // (103,49): error CS8121: An expression of type 'S0' cannot be handled by a pattern of type 'C3'. // _ = u is {} and (int or ((S1 and C2) or C3)); Diagnostic(ErrorCode.ERR_PatternWrongType, "C3").WithArguments("S0", "C3").WithLocation(103, 49), // (104,35): error CS8121: An expression of type 'S1' cannot be handled by a pattern of type 'int'. // _ = u is {} and (((S1 and int) or string) or C3); Diagnostic(ErrorCode.ERR_PatternWrongType, "int").WithArguments("S1", "int").WithLocation(104, 35), // (104,43): error CS8121: An expression of type 'S0' cannot be handled by a pattern of type 'string'. // _ = u is {} and (((S1 and int) or string) or C3); Diagnostic(ErrorCode.ERR_PatternWrongType, "string").WithArguments("S0", "string").WithLocation(104, 43), // (104,54): error CS8121: An expression of type 'S0' cannot be handled by a pattern of type 'C3'. // _ = u is {} and (((S1 and int) or string) or C3); Diagnostic(ErrorCode.ERR_PatternWrongType, "C3").WithArguments("S0", "C3").WithLocation(104, 54), // (105,33): error CS8121: An expression of type 'S1' cannot be handled by a pattern of type 'int'. // _ = u is {} and (S1 and int or string or C3); Diagnostic(ErrorCode.ERR_PatternWrongType, "int").WithArguments("S1", "int").WithLocation(105, 33), // (105,40): error CS8121: An expression of type 'S0' cannot be handled by a pattern of type 'string'. // _ = u is {} and (S1 and int or string or C3); Diagnostic(ErrorCode.ERR_PatternWrongType, "string").WithArguments("S0", "string").WithLocation(105, 40), // (105,50): error CS8121: An expression of type 'S0' cannot be handled by a pattern of type 'C3'. // _ = u is {} and (S1 and int or string or C3); Diagnostic(ErrorCode.ERR_PatternWrongType, "C3").WithArguments("S0", "C3").WithLocation(105, 50) ); } [Fact] public void PatternWrongType_BinaryPattern_04_Disjunction_Snap_To_Previous_UnionType_02() { var src1 = @" [System.Runtime.CompilerServices.Union] struct S0 { private readonly object _value; public S0(byte x) { _value = x; } public S0(S1 x) { _value = x; } public object Value => _value; } [System.Runtime.CompilerServices.Union] struct S1 { private readonly object _value; public S1(C1 x) { _value = x; } public S1(C2 x) { _value = x; } public object Value => _value; } class C1; class C2; class C3; "; var src2 = @" class Program { static void Test1(S0? u) { #line 100 _ = u is {} and ((S1 and int) or string or C3); _ = u is {} and ((S1 and int) or (string or C3)); _ = u is {} and (int or (S1 and C2) or C3); _ = u is {} and (int or ((S1 and C2) or C3)); _ = u is {} and (((S1 and int) or string) or C3); _ = u is {} and (S1 and int or string or C3); } } "; var comp = CreateCompilation([src2, src1, UnionAttributeSource], targetFramework: TargetFramework.NetCoreApp); comp.VerifyDiagnostics( // (100,34): error CS8121: An expression of type 'S1' cannot be handled by a pattern of type 'int'. // _ = u is {} and ((S1 and int) or string or C3); Diagnostic(ErrorCode.ERR_PatternWrongType, "int").WithArguments("S1", "int").WithLocation(100, 34), // (100,42): error CS8121: An expression of type 'S0' cannot be handled by a pattern of type 'string'. // _ = u is {} and ((S1 and int) or string or C3); Diagnostic(ErrorCode.ERR_PatternWrongType, "string").WithArguments("S0", "string").WithLocation(100, 42), // (100,52): error CS8121: An expression of type 'S0' cannot be handled by a pattern of type 'C3'. // _ = u is {} and ((S1 and int) or string or C3); Diagnostic(ErrorCode.ERR_PatternWrongType, "C3").WithArguments("S0", "C3").WithLocation(100, 52), // (101,34): error CS8121: An expression of type 'S1' cannot be handled by a pattern of type 'int'. // _ = u is {} and ((S1 and int) or (string or C3)); Diagnostic(ErrorCode.ERR_PatternWrongType, "int").WithArguments("S1", "int").WithLocation(101, 34), // (101,43): error CS8121: An expression of type 'S0' cannot be handled by a pattern of type 'string'. // _ = u is {} and ((S1 and int) or (string or C3)); Diagnostic(ErrorCode.ERR_PatternWrongType, "string").WithArguments("S0", "string").WithLocation(101, 43), // (101,53): error CS8121: An expression of type 'S0' cannot be handled by a pattern of type 'C3'. // _ = u is {} and ((S1 and int) or (string or C3)); Diagnostic(ErrorCode.ERR_PatternWrongType, "C3").WithArguments("S0", "C3").WithLocation(101, 53), // (102,26): error CS8121: An expression of type 'S0' cannot be handled by a pattern of type 'int'. // _ = u is {} and (int or (S1 and C2) or C3); Diagnostic(ErrorCode.ERR_PatternWrongType, "int").WithArguments("S0", "int").WithLocation(102, 26), // (102,48): error CS8121: An expression of type 'S0' cannot be handled by a pattern of type 'C3'. // _ = u is {} and (int or (S1 and C2) or C3); Diagnostic(ErrorCode.ERR_PatternWrongType, "C3").WithArguments("S0", "C3").WithLocation(102, 48), // (103,26): error CS8121: An expression of type 'S0' cannot be handled by a pattern of type 'int'. // _ = u is {} and (int or ((S1 and C2) or C3)); Diagnostic(ErrorCode.ERR_PatternWrongType, "int").WithArguments("S0", "int").WithLocation(103, 26), // (103,49): error CS8121: An expression of type 'S0' cannot be handled by a pattern of type 'C3'. // _ = u is {} and (int or ((S1 and C2) or C3)); Diagnostic(ErrorCode.ERR_PatternWrongType, "C3").WithArguments("S0", "C3").WithLocation(103, 49), // (104,35): error CS8121: An expression of type 'S1' cannot be handled by a pattern of type 'int'. // _ = u is {} and (((S1 and int) or string) or C3); Diagnostic(ErrorCode.ERR_PatternWrongType, "int").WithArguments("S1", "int").WithLocation(104, 35), // (104,43): error CS8121: An expression of type 'S0' cannot be handled by a pattern of type 'string'. // _ = u is {} and (((S1 and int) or string) or C3); Diagnostic(ErrorCode.ERR_PatternWrongType, "string").WithArguments("S0", "string").WithLocation(104, 43), // (104,54): error CS8121: An expression of type 'S0' cannot be handled by a pattern of type 'C3'. // _ = u is {} and (((S1 and int) or string) or C3); Diagnostic(ErrorCode.ERR_PatternWrongType, "C3").WithArguments("S0", "C3").WithLocation(104, 54), // (105,33): error CS8121: An expression of type 'S1' cannot be handled by a pattern of type 'int'. // _ = u is {} and (S1 and int or string or C3); Diagnostic(ErrorCode.ERR_PatternWrongType, "int").WithArguments("S1", "int").WithLocation(105, 33), // (105,40): error CS8121: An expression of type 'S0' cannot be handled by a pattern of type 'string'. // _ = u is {} and (S1 and int or string or C3); Diagnostic(ErrorCode.ERR_PatternWrongType, "string").WithArguments("S0", "string").WithLocation(105, 40), // (105,50): error CS8121: An expression of type 'S0' cannot be handled by a pattern of type 'C3'. // _ = u is {} and (S1 and int or string or C3); Diagnostic(ErrorCode.ERR_PatternWrongType, "C3").WithArguments("S0", "C3").WithLocation(105, 50) ); } [Fact] public void PatternWrongType_BinaryPattern_05_Conjunction_Pass_UnionType_Through() { var src1 = @" [System.Runtime.CompilerServices.Union] struct S0 { private readonly object _value; public S0(byte x) { _value = x; } public S0(S1 x) { _value = x; } public object Value => _value; } [System.Runtime.CompilerServices.Union] struct S1 { private readonly object _value; public S1(C1 x) { _value = x; } public S1(C2 x) { _value = x; } public object Value => _value; } class C1; class C2; class C3; "; var src2 = @" class Program { static void Test1(object u) { #line 100 _ = u is S1 and string; _ = u is (S1 and {}) and C3; _ = u is S1 and {} and C3; _ = u is S1 and ({} and C3); } static void Test2(object u) { #line 200 _ = u is S0 and S1 and C3; _ = u is (S0 and S1) and C3; _ = u is S0 and (S1 and C3); } } "; var comp = CreateCompilation([src2, src1, UnionAttributeSource], targetFramework: TargetFramework.NetCoreApp); comp.VerifyDiagnostics( // (100,25): error CS8121: An expression of type 'S1' cannot be handled by a pattern of type 'string'. // _ = u is S1 and string; Diagnostic(ErrorCode.ERR_PatternWrongType, "string").WithArguments("S1", "string").WithLocation(100, 25), // (101,34): error CS8121: An expression of type 'S1' cannot be handled by a pattern of type 'C3'. // _ = u is (S1 and {}) and C3; Diagnostic(ErrorCode.ERR_PatternWrongType, "C3").WithArguments("S1", "C3").WithLocation(101, 34), // (102,32): error CS8121: An expression of type 'S1' cannot be handled by a pattern of type 'C3'. // _ = u is S1 and {} and C3; Diagnostic(ErrorCode.ERR_PatternWrongType, "C3").WithArguments("S1", "C3").WithLocation(102, 32), // (103,33): error CS8121: An expression of type 'S1' cannot be handled by a pattern of type 'C3'. // _ = u is S1 and ({} and C3); Diagnostic(ErrorCode.ERR_PatternWrongType, "C3").WithArguments("S1", "C3").WithLocation(103, 33), // (200,32): error CS8121: An expression of type 'S1' cannot be handled by a pattern of type 'C3'. // _ = u is S0 and S1 and C3; Diagnostic(ErrorCode.ERR_PatternWrongType, "C3").WithArguments("S1", "C3").WithLocation(200, 32), // (201,34): error CS8121: An expression of type 'S1' cannot be handled by a pattern of type 'C3'. // _ = u is (S0 and S1) and C3; Diagnostic(ErrorCode.ERR_PatternWrongType, "C3").WithArguments("S1", "C3").WithLocation(201, 34), // (202,33): error CS8121: An expression of type 'S1' cannot be handled by a pattern of type 'C3'. // _ = u is S0 and (S1 and C3); Diagnostic(ErrorCode.ERR_PatternWrongType, "C3").WithArguments("S1", "C3").WithLocation(202, 33) ); } [Fact] public void PatternWrongType_Direct_Value_Matching_01() { var src1 = @" [System.Runtime.CompilerServices.Union] struct S1 { private readonly object _value; public S1(bool x) { _value = x; } public S1(string x) { _value = x; } public object Value => _value; } "; var src2 = @" class Program { static void Test4(object u) { _ = u is S1 { Value: System.IComparable }; _ = u is S1 { Value: bool }; _ = u is S1 { Value: string }; _ = u is S1 { Value: object }; #line 100 _ = u is S1 { Value: long }; _ = u is S1 { Value: true }; #line 200 _ = u is S1 { Value: 1 }; _ = u is S1 { Value: ""a"" }; } } "; var comp = CreateCompilation([src2, src1, UnionAttributeSource], targetFramework: TargetFramework.NetCoreApp); var expected = new[] { // (100,30): error CS8121: An expression of type 'S1' cannot be handled by a pattern of type 'long'. // _ = u is S1 { Value: long }; Diagnostic(ErrorCode.ERR_PatternWrongType, "long").WithArguments("S1", "long").WithLocation(100, 30), // (200,30): error CS9372: An expression of type 'S1' cannot be handled by this pattern, see additional errors at this location. // _ = u is S1 { Value: 1 }; Diagnostic(ErrorCode.ERR_UnionMatchingWrongPattern, "1").WithArguments("S1").WithLocation(200, 30), // (200,30): error CS0029: Cannot implicitly convert type 'int' to 'bool' // _ = u is S1 { Value: 1 }; Diagnostic(ErrorCode.ERR_NoImplicitConv, "1").WithArguments("int", "bool").WithLocation(200, 30), // (200,30): error CS0029: Cannot implicitly convert type 'int' to 'string' // _ = u is S1 { Value: 1 }; Diagnostic(ErrorCode.ERR_NoImplicitConv, "1").WithArguments("int", "string").WithLocation(200, 30) }; comp.VerifyDiagnostics(expected); comp = CreateCompilation([src2, src1, UnionAttributeSource], targetFramework: TargetFramework.NetCoreApp, parseOptions: TestOptions.Regular15); comp.VerifyDiagnostics(expected); comp = CreateCompilation([src2, src1, UnionAttributeSource], targetFramework: TargetFramework.NetCoreApp, parseOptions: TestOptions.Regular14); comp.VerifyDiagnostics( [ ..expected, // (6,23): error CS9327: Feature 'unions' is not available in C# 14.0. Please use language version 15.0 or greater. // _ = u is S1 { Value: System.IComparable }; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion14, "Value").WithArguments("unions", "15.0").WithLocation(6, 23), // (7,23): error CS9327: Feature 'unions' is not available in C# 14.0. Please use language version 15.0 or greater. // _ = u is S1 { Value: bool }; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion14, "Value").WithArguments("unions", "15.0").WithLocation(7, 23), // (8,23): error CS9327: Feature 'unions' is not available in C# 14.0. Please use language version 15.0 or greater. // _ = u is S1 { Value: string }; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion14, "Value").WithArguments("unions", "15.0").WithLocation(8, 23), // (9,23): error CS9327: Feature 'unions' is not available in C# 14.0. Please use language version 15.0 or greater. // _ = u is S1 { Value: object }; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion14, "Value").WithArguments("unions", "15.0").WithLocation(9, 23), // (100,23): error CS9327: Feature 'unions' is not available in C# 14.0. Please use language version 15.0 or greater. // _ = u is S1 { Value: long }; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion14, "Value").WithArguments("unions", "15.0").WithLocation(100, 23), // (102,23): error CS9327: Feature 'unions' is not available in C# 14.0. Please use language version 15.0 or greater. // _ = u is S1 { Value: true }; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion14, "Value").WithArguments("unions", "15.0").WithLocation(102, 23), // (200,23): error CS9327: Feature 'unions' is not available in C# 14.0. Please use language version 15.0 or greater. // _ = u is S1 { Value: 1 }; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion14, "Value").WithArguments("unions", "15.0").WithLocation(200, 23), // (201,23): error CS9327: Feature 'unions' is not available in C# 14.0. Please use language version 15.0 or greater. // _ = u is S1 { Value: "a" }; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion14, "Value").WithArguments("unions", "15.0").WithLocation(201, 23) ]); } [Theory] [CombinatorialData] public void PatternWrongType_Direct_Value_Matching_02(bool field) { var src1 = @" [System.Runtime.CompilerServices.Union] struct S1 { private readonly object _value; public S1(bool x) { _value = x; } public S1(string x) { _value = x; } public object Value => _value; } struct S2 { public S2(S1 s1) { S1 = s1; } public S1 S1" + (field ? ";" : " { get; }") + @" } "; var src2 = @" class Program { static void Test4(S2 u) { _ = u is { S1.Value: System.IComparable }; _ = u is { S1.Value: bool }; _ = u is { S1.Value: string }; _ = u is { S1.Value: object }; #line 100 _ = u is { S1.Value: long }; _ = u is { S1.Value: true }; #line 200 _ = u is { S1.Value: 1 }; _ = u is { S1.Value: ""a"" }; } } "; var comp = CreateCompilation([src2, src1, UnionAttributeSource], targetFramework: TargetFramework.NetCoreApp); var expected = new[] { // (100,30): error CS8121: An expression of type 'S1' cannot be handled by a pattern of type 'long'. // _ = u is { S1.Value: long }; Diagnostic(ErrorCode.ERR_PatternWrongType, "long").WithArguments("S1", "long").WithLocation(100, 30), // (200,30): error CS9372: An expression of type 'S1' cannot be handled by this pattern, see additional errors at this location. // _ = u is { S1.Value: 1 }; Diagnostic(ErrorCode.ERR_UnionMatchingWrongPattern, "1").WithArguments("S1").WithLocation(200, 30), // (200,30): error CS0029: Cannot implicitly convert type 'int' to 'bool' // _ = u is { S1.Value: 1 }; Diagnostic(ErrorCode.ERR_NoImplicitConv, "1").WithArguments("int", "bool").WithLocation(200, 30), // (200,30): error CS0029: Cannot implicitly convert type 'int' to 'string' // _ = u is { S1.Value: 1 }; Diagnostic(ErrorCode.ERR_NoImplicitConv, "1").WithArguments("int", "string").WithLocation(200, 30) }; comp.VerifyDiagnostics(expected); comp = CreateCompilation([src2, src1, UnionAttributeSource], targetFramework: TargetFramework.NetCoreApp, parseOptions: TestOptions.Regular15); comp.VerifyDiagnostics(expected); comp = CreateCompilation([src2, src1, UnionAttributeSource], targetFramework: TargetFramework.NetCoreApp, parseOptions: TestOptions.Regular14); comp.VerifyDiagnostics( [ ..expected, // (6,23): error CS9327: Feature 'unions' is not available in C# 14.0. Please use language version 15.0 or greater. // _ = u is { S1.Value: System.IComparable }; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion14, "Value").WithArguments("unions", "15.0").WithLocation(6, 23), // (7,23): error CS9327: Feature 'unions' is not available in C# 14.0. Please use language version 15.0 or greater. // _ = u is { S1.Value: bool }; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion14, "Value").WithArguments("unions", "15.0").WithLocation(7, 23), // (8,23): error CS9327: Feature 'unions' is not available in C# 14.0. Please use language version 15.0 or greater. // _ = u is { S1.Value: string }; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion14, "Value").WithArguments("unions", "15.0").WithLocation(8, 23), // (9,23): error CS9327: Feature 'unions' is not available in C# 14.0. Please use language version 15.0 or greater. // _ = u is { S1.Value: object }; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion14, "Value").WithArguments("unions", "15.0").WithLocation(9, 23), // (100,23): error CS9327: Feature 'unions' is not available in C# 14.0. Please use language version 15.0 or greater. // _ = u is { S1.Value: long }; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion14, "Value").WithArguments("unions", "15.0").WithLocation(100, 23), // (102,23): error CS9327: Feature 'unions' is not available in C# 14.0. Please use language version 15.0 or greater. // _ = u is { S1.Value: true }; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion14, "Value").WithArguments("unions", "15.0").WithLocation(102, 23), // (200,23): error CS9327: Feature 'unions' is not available in C# 14.0. Please use language version 15.0 or greater. // _ = u is { S1.Value: 1 }; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion14, "Value").WithArguments("unions", "15.0").WithLocation(200, 23), // (201,23): error CS9327: Feature 'unions' is not available in C# 14.0. Please use language version 15.0 or greater. // _ = u is { S1.Value: "a" }; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion14, "Value").WithArguments("unions", "15.0").WithLocation(201, 23) ]); } [Theory] [CombinatorialData] public void PatternWrongType_Direct_Value_Matching_03(bool field) { var src1 = @" [System.Runtime.CompilerServices.Union] struct S1 { private readonly object _value; public S1(bool x) { _value = x; } public S1(string x) { _value = x; } public object Value => _value; } struct S2 { public S2(S1? s1) { S1 = s1; } public S1? S1" + (field ? ";" : " { get; }") + @" } "; var src2 = @" class Program { static void Test4(S2 u) { _ = u is { S1.Value: System.IComparable }; _ = u is { S1.Value: bool }; _ = u is { S1.Value: string }; _ = u is { S1.Value: object }; #line 100 _ = u is { S1.Value: long }; _ = u is { S1.Value: true }; #line 200 _ = u is { S1.Value: 1 }; _ = u is { S1.Value: ""a"" }; } } "; var comp = CreateCompilation([src2, src1, UnionAttributeSource], targetFramework: TargetFramework.NetCoreApp); var expected = new[] { // (100,30): error CS8121: An expression of type 'S1' cannot be handled by a pattern of type 'long'. // _ = u is { S1.Value: long }; Diagnostic(ErrorCode.ERR_PatternWrongType, "long").WithArguments("S1", "long").WithLocation(100, 30), // (200,30): error CS9372: An expression of type 'S1' cannot be handled by this pattern, see additional errors at this location. // _ = u is { S1.Value: 1 }; Diagnostic(ErrorCode.ERR_UnionMatchingWrongPattern, "1").WithArguments("S1").WithLocation(200, 30), // (200,30): error CS0029: Cannot implicitly convert type 'int' to 'bool' // _ = u is { S1.Value: 1 }; Diagnostic(ErrorCode.ERR_NoImplicitConv, "1").WithArguments("int", "bool").WithLocation(200, 30), // (200,30): error CS0029: Cannot implicitly convert type 'int' to 'string' // _ = u is { S1.Value: 1 }; Diagnostic(ErrorCode.ERR_NoImplicitConv, "1").WithArguments("int", "string").WithLocation(200, 30) }; comp.VerifyDiagnostics(expected); comp = CreateCompilation([src2, src1, UnionAttributeSource], targetFramework: TargetFramework.NetCoreApp, parseOptions: TestOptions.Regular15); comp.VerifyDiagnostics(expected); comp = CreateCompilation([src2, src1, UnionAttributeSource], targetFramework: TargetFramework.NetCoreApp, parseOptions: TestOptions.Regular14); comp.VerifyDiagnostics( [ ..expected, // (6,23): error CS9327: Feature 'unions' is not available in C# 14.0. Please use language version 15.0 or greater. // _ = u is { S1.Value: System.IComparable }; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion14, "Value").WithArguments("unions", "15.0").WithLocation(6, 23), // (7,23): error CS9327: Feature 'unions' is not available in C# 14.0. Please use language version 15.0 or greater. // _ = u is { S1.Value: bool }; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion14, "Value").WithArguments("unions", "15.0").WithLocation(7, 23), // (8,23): error CS9327: Feature 'unions' is not available in C# 14.0. Please use language version 15.0 or greater. // _ = u is { S1.Value: string }; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion14, "Value").WithArguments("unions", "15.0").WithLocation(8, 23), // (9,23): error CS9327: Feature 'unions' is not available in C# 14.0. Please use language version 15.0 or greater. // _ = u is { S1.Value: object }; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion14, "Value").WithArguments("unions", "15.0").WithLocation(9, 23), // (100,23): error CS9327: Feature 'unions' is not available in C# 14.0. Please use language version 15.0 or greater. // _ = u is { S1.Value: long }; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion14, "Value").WithArguments("unions", "15.0").WithLocation(100, 23), // (102,23): error CS9327: Feature 'unions' is not available in C# 14.0. Please use language version 15.0 or greater. // _ = u is { S1.Value: true }; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion14, "Value").WithArguments("unions", "15.0").WithLocation(102, 23), // (200,23): error CS9327: Feature 'unions' is not available in C# 14.0. Please use language version 15.0 or greater. // _ = u is { S1.Value: 1 }; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion14, "Value").WithArguments("unions", "15.0").WithLocation(200, 23), // (201,23): error CS9327: Feature 'unions' is not available in C# 14.0. Please use language version 15.0 or greater. // _ = u is { S1.Value: "a" }; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion14, "Value").WithArguments("unions", "15.0").WithLocation(201, 23) ]); } [Fact] public void Exhaustiveness_01() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 { private readonly object _value; public S1(int x) { _value = x; } #nullable enable public S1(string? x) { _value = x; } #nullable disable public object Value => _value; } class Program { static int Test1(S1 u) { #line 100 return u switch { int => 1, string => 2, null => 3 }; } static int Test2(S1 u) { #line 200 return u switch { int => 1, null => 3, string => 2 }; } static int Test3(S1 u) { #line 300 return u switch { null => 3, int => 1, string => 2 }; } static int Test4(S1 u) { #line 400 return u switch { int => 1, string => 2 }; } static int Test5(S1 u) { #nullable enable #line 500 return u switch { int => 1, string => 2 }; #nullable disable } static int Test6(S1 u) { #line 600 return u switch { int => 1, null => 3 }; } static int Test7(S1 u) { #line 700 return u switch { null => 3, int => 1 }; } static int Test8(S1 u) { #line 800 return u switch { int => 1 }; } static int Test9(S1 u) { #line 900 return u switch { not int => 1 }; } static int Test10(S1 u) { #line 1000 return u switch { null => 3, not int => 1 }; } static int Test11(S1 u) { #line 1100 return u switch { not null => 1 }; } static int Test11_5(S1 u) { #nullable enable #line 1150 return u switch { not null => 1 }; #nullable disable } static int Test12(S1 u) { #line 1200 return u switch { null => 3, not null => 1 }; } static int Test13(S1 u) { #line 1300 return u switch { not null => 3, null => 1 }; } static int Test15(S1 u) { #line 1500 return u switch { null => 3, var x => 1 }; } } "; var comp = CreateCompilation([src, UnionAttributeSource]); var verifier = CompileAndVerify(comp).VerifyDiagnostics( // (500,18): warning CS8655: The switch expression does not handle some null inputs (it is not exhaustive). For example, the pattern 'null' is not covered. // return u switch { int => 1, string => 2 }; Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustiveForNull, "switch").WithArguments("null").WithLocation(500, 18), // (600,18): warning CS8509: The switch expression does not handle all possible values of its input type (it is not exhaustive). For example, the pattern 'string' is not covered. // return u switch { int => 1, null => 3 }; Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustive, "switch").WithArguments("string").WithLocation(600, 18), // (700,18): warning CS8509: The switch expression does not handle all possible values of its input type (it is not exhaustive). For example, the pattern 'string' is not covered. // return u switch { null => 3, int => 1 }; Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustive, "switch").WithArguments("string").WithLocation(700, 18), // (800,18): warning CS8509: The switch expression does not handle all possible values of its input type (it is not exhaustive). For example, the pattern 'string' is not covered. // return u switch { int => 1 }; Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustive, "switch").WithArguments("string").WithLocation(800, 18), // (900,18): warning CS8509: The switch expression does not handle all possible values of its input type (it is not exhaustive). For example, the pattern 'int' is not covered. // return u switch { not int => 1 }; Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustive, "switch").WithArguments("int").WithLocation(900, 18), // (1000,18): warning CS8509: The switch expression does not handle all possible values of its input type (it is not exhaustive). For example, the pattern 'int' is not covered. // return u switch { null => 3, not int => 1 }; Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustive, "switch").WithArguments("int").WithLocation(1000, 18), // (1150,18): warning CS8655: The switch expression does not handle some null inputs (it is not exhaustive). For example, the pattern 'null' is not covered. // return u switch { not null => 1 }; Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustiveForNull, "switch").WithArguments("null").WithLocation(1150, 18) ); verifier.VerifyIL("Program.Test1", @" { // Code size 48 (0x30) .maxstack 1 .locals init (int V_0, object V_1) IL_0000: ldarga.s V_0 IL_0002: call ""object S1.Value.get"" IL_0007: stloc.1 IL_0008: ldloc.1 IL_0009: isinst ""int"" IL_000e: brtrue.s IL_001d IL_0010: ldloc.1 IL_0011: isinst ""string"" IL_0016: brtrue.s IL_0021 IL_0018: ldloc.1 IL_0019: brfalse.s IL_0025 IL_001b: br.s IL_0029 IL_001d: ldc.i4.1 IL_001e: stloc.0 IL_001f: br.s IL_002e IL_0021: ldc.i4.2 IL_0022: stloc.0 IL_0023: br.s IL_002e IL_0025: ldc.i4.3 IL_0026: stloc.0 IL_0027: br.s IL_002e IL_0029: call ""void <PrivateImplementationDetails>.ThrowInvalidOperationException()"" IL_002e: ldloc.0 IL_002f: ret } "); } [Fact] public void Exhaustiveness_02() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 { private readonly object _value; public S1(int? x) { _value = x; } public S1(string x) { _value = x; } public object Value => _value; } class Program { static int Test1(S1 u) { #line 100 return u switch { int => 1, string => 2, null => 3 }; } static int Test2(S1 u) { #line 200 return u switch { int => 1, null => 3, string => 2 }; } static int Test3(S1 u) { #line 300 return u switch { null => 3, int => 1, string => 2 }; } static int Test4(S1 u) { #line 400 return u switch { int => 1, string => 2 }; } static int Test5(S1 u) { #nullable enable #line 500 return u switch { int => 1, string => 2 }; #nullable disable } static int Test6(S1 u) { #line 600 return u switch { int => 1, null => 3 }; } static int Test7(S1 u) { #line 700 return u switch { null => 3, int => 1 }; } static int Test8(S1 u) { #line 800 return u switch { int => 1 }; } static int Test9(S1 u) { #line 900 return u switch { not int => 1 }; } static int Test10(S1 u) { #line 1000 return u switch { null => 3, not int => 1 }; } } "; var comp = CreateCompilation([src, UnionAttributeSource]); comp.VerifyDiagnostics( // (500,18): warning CS8655: The switch expression does not handle some null inputs (it is not exhaustive). For example, the pattern 'null' is not covered. // return u switch { int => 1, string => 2 }; Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustiveForNull, "switch").WithArguments("null").WithLocation(500, 18), // (600,18): warning CS8509: The switch expression does not handle all possible values of its input type (it is not exhaustive). For example, the pattern 'string' is not covered. // return u switch { int => 1, null => 3 }; Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustive, "switch").WithArguments("string").WithLocation(600, 18), // (700,18): warning CS8509: The switch expression does not handle all possible values of its input type (it is not exhaustive). For example, the pattern 'string' is not covered. // return u switch { null => 3, int => 1 }; Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustive, "switch").WithArguments("string").WithLocation(700, 18), // (800,18): warning CS8509: The switch expression does not handle all possible values of its input type (it is not exhaustive). For example, the pattern 'string' is not covered. // return u switch { int => 1 }; Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustive, "switch").WithArguments("string").WithLocation(800, 18), // (900,18): warning CS8509: The switch expression does not handle all possible values of its input type (it is not exhaustive). For example, the pattern 'int' is not covered. // return u switch { not int => 1 }; Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustive, "switch").WithArguments("int").WithLocation(900, 18), // (1000,18): warning CS8509: The switch expression does not handle all possible values of its input type (it is not exhaustive). For example, the pattern 'int' is not covered. // return u switch { null => 3, not int => 1 }; Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustive, "switch").WithArguments("int").WithLocation(1000, 18) ); } [Fact] public void Exhaustiveness_03() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 { private readonly object _value; public S1(int x) { _value = x; } #nullable enable public S1(string? x) { _value = x; } #nullable disable public object Value => _value; } class Program { static int Test1(S1 u) { #line 100 return u switch { not null => 2, null => 3 }; } static int Test2(S1 u) { #nullable enable #line 200 return u switch { not null => 2, null => 3 }; #nullable disable } } "; var comp = CreateCompilation([src, UnionAttributeSource]); comp.VerifyDiagnostics( ); } [Fact] public void Exhaustiveness_04() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 { private readonly object _value; public S1(bool x) { _value = x; } #nullable enable public S1(string? x) { _value = x; } #nullable disable public object Value => _value; } class Program { static int Test1(S1 u) { #line 100 return u switch { true => 1, false => 4, string => 2, null => 3 }; } static int Test2(S1 u) { #line 200 return u switch { true => 1, false => 4, string => 2 }; } static int Test3(S1 u) { #nullable enable #line 300 return u switch { true => 1, false => 4, string => 2 }; #nullable disable } static int Test4(S1 u) { #line 400 return u switch { true => 1, string => 2, null => 3 }; } static int Test5(S1 u) { #line 500 return u switch { null => 3 , true => 1, string => 2 }; } } "; var comp = CreateCompilation([src, UnionAttributeSource]); comp.VerifyDiagnostics( // (300,18): warning CS8655: The switch expression does not handle some null inputs (it is not exhaustive). For example, the pattern 'null' is not covered. // return u switch { true => 1, false => 4, string => 2 }; Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustiveForNull, "switch").WithArguments("null").WithLocation(300, 18), // (400,18): warning CS8509: The switch expression does not handle all possible values of its input type (it is not exhaustive). For example, the pattern 'false' is not covered. // return u switch { true => 1, string => 2, null => 3 }; Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustive, "switch").WithArguments("false").WithLocation(400, 18), // (500,18): warning CS8509: The switch expression does not handle all possible values of its input type (it is not exhaustive). For example, the pattern 'false' is not covered. // return u switch { null => 3 , true => 1, string => 2 }; Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustive, "switch").WithArguments("false").WithLocation(500, 18) ); } [Fact] public void Exhaustiveness_05() { var src1 = @" #nullable enable [System.Runtime.CompilerServices.Union] class C1 { private readonly object? _value; public C1(){} public C1(int x) { _value = x; } public C1(string? x) { _value = x; } public object? Value => _value; } class Program { static void Main() { System.Console.Write(Test1(new C1(10))); System.Console.Write(Test1(new C1())); System.Console.Write(Test1(new C1(""10""))); System.Console.Write(Test1(null)); System.Console.Write(' '); System.Console.Write(Test2(new C1(10))); System.Console.Write(Test2(new C1())); System.Console.Write(Test2(new C1(""10""))); System.Console.Write(Test2(null)); } static int Test1(C1? u) { #line 26 return u switch { int => 1, string => 2, null => 3 }; } static int Test2(C1? u) { #line 31 return u switch { int => -1, string => -2, _ => -3 }; } static int Test3(C2? u) { return u switch { { Value: int } => -1, { Value: string } => -2, { Value: null } => -3, _ => -4 }; } static int Test4(C1? u) { return u switch { _ => 3 }; } static int Test5(C2 u) { #line 46 return u switch { null => -4, { Value: int } => -1, { Value: string } => -2, { Value: object } => -3 }; } } class C2 { public object? Value => null; } "; var comp1 = CreateCompilation([src1, UnionAttributeSource], options: TestOptions.ReleaseExe); CompileAndVerify(comp1, expectedOutput: "1323 -1-3-2-3").VerifyDiagnostics( // (46,18): warning CS8655: The switch expression does not handle some null inputs (it is not exhaustive). For example, the pattern '{ Value: null }' is not covered. // return u switch { null => -4, { Value: int } => -1, { Value: string } => -2, { Value: object } => -3 }; Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustiveForNull, "switch").WithArguments("{ Value: null }").WithLocation(46, 18) ); var src2 = @" #nullable enable [System.Runtime.CompilerServices.Union] class C1 { private readonly object? _value; public C1(){} public C1(int x) { _value = x; } public C1(string? x) { _value = x; } public object? Value => _value; } class Program { static int Test2(C1? u) { #line 31 return u switch { int => -1, string => -2, null => -3, _ => -4 }; } } class C2 { public object? Value => null; } "; var comp2 = CreateCompilation([src2, UnionAttributeSource]); comp2.VerifyDiagnostics( // (31,64): error CS8510: The pattern is unreachable. It has already been handled by a previous arm of the switch expression or it is impossible to match. // return u switch { int => -1, string => -2, null => -3, _ => -4 }; Diagnostic(ErrorCode.ERR_SwitchArmSubsumed, "_").WithLocation(31, 64) ); } [Fact] public void Exhaustiveness_06() { var src = @" #nullable enable [System.Runtime.CompilerServices.Union] class C1 { private readonly object? _value; public C1(){} public C1(int x) { _value = x; } public C1(string? x) { _value = x; } public object? Value => _value; } class Program { static int Test4(C1? u) { #line 41 return u switch { int => 1, string => 2, not null => 3 }; } } "; var comp = CreateCompilation([src, UnionAttributeSource]); comp.VerifyDiagnostics( // (41,50): error CS8510: The pattern is unreachable. It has already been handled by a previous arm of the switch expression or it is impossible to match. // return u switch { int => 1, string => 2, not null => 3 }; Diagnostic(ErrorCode.ERR_SwitchArmSubsumed, "not null").WithLocation(41, 50), // The following warning is for 'u.Value' missing null check. // (41,18): warning CS8655: The switch expression does not handle some null inputs (it is not exhaustive). For example, the pattern 'null' is not covered. // return u switch { int => 1, string => 2, not null => 3 }; Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustiveForNull, "switch").WithArguments("null").WithLocation(41, 18) ); } [Fact] public void Exhaustiveness_07() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 { private readonly object _value; public S1(int x) { _value = x; } public S1(C1 x) { _value = x; } public object Value => _value; } class C1; class C2 : C1; class Program { static int Test1(S1 u) { #line 17 return u switch { int => 1, C2 => 2, null => 3 }; } } "; var comp = CreateCompilation([src, UnionAttributeSource]); comp.VerifyDiagnostics( // (17,18): warning CS8509: The switch expression does not handle all possible values of its input type (it is not exhaustive). For example, the pattern 'C1' is not covered. // return u switch { int => 1, C2 => 2, null => 3 }; Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustive, "switch").WithArguments("C1").WithLocation(17, 18) ); } [Fact] public void Exhaustiveness_08() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 { private readonly object _value; public S1(int x) { _value = x; } public S1(C2 x) { _value = x; } public object Value => _value; } class C1; class C2 : C1; class Program { static int Test1(S1 u) { #line 17 return u switch { int => 1, C1 => 2, null => 3 }; } } "; var comp = CreateCompilation([src, UnionAttributeSource]); comp.VerifyDiagnostics( ); } [Fact] public void Exhaustiveness_09() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 { private readonly object _value; public S1(int x) { _value = x; } public S1(C2 x) { _value = x; } public object Value => _value; } interface I1; class C2; class C3; class Program { static int Test1(S1 u) { #line 18 return u switch { int => 1, I1 => 2, null => 3 }; } static int Test2(S1 u) { return u switch { int => 1, I1 => 2, C2 => 4, null => 3 }; } static int Test3(S1 u) { return u switch { int => 1, I1 => 2, C3 => 5, C2 => 4, null => 3 }; } static int Test4(S1 u) { return u switch { int => 1, I1 => 2, null => 3, C2 => 4 }; } } "; var comp = CreateCompilation([src, UnionAttributeSource]); comp.VerifyDiagnostics( // (18,18): warning CS8509: The switch expression does not handle all possible values of its input type (it is not exhaustive). For example, the pattern 'C2' is not covered. // return u switch { int => 1, I1 => 2, null => 3 }; Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustive, "switch").WithArguments("C2").WithLocation(18, 18), // (28,46): error CS8121: An expression of type 'S1' cannot be handled by a pattern of type 'C3'. // return u switch { int => 1, I1 => 2, C3 => 5, C2 => 4, null => 3 }; Diagnostic(ErrorCode.ERR_PatternWrongType, "C3").WithArguments("S1", "C3").WithLocation(28, 46) ); } [Fact] public void Exhaustiveness_10() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 { private readonly object _value; public S1(Q x) { _value = x; } public S1(int x) { _value = x; } public object Value => _value; } class C { #line 12 int M2(S1 o) => o switch { not (Q(1, 2.5) { P1: 1 } and Q(3, 4, 5) { P2: 2 }) => 1 }; int M3(S1 o) => o switch { null => 0, not (Q(1, 2.5) { P1: 1 } and Q(3, 4, 5) { P2: 2 }) => 1 }; } class Q { public void Deconstruct(out object o1, out object o2) => throw null!; public void Deconstruct(out object o1, out object o2, out object o3) => throw null!; public int P1 = 5; public int P2 = 6; } "; var comp = CreateCompilation([src, UnionAttributeSource]); comp.VerifyDiagnostics( // (12,23): warning CS8509: The switch expression does not handle all possible values of its input type (it is not exhaustive). For example, the pattern 'Q(1, 2.5D) and (3, 4, 5) { P1: 1, P2: 2 }' is not covered. // int M2(S1 o) => o switch { not (Q(1, 2.5) { P1: 1 } and Q(3, 4, 5) { P2: 2 }) => 1 }; Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustive, "switch").WithArguments("Q(1, 2.5D) and (3, 4, 5) { P1: 1, P2: 2 }").WithLocation(12, 23), // (13,23): warning CS8509: The switch expression does not handle all possible values of its input type (it is not exhaustive). For example, the pattern 'Q(1, 2.5D) and (3, 4, 5) { P1: 1, P2: 2 }' is not covered. // int M3(S1 o) => o switch { null => 0, not (Q(1, 2.5) { P1: 1 } and Q(3, 4, 5) { P2: 2 }) => 1 }; Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustive, "switch").WithArguments("Q(1, 2.5D) and (3, 4, 5) { P1: 1, P2: 2 }").WithLocation(13, 23) ); } [Fact] public void Exhaustiveness_11() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 { private readonly object _value; public S1(Q x) { _value = x; } public S1(int x) { _value = x; } public object Value => _value; } class C { int M2(S1 o) #line 100 => o switch { int => 1, Q { P1: true } => 2 }; int M3(S1 o) #line 200 => o switch { Q { P1: true } => 2, int => 1 }; int M4(S1 o) #line 300 => o switch { null => 0, int => 1, Q { P1: true } => 2 }; int M5(S1 o) #line 400 => o switch { null => 0, Q { P1: true } => 2, int => 1 }; } class Q { public bool P1 = false; } "; var comp = CreateCompilation([src, UnionAttributeSource]); comp.VerifyDiagnostics( // (100,14): warning CS8509: The switch expression does not handle all possible values of its input type (it is not exhaustive). For example, the pattern 'Q{ P1: false }' is not covered. // => o switch { int => 1, Q { P1: true } => 2 }; Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustive, "switch").WithArguments("Q{ P1: false }").WithLocation(100, 14), // (200,14): warning CS8509: The switch expression does not handle all possible values of its input type (it is not exhaustive). For example, the pattern 'Q{ P1: false }' is not covered. // => o switch { Q { P1: true } => 2, int => 1 }; Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustive, "switch").WithArguments("Q{ P1: false }").WithLocation(200, 14), // (300,14): warning CS8509: The switch expression does not handle all possible values of its input type (it is not exhaustive). For example, the pattern 'Q{ P1: false }' is not covered. // => o switch { null => 0, int => 1, Q { P1: true } => 2 }; Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustive, "switch").WithArguments("Q{ P1: false }").WithLocation(300, 14), // (400,14): warning CS8509: The switch expression does not handle all possible values of its input type (it is not exhaustive). For example, the pattern 'Q{ P1: false }' is not covered. // => o switch { null => 0, Q { P1: true } => 2, int => 1 }; Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustive, "switch").WithArguments("Q{ P1: false }").WithLocation(400, 14) ); } [Fact] public void Exhaustiveness_12() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 { private readonly object _value; public S1(int x) { _value = x; } #nullable enable public S1(string? x) { _value = x; } #nullable disable public object Value => _value; } class Program { static int Test1(S1 u) { #line 100 return u switch { object => 1, null => 3 }; } static int Test3(S1 u) { #line 300 return u switch { null => 3, object => 2 }; } static int Test4(S1 u) { #line 400 return u switch { object => 2 }; } static int Test5(S1 u) { #nullable enable #line 500 return u switch { object => 2 }; #nullable disable } static int Test9(S1 u) { #line 900 return u switch { not object => 1 }; } } "; var comp = CreateCompilation([src, UnionAttributeSource]); comp.VerifyDiagnostics( // (100,40): error CS8510: The pattern is unreachable. It has already been handled by a previous arm of the switch expression or it is impossible to match. // return u switch { object => 1, null => 3 }; Diagnostic(ErrorCode.ERR_SwitchArmSubsumed, "null").WithLocation(100, 40), // (900,18): warning CS8509: The switch expression does not handle all possible values of its input type (it is not exhaustive). For example, the pattern '_' is not covered. // return u switch { not object => 1 }; Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustive, "switch").WithArguments("_").WithLocation(900, 18), // (900,27): error CS8510: The pattern is unreachable. It has already been handled by a previous arm of the switch expression or it is impossible to match. // return u switch { not object => 1 }; Diagnostic(ErrorCode.ERR_SwitchArmSubsumed, "not object").WithLocation(900, 27) ); } [Fact] public void Exhaustiveness_13() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 { private readonly object _value; #nullable enable public S1(string x) { _value = x; } public object? Value => _value; #nullable disable } class Program { static int Test1(S1 u) { #line 100 return u switch { string => 2, null => 3 }; } static int Test4(S1 u) { #line 400 return u switch { string => 2 }; } static int Test5(S1 u) { #nullable enable #line 500 return u switch { string => 2 }; #nullable disable } static int Test6(S1 u) { #line 600 return u switch { null => 3, string => 2 }; } } "; var comp = CreateCompilation([src, UnionAttributeSource]); var verifier = CompileAndVerify(comp).VerifyDiagnostics( ); } [Fact] public void Exhaustiveness_14() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 { private readonly object _value; public S1(int x) { _value = x; } #nullable enable public object? Value => _value; #nullable disable } class Program { static int Test1(S1 u) { #line 100 return u switch { int => 1, null => 3 }; } static int Test4(S1 u) { #line 400 return u switch { int => 1 }; } static int Test5(S1 u) { #nullable enable #line 500 return u switch { int => 1 }; #nullable disable } static int Test6(S1 u) { #line 600 return u switch { null => 3, int => 1 }; } } "; var comp = CreateCompilation([src, UnionAttributeSource]); var verifier = CompileAndVerify(comp).VerifyDiagnostics( ); } [Fact] public void Exhaustiveness_15_Direct_Value_Matching() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 { private readonly object _value; public S1(int x) { _value = x; } #nullable enable public S1(string? x) { _value = x; } #nullable disable public object Value => _value; } class Program { static int Test1(object u) { #line 100 return u switch { S1 { Value: int } => 1, S1 { Value: string } => 2, S1 { Value: null } => 3, not S1 => -100 }; } static int Test2(object u) { #line 200 return u switch { S1 { Value: int } => 1, S1 { Value: null } => 3, S1 { Value: string } => 2, not S1 => -100 }; } static int Test3(object u) { #line 300 return u switch { S1 { Value: null } => 3, S1 { Value: int } => 1, S1 { Value: string } => 2, not S1 => -100 }; } static int Test4(object u) { #line 400 return u switch { S1 { Value: int } => 1, S1 { Value: string } => 2, not S1 => -100 }; } static int Test5(object u) { #nullable enable #line 500 return u switch { S1 { Value: int } => 1, S1 { Value: string } => 2, not S1 => -100 }; #nullable disable } static int Test6(object u) { #line 600 return u switch { S1 { Value: int } => 1, S1 { Value: null } => 3, not S1 => -100 }; } static int Test7(object u) { #line 700 return u switch { S1 { Value: null } => 3, S1 { Value: int } => 1, not S1 => -100 }; } static int Test8(object u) { #line 800 return u switch { S1 { Value: int } => 1, not S1 => -100 }; } static int Test9(object u) { #line 900 return u switch { S1 { Value: not int } => 1, not S1 => -100 }; } static int Test10(object u) { #line 1000 return u switch { S1 { Value: null } => 3, S1 { Value: not int } => 1, not S1 => -100 }; } static int Test11(object u) { #line 1100 return u switch { S1 { Value: not null } => 1, not S1 => -100 }; } static int Test11_5(object u) { #nullable enable #line 1150 return u switch { S1 { Value: not null } => 1, not S1 => -100 }; #nullable disable } static int Test12(object u) { #line 1200 return u switch { S1 { Value: null } => 3, S1 { Value: not null } => 1, not S1 => -100 }; } static int Test13(object u) { #line 1300 return u switch { S1 { Value: not null } => 3, S1 { Value: null } => 1, not S1 => -100 }; } static int Test14(object u) { #line 1400 return u switch { S1 { Value: { } } => 1, S1 { Value: null } => 3, not S1 => -100 }; } static int Test15(object u) { #line 1500 return u switch { S1 { Value: null } => 3, S1 { Value: var x } => 1, not S1 => -100 }; } } "; var comp = CreateCompilation([src, UnionAttributeSource]); var expected = new[] { // (500,18): warning CS8655: The switch expression does not handle some null inputs (it is not exhaustive). For example, the pattern 'S1{ Value: null }' is not covered. // return u switch { S1 { Value: int } => 1, S1 { Value: string } => 2, not S1 => -100 }; Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustiveForNull, "switch").WithArguments("S1{ Value: null }").WithLocation(500, 18), // (600,18): warning CS8509: The switch expression does not handle all possible values of its input type (it is not exhaustive). For example, the pattern 'S1{ Value: string }' is not covered. // return u switch { S1 { Value: int } => 1, S1 { Value: null } => 3, not S1 => -100 }; Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustive, "switch").WithArguments("S1{ Value: string }").WithLocation(600, 18), // (700,18): warning CS8509: The switch expression does not handle all possible values of its input type (it is not exhaustive). For example, the pattern 'S1{ Value: string }' is not covered. // return u switch { S1 { Value: null } => 3, S1 { Value: int } => 1, not S1 => -100 }; Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustive, "switch").WithArguments("S1{ Value: string }").WithLocation(700, 18), // (800,18): warning CS8509: The switch expression does not handle all possible values of its input type (it is not exhaustive). For example, the pattern 'S1{ Value: string }' is not covered. // return u switch { S1 { Value: int } => 1, not S1 => -100 }; Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustive, "switch").WithArguments("S1{ Value: string }").WithLocation(800, 18), // (900,18): warning CS8509: The switch expression does not handle all possible values of its input type (it is not exhaustive). For example, the pattern 'S1{ Value: int }' is not covered. // return u switch { S1 { Value: not int } => 1, not S1 => -100 }; Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustive, "switch").WithArguments("S1{ Value: int }").WithLocation(900, 18), // (1000,18): warning CS8509: The switch expression does not handle all possible values of its input type (it is not exhaustive). For example, the pattern 'S1{ Value: int }' is not covered. // return u switch { S1 { Value: null } => 3, S1 { Value: not int } => 1, not S1 => -100 }; Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustive, "switch").WithArguments("S1{ Value: int }").WithLocation(1000, 18), // (1150,18): warning CS8655: The switch expression does not handle some null inputs (it is not exhaustive). For example, the pattern 'S1{ Value: null }' is not covered. // return u switch { S1 { Value: not null } => 1, not S1 => -100 }; Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustiveForNull, "switch").WithArguments("S1{ Value: null }").WithLocation(1150, 18), }; CompileAndVerify(comp).VerifyDiagnostics(expected); comp = CreateCompilation([src, UnionAttributeSource], parseOptions: TestOptions.Regular15); CompileAndVerify(comp).VerifyDiagnostics(expected); comp = CreateCompilation([src, UnionAttributeSource], parseOptions: TestOptions.Regular14); comp.VerifyDiagnostics( [ ..expected, // (100,32): error CS9327: Feature 'unions' is not available in C# 14.0. Please use language version 15.0 or greater. // return u switch { S1 { Value: int } => 1, S1 { Value: string } => 2, S1 { Value: null } => 3, not S1 => -100 }; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion14, "Value").WithArguments("unions", "15.0").WithLocation(100, 32), // (100,56): error CS9327: Feature 'unions' is not available in C# 14.0. Please use language version 15.0 or greater. // return u switch { S1 { Value: int } => 1, S1 { Value: string } => 2, S1 { Value: null } => 3, not S1 => -100 }; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion14, "Value").WithArguments("unions", "15.0").WithLocation(100, 56), // (100,83): error CS9327: Feature 'unions' is not available in C# 14.0. Please use language version 15.0 or greater. // return u switch { S1 { Value: int } => 1, S1 { Value: string } => 2, S1 { Value: null } => 3, not S1 => -100 }; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion14, "Value").WithArguments("unions", "15.0").WithLocation(100, 83), // (200,32): error CS9327: Feature 'unions' is not available in C# 14.0. Please use language version 15.0 or greater. // return u switch { S1 { Value: int } => 1, S1 { Value: null } => 3, S1 { Value: string } => 2, not S1 => -100 }; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion14, "Value").WithArguments("unions", "15.0").WithLocation(200, 32), // (200,56): error CS9327: Feature 'unions' is not available in C# 14.0. Please use language version 15.0 or greater. // return u switch { S1 { Value: int } => 1, S1 { Value: null } => 3, S1 { Value: string } => 2, not S1 => -100 }; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion14, "Value").WithArguments("unions", "15.0").WithLocation(200, 56), // (200,81): error CS9327: Feature 'unions' is not available in C# 14.0. Please use language version 15.0 or greater. // return u switch { S1 { Value: int } => 1, S1 { Value: null } => 3, S1 { Value: string } => 2, not S1 => -100 }; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion14, "Value").WithArguments("unions", "15.0").WithLocation(200, 81), // (300,32): error CS9327: Feature 'unions' is not available in C# 14.0. Please use language version 15.0 or greater. // return u switch { S1 { Value: null } => 3, S1 { Value: int } => 1, S1 { Value: string } => 2, not S1 => -100 }; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion14, "Value").WithArguments("unions", "15.0").WithLocation(300, 32), // (300,57): error CS9327: Feature 'unions' is not available in C# 14.0. Please use language version 15.0 or greater. // return u switch { S1 { Value: null } => 3, S1 { Value: int } => 1, S1 { Value: string } => 2, not S1 => -100 }; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion14, "Value").WithArguments("unions", "15.0").WithLocation(300, 57), // (300,81): error CS9327: Feature 'unions' is not available in C# 14.0. Please use language version 15.0 or greater. // return u switch { S1 { Value: null } => 3, S1 { Value: int } => 1, S1 { Value: string } => 2, not S1 => -100 }; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion14, "Value").WithArguments("unions", "15.0").WithLocation(300, 81), // (400,32): error CS9327: Feature 'unions' is not available in C# 14.0. Please use language version 15.0 or greater. // return u switch { S1 { Value: int } => 1, S1 { Value: string } => 2, not S1 => -100 }; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion14, "Value").WithArguments("unions", "15.0").WithLocation(400, 32), // (400,56): error CS9327: Feature 'unions' is not available in C# 14.0. Please use language version 15.0 or greater. // return u switch { S1 { Value: int } => 1, S1 { Value: string } => 2, not S1 => -100 }; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion14, "Value").WithArguments("unions", "15.0").WithLocation(400, 56), // (500,32): error CS9327: Feature 'unions' is not available in C# 14.0. Please use language version 15.0 or greater. // return u switch { S1 { Value: int } => 1, S1 { Value: string } => 2, not S1 => -100 }; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion14, "Value").WithArguments("unions", "15.0").WithLocation(500, 32), // (500,56): error CS9327: Feature 'unions' is not available in C# 14.0. Please use language version 15.0 or greater. // return u switch { S1 { Value: int } => 1, S1 { Value: string } => 2, not S1 => -100 }; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion14, "Value").WithArguments("unions", "15.0").WithLocation(500, 56), // (600,32): error CS9327: Feature 'unions' is not available in C# 14.0. Please use language version 15.0 or greater. // return u switch { S1 { Value: int } => 1, S1 { Value: null } => 3, not S1 => -100 }; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion14, "Value").WithArguments("unions", "15.0").WithLocation(600, 32), // (600,56): error CS9327: Feature 'unions' is not available in C# 14.0. Please use language version 15.0 or greater. // return u switch { S1 { Value: int } => 1, S1 { Value: null } => 3, not S1 => -100 }; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion14, "Value").WithArguments("unions", "15.0").WithLocation(600, 56), // (700,32): error CS9327: Feature 'unions' is not available in C# 14.0. Please use language version 15.0 or greater. // return u switch { S1 { Value: null } => 3, S1 { Value: int } => 1, not S1 => -100 }; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion14, "Value").WithArguments("unions", "15.0").WithLocation(700, 32), // (700,57): error CS9327: Feature 'unions' is not available in C# 14.0. Please use language version 15.0 or greater. // return u switch { S1 { Value: null } => 3, S1 { Value: int } => 1, not S1 => -100 }; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion14, "Value").WithArguments("unions", "15.0").WithLocation(700, 57), // (800,32): error CS9327: Feature 'unions' is not available in C# 14.0. Please use language version 15.0 or greater. // return u switch { S1 { Value: int } => 1, not S1 => -100 }; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion14, "Value").WithArguments("unions", "15.0").WithLocation(800, 32), // (900,32): error CS9327: Feature 'unions' is not available in C# 14.0. Please use language version 15.0 or greater. // return u switch { S1 { Value: not int } => 1, not S1 => -100 }; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion14, "Value").WithArguments("unions", "15.0").WithLocation(900, 32), // (1000,33): error CS9327: Feature 'unions' is not available in C# 14.0. Please use language version 15.0 or greater. // return u switch { S1 { Value: null } => 3, S1 { Value: not int } => 1, not S1 => -100 }; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion14, "Value").WithArguments("unions", "15.0").WithLocation(1000, 33), // (1000,58): error CS9327: Feature 'unions' is not available in C# 14.0. Please use language version 15.0 or greater. // return u switch { S1 { Value: null } => 3, S1 { Value: not int } => 1, not S1 => -100 }; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion14, "Value").WithArguments("unions", "15.0").WithLocation(1000, 58), // (1100,32): error CS9327: Feature 'unions' is not available in C# 14.0. Please use language version 15.0 or greater. // return u switch { S1 { Value: not null } => 1, not S1 => -100 }; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion14, "Value").WithArguments("unions", "15.0").WithLocation(1100, 32), // (1150,32): error CS9327: Feature 'unions' is not available in C# 14.0. Please use language version 15.0 or greater. // return u switch { S1 { Value: not null } => 1, not S1 => -100 }; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion14, "Value").WithArguments("unions", "15.0").WithLocation(1150, 32), // (1200,32): error CS9327: Feature 'unions' is not available in C# 14.0. Please use language version 15.0 or greater. // return u switch { S1 { Value: null } => 3, S1 { Value: not null } => 1, not S1 => -100 }; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion14, "Value").WithArguments("unions", "15.0").WithLocation(1200, 32), // (1200,57): error CS9327: Feature 'unions' is not available in C# 14.0. Please use language version 15.0 or greater. // return u switch { S1 { Value: null } => 3, S1 { Value: not null } => 1, not S1 => -100 }; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion14, "Value").WithArguments("unions", "15.0").WithLocation(1200, 57), // (1300,32): error CS9327: Feature 'unions' is not available in C# 14.0. Please use language version 15.0 or greater. // return u switch { S1 { Value: not null } => 3, S1 { Value: null } => 1, not S1 => -100 }; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion14, "Value").WithArguments("unions", "15.0").WithLocation(1300, 32), // (1300,61): error CS9327: Feature 'unions' is not available in C# 14.0. Please use language version 15.0 or greater. // return u switch { S1 { Value: not null } => 3, S1 { Value: null } => 1, not S1 => -100 }; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion14, "Value").WithArguments("unions", "15.0").WithLocation(1300, 61), // (1400,32): error CS9327: Feature 'unions' is not available in C# 14.0. Please use language version 15.0 or greater. // return u switch { S1 { Value: { } } => 1, S1 { Value: null } => 3, not S1 => -100 }; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion14, "Value").WithArguments("unions", "15.0").WithLocation(1400, 32), // (1400,56): error CS9327: Feature 'unions' is not available in C# 14.0. Please use language version 15.0 or greater. // return u switch { S1 { Value: { } } => 1, S1 { Value: null } => 3, not S1 => -100 }; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion14, "Value").WithArguments("unions", "15.0").WithLocation(1400, 56), // (1500,32): error CS9327: Feature 'unions' is not available in C# 14.0. Please use language version 15.0 or greater. // return u switch { S1 { Value: null } => 3, S1 { Value: var x } => 1, not S1 => -100 }; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion14, "Value").WithArguments("unions", "15.0").WithLocation(1500, 32), // (1500,57): error CS9327: Feature 'unions' is not available in C# 14.0. Please use language version 15.0 or greater. // return u switch { S1 { Value: null } => 3, S1 { Value: var x } => 1, not S1 => -100 }; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion14, "Value").WithArguments("unions", "15.0").WithLocation(1500, 57) ]); } [Theory] [CombinatorialData] public void Exhaustiveness_16_Direct_Value_Matching(bool field) { var src = @" [System.Runtime.CompilerServices.Union] struct S1 { private readonly object _value; public S1(int x) { _value = x; } #nullable enable public S1(string? x) { _value = x; } #nullable disable public object Value => _value; } struct S2 { public S2(S1 s1) { S1 = s1; } public S1 S1" + (field ? ";" : " { get; }") + @" } class Program { static int Test1(S2 u) { #line 100 return u switch { { S1.Value: int } => 1, { S1.Value: string } => 2, { S1.Value: null } => 3 }; } static int Test2(S2 u) { #line 200 return u switch { { S1.Value: int } => 1, { S1.Value: null } => 3, { S1.Value: string } => 2 }; } static int Test3(S2 u) { #line 300 return u switch { { S1.Value: null } => 3, { S1.Value: int } => 1, { S1.Value: string } => 2 }; } static int Test4(S2 u) { #line 400 return u switch { { S1.Value: int } => 1, { S1.Value: string } => 2 }; } static int Test5(S2 u) { #nullable enable #line 500 return u switch { { S1.Value: int } => 1, { S1.Value: string } => 2 }; #nullable disable } static int Test6(S2 u) { #line 600 return u switch { { S1.Value: int } => 1, { S1.Value: null } => 3 }; } static int Test7(S2 u) { #line 700 return u switch { { S1.Value: null } => 3, { S1.Value: int } => 1 }; } static int Test8(S2 u) { #line 800 return u switch { { S1.Value: int } => 1 }; } static int Test9(S2 u) { #line 900 return u switch { { S1.Value: not int } => 1 }; } static int Test10(S2 u) { #line 1000 return u switch { { S1.Value: null } => 3, { S1.Value: not int } => 1 }; } static int Test11(S2 u) { #line 1100 return u switch { { S1.Value: not null } => 1 }; } static int Test11_5(S2 u) { #nullable enable #line 1150 return u switch { { S1.Value: not null } => 1 }; #nullable disable } static int Test12(S2 u) { #line 1200 return u switch { { S1.Value: null } => 3, { S1.Value: not null } => 1 }; } static int Test13(S2 u) { #line 1300 return u switch { { S1.Value: not null } => 3, { S1.Value: null } => 1 }; } static int Test14(S2 u) { #line 1400 return u switch { { S1.Value: { } } => 1, { S1.Value: null } => 3 }; } static int Test15(S2 u) { #line 1500 return u switch { { S1.Value: null } => 3, { S1.Value: var x } => 1 }; } } "; var comp = CreateCompilation([src, UnionAttributeSource]); var expected = new[] { // (500,18): warning CS8655: The switch expression does not handle some null inputs (it is not exhaustive). For example, the pattern '{ S1: null }' is not covered. // return u switch { { S1.Value: int } => 1, { S1.Value: string } => 2 }; Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustiveForNull, "switch").WithArguments("{ S1: null }").WithLocation(500, 18), // (600,18): warning CS8509: The switch expression does not handle all possible values of its input type (it is not exhaustive). For example, the pattern '{ S1: string }' is not covered. // return u switch { { S1.Value: int } => 1, { S1.Value: null } => 3 }; Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustive, "switch").WithArguments("{ S1: string }").WithLocation(600, 18), // (700,18): warning CS8509: The switch expression does not handle all possible values of its input type (it is not exhaustive). For example, the pattern '{ S1: string }' is not covered. // return u switch { { S1.Value: null } => 3, { S1.Value: int } => 1 }; Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustive, "switch").WithArguments("{ S1: string }").WithLocation(700, 18), // (800,18): warning CS8509: The switch expression does not handle all possible values of its input type (it is not exhaustive). For example, the pattern '{ S1: string }' is not covered. // return u switch { { S1.Value: int } => 1 }; Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustive, "switch").WithArguments("{ S1: string }").WithLocation(800, 18), // (900,18): warning CS8509: The switch expression does not handle all possible values of its input type (it is not exhaustive). For example, the pattern '{ S1: int }' is not covered. // return u switch { { S1.Value: not int } => 1 }; Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustive, "switch").WithArguments("{ S1: int }").WithLocation(900, 18), // (1000,18): warning CS8509: The switch expression does not handle all possible values of its input type (it is not exhaustive). For example, the pattern '{ S1: int }' is not covered. // return u switch { { S1.Value: null } => 3, { S1.Value: not int } => 1 }; Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustive, "switch").WithArguments("{ S1: int }").WithLocation(1000, 18), // (1150,18): warning CS8655: The switch expression does not handle some null inputs (it is not exhaustive). For example, the pattern '{ S1: null }' is not covered. // return u switch { { S1.Value: not null } => 1 }; Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustiveForNull, "switch").WithArguments("{ S1: null }").WithLocation(1150, 18), }; CompileAndVerify(comp).VerifyDiagnostics(expected); comp = CreateCompilation([src, UnionAttributeSource], parseOptions: TestOptions.Regular15); CompileAndVerify(comp).VerifyDiagnostics(expected); comp = CreateCompilation([src, UnionAttributeSource], parseOptions: TestOptions.Regular14); comp.VerifyDiagnostics( [ ..expected, // (100,32): error CS9327: Feature 'unions' is not available in C# 14.0. Please use language version 15.0 or greater. // return u switch { { S1.Value: int } => 1, { S1.Value: string } => 2, { S1.Value: null } => 3 }; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion14, "Value").WithArguments("unions", "15.0").WithLocation(100, 32), // (100,56): error CS9327: Feature 'unions' is not available in C# 14.0. Please use language version 15.0 or greater. // return u switch { { S1.Value: int } => 1, { S1.Value: string } => 2, { S1.Value: null } => 3 }; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion14, "Value").WithArguments("unions", "15.0").WithLocation(100, 56), // (100,83): error CS9327: Feature 'unions' is not available in C# 14.0. Please use language version 15.0 or greater. // return u switch { { S1.Value: int } => 1, { S1.Value: string } => 2, { S1.Value: null } => 3 }; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion14, "Value").WithArguments("unions", "15.0").WithLocation(100, 83), // (200,32): error CS9327: Feature 'unions' is not available in C# 14.0. Please use language version 15.0 or greater. // return u switch { { S1.Value: int } => 1, { S1.Value: null } => 3, { S1.Value: string } => 2 }; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion14, "Value").WithArguments("unions", "15.0").WithLocation(200, 32), // (200,56): error CS9327: Feature 'unions' is not available in C# 14.0. Please use language version 15.0 or greater. // return u switch { { S1.Value: int } => 1, { S1.Value: null } => 3, { S1.Value: string } => 2 }; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion14, "Value").WithArguments("unions", "15.0").WithLocation(200, 56), // (200,81): error CS9327: Feature 'unions' is not available in C# 14.0. Please use language version 15.0 or greater. // return u switch { { S1.Value: int } => 1, { S1.Value: null } => 3, { S1.Value: string } => 2 }; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion14, "Value").WithArguments("unions", "15.0").WithLocation(200, 81), // (300,32): error CS9327: Feature 'unions' is not available in C# 14.0. Please use language version 15.0 or greater. // return u switch { { S1.Value: null } => 3, { S1.Value: int } => 1, { S1.Value: string } => 2 }; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion14, "Value").WithArguments("unions", "15.0").WithLocation(300, 32), // (300,57): error CS9327: Feature 'unions' is not available in C# 14.0. Please use language version 15.0 or greater. // return u switch { { S1.Value: null } => 3, { S1.Value: int } => 1, { S1.Value: string } => 2 }; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion14, "Value").WithArguments("unions", "15.0").WithLocation(300, 57), // (300,81): error CS9327: Feature 'unions' is not available in C# 14.0. Please use language version 15.0 or greater. // return u switch { { S1.Value: null } => 3, { S1.Value: int } => 1, { S1.Value: string } => 2 }; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion14, "Value").WithArguments("unions", "15.0").WithLocation(300, 81), // (400,32): error CS9327: Feature 'unions' is not available in C# 14.0. Please use language version 15.0 or greater. // return u switch { { S1.Value: int } => 1, { S1.Value: string } => 2 }; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion14, "Value").WithArguments("unions", "15.0").WithLocation(400, 32), // (400,56): error CS9327: Feature 'unions' is not available in C# 14.0. Please use language version 15.0 or greater. // return u switch { { S1.Value: int } => 1, { S1.Value: string } => 2 }; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion14, "Value").WithArguments("unions", "15.0").WithLocation(400, 56), // (500,32): error CS9327: Feature 'unions' is not available in C# 14.0. Please use language version 15.0 or greater. // return u switch { { S1.Value: int } => 1, { S1.Value: string } => 2 }; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion14, "Value").WithArguments("unions", "15.0").WithLocation(500, 32), // (500,56): error CS9327: Feature 'unions' is not available in C# 14.0. Please use language version 15.0 or greater. // return u switch { { S1.Value: int } => 1, { S1.Value: string } => 2 }; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion14, "Value").WithArguments("unions", "15.0").WithLocation(500, 56), // (600,32): error CS9327: Feature 'unions' is not available in C# 14.0. Please use language version 15.0 or greater. // return u switch { { S1.Value: int } => 1, { S1.Value: null } => 3 }; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion14, "Value").WithArguments("unions", "15.0").WithLocation(600, 32), // (600,56): error CS9327: Feature 'unions' is not available in C# 14.0. Please use language version 15.0 or greater. // return u switch { { S1.Value: int } => 1, { S1.Value: null } => 3 }; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion14, "Value").WithArguments("unions", "15.0").WithLocation(600, 56), // (700,32): error CS9327: Feature 'unions' is not available in C# 14.0. Please use language version 15.0 or greater. // return u switch { { S1.Value: null } => 3, { S1.Value: int } => 1 }; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion14, "Value").WithArguments("unions", "15.0").WithLocation(700, 32), // (700,57): error CS9327: Feature 'unions' is not available in C# 14.0. Please use language version 15.0 or greater. // return u switch { { S1.Value: null } => 3, { S1.Value: int } => 1 }; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion14, "Value").WithArguments("unions", "15.0").WithLocation(700, 57), // (800,32): error CS9327: Feature 'unions' is not available in C# 14.0. Please use language version 15.0 or greater. // return u switch { { S1.Value: int } => 1 }; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion14, "Value").WithArguments("unions", "15.0").WithLocation(800, 32), // (900,32): error CS9327: Feature 'unions' is not available in C# 14.0. Please use language version 15.0 or greater. // return u switch { { S1.Value: not int } => 1 }; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion14, "Value").WithArguments("unions", "15.0").WithLocation(900, 32), // (1000,32): error CS9327: Feature 'unions' is not available in C# 14.0. Please use language version 15.0 or greater. // return u switch { { S1.Value: null } => 3, { S1.Value: not int } => 1 }; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion14, "Value").WithArguments("unions", "15.0").WithLocation(1000, 32), // (1000,57): error CS9327: Feature 'unions' is not available in C# 14.0. Please use language version 15.0 or greater. // return u switch { { S1.Value: null } => 3, { S1.Value: not int } => 1 }; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion14, "Value").WithArguments("unions", "15.0").WithLocation(1000, 57), // (1100,32): error CS9327: Feature 'unions' is not available in C# 14.0. Please use language version 15.0 or greater. // return u switch { { S1.Value: not null } => 1 }; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion14, "Value").WithArguments("unions", "15.0").WithLocation(1100, 32), // (1150,32): error CS9327: Feature 'unions' is not available in C# 14.0. Please use language version 15.0 or greater. // return u switch { { S1.Value: not null } => 1 }; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion14, "Value").WithArguments("unions", "15.0").WithLocation(1150, 32), // (1200,32): error CS9327: Feature 'unions' is not available in C# 14.0. Please use language version 15.0 or greater. // return u switch { { S1.Value: null } => 3, { S1.Value: not null } => 1 }; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion14, "Value").WithArguments("unions", "15.0").WithLocation(1200, 32), // (1200,57): error CS9327: Feature 'unions' is not available in C# 14.0. Please use language version 15.0 or greater. // return u switch { { S1.Value: null } => 3, { S1.Value: not null } => 1 }; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion14, "Value").WithArguments("unions", "15.0").WithLocation(1200, 57), // (1300,32): error CS9327: Feature 'unions' is not available in C# 14.0. Please use language version 15.0 or greater. // return u switch { { S1.Value: not null } => 3, { S1.Value: null } => 1 }; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion14, "Value").WithArguments("unions", "15.0").WithLocation(1300, 32), // (1300,61): error CS9327: Feature 'unions' is not available in C# 14.0. Please use language version 15.0 or greater. // return u switch { { S1.Value: not null } => 3, { S1.Value: null } => 1 }; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion14, "Value").WithArguments("unions", "15.0").WithLocation(1300, 61), // (1400,32): error CS9327: Feature 'unions' is not available in C# 14.0. Please use language version 15.0 or greater. // return u switch { { S1.Value: { } } => 1, { S1.Value: null } => 3 }; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion14, "Value").WithArguments("unions", "15.0").WithLocation(1400, 32), // (1400,56): error CS9327: Feature 'unions' is not available in C# 14.0. Please use language version 15.0 or greater. // return u switch { { S1.Value: { } } => 1, { S1.Value: null } => 3 }; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion14, "Value").WithArguments("unions", "15.0").WithLocation(1400, 56), // (1500,32): error CS9327: Feature 'unions' is not available in C# 14.0. Please use language version 15.0 or greater. // return u switch { { S1.Value: null } => 3, { S1.Value: var x } => 1 }; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion14, "Value").WithArguments("unions", "15.0").WithLocation(1500, 32), // (1500,57): error CS9327: Feature 'unions' is not available in C# 14.0. Please use language version 15.0 or greater. // return u switch { { S1.Value: null } => 3, { S1.Value: var x } => 1 }; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion14, "Value").WithArguments("unions", "15.0").WithLocation(1500, 57) ]); } [Theory] [CombinatorialData] public void Exhaustiveness_17_Direct_Value_Matching(bool field) { var src = @" [System.Runtime.CompilerServices.Union] struct S1 { private readonly object _value; public S1(int x) { _value = x; } #nullable enable public S1(string? x) { _value = x; } #nullable disable public object Value => _value; } struct S2 { public S2(S1? s1) { S1 = s1; } public S1? S1" + (field ? ";" : " { get; }") + @" } class Program { static int Test1(S2 u) { #line 100 return u switch { { S1.Value: int } => 1, { S1.Value: string } => 2, { S1.Value: null } => 3 }; } static int Test2(S2 u) { #line 200 return u switch { { S1.Value: int } => 1, { S1.Value: null } => 3, { S1.Value: string } => 2 }; } static int Test3(S2 u) { #line 300 return u switch { { S1.Value: null } => 3, { S1.Value: int } => 1, { S1.Value: string } => 2 }; } static int Test4(S2 u) { #line 400 return u switch { { S1.Value: int } => 1, { S1.Value: string } => 2 }; } static int Test5(S2 u) { #nullable enable #line 500 return u switch { { S1.Value: int } => 1, { S1.Value: string } => 2 }; #nullable disable } static int Test6(S2 u) { #line 600 return u switch { { S1.Value: int } => 1, { S1.Value: null } => 3 }; } static int Test7(S2 u) { #line 700 return u switch { { S1.Value: null } => 3, { S1.Value: int } => 1 }; } static int Test8(S2 u) { #line 800 return u switch { { S1.Value: int } => 1 }; } static int Test9(S2 u) { #line 900 return u switch { { S1.Value: not int } => 1 }; } static int Test10(S2 u) { #line 1000 return u switch { { S1.Value: null } => 3, { S1.Value: not int } => 1 }; } static int Test11(S2 u) { #line 1100 return u switch { { S1.Value: not null } => 1 }; } static int Test11_5(S2 u) { #nullable enable #line 1150 return u switch { { S1.Value: not null } => 1 }; #nullable disable } static int Test12(S2 u) { #line 1200 return u switch { { S1.Value: null } => 3, { S1.Value: not null } => 1 }; } static int Test13(S2 u) { #line 1300 return u switch { { S1.Value: not null } => 3, { S1.Value: null } => 1 }; } static int Test14(S2 u) { #line 1400 return u switch { { S1.Value: { } } => 1, { S1.Value: null } => 3 }; } static int Test15(S2 u) { #line 1500 return u switch { { S1.Value: null } => 3, { S1.Value: var x } => 1 }; } static int Test16(S2 u) { #nullable enable #line 1600 return u switch { { S1.Value: int } => 1, { S1.Value: string } => 2, { S1.Value: null } => 3 }; #nullable disable } static int Test17(S2 u) { #nullable enable #line 1700 return u switch { { S1.Value: int } => 1, { S1.Value: null } => 3, { S1.Value: string } => 2 }; #nullable disable } } "; var comp = CreateCompilation([src, UnionAttributeSource]); var expected = new[] { // (500,18): warning CS8655: The switch expression does not handle some null inputs (it is not exhaustive). For example, the pattern '{ S1: null }' is not covered. // return u switch { { S1.Value: int } => 1, { S1.Value: string } => 2 }; Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustiveForNull, "switch").WithArguments("{ S1: null }").WithLocation(500, 18), // (600,18): warning CS8509: The switch expression does not handle all possible values of its input type (it is not exhaustive). For example, the pattern '{ S1: string }' is not covered. // return u switch { { S1.Value: int } => 1, { S1.Value: null } => 3 }; Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustive, "switch").WithArguments("{ S1: string }").WithLocation(600, 18), // (700,18): warning CS8509: The switch expression does not handle all possible values of its input type (it is not exhaustive). For example, the pattern '{ S1: string }' is not covered. // return u switch { { S1.Value: null } => 3, { S1.Value: int } => 1 }; Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustive, "switch").WithArguments("{ S1: string }").WithLocation(700, 18), // (800,18): warning CS8509: The switch expression does not handle all possible values of its input type (it is not exhaustive). For example, the pattern '{ S1: string }' is not covered. // return u switch { { S1.Value: int } => 1 }; Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustive, "switch").WithArguments("{ S1: string }").WithLocation(800, 18), // (900,18): warning CS8509: The switch expression does not handle all possible values of its input type (it is not exhaustive). For example, the pattern '{ S1: int }' is not covered. // return u switch { { S1.Value: not int } => 1 }; Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustive, "switch").WithArguments("{ S1: int }").WithLocation(900, 18), // (1000,18): warning CS8509: The switch expression does not handle all possible values of its input type (it is not exhaustive). For example, the pattern '{ S1: int }' is not covered. // return u switch { { S1.Value: null } => 3, { S1.Value: not int } => 1 }; Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustive, "switch").WithArguments("{ S1: int }").WithLocation(1000, 18), // (1150,18): warning CS8655: The switch expression does not handle some null inputs (it is not exhaustive). For example, the pattern '{ S1: null }' is not covered. // return u switch { { S1.Value: not null } => 1 }; Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustiveForNull, "switch").WithArguments("{ S1: null }").WithLocation(1150, 18), // (1600,18): warning CS8655: The switch expression does not handle some null inputs (it is not exhaustive). For example, the pattern '{ S1: null }' is not covered. // return u switch { { S1.Value: int } => 1, { S1.Value: string } => 2, { S1.Value: null } => 3 }; Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustiveForNull, "switch").WithArguments("{ S1: null }").WithLocation(1600, 18), // (1700,18): warning CS8655: The switch expression does not handle some null inputs (it is not exhaustive). For example, the pattern '{ S1: null }' is not covered. // return u switch { { S1.Value: int } => 1, { S1.Value: null } => 3, { S1.Value: string } => 2 }; Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustiveForNull, "switch").WithArguments("{ S1: null }").WithLocation(1700, 18), }; CompileAndVerify(comp).VerifyDiagnostics(expected); comp = CreateCompilation([src, UnionAttributeSource], parseOptions: TestOptions.Regular15); CompileAndVerify(comp).VerifyDiagnostics(expected); comp = CreateCompilation([src, UnionAttributeSource], parseOptions: TestOptions.Regular14); comp.VerifyDiagnostics( [ ..expected, // (100,32): error CS9327: Feature 'unions' is not available in C# 14.0. Please use language version 15.0 or greater. // return u switch { { S1.Value: int } => 1, { S1.Value: string } => 2, { S1.Value: null } => 3 }; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion14, "Value").WithArguments("unions", "15.0").WithLocation(100, 32), // (100,56): error CS9327: Feature 'unions' is not available in C# 14.0. Please use language version 15.0 or greater. // return u switch { { S1.Value: int } => 1, { S1.Value: string } => 2, { S1.Value: null } => 3 }; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion14, "Value").WithArguments("unions", "15.0").WithLocation(100, 56), // (100,83): error CS9327: Feature 'unions' is not available in C# 14.0. Please use language version 15.0 or greater. // return u switch { { S1.Value: int } => 1, { S1.Value: string } => 2, { S1.Value: null } => 3 }; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion14, "Value").WithArguments("unions", "15.0").WithLocation(100, 83), // (200,32): error CS9327: Feature 'unions' is not available in C# 14.0. Please use language version 15.0 or greater. // return u switch { { S1.Value: int } => 1, { S1.Value: null } => 3, { S1.Value: string } => 2 }; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion14, "Value").WithArguments("unions", "15.0").WithLocation(200, 32), // (200,56): error CS9327: Feature 'unions' is not available in C# 14.0. Please use language version 15.0 or greater. // return u switch { { S1.Value: int } => 1, { S1.Value: null } => 3, { S1.Value: string } => 2 }; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion14, "Value").WithArguments("unions", "15.0").WithLocation(200, 56), // (200,81): error CS9327: Feature 'unions' is not available in C# 14.0. Please use language version 15.0 or greater. // return u switch { { S1.Value: int } => 1, { S1.Value: null } => 3, { S1.Value: string } => 2 }; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion14, "Value").WithArguments("unions", "15.0").WithLocation(200, 81), // (300,32): error CS9327: Feature 'unions' is not available in C# 14.0. Please use language version 15.0 or greater. // return u switch { { S1.Value: null } => 3, { S1.Value: int } => 1, { S1.Value: string } => 2 }; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion14, "Value").WithArguments("unions", "15.0").WithLocation(300, 32), // (300,57): error CS9327: Feature 'unions' is not available in C# 14.0. Please use language version 15.0 or greater. // return u switch { { S1.Value: null } => 3, { S1.Value: int } => 1, { S1.Value: string } => 2 }; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion14, "Value").WithArguments("unions", "15.0").WithLocation(300, 57), // (300,81): error CS9327: Feature 'unions' is not available in C# 14.0. Please use language version 15.0 or greater. // return u switch { { S1.Value: null } => 3, { S1.Value: int } => 1, { S1.Value: string } => 2 }; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion14, "Value").WithArguments("unions", "15.0").WithLocation(300, 81), // (400,32): error CS9327: Feature 'unions' is not available in C# 14.0. Please use language version 15.0 or greater. // return u switch { { S1.Value: int } => 1, { S1.Value: string } => 2 }; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion14, "Value").WithArguments("unions", "15.0").WithLocation(400, 32), // (400,56): error CS9327: Feature 'unions' is not available in C# 14.0. Please use language version 15.0 or greater. // return u switch { { S1.Value: int } => 1, { S1.Value: string } => 2 }; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion14, "Value").WithArguments("unions", "15.0").WithLocation(400, 56), // (500,32): error CS9327: Feature 'unions' is not available in C# 14.0. Please use language version 15.0 or greater. // return u switch { { S1.Value: int } => 1, { S1.Value: string } => 2 }; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion14, "Value").WithArguments("unions", "15.0").WithLocation(500, 32), // (500,56): error CS9327: Feature 'unions' is not available in C# 14.0. Please use language version 15.0 or greater. // return u switch { { S1.Value: int } => 1, { S1.Value: string } => 2 }; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion14, "Value").WithArguments("unions", "15.0").WithLocation(500, 56), // (600,32): error CS9327: Feature 'unions' is not available in C# 14.0. Please use language version 15.0 or greater. // return u switch { { S1.Value: int } => 1, { S1.Value: null } => 3 }; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion14, "Value").WithArguments("unions", "15.0").WithLocation(600, 32), // (600,56): error CS9327: Feature 'unions' is not available in C# 14.0. Please use language version 15.0 or greater. // return u switch { { S1.Value: int } => 1, { S1.Value: null } => 3 }; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion14, "Value").WithArguments("unions", "15.0").WithLocation(600, 56), // (700,32): error CS9327: Feature 'unions' is not available in C# 14.0. Please use language version 15.0 or greater. // return u switch { { S1.Value: null } => 3, { S1.Value: int } => 1 }; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion14, "Value").WithArguments("unions", "15.0").WithLocation(700, 32), // (700,57): error CS9327: Feature 'unions' is not available in C# 14.0. Please use language version 15.0 or greater. // return u switch { { S1.Value: null } => 3, { S1.Value: int } => 1 }; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion14, "Value").WithArguments("unions", "15.0").WithLocation(700, 57), // (800,32): error CS9327: Feature 'unions' is not available in C# 14.0. Please use language version 15.0 or greater. // return u switch { { S1.Value: int } => 1 }; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion14, "Value").WithArguments("unions", "15.0").WithLocation(800, 32), // (900,32): error CS9327: Feature 'unions' is not available in C# 14.0. Please use language version 15.0 or greater. // return u switch { { S1.Value: not int } => 1 }; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion14, "Value").WithArguments("unions", "15.0").WithLocation(900, 32), // (1000,32): error CS9327: Feature 'unions' is not available in C# 14.0. Please use language version 15.0 or greater. // return u switch { { S1.Value: null } => 3, { S1.Value: not int } => 1 }; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion14, "Value").WithArguments("unions", "15.0").WithLocation(1000, 32), // (1000,57): error CS9327: Feature 'unions' is not available in C# 14.0. Please use language version 15.0 or greater. // return u switch { { S1.Value: null } => 3, { S1.Value: not int } => 1 }; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion14, "Value").WithArguments("unions", "15.0").WithLocation(1000, 57), // (1100,32): error CS9327: Feature 'unions' is not available in C# 14.0. Please use language version 15.0 or greater. // return u switch { { S1.Value: not null } => 1 }; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion14, "Value").WithArguments("unions", "15.0").WithLocation(1100, 32), // (1150,32): error CS9327: Feature 'unions' is not available in C# 14.0. Please use language version 15.0 or greater. // return u switch { { S1.Value: not null } => 1 }; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion14, "Value").WithArguments("unions", "15.0").WithLocation(1150, 32), // (1200,32): error CS9327: Feature 'unions' is not available in C# 14.0. Please use language version 15.0 or greater. // return u switch { { S1.Value: null } => 3, { S1.Value: not null } => 1 }; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion14, "Value").WithArguments("unions", "15.0").WithLocation(1200, 32), // (1200,57): error CS9327: Feature 'unions' is not available in C# 14.0. Please use language version 15.0 or greater. // return u switch { { S1.Value: null } => 3, { S1.Value: not null } => 1 }; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion14, "Value").WithArguments("unions", "15.0").WithLocation(1200, 57), // (1300,32): error CS9327: Feature 'unions' is not available in C# 14.0. Please use language version 15.0 or greater. // return u switch { { S1.Value: not null } => 3, { S1.Value: null } => 1 }; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion14, "Value").WithArguments("unions", "15.0").WithLocation(1300, 32), // (1300,61): error CS9327: Feature 'unions' is not available in C# 14.0. Please use language version 15.0 or greater. // return u switch { { S1.Value: not null } => 3, { S1.Value: null } => 1 }; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion14, "Value").WithArguments("unions", "15.0").WithLocation(1300, 61), // (1400,32): error CS9327: Feature 'unions' is not available in C# 14.0. Please use language version 15.0 or greater. // return u switch { { S1.Value: { } } => 1, { S1.Value: null } => 3 }; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion14, "Value").WithArguments("unions", "15.0").WithLocation(1400, 32), // (1400,56): error CS9327: Feature 'unions' is not available in C# 14.0. Please use language version 15.0 or greater. // return u switch { { S1.Value: { } } => 1, { S1.Value: null } => 3 }; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion14, "Value").WithArguments("unions", "15.0").WithLocation(1400, 56), // (1500,32): error CS9327: Feature 'unions' is not available in C# 14.0. Please use language version 15.0 or greater. // return u switch { { S1.Value: null } => 3, { S1.Value: var x } => 1 }; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion14, "Value").WithArguments("unions", "15.0").WithLocation(1500, 32), // (1500,57): error CS9327: Feature 'unions' is not available in C# 14.0. Please use language version 15.0 or greater. // return u switch { { S1.Value: null } => 3, { S1.Value: var x } => 1 }; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion14, "Value").WithArguments("unions", "15.0").WithLocation(1500, 57), // (1600,32): error CS9327: Feature 'unions' is not available in C# 14.0. Please use language version 15.0 or greater. // return u switch { { S1.Value: int } => 1, { S1.Value: string } => 2, { S1.Value: null } => 3 }; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion14, "Value").WithArguments("unions", "15.0").WithLocation(1600, 32), // (1600,56): error CS9327: Feature 'unions' is not available in C# 14.0. Please use language version 15.0 or greater. // return u switch { { S1.Value: int } => 1, { S1.Value: string } => 2, { S1.Value: null } => 3 }; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion14, "Value").WithArguments("unions", "15.0").WithLocation(1600, 56), // (1600,83): error CS9327: Feature 'unions' is not available in C# 14.0. Please use language version 15.0 or greater. // return u switch { { S1.Value: int } => 1, { S1.Value: string } => 2, { S1.Value: null } => 3 }; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion14, "Value").WithArguments("unions", "15.0").WithLocation(1600, 83), // (1700,32): error CS9327: Feature 'unions' is not available in C# 14.0. Please use language version 15.0 or greater. // return u switch { { S1.Value: int } => 1, { S1.Value: null } => 3, { S1.Value: string } => 2 }; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion14, "Value").WithArguments("unions", "15.0").WithLocation(1700, 32), // (1700,56): error CS9327: Feature 'unions' is not available in C# 14.0. Please use language version 15.0 or greater. // return u switch { { S1.Value: int } => 1, { S1.Value: null } => 3, { S1.Value: string } => 2 }; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion14, "Value").WithArguments("unions", "15.0").WithLocation(1700, 56), // (1700,81): error CS9327: Feature 'unions' is not available in C# 14.0. Please use language version 15.0 or greater. // return u switch { { S1.Value: int } => 1, { S1.Value: null } => 3, { S1.Value: string } => 2 }; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion14, "Value").WithArguments("unions", "15.0").WithLocation(1700, 81) ]); } [Fact] [WorkItem("https://github.com/dotnet/roslyn/issues/83666")] public void Exhaustiveness_18() { var src = @" #nullable enable public union IntUnion(int); public static class Repro { public static object Deconstruct(IntUnion value) => value switch { int i => i, }; } "; var comp = CreateCompilation([src, UnionAttributeSource, IUnionSource]); CompileAndVerify(comp).VerifyDiagnostics(); } [Fact] public void EmptyUnion_01() { // #nullable enable // [System.Runtime.CompilerServices.Union] // struct S1 // { // public object Value => null!; // } var ilSource = @" .class public sequential ansi sealed beforefieldinit S1 extends [mscorlib]System.ValueType { .custom instance void [mscorlib]System.Runtime.CompilerServices.NullableContextAttribute::.ctor(uint8) = ( 01 00 01 00 00 ) .custom instance void [mscorlib]System.Runtime.CompilerServices.NullableAttribute::.ctor(uint8) = ( 01 00 00 00 00 ) .custom instance void System.Runtime.CompilerServices.UnionAttribute::.ctor() = ( 01 00 00 00 ) .pack 0 .size 1 .method public hidebysig specialname instance object get_Value () cil managed { IL_0000: ldnull IL_0001: ret } .property instance object Value() { .get instance object S1::get_Value() } } .class public auto ansi beforefieldinit System.Runtime.CompilerServices.UnionAttribute extends [mscorlib]System.Attribute { .method public hidebysig specialname rtspecialname instance void .ctor () cil managed { .maxstack 8 IL_0000: ldarg.0 IL_0001: call instance void [mscorlib]System.Attribute::.ctor() IL_0006: nop IL_0007: ret } } "; var src = @" #nullable enable class Program { static int Test1(S1 u) { #line 100 return u switch { int => 1, null => 3 }; } static int Test2(S1 u) { #line 200 return u switch { null => 1 }; } static int Test3(S1 u) { #line 300 return u switch { null => 3, object => 1 }; } static int Test4(S1 u) { #line 400 return u switch { int => 1 }; } static int Test5(S1 u) { #line 500 return u switch { object => 1 }; } static int Test6(S1 u) { #line 600 return u switch { not object => 1 }; } static int Test7(S1 u) { #line 700 return u switch { null => 3, not object => 1 }; } static int Test8(S1 u) { #line 800 return u switch { object => 1, null => 3 }; } static int Test9(S1 u) { #line 900 return u switch { not null => 1 }; } static int Test10(S1 u) { #line 1000 return u switch { null => 3, not null => 1 }; } static int Test11(S1 u) { #line 1100 return u switch { not null => 3, null => 1 }; } static int Test12(S1 u) { #line 1200 return u switch { { } => 1, null => 3 }; } static int Test13(S1 u) { #line 1300 return u switch { null => 3, var x => 1 }; } } "; var comp = CreateCompilationWithIL([src, UnionAttributeSource], ilSource); comp.VerifyDiagnostics( // (100,27): error CS8121: An expression of type 'S1' cannot be handled by a pattern of type 'int'. // return u switch { int => 1, null => 3 }; Diagnostic(ErrorCode.ERR_PatternWrongType, "int").WithArguments("S1", "int").WithLocation(100, 27), // (200,18): warning CS8509: The switch expression does not handle all possible values of its input type (it is not exhaustive). For example, the pattern 'not null' is not covered. // return u switch { null => 1 }; Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustive, "switch").WithArguments("not null").WithLocation(200, 18), // (400,27): error CS8121: An expression of type 'S1' cannot be handled by a pattern of type 'int'. // return u switch { int => 1 }; Diagnostic(ErrorCode.ERR_PatternWrongType, "int").WithArguments("S1", "int").WithLocation(400, 27), // (600,18): warning CS8509: The switch expression does not handle all possible values of its input type (it is not exhaustive). For example, the pattern '_' is not covered. // return u switch { not object => 1 }; Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustive, "switch").WithArguments("_").WithLocation(600, 18), // (600,27): error CS8510: The pattern is unreachable. It has already been handled by a previous arm of the switch expression or it is impossible to match. // return u switch { not object => 1 }; Diagnostic(ErrorCode.ERR_SwitchArmSubsumed, "not object").WithLocation(600, 27), // (700,18): warning CS8509: The switch expression does not handle all possible values of its input type (it is not exhaustive). For example, the pattern 'not null' is not covered. // return u switch { null => 3, not object => 1 }; Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustive, "switch").WithArguments("not null").WithLocation(700, 18), // (700,39): error CS8510: The pattern is unreachable. It has already been handled by a previous arm of the switch expression or it is impossible to match. // return u switch { null => 3, not object => 1 }; Diagnostic(ErrorCode.ERR_SwitchArmSubsumed, "not object").WithLocation(700, 39), // (800,40): error CS8510: The pattern is unreachable. It has already been handled by a previous arm of the switch expression or it is impossible to match. // return u switch { object => 1, null => 3 }; Diagnostic(ErrorCode.ERR_SwitchArmSubsumed, "null").WithLocation(800, 40), // (900,18): warning CS8655: The switch expression does not handle some null inputs (it is not exhaustive). For example, the pattern 'null' is not covered. // return u switch { not null => 1 }; Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustiveForNull, "switch").WithArguments("null").WithLocation(900, 18), // (1200,37): error CS8510: The pattern is unreachable. It has already been handled by a previous arm of the switch expression or it is impossible to match. // return u switch { { } => 1, null => 3 }; Diagnostic(ErrorCode.ERR_SwitchArmSubsumed, "null").WithLocation(1200, 37) ); } [Fact] public void UnionConversion_01_Implicit() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 { private readonly object _value; public S1(int x) { System.Console.Write(""int {""); System.Console.Write(x); System.Console.Write(""} ""); _value = x; } public S1(string x) { System.Console.Write(""string {""); System.Console.Write(x); System.Console.Write(""} ""); _value = x; } public object Value => _value; } class Program { static void Main() { Test1(); Test2(); Test3(); Test4(); Test5(); } static S1 Test1() { System.Console.Write(""1-""); /*<bind>*/ return 10; /*</bind>*/ } static S1 Test2() { System.Console.Write(""2-""); return default; } static S1 Test3() { System.Console.Write(""3-""); return default(S1); } static S1 Test4() { System.Console.Write(""4-""); return null; } static S1 Test5() { System.Console.Write(""5-""); return ""11""; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var ten = GetSyntax<LiteralExpressionSyntax>(tree, "10"); var symbolInfo = model.GetSymbolInfo(ten); Assert.Equal(CandidateReason.None, symbolInfo.CandidateReason); Assert.Null(symbolInfo.Symbol); Assert.Empty(symbolInfo.CandidateSymbols); var typeInfo = model.GetTypeInfo(ten); Assert.Equal("System.Int32", typeInfo.Type.ToTestDisplayString()); Assert.Equal("S1", typeInfo.ConvertedType.ToTestDisplayString()); Conversion conversion = model.GetConversion(ten); Assert.True(conversion.Exists); Assert.True(conversion.IsValid); Assert.True(conversion.IsImplicit); Assert.False(conversion.IsExplicit); Assert.Equal(ConversionKind.Union, conversion.Kind); Assert.Equal(LookupResultKind.Viable, conversion.ResultKind); Assert.True(conversion.IsUnion); Assert.False(conversion.IsUserDefined); AssertEx.Equal("S1..ctor(System.Int32 x)", conversion.Method.ToTestDisplayString()); AssertEx.Equal("S1..ctor(System.Int32 x)", conversion.MethodSymbol.ToTestDisplayString()); Assert.Null(conversion.BestUserDefinedConversionAnalysis); Assert.Equal(Conversion.NoConversion, conversion.UserDefinedFromConversion); Assert.Equal(Conversion.NoConversion, conversion.UserDefinedToConversion); Assert.NotNull(conversion.BestUnionConversionAnalysis); AssertEx.SequenceEqual(["S1..ctor(System.Int32 x)"], conversion.OriginalUserDefinedOrUnionConversions.ToTestDisplayStrings()); Assert.True(conversion.UnderlyingConversions.IsDefault); Assert.False(conversion.IsArrayIndex); Assert.False(conversion.IsExtensionMethod); CommonConversion commonConversion = conversion.ToCommonConversion(); Assert.True(commonConversion.Exists); Assert.True(commonConversion.IsImplicit); Assert.True(commonConversion.IsUnion); Assert.False(commonConversion.IsUserDefined); AssertEx.Equal("S1..ctor(System.Int32 x)", commonConversion.MethodSymbol.ToTestDisplayString()); VerifyOperationTreeForTest<ReturnStatementSyntax>(comp, """ IReturnOperation (OperationKind.Return, Type: null) (Syntax: 'return 10;') ReturnedValue: IConversionOperation (TryCast: False, Unchecked) (OperatorMethod: S1..ctor(System.Int32 x)) (OperationKind.Conversion, Type: S1, IsImplicit) (Syntax: '10') Conversion: CommonConversion (Exists: True, IsIdentity: False, IsNumeric: False, IsReference: False, IsUserDefined: False, IsUnion: True) (MethodSymbol: S1..ctor(System.Int32 x)) Operand: ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 10) (Syntax: '10') """); var verifier = CompileAndVerify(comp, expectedOutput: "1-int {10} 2-3-4-string {} 5-string {11}").VerifyDiagnostics(); verifier.VerifyIL("Program.Test1", @" { // Code size 18 (0x12) .maxstack 1 IL_0000: ldstr ""1-"" IL_0005: call ""void System.Console.Write(string)"" IL_000a: ldc.i4.s 10 IL_000c: newobj ""S1..ctor(int)"" IL_0011: ret } "); verifier.VerifyIL("Program.Test2", @" { // Code size 20 (0x14) .maxstack 1 .locals init (S1 V_0) IL_0000: ldstr ""2-"" IL_0005: call ""void System.Console.Write(string)"" IL_000a: ldloca.s V_0 IL_000c: initobj ""S1"" IL_0012: ldloc.0 IL_0013: ret } "); verifier.VerifyIL("Program.Test3", @" { // Code size 20 (0x14) .maxstack 1 .locals init (S1 V_0) IL_0000: ldstr ""3-"" IL_0005: call ""void System.Console.Write(string)"" IL_000a: ldloca.s V_0 IL_000c: initobj ""S1"" IL_0012: ldloc.0 IL_0013: ret } "); verifier.VerifyIL("Program.Test4", @" { // Code size 17 (0x11) .maxstack 1 IL_0000: ldstr ""4-"" IL_0005: call ""void System.Console.Write(string)"" IL_000a: ldnull IL_000b: newobj ""S1..ctor(string)"" IL_0010: ret } "); verifier.VerifyIL("Program.Test5", @" { // Code size 21 (0x15) .maxstack 1 IL_0000: ldstr ""5-"" IL_0005: call ""void System.Console.Write(string)"" IL_000a: ldstr ""11"" IL_000f: newobj ""S1..ctor(string)"" IL_0014: ret } "); comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular15); CompileAndVerify(comp, expectedOutput: "1-int {10} 2-3-4-string {} 5-string {11}").VerifyDiagnostics(); comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular14); comp.VerifyDiagnostics( // (37,27): error CS9327: Feature 'unions' is not available in C# 14.0. Please use language version 15.0 or greater. // /*<bind>*/ return 10; /*</bind>*/ Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion14, "10").WithArguments("unions", "15.0").WithLocation(37, 27), // (55,16): error CS9327: Feature 'unions' is not available in C# 14.0. Please use language version 15.0 or greater. // return null; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion14, "null").WithArguments("unions", "15.0").WithLocation(55, 16), // (61,16): error CS9327: Feature 'unions' is not available in C# 14.0. Please use language version 15.0 or greater. // return "11"; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion14, @"""11""").WithArguments("unions", "15.0").WithLocation(61, 16) ); } [Fact] public void UnionConversion_02_Implicit_Class() { var src = @" [System.Runtime.CompilerServices.Union] class S1 { private readonly object _value; public S1(int x) { System.Console.Write(""int {""); System.Console.Write(x); System.Console.Write(""} ""); _value = x; } public S1(string x) { System.Console.Write(""string {""); System.Console.Write(x); System.Console.Write(""} ""); _value = x; } public object Value => _value; } class Program { static void Main() { Test1(); Test2(); Test3(); Test4(); Test5(); } static S1 Test1() { System.Console.Write(""1-""); return 10; } static S1 Test2() { System.Console.Write(""2-""); return default; } static S1 Test3() { System.Console.Write(""3-""); return default(S1); } static S1 Test4() { System.Console.Write(""4-""); return null; } static S1 Test5() { System.Console.Write(""5-""); return ""11""; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); var verifier = CompileAndVerify(comp, expectedOutput: "1-int {10} 2-3-4-5-string {11}").VerifyDiagnostics(); verifier.VerifyIL("Program.Test1", @" { // Code size 18 (0x12) .maxstack 1 IL_0000: ldstr ""1-"" IL_0005: call ""void System.Console.Write(string)"" IL_000a: ldc.i4.s 10 IL_000c: newobj ""S1..ctor(int)"" IL_0011: ret } "); verifier.VerifyIL("Program.Test2", @" { // Code size 12 (0xc) .maxstack 1 IL_0000: ldstr ""2-"" IL_0005: call ""void System.Console.Write(string)"" IL_000a: ldnull IL_000b: ret } "); verifier.VerifyIL("Program.Test3", @" { // Code size 12 (0xc) .maxstack 1 IL_0000: ldstr ""3-"" IL_0005: call ""void System.Console.Write(string)"" IL_000a: ldnull IL_000b: ret } "); verifier.VerifyIL("Program.Test4", @" { // Code size 12 (0xc) .maxstack 1 IL_0000: ldstr ""4-"" IL_0005: call ""void System.Console.Write(string)"" IL_000a: ldnull IL_000b: ret } "); verifier.VerifyIL("Program.Test5", @" { // Code size 21 (0x15) .maxstack 1 IL_0000: ldstr ""5-"" IL_0005: call ""void System.Console.Write(string)"" IL_000a: ldstr ""11"" IL_000f: newobj ""S1..ctor(string)"" IL_0014: ret } "); } [Fact] public void UnionConversion_03_Cast() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 { private readonly object _value; public S1(int x) { System.Console.Write(""int {""); System.Console.Write(x); System.Console.Write(""} ""); _value = x; } public S1(string x) { System.Console.Write(""string {""); System.Console.Write(x); System.Console.Write(""} ""); _value = x; } public object Value => _value; } class Program { static void Main() { Test1(); Test2(); Test3(); Test4(); Test5(); } static S1 Test1() { System.Console.Write(""1-""); return /*<bind>*/ (S1)10 /*</bind>*/; } static S1 Test2() { System.Console.Write(""2-""); return (S1)default; } static S1 Test3() { System.Console.Write(""3-""); return (S1)default(S1); } static S1 Test4() { System.Console.Write(""4-""); return (S1)null; } static S1 Test5() { System.Console.Write(""5-""); return (S1)""11""; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var cast = GetSyntax<CastExpressionSyntax>(tree, "(S1)10"); var typeInfo = model.GetTypeInfo(cast); Assert.Equal("S1", typeInfo.Type.ToTestDisplayString()); Assert.Equal("S1", typeInfo.ConvertedType.ToTestDisplayString()); Conversion conversion = model.GetConversion(cast); Assert.True(conversion.IsIdentity); var symbolInfo = model.GetSymbolInfo(cast); Assert.Equal(CandidateReason.None, symbolInfo.CandidateReason); AssertEx.Equal("S1..ctor(System.Int32 x)", symbolInfo.Symbol.ToTestDisplayString()); Assert.Empty(symbolInfo.CandidateSymbols); VerifyOperationTreeForTest<CastExpressionSyntax>(comp, """ IConversionOperation (TryCast: False, Unchecked) (OperatorMethod: S1..ctor(System.Int32 x)) (OperationKind.Conversion, Type: S1) (Syntax: '(S1)10') Conversion: CommonConversion (Exists: True, IsIdentity: False, IsNumeric: False, IsReference: False, IsUserDefined: False, IsUnion: True) (MethodSymbol: S1..ctor(System.Int32 x)) Operand: ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 10) (Syntax: '10') """); var ten = GetSyntax<LiteralExpressionSyntax>(tree, "10"); typeInfo = model.GetTypeInfo(ten); Assert.Equal("System.Int32", typeInfo.Type.ToTestDisplayString()); Assert.Equal("System.Int32", typeInfo.ConvertedType.ToTestDisplayString()); conversion = model.GetConversion(ten); Assert.True(conversion.IsIdentity); var verifier = CompileAndVerify(comp, expectedOutput: "1-int {10} 2-3-4-string {} 5-string {11}").VerifyDiagnostics(); verifier.VerifyIL("Program.Test1", @" { // Code size 18 (0x12) .maxstack 1 IL_0000: ldstr ""1-"" IL_0005: call ""void System.Console.Write(string)"" IL_000a: ldc.i4.s 10 IL_000c: newobj ""S1..ctor(int)"" IL_0011: ret } "); verifier.VerifyIL("Program.Test2", @" { // Code size 20 (0x14) .maxstack 1 .locals init (S1 V_0) IL_0000: ldstr ""2-"" IL_0005: call ""void System.Console.Write(string)"" IL_000a: ldloca.s V_0 IL_000c: initobj ""S1"" IL_0012: ldloc.0 IL_0013: ret } "); verifier.VerifyIL("Program.Test3", @" { // Code size 20 (0x14) .maxstack 1 .locals init (S1 V_0) IL_0000: ldstr ""3-"" IL_0005: call ""void System.Console.Write(string)"" IL_000a: ldloca.s V_0 IL_000c: initobj ""S1"" IL_0012: ldloc.0 IL_0013: ret } "); verifier.VerifyIL("Program.Test4", @" { // Code size 17 (0x11) .maxstack 1 IL_0000: ldstr ""4-"" IL_0005: call ""void System.Console.Write(string)"" IL_000a: ldnull IL_000b: newobj ""S1..ctor(string)"" IL_0010: ret } "); verifier.VerifyIL("Program.Test5", @" { // Code size 21 (0x15) .maxstack 1 IL_0000: ldstr ""5-"" IL_0005: call ""void System.Console.Write(string)"" IL_000a: ldstr ""11"" IL_000f: newobj ""S1..ctor(string)"" IL_0014: ret } "); comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular15); CompileAndVerify(comp, expectedOutput: "1-int {10} 2-3-4-string {} 5-string {11}").VerifyDiagnostics(); comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular14); comp.VerifyDiagnostics( // (37,27): error CS9327: Feature 'unions' is not available in C# 14.0. Please use language version 15.0 or greater. // return /*<bind>*/ (S1)10 /*</bind>*/; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion14, "(S1)10").WithArguments("unions", "15.0").WithLocation(37, 27), // (55,16): error CS9327: Feature 'unions' is not available in C# 14.0. Please use language version 15.0 or greater. // return (S1)null; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion14, "(S1)null").WithArguments("unions", "15.0").WithLocation(55, 16), // (61,16): error CS9327: Feature 'unions' is not available in C# 14.0. Please use language version 15.0 or greater. // return (S1)"11"; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion14, @"(S1)""11""").WithArguments("unions", "15.0").WithLocation(61, 16) ); } [Fact] public void UnionConversion_04_Cast_Class() { var src = @" [System.Runtime.CompilerServices.Union] class S1 { private readonly object _value; public S1(int x) { System.Console.Write(""int {""); System.Console.Write(x); System.Console.Write(""} ""); _value = x; } public S1(string x) { System.Console.Write(""string {""); System.Console.Write(x); System.Console.Write(""} ""); _value = x; } public object Value => _value; } class Program { static void Main() { Test1(); Test2(); Test3(); Test4(); Test5(); } static S1 Test1() { System.Console.Write(""1-""); return (S1)10; } static S1 Test2() { System.Console.Write(""2-""); return (S1)default; } static S1 Test3() { System.Console.Write(""3-""); return (S1)default(S1); } static S1 Test4() { System.Console.Write(""4-""); return (S1)null; } static S1 Test5() { System.Console.Write(""5-""); return (S1)""11""; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); var verifier = CompileAndVerify(comp, expectedOutput: "1-int {10} 2-3-4-5-string {11}").VerifyDiagnostics(); verifier.VerifyIL("Program.Test1", @" { // Code size 18 (0x12) .maxstack 1 IL_0000: ldstr ""1-"" IL_0005: call ""void System.Console.Write(string)"" IL_000a: ldc.i4.s 10 IL_000c: newobj ""S1..ctor(int)"" IL_0011: ret } "); verifier.VerifyIL("Program.Test2", @" { // Code size 12 (0xc) .maxstack 1 IL_0000: ldstr ""2-"" IL_0005: call ""void System.Console.Write(string)"" IL_000a: ldnull IL_000b: ret } "); verifier.VerifyIL("Program.Test3", @" { // Code size 12 (0xc) .maxstack 1 IL_0000: ldstr ""3-"" IL_0005: call ""void System.Console.Write(string)"" IL_000a: ldnull IL_000b: ret } "); verifier.VerifyIL("Program.Test4", @" { // Code size 12 (0xc) .maxstack 1 IL_0000: ldstr ""4-"" IL_0005: call ""void System.Console.Write(string)"" IL_000a: ldnull IL_000b: ret } "); verifier.VerifyIL("Program.Test5", @" { // Code size 21 (0x15) .maxstack 1 IL_0000: ldstr ""5-"" IL_0005: call ""void System.Console.Write(string)"" IL_000a: ldstr ""11"" IL_000f: newobj ""S1..ctor(string)"" IL_0014: ret } "); } [Fact] public void UnionConversion_05_No_Lifted_Form() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } public object Value => _value; } class Program { static S1 Test1(int? x) { #line 20 return x; } static S1? Test2(int? y) { return y; } } "; var comp = CreateCompilation([src, UnionAttributeSource]); comp.VerifyDiagnostics( // (20,16): error CS0029: Cannot implicitly convert type 'int?' to 'S1' // return x; Diagnostic(ErrorCode.ERR_NoImplicitConv, "x").WithArguments("int?", "S1").WithLocation(20, 16), // (25,16): error CS0029: Cannot implicitly convert type 'int?' to 'S1?' // return y; Diagnostic(ErrorCode.ERR_NoImplicitConv, "y").WithArguments("int?", "S1?").WithLocation(25, 16) ); } [Fact] public void UnionConversion_06_No_Lifted_Form_Class() { var src = @" [System.Runtime.CompilerServices.Union] class S1 { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } public object Value => _value; } class Program { static S1 Test1(int? x) { #line 20 return x; } } "; var comp = CreateCompilation([src, UnionAttributeSource]); comp.VerifyDiagnostics( // (20,16): error CS0029: Cannot implicitly convert type 'int?' to 'S1' // return x; Diagnostic(ErrorCode.ERR_NoImplicitConv, "x").WithArguments("int?", "S1").WithLocation(20, 16) ); } [Fact] public void UnionConversion_07_Ambiguity_First_Declared_Wins() { var src1 = @" [System.Runtime.CompilerServices.Union] public struct S1 { private readonly object _value; public S1(C1 x) { System.Console.Write(""C1""); _value = x; } public S1(C2 x) => throw null; public object Value => _value; } [System.Runtime.CompilerServices.Union] public struct S2 { private readonly object _value; public S2(C2 x) { System.Console.Write(""C2""); _value = x; } public S2(C1 x) => throw null; public object Value => _value; } public class C1 { } public class C2 { } "; var src2 = @" class Program { static void Main() { Test1(); Test2(); } static S1 Test1() { return null; } static S2 Test2() { return (S2)null; } } "; var comp = CreateCompilation([src1, src2, UnionAttributeSource], options: TestOptions.ReleaseExe); comp.VerifyDiagnostics( // (12,16): error CS0037: Cannot convert null to 'S1' because it is a non-nullable value type // return null; Diagnostic(ErrorCode.ERR_ValueCantBeNull, "null").WithArguments("S1").WithLocation(12, 16), // (17,16): error CS0037: Cannot convert null to 'S2' because it is a non-nullable value type // return (S2)null; Diagnostic(ErrorCode.ERR_ValueCantBeNull, "(S2)null").WithArguments("S2").WithLocation(17, 16) ); } [Fact] public void UnionConversion_08_Standard_Conversion_For_Source_Allowed() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 { private readonly object _value; public S1(int x) { System.Console.Write(""int {""); System.Console.Write(x); System.Console.Write(""} ""); _value = x; } public S1(string x) => throw null; public object Value => _value; } class Program { static void Main() { Test1(15); Test2(16); } static S1 Test1(byte x1) { return x1; } static S1 Test2(byte x2) { return (S1)x2; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); CompileAndVerify(comp, expectedOutput: "int {15} int {16}").VerifyDiagnostics(); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var x1 = GetSyntax<IdentifierNameSyntax>(tree, "x1"); var symbolInfo = model.GetSymbolInfo(x1); Assert.Equal(CandidateReason.None, symbolInfo.CandidateReason); AssertEx.Equal("System.Byte x1", symbolInfo.Symbol.ToTestDisplayString()); Assert.Empty(symbolInfo.CandidateSymbols); var typeInfo = model.GetTypeInfo(x1); Assert.Equal("System.Byte", typeInfo.Type.ToTestDisplayString()); Assert.Equal("S1", typeInfo.ConvertedType.ToTestDisplayString()); Conversion conversion = model.GetConversion(x1); Assert.True(conversion.IsUnion); Assert.False(conversion.IsUserDefined); AssertEx.Equal("S1..ctor(System.Int32 x)", conversion.Method.ToTestDisplayString()); Assert.Null(conversion.BestUserDefinedConversionAnalysis); Assert.Equal(Conversion.NoConversion, conversion.UserDefinedFromConversion); Assert.Equal(Conversion.NoConversion, conversion.UserDefinedToConversion); Assert.NotNull(conversion.BestUnionConversionAnalysis); AssertEx.SequenceEqual(["S1..ctor(System.Int32 x)"], conversion.OriginalUserDefinedOrUnionConversions.ToTestDisplayStrings()); Assert.True(conversion.UnderlyingConversions.IsDefault); CommonConversion commonConversion = conversion.ToCommonConversion(); Assert.True(commonConversion.Exists); Assert.True(commonConversion.IsImplicit); Assert.True(commonConversion.IsUnion); Assert.False(commonConversion.IsUserDefined); AssertEx.Equal("S1..ctor(System.Int32 x)", commonConversion.MethodSymbol.ToTestDisplayString()); VerifyOperationTreeForNode(comp, model, GetSyntax<ReturnStatementSyntax>(tree, "return x1;"), """ IReturnOperation (OperationKind.Return, Type: null) (Syntax: 'return x1;') ReturnedValue: IConversionOperation (TryCast: False, Unchecked) (OperatorMethod: S1..ctor(System.Int32 x)) (OperationKind.Conversion, Type: S1, IsImplicit) (Syntax: 'x1') Conversion: CommonConversion (Exists: True, IsIdentity: False, IsNumeric: False, IsReference: False, IsUserDefined: False, IsUnion: True) (MethodSymbol: S1..ctor(System.Int32 x)) Operand: IConversionOperation (TryCast: False, Unchecked) (OperationKind.Conversion, Type: System.Int32, IsImplicit) (Syntax: 'x1') Conversion: CommonConversion (Exists: True, IsIdentity: False, IsNumeric: True, IsReference: False, IsUserDefined: False) (MethodSymbol: null) Operand: IParameterReferenceOperation: x1 (OperationKind.ParameterReference, Type: System.Byte) (Syntax: 'x1') """); var x2 = GetSyntax<IdentifierNameSyntax>(tree, "x2"); symbolInfo = model.GetSymbolInfo(x2); Assert.Equal(CandidateReason.None, symbolInfo.CandidateReason); AssertEx.Equal("System.Byte x2", symbolInfo.Symbol.ToTestDisplayString()); Assert.Empty(symbolInfo.CandidateSymbols); typeInfo = model.GetTypeInfo(x2); Assert.Equal("System.Byte", typeInfo.Type.ToTestDisplayString()); Assert.Equal("System.Byte", typeInfo.ConvertedType.ToTestDisplayString()); conversion = model.GetConversion(x2); Assert.True(conversion.IsIdentity); Assert.False(conversion.IsUnion); Assert.False(conversion.IsUserDefined); var cast = GetSyntax<CastExpressionSyntax>(tree, "(S1)x2"); symbolInfo = model.GetSymbolInfo(cast); Assert.Equal(CandidateReason.None, symbolInfo.CandidateReason); AssertEx.Equal("S1..ctor(System.Int32 x)", symbolInfo.Symbol.ToTestDisplayString()); Assert.Empty(symbolInfo.CandidateSymbols); typeInfo = model.GetTypeInfo(cast); Assert.Equal("S1", typeInfo.Type.ToTestDisplayString()); Assert.Equal("S1", typeInfo.ConvertedType.ToTestDisplayString()); VerifyOperationTreeForNode(comp, model, GetSyntax<ReturnStatementSyntax>(tree, "return (S1)x2;"), """ IReturnOperation (OperationKind.Return, Type: null) (Syntax: 'return (S1)x2;') ReturnedValue: IConversionOperation (TryCast: False, Unchecked) (OperatorMethod: S1..ctor(System.Int32 x)) (OperationKind.Conversion, Type: S1) (Syntax: '(S1)x2') Conversion: CommonConversion (Exists: True, IsIdentity: False, IsNumeric: False, IsReference: False, IsUserDefined: False, IsUnion: True) (MethodSymbol: S1..ctor(System.Int32 x)) Operand: IConversionOperation (TryCast: False, Unchecked) (OperationKind.Conversion, Type: System.Int32, IsImplicit) (Syntax: '(S1)x2') Conversion: CommonConversion (Exists: True, IsIdentity: False, IsNumeric: True, IsReference: False, IsUserDefined: False) (MethodSymbol: null) Operand: IParameterReferenceOperation: x2 (OperationKind.ParameterReference, Type: System.Byte) (Syntax: 'x2') """); } [Fact] public void UnionConversion_09_NonStandard_Conversion_For_Source_Not_Allowed() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 { public S1(C1 x) => throw null; public S1(string x) => throw null; public object Value => throw null; } class C1 { public static implicit operator C1(byte x) => new C1(); } class Program { static S1 Test1(byte x) { #line 100 return x; } static S1 Test2(byte x) { #line 200 return (S1)x; } static C1 Test3(byte x) { return x; } } "; var comp = CreateCompilation([src, UnionAttributeSource]); comp.VerifyDiagnostics( // (100,16): error CS0029: Cannot implicitly convert type 'byte' to 'S1' // return x; Diagnostic(ErrorCode.ERR_NoImplicitConv, "x").WithArguments("byte", "S1").WithLocation(100, 16), // (200,16): error CS0030: Cannot convert type 'byte' to 'S1' // return (S1)x; Diagnostic(ErrorCode.ERR_NoExplicitConv, "(S1)x").WithArguments("byte", "S1").WithLocation(200, 16) ); } [Fact] public void UnionConversion_10_Explicit_Conversion_For_Source_Not_Allowed() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 { public S1(int x) => throw null; public S1(string x) => throw null; public object Value => throw null; } class Program { static S1 Test1(long x) { #line 100 return x; } static S1 Test2(long x) { #line 200 return (S1)x; } } "; var comp = CreateCompilation([src, UnionAttributeSource]); comp.VerifyDiagnostics( // (100,16): error CS0029: Cannot implicitly convert type 'long' to 'S1' // return x; Diagnostic(ErrorCode.ERR_NoImplicitConv, "x").WithArguments("long", "S1").WithLocation(100, 16), // (200,16): error CS0030: Cannot convert type 'long' to 'S1' // return (S1)x; Diagnostic(ErrorCode.ERR_NoExplicitConv, "(S1)x").WithArguments("long", "S1").WithLocation(200, 16) ); } [Fact] public void UnionConversion_11_Not_Standard_Conversion() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 { public S1(S2 x) => throw null; public S1(string x) => throw null; public object Value => throw null; } [System.Runtime.CompilerServices.Union] struct S2 { public S2(int x) => throw null; public S2(string x) => throw null; public object Value => throw null; } class C1 { public static implicit operator C1(S2 x) => new C1(); } class Program { static S1 Test1(int x) { #line 100 return x; } static C1 Test2(int x) { #line 200 return x; } static S1 Test3(int x) { #line 300 return (S2)x; } static C1 Test4(int x) { #line 400 return (S2)x; } } "; var comp = CreateCompilation([src, UnionAttributeSource]); comp.VerifyDiagnostics( // (100,16): error CS0029: Cannot implicitly convert type 'int' to 'S1' // return x; Diagnostic(ErrorCode.ERR_NoImplicitConv, "x").WithArguments("int", "S1").WithLocation(100, 16), // (200,16): error CS0029: Cannot implicitly convert type 'int' to 'C1' // return x; Diagnostic(ErrorCode.ERR_NoImplicitConv, "x").WithArguments("int", "C1").WithLocation(200, 16) ); } [Fact] public void UnionConversion_12_Implicit_UserDefined_Conversion_Wins() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 { public S1(int x) => throw null; public S1(string x) { System.Console.Write(""string {""); System.Console.Write(x); System.Console.Write(""} ""); } public object Value => throw null; public static implicit operator S1(int x) { System.Console.Write(""implicit operator ""); return new S1(x.ToString()); } } class Program { static void Main() { Test1(); Test2(); } static S1 Test1() { return 10; } static S1 Test2() { return (S1)20; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); CompileAndVerify(comp, expectedOutput: "implicit operator string {10} implicit operator string {20}").VerifyDiagnostics(); } [Fact] public void UnionConversion_13_Cast_Explicit_UserDefined_Conversion_Wins() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 { public S1(int x) => throw null; public S1(string x) { System.Console.Write(""string {""); System.Console.Write(x); System.Console.Write(""} ""); } public object Value => throw null; public static explicit operator S1(int x) { System.Console.Write(""explicit operator ""); return new S1(x.ToString()); } } class Program { static void Main() { Test2(); } static S1 Test2() { return (S1)20; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); CompileAndVerify(comp, expectedOutput: "explicit operator string {20}").VerifyDiagnostics(); } [Fact] public void UnionConversion_14_Explicit_UserDefined_Conversion_Loses() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 { public S1(int x) { System.Console.Write(""int {""); System.Console.Write(x); System.Console.Write(""} ""); } public S1(string x) => throw null; public object Value => throw null; public static explicit operator S1(int x) => throw null; } class Program { static void Main() { Test1(); } static S1 Test1() { return 10; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); CompileAndVerify(comp, expectedOutput: "int {10}").VerifyDiagnostics(); } [Fact] public void UnionConversion_15_Cast_From_Base_Class_Not_Union_Conversion() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 { public S1(System.ValueType x) => throw null; public S1(string x) => throw null; public object Value => throw null; } class Program { static void Main() { System.Console.Write(Test2(new S1())); } static S1 Test2(System.ValueType x) { return (S1)x; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); var verifier = CompileAndVerify(comp, expectedOutput: "S1").VerifyDiagnostics(); verifier.VerifyIL("Program.Test2", @" { // Code size 7 (0x7) .maxstack 1 IL_0000: ldarg.0 IL_0001: unbox.any ""S1"" IL_0006: ret } "); } [Fact] public void UnionConversion_16_Implicit_From_Base_Class_Union_Conversion() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 { public S1(System.ValueType x) { System.Console.Write(""System.ValueType ""); } public S1(string x) => throw null; public object Value => throw null; } class Program { static void Main() { System.Console.Write(Test2(new S1())); } static S1 Test2(System.ValueType x) { return x; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); var verifier = CompileAndVerify(comp, expectedOutput: "System.ValueType S1").VerifyDiagnostics(); verifier.VerifyIL("Program.Test2", @" { // Code size 7 (0x7) .maxstack 1 IL_0000: ldarg.0 IL_0001: newobj ""S1..ctor(System.ValueType)"" IL_0006: ret } "); var src2 = @" struct S1 { public static implicit operator S1(System.ValueType x) => throw null; } struct S2 { public static explicit operator S2(System.ValueType x) => throw null; } "; CreateCompilation(src2).VerifyDiagnostics( // (4,37): error CS0553: 'S1.implicit operator S1(ValueType)': user-defined conversions to or from a base type are not allowed // public static implicit operator S1(System.ValueType x) Diagnostic(ErrorCode.ERR_ConversionWithBase, "S1").WithArguments("S1.implicit operator S1(System.ValueType)").WithLocation(4, 37), // (9,37): error CS0553: 'S2.explicit operator S2(ValueType)': user-defined conversions to or from a base type are not allowed // public static explicit operator S2(System.ValueType x) Diagnostic(ErrorCode.ERR_ConversionWithBase, "S2").WithArguments("S2.explicit operator S2(System.ValueType)").WithLocation(9, 37) ); } [Fact] public void UnionConversion_17_Cast_From_Implemented_Interface_Not_Union_Conversion() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 : I1 { public S1(I1 x) => throw null; public S1(string x) => throw null; public object Value => throw null; } interface I1 { } class Program { static void Main() { System.Console.Write(Test2(new S1())); } static S1 Test2(I1 x) { return (S1)x; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); var verifier = CompileAndVerify(comp, expectedOutput: "S1").VerifyDiagnostics(); verifier.VerifyIL("Program.Test2", @" { // Code size 7 (0x7) .maxstack 1 IL_0000: ldarg.0 IL_0001: unbox.any ""S1"" IL_0006: ret } "); } [Fact] public void UnionConversion_18_Implicit_From_Implemented_Interface_Union_Conversion() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 : I1 { public S1(I1 x) { System.Console.Write(""I1 ""); } public S1(string x) => throw null; public object Value => throw null; } interface I1 { } class Program { static void Main() { System.Console.Write(Test2(new S1())); } static S1 Test2(I1 x) { return x; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); var verifier = CompileAndVerify(comp, expectedOutput: "I1 S1").VerifyDiagnostics(); verifier.VerifyIL("Program.Test2", @" { // Code size 7 (0x7) .maxstack 1 IL_0000: ldarg.0 IL_0001: newobj ""S1..ctor(I1)"" IL_0006: ret } "); var src2 = @" interface I1 { } struct S1 : I1 { public static implicit operator S1(I1 x) => throw null; } struct S2 : I1 { public static explicit operator S2(I1 x) => throw null; } "; CreateCompilation(src2).VerifyDiagnostics( // (6,37): error CS0552: 'S1.implicit operator S1(I1)': user-defined conversions to or from an interface are not allowed // public static implicit operator S1(I1 x) Diagnostic(ErrorCode.ERR_ConversionWithInterface, "S1").WithArguments("S1.implicit operator S1(I1)").WithLocation(6, 37), // (11,37): error CS0552: 'S2.explicit operator S2(I1)': user-defined conversions to or from an interface are not allowed // public static explicit operator S2(I1 x) Diagnostic(ErrorCode.ERR_ConversionWithInterface, "S2").WithArguments("S2.explicit operator S2(I1)").WithLocation(11, 37) ); } [Fact] public void UnionConversion_19_From_Not_Implemented_Interface_Union_Conversion() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 { public S1(I1 x) { System.Console.Write(""I1 ""); } public S1(string x) => throw null; public object Value => throw null; } interface I1 { } struct S2 : I1; class Program { static void Main() { System.Console.Write(Test1(new S2())); System.Console.Write(' '); System.Console.Write(Test2(new S2())); } static S1 Test1(I1 x) { return x; } static S1 Test2(I1 x) { return (S1)x; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); var verifier = CompileAndVerify(comp, expectedOutput: "I1 S1 I1 S1").VerifyDiagnostics(); verifier.VerifyIL("Program.Test1", @" { // Code size 7 (0x7) .maxstack 1 IL_0000: ldarg.0 IL_0001: newobj ""S1..ctor(I1)"" IL_0006: ret } "); verifier.VerifyIL("Program.Test2", @" { // Code size 7 (0x7) .maxstack 1 IL_0000: ldarg.0 IL_0001: newobj ""S1..ctor(I1)"" IL_0006: ret } "); var src2 = @" interface I1 { } struct S1 { public static implicit operator S1(I1 x) => throw null; } struct S2 { public static explicit operator S2(I1 x) => throw null; } "; CreateCompilation(src2).VerifyDiagnostics( // (6,37): error CS0552: 'S1.implicit operator S1(I1)': user-defined conversions to or from an interface are not allowed // public static implicit operator S1(I1 x) Diagnostic(ErrorCode.ERR_ConversionWithInterface, "S1").WithArguments("S1.implicit operator S1(I1)").WithLocation(6, 37), // (11,37): error CS0552: 'S2.explicit operator S2(I1)': user-defined conversions to or from an interface are not allowed // public static explicit operator S2(I1 x) Diagnostic(ErrorCode.ERR_ConversionWithInterface, "S2").WithArguments("S2.explicit operator S2(I1)").WithLocation(11, 37) ); } [Fact] public void UnionConversion_20_From_Not_Implemented_Interface_Union_Conversion() { var src = @" [System.Runtime.CompilerServices.Union] class S1 { public S1(I1 x) { System.Console.Write(""I1 ""); } public S1(string x) => throw null; public object Value => throw null; } interface I1 { } struct S2 : I1; class Program { static void Main() { System.Console.Write(Test1(new S2())); } static S1 Test1(I1 x) { return x; } static S1 Test2(I1 x) { return (S1)x; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); var verifier = CompileAndVerify(comp, expectedOutput: "I1 S1").VerifyDiagnostics(); verifier.VerifyIL("Program.Test1", @" { // Code size 7 (0x7) .maxstack 1 IL_0000: ldarg.0 IL_0001: newobj ""S1..ctor(I1)"" IL_0006: ret } "); verifier.VerifyIL("Program.Test2", @" { // Code size 7 (0x7) .maxstack 1 IL_0000: ldarg.0 IL_0001: castclass ""S1"" IL_0006: ret } "); var src2 = @" interface I1 { } class S1 { public static implicit operator S1(I1 x) => throw null; } class S2 { public static explicit operator S2(I1 x) => throw null; } "; CreateCompilation(src2).VerifyDiagnostics( // (6,37): error CS0552: 'S1.implicit operator S1(I1)': user-defined conversions to or from an interface are not allowed // public static implicit operator S1(I1 x) Diagnostic(ErrorCode.ERR_ConversionWithInterface, "S1").WithArguments("S1.implicit operator S1(I1)").WithLocation(6, 37), // (11,37): error CS0552: 'S2.explicit operator S2(I1)': user-defined conversions to or from an interface are not allowed // public static explicit operator S2(I1 x) Diagnostic(ErrorCode.ERR_ConversionWithInterface, "S2").WithArguments("S2.explicit operator S2(I1)").WithLocation(11, 37) ); } [Fact] public void UnionConversion_21_Through_Base_Class_Or_Interface() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 { private readonly object _value; public S1(System.ValueType x) { System.Console.Write(""System.ValueType {""); System.Console.Write(x.GetType()); System.Console.Write(' '); System.Console.Write(x); System.Console.Write(""} ""); _value = x; } public S1(System.IComparable x) { System.Console.Write(""System.IComparable {""); System.Console.Write(x.GetType()); System.Console.Write(' '); System.Console.Write(x); System.Console.Write(""} ""); _value = x; } public object Value => _value; } class Program { static void Main() { Test1(); Test5(); } static S1 Test1() { System.Console.Write(""1-""); return 10; } static S1 Test5() { System.Console.Write(""5-""); return ""11""; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); comp.VerifyDiagnostics( // (38,16): error CS0457: Ambiguous user defined conversions 'S1.S1(ValueType)' and 'S1.S1(IComparable)' when converting from 'int' to 'S1' // return 10; Diagnostic(ErrorCode.ERR_AmbigUDConv, "10").WithArguments("S1.S1(System.ValueType)", "S1.S1(System.IComparable)", "int", "S1").WithLocation(38, 16) ); } [Fact] public void UnionConversion_22_ExpressionTree() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 { public S1(int x) => throw null; public S1(string x) => throw null; public object Value => throw null; } class Program { static System.Linq.Expressions.Expression<System.Func<S1>> Test1(int x) { #line 13 return () => x; } } "; var comp = CreateCompilation([src, UnionAttributeSource]); comp.VerifyDiagnostics( // (13,22): error CS9369: An expression tree may not contain a union conversion. // return () => x; Diagnostic(ErrorCode.ERR_ExpressionTreeContainsUnionConversion, "x").WithLocation(13, 22) ); } [Fact] public void UnionConversion_23_ClassifyImplicitConversionFromType() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 { public S1(int x) { System.Console.Write(""int {""); System.Console.Write(x); System.Console.Write(""} ""); } public S1(string x) => throw null; public object Value => throw null; } class Program { static void Main() { Test1(10); } static S1 Test1(int? x) { return x ?? new S1(""""); } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); CompileAndVerify(comp, expectedOutput: "int {10}").VerifyDiagnostics(); } [Fact] public void UnionConversion_24_ClassifyConversionFromType() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 { public S1(int x) { System.Console.Write(""int {""); System.Console.Write(x); System.Console.Write(""} ""); } public S1(string x) => throw null; public object Value => throw null; } class Program { static void Main() { var x = new S1(); var y = (0, 123); (var z, x) = y; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); CompileAndVerify(comp, expectedOutput: "int {123}").VerifyDiagnostics(); } [Fact] public void UnionConversion_25_ClassifyConversionFromTypeForCast_Implicit_UserDefined_Conversion_Wins() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 { public S1(int x) => throw null; public S1(string x) { System.Console.Write(""string {""); System.Console.Write(x); System.Console.Write(""} ""); } public object Value => throw null; public static implicit operator S1(int x) { System.Console.Write(""implicit operator ""); return new S1(x.ToString()); } } class Program { static void Main() { Test1(); } static void Test1() { foreach (S1 y in new int[] { 10 }) { } } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); CompileAndVerify(comp, expectedOutput: "implicit operator string {10}").VerifyDiagnostics(); } [Fact] public void UnionConversion_26_ClassifyConversionFromTypeForCast_Explicit_UserDefined_Conversion_Wins() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 { public S1(int x) => throw null; public S1(string x) { System.Console.Write(""string {""); System.Console.Write(x); System.Console.Write(""} ""); } public object Value => throw null; public static explicit operator S1(int x) { System.Console.Write(""explicit operator ""); return new S1(x.ToString()); } } class Program { static void Main() { Test2(); } static void Test2() { foreach (S1 y in new int[] { 20 }) { } } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); CompileAndVerify(comp, expectedOutput: "explicit operator string {20}").VerifyDiagnostics(); } [Fact] public void UnionConversion_27_ClassifyConversionFromTypeForCast() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 { public S1(int x) { System.Console.Write(""int {""); System.Console.Write(x); System.Console.Write(""} ""); } public S1(string x) => throw null; public object Value => throw null; } class Program { static void Main() { Test1(); } static void Test1() { foreach (S1 y in new int[] { 10 }) { } } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); CompileAndVerify(comp, expectedOutput: "int {10}").VerifyDiagnostics(); } [Fact] public void UnionConversion_28_Under_Tuple_Conversion() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 { public S1(double x) { System.Console.Write(""double {""); System.Console.Write((int)x); System.Console.Write(""} ""); } public S1(string x) => throw null; public object Value => throw null; } class Program { static void Main() { Test1((0, 10)); } static (int, S1) Test1((int, byte) x) { return x; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); var verifier = CompileAndVerify(comp, expectedOutput: "double {10}").VerifyDiagnostics(); verifier.VerifyIL("Program.Test1", @" { // Code size 26 (0x1a) .maxstack 2 .locals init (System.ValueTuple<int, byte> V_0) IL_0000: ldarg.0 IL_0001: stloc.0 IL_0002: ldloc.0 IL_0003: ldfld ""int System.ValueTuple<int, byte>.Item1"" IL_0008: ldloc.0 IL_0009: ldfld ""byte System.ValueTuple<int, byte>.Item2"" IL_000e: conv.r8 IL_000f: newobj ""S1..ctor(double)"" IL_0014: newobj ""System.ValueTuple<int, S1>..ctor(int, S1)"" IL_0019: ret } "); } [Fact] public void UnionConversion_30_In_Parameter() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 { public S1(in int x) { System.Console.Write(""int {""); System.Console.Write(x); System.Console.Write(""} ""); } public S1(string x) => throw null; public object Value => throw null; } class Program { static void Main() { Test1(); Test2(11); Test3(12); } static S1 Test1() { System.Console.Write(""1-""); return 10; } static S1 Test2(int x) { System.Console.Write(""2-""); return x; } static S1 Test3(byte x) { System.Console.Write(""3-""); return x; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); var verifier = CompileAndVerify(comp, expectedOutput: "1-int {10} 2-int {11} 3-int {12}").VerifyDiagnostics(); verifier.VerifyIL("Program.Test1", @" { // Code size 21 (0x15) .maxstack 1 .locals init (int V_0) IL_0000: ldstr ""1-"" IL_0005: call ""void System.Console.Write(string)"" IL_000a: ldc.i4.s 10 IL_000c: stloc.0 IL_000d: ldloca.s V_0 IL_000f: newobj ""S1..ctor(in int)"" IL_0014: ret } "); verifier.VerifyIL("Program.Test2", @" { // Code size 18 (0x12) .maxstack 1 IL_0000: ldstr ""2-"" IL_0005: call ""void System.Console.Write(string)"" IL_000a: ldarga.s V_0 IL_000c: newobj ""S1..ctor(in int)"" IL_0011: ret } "); verifier.VerifyIL("Program.Test3", @" { // Code size 20 (0x14) .maxstack 1 .locals init (int V_0) IL_0000: ldstr ""3-"" IL_0005: call ""void System.Console.Write(string)"" IL_000a: ldarg.0 IL_000b: stloc.0 IL_000c: ldloca.s V_0 IL_000e: newobj ""S1..ctor(in int)"" IL_0013: ret } "); } [Fact] public void UnionConversion_31_Ambiguity_In_Vs_Val() { var src1 = @" [System.Runtime.CompilerServices.Union] public struct S1 { public S1(in int x) { System.Console.Write(""In""); } public S1(int x) => throw null; public S1(string x) => throw null; public object Value => throw null; } [System.Runtime.CompilerServices.Union] public struct S2 { public S2(int x) { System.Console.Write(""Val""); } public S2(in int x) => throw null; public S2(string x) => throw null; public object Value => throw null; } "; var src2 = @" class Program { static void Main() { Test1(); Test2(); } static S1 Test1() { return 10; } static S2 Test2() { return (S2)10; } static void Test3(int[] s) { foreach (S1 x in s) {} } static S1? Test4() { return (S1?)10; } } "; var comp = CreateCompilation([src1, src2, UnionAttributeSource], options: TestOptions.ReleaseExe); comp.VerifyDiagnostics( // (12,16): error CS0457: Ambiguous user defined conversions 'S1.S1(in int)' and 'S1.S1(int)' when converting from 'int' to 'S1' // return 10; Diagnostic(ErrorCode.ERR_AmbigUDConv, "10").WithArguments("S1.S1(in int)", "S1.S1(int)", "int", "S1").WithLocation(12, 16), // (17,16): error CS0457: Ambiguous user defined conversions 'S2.S2(int)' and 'S2.S2(in int)' when converting from 'int' to 'S2' // return (S2)10; Diagnostic(ErrorCode.ERR_AmbigUDConv, "(S2)10").WithArguments("S2.S2(int)", "S2.S2(in int)", "int", "S2").WithLocation(17, 16), // (22,9): error CS0457: Ambiguous user defined conversions 'S1.S1(in int)' and 'S1.S1(int)' when converting from 'int' to 'S1' // foreach (S1 x in s) Diagnostic(ErrorCode.ERR_AmbigUDConv, "foreach").WithArguments("S1.S1(in int)", "S1.S1(int)", "int", "S1").WithLocation(22, 9), // (28,16): error CS0457: Ambiguous user defined conversions 'S1.S1(in int)' and 'S1.S1(int)' when converting from 'int' to 'S1?' // return (S1?)10; Diagnostic(ErrorCode.ERR_AmbigUDConv, "(S1?)10").WithArguments("S1.S1(in int)", "S1.S1(int)", "int", "S1?").WithLocation(28, 16) ); var tree = comp.SyntaxTrees[1]; var model = comp.GetSemanticModel(tree); var cast = GetSyntax<CastExpressionSyntax>(tree, "(S2)10"); var typeInfo = model.GetTypeInfo(cast); Assert.Equal("S2", typeInfo.Type.ToTestDisplayString()); Assert.Equal("S2", typeInfo.ConvertedType.ToTestDisplayString()); Conversion conversion = model.GetConversion(cast); Assert.True(conversion.IsIdentity); var symbolInfo = model.GetSymbolInfo(cast); Assert.Equal(CandidateReason.OverloadResolutionFailure, symbolInfo.CandidateReason); Assert.Null(symbolInfo.Symbol); AssertEx.SequenceEqual(["S2..ctor(System.Int32 x)", "S2..ctor(in System.Int32 x)"], symbolInfo.CandidateSymbols.ToTestDisplayStrings()); cast = GetSyntax<CastExpressionSyntax>(tree, "(S1?)10"); typeInfo = model.GetTypeInfo(cast); Assert.Equal("S1?", typeInfo.Type.ToTestDisplayString()); Assert.Equal("S1?", typeInfo.ConvertedType.ToTestDisplayString()); conversion = model.GetConversion(cast); Assert.True(conversion.IsIdentity); symbolInfo = model.GetSymbolInfo(cast); Assert.Equal(CandidateReason.OverloadResolutionFailure, symbolInfo.CandidateReason); Assert.Null(symbolInfo.Symbol); AssertEx.SequenceEqual(["S1..ctor(in System.Int32 x)", "S1..ctor(System.Int32 x)"], symbolInfo.CandidateSymbols.ToTestDisplayStrings()); } [Fact] public void UnionConversion_32_No_Params_Expansion() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 { public S1(params int[] x) => throw null; public S1(string x) => throw null; public object Value => throw null; } class Program { static S1 Test1(int x) { #line 13 return (S1)x; } } "; var comp = CreateCompilation([src, UnionAttributeSource]); comp.VerifyDiagnostics( // (13,16): error CS0030: Cannot convert type 'int' to 'S1' // return (S1)x; Diagnostic(ErrorCode.ERR_NoExplicitConv, "(S1)x").WithArguments("int", "S1").WithLocation(13, 16) ); } [Fact] public void UnionConversion_33_No_Optional() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 { public S1(byte x) => throw null; public S1(string x) => throw null; public S1(int x, object o = null) => throw null; public object Value => throw null; } class Program { static S1 Test1(int x) { #line 14 return (S1)x; } } "; var comp = CreateCompilation([src, UnionAttributeSource]); comp.VerifyDiagnostics( // (14,16): error CS0030: Cannot convert type 'int' to 'S1' // return (S1)x; Diagnostic(ErrorCode.ERR_NoExplicitConv, "(S1)x").WithArguments("int", "S1").WithLocation(14, 16) ); } [Fact] public void UnionConversion_34_No_Non_Public() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 { public S1(byte x) => throw null; public S1(string x) => throw null; internal S1(int x) => throw null; public object Value => throw null; } class Program { static S1 Test1(int x) { #line 14 return (S1)x; } } "; var comp = CreateCompilation([src, UnionAttributeSource]); comp.VerifyDiagnostics( // (14,16): error CS0030: Cannot convert type 'int' to 'S1' // return (S1)x; Diagnostic(ErrorCode.ERR_NoExplicitConv, "(S1)x").WithArguments("int", "S1").WithLocation(14, 16) ); } [Theory] [CombinatorialData] public void UnionConversion_35_No_Ref_Out([CombinatorialValues("ref", "out", "ref readonly")] string refModifier) { var src = @" [System.Runtime.CompilerServices.Union] struct S1 { public S1(" + refModifier + @" int x) => throw null; public S1(string x) => throw null; public object Value => throw null; } class Program { static S1 Test1(int x) { #line 13 return (S1)x; } } "; var comp = CreateCompilation([src, UnionAttributeSource]); comp.VerifyDiagnostics( // (13,16): error CS0030: Cannot convert type 'int' to 'S1' // return (S1)x; Diagnostic(ErrorCode.ERR_NoExplicitConv, "(S1)x").WithArguments("int", "S1").WithLocation(13, 16) ); } [Fact] public void UnionConversion_36_Implicit_ToNullableOfUnion() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 { private readonly object _value; public S1(int x) { System.Console.Write(""int {""); System.Console.Write(x); System.Console.Write(""} ""); _value = x; } public S1(string x) { System.Console.Write(""string {""); System.Console.Write(x); System.Console.Write(""} ""); _value = x; } public object Value => _value; } class Program { static void Main() { System.Console.Write(Test1().HasValue ? ""[not null] "" : ""null ""); System.Console.Write(Test2().HasValue ? ""[not null] "" : ""null ""); System.Console.Write(Test3().HasValue ? ""[not null] "" : ""null ""); System.Console.Write(Test4().HasValue ? ""[not null] "" : ""null ""); System.Console.Write(Test5().HasValue ? ""[not null] "" : ""null ""); } static S1? Test1() { System.Console.Write(""1-""); /*<bind>*/ return 10; /*</bind>*/ } static S1? Test2() { System.Console.Write(""2-""); return default; } static S1? Test3() { System.Console.Write(""3-""); return default(S1); } static S1? Test4() { System.Console.Write(""4-""); return null; } static S1? Test5() { System.Console.Write(""5-""); return ""11""; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var ten = GetSyntax<LiteralExpressionSyntax>(tree, "10"); var symbolInfo = model.GetSymbolInfo(ten); Assert.Equal(CandidateReason.None, symbolInfo.CandidateReason); Assert.Null(symbolInfo.Symbol); Assert.Empty(symbolInfo.CandidateSymbols); var typeInfo = model.GetTypeInfo(ten); Assert.Equal("System.Int32", typeInfo.Type.ToTestDisplayString()); Assert.Equal("S1?", typeInfo.ConvertedType.ToTestDisplayString()); Conversion conversion = model.GetConversion(ten); Assert.True(conversion.Exists); Assert.True(conversion.IsValid); Assert.True(conversion.IsImplicit); Assert.False(conversion.IsExplicit); Assert.Equal(ConversionKind.Union, conversion.Kind); Assert.Equal(LookupResultKind.Viable, conversion.ResultKind); Assert.True(conversion.IsUnion); Assert.False(conversion.IsUserDefined); AssertEx.Equal("S1..ctor(System.Int32 x)", conversion.Method.ToTestDisplayString()); AssertEx.Equal("S1..ctor(System.Int32 x)", conversion.MethodSymbol.ToTestDisplayString()); Assert.Null(conversion.BestUserDefinedConversionAnalysis); Assert.Equal(Conversion.NoConversion, conversion.UserDefinedFromConversion); Assert.Equal(Conversion.NoConversion, conversion.UserDefinedToConversion); Assert.NotNull(conversion.BestUnionConversionAnalysis); AssertEx.SequenceEqual(["S1..ctor(System.Int32 x)"], conversion.OriginalUserDefinedOrUnionConversions.ToTestDisplayStrings()); Assert.True(conversion.UnderlyingConversions.IsDefault); Assert.False(conversion.IsArrayIndex); Assert.False(conversion.IsExtensionMethod); CommonConversion commonConversion = conversion.ToCommonConversion(); Assert.True(commonConversion.Exists); Assert.True(commonConversion.IsImplicit); Assert.True(commonConversion.IsUnion); Assert.False(commonConversion.IsUserDefined); AssertEx.Equal("S1..ctor(System.Int32 x)", commonConversion.MethodSymbol.ToTestDisplayString()); VerifyOperationTreeForTest<ReturnStatementSyntax>(comp, """ IReturnOperation (OperationKind.Return, Type: null) (Syntax: 'return 10;') ReturnedValue: IConversionOperation (TryCast: False, Unchecked) (OperationKind.Conversion, Type: S1?, IsImplicit) (Syntax: '10') Conversion: CommonConversion (Exists: True, IsIdentity: False, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) Operand: IConversionOperation (TryCast: False, Unchecked) (OperatorMethod: S1..ctor(System.Int32 x)) (OperationKind.Conversion, Type: S1, IsImplicit) (Syntax: '10') Conversion: CommonConversion (Exists: True, IsIdentity: False, IsNumeric: False, IsReference: False, IsUserDefined: False, IsUnion: True) (MethodSymbol: S1..ctor(System.Int32 x)) Operand: ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 10) (Syntax: '10') """); var verifier = CompileAndVerify(comp, expectedOutput: "1-int {10} [not null] 2-null 3-[not null] 4-null 5-string {11} [not null]").VerifyDiagnostics(); verifier.VerifyIL("Program.Test1", @" { // Code size 23 (0x17) .maxstack 1 IL_0000: ldstr ""1-"" IL_0005: call ""void System.Console.Write(string)"" IL_000a: ldc.i4.s 10 IL_000c: newobj ""S1..ctor(int)"" IL_0011: newobj ""S1?..ctor(S1)"" IL_0016: ret } "); verifier.VerifyIL("Program.Test2", @" { // Code size 20 (0x14) .maxstack 1 .locals init (S1? V_0) IL_0000: ldstr ""2-"" IL_0005: call ""void System.Console.Write(string)"" IL_000a: ldloca.s V_0 IL_000c: initobj ""S1?"" IL_0012: ldloc.0 IL_0013: ret } "); verifier.VerifyIL("Program.Test3", @" { // Code size 25 (0x19) .maxstack 1 .locals init (S1 V_0) IL_0000: ldstr ""3-"" IL_0005: call ""void System.Console.Write(string)"" IL_000a: ldloca.s V_0 IL_000c: initobj ""S1"" IL_0012: ldloc.0 IL_0013: newobj ""S1?..ctor(S1)"" IL_0018: ret } "); verifier.VerifyIL("Program.Test4", @" { // Code size 20 (0x14) .maxstack 1 .locals init (S1? V_0) IL_0000: ldstr ""4-"" IL_0005: call ""void System.Console.Write(string)"" IL_000a: ldloca.s V_0 IL_000c: initobj ""S1?"" IL_0012: ldloc.0 IL_0013: ret } "); verifier.VerifyIL("Program.Test5", @" { // Code size 26 (0x1a) .maxstack 1 IL_0000: ldstr ""5-"" IL_0005: call ""void System.Console.Write(string)"" IL_000a: ldstr ""11"" IL_000f: newobj ""S1..ctor(string)"" IL_0014: newobj ""S1?..ctor(S1)"" IL_0019: ret } "); } [Fact] public void UnionConversion_37_Cast_ToNullableOfUnion() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 { private readonly object _value; public S1(int x) { System.Console.Write(""int {""); System.Console.Write(x); System.Console.Write(""} ""); _value = x; } public S1(string x) { System.Console.Write(""string {""); System.Console.Write(x); System.Console.Write(""} ""); _value = x; } public object Value => _value; } class Program { static void Main() { System.Console.Write(Test1().HasValue ? ""[not null] "" : ""null ""); System.Console.Write(Test2().HasValue ? ""[not null] "" : ""null ""); System.Console.Write(Test3().HasValue ? ""[not null] "" : ""null ""); System.Console.Write(Test4().HasValue ? ""[not null] "" : ""null ""); System.Console.Write(Test5().HasValue ? ""[not null] "" : ""null ""); } static S1? Test1() { System.Console.Write(""1-""); return /*<bind>*/ (S1?)10 /*</bind>*/; } static S1? Test2() { System.Console.Write(""2-""); return (S1?)default; } static S1? Test3() { System.Console.Write(""3-""); return (S1?)default(S1); } static S1? Test4() { System.Console.Write(""4-""); return (S1?)null; } static S1? Test5() { System.Console.Write(""5-""); return (S1?)""11""; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var cast = GetSyntax<CastExpressionSyntax>(tree, "(S1?)10"); var typeInfo = model.GetTypeInfo(cast); Assert.Equal("S1?", typeInfo.Type.ToTestDisplayString()); Assert.Equal("S1?", typeInfo.ConvertedType.ToTestDisplayString()); Conversion conversion = model.GetConversion(cast); Assert.True(conversion.IsIdentity); var symbolInfo = model.GetSymbolInfo(cast); Assert.Equal(CandidateReason.None, symbolInfo.CandidateReason); AssertEx.Equal("S1..ctor(System.Int32 x)", symbolInfo.Symbol.ToTestDisplayString()); Assert.Empty(symbolInfo.CandidateSymbols); VerifyOperationTreeForTest<CastExpressionSyntax>(comp, """ IConversionOperation (TryCast: False, Unchecked) (OperationKind.Conversion, Type: S1?) (Syntax: '(S1?)10') Conversion: CommonConversion (Exists: True, IsIdentity: False, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) Operand: IConversionOperation (TryCast: False, Unchecked) (OperatorMethod: S1..ctor(System.Int32 x)) (OperationKind.Conversion, Type: S1, IsImplicit) (Syntax: '(S1?)10') Conversion: CommonConversion (Exists: True, IsIdentity: False, IsNumeric: False, IsReference: False, IsUserDefined: False, IsUnion: True) (MethodSymbol: S1..ctor(System.Int32 x)) Operand: ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 10) (Syntax: '10') """); var ten = GetSyntax<LiteralExpressionSyntax>(tree, "10"); typeInfo = model.GetTypeInfo(ten); Assert.Equal("System.Int32", typeInfo.Type.ToTestDisplayString()); Assert.Equal("System.Int32", typeInfo.ConvertedType.ToTestDisplayString()); conversion = model.GetConversion(ten); Assert.True(conversion.IsIdentity); var verifier = CompileAndVerify(comp, expectedOutput: "1-int {10} [not null] 2-null 3-[not null] 4-null 5-string {11} [not null]").VerifyDiagnostics(); verifier.VerifyIL("Program.Test1", @" { // Code size 23 (0x17) .maxstack 1 IL_0000: ldstr ""1-"" IL_0005: call ""void System.Console.Write(string)"" IL_000a: ldc.i4.s 10 IL_000c: newobj ""S1..ctor(int)"" IL_0011: newobj ""S1?..ctor(S1)"" IL_0016: ret } "); verifier.VerifyIL("Program.Test2", @" { // Code size 20 (0x14) .maxstack 1 .locals init (S1? V_0) IL_0000: ldstr ""2-"" IL_0005: call ""void System.Console.Write(string)"" IL_000a: ldloca.s V_0 IL_000c: initobj ""S1?"" IL_0012: ldloc.0 IL_0013: ret } "); verifier.VerifyIL("Program.Test3", @" { // Code size 25 (0x19) .maxstack 1 .locals init (S1 V_0) IL_0000: ldstr ""3-"" IL_0005: call ""void System.Console.Write(string)"" IL_000a: ldloca.s V_0 IL_000c: initobj ""S1"" IL_0012: ldloc.0 IL_0013: newobj ""S1?..ctor(S1)"" IL_0018: ret } "); verifier.VerifyIL("Program.Test4", @" { // Code size 20 (0x14) .maxstack 1 .locals init (S1? V_0) IL_0000: ldstr ""4-"" IL_0005: call ""void System.Console.Write(string)"" IL_000a: ldloca.s V_0 IL_000c: initobj ""S1?"" IL_0012: ldloc.0 IL_0013: ret } "); verifier.VerifyIL("Program.Test5", @" { // Code size 26 (0x1a) .maxstack 1 IL_0000: ldstr ""5-"" IL_0005: call ""void System.Console.Write(string)"" IL_000a: ldstr ""11"" IL_000f: newobj ""S1..ctor(string)"" IL_0014: newobj ""S1?..ctor(S1)"" IL_0019: ret } "); } [Fact] public void UnionConversion_38_Standard_Conversion_For_Source_Allowed_ToNullableOfUnion() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 { private readonly object _value; public S1(int x) { System.Console.Write(""int {""); System.Console.Write(x); System.Console.Write(""} ""); _value = x; } public S1(string x) => throw null; public object Value => _value; } class Program { static void Main() { Test1(15); Test2(16); } static S1? Test1(byte x1) { return x1; } static S1? Test2(byte x2) { return (S1?)x2; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); CompileAndVerify(comp, expectedOutput: "int {15} int {16}").VerifyDiagnostics(); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var x1 = GetSyntax<IdentifierNameSyntax>(tree, "x1"); var symbolInfo = model.GetSymbolInfo(x1); Assert.Equal(CandidateReason.None, symbolInfo.CandidateReason); AssertEx.Equal("System.Byte x1", symbolInfo.Symbol.ToTestDisplayString()); Assert.Empty(symbolInfo.CandidateSymbols); var typeInfo = model.GetTypeInfo(x1); Assert.Equal("System.Byte", typeInfo.Type.ToTestDisplayString()); Assert.Equal("S1?", typeInfo.ConvertedType.ToTestDisplayString()); Conversion conversion = model.GetConversion(x1); Assert.True(conversion.IsUnion); Assert.False(conversion.IsUserDefined); AssertEx.Equal("S1..ctor(System.Int32 x)", conversion.Method.ToTestDisplayString()); Assert.Null(conversion.BestUserDefinedConversionAnalysis); Assert.Equal(Conversion.NoConversion, conversion.UserDefinedFromConversion); Assert.Equal(Conversion.NoConversion, conversion.UserDefinedToConversion); Assert.NotNull(conversion.BestUnionConversionAnalysis); AssertEx.SequenceEqual(["S1..ctor(System.Int32 x)"], conversion.OriginalUserDefinedOrUnionConversions.ToTestDisplayStrings()); Assert.True(conversion.UnderlyingConversions.IsDefault); CommonConversion commonConversion = conversion.ToCommonConversion(); Assert.True(commonConversion.Exists); Assert.True(commonConversion.IsImplicit); Assert.True(commonConversion.IsUnion); Assert.False(commonConversion.IsUserDefined); AssertEx.Equal("S1..ctor(System.Int32 x)", commonConversion.MethodSymbol.ToTestDisplayString()); VerifyOperationTreeForNode(comp, model, GetSyntax<ReturnStatementSyntax>(tree, "return x1;"), """ IReturnOperation (OperationKind.Return, Type: null) (Syntax: 'return x1;') ReturnedValue: IConversionOperation (TryCast: False, Unchecked) (OperationKind.Conversion, Type: S1?, IsImplicit) (Syntax: 'x1') Conversion: CommonConversion (Exists: True, IsIdentity: False, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) Operand: IConversionOperation (TryCast: False, Unchecked) (OperatorMethod: S1..ctor(System.Int32 x)) (OperationKind.Conversion, Type: S1, IsImplicit) (Syntax: 'x1') Conversion: CommonConversion (Exists: True, IsIdentity: False, IsNumeric: False, IsReference: False, IsUserDefined: False, IsUnion: True) (MethodSymbol: S1..ctor(System.Int32 x)) Operand: IConversionOperation (TryCast: False, Unchecked) (OperationKind.Conversion, Type: System.Int32, IsImplicit) (Syntax: 'x1') Conversion: CommonConversion (Exists: True, IsIdentity: False, IsNumeric: True, IsReference: False, IsUserDefined: False) (MethodSymbol: null) Operand: IParameterReferenceOperation: x1 (OperationKind.ParameterReference, Type: System.Byte) (Syntax: 'x1') """); var x2 = GetSyntax<IdentifierNameSyntax>(tree, "x2"); symbolInfo = model.GetSymbolInfo(x2); Assert.Equal(CandidateReason.None, symbolInfo.CandidateReason); AssertEx.Equal("System.Byte x2", symbolInfo.Symbol.ToTestDisplayString()); Assert.Empty(symbolInfo.CandidateSymbols); typeInfo = model.GetTypeInfo(x2); Assert.Equal("System.Byte", typeInfo.Type.ToTestDisplayString()); Assert.Equal("System.Byte", typeInfo.ConvertedType.ToTestDisplayString()); conversion = model.GetConversion(x2); Assert.True(conversion.IsIdentity); Assert.False(conversion.IsUnion); Assert.False(conversion.IsUserDefined); var cast = GetSyntax<CastExpressionSyntax>(tree, "(S1?)x2"); symbolInfo = model.GetSymbolInfo(cast); Assert.Equal(CandidateReason.None, symbolInfo.CandidateReason); AssertEx.Equal("S1..ctor(System.Int32 x)", symbolInfo.Symbol.ToTestDisplayString()); Assert.Empty(symbolInfo.CandidateSymbols); typeInfo = model.GetTypeInfo(cast); Assert.Equal("S1?", typeInfo.Type.ToTestDisplayString()); Assert.Equal("S1?", typeInfo.ConvertedType.ToTestDisplayString()); VerifyOperationTreeForNode(comp, model, GetSyntax<ReturnStatementSyntax>(tree, "return (S1?)x2;"), """ IReturnOperation (OperationKind.Return, Type: null) (Syntax: 'return (S1?)x2;') ReturnedValue: IConversionOperation (TryCast: False, Unchecked) (OperationKind.Conversion, Type: S1?) (Syntax: '(S1?)x2') Conversion: CommonConversion (Exists: True, IsIdentity: False, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) Operand: IConversionOperation (TryCast: False, Unchecked) (OperatorMethod: S1..ctor(System.Int32 x)) (OperationKind.Conversion, Type: S1, IsImplicit) (Syntax: '(S1?)x2') Conversion: CommonConversion (Exists: True, IsIdentity: False, IsNumeric: False, IsReference: False, IsUserDefined: False, IsUnion: True) (MethodSymbol: S1..ctor(System.Int32 x)) Operand: IConversionOperation (TryCast: False, Unchecked) (OperationKind.Conversion, Type: System.Int32, IsImplicit) (Syntax: '(S1?)x2') Conversion: CommonConversion (Exists: True, IsIdentity: False, IsNumeric: True, IsReference: False, IsUserDefined: False) (MethodSymbol: null) Operand: IParameterReferenceOperation: x2 (OperationKind.ParameterReference, Type: System.Byte) (Syntax: 'x2') """); } [Fact] public void UnionConversion_39_Implicit_UserDefined_Conversion_Wins_ToNullableOfUnion() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 { public S1(int x) => throw null; public S1(string x) { System.Console.Write(""string {""); System.Console.Write(x); System.Console.Write(""} ""); } public object Value => throw null; public static implicit operator S1(int x) { System.Console.Write(""implicit operator ""); return new S1(x.ToString()); } } class Program { static void Main() { Test1(); Test2(); } static S1? Test1() { return 10; } static S1? Test2() { return (S1?)20; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); CompileAndVerify(comp, expectedOutput: "implicit operator string {10} implicit operator string {20}").VerifyDiagnostics(); } [Fact] public void UnionConversion_40_Cast_Explicit_UserDefined_Conversion_Wins_ToNullableOfUnion() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 { public S1(int x) => throw null; public S1(string x) { System.Console.Write(""string {""); System.Console.Write(x); System.Console.Write(""} ""); } public object Value => throw null; public static explicit operator S1(int x) { System.Console.Write(""explicit operator ""); return new S1(x.ToString()); } } class Program { static void Main() { Test2(); } static S1? Test2() { return (S1?)20; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); CompileAndVerify(comp, expectedOutput: "explicit operator string {20}").VerifyDiagnostics(); } [Fact] public void UnionConversion_41_Explicit_UserDefined_Conversion_Loses_ToNullableOfUnion() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 { public S1(int x) { System.Console.Write(""int {""); System.Console.Write(x); System.Console.Write(""} ""); } public S1(string x) => throw null; public object Value => throw null; public static explicit operator S1(int x) => throw null; } class Program { static void Main() { Test1(); } static S1? Test1() { return 10; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); CompileAndVerify(comp, expectedOutput: "int {10}").VerifyDiagnostics(); } [Fact] public void UnionConversion_42_Under_Tuple_Conversion_ToNullableOfUnion() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 { public S1(double x) { System.Console.Write(""double {""); System.Console.Write((int)x); System.Console.Write(""} ""); } public S1(string x) => throw null; public object Value => throw null; } class Program { static void Main() { Test1((0, 10)); } static (int, S1?) Test1((int, byte) x) { return x; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); var verifier = CompileAndVerify(comp, expectedOutput: "double {10}").VerifyDiagnostics(); verifier.VerifyIL("Program.Test1", @" { // Code size 31 (0x1f) .maxstack 2 .locals init (System.ValueTuple<int, byte> V_0) IL_0000: ldarg.0 IL_0001: stloc.0 IL_0002: ldloc.0 IL_0003: ldfld ""int System.ValueTuple<int, byte>.Item1"" IL_0008: ldloc.0 IL_0009: ldfld ""byte System.ValueTuple<int, byte>.Item2"" IL_000e: conv.r8 IL_000f: newobj ""S1..ctor(double)"" IL_0014: newobj ""S1?..ctor(S1)"" IL_0019: newobj ""System.ValueTuple<int, S1?>..ctor(int, S1?)"" IL_001e: ret } "); } [Fact] public void UnionConversion_43_From_TupleLiteral() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 { private readonly object _value; public S1((int, object) x) { System.Console.Write(""(int, object) {""); System.Console.Write(x); System.Console.Write(""} ""); _value = x; } public S1(string x) { System.Console.Write(""string {""); System.Console.Write(x); System.Console.Write(""} ""); _value = x; } public object Value => _value; } class Program { static void Main() { Test1(); } static S1 Test1() { return (10, null); } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var tuple = GetSyntax<TupleExpressionSyntax>(tree, "(10, null)"); var symbolInfo = model.GetSymbolInfo(tuple); Assert.Equal(CandidateReason.None, symbolInfo.CandidateReason); Assert.Null(symbolInfo.Symbol); Assert.Empty(symbolInfo.CandidateSymbols); var typeInfo = model.GetTypeInfo(tuple); Assert.Null(typeInfo.Type); Assert.Equal("S1", typeInfo.ConvertedType.ToTestDisplayString()); Conversion conversion = model.GetConversion(tuple); Assert.Equal(ConversionKind.Union, conversion.Kind); Assert.Equal(LookupResultKind.Viable, conversion.ResultKind); Assert.True(conversion.IsUnion); AssertEx.Equal("S1..ctor((System.Int32, System.Object) x)", conversion.Method.ToTestDisplayString()); AssertEx.Equal("S1..ctor((System.Int32, System.Object) x)", conversion.MethodSymbol.ToTestDisplayString()); CommonConversion commonConversion = conversion.ToCommonConversion(); Assert.True(commonConversion.Exists); Assert.True(commonConversion.IsImplicit); Assert.True(commonConversion.IsUnion); Assert.False(commonConversion.IsUserDefined); AssertEx.Equal("S1..ctor((System.Int32, System.Object) x)", commonConversion.MethodSymbol.ToTestDisplayString()); CompileAndVerify(comp, expectedOutput: "(int, object) {(10, )}").VerifyDiagnostics(); } [Fact] public void UnionConversion_44_From_TupleLiteral() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 { private readonly object _value; public S1((int, object) x) { System.Console.Write(""(int, object) {""); System.Console.Write(x); System.Console.Write(""} ""); _value = x; } public S1(string x) { System.Console.Write(""string {""); System.Console.Write(x); System.Console.Write(""} ""); _value = x; } public object Value => _value; } class Program { static void Main() { Test1(); } static S1 Test1() { return ((byte)10, null); } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var tuple = GetSyntax<TupleExpressionSyntax>(tree, "((byte)10, null)"); var symbolInfo = model.GetSymbolInfo(tuple); Assert.Equal(CandidateReason.None, symbolInfo.CandidateReason); Assert.Null(symbolInfo.Symbol); Assert.Empty(symbolInfo.CandidateSymbols); var typeInfo = model.GetTypeInfo(tuple); Assert.Null(typeInfo.Type); Assert.Equal("S1", typeInfo.ConvertedType.ToTestDisplayString()); Conversion conversion = model.GetConversion(tuple); Assert.Equal(ConversionKind.Union, conversion.Kind); Assert.Equal(LookupResultKind.Viable, conversion.ResultKind); Assert.True(conversion.IsUnion); AssertEx.Equal("S1..ctor((System.Int32, System.Object) x)", conversion.Method.ToTestDisplayString()); AssertEx.Equal("S1..ctor((System.Int32, System.Object) x)", conversion.MethodSymbol.ToTestDisplayString()); CommonConversion commonConversion = conversion.ToCommonConversion(); Assert.True(commonConversion.Exists); Assert.True(commonConversion.IsImplicit); Assert.True(commonConversion.IsUnion); Assert.False(commonConversion.IsUserDefined); AssertEx.Equal("S1..ctor((System.Int32, System.Object) x)", commonConversion.MethodSymbol.ToTestDisplayString()); CompileAndVerify(comp, expectedOutput: "(int, object) {(10, )}").VerifyDiagnostics(); } [Fact] public void UnionConversion_45_From_TupleLiteral_ToNullableOfUnion() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 { private readonly object _value; public S1((int, object) x) { System.Console.Write(""(int, object) {""); System.Console.Write(x); System.Console.Write(""} ""); _value = x; } public S1(string x) { System.Console.Write(""string {""); System.Console.Write(x); System.Console.Write(""} ""); _value = x; } public object Value => _value; } class Program { static void Main() { Test1(); } static S1? Test1() { return ((byte)10, null); } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var tuple = GetSyntax<TupleExpressionSyntax>(tree, "((byte)10, null)"); var symbolInfo = model.GetSymbolInfo(tuple); Assert.Equal(CandidateReason.None, symbolInfo.CandidateReason); Assert.Null(symbolInfo.Symbol); Assert.Empty(symbolInfo.CandidateSymbols); var typeInfo = model.GetTypeInfo(tuple); Assert.Null(typeInfo.Type); Assert.Equal("S1?", typeInfo.ConvertedType.ToTestDisplayString()); Conversion conversion = model.GetConversion(tuple); Assert.Equal(ConversionKind.Union, conversion.Kind); Assert.Equal(LookupResultKind.Viable, conversion.ResultKind); Assert.True(conversion.IsUnion); AssertEx.Equal("S1..ctor((System.Int32, System.Object) x)", conversion.Method.ToTestDisplayString()); AssertEx.Equal("S1..ctor((System.Int32, System.Object) x)", conversion.MethodSymbol.ToTestDisplayString()); CommonConversion commonConversion = conversion.ToCommonConversion(); Assert.True(commonConversion.Exists); Assert.True(commonConversion.IsImplicit); Assert.True(commonConversion.IsUnion); Assert.False(commonConversion.IsUserDefined); AssertEx.Equal("S1..ctor((System.Int32, System.Object) x)", commonConversion.MethodSymbol.ToTestDisplayString()); CompileAndVerify(comp, expectedOutput: "(int, object) {(10, )}").VerifyDiagnostics(); } [Fact] public void UnionConversion_46_Implicit_Ambiguous_UserDefined_Conversion_Shadows() { var src = @" [System.Runtime.CompilerServices.Union] public struct S1 { public S1(S2 x) => throw null; public S1(string x) => throw null; public object Value => throw null; public static implicit operator S1(S2 x) => throw null; } public struct S2 { public static implicit operator S1(S2 x) => throw null; } class Program { static S1 Test2(S2 x) { #line 20 return x; } } "; var comp = CreateCompilation([src, UnionAttributeSource]); comp.VerifyDiagnostics( // (20,16): error CS0457: Ambiguous user defined conversions 'S2.implicit operator S1(S2)' and 'S1.implicit operator S1(S2)' when converting from 'S2' to 'S1' // return x; Diagnostic(ErrorCode.ERR_AmbigUDConv, "x").WithArguments("S2.implicit operator S1(S2)", "S1.implicit operator S1(S2)", "S2", "S1").WithLocation(20, 16) ); } [Fact] public void UnionConversion_47_Cast_Emplicit_Ambiguous_UserDefined_Conversion_Shadows() { var src = @" [System.Runtime.CompilerServices.Union] public struct S1 { public S1(S2 x) => throw null; public S1(string x) => throw null; public object Value => throw null; public static explicit operator S1(S2 x) => throw null; } public struct S2 { public static explicit operator S1(S2 x) => throw null; } class Program { static S1 Test2(S2 x) { #line 20 return (S1)x; } } "; var comp = CreateCompilation([src, UnionAttributeSource]); comp.VerifyDiagnostics( // (20,16): error CS0457: Ambiguous user defined conversions 'S2.explicit operator S1(S2)' and 'S1.explicit operator S1(S2)' when converting from 'S2' to 'S1' // return (S1)x; Diagnostic(ErrorCode.ERR_AmbigUDConv, "(S1)x").WithArguments("S2.explicit operator S1(S2)", "S1.explicit operator S1(S2)", "S2", "S1").WithLocation(20, 16) ); } [Fact] public void UnionConversion_48_Construction_Errors() { var src = @" [System.Runtime.CompilerServices.Union] public abstract class C1 { public C1(int x) => throw null; public C1(string x) => throw null; public object Value => throw null; } [System.Runtime.CompilerServices.Union] public class C2 { public C2(int x) => throw null; public C2(string x) => throw null; public object Value => throw null; public required int Prop { get; set; } } class Program { static C1 Test1(int x) { #line 100 return new C1(x); } static C1 Test2(int x) { #line 200 return x; } static C2 Test3(int x) { #line 300 return new C2(x); } static C2 Test4(int x) { #line 400 return x; } } "; var comp = CreateCompilation([src, UnionAttributeSource], targetFramework: TargetFramework.Net100); comp.VerifyDiagnostics( // (100,16): error CS0144: Cannot create an instance of the abstract type or interface 'C1' // return new C1(x); Diagnostic(ErrorCode.ERR_NoNewAbstract, "new C1(x)").WithArguments("C1").WithLocation(100, 16), // (200,16): error CS0144: Cannot create an instance of the abstract type or interface 'C1' // return x; Diagnostic(ErrorCode.ERR_NoNewAbstract, "x").WithArguments("C1").WithLocation(200, 16), // (300,20): error CS9035: Required member 'C2.Prop' must be set in the object initializer or attribute constructor. // return new C2(x); Diagnostic(ErrorCode.ERR_RequiredMemberMustBeSet, "C2").WithArguments("C2.Prop").WithLocation(300, 20), // (400,16): error CS9035: Required member 'C2.Prop' must be set in the object initializer or attribute constructor. // return x; Diagnostic(ErrorCode.ERR_RequiredMemberMustBeSet, "x").WithArguments("C2.Prop").WithLocation(400, 16) ); } [Fact] public void UnionConversion_49_From_Dynamic() { var src = @" [System.Runtime.CompilerServices.Union] public struct S1 { public S1(int x) => throw null; public S1(string x) => throw null; public object Value => throw null; } class Program { static void Main() { try { Test1(1); } catch (Microsoft.CSharp.RuntimeBinder.RuntimeBinderException) { System.Console.WriteLine(""RuntimeBinderException caught""); } } static S1 Test1(dynamic x) { return x; } } "; var comp = CreateCompilation([src, UnionAttributeSource], targetFramework: TargetFramework.StandardAndCSharp, options: TestOptions.DebugExe); // Conversion from dynamic is not a union conversion. CompileAndVerify(comp, expectedOutput: "RuntimeBinderException caught").VerifyDiagnostics(); } [Fact] public void UnionConversion_50_NullableConstructorParameter() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 { private readonly object _value; public S1(int? x) { System.Console.Write(""int? {""); System.Console.Write(x); System.Console.Write(""} ""); _value = x; } public object Value => _value; } class Program { static void Main() { Test1(); Test2(); } static S1 Test1() { System.Console.Write(""1-""); return (int?)null; } static S1 Test2() { System.Console.Write(""2-""); return null; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); var verifier = CompileAndVerify(comp, expectedOutput: "1-int? {} 2-int? {}").VerifyDiagnostics(); verifier.VerifyIL("Program.Test1", @" { // Code size 25 (0x19) .maxstack 1 .locals init (int? V_0) IL_0000: ldstr ""1-"" IL_0005: call ""void System.Console.Write(string)"" IL_000a: ldloca.s V_0 IL_000c: initobj ""int?"" IL_0012: ldloc.0 IL_0013: newobj ""S1..ctor(int?)"" IL_0018: ret } "); verifier.VerifyIL("Program.Test2", @" { // Code size 25 (0x19) .maxstack 1 .locals init (int? V_0) IL_0000: ldstr ""2-"" IL_0005: call ""void System.Console.Write(string)"" IL_000a: ldloca.s V_0 IL_000c: initobj ""int?"" IL_0012: ldloc.0 IL_0013: newobj ""S1..ctor(int?)"" IL_0018: ret } "); } [Fact] public void UnionConversion_51_NullableConstructorParameter() { var src = @" #nullable enable [System.Runtime.CompilerServices.Union] struct S1 { private readonly object? _value; public S1(string? x) { System.Console.Write(""string? {""); System.Console.Write(x); System.Console.Write(""} ""); _value = x; } public object? Value => _value; } class Program { static void Main() { Test1(); Test2(); } static S1 Test1() { System.Console.Write(""1-""); return (string?)null; } static S1 Test2() { System.Console.Write(""2-""); return null; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); var verifier = CompileAndVerify(comp, expectedOutput: "1-string? {} 2-string? {}").VerifyDiagnostics(); verifier.VerifyIL("Program.Test1", @" { // Code size 17 (0x11) .maxstack 1 IL_0000: ldstr ""1-"" IL_0005: call ""void System.Console.Write(string)"" IL_000a: ldnull IL_000b: newobj ""S1..ctor(string)"" IL_0010: ret } "); verifier.VerifyIL("Program.Test2", @" { // Code size 17 (0x11) .maxstack 1 IL_0000: ldstr ""2-"" IL_0005: call ""void System.Console.Write(string)"" IL_000a: ldnull IL_000b: newobj ""S1..ctor(string)"" IL_0010: ret } "); } [Fact] public void UnionConversion_52() { var src = @" class C1; [System.Runtime.CompilerServices.Union] struct S1 { public S1(C1 x) => throw null; public object Value => throw null; } class Program { static void Main() { Test1(); } static S1 Test1() { return new(); } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var expr = GetSyntax<ExpressionSyntax>(tree, "new()"); var symbolInfo = model.GetSymbolInfo(expr); Assert.Equal(CandidateReason.None, symbolInfo.CandidateReason); Assert.Equal("S1..ctor()", symbolInfo.Symbol.ToTestDisplayString()); var typeInfo = model.GetTypeInfo(expr); Assert.Equal("S1", typeInfo.Type.ToTestDisplayString()); Assert.Equal("S1", typeInfo.ConvertedType.ToTestDisplayString()); Conversion conversion = model.GetConversion(expr); Assert.True(conversion.Exists); Assert.True(conversion.IsValid); Assert.True(conversion.IsImplicit); Assert.False(conversion.IsExplicit); Assert.Equal(ConversionKind.ObjectCreation, conversion.Kind); var verifier = CompileAndVerify(comp).VerifyDiagnostics(); verifier.VerifyIL("Program.Test1", @" { // Code size 10 (0xa) .maxstack 1 .locals init (S1 V_0) IL_0000: ldloca.s V_0 IL_0002: initobj ""S1"" IL_0008: ldloc.0 IL_0009: ret } "); } [Fact] public void UnionConversion_53() { var src = @" class C1; class C2; [System.Runtime.CompilerServices.Union] struct S1 { public S1(C1 x) => throw null; public S1(C2 x) => throw null; public object Value => throw null; } class Program { static void Main() { Test1(); } static S1 Test1() { return (S1)new(); } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var cast = GetSyntax<CastExpressionSyntax>(tree, "(S1)new()"); var typeInfo = model.GetTypeInfo(cast); Assert.Equal("S1", typeInfo.Type.ToTestDisplayString()); Assert.Equal("S1", typeInfo.ConvertedType.ToTestDisplayString()); Conversion conversion = model.GetConversion(cast); Assert.True(conversion.IsIdentity); var symbolInfo = model.GetSymbolInfo(cast); Assert.Equal(CandidateReason.None, symbolInfo.CandidateReason); Assert.Null(symbolInfo.Symbol); Assert.Empty(symbolInfo.CandidateSymbols); var verifier = CompileAndVerify(comp).VerifyDiagnostics(); verifier.VerifyIL("Program.Test1", @" { // Code size 10 (0xa) .maxstack 1 .locals init (S1 V_0) IL_0000: ldloca.s V_0 IL_0002: initobj ""S1"" IL_0008: ldloc.0 IL_0009: ret } "); } [Fact] public void UnionConversion_54() { var src = @" class C1; class C2; [System.Runtime.CompilerServices.Union] class S1 { public S1(C1 x) => throw null; public S1(C2 x) => throw null; public object Value => throw null; } class Program { static void Main() { Test1(); } static S1 Test1() { #line 21 return new(); } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); comp.VerifyDiagnostics( // (21,16): error CS1729: 'S1' does not contain a constructor that takes 0 arguments // return new(); Diagnostic(ErrorCode.ERR_BadCtorArgCount, "new()").WithArguments("S1", "0").WithLocation(21, 16) ); } [Fact] public void UnionConversion_55() { var src = @" class C1; class C2; [System.Runtime.CompilerServices.Union] class S1 { public S1(C1 x) => throw null; public S1(C2 x) => throw null; public object Value => throw null; } class Program { static void Main() { Test1(); } static S1 Test1() { #line 21 return (S1)new(); } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); comp.VerifyDiagnostics( // (21,20): error CS1729: 'S1' does not contain a constructor that takes 0 arguments // return (S1)new(); Diagnostic(ErrorCode.ERR_BadCtorArgCount, "new()").WithArguments("S1", "0").WithLocation(21, 20) ); } [Fact] public void UnionConversion_56_OverloadResolution() { var src1 = @" [System.Runtime.CompilerServices.Union] public struct S1 { public S1(ushort x) { System.Console.Write(""ushort""); } public S1(int x) => throw null; public object Value => throw null; } [System.Runtime.CompilerServices.Union] public struct S2 { public S2(int x) => throw null; public S2(ushort x) { System.Console.Write(""ushort""); } public object Value => throw null; } "; var src2 = @" class Program { static void Main() { Test1(10); Test2(10); } static S1 Test1(byte x) { return x; } static S2 Test2(byte x) { return x; } } "; var comp = CreateCompilation([src1, src2, UnionAttributeSource], options: TestOptions.ReleaseExe); CompileAndVerify(comp, expectedOutput: "ushortushort").VerifyDiagnostics(); comp = CreateCompilation(src2, references: [comp.EmitToImageReference()], options: TestOptions.ReleaseExe); CompileAndVerify(comp, expectedOutput: "ushortushort").VerifyDiagnostics(); } [Fact] public void UnionConversion_57_WriteConsideredUse() { var source = """ S s; s = (S)100; union S(int); """; CreateCompilation([source, UnionAttributeSource, IUnionSource]).VerifyDiagnostics(); } [Fact] public void UnionConversion_58_DefaultValue() { var source = """ union S(int) { static void M1(S v = 1) {} } """; CreateCompilation([source, UnionAttributeSource, IUnionSource]).VerifyDiagnostics( // (3,22): error CS1750: A value of type 'int' cannot be used as a default parameter because there are no standard conversions to type 'S' // static void M1(S v = 1) Diagnostic(ErrorCode.ERR_NoConversionForDefaultParam, "v").WithArguments("int", "S").WithLocation(3, 22) ); } [Fact] public void UnionConversion_MemberProvider_01_Implicit() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 : S1.IUnionMembers { private readonly object _value; S1(int x) { System.Console.Write(""int {""); System.Console.Write(x); System.Console.Write(""} ""); _value = x; } S1(string x) { System.Console.Write(""string {""); System.Console.Write(x); System.Console.Write(""} ""); _value = x; } object IUnionMembers.Value => _value; public interface IUnionMembers { public static S1 Create(int x) => new S1(x); public static S1 Create(string x) => new S1(x); public object Value { get; } } } class Program { static void Main() { Test1(); Test2(); Test3(); Test4(); Test5(); } static S1 Test1() { #line 36 System.Console.Write(""1-""); /*<bind>*/ return 10; /*</bind>*/ } static S1 Test2() { System.Console.Write(""2-""); return default; } static S1 Test3() { System.Console.Write(""3-""); return default(S1); } static S1 Test4() { System.Console.Write(""4-""); #line 55 return null; } static S1 Test5() { System.Console.Write(""5-""); #line 61 return ""11""; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var ten = GetSyntax<LiteralExpressionSyntax>(tree, "10"); var symbolInfo = model.GetSymbolInfo(ten); Assert.Equal(CandidateReason.None, symbolInfo.CandidateReason); Assert.Null(symbolInfo.Symbol); Assert.Empty(symbolInfo.CandidateSymbols); var typeInfo = model.GetTypeInfo(ten); Assert.Equal("System.Int32", typeInfo.Type.ToTestDisplayString()); Assert.Equal("S1", typeInfo.ConvertedType.ToTestDisplayString()); Conversion conversion = model.GetConversion(ten); Assert.True(conversion.Exists); Assert.True(conversion.IsValid); Assert.True(conversion.IsImplicit); Assert.False(conversion.IsExplicit); Assert.Equal(ConversionKind.Union, conversion.Kind); Assert.Equal(LookupResultKind.Viable, conversion.ResultKind); Assert.True(conversion.IsUnion); Assert.False(conversion.IsUserDefined); AssertEx.Equal("S1 S1.IUnionMembers.Create(System.Int32 x)", conversion.Method.ToTestDisplayString()); AssertEx.Equal("S1 S1.IUnionMembers.Create(System.Int32 x)", conversion.MethodSymbol.ToTestDisplayString()); Assert.Null(conversion.BestUserDefinedConversionAnalysis); Assert.Equal(Conversion.NoConversion, conversion.UserDefinedFromConversion); Assert.Equal(Conversion.NoConversion, conversion.UserDefinedToConversion); Assert.NotNull(conversion.BestUnionConversionAnalysis); AssertEx.SequenceEqual(["S1 S1.IUnionMembers.Create(System.Int32 x)"], conversion.OriginalUserDefinedOrUnionConversions.ToTestDisplayStrings()); Assert.True(conversion.UnderlyingConversions.IsDefault); Assert.False(conversion.IsArrayIndex); Assert.False(conversion.IsExtensionMethod); CommonConversion commonConversion = conversion.ToCommonConversion(); Assert.True(commonConversion.Exists); Assert.True(commonConversion.IsImplicit); Assert.True(commonConversion.IsUnion); Assert.False(commonConversion.IsUserDefined); AssertEx.Equal("S1 S1.IUnionMembers.Create(System.Int32 x)", commonConversion.MethodSymbol.ToTestDisplayString()); VerifyOperationTreeForTest<ReturnStatementSyntax>(comp, """ IReturnOperation (OperationKind.Return, Type: null) (Syntax: 'return 10;') ReturnedValue: IConversionOperation (TryCast: False, Unchecked) (OperatorMethod: S1 S1.IUnionMembers.Create(System.Int32 x)) (OperationKind.Conversion, Type: S1, IsImplicit) (Syntax: '10') Conversion: CommonConversion (Exists: True, IsIdentity: False, IsNumeric: False, IsReference: False, IsUserDefined: False, IsUnion: True) (MethodSymbol: S1 S1.IUnionMembers.Create(System.Int32 x)) Operand: ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 10) (Syntax: '10') """); var verifier = CompileAndVerify(comp, expectedOutput: "1-int {10} 2-3-4-string {} 5-string {11}").VerifyDiagnostics(); verifier.VerifyIL("Program.Test1", @" { // Code size 18 (0x12) .maxstack 1 IL_0000: ldstr ""1-"" IL_0005: call ""void System.Console.Write(string)"" IL_000a: ldc.i4.s 10 IL_000c: call ""S1 S1.IUnionMembers.Create(int)"" IL_0011: ret } "); verifier.VerifyIL("Program.Test2", @" { // Code size 20 (0x14) .maxstack 1 .locals init (S1 V_0) IL_0000: ldstr ""2-"" IL_0005: call ""void System.Console.Write(string)"" IL_000a: ldloca.s V_0 IL_000c: initobj ""S1"" IL_0012: ldloc.0 IL_0013: ret } "); verifier.VerifyIL("Program.Test3", @" { // Code size 20 (0x14) .maxstack 1 .locals init (S1 V_0) IL_0000: ldstr ""3-"" IL_0005: call ""void System.Console.Write(string)"" IL_000a: ldloca.s V_0 IL_000c: initobj ""S1"" IL_0012: ldloc.0 IL_0013: ret } "); verifier.VerifyIL("Program.Test4", @" { // Code size 17 (0x11) .maxstack 1 IL_0000: ldstr ""4-"" IL_0005: call ""void System.Console.Write(string)"" IL_000a: ldnull IL_000b: call ""S1 S1.IUnionMembers.Create(string)"" IL_0010: ret } "); verifier.VerifyIL("Program.Test5", @" { // Code size 21 (0x15) .maxstack 1 IL_0000: ldstr ""5-"" IL_0005: call ""void System.Console.Write(string)"" IL_000a: ldstr ""11"" IL_000f: call ""S1 S1.IUnionMembers.Create(string)"" IL_0014: ret } "); comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular15); CompileAndVerify(comp, expectedOutput: "1-int {10} 2-3-4-string {} 5-string {11}").VerifyDiagnostics(); comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular14); comp.VerifyDiagnostics( // (25,26): error CS9327: Feature 'static members in interfaces' is not available in C# 14.0. Please use language version 15.0 or greater. // public static S1 Create(int x) => new S1(x); Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion14, "Create").WithArguments("static members in interfaces", "15.0").WithLocation(25, 26), // (26,26): error CS9327: Feature 'static members in interfaces' is not available in C# 14.0. Please use language version 15.0 or greater. // public static S1 Create(string x) => new S1(x); Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion14, "Create").WithArguments("static members in interfaces", "15.0").WithLocation(26, 26), // (37,27): error CS9327: Feature 'unions' is not available in C# 14.0. Please use language version 15.0 or greater. // /*<bind>*/ return 10; /*</bind>*/ Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion14, "10").WithArguments("unions", "15.0").WithLocation(37, 27), // (55,16): error CS9327: Feature 'unions' is not available in C# 14.0. Please use language version 15.0 or greater. // return null; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion14, "null").WithArguments("unions", "15.0").WithLocation(55, 16), // (61,16): error CS9327: Feature 'unions' is not available in C# 14.0. Please use language version 15.0 or greater. // return "11"; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion14, @"""11""").WithArguments("unions", "15.0").WithLocation(61, 16) ); } [Fact] public void UnionConversion_MemberProvider_02_Implicit_Class() { var src = @" [System.Runtime.CompilerServices.Union] class S1 : S1.IUnionMembers { private readonly object _value; S1(int x) { System.Console.Write(""int {""); System.Console.Write(x); System.Console.Write(""} ""); _value = x; } S1(string x) { System.Console.Write(""string {""); System.Console.Write(x); System.Console.Write(""} ""); _value = x; } object IUnionMembers.Value => _value; public interface IUnionMembers { public static S1 Create(int x) => new S1(x); public static S1 Create(string x) => new S1(x); public object Value { get; } } } class Program { static void Main() { Test1(); Test2(); Test3(); Test4(); Test5(); } static S1 Test1() { System.Console.Write(""1-""); return 10; } static S1 Test2() { System.Console.Write(""2-""); return default; } static S1 Test3() { System.Console.Write(""3-""); return default(S1); } static S1 Test4() { System.Console.Write(""4-""); return null; } static S1 Test5() { System.Console.Write(""5-""); return ""11""; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); var verifier = CompileAndVerify(comp, expectedOutput: "1-int {10} 2-3-4-5-string {11}").VerifyDiagnostics(); verifier.VerifyIL("Program.Test1", @" { // Code size 18 (0x12) .maxstack 1 IL_0000: ldstr ""1-"" IL_0005: call ""void System.Console.Write(string)"" IL_000a: ldc.i4.s 10 IL_000c: call ""S1 S1.IUnionMembers.Create(int)"" IL_0011: ret } "); verifier.VerifyIL("Program.Test2", @" { // Code size 12 (0xc) .maxstack 1 IL_0000: ldstr ""2-"" IL_0005: call ""void System.Console.Write(string)"" IL_000a: ldnull IL_000b: ret } "); verifier.VerifyIL("Program.Test3", @" { // Code size 12 (0xc) .maxstack 1 IL_0000: ldstr ""3-"" IL_0005: call ""void System.Console.Write(string)"" IL_000a: ldnull IL_000b: ret } "); verifier.VerifyIL("Program.Test4", @" { // Code size 12 (0xc) .maxstack 1 IL_0000: ldstr ""4-"" IL_0005: call ""void System.Console.Write(string)"" IL_000a: ldnull IL_000b: ret } "); verifier.VerifyIL("Program.Test5", @" { // Code size 21 (0x15) .maxstack 1 IL_0000: ldstr ""5-"" IL_0005: call ""void System.Console.Write(string)"" IL_000a: ldstr ""11"" IL_000f: call ""S1 S1.IUnionMembers.Create(string)"" IL_0014: ret } "); } [Theory] [CombinatorialData] public void UnionConversion_MemberProvider_03_Factory_AbstractOrVirtual(bool isClass, bool isAbstract) { var src = @" [System.Runtime.CompilerServices.Union] " + (isClass ? "class" : "struct") + @" S1 : S1.IUnionMembers { private readonly object _value; S1(int x) { System.Console.Write(""int {""); System.Console.Write(x); System.Console.Write(""} ""); _value = x; } S1(string x) { System.Console.Write(""string {""); System.Console.Write(x); System.Console.Write(""} ""); _value = x; } static S1 IUnionMembers.Create(int x) => new S1(x); static S1 IUnionMembers.Create(string x) => new S1(x); object IUnionMembers.Value => _value; public interface IUnionMembers { public " + (isAbstract ? "abstract" : "virtual") + @" static S1 Create(int x)" + (isAbstract ? ";" : " => throw null;") + @" public " + (isAbstract ? "abstract" : "virtual") + @" static S1 Create(string x)" + (isAbstract ? ";" : " => throw null;") + @" public object Value { get; } } } class Program { static void Main() { Test1(); Test5(); } static S1 Test1() { System.Console.Write(""1-""); return 10; } static S1 Test5() { System.Console.Write(""5-""); return ""11""; } } "; var comp = CreateCompilation([src, UnionAttributeSource], targetFramework: TargetFramework.NetCoreApp, options: TestOptions.ReleaseExe); // https://github.com/dotnet/roslyn/issues/82636: Fix verifier? var verifier = CompileAndVerify(comp, expectedOutput: ExecutionConditionUtil.IsMonoOrCoreClr ? "1-int {10} 5-string {11}" : null, verify: Verification.Skipped).VerifyDiagnostics(); verifier.VerifyIL("Program.Test1", @" { // Code size 24 (0x18) .maxstack 1 IL_0000: ldstr ""1-"" IL_0005: call ""void System.Console.Write(string)"" IL_000a: ldc.i4.s 10 IL_000c: constrained. ""S1"" IL_0012: call ""S1 S1.IUnionMembers.Create(int)"" IL_0017: ret } "); verifier.VerifyIL("Program.Test5", @" { // Code size 27 (0x1b) .maxstack 1 IL_0000: ldstr ""5-"" IL_0005: call ""void System.Console.Write(string)"" IL_000a: ldstr ""11"" IL_000f: constrained. ""S1"" IL_0015: call ""S1 S1.IUnionMembers.Create(string)"" IL_001a: ret } "); comp = CreateCompilation([src, UnionAttributeSource], targetFramework: TargetFramework.NetCoreApp, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular15); CompileAndVerify(comp, expectedOutput: ExecutionConditionUtil.IsMonoOrCoreClr ? "1-int {10} 5-string {11}" : null, verify: Verification.Skipped).VerifyDiagnostics(); comp = CreateCompilation([src, UnionAttributeSource], targetFramework: TargetFramework.NetCoreApp, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular14); comp.VerifyDiagnostics( // (45,16): error CS9327: Feature 'unions' is not available in C# 14.0. Please use language version 15.0 or greater. // return 10; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion14, "10").WithArguments("unions", "15.0").WithLocation(45, 16), // (51,16): error CS9327: Feature 'unions' is not available in C# 14.0. Please use language version 15.0 or greater. // return "11"; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion14, @"""11""").WithArguments("unions", "15.0").WithLocation(51, 16) ); } [Theory] [CombinatorialData] public void UnionConversion_MemberProvider_04_Factory_AbstractOrVirtual_NotSupportedByRuntime(bool isClass, bool isAbstract) { var src1 = @" [System.Runtime.CompilerServices.Union] public " + (isClass ? "class" : "struct") + @" S1 : S1.IUnionMembers { private readonly object _value; S1(int x) { System.Console.Write(""int {""); System.Console.Write(x); System.Console.Write(""} ""); _value = x; } S1(string x) { System.Console.Write(""string {""); System.Console.Write(x); System.Console.Write(""} ""); _value = x; } static S1 IUnionMembers.Create(int x) => new S1(x); static S1 IUnionMembers.Create(string x) => new S1(x); object IUnionMembers.Value => _value; public interface IUnionMembers { public " + (isAbstract ? "abstract" : "virtual") + @" static S1 Create(int x)" + (isAbstract ? ";" : " => throw null;") + @" public " + (isAbstract ? "abstract" : "virtual") + @" static S1 Create(string x)" + (isAbstract ? ";" : " => throw null;") + @" public object Value { get; } } } "; var src2 = @" class Program { static S1 Test1() { return 10; } } "; var comp1 = CreateCompilation([src1, UnionAttributeSource], targetFramework: TargetFramework.NetCoreApp); comp1.VerifyDiagnostics(); var comp2 = CreateCompilation(src2, references: [comp1.ToMetadataReference()], targetFramework: TargetFramework.Mscorlib461Extended); comp2.VerifyDiagnostics( // (6,16): error CS8919: Target runtime doesn't support static abstract members in interfaces. // return 10; Diagnostic(ErrorCode.ERR_RuntimeDoesNotSupportStaticAbstractMembersInInterfaces, "10").WithLocation(6, 16) ); } [Fact] public void UnionConversion_MemberProvider_05_NullableAnalysis() { var src = @" #nullable enable [System.Runtime.CompilerServices.Union] class S1 : S1.IUnionMembers { private readonly object _value; S1(int x) { System.Console.Write(""int {""); System.Console.Write(x); System.Console.Write(""} ""); _value = x; } object IUnionMembers.Value => _value; public interface IUnionMembers { public static S1? Create(int x) => new S1(x); public object Value { get; } } } class Program { static S1 Test1() { return 10; } } "; var comp = CreateCompilation([src, UnionAttributeSource]); comp.VerifyDiagnostics( // (30,16): warning CS8603: Possible null reference return. // return 10; Diagnostic(ErrorCode.WRN_NullReferenceReturn, "10").WithLocation(30, 16) ); } [Fact] public void UnionConversion_MemberProvider_06_Ambiguity_In_Vs_Val() { var src1 = @" [System.Runtime.CompilerServices.Union] public struct S1 : S1.IUnionMembers { public interface IUnionMembers { public static S1 Create(in int x) => throw null; public static S1 Create(int x) => throw null; public static S1 Create(string x) => throw null; public object Value { get; } } public object Value => throw null; } [System.Runtime.CompilerServices.Union] public struct S2 : S2.IUnionMembers { public interface IUnionMembers { public static S2 Create(int x) => throw null; public static S2 Create(in int x) => throw null; public static S2 Create(string x) => throw null; public object Value { get; } } public object Value => throw null; } "; var src2 = @" class Program { static S1 Test1() { #line 100 return 10; } static S2 Test2() { #line 200 return (S2)10; } } "; var comp = CreateCompilation([src1, src2, UnionAttributeSource]); comp.VerifyDiagnostics( // (100,16): error CS0457: Ambiguous user defined conversions 'S1.IUnionMembers.Create(in int)' and 'S1.IUnionMembers.Create(int)' when converting from 'int' to 'S1' // return 10; Diagnostic(ErrorCode.ERR_AmbigUDConv, "10").WithArguments("S1.IUnionMembers.Create(in int)", "S1.IUnionMembers.Create(int)", "int", "S1").WithLocation(100, 16), // (200,16): error CS0457: Ambiguous user defined conversions 'S2.IUnionMembers.Create(int)' and 'S2.IUnionMembers.Create(in int)' when converting from 'int' to 'S2' // return (S2)10; Diagnostic(ErrorCode.ERR_AmbigUDConv, "(S2)10").WithArguments("S2.IUnionMembers.Create(int)", "S2.IUnionMembers.Create(in int)", "int", "S2").WithLocation(200, 16) ); var tree = comp.SyntaxTrees[1]; var model = comp.GetSemanticModel(tree); var cast = GetSyntax<CastExpressionSyntax>(tree, "(S2)10"); var typeInfo = model.GetTypeInfo(cast); Assert.Equal("S2", typeInfo.Type.ToTestDisplayString()); Assert.Equal("S2", typeInfo.ConvertedType.ToTestDisplayString()); Conversion conversion = model.GetConversion(cast); Assert.True(conversion.IsIdentity); var symbolInfo = model.GetSymbolInfo(cast); Assert.Equal(CandidateReason.OverloadResolutionFailure, symbolInfo.CandidateReason); Assert.Null(symbolInfo.Symbol); AssertEx.SequenceEqual(["S2 S2.IUnionMembers.Create(System.Int32 x)", "S2 S2.IUnionMembers.Create(in System.Int32 x)"], symbolInfo.CandidateSymbols.ToTestDisplayStrings()); } [Fact] public void UnionConversion_MemberProvider_07_Inheritance() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 : S1.IUnionMembers { private readonly object _value; S1(int x) { System.Console.Write(""int {""); System.Console.Write(x); System.Console.Write(""} ""); _value = x; } S1(string x) => throw null; object IUnionMembers.Value => _value; public interface IUnionMembers : IBase { public static S1 Create(string x) => new S1(x); public object Value { get; } } public interface IBase { public static S1 Create(int x) => new S1(x); } } class Program { static void Main() { Test1(); } static S1 Test1() { return 10; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); var verifier = CompileAndVerify(comp, expectedOutput: "int {10}").VerifyDiagnostics(); verifier.VerifyIL("Program.Test1", @" { // Code size 8 (0x8) .maxstack 1 IL_0000: ldc.i4.s 10 IL_0002: call ""S1 S1.IBase.Create(int)"" IL_0007: ret } "); } [Fact] public void UnionConversion_MemberProvider_08_Inheritance() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 : S1.IUnionMembers { private readonly object _value; S1(int x) { System.Console.Write(""int {""); System.Console.Write(x); System.Console.Write(""} ""); _value = x; } S1(string x) => throw null; object IUnionMembers.Value => _value; public interface IUnionMembers : IBase2 { public static S1 Create(string x) => new S1(x); public object Value { get; } } public interface IBase2 : IBase1 { } public interface IBase1 { public static S1 Create(int x) => new S1(x); } } class Program { static void Main() { Test1(); } static S1 Test1() { return 10; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); var verifier = CompileAndVerify(comp, expectedOutput: "int {10}").VerifyDiagnostics(); verifier.VerifyIL("Program.Test1", @" { // Code size 8 (0x8) .maxstack 1 IL_0000: ldc.i4.s 10 IL_0002: call ""S1 S1.IBase1.Create(int)"" IL_0007: ret } "); } [Fact] public void UnionConversion_MemberProvider_09_Inheritance() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 : S1.IUnionMembers { private readonly object _value; S1(int x) { System.Console.Write(""int {""); System.Console.Write(x); System.Console.Write(""} ""); _value = x; } S1(string x) => throw null; object IUnionMembers.Value => _value; public interface IUnionMembers : IBase<int> { public static S1 Create(string x) => new S1(x); public object Value { get; } } public interface IBase<T> { public static S1 Create(T x) => new S1((int)(object)x); } } class Program { static void Main() { Test1(); } static S1 Test1() { return 10; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); var verifier = CompileAndVerify(comp, expectedOutput: "int {10}").VerifyDiagnostics(); verifier.VerifyIL("Program.Test1", @" { // Code size 8 (0x8) .maxstack 1 IL_0000: ldc.i4.s 10 IL_0002: call ""S1 S1.IBase<int>.Create(int)"" IL_0007: ret } "); } [Fact] public void UnionConversion_MemberProvider_10_Inheritance() { var src = @" [System.Runtime.CompilerServices.Union] public struct S1<T> : S1<T>.IUnionMembers { private readonly object _value; public S1(int x) { System.Console.Write(""int {""); System.Console.Write(x); System.Console.Write(""} ""); _value = x; } S1(string x) => throw null; object IUnionMembers.Value => _value; public interface IUnionMembers : IBase<T> { public static S1<T> Create(string x) => throw null; public object Value { get; } } } public interface IBase<T> { public static S1<T> Create(T x) => new S1<T>((int)(object)x); } class Program { static void Main() { Test1(); } static S1<int> Test1() { return 10; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); var verifier = CompileAndVerify(comp, expectedOutput: "int {10}").VerifyDiagnostics(); verifier.VerifyIL("Program.Test1", @" { // Code size 8 (0x8) .maxstack 1 IL_0000: ldc.i4.s 10 IL_0002: call ""S1<int> IBase<int>.Create(int)"" IL_0007: ret } "); } [Fact] public void UnionConversion_MemberProvider_11_Inheritance_Shadowing() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 : S1.IUnionMembers { private readonly object _value; S1(int x) { System.Console.Write(""int {""); System.Console.Write(x); System.Console.Write(""} ""); _value = x; } S1(string x) => throw null; object IUnionMembers.Value => _value; public interface IUnionMembers : IBase { public new static S1 Create(int x) => new S1(x); public static S1 Create(string x) => new S1(x); public object Value { get; } } public interface IBase { public static S1 Create(int x) => throw null; } } class Program { static void Main() { Test1(); } static S1 Test1() { return 10; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); var verifier = CompileAndVerify(comp, expectedOutput: "int {10}").VerifyDiagnostics(); verifier.VerifyIL("Program.Test1", @" { // Code size 8 (0x8) .maxstack 1 IL_0000: ldc.i4.s 10 IL_0002: call ""S1 S1.IUnionMembers.Create(int)"" IL_0007: ret } "); } [Fact] public void UnionConversion_MemberProvider_12_Inheritance_Shadowing() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 : S1.IUnionMembers { private readonly object _value; S1(int x) { System.Console.Write(""int {""); System.Console.Write(x); System.Console.Write(""} ""); _value = x; } S1(string x) => throw null; object IUnionMembers.Value => _value; public interface IUnionMembers : IBase1, IBase2 { public static S1 Create(string x) => new S1(x); public object Value { get; } } public interface IBase2 : IBase1 { public new static S1 Create(int x) => new S1(x); } public interface IBase1 { public static S1 Create(int x) => throw null; } } class Program { static void Main() { Test1(); } static S1 Test1() { return 10; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); var verifier = CompileAndVerify(comp, expectedOutput: "int {10}").VerifyDiagnostics(); verifier.VerifyIL("Program.Test1", @" { // Code size 8 (0x8) .maxstack 1 IL_0000: ldc.i4.s 10 IL_0002: call ""S1 S1.IBase2.Create(int)"" IL_0007: ret } "); } [Fact] public void UnionConversion_MemberProvider_13_Inheritance_Shadowing() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 : S1.IUnionMembers { private readonly object _value; S1(int x) { System.Console.Write(""int {""); System.Console.Write(x); System.Console.Write(""} ""); _value = x; } S1(string x) => throw null; object IUnionMembers.Value => _value; public interface IUnionMembers : IBase<int> { public new static S1 Create(int x) => new S1(x); public static S1 Create(string x) => new S1(x); public object Value { get; } } public interface IBase<T> { public static S1 Create(T x) => throw null; } } class Program { static void Main() { Test1(); } static S1 Test1() { return 10; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); var verifier = CompileAndVerify(comp, expectedOutput: "int {10}").VerifyDiagnostics(); verifier.VerifyIL("Program.Test1", @" { // Code size 8 (0x8) .maxstack 1 IL_0000: ldc.i4.s 10 IL_0002: call ""S1 S1.IUnionMembers.Create(int)"" IL_0007: ret } "); } [Fact] public void UnionConversion_MemberProvider_14_Inheritance_Shadowing() { var src = @" [System.Runtime.CompilerServices.Union] public struct S1<T> : S1<T>.IUnionMembers { private readonly object _value; public S1(int x) { System.Console.Write(""int {""); System.Console.Write(x); System.Console.Write(""} ""); _value = x; } S1(string x) => throw null; object IUnionMembers.Value => _value; public interface IUnionMembers : IBase<T> { public static S1<T> Create(int x) => new S1<T>(x); public static S1<T> Create(string x) => throw null; public object Value { get; } } } public interface IBase<T> { public static S1<T> Create(T x) => throw null; } class Program { static void Main() { Test1(); } static S1<int> Test1() { return 10; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); var verifier = CompileAndVerify(comp, expectedOutput: "int {10}").VerifyDiagnostics(); verifier.VerifyIL("Program.Test1", @" { // Code size 8 (0x8) .maxstack 1 IL_0000: ldc.i4.s 10 IL_0002: call ""S1<int> S1<int>.IUnionMembers.Create(int)"" IL_0007: ret } "); } [Fact] public void UnionConversion_MemberProvider_15_Inheritance_Shadowing() { var src = @" [System.Runtime.CompilerServices.Union] public struct S1<T> : S1<T>.IUnionMembers { private readonly object _value; public S1(int x) { System.Console.Write(""int {""); System.Console.Write(x); System.Console.Write(""} ""); _value = x; } S1(string x) => throw null; object IUnionMembers.Value => _value; public interface IUnionMembers : IBase<T> { public static S1<T> Create(T x) => new S1<T>((int)(object)x); public static S1<T> Create(string x) => throw null; public object Value { get; } } } public interface IBase<T> { public static S1<T> Create(int x) => throw null; } class Program { static void Main() { Test1(); } static S1<int> Test1() { return 10; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); var verifier = CompileAndVerify(comp, expectedOutput: "int {10}").VerifyDiagnostics(); verifier.VerifyIL("Program.Test1", @" { // Code size 8 (0x8) .maxstack 1 IL_0000: ldc.i4.s 10 IL_0002: call ""S1<int> S1<int>.IUnionMembers.Create(int)"" IL_0007: ret } "); } [Fact] public void UnionConversion_MemberProvider_16_Inheritance_Shadowing() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 : S1.IUnionMembers { private readonly object _value; S1(int x) { System.Console.Write(""int {""); System.Console.Write(x); System.Console.Write(""} ""); _value = x; } S1(string x) => throw null; object IUnionMembers.Value => _value; public interface IUnionMembers : IBase0, IBase1, IBase2 { public static S1 Create(string x) => new S1(x); public object Value { get; } } public interface IBase2 : IBase1 { public new static S1 Create(int x) => new S1(x); } public interface IBase1 : IBase0 { public new static int Create { get; set; } } public interface IBase0 { public static S1 Create(int x) => throw null; } } class Program { static void Main() { Test1(); } static S1 Test1() { return 10; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); var verifier = CompileAndVerify(comp, expectedOutput: "int {10}").VerifyDiagnostics(); verifier.VerifyIL("Program.Test1", @" { // Code size 8 (0x8) .maxstack 1 IL_0000: ldc.i4.s 10 IL_0002: call ""S1 S1.IBase2.Create(int)"" IL_0007: ret } "); } [Fact] public void UnionConversion_MemberProvider_17_Inheritance_Ambiguity_In_Vs_Val() { var src1 = @" [System.Runtime.CompilerServices.Union] public struct S1 : S1.IUnionMembers { public interface IUnionMembers : IBase { public static S1 Create(int x) => throw null; public static S1 Create(string x) => throw null; public object Value { get; } } public interface IBase { public static S1 Create(in int x) => throw null; } public object Value => throw null; } [System.Runtime.CompilerServices.Union] public struct S2 : S2.IUnionMembers { public interface IUnionMembers : IBase { public static S2 Create(in int x) => throw null; public static S2 Create(string x) => throw null; public object Value { get; } } public interface IBase { public static S2 Create(int x) => throw null; } public object Value => throw null; } "; var src2 = @" class Program { static S1 Test1() { #line 100 return 10; } static S2 Test2() { #line 200 return (S2)10; } } "; var comp = CreateCompilation([src1, src2, UnionAttributeSource]); comp.VerifyDiagnostics( // (100,16): error CS0457: Ambiguous user defined conversions 'S1.IUnionMembers.Create(int)' and 'S1.IBase.Create(in int)' when converting from 'int' to 'S1' // return 10; Diagnostic(ErrorCode.ERR_AmbigUDConv, "10").WithArguments("S1.IUnionMembers.Create(int)", "S1.IBase.Create(in int)", "int", "S1").WithLocation(100, 16), // (200,16): error CS0457: Ambiguous user defined conversions 'S2.IUnionMembers.Create(in int)' and 'S2.IBase.Create(int)' when converting from 'int' to 'S2' // return (S2)10; Diagnostic(ErrorCode.ERR_AmbigUDConv, "(S2)10").WithArguments("S2.IUnionMembers.Create(in int)", "S2.IBase.Create(int)", "int", "S2").WithLocation(200, 16) ); var tree = comp.SyntaxTrees[1]; var model = comp.GetSemanticModel(tree); var cast = GetSyntax<CastExpressionSyntax>(tree, "(S2)10"); var typeInfo = model.GetTypeInfo(cast); Assert.Equal("S2", typeInfo.Type.ToTestDisplayString()); Assert.Equal("S2", typeInfo.ConvertedType.ToTestDisplayString()); Conversion conversion = model.GetConversion(cast); Assert.True(conversion.IsIdentity); var symbolInfo = model.GetSymbolInfo(cast); Assert.Equal(CandidateReason.OverloadResolutionFailure, symbolInfo.CandidateReason); Assert.Null(symbolInfo.Symbol); AssertEx.SequenceEqual(["S2 S2.IUnionMembers.Create(in System.Int32 x)", "S2 S2.IBase.Create(System.Int32 x)"], symbolInfo.CandidateSymbols.ToTestDisplayStrings()); } [Fact] public void UnionConversion_MemberProvider_18_Inheritance_Ambiguity_In_Vs_Val() { var src1 = @" [System.Runtime.CompilerServices.Union] public struct S1 : S1.IUnionMembers { public interface IUnionMembers : IBase2 { public static S1 Create(string x) => throw null; public object Value { get; } } public interface IBase2 : IBase1 { public static S1 Create(int x) => throw null; } public interface IBase1 { public static S1 Create(in int x) => throw null; } public object Value => throw null; } [System.Runtime.CompilerServices.Union] public struct S2 : S2.IUnionMembers { public interface IUnionMembers : IBase2 { public static S2 Create(string x) => throw null; public object Value { get; } } public interface IBase2 : IBase1 { public static S2 Create(in int x) => throw null; } public interface IBase1 { public static S2 Create(int x) => throw null; } public object Value => throw null; } "; var src2 = @" class Program { static S1 Test1() { #line 100 return 10; } static S2 Test2() { #line 200 return (S2)10; } } "; var comp = CreateCompilation([src1, src2, UnionAttributeSource]); comp.VerifyDiagnostics( // (100,16): error CS0457: Ambiguous user defined conversions 'S1.IBase2.Create(int)' and 'S1.IBase1.Create(in int)' when converting from 'int' to 'S1' // return 10; Diagnostic(ErrorCode.ERR_AmbigUDConv, "10").WithArguments("S1.IBase2.Create(int)", "S1.IBase1.Create(in int)", "int", "S1").WithLocation(100, 16), // (200,16): error CS0457: Ambiguous user defined conversions 'S2.IBase2.Create(in int)' and 'S2.IBase1.Create(int)' when converting from 'int' to 'S2' // return (S2)10; Diagnostic(ErrorCode.ERR_AmbigUDConv, "(S2)10").WithArguments("S2.IBase2.Create(in int)", "S2.IBase1.Create(int)", "int", "S2").WithLocation(200, 16) ); var tree = comp.SyntaxTrees[1]; var model = comp.GetSemanticModel(tree); var cast = GetSyntax<CastExpressionSyntax>(tree, "(S2)10"); var typeInfo = model.GetTypeInfo(cast); Assert.Equal("S2", typeInfo.Type.ToTestDisplayString()); Assert.Equal("S2", typeInfo.ConvertedType.ToTestDisplayString()); Conversion conversion = model.GetConversion(cast); Assert.True(conversion.IsIdentity); var symbolInfo = model.GetSymbolInfo(cast); Assert.Equal(CandidateReason.OverloadResolutionFailure, symbolInfo.CandidateReason); Assert.Null(symbolInfo.Symbol); AssertEx.SequenceEqual(["S2 S2.IBase2.Create(in System.Int32 x)", "S2 S2.IBase1.Create(System.Int32 x)"], symbolInfo.CandidateSymbols.ToTestDisplayStrings()); } [Fact] public void UnionConversion_MemberProvider_19_Inheritance_Ambiguity() { var src1 = @" [System.Runtime.CompilerServices.Union] public struct S1 : S1.IUnionMembers { public interface IUnionMembers : IBase1, IBase2 { public static S1 Create(string x) => throw null; public object Value { get; } } public interface IBase2 { public static S1 Create(int x) => throw null; } public interface IBase1 { public static S1 Create(int x) => throw null; } public object Value => throw null; } "; var src2 = @" class Program { static S1 Test1() { #line 100 return 10; } static S1 Test2() { #line 200 return (S1)10; } } "; var comp = CreateCompilation([src1, src2, UnionAttributeSource]); comp.VerifyDiagnostics( // (100,16): error CS0457: Ambiguous user defined conversions 'S1.IBase1.Create(int)' and 'S1.IBase2.Create(int)' when converting from 'int' to 'S1' // return 10; Diagnostic(ErrorCode.ERR_AmbigUDConv, "10").WithArguments("S1.IBase1.Create(int)", "S1.IBase2.Create(int)", "int", "S1").WithLocation(100, 16), // (200,16): error CS0457: Ambiguous user defined conversions 'S1.IBase1.Create(int)' and 'S1.IBase2.Create(int)' when converting from 'int' to 'S1' // return (S1)10; Diagnostic(ErrorCode.ERR_AmbigUDConv, "(S1)10").WithArguments("S1.IBase1.Create(int)", "S1.IBase2.Create(int)", "int", "S1").WithLocation(200, 16) ); var tree = comp.SyntaxTrees[1]; var model = comp.GetSemanticModel(tree); var cast = GetSyntax<CastExpressionSyntax>(tree, "(S1)10"); var typeInfo = model.GetTypeInfo(cast); Assert.Equal("S1", typeInfo.Type.ToTestDisplayString()); Assert.Equal("S1", typeInfo.ConvertedType.ToTestDisplayString()); Conversion conversion = model.GetConversion(cast); Assert.True(conversion.IsIdentity); var symbolInfo = model.GetSymbolInfo(cast); Assert.Equal(CandidateReason.OverloadResolutionFailure, symbolInfo.CandidateReason); Assert.Null(symbolInfo.Symbol); AssertEx.SequenceEqual(["S1 S1.IBase1.Create(System.Int32 x)", "S1 S1.IBase2.Create(System.Int32 x)"], symbolInfo.CandidateSymbols.ToTestDisplayStrings()); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/71773")] public void UserDefinedCast_RefStruct_Explicit() { var source = """ class C { S M1() { S s; s = (S)100; // 1 return s; } S M2() { return (S)200; // 2 } S M3(in int x) { S s; s = (S)x; // 3 return s; } S M4(in int x) { return (S)x; } S M4s(scoped in int x) { return (S)x; // 4 } S M5(in int x) { S s = (S)x; return s; } S M5s(scoped in int x) { S s = (S)x; return s; // 5 } S M6() { S s = (S)300; return s; // 6 } void M7(in int x) { scoped S s; s = (S)x; s = (S)100; } } [System.Runtime.CompilerServices.Union] ref struct S { public S(in int x) => throw null; public object Value => throw null; } """; CreateCompilation([source, UnionAttributeSource]).VerifyDiagnostics( // (6,13): error CS8347: Cannot use a result of 'S.S(in int)' in this context because it may expose variables referenced by parameter 'x' outside of their declaration scope // s = (S)100; // 1 Diagnostic(ErrorCode.ERR_EscapeCall, "(S)100").WithArguments("S.S(in int)", "x").WithLocation(6, 13), // (6,16): error CS8156: An expression cannot be used in this context because it may not be passed or returned by reference // s = (S)100; // 1 Diagnostic(ErrorCode.ERR_RefReturnLvalueExpected, "100").WithLocation(6, 16), // (12,16): error CS8347: Cannot use a result of 'S.S(in int)' in this context because it may expose variables referenced by parameter 'x' outside of their declaration scope // return (S)200; // 2 Diagnostic(ErrorCode.ERR_EscapeCall, "(S)200").WithArguments("S.S(in int)", "x").WithLocation(12, 16), // (12,19): error CS8156: An expression cannot be used in this context because it may not be passed or returned by reference // return (S)200; // 2 Diagnostic(ErrorCode.ERR_RefReturnLvalueExpected, "200").WithLocation(12, 19), // (18,13): error CS8347: Cannot use a result of 'S.S(in int)' in this context because it may expose variables referenced by parameter 'x' outside of their declaration scope // s = (S)x; // 3 Diagnostic(ErrorCode.ERR_EscapeCall, "(S)x").WithArguments("S.S(in int)", "x").WithLocation(18, 13), // (18,16): error CS9077: Cannot return a parameter by reference 'x' through a ref parameter; it can only be returned in a return statement // s = (S)x; // 3 Diagnostic(ErrorCode.ERR_RefReturnOnlyParameter, "x").WithArguments("x").WithLocation(18, 16), // (29,16): error CS8347: Cannot use a result of 'S.S(in int)' in this context because it may expose variables referenced by parameter 'x' outside of their declaration scope // return (S)x; // 4 Diagnostic(ErrorCode.ERR_EscapeCall, "(S)x").WithArguments("S.S(in int)", "x").WithLocation(29, 16), // (29,19): error CS9075: Cannot return a parameter by reference 'x' because it is scoped to the current method // return (S)x; // 4 Diagnostic(ErrorCode.ERR_RefReturnScopedParameter, "x").WithArguments("x").WithLocation(29, 19), // (41,16): error CS8352: Cannot use variable 's' in this context because it may expose referenced variables outside of their declaration scope // return s; // 5 Diagnostic(ErrorCode.ERR_EscapeVariable, "s").WithArguments("s").WithLocation(41, 16), // (47,16): error CS8352: Cannot use variable 's' in this context because it may expose referenced variables outside of their declaration scope // return s; // 6 Diagnostic(ErrorCode.ERR_EscapeVariable, "s").WithArguments("s").WithLocation(47, 16)); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/71773")] public void UserDefinedCast_RefStruct_Implicit() { var source = """ class C { S M1() { S s; s = 100; // 1 return s; } S M2() { return 200; // 2 } S M3(in int x) { S s; s = x; // 3 return s; } S M4(in int x) { return x; } S M4s(scoped in int x) { return x; // 4 } S M5(in int x) { S s = x; return s; } S M5s(scoped in int x) { S s = x; return s; // 5 } S M6() { S s = 300; return s; // 6 } void M7(in int x) { scoped S s; s = x; s = 100; } } [System.Runtime.CompilerServices.Union] ref struct S { public S(in int x) => throw null; public object Value => throw null; } """; CreateCompilation([source, UnionAttributeSource]).VerifyDiagnostics( // (6,13): error CS8156: An expression cannot be used in this context because it may not be passed or returned by reference // s = 100; // 1 Diagnostic(ErrorCode.ERR_RefReturnLvalueExpected, "100").WithLocation(6, 13), // (6,13): error CS8347: Cannot use a result of 'S.S(in int)' in this context because it may expose variables referenced by parameter 'x' outside of their declaration scope // s = 100; // 1 Diagnostic(ErrorCode.ERR_EscapeCall, "100").WithArguments("S.S(in int)", "x").WithLocation(6, 13), // (12,16): error CS8156: An expression cannot be used in this context because it may not be passed or returned by reference // return 200; // 2 Diagnostic(ErrorCode.ERR_RefReturnLvalueExpected, "200").WithLocation(12, 16), // (12,16): error CS8347: Cannot use a result of 'S.S(in int)' in this context because it may expose variables referenced by parameter 'x' outside of their declaration scope // return 200; // 2 Diagnostic(ErrorCode.ERR_EscapeCall, "200").WithArguments("S.S(in int)", "x").WithLocation(12, 16), // (18,13): error CS9077: Cannot return a parameter by reference 'x' through a ref parameter; it can only be returned in a return statement // s = x; // 3 Diagnostic(ErrorCode.ERR_RefReturnOnlyParameter, "x").WithArguments("x").WithLocation(18, 13), // (18,13): error CS8347: Cannot use a result of 'S.S(in int)' in this context because it may expose variables referenced by parameter 'x' outside of their declaration scope // s = x; // 3 Diagnostic(ErrorCode.ERR_EscapeCall, "x").WithArguments("S.S(in int)", "x").WithLocation(18, 13), // (29,16): error CS9075: Cannot return a parameter by reference 'x' because it is scoped to the current method // return x; // 4 Diagnostic(ErrorCode.ERR_RefReturnScopedParameter, "x").WithArguments("x").WithLocation(29, 16), // (29,16): error CS8347: Cannot use a result of 'S.S(in int)' in this context because it may expose variables referenced by parameter 'x' outside of their declaration scope // return x; // 4 Diagnostic(ErrorCode.ERR_EscapeCall, "x").WithArguments("S.S(in int)", "x").WithLocation(29, 16), // (41,16): error CS8352: Cannot use variable 's' in this context because it may expose referenced variables outside of their declaration scope // return s; // 5 Diagnostic(ErrorCode.ERR_EscapeVariable, "s").WithArguments("s").WithLocation(41, 16), // (47,16): error CS8352: Cannot use variable 's' in this context because it may expose referenced variables outside of their declaration scope // return s; // 6 Diagnostic(ErrorCode.ERR_EscapeVariable, "s").WithArguments("s").WithLocation(47, 16)); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/71773")] public void UserDefinedCast_RefStructArgument() { var source = """ class C { S2 M1() { int x = 1; S1 s1 = (S1)x; return (S2)s1; // 1 } } ref struct S1 { public static implicit operator S1(in int x) => throw null; } [System.Runtime.CompilerServices.Union] ref struct S2 { public S2(S1 s1) => throw null; public object Value => throw null; } """; CreateCompilation([source, UnionAttributeSource]).VerifyDiagnostics( // (7,16): error CS8347: Cannot use a result of 'S2.S2(S1)' in this context because it may expose variables referenced by parameter 's1' outside of their declaration scope // return (S2)s1; // 1 Diagnostic(ErrorCode.ERR_EscapeCall, "(S2)s1").WithArguments("S2.S2(S1)", "s1").WithLocation(7, 16), // (7,20): error CS8352: Cannot use variable 's1' in this context because it may expose referenced variables outside of their declaration scope // return (S2)s1; // 1 Diagnostic(ErrorCode.ERR_EscapeVariable, "s1").WithArguments("s1").WithLocation(7, 20)); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/71773")] public void UserDefinedCast_StandardImplicitConversion_Input() { var source = """ class C { S M1() { S s; s = 100; // 1 return s; } S M2() { return 200; // 2 } S M3(in int x) { S s; s = x; // 3 return s; } S M4(in int x) { return x; // 4 } S M4s(scoped in int x) { return x; // 5 } S M5(in int x) { S s = x; return s; // 6 } S M5s(scoped in int x) { S s = x; return s; // 7 } S M6() { S s = 300; return s; // 8 } } [System.Runtime.CompilerServices.Union] ref struct S { public S(in int? x) => throw null; public object Value => throw null; } """; CreateCompilation([source, UnionAttributeSource]).VerifyDiagnostics( // (6,13): error CS8156: An expression cannot be used in this context because it may not be passed or returned by reference // s = 100; // 1 Diagnostic(ErrorCode.ERR_RefReturnLvalueExpected, "100").WithLocation(6, 13), // (6,13): error CS8347: Cannot use a result of 'S.S(in int?)' in this context because it may expose variables referenced by parameter 'x' outside of their declaration scope // s = 100; // 1 Diagnostic(ErrorCode.ERR_EscapeCall, "100").WithArguments("S.S(in int?)", "x").WithLocation(6, 13), // (12,16): error CS8156: An expression cannot be used in this context because it may not be passed or returned by reference // return 200; // 2 Diagnostic(ErrorCode.ERR_RefReturnLvalueExpected, "200").WithLocation(12, 16), // (12,16): error CS8347: Cannot use a result of 'S.S(in int?)' in this context because it may expose variables referenced by parameter 'x' outside of their declaration scope // return 200; // 2 Diagnostic(ErrorCode.ERR_EscapeCall, "200").WithArguments("S.S(in int?)", "x").WithLocation(12, 16), // (18,13): error CS8156: An expression cannot be used in this context because it may not be passed or returned by reference // s = x; // 3 Diagnostic(ErrorCode.ERR_RefReturnLvalueExpected, "x").WithLocation(18, 13), // (18,13): error CS8347: Cannot use a result of 'S.S(in int?)' in this context because it may expose variables referenced by parameter 'x' outside of their declaration scope // s = x; // 3 Diagnostic(ErrorCode.ERR_EscapeCall, "x").WithArguments("S.S(in int?)", "x").WithLocation(18, 13), // (24,16): error CS8156: An expression cannot be used in this context because it may not be passed or returned by reference // return x; // 4 Diagnostic(ErrorCode.ERR_RefReturnLvalueExpected, "x").WithLocation(24, 16), // (24,16): error CS8347: Cannot use a result of 'S.S(in int?)' in this context because it may expose variables referenced by parameter 'x' outside of their declaration scope // return x; // 4 Diagnostic(ErrorCode.ERR_EscapeCall, "x").WithArguments("S.S(in int?)", "x").WithLocation(24, 16), // (29,16): error CS8156: An expression cannot be used in this context because it may not be passed or returned by reference // return x; // 5 Diagnostic(ErrorCode.ERR_RefReturnLvalueExpected, "x").WithLocation(29, 16), // (29,16): error CS8347: Cannot use a result of 'S.S(in int?)' in this context because it may expose variables referenced by parameter 'x' outside of their declaration scope // return x; // 5 Diagnostic(ErrorCode.ERR_EscapeCall, "x").WithArguments("S.S(in int?)", "x").WithLocation(29, 16), // (35,16): error CS8352: Cannot use variable 's' in this context because it may expose referenced variables outside of their declaration scope // return s; // 6 Diagnostic(ErrorCode.ERR_EscapeVariable, "s").WithArguments("s").WithLocation(35, 16), // (41,16): error CS8352: Cannot use variable 's' in this context because it may expose referenced variables outside of their declaration scope // return s; // 7 Diagnostic(ErrorCode.ERR_EscapeVariable, "s").WithArguments("s").WithLocation(41, 16), // (47,16): error CS8352: Cannot use variable 's' in this context because it may expose referenced variables outside of their declaration scope // return s; // 8 Diagnostic(ErrorCode.ERR_EscapeVariable, "s").WithArguments("s").WithLocation(47, 16)); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/71773")] public void UserDefinedCast_Call() { var source = """ class C { S M1(int x) { return M2(x); } S M2(S s) => s; } [System.Runtime.CompilerServices.Union] ref struct S { public S(in int x) => throw null; public object Value => throw null; } """; CreateCompilation([source, UnionAttributeSource]).VerifyDiagnostics( // (5,16): error CS8347: Cannot use a result of 'C.M2(S)' in this context because it may expose variables referenced by parameter 's' outside of their declaration scope // return M2(x); Diagnostic(ErrorCode.ERR_EscapeCall, "M2(x)").WithArguments("C.M2(S)", "s").WithLocation(5, 16), // (5,19): error CS8166: Cannot return a parameter by reference 'x' because it is not a ref parameter // return M2(x); Diagnostic(ErrorCode.ERR_RefReturnParameter, "x").WithArguments("x").WithLocation(5, 19), // (5,19): error CS8347: Cannot use a result of 'S.S(in int)' in this context because it may expose variables referenced by parameter 'x' outside of their declaration scope // return M2(x); Diagnostic(ErrorCode.ERR_EscapeCall, "x").WithArguments("S.S(in int)", "x").WithLocation(5, 19)); } [Fact] public void NullableAnalysis_01_State_From_Default() { var src = @" #nullable enable [System.Runtime.CompilerServices.Union] struct S1 { public S1(int x) => throw null!; public S1(bool? x) => throw null!; public object? Value => throw null!; } [System.Runtime.CompilerServices.Union] struct S2 { public S2(int x) => throw null!; public S2(bool x) => throw null!; public object? Value => throw null!; } class Program { static void Test1() { #line 100 S1 s = default; _ = s switch { int => 1, bool => 3 }; } static void Test2() { #line 200 S1 s = default; s.Value.ToString(); } static void Test3() { #line 300 S2 s = default; _ = s switch { int => 1, bool => 3 }; } static void Test4() { #line 400 S2 s = default; s.Value.ToString(); } } "; var comp = CreateCompilation([src, UnionAttributeSource]); comp.VerifyDiagnostics( // (101,15): warning CS8655: The switch expression does not handle some null inputs (it is not exhaustive). For example, the pattern 'null' is not covered. // _ = s switch { int => 1, bool => 3 }; Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustiveForNull, "switch").WithArguments("null").WithLocation(101, 15), // (201,9): warning CS8602: Dereference of a possibly null reference. // s.Value.ToString(); Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "s.Value").WithLocation(201, 9) ); } [Fact] public void NullableAnalysis_02_State_From_Default() { var src = @" #nullable enable [System.Runtime.CompilerServices.Union] class S1 { public S1(int x) => throw null!; public S1(bool? x) => throw null!; public object? Value => throw null!; } [System.Runtime.CompilerServices.Union] class S2 { public S2(int x) => throw null!; public S2(bool x) => throw null!; public object? Value => throw null!; } class Program { static void Test1() { #line 100 S1? s = null; _ = s switch { int => 1, bool => 3 }; } static void Test3() { #line 300 S2? s = null; _ = s switch { int => 1, bool => 3 }; } } "; var comp = CreateCompilation([src, UnionAttributeSource]); comp.VerifyDiagnostics( // (101,15): warning CS8655: The switch expression does not handle some null inputs (it is not exhaustive). For example, the pattern 'null' is not covered. // _ = s switch { int => 1, bool => 3 }; Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustiveForNull, "switch").WithArguments("null").WithLocation(101, 15), // (301,15): warning CS8655: The switch expression does not handle some null inputs (it is not exhaustive). For example, the pattern 'null' is not covered. // _ = s switch { int => 1, bool => 3 }; Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustiveForNull, "switch").WithArguments("null").WithLocation(301, 15) ); } [Theory] [CombinatorialData] public void NullableAnalysis_03_State_From_Default([CombinatorialValues("class", "struct")] string typeKind) { var src = @" #nullable enable [System.Runtime.CompilerServices.Union] " + typeKind + @" S1 { public S1(int x) => throw null!; public S1(bool? x) => throw null!; public object? Value => throw null!; } [System.Runtime.CompilerServices.Union] " + typeKind + @" S2 { public S2(int x) => throw null!; public S2(bool x) => throw null!; public object? Value => throw null!; } class Program { static void Test2(S1 s) { #line 200 _ = s switch { int => 1, bool => 3 }; } static void Test4(S2 s) { #line 400 _ = s switch { int => 1, bool => 3 }; } } "; var comp = CreateCompilation([src, UnionAttributeSource]); comp.VerifyDiagnostics( // (200,15): warning CS8655: The switch expression does not handle some null inputs (it is not exhaustive). For example, the pattern 'null' is not covered. // _ = s switch { int => 1, bool => 3 }; Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustiveForNull, "switch").WithArguments("null").WithLocation(200, 15) ); } [Theory] [CombinatorialData] public void NullableAnalysis_04_State_From_Default_PostCondition([CombinatorialValues("class", "struct")] string typeKind) { var src = @" #nullable enable [System.Runtime.CompilerServices.Union] " + typeKind + @" S1 { public S1(int x) => throw null!; public S1([System.Diagnostics.CodeAnalysis.NotNull] bool? x) => throw null!; public object? Value => throw null!; } class Program { static void Test2(S1 s) { #line 200 _ = s switch { int => 1, bool => 3 }; } } "; var comp = CreateCompilation([src, UnionAttributeSource, NotNullAttributeDefinition]); comp.VerifyDiagnostics( // (200,15): warning CS8655: The switch expression does not handle some null inputs (it is not exhaustive). For example, the pattern 'null' is not covered. // _ = s switch { int => 1, bool => 3 }; Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustiveForNull, "switch").WithArguments("null").WithLocation(200, 15) ); } [Theory] [CombinatorialData] public void NullableAnalysis_05_State_From_Constructor([CombinatorialValues("class", "struct")] string typeKind) { var src = @" #nullable enable [System.Runtime.CompilerServices.Union] " + typeKind + @" S1 { public S1(int x) => throw null!; public S1(string? x) => throw null!; public S1(bool? x) => throw null!; public object? Value => throw null!; } class Program { static void Test1() { #line 100 var s = new S1(1); _ = s switch { int => 1, string => 2, bool => 3 }; } static void Test2() { #line 200 var s = new S1(""""); _ = s switch { int => 1, string => 2, bool => 3 }; } static void Test3(string? x) { #line 300 var s = new S1(x); _ = s switch { int => 1, string => 2, bool => 3 }; } static void Test4(bool x) { #line 400 var s = new S1(x); _ = s switch { int => 1, string => 2, bool => 3 }; } static void Test5(bool? x) { #line 500 var s = new S1(x); _ = s switch { int => 1, string => 2, bool => 3 }; } } "; var comp = CreateCompilation([src, UnionAttributeSource]); comp.VerifyDiagnostics( // (301,15): warning CS8655: The switch expression does not handle some null inputs (it is not exhaustive). For example, the pattern 'null' is not covered. // _ = s switch { int => 1, string => 2, bool => 3 }; Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustiveForNull, "switch").WithArguments("null").WithLocation(301, 15), // (501,15): warning CS8655: The switch expression does not handle some null inputs (it is not exhaustive). For example, the pattern 'null' is not covered. // _ = s switch { int => 1, string => 2, bool => 3 }; Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustiveForNull, "switch").WithArguments("null").WithLocation(501, 15) ); } [Theory] [CombinatorialData] public void NullableAnalysis_06_State_From_Constructor_PostCondition([CombinatorialValues("class", "struct")] string typeKind) { var src = @" #nullable enable [System.Runtime.CompilerServices.Union] " + typeKind + @" S1 { public S1(int x) => throw null!; public S1([System.Diagnostics.CodeAnalysis.NotNull] string? x) => throw null!; public S1([System.Diagnostics.CodeAnalysis.NotNull] bool? x) => throw null!; public object? Value => throw null!; } class Program { static void Test1() { #line 100 var s = new S1(1); _ = s switch { int => 1, string => 2, bool => 3 }; } static void Test2() { #line 200 var s = new S1(""""); _ = s switch { int => 1, string => 2, bool => 3 }; } static void Test3(string? x) { #line 300 var s = new S1(x); _ = s switch { int => 1, string => 2, bool => 3 }; x.ToString(); } static void Test4(bool x) { #line 400 var s = new S1(x); _ = s switch { int => 1, string => 2, bool => 3 }; } static void Test5(bool? x) { #line 500 var s = new S1(x); _ = s switch { int => 1, string => 2, bool => 3 }; x.Value.ToString(); } } "; var comp = CreateCompilation([src, UnionAttributeSource, NotNullAttributeDefinition]); comp.VerifyDiagnostics(); } [Theory] [CombinatorialData] public void NullableAnalysis_07_State_From_Conversion([CombinatorialValues("class", "struct")] string typeKind) { var src = @" #nullable enable [System.Runtime.CompilerServices.Union] " + typeKind + @" S1 { public S1(int x) => throw null!; public S1(string? x) => throw null!; public S1(bool? x) => throw null!; public object? Value => throw null!; } class Program { static void Test1() { #line 100 S1 s = 1; _ = s switch { int => 1, string => 2, bool => 3 }; } static void Test2() { #line 200 S1 s = """"; _ = s switch { int => 1, string => 2, bool => 3 }; } static void Test3(string? x) { #line 300 S1 s = x; _ = s switch { int => 1, string => 2, bool => 3 }; } static void Test4(bool x) { #line 400 S1 s = x; _ = s switch { int => 1, string => 2, bool => 3 }; } static void Test5(bool? x) { #line 500 S1 s = x; _ = s switch { int => 1, string => 2, bool => 3 }; } } "; var comp = CreateCompilation([src, UnionAttributeSource]); comp.VerifyDiagnostics( // (301,15): warning CS8655: The switch expression does not handle some null inputs (it is not exhaustive). For example, the pattern 'null' is not covered. // _ = s switch { int => 1, string => 2, bool => 3 }; Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustiveForNull, "switch").WithArguments("null").WithLocation(301, 15), // (501,15): warning CS8655: The switch expression does not handle some null inputs (it is not exhaustive). For example, the pattern 'null' is not covered. // _ = s switch { int => 1, string => 2, bool => 3 }; Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustiveForNull, "switch").WithArguments("null").WithLocation(501, 15) ); } [Theory] [CombinatorialData] public void NullableAnalysis_08_State_From_Conversion_PostCondition([CombinatorialValues("class", "struct")] string typeKind) { var src = @" #nullable enable [System.Runtime.CompilerServices.Union] " + typeKind + @" S1 { public S1(int x) => throw null!; public S1([System.Diagnostics.CodeAnalysis.NotNull] string? x) => throw null!; public S1([System.Diagnostics.CodeAnalysis.NotNull] bool? x) => throw null!; public object? Value => throw null!; } class Program { static void Test1() { #line 100 S1 s = 1; _ = s switch { int => 1, string => 2, bool => 3 }; } static void Test2() { #line 200 S1 s = """"; _ = s switch { int => 1, string => 2, bool => 3 }; } static void Test3(string? x) { #line 300 S1 s = x; _ = s switch { int => 1, string => 2, bool => 3 }; x.ToString(); } static void Test4(bool x) { #line 400 S1 s = x; _ = s switch { int => 1, string => 2, bool => 3 }; } static void Test5(bool? x) { #line 500 S1 s = x; _ = s switch { int => 1, string => 2, bool => 3 }; x.Value.ToString(); } } "; var comp = CreateCompilation([src, UnionAttributeSource, NotNullAttributeDefinition]); comp.VerifyDiagnostics(); } [Theory] [CombinatorialData] public void NullableAnalysis_09_State_From_Conversion_TupleLiteral([CombinatorialValues("class", "struct")] string typeKind) { var src = @" #nullable enable [System.Runtime.CompilerServices.Union] " + typeKind + @" S1 { public S1(int x) => throw null!; public S1(string? x) => throw null!; public S1(bool? x) => throw null!; public object? Value => throw null!; } class Program { static void Test1() { #line 100 (S1, int) s = (1, 1); _ = s.Item1 switch { int => 1, string => 2, bool => 3 }; } static void Test2() { #line 200 (S1, int) s = ("""", 1); _ = s.Item1 switch { int => 1, string => 2, bool => 3 }; } static void Test3(string? x) { #line 300 (S1, int) s = (x, 1); _ = s.Item1 switch { int => 1, string => 2, bool => 3 }; } static void Test4(bool x) { #line 400 (S1, int) s = (x, 1); _ = s.Item1 switch { int => 1, string => 2, bool => 3 }; } static void Test5(bool? x) { #line 500 (S1, int) s = (x, 1); _ = s.Item1 switch { int => 1, string => 2, bool => 3 }; } } "; var comp = CreateCompilation([src, UnionAttributeSource]); comp.VerifyDiagnostics( // (301,21): warning CS8655: The switch expression does not handle some null inputs (it is not exhaustive). For example, the pattern 'null' is not covered. // _ = s.Item1 switch { int => 1, string => 2, bool => 3 }; Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustiveForNull, "switch").WithArguments("null").WithLocation(301, 21), // (501,21): warning CS8655: The switch expression does not handle some null inputs (it is not exhaustive). For example, the pattern 'null' is not covered. // _ = s.Item1 switch { int => 1, string => 2, bool => 3 }; Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustiveForNull, "switch").WithArguments("null").WithLocation(501, 21) ); } [Theory] [CombinatorialData] public void NullableAnalysis_10_State_From_Conversion_TupleLiteral_PostCondition([CombinatorialValues("class", "struct")] string typeKind) { var src = @" #nullable enable [System.Runtime.CompilerServices.Union] " + typeKind + @" S1 { public S1(int x) => throw null!; public S1([System.Diagnostics.CodeAnalysis.NotNull] string? x) => throw null!; public S1([System.Diagnostics.CodeAnalysis.NotNull] bool? x) => throw null!; public object? Value => throw null!; } class Program { static void Test1() { #line 100 (S1, int) s = (1, 1); _ = s.Item1 switch { int => 1, string => 2, bool => 3 }; } static void Test2() { #line 200 (S1, int) s = ("""", 1); _ = s.Item1 switch { int => 1, string => 2, bool => 3 }; } static void Test3(string? x) { #line 300 (S1, int) s = (x, 1); _ = s.Item1 switch { int => 1, string => 2, bool => 3 }; x.ToString(); } static void Test4(bool x) { #line 400 (S1, int) s = (x, 1); _ = s.Item1 switch { int => 1, string => 2, bool => 3 }; } static void Test5(bool? x) { #line 500 (S1, int) s = (x, 1); _ = s.Item1 switch { int => 1, string => 2, bool => 3 }; x.Value.ToString(); } } "; var comp = CreateCompilation([src, UnionAttributeSource, NotNullAttributeDefinition]); comp.VerifyDiagnostics(); } [Theory] [CombinatorialData] public void NullableAnalysis_11_State_From_Conversion_TupleValue([CombinatorialValues("class", "struct")] string typeKind) { var src = @" #nullable enable [System.Runtime.CompilerServices.Union] " + typeKind + @" S1 { public S1(int x) => throw null!; public S1(string? x) => throw null!; public S1(bool? x) => throw null!; public object? Value => throw null!; } class Program { static void Test1((int, int) x) { #line 100 (S1, int) s = x; _ = s.Item1 switch { int => 1, string => 2, bool => 3 }; } static void Test2((string, int) x) { #line 200 (S1, int) s = x; _ = s.Item1 switch { int => 1, string => 2, bool => 3 }; } static void Test3((string?, int) x) { #line 300 (S1, int) s = x; _ = s.Item1 switch { int => 1, string => 2, bool => 3 }; } static void Test4((bool, int) x) { #line 400 (S1, int) s = x; _ = s.Item1 switch { int => 1, string => 2, bool => 3 }; } static void Test5((bool?, int) x) { #line 500 (S1, int) s = x; _ = s.Item1 switch { int => 1, string => 2, bool => 3 }; } } "; var comp = CreateCompilation([src, UnionAttributeSource]); comp.VerifyDiagnostics( // (301,21): warning CS8655: The switch expression does not handle some null inputs (it is not exhaustive). For example, the pattern 'null' is not covered. // _ = s.Item1 switch { int => 1, string => 2, bool => 3 }; Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustiveForNull, "switch").WithArguments("null").WithLocation(301, 21), // (501,21): warning CS8655: The switch expression does not handle some null inputs (it is not exhaustive). For example, the pattern 'null' is not covered. // _ = s.Item1 switch { int => 1, string => 2, bool => 3 }; Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustiveForNull, "switch").WithArguments("null").WithLocation(501, 21) ); } [Theory] [CombinatorialData] public void NullableAnalysis_12_State_From_Conversion_TupleValue_PostCondition([CombinatorialValues("class", "struct")] string typeKind) { var src = @" #nullable enable [System.Runtime.CompilerServices.Union] " + typeKind + @" S1 { public S1(int x) => throw null!; public S1([System.Diagnostics.CodeAnalysis.NotNull] string? x) => throw null!; public S1([System.Diagnostics.CodeAnalysis.NotNull] bool? x) => throw null!; public object? Value => throw null!; } class Program { static void Test1((int, int) x) { #line 100 (S1, int) s = x; _ = s.Item1 switch { int => 1, string => 2, bool => 3 }; } static void Test2((string, int) x) { #line 200 (S1, int) s = x; _ = s.Item1 switch { int => 1, string => 2, bool => 3 }; } static void Test3((string?, int) x) { #line 300 (S1, int) s = x; _ = s.Item1 switch { int => 1, string => 2, bool => 3 }; x.Item1.ToString(); } static void Test4((bool, int) x) { #line 400 (S1, int) s = x; _ = s.Item1 switch { int => 1, string => 2, bool => 3 }; } static void Test5((bool?, int) x) { #line 500 (S1, int) s = x; _ = s.Item1 switch { int => 1, string => 2, bool => 3 }; x.Item1.Value.ToString(); } } "; var comp = CreateCompilation([src, UnionAttributeSource, NotNullAttributeDefinition]); comp.VerifyDiagnostics(); } [Theory] [CombinatorialData] public void NullableAnalysis_13_State_From_Conversion_Cast([CombinatorialValues("class", "struct")] string typeKind) { var src = @" #nullable enable [System.Runtime.CompilerServices.Union] " + typeKind + @" S1 { public S1(int x) => throw null!; public S1(string? x) => throw null!; public S1(bool? x) => throw null!; public object? Value => throw null!; } class Program { static void Test1() { #line 100 S1 s = (S1)1; _ = s switch { int => 1, string => 2, bool => 3 }; } static void Test2() { #line 200 S1 s = (S1)""""; _ = s switch { int => 1, string => 2, bool => 3 }; } static void Test3(string? x) { #line 300 S1 s = (S1)x; _ = s switch { int => 1, string => 2, bool => 3 }; } static void Test4(bool x) { #line 400 S1 s = (S1)x; _ = s switch { int => 1, string => 2, bool => 3 }; } static void Test5(bool? x) { #line 500 S1 s = (S1)x; _ = s switch { int => 1, string => 2, bool => 3 }; } } "; var comp = CreateCompilation([src, UnionAttributeSource]); comp.VerifyDiagnostics( // (301,15): warning CS8655: The switch expression does not handle some null inputs (it is not exhaustive). For example, the pattern 'null' is not covered. // _ = s switch { int => 1, string => 2, bool => 3 }; Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustiveForNull, "switch").WithArguments("null").WithLocation(301, 15), // (501,15): warning CS8655: The switch expression does not handle some null inputs (it is not exhaustive). For example, the pattern 'null' is not covered. // _ = s switch { int => 1, string => 2, bool => 3 }; Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustiveForNull, "switch").WithArguments("null").WithLocation(501, 15) ); } [Theory] [CombinatorialData] public void NullableAnalysis_14_State_From_Conversion_Cast_PostCondition([CombinatorialValues("class", "struct")] string typeKind) { var src = @" #nullable enable [System.Runtime.CompilerServices.Union] " + typeKind + @" S1 { public S1(int x) => throw null!; public S1([System.Diagnostics.CodeAnalysis.NotNull] string? x) => throw null!; public S1([System.Diagnostics.CodeAnalysis.NotNull] bool? x) => throw null!; public object? Value => throw null!; } class Program { static void Test1() { #line 100 S1 s = (S1)1; _ = s switch { int => 1, string => 2, bool => 3 }; } static void Test2() { #line 200 S1 s = (S1)""""; _ = s switch { int => 1, string => 2, bool => 3 }; } static void Test3(string? x) { #line 300 S1 s = (S1)x; _ = s switch { int => 1, string => 2, bool => 3 }; x.ToString(); } static void Test4(bool x) { #line 400 S1 s = (S1)x; _ = s switch { int => 1, string => 2, bool => 3 }; } static void Test5(bool? x) { #line 500 S1 s = (S1)x; _ = s switch { int => 1, string => 2, bool => 3 }; x.Value.ToString(); } } "; var comp = CreateCompilation([src, UnionAttributeSource, NotNullAttributeDefinition]); comp.VerifyDiagnostics(); } [Theory] [CombinatorialData] public void NullableAnalysis_15_State_From_Conversion_Cast_TupleLiteral([CombinatorialValues("class", "struct")] string typeKind) { var src = @" #nullable enable [System.Runtime.CompilerServices.Union] " + typeKind + @" S1 { public S1(int x) => throw null!; public S1(string? x) => throw null!; public S1(bool? x) => throw null!; public object? Value => throw null!; } class Program { static void Test1() { #line 100 (S1, int) s = ((S1, int))(1, 1.0); _ = s.Item1 switch { int => 1, string => 2, bool => 3 }; } static void Test2() { #line 200 (S1, int) s = ((S1, int))("""", 1.0); _ = s.Item1 switch { int => 1, string => 2, bool => 3 }; } static void Test3(string? x) { #line 300 (S1, int) s = ((S1, int))(x, 1.0); _ = s.Item1 switch { int => 1, string => 2, bool => 3 }; } static void Test4(bool x) { #line 400 (S1, int) s = ((S1, int))(x, 1.0); _ = s.Item1 switch { int => 1, string => 2, bool => 3 }; } static void Test5(bool? x) { #line 500 (S1, int) s = ((S1, int))(x, 1.0); _ = s.Item1 switch { int => 1, string => 2, bool => 3 }; } } "; var comp = CreateCompilation([src, UnionAttributeSource]); comp.VerifyDiagnostics( // (301,21): warning CS8655: The switch expression does not handle some null inputs (it is not exhaustive). For example, the pattern 'null' is not covered. // _ = s.Item1 switch { int => 1, string => 2, bool => 3 }; Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustiveForNull, "switch").WithArguments("null").WithLocation(301, 21), // (501,21): warning CS8655: The switch expression does not handle some null inputs (it is not exhaustive). For example, the pattern 'null' is not covered. // _ = s.Item1 switch { int => 1, string => 2, bool => 3 }; Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustiveForNull, "switch").WithArguments("null").WithLocation(501, 21) ); } [Theory] [CombinatorialData] public void NullableAnalysis_16_State_From_Conversion_Cast_TupleLiteral_PostCondition([CombinatorialValues("class", "struct")] string typeKind) { var src = @" #nullable enable [System.Runtime.CompilerServices.Union] " + typeKind + @" S1 { public S1(int x) => throw null!; public S1([System.Diagnostics.CodeAnalysis.NotNull] string? x) => throw null!; public S1([System.Diagnostics.CodeAnalysis.NotNull] bool? x) => throw null!; public object? Value => throw null!; } class Program { static void Test1() { #line 100 (S1, int) s = ((S1, int))(1, 1.0); _ = s.Item1 switch { int => 1, string => 2, bool => 3 }; } static void Test2() { #line 200 (S1, int) s = ((S1, int))("""", 1.0); _ = s.Item1 switch { int => 1, string => 2, bool => 3 }; } static void Test3(string? x) { #line 300 (S1, int) s = ((S1, int))(x, 1.0); _ = s.Item1 switch { int => 1, string => 2, bool => 3 }; x.ToString(); } static void Test4(bool x) { #line 400 (S1, int) s = ((S1, int))(x, 1.0); _ = s.Item1 switch { int => 1, string => 2, bool => 3 }; } static void Test5(bool? x) { #line 500 (S1, int) s = ((S1, int))(x, 1.0); _ = s.Item1 switch { int => 1, string => 2, bool => 3 }; x.Value.ToString(); } } "; var comp = CreateCompilation([src, UnionAttributeSource, NotNullAttributeDefinition]); comp.VerifyDiagnostics(); } [Theory] [CombinatorialData] public void NullableAnalysis_17_State_From_Conversion_Cast_TupleValue([CombinatorialValues("class", "struct")] string typeKind) { var src = @" #nullable enable [System.Runtime.CompilerServices.Union] " + typeKind + @" S1 { public S1(int x) => throw null!; public S1(string? x) => throw null!; public S1(bool? x) => throw null!; public object? Value => throw null!; } class Program { static void Test1((int, long) x) { #line 100 (S1, int) s = ((S1, int))x; _ = s.Item1 switch { int => 1, string => 2, bool => 3 }; } static void Test2((string, long) x) { #line 200 (S1, int) s = ((S1, int))x; _ = s.Item1 switch { int => 1, string => 2, bool => 3 }; } static void Test3((string?, long) x) { #line 300 (S1, int) s = ((S1, int))x; _ = s.Item1 switch { int => 1, string => 2, bool => 3 }; } static void Test4((bool, long) x) { #line 400 (S1, int) s = ((S1, int))x; _ = s.Item1 switch { int => 1, string => 2, bool => 3 }; } static void Test5((bool?, long) x) { #line 500 (S1, int) s = ((S1, int))x; _ = s.Item1 switch { int => 1, string => 2, bool => 3 }; } } "; var comp = CreateCompilation([src, UnionAttributeSource]); comp.VerifyDiagnostics( // (301,21): warning CS8655: The switch expression does not handle some null inputs (it is not exhaustive). For example, the pattern 'null' is not covered. // _ = s.Item1 switch { int => 1, string => 2, bool => 3 }; Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustiveForNull, "switch").WithArguments("null").WithLocation(301, 21), // (501,21): warning CS8655: The switch expression does not handle some null inputs (it is not exhaustive). For example, the pattern 'null' is not covered. // _ = s.Item1 switch { int => 1, string => 2, bool => 3 }; Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustiveForNull, "switch").WithArguments("null").WithLocation(501, 21) ); } [Theory] [CombinatorialData] public void NullableAnalysis_18_State_From_Conversion_Cast_TupleValue_PostCondition([CombinatorialValues("class", "struct")] string typeKind) { var src = @" #nullable enable [System.Runtime.CompilerServices.Union] " + typeKind + @" S1 { public S1(int x) => throw null!; public S1([System.Diagnostics.CodeAnalysis.NotNull] string? x) => throw null!; public S1([System.Diagnostics.CodeAnalysis.NotNull] bool? x) => throw null!; public object? Value => throw null!; } class Program { static void Test1((int, long) x) { #line 100 (S1, int) s = ((S1, int))x; _ = s.Item1 switch { int => 1, string => 2, bool => 3 }; } static void Test2((string, long) x) { #line 200 (S1, int) s = ((S1, int))x; _ = s.Item1 switch { int => 1, string => 2, bool => 3 }; } static void Test3((string?, long) x) { #line 300 (S1, int) s = ((S1, int))x; _ = s.Item1 switch { int => 1, string => 2, bool => 3 }; x.Item1.ToString(); } static void Test4((bool, long) x) { #line 400 (S1, int) s = ((S1, int))x; _ = s.Item1 switch { int => 1, string => 2, bool => 3 }; } static void Test5((bool?, long) x) { #line 500 (S1, int) s = ((S1, int))x; _ = s.Item1 switch { int => 1, string => 2, bool => 3 }; x.Item1.Value.ToString(); } } "; var comp = CreateCompilation([src, UnionAttributeSource, NotNullAttributeDefinition]); comp.VerifyDiagnostics(); } [Fact] public void NullableAnalysis_19_State_From_Null_Test() { var src = @" #nullable enable [System.Runtime.CompilerServices.Union] struct S1 { public S1(int x) => throw null!; public S1(bool? x) => throw null!; public object? Value => throw null!; } [System.Runtime.CompilerServices.Union] struct S2 { public S2(int x) => throw null!; public S2(bool x) => throw null!; public object? Value => throw null!; } class Program { static void Test2(S1 s) { if (s is null) { #line 100 _ = s switch { int => 1, bool => 3 }; } else { #line 200 _ = s switch { int => 1, bool => 3 }; } } static void Test4(S2 s) { if (s is null) { #line 300 _ = s switch { int => 1, bool => 3 }; } else { #line 400 _ = s switch { int => 1, bool => 3 }; } } } "; var comp = CreateCompilation([src, UnionAttributeSource]); comp.VerifyDiagnostics( // (100,19): warning CS8655: The switch expression does not handle some null inputs (it is not exhaustive). For example, the pattern 'null' is not covered. // _ = s switch { int => 1, bool => 3 }; Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustiveForNull, "switch").WithArguments("null").WithLocation(100, 19), // (300,19): warning CS8655: The switch expression does not handle some null inputs (it is not exhaustive). For example, the pattern 'null' is not covered. // _ = s switch { int => 1, bool => 3 }; Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustiveForNull, "switch").WithArguments("null").WithLocation(300, 19) ); } [Fact] public void NullableAnalysis_20_State_From_Null_Test_Class() { var src1 = @" #nullable enable [System.Runtime.CompilerServices.Union] class S1 { public S1(int x) => throw null!; public S1(bool? x) => throw null!; public object? Value => throw null!; } [System.Runtime.CompilerServices.Union] class S2 { public S2(int x) => throw null!; public S2(bool x) => throw null!; public object? Value => throw null!; } class Program { static void Test2(S1 s) { if (s is null) { #line 100 _ = s switch { int => 1, bool => 3 }; } else { #line 200 _ = s switch { int => 1, bool => 3 }; } } static void Test4(S2 s) { if (s is null) { #line 300 _ = s switch { int => 1, bool => 3 }; } else { #line 400 _ = s switch { int => 1, bool => 3 }; } } } "; var comp1 = CreateCompilation([src1, UnionAttributeSource]); comp1.VerifyDiagnostics( // (100,19): warning CS8655: The switch expression does not handle some null inputs (it is not exhaustive). For example, the pattern 'null' is not covered. // _ = s switch { int => 1, bool => 3 }; Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustiveForNull, "switch").WithArguments("null").WithLocation(100, 19), // (300,19): warning CS8655: The switch expression does not handle some null inputs (it is not exhaustive). For example, the pattern 'null' is not covered. // _ = s switch { int => 1, bool => 3 }; Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustiveForNull, "switch").WithArguments("null").WithLocation(300, 19) ); var src2 = @" #nullable enable class S1 { public bool? Value => throw null!; } class Program { static void Test2(S1 s) { _ = s.Value; if (s is null or { Value: null }) { #line 1000 _ = s switch { { Value: bool } => 1 }; } else { #line 2000 _ = s switch { { Value: bool } => 1 }; } } } "; var comp2 = CreateCompilation(src2); comp2.VerifyDiagnostics( // (1000,19): warning CS8655: The switch expression does not handle some null inputs (it is not exhaustive). For example, the pattern 'null' is not covered. // _ = s switch { { Value: bool } => 1 }; Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustiveForNull, "switch").WithArguments("null").WithLocation(1000, 19) ); } [Theory] [CombinatorialData] public void NullableAnalysis_21_State_From_NotNull_Test([CombinatorialValues("class", "struct")] string typeKind) { var src = @" #nullable enable [System.Runtime.CompilerServices.Union] " + typeKind + @" S1 { public S1(int x) => throw null!; public S1(bool? x) => throw null!; public object? Value => throw null!; } [System.Runtime.CompilerServices.Union] " + typeKind + @" S2 { public S2(int x) => throw null!; public S2(bool x) => throw null!; public object? Value => throw null!; } class Program { static void Test2(S1 s) { if (s is not null) { #line 100 _ = s switch { int => 1, bool => 3 }; } else { #line 200 _ = s switch { int => 1, bool => 3 }; } } static void Test4(S2 s) { if (s is not null) { #line 300 _ = s switch { int => 1, bool => 3 }; } else { #line 400 _ = s switch { int => 1, bool => 3 }; } } } "; var comp = CreateCompilation([src, UnionAttributeSource]); comp.VerifyDiagnostics( // (200,19): warning CS8655: The switch expression does not handle some null inputs (it is not exhaustive). For example, the pattern 'null' is not covered. // _ = s switch { int => 1, bool => 3 }; Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustiveForNull, "switch").WithArguments("null").WithLocation(200, 19), // (400,19): warning CS8655: The switch expression does not handle some null inputs (it is not exhaustive). For example, the pattern 'null' is not covered. // _ = s switch { int => 1, bool => 3 }; Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustiveForNull, "switch").WithArguments("null").WithLocation(400, 19) ); } [Theory] [CombinatorialData] public void NullableAnalysis_22_State_From_Type_Test([CombinatorialValues("class", "struct")] string typeKind) { var src = @" #nullable enable [System.Runtime.CompilerServices.Union] " + typeKind + @" S1 { public S1(int x) => throw null!; public S1(bool? x) => throw null!; public object? Value => throw null!; } [System.Runtime.CompilerServices.Union] " + typeKind + @" S2 { public S2(int x) => throw null!; public S2(bool x) => throw null!; public object? Value => throw null!; } class Program { static void Test2(S1 s) { if (s is int) { #line 100 _ = s switch { int => 1, bool => 3 }; } else { #line 200 _ = s switch { int => 1, bool => 3 }; } } static void Test4(S2 s) { if (s is int) { #line 300 _ = s switch { int => 1, bool => 3 }; } else { #line 400 _ = s switch { int => 1, bool => 3 }; } } } "; var comp = CreateCompilation([src, UnionAttributeSource]); comp.VerifyDiagnostics( // (200,19): warning CS8655: The switch expression does not handle some null inputs (it is not exhaustive). For example, the pattern 'null' is not covered. // _ = s switch { int => 1, bool => 3 }; Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustiveForNull, "switch").WithArguments("null").WithLocation(200, 19) ); } [Fact] public void NullableAnalysis_23_State_From_NotType_Test() { var src = @" #nullable enable [System.Runtime.CompilerServices.Union] struct S1 { public S1(int x) => throw null!; public S1(bool? x) => throw null!; public object? Value => throw null!; } [System.Runtime.CompilerServices.Union] struct S2 { public S2(int x) => throw null!; public S2(bool x) => throw null!; public object? Value => throw null!; } class Program { static void Test2(S1 s) { if (s is not int) { #line 100 _ = s switch { int => 1, bool => 3 }; } else { #line 200 _ = s switch { int => 1, bool => 3 }; } } static void Test4(S2 s) { if (s is not int) { #line 300 _ = s switch { int => 1, bool => 3 }; } else { #line 400 _ = s switch { int => 1, bool => 3 }; } } } "; var comp = CreateCompilation([src, UnionAttributeSource]); comp.VerifyDiagnostics( // (100,19): warning CS8655: The switch expression does not handle some null inputs (it is not exhaustive). For example, the pattern 'null' is not covered. // _ = s switch { int => 1, bool => 3 }; Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustiveForNull, "switch").WithArguments("null").WithLocation(100, 19) ); } [Fact] public void NullableAnalysis_24_State_From_NotType_Test_Class() { var src = @" #nullable enable [System.Runtime.CompilerServices.Union] class S1 { public S1(int x) => throw null!; public S1(bool? x) => throw null!; public object? Value => throw null!; } [System.Runtime.CompilerServices.Union] class S2 { public S2(int x) => throw null!; public S2(bool x) => throw null!; public object? Value => throw null!; } class Program { static void Test2(S1 s) { if (s is not int) { #line 100 _ = s switch { int => 1, bool => 3 }; } else { #line 200 _ = s switch { int => 1, bool => 3 }; } } static void Test4(S2 s) { if (s is not int) { #line 300 _ = s switch { int => 1, bool => 3 }; } else { #line 400 _ = s switch { int => 1, bool => 3 }; } } } "; var comp = CreateCompilation([src, UnionAttributeSource]); comp.VerifyDiagnostics( // (100,19): warning CS8655: The switch expression does not handle some null inputs (it is not exhaustive). For example, the pattern 'null' is not covered. // _ = s switch { int => 1, bool => 3 }; Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustiveForNull, "switch").WithArguments("null").WithLocation(100, 19) ); var src2 = @" #nullable enable class S1 { public bool? Value => throw null!; } class Program { static void Test2(S1 s) { _ = s.Value; if (s is not { Value: bool }) { #line 1000 _ = s switch { { Value: bool } => 1 }; } else { #line 2000 _ = s switch { { Value: bool } => 1 }; } } } "; var comp2 = CreateCompilation(src2); comp2.VerifyDiagnostics( // (1000,19): warning CS8655: The switch expression does not handle some null inputs (it is not exhaustive). For example, the pattern '{ Value: null }' is not covered. // _ = s switch { { Value: bool } => 1 }; Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustiveForNull, "switch").WithArguments("{ Value: null }").WithLocation(1000, 19) ); } [Theory] [CombinatorialData] public void NullableAnalysis_25_State_From_Value_Test([CombinatorialValues("class", "struct")] string typeKind) { var src = @" #nullable enable [System.Runtime.CompilerServices.Union] " + typeKind + @" S1 { public S1(int x) => throw null!; public S1(bool? x) => throw null!; public object? Value => throw null!; } [System.Runtime.CompilerServices.Union] " + typeKind + @" S2 { public S2(int x) => throw null!; public S2(bool x) => throw null!; public object? Value => throw null!; } class Program { static void Test2(S1 s) { if (s is 1) { #line 100 _ = s switch { int => 1, bool => 3 }; } else { #line 200 _ = s switch { int => 1, bool => 3 }; } } static void Test4(S2 s) { if (s is 1) { #line 300 _ = s switch { int => 1, bool => 3 }; } else { #line 400 _ = s switch { int => 1, bool => 3 }; } } } "; var comp = CreateCompilation([src, UnionAttributeSource]); comp.VerifyDiagnostics( // (200,19): warning CS8655: The switch expression does not handle some null inputs (it is not exhaustive). For example, the pattern 'null' is not covered. // _ = s switch { int => 1, bool => 3 }; Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustiveForNull, "switch").WithArguments("null").WithLocation(200, 19) ); } [Fact] public void NullableAnalysis_26_State_From_NotValue_Test() { var src = @" #nullable enable [System.Runtime.CompilerServices.Union] struct S1 { public S1(int x) => throw null!; public S1(bool? x) => throw null!; public object? Value => throw null!; } [System.Runtime.CompilerServices.Union] struct S2 { public S2(int x) => throw null!; public S2(bool x) => throw null!; public object? Value => throw null!; } class Program { static void Test2(S1 s) { if (s is not 1) { #line 100 _ = s switch { int => 1, bool => 3 }; } else { #line 200 _ = s switch { int => 1, bool => 3 }; } } static void Test4(S2 s) { if (s is not 1) { #line 300 _ = s switch { int => 1, bool => 3 }; } else { #line 400 _ = s switch { int => 1, bool => 3 }; } } } "; var comp = CreateCompilation([src, UnionAttributeSource]); comp.VerifyDiagnostics( // (100,19): warning CS8655: The switch expression does not handle some null inputs (it is not exhaustive). For example, the pattern 'null' is not covered. // _ = s switch { int => 1, bool => 3 }; Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustiveForNull, "switch").WithArguments("null").WithLocation(100, 19) ); } [Fact] public void NullableAnalysis_27_State_From_NotValue_Test_Class() { var src = @" #nullable enable [System.Runtime.CompilerServices.Union] class S1 { public S1(int x) => throw null!; public S1(bool? x) => throw null!; public object? Value => throw null!; } [System.Runtime.CompilerServices.Union] class S2 { public S2(int x) => throw null!; public S2(bool x) => throw null!; public object? Value => throw null!; } class Program { static void Test2(S1 s) { if (s is not 1) { #line 100 _ = s switch { int => 1, bool => 3 }; } else { #line 200 _ = s switch { int => 1, bool => 3 }; } } static void Test4(S2 s) { if (s is not 1) { #line 300 _ = s switch { int => 1, bool => 3 }; } else { #line 400 _ = s switch { int => 1, bool => 3 }; } } } "; var comp = CreateCompilation([src, UnionAttributeSource]); comp.VerifyDiagnostics( // (100,19): warning CS8655: The switch expression does not handle some null inputs (it is not exhaustive). For example, the pattern 'null' is not covered. // _ = s switch { int => 1, bool => 3 }; Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustiveForNull, "switch").WithArguments("null").WithLocation(100, 19) ); var src2 = @" #nullable enable class S1 { public bool? Value => throw null!; } class Program { static void Test2(S1 s) { _ = s.Value; if (s is not { Value: true }) { #line 1000 _ = s switch { { Value: bool } => 1 }; } else { #line 2000 _ = s switch { { Value: bool } => 1 }; } } } "; var comp2 = CreateCompilation(src2); comp2.VerifyDiagnostics( // (1000,19): warning CS8655: The switch expression does not handle some null inputs (it is not exhaustive). For example, the pattern '{ Value: null }' is not covered. // _ = s switch { { Value: bool } => 1 }; Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustiveForNull, "switch").WithArguments("{ Value: null }").WithLocation(1000, 19) ); } [Fact] public void NullableAnalysis_28() { var src = @" #nullable enable [System.Runtime.CompilerServices.Union] struct S1 { public S1(int x) => throw null!; public S1(bool? x) => throw null!; [System.Diagnostics.CodeAnalysis.MemberNotNull(nameof(OtherProp))] public object? Value => throw null!; public string? OtherProp => throw null!; } public interface I1 { object? Value { get; } } struct S2 : I1 { public S2(int x) => throw null!; public S2(bool? x) => throw null!; [System.Diagnostics.CodeAnalysis.MemberNotNull(nameof(OtherProp))] object? I1.Value => throw null!; public string? OtherProp => throw null!; } class Program { static void Test2(S1 s) { #line 200 _ = s switch { bool => s.OtherProp.ToString(), _ => """" }; } static void Test3(S2 s) { #line 300 _ = s switch { I1 and { Value: bool } => s.OtherProp.ToString(), _ => """" }; } } "; var comp = CreateCompilation([src, UnionAttributeSource, MemberNotNullAttributeDefinition]); comp.VerifyDiagnostics( // (300,51): warning CS8602: Dereference of a possibly null reference. // _ = s switch { I1 and { Value: bool } => s.OtherProp.ToString(), _ => "" }; Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "s.OtherProp").WithLocation(300, 51) ); } [Fact] public void NullableAnalysis_29() { var src = @" #nullable enable [System.Runtime.CompilerServices.Union] struct S1 { public S1(int x) => throw null!; public S1(bool? x) => throw null!; [System.Diagnostics.CodeAnalysis.MemberNotNull(nameof(OtherProp))] public object? Value => throw null!; public string? OtherProp => throw null!; } [System.Runtime.CompilerServices.Union] struct S2 { public S2(int x) => throw null!; public S2(bool? x) => throw null!; [System.Diagnostics.CodeAnalysis.MemberNotNull(nameof(OtherProp))] public object? Value => throw null!; public string? OtherProp => throw null!; } class Program { static void Test2(S1 s) { #line 200 _ = s switch { bool => s.OtherProp.ToString(), _ => """" }; } static void Test3(S2 s) { #line 300 _ = s switch { bool => s.OtherProp.ToString(), _ => """" }; } } "; var comp = CreateCompilation([src, MemberNotNullAttributeDefinition, UnionAttributeSource]); comp.VerifyDiagnostics(); } [Fact] public void NullableAnalysis_30() { var src = @" #nullable enable [System.Runtime.CompilerServices.Union] struct S1 { public S1(int x) => throw null!; public S1(bool? x) => throw null!; [System.Diagnostics.CodeAnalysis.MemberNotNull(nameof(OtherProp))] public object? Value => throw null!; public string? OtherProp => throw null!; } class Program { static void Test2(S1 s) { #line 200 _ = s switch { bool => s.OtherProp.ToString(), _ => """" }; } } "; var comp = CreateCompilation([src, MemberNotNullAttributeDefinition, UnionAttributeSource]); comp.VerifyDiagnostics(); } [Theory] [CombinatorialData] public void NullableAnalysis_31_Conversion_Value_Check([CombinatorialValues("class", "struct")] string typeKind) { var src = @" #nullable enable [System.Runtime.CompilerServices.Union] " + typeKind + @" S1 { public S1(string x) => throw null!; public S1(bool? x) => throw null!; public object? Value => throw null!; } class Program { static void Test1(string? x) { #line 100 S1 s = x; x.ToString(); } static void Test2(string? x) { #line 200 var s = new S1(x); x.ToString(); } } "; var comp = CreateCompilation([src, UnionAttributeSource]); comp.VerifyDiagnostics( // (100,16): warning CS8604: Possible null reference argument for parameter 'x' in 'S1.S1(string x)'. // S1 s = x; Diagnostic(ErrorCode.WRN_NullReferenceArgument, "x").WithArguments("x", "S1.S1(string x)").WithLocation(100, 16), // (200,24): warning CS8604: Possible null reference argument for parameter 'x' in 'S1.S1(string x)'. // var s = new S1(x); Diagnostic(ErrorCode.WRN_NullReferenceArgument, "x").WithArguments("x", "S1.S1(string x)").WithLocation(200, 24) ); } [Theory] [CombinatorialData] public void NullableAnalysis_32_Conversion_Value_Check([CombinatorialValues("class", "struct")] string typeKind) { var src = @" #nullable enable [System.Runtime.CompilerServices.Union] " + typeKind + @" S1 { public S1([System.Diagnostics.CodeAnalysis.DisallowNull] string? x) => throw null!; public S1([System.Diagnostics.CodeAnalysis.DisallowNull] bool? x) => throw null!; public object? Value => throw null!; } class Program { static void Test1(string? x) { #line 100 S1 s = x; x.ToString(); } static void Test2(string? x) { #line 200 var s = new S1(x); x.ToString(); } static void Test3(bool? x) { #line 300 S1 s = x; x.Value.ToString(); } static void Test4(bool? x) { #line 400 var s = new S1(x); x.Value.ToString(); } } "; var comp = CreateCompilation([src, UnionAttributeSource, DisallowNullAttributeDefinition]); comp.VerifyDiagnostics( // (100,16): warning CS8604: Possible null reference argument for parameter 'x' in 'S1.S1(string? x)'. // S1 s = x; Diagnostic(ErrorCode.WRN_NullReferenceArgument, "x").WithArguments("x", "S1.S1(string? x)").WithLocation(100, 16), // (200,24): warning CS8604: Possible null reference argument for parameter 'x' in 'S1.S1(string? x)'. // var s = new S1(x); Diagnostic(ErrorCode.WRN_NullReferenceArgument, "x").WithArguments("x", "S1.S1(string? x)").WithLocation(200, 24), // (300,16): warning CS8607: A possible null value may not be used for a type marked with [NotNull] or [DisallowNull] // S1 s = x; Diagnostic(ErrorCode.WRN_DisallowNullAttributeForbidsMaybeNullAssignment, "x").WithLocation(300, 16), // (400,24): warning CS8607: A possible null value may not be used for a type marked with [NotNull] or [DisallowNull] // var s = new S1(x); Diagnostic(ErrorCode.WRN_DisallowNullAttributeForbidsMaybeNullAssignment, "x").WithLocation(400, 24) ); } [Fact] public void NullableAnalysis_33_State_From_Default_NullableOfUnion() { var src = @" #nullable enable [System.Runtime.CompilerServices.Union] struct S1 { public S1(int x) => throw null!; public S1(bool? x) => throw null!; public object? Value => throw null!; } [System.Runtime.CompilerServices.Union] struct S2 { public S2(int x) => throw null!; public S2(bool x) => throw null!; public object? Value => throw null!; } class Program { static void Test1() { #line 100 S1? s = default(S1); _ = s.Value switch { int => 1, bool => 3 }; } static void Test3() { #line 300 S2? s = default(S2); _ = s.Value switch { int => 1, bool => 3 }; } } "; var comp = CreateCompilation([src, UnionAttributeSource]); comp.VerifyDiagnostics( // (101,21): warning CS8655: The switch expression does not handle some null inputs (it is not exhaustive). For example, the pattern 'null' is not covered. // _ = s.Value switch { int => 1, bool => 3 }; Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustiveForNull, "switch").WithArguments("null").WithLocation(101, 21) ); } [Fact] public void NullableAnalysis_34_State_From_Default_NullableOfUnion() { var src = @" #nullable enable [System.Runtime.CompilerServices.Union] struct S1 { public S1(int x) => throw null!; public S1(bool? x) => throw null!; public object? Value => throw null!; } [System.Runtime.CompilerServices.Union] struct S2 { public S2(int x) => throw null!; public S2(bool x) => throw null!; public object? Value => throw null!; } class Program { static void Test2(S1? s) { if (s is null) return; #line 200 _ = s.Value switch { int => 1, bool => 3 }; } static void Test4(S2? s) { if (s is null) return; #line 400 _ = s.Value switch { int => 1, bool => 3 }; } } "; var comp = CreateCompilation([src, UnionAttributeSource]); comp.VerifyDiagnostics(); } [Fact] public void NullableAnalysis_35_State_From_Constructor_NullableOfUnion() { var src = @" #nullable enable [System.Runtime.CompilerServices.Union] struct S1 { public S1(int x) => throw null!; public S1(string? x) => throw null!; public S1(bool? x) => throw null!; public object? Value => throw null!; } class Program { static void Test1() { #line 100 S1? s = new S1(1); _ = s.Value switch { int => 1, string => 2, bool => 3 }; } static void Test2() { #line 200 S1? s = new S1(""""); _ = s.Value switch { int => 1, string => 2, bool => 3 }; } static void Test3(string? x) { #line 300 S1? s = new S1(x); _ = s.Value switch { int => 1, string => 2, bool => 3 }; } static void Test4(bool x) { #line 400 S1? s = new S1(x); _ = s.Value switch { int => 1, string => 2, bool => 3 }; } static void Test5(bool? x) { #line 500 S1? s = new S1(x); _ = s.Value switch { int => 1, string => 2, bool => 3 }; } } "; var comp = CreateCompilation([src, UnionAttributeSource]); comp.VerifyDiagnostics( // (301,21): warning CS8655: The switch expression does not handle some null inputs (it is not exhaustive). For example, the pattern 'null' is not covered. // _ = s.Value switch { int => 1, string => 2, bool => 3 }; Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustiveForNull, "switch").WithArguments("null").WithLocation(301, 21), // (501,21): warning CS8655: The switch expression does not handle some null inputs (it is not exhaustive). For example, the pattern 'null' is not covered. // _ = s.Value switch { int => 1, string => 2, bool => 3 }; Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustiveForNull, "switch").WithArguments("null").WithLocation(501, 21) ); } [Fact] public void NullableAnalysis_36_State_From_Conversion_NullableOfUnion() { var src = @" #nullable enable [System.Runtime.CompilerServices.Union] struct S1 { public S1(int x) => throw null!; public S1(string? x) => throw null!; public S1(bool? x) => throw null!; public object? Value => throw null!; } class Program { static void Test1() { #line 100 S1? s = 1; _ = s.Value switch { int => 1, string => 2, bool => 3 }; } static void Test2() { #line 200 S1? s = """"; _ = s.Value switch { int => 1, string => 2, bool => 3 }; } static void Test3(string? x) { #line 300 S1? s = x; _ = s.Value switch { int => 1, string => 2, bool => 3 }; } static void Test4(bool x) { #line 400 S1? s = x; _ = s.Value switch { int => 1, string => 2, bool => 3 }; } static void Test5(bool? x) { #line 500 S1? s = x; _ = s.Value switch { int => 1, string => 2, bool => 3 }; } } "; var comp = CreateCompilation([src, UnionAttributeSource]); comp.VerifyDiagnostics( // (301,21): warning CS8655: The switch expression does not handle some null inputs (it is not exhaustive). For example, the pattern 'null' is not covered. // _ = s.Value switch { int => 1, string => 2, bool => 3 }; Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustiveForNull, "switch").WithArguments("null").WithLocation(301, 21), // (501,21): warning CS8655: The switch expression does not handle some null inputs (it is not exhaustive). For example, the pattern 'null' is not covered. // _ = s.Value switch { int => 1, string => 2, bool => 3 }; Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustiveForNull, "switch").WithArguments("null").WithLocation(501, 21) ); } [Fact] public void NullableAnalysis_37_State_From_Conversion_TupleLiteral_NullableOfUnion() { var src = @" #nullable enable [System.Runtime.CompilerServices.Union] struct S1 { public S1(int x) => throw null!; public S1(string? x) => throw null!; public S1(bool? x) => throw null!; public object? Value => throw null!; } class Program { static void Test1() { #line 100 (S1?, int) s = (1, 1); _ = s.Item1.Value switch { int => 1, string => 2, bool => 3 }; } static void Test2() { #line 200 (S1?, int) s = ("""", 1); _ = s.Item1.Value switch { int => 1, string => 2, bool => 3 }; } static void Test3(string? x) { #line 300 (S1?, int) s = (x, 1); _ = s.Item1.Value switch { int => 1, string => 2, bool => 3 }; } static void Test4(bool x) { #line 400 (S1?, int) s = (x, 1); _ = s.Item1.Value switch { int => 1, string => 2, bool => 3 }; } static void Test5(bool? x) { #line 500 (S1?, int) s = (x, 1); _ = s.Item1.Value switch { int => 1, string => 2, bool => 3 }; } } "; var comp = CreateCompilation([src, UnionAttributeSource]); comp.VerifyDiagnostics( // (301,27): warning CS8655: The switch expression does not handle some null inputs (it is not exhaustive). For example, the pattern 'null' is not covered. // _ = s.Item1.Value switch { int => 1, string => 2, bool => 3 }; Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustiveForNull, "switch").WithArguments("null").WithLocation(301, 27), // (501,27): warning CS8655: The switch expression does not handle some null inputs (it is not exhaustive). For example, the pattern 'null' is not covered. // _ = s.Item1.Value switch { int => 1, string => 2, bool => 3 }; Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustiveForNull, "switch").WithArguments("null").WithLocation(501, 27) ); } [Fact] public void NullableAnalysis_38_State_From_Conversion_TupleValue_NullableOfUnion() { var src = @" #nullable enable [System.Runtime.CompilerServices.Union] struct S1 { public S1(int x) => throw null!; public S1(string? x) => throw null!; public S1(bool? x) => throw null!; public object? Value => throw null!; } class Program { static void Test1((int, int) x) { #line 100 (S1?, int) s = x; _ = s.Item1.Value switch { int => 1, string => 2, bool => 3 }; } static void Test2((string, int) x) { #line 200 (S1?, int) s = x; _ = s.Item1.Value switch { int => 1, string => 2, bool => 3 }; } static void Test3((string?, int) x) { #line 300 (S1?, int) s = x; _ = s.Item1.Value switch { int => 1, string => 2, bool => 3 }; } static void Test4((bool, int) x) { #line 400 (S1?, int) s = x; _ = s.Item1.Value switch { int => 1, string => 2, bool => 3 }; } static void Test5((bool?, int) x) { #line 500 (S1?, int) s = x; _ = s.Item1.Value switch { int => 1, string => 2, bool => 3 }; } } "; var comp = CreateCompilation([src, UnionAttributeSource]); comp.VerifyDiagnostics( // (301,27): warning CS8655: The switch expression does not handle some null inputs (it is not exhaustive). For example, the pattern 'null' is not covered. // _ = s.Item1.Value switch { int => 1, string => 2, bool => 3 }; Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustiveForNull, "switch").WithArguments("null").WithLocation(301, 27), // (501,27): warning CS8655: The switch expression does not handle some null inputs (it is not exhaustive). For example, the pattern 'null' is not covered. // _ = s.Item1.Value switch { int => 1, string => 2, bool => 3 }; Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustiveForNull, "switch").WithArguments("null").WithLocation(501, 27) ); } [Fact] public void NullableAnalysis_39_State_From_Conversion_Cast_NullableOfUnion() { var src = @" #nullable enable [System.Runtime.CompilerServices.Union] struct S1 { public S1(int x) => throw null!; public S1(string? x) => throw null!; public S1(bool? x) => throw null!; public object? Value => throw null!; } class Program { static void Test1() { #line 100 S1? s = (S1?)1; _ = s.Value switch { int => 1, string => 2, bool => 3 }; } static void Test2() { #line 200 S1? s = (S1?)""""; _ = s.Value switch { int => 1, string => 2, bool => 3 }; } static void Test3(string? x) { #line 300 S1? s = (S1?)x; _ = s.Value switch { int => 1, string => 2, bool => 3 }; } static void Test4(bool x) { #line 400 S1? s = (S1?)x; _ = s.Value switch { int => 1, string => 2, bool => 3 }; } static void Test5(bool? x) { #line 500 S1? s = (S1?)x; _ = s.Value switch { int => 1, string => 2, bool => 3 }; } } "; var comp = CreateCompilation([src, UnionAttributeSource]); comp.VerifyDiagnostics( // (301,21): warning CS8655: The switch expression does not handle some null inputs (it is not exhaustive). For example, the pattern 'null' is not covered. // _ = s.Value switch { int => 1, string => 2, bool => 3 }; Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustiveForNull, "switch").WithArguments("null").WithLocation(301, 21), // (501,21): warning CS8655: The switch expression does not handle some null inputs (it is not exhaustive). For example, the pattern 'null' is not covered. // _ = s.Value switch { int => 1, string => 2, bool => 3 }; Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustiveForNull, "switch").WithArguments("null").WithLocation(501, 21) ); } [Fact] public void NullableAnalysis_40_State_From_Conversion_Cast_TupleLiteral_NullableOfUnion() { var src = @" #nullable enable [System.Runtime.CompilerServices.Union] struct S1 { public S1(int x) => throw null!; public S1(string? x) => throw null!; public S1(bool? x) => throw null!; public object? Value => throw null!; } class Program { static void Test1() { #line 100 (S1?, int) s = ((S1?, int))(1, 1); _ = s.Item1.Value switch { int => 1, string => 2, bool => 3 }; } static void Test2() { #line 200 (S1?, int) s = ((S1?, int))("""", 1); _ = s.Item1.Value switch { int => 1, string => 2, bool => 3 }; } static void Test3(string? x) { #line 300 (S1?, int) s = ((S1?, int))(x, 1); _ = s.Item1.Value switch { int => 1, string => 2, bool => 3 }; } static void Test4(bool x) { #line 400 (S1?, int) s = ((S1?, int))(x, 1); _ = s.Item1.Value switch { int => 1, string => 2, bool => 3 }; } static void Test5(bool? x) { #line 500 (S1?, int) s = ((S1?, int))(x, 1); _ = s.Item1.Value switch { int => 1, string => 2, bool => 3 }; } } "; var comp = CreateCompilation([src, UnionAttributeSource]); comp.VerifyDiagnostics( // (301,27): warning CS8655: The switch expression does not handle some null inputs (it is not exhaustive). For example, the pattern 'null' is not covered. // _ = s.Item1.Value switch { int => 1, string => 2, bool => 3 }; Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustiveForNull, "switch").WithArguments("null").WithLocation(301, 27), // (501,27): warning CS8655: The switch expression does not handle some null inputs (it is not exhaustive). For example, the pattern 'null' is not covered. // _ = s.Item1.Value switch { int => 1, string => 2, bool => 3 }; Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustiveForNull, "switch").WithArguments("null").WithLocation(501, 27) ); } [Fact] public void NullableAnalysis_41_State_From_Conversion_Cast_TupleValue_NullableOfUnion() { var src = @" #nullable enable [System.Runtime.CompilerServices.Union] struct S1 { public S1(int x) => throw null!; public S1(string? x) => throw null!; public S1(bool? x) => throw null!; public object? Value => throw null!; } class Program { static void Test1((int, int) x) { #line 100 (S1?, int) s = ((S1?, int))x; _ = s.Item1.Value switch { int => 1, string => 2, bool => 3 }; } static void Test2((string, int) x) { #line 200 (S1?, int) s = ((S1?, int))x; _ = s.Item1.Value switch { int => 1, string => 2, bool => 3 }; } static void Test3((string?, int) x) { #line 300 (S1?, int) s = ((S1?, int))x; _ = s.Item1.Value switch { int => 1, string => 2, bool => 3 }; } static void Test4((bool, int) x) { #line 400 (S1?, int) s = ((S1?, int))x; _ = s.Item1.Value switch { int => 1, string => 2, bool => 3 }; } static void Test5((bool?, int) x) { #line 500 (S1?, int) s = ((S1?, int))x; _ = s.Item1.Value switch { int => 1, string => 2, bool => 3 }; } } "; var comp = CreateCompilation([src, UnionAttributeSource]); comp.VerifyDiagnostics( // (301,27): warning CS8655: The switch expression does not handle some null inputs (it is not exhaustive). For example, the pattern 'null' is not covered. // _ = s.Item1.Value switch { int => 1, string => 2, bool => 3 }; Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustiveForNull, "switch").WithArguments("null").WithLocation(301, 27), // (501,27): warning CS8655: The switch expression does not handle some null inputs (it is not exhaustive). For example, the pattern 'null' is not covered. // _ = s.Item1.Value switch { int => 1, string => 2, bool => 3 }; Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustiveForNull, "switch").WithArguments("null").WithLocation(501, 27) ); } [Fact] public void NullableAnalysis_42_State_From_Null_Test_NullableOfUnion() { var src = @" #nullable enable [System.Runtime.CompilerServices.Union] struct S1 { public S1(int x) => throw null!; public S1(bool? x) => throw null!; public object? Value => throw null!; } [System.Runtime.CompilerServices.Union] struct S2 { public S2(int x) => throw null!; public S2(bool x) => throw null!; public object? Value => throw null!; } class Program { static void Test2(S1? s0) { if (s0 is null) return; if (s0.Value is null) { var s = s0; #line 100 _ = s.Value switch { int => 1, bool => 3 }; } else { var s = s0; #line 200 _ = s.Value switch { int => 1, bool => 3 }; } } static void Test4(S2? s0) { if (s0 is null) return; if (s0.Value is null) { var s = s0; #line 300 _ = s.Value switch { int => 1, bool => 3 }; } else { var s = s0; #line 400 _ = s.Value switch { int => 1, bool => 3 }; } } } "; var comp = CreateCompilation([src, UnionAttributeSource]); comp.VerifyDiagnostics( // (100,25): warning CS8655: The switch expression does not handle some null inputs (it is not exhaustive). For example, the pattern 'null' is not covered. // _ = s.Value switch { int => 1, bool => 3 }; Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustiveForNull, "switch").WithArguments("null").WithLocation(100, 25), // (300,25): warning CS8655: The switch expression does not handle some null inputs (it is not exhaustive). For example, the pattern 'null' is not covered. // _ = s.Value switch { int => 1, bool => 3 }; Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustiveForNull, "switch").WithArguments("null").WithLocation(300, 25) ); } [Fact] public void NullableAnalysis_43_State_From_NotNull_Test_NullableOfUnion() { var src = @" #nullable enable [System.Runtime.CompilerServices.Union] struct S1 { public S1(int x) => throw null!; public S1(bool? x) => throw null!; public object? Value => throw null!; } [System.Runtime.CompilerServices.Union] struct S2 { public S2(int x) => throw null!; public S2(bool x) => throw null!; public object? Value => throw null!; } class Program { static void Test2(S1? s0) { if (s0 is null) return; if (s0.Value is not null) { var s = s0; #line 100 _ = s.Value switch { int => 1, bool => 3 }; } else { var s = s0; #line 200 _ = s.Value switch { int => 1, bool => 3 }; } } static void Test4(S2? s0) { if (s0 is null) return; if (s0.Value is not null) { var s = s0; #line 300 _ = s.Value switch { int => 1, bool => 3 }; } else { var s = s0; #line 400 _ = s.Value switch { int => 1, bool => 3 }; } } } "; var comp = CreateCompilation([src, UnionAttributeSource]); comp.VerifyDiagnostics( // (200,25): warning CS8655: The switch expression does not handle some null inputs (it is not exhaustive). For example, the pattern 'null' is not covered. // _ = s.Value switch { int => 1, bool => 3 }; Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustiveForNull, "switch").WithArguments("null").WithLocation(200, 25), // (400,25): warning CS8655: The switch expression does not handle some null inputs (it is not exhaustive). For example, the pattern 'null' is not covered. // _ = s.Value switch { int => 1, bool => 3 }; Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustiveForNull, "switch").WithArguments("null").WithLocation(400, 25) ); } [Fact] public void NullableAnalysis_44_Conversion_Value_Check_ReinferConstructor() { var src = @" #nullable enable [System.Runtime.CompilerServices.Union] struct S1<T> { public S1(T x) => throw null!; public S1(bool x) => throw null!; public object? Value => throw null!; } class Program { static void Test1(string? x, string? y) { var s = GetS1(y); #line 100 s = x; x.ToString(); } static void Test2(string? x, string y) { var s = GetS1(y); #line 200 s = x; x.ToString(); } static S1<T> GetS1<T>(T x) { return default; } } "; var comp = CreateCompilation([src, UnionAttributeSource]); comp.VerifyDiagnostics( // (101,9): warning CS8602: Dereference of a possibly null reference. // x.ToString(); Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "x").WithLocation(101, 9), // (200,13): warning CS8604: Possible null reference argument for parameter 'x' in 'S1<string>.S1(string x)'. // s = x; Diagnostic(ErrorCode.WRN_NullReferenceArgument, "x").WithArguments("x", "S1<string>.S1(string x)").WithLocation(200, 13) ); } [Fact] public void NullableAnalysis_45_ValuePropertyOfTheInterfaceIsTargetedNotValuePropertyOfTheType() { var src = @" #nullable enable [System.Runtime.CompilerServices.Union] struct S1 : S1.IUnionMembers { public object? Value => throw null!; public interface IUnionMembers { public static S1 Create(int x) => throw null!; public static S1 Create(bool? x) => throw null!; public object? Value { get; } } } class Program { static void Test2(S1 s) { if (s is not null) { #line 100 s.Value.ToString(); } else { #line 200 s.Value.ToString(); } } static void Test4(S1 s) { if (s is null) { #line 300 s.Value.ToString(); } else { #line 400 s.Value.ToString(); } } } "; var comp = CreateCompilation([src, UnionAttributeSource]); comp.VerifyDiagnostics( // (100,13): warning CS8602: Dereference of a possibly null reference. // s.Value.ToString(); Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "s.Value").WithLocation(100, 13), // (200,13): warning CS8602: Dereference of a possibly null reference. // s.Value.ToString(); Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "s.Value").WithLocation(200, 13), // (300,13): warning CS8602: Dereference of a possibly null reference. // s.Value.ToString(); Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "s.Value").WithLocation(300, 13), // (400,13): warning CS8602: Dereference of a possibly null reference. // s.Value.ToString(); Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "s.Value").WithLocation(400, 13) ); } [Theory] [CombinatorialData] public void NullableAnalysis_46_State_From_isExplicitNotNullTest([CombinatorialValues("int", "System.Int32")] string typeNameSyntax) { var src = @" #nullable enable [System.Runtime.CompilerServices.Union] struct S2 { public S2(int x) => throw null!; public S2(bool x) => throw null!; public object? Value => throw null!; } struct S3 { public object Value => throw null!; } class Program { static void Test1(S2 s) { if (s is " + typeNameSyntax + @") return; #line 100 s.Value.ToString(); } static void Test2(S3 s) { if (s is { Value: " + typeNameSyntax + @" }) return; #line 200 s.Value.ToString(); } } "; var comp = CreateCompilation([src, UnionAttributeSource]); comp.VerifyDiagnostics(); } [Theory] [CombinatorialData] public void NullableAnalysis_47_State_From_isExplicitNotNullTest([CombinatorialValues("object", "System.Object")] string typeNameSyntax) { var src = @" #nullable enable [System.Runtime.CompilerServices.Union] struct S2 { public S2(int x) => throw null!; public S2(bool x) => throw null!; public object Value => throw null!; } struct S3 { public object Value => throw null!; } class Program { static void Test1(S2 s) { if (s is " + typeNameSyntax + @") return; #line 100 s.Value.ToString(); } static void Test2(S3 s) { if (s is " + typeNameSyntax + @") return; #line 200 s.Value.ToString(); } static void Test3(S2 s) { if (s switch { " + typeNameSyntax + @" => true, _ => false }) return; #line 300 s.Value.ToString(); } static void Test4(S3 s) { if (s switch { " + typeNameSyntax + @" => true, _ => false }) return; #line 400 s.Value.ToString(); } } "; var comp = CreateCompilation([src, UnionAttributeSource]); comp.VerifyDiagnostics( // (21,13): warning CS0183: The given expression is always of the provided ('object') type // if (s is System.Object) return; Diagnostic(ErrorCode.WRN_IsAlwaysTrue, "s is " + typeNameSyntax).WithArguments("object").WithLocation(21, 13), // (105,13): warning CS0183: The given expression is always of the provided ('object') type // if (s is System.Object) return; Diagnostic(ErrorCode.WRN_IsAlwaysTrue, "s is " + typeNameSyntax).WithArguments("object").WithLocation(105, 13), // (205,47): error CS8510: The pattern is unreachable. It has already been handled by a previous arm of the switch expression or it is impossible to match. // if (s switch { System.Object => true, _ => false }) return; Diagnostic(ErrorCode.ERR_SwitchArmSubsumed, "_").WithLocation(205, 34 + typeNameSyntax.Length), // (305,47): error CS8510: The pattern is unreachable. It has already been handled by a previous arm of the switch expression or it is impossible to match. // if (s switch { System.Object => true, _ => false }) return; Diagnostic(ErrorCode.ERR_SwitchArmSubsumed, "_").WithLocation(305, 34 + typeNameSyntax.Length) ); } [Theory] [CombinatorialData] public void NullableAnalysis_48_State_From_isExplicitNotNullTest([CombinatorialValues("int", "System.Int32")] string typeNameSyntax) { var src = @" #nullable enable struct S0<T> { public T S => default(T)!; } [System.Runtime.CompilerServices.Union] struct S2 { public S2(int x) => throw null!; public S2(bool x) => throw null!; public object? Value => throw null!; } struct S3 { public object Value => throw null!; } class Program { static void Test1(S0<S2> s) { if (s is { S: " + typeNameSyntax + @" }) return; #line 100 s.S.Value.ToString(); } static void Test2(S0<S3> s) { if (s is { S.Value: " + typeNameSyntax + @" }) return; #line 200 s.S.Value.ToString(); } } "; var comp = CreateCompilation([src, UnionAttributeSource]); comp.VerifyDiagnostics(); } [Theory] [CombinatorialData] public void NullableAnalysis_49_State_From_isExplicitNotNullTest([CombinatorialValues("object", "System.Object")] string typeNameSyntax) { var src = @" #nullable enable struct S0<T> { public T S => default(T)!; } [System.Runtime.CompilerServices.Union] struct S2 { public S2(int x) => throw null!; public S2(bool x) => throw null!; public object Value => throw null!; } struct S3 { public object Value => throw null!; } class Program { static void Test1(S0<S2> s) { if (s is { S: " + typeNameSyntax + @" }) return; #line 100 s.S.Value.ToString(); } static void Test2(S0<S3> s) { if (s is { S.Value: " + typeNameSyntax + @" }) return; #line 200 s.S.Value.ToString(); } } "; var comp = CreateCompilation([src, UnionAttributeSource]); comp.VerifyDiagnostics( // (200,9): warning CS8602: Dereference of a possibly null reference. // s.S.Value.ToString(); Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "s.S.Value").WithLocation(200, 9) ); } [Theory] [CombinatorialData] public void NullableAnalysis_50_State_From_isExplicitNotNullTest([CombinatorialValues("int", "System.Int32")] string typeNameSyntax) { var src = @" #nullable enable [System.Runtime.CompilerServices.Union] class S2 { public S2(int x) => throw null!; public S2(bool x) => throw null!; public object? Value => throw null!; } class S3 { public object Value => throw null!; } class Program { static void Test1(S2 s) { if (s is " + typeNameSyntax + @") return; #line 100 s.Value.ToString(); } static void Test2(S3 s) { if (s is { Value: " + typeNameSyntax + @" }) return; #line 200 s.Value.ToString(); } } "; var comp = CreateCompilation([src, UnionAttributeSource]); comp.VerifyDiagnostics(); } [Theory] [CombinatorialData] public void NullableAnalysis_51_State_From_isExplicitNotNullTest([CombinatorialValues("object", "System.Object")] string typeNameSyntax) { var src = @" #nullable enable [System.Runtime.CompilerServices.Union] class S2 { public S2(int x) => throw null!; public S2(bool x) => throw null!; public object Value => throw null!; } class S3 { public object Value => throw null!; } class Program { static void Test1(S2 s) { if (s is " + typeNameSyntax + @") return; #line 100 s.Value.ToString(); } static void Test2(S3 s) { if (s is " + typeNameSyntax + @") return; #line 200 s.Value.ToString(); } static void Test3(S2 s) { if (s switch { " + typeNameSyntax + @" => true, _ => false }) return; #line 300 s.Value.ToString(); } static void Test4(S3 s) { if (s switch { " + typeNameSyntax + @" => true, _ => false }) return; #line 400 s.Value.ToString(); } } "; var comp = CreateCompilation([src, UnionAttributeSource]); comp.VerifyDiagnostics( // (100,9): warning CS8602: Dereference of a possibly null reference. // s.Value.ToString(); Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "s").WithLocation(100, 9), // (200,9): warning CS8602: Dereference of a possibly null reference. // s.Value.ToString(); Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "s").WithLocation(200, 9), // (300,9): warning CS8602: Dereference of a possibly null reference. // s.Value.ToString(); Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "s").WithLocation(300, 9), // (400,9): warning CS8602: Dereference of a possibly null reference. // s.Value.ToString(); Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "s").WithLocation(400, 9) ); } [Theory] [CombinatorialData] public void NullableAnalysis_52_State_From_isExplicitNotNullTest([CombinatorialValues("int", "System.Int32")] string typeNameSyntax) { var src = @" #nullable enable struct S0<T> where T : class { public T S => default(T)!; } [System.Runtime.CompilerServices.Union] class S2 { public S2(int x) => throw null!; public S2(bool x) => throw null!; public object? Value => throw null!; } class S3 { public object Value => throw null!; } class Program { static void Test1(S0<S2> s) { if (s is { S: " + typeNameSyntax + @" }) return; #line 100 s.S.Value.ToString(); } static void Test2(S0<S3> s) { if (s is { S.Value: " + typeNameSyntax + @" }) return; #line 200 s.S.Value.ToString(); } } "; var comp = CreateCompilation([src, UnionAttributeSource]); comp.VerifyDiagnostics(); } [Theory] [CombinatorialData] public void NullableAnalysis_53_State_From_isExplicitNotNullTest([CombinatorialValues("object", "System.Object")] string typeNameSyntax) { var src = @" #nullable enable struct S0<T> where T : class { public T S => default(T)!; } [System.Runtime.CompilerServices.Union] class S2 { public S2(int x) => throw null!; public S2(bool x) => throw null!; public object Value => throw null!; } class S3 { public object Value => throw null!; } class Program { static void Test1(S0<S2> s) { if (s is { S: " + typeNameSyntax + @" }) return; #line 100 s.S.Value.ToString(); } static void Test2(S0<S3> s) { if (s is { S.Value: " + typeNameSyntax + @" }) return; #line 200 s.S.Value.ToString(); } } "; var comp = CreateCompilation([src, UnionAttributeSource]); comp.VerifyDiagnostics( // (100,9): warning CS8602: Dereference of a possibly null reference. // s.S.Value.ToString(); Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "s.S").WithLocation(100, 9), // (200,9): warning CS8602: Dereference of a possibly null reference. // s.S.Value.ToString(); Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "s.S.Value").WithLocation(200, 9) ); } [Theory] [CombinatorialData] public void NullableAnalysis_54_State_From_isExplicitNotNullTest([CombinatorialValues("int", "System.Int32")] string typeNameSyntax) { var src = @" #nullable enable [System.Runtime.CompilerServices.Union] struct S2 { public S2(int x) => throw null!; public S2(bool x) => throw null!; public object? Value => throw null!; } struct S3 { public object Value => throw null!; } class Program { static void Test1(S2? s) { if (s is null) return; if (s is " + typeNameSyntax + @") return; #line 100 s.Value.Value.ToString(); } static void Test2(S3? s) { if (s is null) return; if (s is { Value: " + typeNameSyntax + @" }) return; #line 200 s.Value.Value.ToString(); } } "; var comp = CreateCompilation([src, UnionAttributeSource]); comp.VerifyDiagnostics(); } [Theory] [CombinatorialData] public void NullableAnalysis_55_State_From_isExplicitNotNullTest([CombinatorialValues("object", "System.Object")] string typeNameSyntax) { var src = @" #nullable enable [System.Runtime.CompilerServices.Union] struct S2 { public S2(int x) => throw null!; public S2(bool x) => throw null!; public object Value => throw null!; } struct S3 { public object Value => throw null!; } class Program { static void Test1(S2? s) { if (s is null) return; if (s is " + typeNameSyntax + @") return; #line 100 s.Value.Value.ToString(); } static void Test2(S3? s) { if (s is null) return; if (s is " + typeNameSyntax + @") return; #line 200 s.Value.Value.ToString(); } static void Test3(S2? s) { if (s is null) return; if (s switch { " + typeNameSyntax + @" => true, _ => false }) return; #line 300 s.Value.Value.ToString(); } static void Test4(S3? s) { if (s is null) return; if (s switch { " + typeNameSyntax + @" => true, _ => false }) return; #line 400 s.Value.Value.ToString(); } } "; var comp = CreateCompilation([src, UnionAttributeSource]); comp.VerifyDiagnostics( // (100,9): warning CS8629: Nullable value type may be null. // s.Value.Value.ToString(); Diagnostic(ErrorCode.WRN_NullableValueTypeMayBeNull, "s").WithLocation(100, 9), // (200,9): warning CS8629: Nullable value type may be null. // s.Value.Value.ToString(); Diagnostic(ErrorCode.WRN_NullableValueTypeMayBeNull, "s").WithLocation(200, 9), // (300,9): warning CS8629: Nullable value type may be null. // s.Value.Value.ToString(); Diagnostic(ErrorCode.WRN_NullableValueTypeMayBeNull, "s").WithLocation(300, 9), // (400,9): warning CS8629: Nullable value type may be null. // s.Value.Value.ToString(); Diagnostic(ErrorCode.WRN_NullableValueTypeMayBeNull, "s").WithLocation(400, 9) ); } [Theory] [CombinatorialData] public void NullableAnalysis_56_State_From_isExplicitNotNullTest([CombinatorialValues("int", "System.Int32")] string typeNameSyntax) { var src = @" #nullable enable struct S0<T> where T : struct { public T? S => default(T)!; } [System.Runtime.CompilerServices.Union] struct S2 { public S2(int x) => throw null!; public S2(bool x) => throw null!; public object? Value => throw null!; } struct S3 { public object Value => throw null!; } class Program { static void Test1(S0<S2> s) { if (s.S is null) return; if (s is { S: " + typeNameSyntax + @" }) return; #line 100 s.S.Value.Value.ToString(); } static void Test2(S0<S3> s) { if (s.S is null) return; if (s is { S.Value: " + typeNameSyntax + @" }) return; #line 200 s.S.Value.Value.ToString(); } } "; var comp = CreateCompilation([src, UnionAttributeSource]); comp.VerifyDiagnostics(); } [Theory] [CombinatorialData] public void NullableAnalysis_57_State_From_isExplicitNotNullTest([CombinatorialValues("object", "System.Object")] string typeNameSyntax) { var src = @" #nullable enable struct S0<T> where T : struct { public T? S => default(T)!; } [System.Runtime.CompilerServices.Union] struct S2 { public S2(int x) => throw null!; public S2(bool x) => throw null!; public object Value => throw null!; } struct S3 { public object Value => throw null!; } class Program { static void Test1(S0<S2> s) { if (s.S is null) return; if (s is { S: " + typeNameSyntax + @" }) return; #line 100 s.S.Value.Value.ToString(); } static void Test2(S0<S3> s) { if (s.S is null) return; if (s is { S.Value: " + typeNameSyntax + @" }) return; #line 200 s.S.Value.Value.ToString(); } } "; var comp = CreateCompilation([src, UnionAttributeSource]); comp.VerifyDiagnostics( // (100,9): warning CS8629: Nullable value type may be null. // s.S.Value.Value.ToString(); Diagnostic(ErrorCode.WRN_NullableValueTypeMayBeNull, "s.S").WithLocation(100, 9), // (200,9): warning CS8602: Dereference of a possibly null reference. // s.S.Value.Value.ToString(); Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "s.S.Value.Value").WithLocation(200, 9) ); } [Theory] [CombinatorialData] public void NullableAnalysis_58_State_From_isExplicitNotNullTest([CombinatorialValues("int", "System.Int32")] string typeNameSyntax) { var src = @" #nullable enable [System.Runtime.CompilerServices.Union] struct S2 { public S2(int x) => throw null!; public S2(bool x) => throw null!; public object? Value => throw null!; } struct S3 { public object Value => throw null!; } class Program { static void Test1(S2 s) { switch (s) { case " + typeNameSyntax + @": return; default: #line 100 s.Value.ToString(); break; } } static void Test2(S3 s) { switch (s) { case { Value: " + typeNameSyntax + @" }: return; default: #line 200 s.Value.ToString(); break; } } } "; var comp = CreateCompilation([src, UnionAttributeSource]); comp.VerifyDiagnostics(); } [Theory] [CombinatorialData] public void NullableAnalysis_59_State_From_isExplicitNotNullTest([CombinatorialValues("object", "System.Object")] string typeNameSyntax) { var src = @" #nullable enable [System.Runtime.CompilerServices.Union] struct S2 { public S2(int x) => throw null!; public S2(bool x) => throw null!; public object Value => throw null!; } struct S3 { public object Value => throw null!; } class Program { static void Test1(S2 s) { switch (s) { case " + typeNameSyntax + @": return; default: #line 100 s.Value.ToString(); break; } } static void Test2(S3 s) { switch (s) { case { Value: " + typeNameSyntax + @" }: return; default: #line 200 s.Value.ToString(); break; } } } "; var comp = CreateCompilation([src, UnionAttributeSource]); comp.VerifyDiagnostics( // (100,17): warning CS0162: Unreachable code detected // s.Value.ToString(); Diagnostic(ErrorCode.WRN_UnreachableCode, "s").WithLocation(100, 17), // (200,17): warning CS8602: Dereference of a possibly null reference. // s.Value.ToString(); Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "s.Value").WithLocation(200, 17) ); } [Theory] [CombinatorialData] public void NullableAnalysis_61_State_From_isExplicitNotNullTest([CombinatorialValues("int", "System.Int32")] string typeNameSyntax) { var src = @" #nullable enable [System.Runtime.CompilerServices.Union] struct S2 { public S2(int x) => throw null!; public S2(bool x) => throw null!; public object? Value => throw null!; } struct S3 { public object Value => throw null!; } class Program { static string? Test1(S2 s) { return s switch { " + typeNameSyntax + @" => null, _ => #line 100 s.Value.ToString() }; } static string? Test2(S3 s) { return s switch { { Value: " + typeNameSyntax + @" } => null, _ => #line 200 s.Value.ToString() }; } } "; var comp = CreateCompilation([src, UnionAttributeSource]); comp.VerifyDiagnostics(); } [Theory] [CombinatorialData] public void NullableAnalysis_62_State_From_isExplicitNotNullTest([CombinatorialValues("object", "System.Object")] string typeNameSyntax) { var src = @" #nullable enable [System.Runtime.CompilerServices.Union] struct S2 { public S2(int x) => throw null!; public S2(bool x) => throw null!; public object Value => throw null!; } struct S3 { public object Value => throw null!; } class Program { static string? Test1(S2 s) { return s switch { " + typeNameSyntax + @" => null, _ => #line 100 s.Value.ToString() }; } static string? Test2(S3 s) { return s switch { { Value: " + typeNameSyntax + @" } => null, _ => #line 200 s.Value.ToString() }; } } "; var comp = CreateCompilation([src, UnionAttributeSource]); comp.VerifyDiagnostics( // (24,13): error CS8510: The pattern is unreachable. It has already been handled by a previous arm of the switch expression or it is impossible to match. // _ => Diagnostic(ErrorCode.ERR_SwitchArmSubsumed, "_").WithLocation(24, 13), // (200,17): warning CS8602: Dereference of a possibly null reference. // s.Value.ToString() Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "s.Value").WithLocation(200, 17) ); } [Fact] public void NullableAnalysis_63_State_From_DefaultStructConstructor() { var src = @" #nullable enable [System.Runtime.CompilerServices.Union] struct S1 { public S1(int x) => throw null!; public S1(bool? x) => throw null!; public object? Value => throw null!; } [System.Runtime.CompilerServices.Union] struct S2 { public S2(int x) => throw null!; public S2(bool x) => throw null!; public object? Value => throw null!; } class Program { static void Test1() { #line 100 S1 s = new S1(); _ = s switch { int => 1, bool => 3 }; } static void Test3() { #line 300 S2 s = new S2(); _ = s switch { int => 1, bool => 3 }; } } "; var comp = CreateCompilation([src, UnionAttributeSource]); comp.VerifyDiagnostics( // (101,15): warning CS8655: The switch expression does not handle some null inputs (it is not exhaustive). For example, the pattern 'null' is not covered. // _ = s switch { int => 1, bool => 3 }; Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustiveForNull, "switch").WithArguments("null").WithLocation(101, 15) ); } [Fact] public void NullableAnalysis_MemberProvider_01_State_From_Default() { var src = @" #nullable enable [System.Runtime.CompilerServices.Union] struct S1 : S1.IUnionMembers { object? IUnionMembers.Value => throw null!; public interface IUnionMembers { public static S1 Create(int x) => throw null!; public static S1 Create(bool? x) => throw null!; public object? Value { get; } } } [System.Runtime.CompilerServices.Union] struct S2 : S2.IUnionMembers { object? IUnionMembers.Value => throw null!; public interface IUnionMembers { public static S2 Create(int x) => throw null!; public static S2 Create(bool x) => throw null!; public object? Value { get; } } } class Program { static void Test1() { #line 100 S1 s = default; _ = s switch { int => 1, bool => 3 }; } static void Test3() { #line 300 S2 s = default; _ = s switch { int => 1, bool => 3 }; } } "; var comp = CreateCompilation([src, UnionAttributeSource]); comp.VerifyDiagnostics( // (101,15): warning CS8655: The switch expression does not handle some null inputs (it is not exhaustive). For example, the pattern 'null' is not covered. // _ = s switch { int => 1, bool => 3 }; Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustiveForNull, "switch").WithArguments("null").WithLocation(101, 15) ); } [Fact] public void NullableAnalysis_MemberProvider_02_State_From_Default() { var src = @" #nullable enable [System.Runtime.CompilerServices.Union] class S1 : S1.IUnionMembers { object? IUnionMembers.Value => throw null!; public interface IUnionMembers { public static S1 Create(int x) => throw null!; public static S1 Create(bool? x) => throw null!; public object? Value { get; } } } [System.Runtime.CompilerServices.Union] class S2 : S2.IUnionMembers { object? IUnionMembers.Value => throw null!; public interface IUnionMembers { public static S2 Create(int x) => throw null!; public static S2 Create(bool x) => throw null!; public object? Value { get; } } } class Program { static void Test1() { #line 100 S1? s = null; _ = s switch { int => 1, bool => 3 }; } static void Test3() { #line 300 S2? s = null; _ = s switch { int => 1, bool => 3 }; } } "; var comp = CreateCompilation([src, UnionAttributeSource]); comp.VerifyDiagnostics( // (101,15): warning CS8655: The switch expression does not handle some null inputs (it is not exhaustive). For example, the pattern 'null' is not covered. // _ = s switch { int => 1, bool => 3 }; Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustiveForNull, "switch").WithArguments("null").WithLocation(101, 15), // (301,15): warning CS8655: The switch expression does not handle some null inputs (it is not exhaustive). For example, the pattern 'null' is not covered. // _ = s switch { int => 1, bool => 3 }; Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustiveForNull, "switch").WithArguments("null").WithLocation(301, 15) ); } [Theory] [CombinatorialData] public void NullableAnalysis_MemberProvider_03_State_From_Default([CombinatorialValues("class", "struct")] string typeKind) { var src = @" #nullable enable [System.Runtime.CompilerServices.Union] " + typeKind + @" S1 : S1.IUnionMembers { object? IUnionMembers.Value => throw null!; public interface IUnionMembers { public static S1 Create(int x) => throw null!; public static S1 Create(bool? x) => throw null!; public object? Value { get; } } } [System.Runtime.CompilerServices.Union] " + typeKind + @" S2 : S2.IUnionMembers { object? IUnionMembers.Value => throw null!; public interface IUnionMembers { public static S2 Create(int x) => throw null!; public static S2 Create(bool x) => throw null!; public object? Value { get; } } } class Program { static void Test2(S1 s) { #line 200 _ = s switch { int => 1, bool => 3 }; } static void Test4(S2 s) { #line 400 _ = s switch { int => 1, bool => 3 }; } } "; var comp = CreateCompilation([src, UnionAttributeSource]); comp.VerifyDiagnostics( // (200,15): warning CS8655: The switch expression does not handle some null inputs (it is not exhaustive). For example, the pattern 'null' is not covered. // _ = s switch { int => 1, bool => 3 }; Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustiveForNull, "switch").WithArguments("null").WithLocation(200, 15) ); } [Theory] [CombinatorialData] public void NullableAnalysis_MemberProvider_04_State_From_Default_PostCondition([CombinatorialValues("class", "struct")] string typeKind) { var src = @" #nullable enable [System.Runtime.CompilerServices.Union] " + typeKind + @" S1 : S1.IUnionMembers { object? IUnionMembers.Value => throw null!; public interface IUnionMembers { public static S1 Create(int x) => throw null!; public static S1 Create([System.Diagnostics.CodeAnalysis.NotNull] bool? x) => throw null!; public object? Value { get; } } } class Program { static void Test2(S1 s) { #line 200 _ = s switch { int => 1, bool => 3 }; } } "; var comp = CreateCompilation([src, UnionAttributeSource, NotNullAttributeDefinition]); comp.VerifyDiagnostics( // (200,15): warning CS8655: The switch expression does not handle some null inputs (it is not exhaustive). For example, the pattern 'null' is not covered. // _ = s switch { int => 1, bool => 3 }; Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustiveForNull, "switch").WithArguments("null").WithLocation(200, 15) ); } [Theory] [CombinatorialData] public void NullableAnalysis_MemberProvider_05_State_From_Constructor([CombinatorialValues("class", "struct")] string typeKind) { var src = @" #nullable enable [System.Runtime.CompilerServices.Union] " + typeKind + @" S1 : S1.IUnionMembers { public S1(int x) => throw null!; public S1(string? x) => throw null!; public S1(bool? x) => throw null!; object? IUnionMembers.Value => throw null!; public interface IUnionMembers { public static S1 Create(int x) => throw null!; public static S1 Create(string? x) => throw null!; public static S1 Create(bool? x) => throw null!; public object? Value { get; } } } class Program { static void Test1() { #line 100 var s = new S1(1); _ = s switch { int => 1, string => 2, bool => 3 }; } static void Test2() { #line 200 var s = new S1(""""); _ = s switch { int => 1, string => 2, bool => 3 }; } static void Test3(string? x) { #line 300 var s = new S1(x); _ = s switch { int => 1, string => 2, bool => 3 }; } static void Test4(bool x) { #line 400 var s = new S1(x); _ = s switch { int => 1, string => 2, bool => 3 }; } static void Test5(bool? x) { #line 500 var s = new S1(x); _ = s switch { int => 1, string => 2, bool => 3 }; } } "; var comp = CreateCompilation([src, UnionAttributeSource]); comp.VerifyDiagnostics( // (101,15): warning CS8655: The switch expression does not handle some null inputs (it is not exhaustive). For example, the pattern 'null' is not covered. // _ = s switch { int => 1, string => 2, bool => 3 }; Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustiveForNull, "switch").WithArguments("null").WithLocation(101, 15), // (201,15): warning CS8655: The switch expression does not handle some null inputs (it is not exhaustive). For example, the pattern 'null' is not covered. // _ = s switch { int => 1, string => 2, bool => 3 }; Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustiveForNull, "switch").WithArguments("null").WithLocation(201, 15), // (301,15): warning CS8655: The switch expression does not handle some null inputs (it is not exhaustive). For example, the pattern 'null' is not covered. // _ = s switch { int => 1, string => 2, bool => 3 }; Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustiveForNull, "switch").WithArguments("null").WithLocation(301, 15), // (401,15): warning CS8655: The switch expression does not handle some null inputs (it is not exhaustive). For example, the pattern 'null' is not covered. // _ = s switch { int => 1, string => 2, bool => 3 }; Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustiveForNull, "switch").WithArguments("null").WithLocation(401, 15), // (501,15): warning CS8655: The switch expression does not handle some null inputs (it is not exhaustive). For example, the pattern 'null' is not covered. // _ = s switch { int => 1, string => 2, bool => 3 }; Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustiveForNull, "switch").WithArguments("null").WithLocation(501, 15) ); } [Theory] [CombinatorialData] public void NullableAnalysis_MemberProvider_06_State_From_Constructor_PostCondition([CombinatorialValues("class", "struct")] string typeKind) { var src = @" #nullable enable [System.Runtime.CompilerServices.Union] " + typeKind + @" S1 : S1.IUnionMembers { public S1(int x) => throw null!; public S1([System.Diagnostics.CodeAnalysis.NotNull] string? x) => throw null!; public S1([System.Diagnostics.CodeAnalysis.NotNull] bool? x) => throw null!; public object? Value => throw null!; object? IUnionMembers.Value => throw null!; public interface IUnionMembers { public static S1 Create(int x) => throw null!; public static S1 Create([System.Diagnostics.CodeAnalysis.NotNull] string? x) => throw null!; public static S1 Create([System.Diagnostics.CodeAnalysis.NotNull] bool? x) => throw null!; public object? Value { get; } } } class Program { static void Test1() { #line 100 var s = new S1(1); _ = s switch { int => 1, string => 2, bool => 3 }; } static void Test2() { #line 200 var s = new S1(""""); _ = s switch { int => 1, string => 2, bool => 3 }; } static void Test3(string? x) { #line 300 var s = new S1(x); _ = s switch { int => 1, string => 2, bool => 3 }; x.ToString(); } static void Test4(bool x) { #line 400 var s = new S1(x); _ = s switch { int => 1, string => 2, bool => 3 }; } static void Test5(bool? x) { #line 500 var s = new S1(x); _ = s switch { int => 1, string => 2, bool => 3 }; x.Value.ToString(); } } "; var comp = CreateCompilation([src, UnionAttributeSource, NotNullAttributeDefinition]); comp.VerifyDiagnostics( // (101,15): warning CS8655: The switch expression does not handle some null inputs (it is not exhaustive). For example, the pattern 'null' is not covered. // _ = s switch { int => 1, string => 2, bool => 3 }; Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustiveForNull, "switch").WithArguments("null").WithLocation(101, 15), // (201,15): warning CS8655: The switch expression does not handle some null inputs (it is not exhaustive). For example, the pattern 'null' is not covered. // _ = s switch { int => 1, string => 2, bool => 3 }; Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustiveForNull, "switch").WithArguments("null").WithLocation(201, 15), // (301,15): warning CS8655: The switch expression does not handle some null inputs (it is not exhaustive). For example, the pattern 'null' is not covered. // _ = s switch { int => 1, string => 2, bool => 3 }; Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustiveForNull, "switch").WithArguments("null").WithLocation(301, 15), // (401,15): warning CS8655: The switch expression does not handle some null inputs (it is not exhaustive). For example, the pattern 'null' is not covered. // _ = s switch { int => 1, string => 2, bool => 3 }; Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustiveForNull, "switch").WithArguments("null").WithLocation(401, 15), // (501,15): warning CS8655: The switch expression does not handle some null inputs (it is not exhaustive). For example, the pattern 'null' is not covered. // _ = s switch { int => 1, string => 2, bool => 3 }; Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustiveForNull, "switch").WithArguments("null").WithLocation(501, 15) ); } [Theory] [CombinatorialData] public void NullableAnalysis_MemberProvider_07_State_From_Conversion([CombinatorialValues("class", "struct")] string typeKind) { var src = @" #nullable enable [System.Runtime.CompilerServices.Union] " + typeKind + @" S1 : S1.IUnionMembers { object? IUnionMembers.Value => throw null!; public interface IUnionMembers { public static S1 Create(int x) => throw null!; public static S1 Create(string? x) => throw null!; public static S1 Create(bool? x) => throw null!; public object? Value { get; } } } class Program { static void Test1() { #line 100 S1 s = 1; _ = s switch { int => 1, string => 2, bool => 3 }; } static void Test2() { #line 200 S1 s = """"; _ = s switch { int => 1, string => 2, bool => 3 }; } static void Test3(string? x) { #line 300 S1 s = x; _ = s switch { int => 1, string => 2, bool => 3 }; } static void Test4(bool x) { #line 400 S1 s = x; _ = s switch { int => 1, string => 2, bool => 3 }; } static void Test5(bool? x) { #line 500 S1 s = x; _ = s switch { int => 1, string => 2, bool => 3 }; } } "; var comp = CreateCompilation([src, UnionAttributeSource]); comp.VerifyDiagnostics( // (301,15): warning CS8655: The switch expression does not handle some null inputs (it is not exhaustive). For example, the pattern 'null' is not covered. // _ = s switch { int => 1, string => 2, bool => 3 }; Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustiveForNull, "switch").WithArguments("null").WithLocation(301, 15), // (501,15): warning CS8655: The switch expression does not handle some null inputs (it is not exhaustive). For example, the pattern 'null' is not covered. // _ = s switch { int => 1, string => 2, bool => 3 }; Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustiveForNull, "switch").WithArguments("null").WithLocation(501, 15) ); } [Theory] [CombinatorialData] public void NullableAnalysis_MemberProvider_08_State_From_Conversion_PostCondition([CombinatorialValues("class", "struct")] string typeKind) { var src = @" #nullable enable [System.Runtime.CompilerServices.Union] " + typeKind + @" S1 : S1.IUnionMembers { object? IUnionMembers.Value => throw null!; public interface IUnionMembers { public static S1 Create(int x) => throw null!; public static S1 Create([System.Diagnostics.CodeAnalysis.NotNull] string? x) => throw null!; public static S1 Create([System.Diagnostics.CodeAnalysis.NotNull] bool? x) => throw null!; public object? Value { get; } } } class Program { static void Test1() { #line 100 S1 s = 1; _ = s switch { int => 1, string => 2, bool => 3 }; } static void Test2() { #line 200 S1 s = """"; _ = s switch { int => 1, string => 2, bool => 3 }; } static void Test3(string? x) { #line 300 S1 s = x; _ = s switch { int => 1, string => 2, bool => 3 }; x.ToString(); } static void Test4(bool x) { #line 400 S1 s = x; _ = s switch { int => 1, string => 2, bool => 3 }; } static void Test5(bool? x) { #line 500 S1 s = x; _ = s switch { int => 1, string => 2, bool => 3 }; x.Value.ToString(); } } "; var comp = CreateCompilation([src, UnionAttributeSource, NotNullAttributeDefinition]); comp.VerifyDiagnostics(); } [Theory] [CombinatorialData] public void NullableAnalysis_MemberProvider_09_State_From_Conversion_TupleLiteral([CombinatorialValues("class", "struct")] string typeKind) { var src = @" #nullable enable [System.Runtime.CompilerServices.Union] " + typeKind + @" S1 : S1.IUnionMembers { object? IUnionMembers.Value => throw null!; public interface IUnionMembers { public static S1 Create(int x) => throw null!; public static S1 Create(string? x) => throw null!; public static S1 Create(bool? x) => throw null!; public object? Value { get; } } } class Program { static void Test1() { #line 100 (S1, int) s = (1, 1); _ = s.Item1 switch { int => 1, string => 2, bool => 3 }; } static void Test2() { #line 200 (S1, int) s = ("""", 1); _ = s.Item1 switch { int => 1, string => 2, bool => 3 }; } static void Test3(string? x) { #line 300 (S1, int) s = (x, 1); _ = s.Item1 switch { int => 1, string => 2, bool => 3 }; } static void Test4(bool x) { #line 400 (S1, int) s = (x, 1); _ = s.Item1 switch { int => 1, string => 2, bool => 3 }; } static void Test5(bool? x) { #line 500 (S1, int) s = (x, 1); _ = s.Item1 switch { int => 1, string => 2, bool => 3 }; } } "; var comp = CreateCompilation([src, UnionAttributeSource]); comp.VerifyDiagnostics( // (301,21): warning CS8655: The switch expression does not handle some null inputs (it is not exhaustive). For example, the pattern 'null' is not covered. // _ = s.Item1 switch { int => 1, string => 2, bool => 3 }; Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustiveForNull, "switch").WithArguments("null").WithLocation(301, 21), // (501,21): warning CS8655: The switch expression does not handle some null inputs (it is not exhaustive). For example, the pattern 'null' is not covered. // _ = s.Item1 switch { int => 1, string => 2, bool => 3 }; Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustiveForNull, "switch").WithArguments("null").WithLocation(501, 21) ); } [Theory] [CombinatorialData] public void NullableAnalysis_MemberProvider_10_State_From_Conversion_TupleLiteral_PostCondition([CombinatorialValues("class", "struct")] string typeKind) { var src = @" #nullable enable [System.Runtime.CompilerServices.Union] " + typeKind + @" S1 : S1.IUnionMembers { object? IUnionMembers.Value => throw null!; public interface IUnionMembers { public static S1 Create(int x) => throw null!; public static S1 Create([System.Diagnostics.CodeAnalysis.NotNull] string? x) => throw null!; public static S1 Create([System.Diagnostics.CodeAnalysis.NotNull] bool? x) => throw null!; public object? Value { get; } } } class Program { static void Test1() { #line 100 (S1, int) s = (1, 1); _ = s.Item1 switch { int => 1, string => 2, bool => 3 }; } static void Test2() { #line 200 (S1, int) s = ("""", 1); _ = s.Item1 switch { int => 1, string => 2, bool => 3 }; } static void Test3(string? x) { #line 300 (S1, int) s = (x, 1); _ = s.Item1 switch { int => 1, string => 2, bool => 3 }; x.ToString(); } static void Test4(bool x) { #line 400 (S1, int) s = (x, 1); _ = s.Item1 switch { int => 1, string => 2, bool => 3 }; } static void Test5(bool? x) { #line 500 (S1, int) s = (x, 1); _ = s.Item1 switch { int => 1, string => 2, bool => 3 }; x.Value.ToString(); } } "; var comp = CreateCompilation([src, UnionAttributeSource, NotNullAttributeDefinition]); comp.VerifyDiagnostics(); } [Theory] [CombinatorialData] public void NullableAnalysis_MemberProvider_11_State_From_Conversion_TupleValue([CombinatorialValues("class", "struct")] string typeKind) { var src = @" #nullable enable [System.Runtime.CompilerServices.Union] " + typeKind + @" S1 : S1.IUnionMembers { object? IUnionMembers.Value => throw null!; public interface IUnionMembers { public static S1 Create(int x) => throw null!; public static S1 Create(string? x) => throw null!; public static S1 Create(bool? x) => throw null!; public object? Value { get; } } } class Program { static void Test1((int, int) x) { #line 100 (S1, int) s = x; _ = s.Item1 switch { int => 1, string => 2, bool => 3 }; } static void Test2((string, int) x) { #line 200 (S1, int) s = x; _ = s.Item1 switch { int => 1, string => 2, bool => 3 }; } static void Test3((string?, int) x) { #line 300 (S1, int) s = x; _ = s.Item1 switch { int => 1, string => 2, bool => 3 }; } static void Test4((bool, int) x) { #line 400 (S1, int) s = x; _ = s.Item1 switch { int => 1, string => 2, bool => 3 }; } static void Test5((bool?, int) x) { #line 500 (S1, int) s = x; _ = s.Item1 switch { int => 1, string => 2, bool => 3 }; } } "; var comp = CreateCompilation([src, UnionAttributeSource]); comp.VerifyDiagnostics( // (301,21): warning CS8655: The switch expression does not handle some null inputs (it is not exhaustive). For example, the pattern 'null' is not covered. // _ = s.Item1 switch { int => 1, string => 2, bool => 3 }; Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustiveForNull, "switch").WithArguments("null").WithLocation(301, 21), // (501,21): warning CS8655: The switch expression does not handle some null inputs (it is not exhaustive). For example, the pattern 'null' is not covered. // _ = s.Item1 switch { int => 1, string => 2, bool => 3 }; Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustiveForNull, "switch").WithArguments("null").WithLocation(501, 21) ); } [Theory] [CombinatorialData] public void NullableAnalysis_MemberProvider_12_State_From_Conversion_TupleValue_PostCondition([CombinatorialValues("class", "struct")] string typeKind) { var src = @" #nullable enable [System.Runtime.CompilerServices.Union] " + typeKind + @" S1 : S1.IUnionMembers { object? IUnionMembers.Value => throw null!; public interface IUnionMembers { public static S1 Create(int x) => throw null!; public static S1 Create([System.Diagnostics.CodeAnalysis.NotNull] string? x) => throw null!; public static S1 Create([System.Diagnostics.CodeAnalysis.NotNull] bool? x) => throw null!; public object? Value { get; } } } class Program { static void Test1((int, int) x) { #line 100 (S1, int) s = x; _ = s.Item1 switch { int => 1, string => 2, bool => 3 }; } static void Test2((string, int) x) { #line 200 (S1, int) s = x; _ = s.Item1 switch { int => 1, string => 2, bool => 3 }; } static void Test3((string?, int) x) { #line 300 (S1, int) s = x; _ = s.Item1 switch { int => 1, string => 2, bool => 3 }; x.Item1.ToString(); } static void Test4((bool, int) x) { #line 400 (S1, int) s = x; _ = s.Item1 switch { int => 1, string => 2, bool => 3 }; } static void Test5((bool?, int) x) { #line 500 (S1, int) s = x; _ = s.Item1 switch { int => 1, string => 2, bool => 3 }; x.Item1.Value.ToString(); } } "; var comp = CreateCompilation([src, UnionAttributeSource, NotNullAttributeDefinition]); comp.VerifyDiagnostics(); } [Theory] [CombinatorialData] public void NullableAnalysis_MemberProvider_13_State_From_Conversion_Cast([CombinatorialValues("class", "struct")] string typeKind) { var src = @" #nullable enable [System.Runtime.CompilerServices.Union] " + typeKind + @" S1 : S1.IUnionMembers { object? IUnionMembers.Value => throw null!; public interface IUnionMembers { public static S1 Create(int x) => throw null!; public static S1 Create(string? x) => throw null!; public static S1 Create(bool? x) => throw null!; public object? Value { get; } } } class Program { static void Test1() { #line 100 S1 s = (S1)1; _ = s switch { int => 1, string => 2, bool => 3 }; } static void Test2() { #line 200 S1 s = (S1)""""; _ = s switch { int => 1, string => 2, bool => 3 }; } static void Test3(string? x) { #line 300 S1 s = (S1)x; _ = s switch { int => 1, string => 2, bool => 3 }; } static void Test4(bool x) { #line 400 S1 s = (S1)x; _ = s switch { int => 1, string => 2, bool => 3 }; } static void Test5(bool? x) { #line 500 S1 s = (S1)x; _ = s switch { int => 1, string => 2, bool => 3 }; } } "; var comp = CreateCompilation([src, UnionAttributeSource]); comp.VerifyDiagnostics( // (301,15): warning CS8655: The switch expression does not handle some null inputs (it is not exhaustive). For example, the pattern 'null' is not covered. // _ = s switch { int => 1, string => 2, bool => 3 }; Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustiveForNull, "switch").WithArguments("null").WithLocation(301, 15), // (501,15): warning CS8655: The switch expression does not handle some null inputs (it is not exhaustive). For example, the pattern 'null' is not covered. // _ = s switch { int => 1, string => 2, bool => 3 }; Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustiveForNull, "switch").WithArguments("null").WithLocation(501, 15) ); } [Theory] [CombinatorialData] public void NullableAnalysis_MemberProvider_14_State_From_Conversion_Cast_PostCondition([CombinatorialValues("class", "struct")] string typeKind) { var src = @" #nullable enable [System.Runtime.CompilerServices.Union] " + typeKind + @" S1 : S1.IUnionMembers { object? IUnionMembers.Value => throw null!; public interface IUnionMembers { public static S1 Create(int x) => throw null!; public static S1 Create([System.Diagnostics.CodeAnalysis.NotNull] string? x) => throw null!; public static S1 Create([System.Diagnostics.CodeAnalysis.NotNull] bool? x) => throw null!; public object? Value { get; } } } class Program { static void Test1() { #line 100 S1 s = (S1)1; _ = s switch { int => 1, string => 2, bool => 3 }; } static void Test2() { #line 200 S1 s = (S1)""""; _ = s switch { int => 1, string => 2, bool => 3 }; } static void Test3(string? x) { #line 300 S1 s = (S1)x; _ = s switch { int => 1, string => 2, bool => 3 }; x.ToString(); } static void Test4(bool x) { #line 400 S1 s = (S1)x; _ = s switch { int => 1, string => 2, bool => 3 }; } static void Test5(bool? x) { #line 500 S1 s = (S1)x; _ = s switch { int => 1, string => 2, bool => 3 }; x.Value.ToString(); } } "; var comp = CreateCompilation([src, UnionAttributeSource, NotNullAttributeDefinition]); comp.VerifyDiagnostics(); } [Theory] [CombinatorialData] public void NullableAnalysis_MemberProvider_15_State_From_Conversion_Cast_TupleLiteral([CombinatorialValues("class", "struct")] string typeKind) { var src = @" #nullable enable [System.Runtime.CompilerServices.Union] " + typeKind + @" S1 : S1.IUnionMembers { object? IUnionMembers.Value => throw null!; public interface IUnionMembers { public static S1 Create(int x) => throw null!; public static S1 Create(string? x) => throw null!; public static S1 Create(bool? x) => throw null!; public object? Value { get; } } } class Program { static void Test1() { #line 100 (S1, int) s = ((S1, int))(1, 1.0); _ = s.Item1 switch { int => 1, string => 2, bool => 3 }; } static void Test2() { #line 200 (S1, int) s = ((S1, int))("""", 1.0); _ = s.Item1 switch { int => 1, string => 2, bool => 3 }; } static void Test3(string? x) { #line 300 (S1, int) s = ((S1, int))(x, 1.0); _ = s.Item1 switch { int => 1, string => 2, bool => 3 }; } static void Test4(bool x) { #line 400 (S1, int) s = ((S1, int))(x, 1.0); _ = s.Item1 switch { int => 1, string => 2, bool => 3 }; } static void Test5(bool? x) { #line 500 (S1, int) s = ((S1, int))(x, 1.0); _ = s.Item1 switch { int => 1, string => 2, bool => 3 }; } } "; var comp = CreateCompilation([src, UnionAttributeSource]); comp.VerifyDiagnostics( // (301,21): warning CS8655: The switch expression does not handle some null inputs (it is not exhaustive). For example, the pattern 'null' is not covered. // _ = s.Item1 switch { int => 1, string => 2, bool => 3 }; Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustiveForNull, "switch").WithArguments("null").WithLocation(301, 21), // (501,21): warning CS8655: The switch expression does not handle some null inputs (it is not exhaustive). For example, the pattern 'null' is not covered. // _ = s.Item1 switch { int => 1, string => 2, bool => 3 }; Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustiveForNull, "switch").WithArguments("null").WithLocation(501, 21) ); } [Theory] [CombinatorialData] public void NullableAnalysis_MemberProvider_16_State_From_Conversion_Cast_TupleLiteral_PostCondition([CombinatorialValues("class", "struct")] string typeKind) { var src = @" #nullable enable [System.Runtime.CompilerServices.Union] " + typeKind + @" S1 : S1.IUnionMembers { object? IUnionMembers.Value => throw null!; public interface IUnionMembers { public static S1 Create(int x) => throw null!; public static S1 Create([System.Diagnostics.CodeAnalysis.NotNull] string? x) => throw null!; public static S1 Create([System.Diagnostics.CodeAnalysis.NotNull] bool? x) => throw null!; public object? Value { get; } } } class Program { static void Test1() { #line 100 (S1, int) s = ((S1, int))(1, 1.0); _ = s.Item1 switch { int => 1, string => 2, bool => 3 }; } static void Test2() { #line 200 (S1, int) s = ((S1, int))("""", 1.0); _ = s.Item1 switch { int => 1, string => 2, bool => 3 }; } static void Test3(string? x) { #line 300 (S1, int) s = ((S1, int))(x, 1.0); _ = s.Item1 switch { int => 1, string => 2, bool => 3 }; x.ToString(); } static void Test4(bool x) { #line 400 (S1, int) s = ((S1, int))(x, 1.0); _ = s.Item1 switch { int => 1, string => 2, bool => 3 }; } static void Test5(bool? x) { #line 500 (S1, int) s = ((S1, int))(x, 1.0); _ = s.Item1 switch { int => 1, string => 2, bool => 3 }; x.Value.ToString(); } } "; var comp = CreateCompilation([src, UnionAttributeSource, NotNullAttributeDefinition]); comp.VerifyDiagnostics(); } [Theory] [CombinatorialData] public void NullableAnalysis_MemberProvider_17_State_From_Conversion_Cast_TupleValue([CombinatorialValues("class", "struct")] string typeKind) { var src = @" #nullable enable [System.Runtime.CompilerServices.Union] " + typeKind + @" S1 : S1.IUnionMembers { object? IUnionMembers.Value => throw null!; public interface IUnionMembers { public static S1 Create(int x) => throw null!; public static S1 Create(string? x) => throw null!; public static S1 Create(bool? x) => throw null!; public object? Value { get; } } } class Program { static void Test1((int, long) x) { #line 100 (S1, int) s = ((S1, int))x; _ = s.Item1 switch { int => 1, string => 2, bool => 3 }; } static void Test2((string, long) x) { #line 200 (S1, int) s = ((S1, int))x; _ = s.Item1 switch { int => 1, string => 2, bool => 3 }; } static void Test3((string?, long) x) { #line 300 (S1, int) s = ((S1, int))x; _ = s.Item1 switch { int => 1, string => 2, bool => 3 }; } static void Test4((bool, long) x) { #line 400 (S1, int) s = ((S1, int))x; _ = s.Item1 switch { int => 1, string => 2, bool => 3 }; } static void Test5((bool?, long) x) { #line 500 (S1, int) s = ((S1, int))x; _ = s.Item1 switch { int => 1, string => 2, bool => 3 }; } } "; var comp = CreateCompilation([src, UnionAttributeSource]); comp.VerifyDiagnostics( // (301,21): warning CS8655: The switch expression does not handle some null inputs (it is not exhaustive). For example, the pattern 'null' is not covered. // _ = s.Item1 switch { int => 1, string => 2, bool => 3 }; Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustiveForNull, "switch").WithArguments("null").WithLocation(301, 21), // (501,21): warning CS8655: The switch expression does not handle some null inputs (it is not exhaustive). For example, the pattern 'null' is not covered. // _ = s.Item1 switch { int => 1, string => 2, bool => 3 }; Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustiveForNull, "switch").WithArguments("null").WithLocation(501, 21) ); } [Theory] [CombinatorialData] public void NullableAnalysis_MemberProvider_18_State_From_Conversion_Cast_TupleValue_PostCondition([CombinatorialValues("class", "struct")] string typeKind) { var src = @" #nullable enable [System.Runtime.CompilerServices.Union] " + typeKind + @" S1 : S1.IUnionMembers { object? IUnionMembers.Value => throw null!; public interface IUnionMembers { public static S1 Create(int x) => throw null!; public static S1 Create([System.Diagnostics.CodeAnalysis.NotNull] string? x) => throw null!; public static S1 Create([System.Diagnostics.CodeAnalysis.NotNull] bool? x) => throw null!; public object? Value { get; } } } class Program { static void Test1((int, long) x) { #line 100 (S1, int) s = ((S1, int))x; _ = s.Item1 switch { int => 1, string => 2, bool => 3 }; } static void Test2((string, long) x) { #line 200 (S1, int) s = ((S1, int))x; _ = s.Item1 switch { int => 1, string => 2, bool => 3 }; } static void Test3((string?, long) x) { #line 300 (S1, int) s = ((S1, int))x; _ = s.Item1 switch { int => 1, string => 2, bool => 3 }; x.Item1.ToString(); } static void Test4((bool, long) x) { #line 400 (S1, int) s = ((S1, int))x; _ = s.Item1 switch { int => 1, string => 2, bool => 3 }; } static void Test5((bool?, long) x) { #line 500 (S1, int) s = ((S1, int))x; _ = s.Item1 switch { int => 1, string => 2, bool => 3 }; x.Item1.Value.ToString(); } } "; var comp = CreateCompilation([src, UnionAttributeSource, NotNullAttributeDefinition]); comp.VerifyDiagnostics(); } [Fact] public void NullableAnalysis_MemberProvider_19_State_From_Null_Test() { var src = @" #nullable enable [System.Runtime.CompilerServices.Union] struct S1 : S1.IUnionMembers { object? IUnionMembers.Value => throw null!; public interface IUnionMembers { public static S1 Create(int x) => throw null!; public static S1 Create(bool? x) => throw null!; public object? Value { get; } } } [System.Runtime.CompilerServices.Union] struct S2 : S2.IUnionMembers { object? IUnionMembers.Value => throw null!; public interface IUnionMembers { public static S2 Create(int x) => throw null!; public static S2 Create(bool x) => throw null!; public object? Value { get; } } } class Program { static void Test2(S1 s) { if (s is null) { #line 100 _ = s switch { int => 1, bool => 3 }; } else { #line 200 _ = s switch { int => 1, bool => 3 }; } } static void Test4(S2 s) { if (s is null) { #line 300 _ = s switch { int => 1, bool => 3 }; } else { #line 400 _ = s switch { int => 1, bool => 3 }; } } } "; var comp = CreateCompilation([src, UnionAttributeSource]); comp.VerifyDiagnostics( // (100,19): warning CS8655: The switch expression does not handle some null inputs (it is not exhaustive). For example, the pattern 'null' is not covered. // _ = s switch { int => 1, bool => 3 }; Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustiveForNull, "switch").WithArguments("null").WithLocation(100, 19), // (300,19): warning CS8655: The switch expression does not handle some null inputs (it is not exhaustive). For example, the pattern 'null' is not covered. // _ = s switch { int => 1, bool => 3 }; Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustiveForNull, "switch").WithArguments("null").WithLocation(300, 19) ); } [Fact] public void NullableAnalysis_MemberProvider_20_State_From_Null_Test_Class() { var src1 = @" #nullable enable [System.Runtime.CompilerServices.Union] class S1 : S1.IUnionMembers { object? IUnionMembers.Value => throw null!; public interface IUnionMembers { public static S1 Create(int x) => throw null!; public static S1 Create(bool? x) => throw null!; public object? Value { get; } } } [System.Runtime.CompilerServices.Union] class S2 : S2.IUnionMembers { object? IUnionMembers.Value => throw null!; public interface IUnionMembers { public static S2 Create(int x) => throw null!; public static S2 Create(bool x) => throw null!; public object? Value { get; } } } class Program { static void Test2(S1 s) { if (s is null) { #line 100 _ = s switch { int => 1, bool => 3 }; } else { #line 200 _ = s switch { int => 1, bool => 3 }; } } static void Test4(S2 s) { if (s is null) { #line 300 _ = s switch { int => 1, bool => 3 }; } else { #line 400 _ = s switch { int => 1, bool => 3 }; } } } "; var comp1 = CreateCompilation([src1, UnionAttributeSource]); comp1.VerifyDiagnostics( // (100,19): warning CS8655: The switch expression does not handle some null inputs (it is not exhaustive). For example, the pattern 'null' is not covered. // _ = s switch { int => 1, bool => 3 }; Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustiveForNull, "switch").WithArguments("null").WithLocation(100, 19), // (300,19): warning CS8655: The switch expression does not handle some null inputs (it is not exhaustive). For example, the pattern 'null' is not covered. // _ = s switch { int => 1, bool => 3 }; Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustiveForNull, "switch").WithArguments("null").WithLocation(300, 19) ); var src2 = @" #nullable enable class S1 { public bool? Value => throw null!; } class Program { static void Test2(S1 s) { _ = s.Value; if (s is null or { Value: null }) { #line 1000 _ = s switch { { Value: bool } => 1 }; } else { #line 2000 _ = s switch { { Value: bool } => 1 }; } } } "; var comp2 = CreateCompilation(src2); comp2.VerifyDiagnostics( // (1000,19): warning CS8655: The switch expression does not handle some null inputs (it is not exhaustive). For example, the pattern 'null' is not covered. // _ = s switch { { Value: bool } => 1 }; Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustiveForNull, "switch").WithArguments("null").WithLocation(1000, 19) ); } [Theory] [CombinatorialData] public void NullableAnalysis_MemberProvider_21_State_From_NotNull_Test([CombinatorialValues("class", "struct")] string typeKind) { var src = @" #nullable enable [System.Runtime.CompilerServices.Union] " + typeKind + @" S1 : S1.IUnionMembers { object? IUnionMembers.Value => throw null!; public interface IUnionMembers { public static S1 Create(int x) => throw null!; public static S1 Create(bool? x) => throw null!; public object? Value { get; } } } [System.Runtime.CompilerServices.Union] " + typeKind + @" S2 : S2.IUnionMembers { object? IUnionMembers.Value => throw null!; public interface IUnionMembers { public static S2 Create(int x) => throw null!; public static S2 Create(bool x) => throw null!; public object? Value { get; } } } class Program { static void Test2(S1 s) { if (s is not null) { #line 100 _ = s switch { int => 1, bool => 3 }; } else { #line 200 _ = s switch { int => 1, bool => 3 }; } } static void Test4(S2 s) { if (s is not null) { #line 300 _ = s switch { int => 1, bool => 3 }; } else { #line 400 _ = s switch { int => 1, bool => 3 }; } } } "; var comp = CreateCompilation([src, UnionAttributeSource]); comp.VerifyDiagnostics( // (200,19): warning CS8655: The switch expression does not handle some null inputs (it is not exhaustive). For example, the pattern 'null' is not covered. // _ = s switch { int => 1, bool => 3 }; Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustiveForNull, "switch").WithArguments("null").WithLocation(200, 19), // (400,19): warning CS8655: The switch expression does not handle some null inputs (it is not exhaustive). For example, the pattern 'null' is not covered. // _ = s switch { int => 1, bool => 3 }; Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustiveForNull, "switch").WithArguments("null").WithLocation(400, 19) ); } [Theory] [CombinatorialData] public void NullableAnalysis_MemberProvider_22_State_From_Type_Test([CombinatorialValues("class", "struct")] string typeKind) { var src = @" #nullable enable [System.Runtime.CompilerServices.Union] " + typeKind + @" S1 : S1.IUnionMembers { object? IUnionMembers.Value => throw null!; public interface IUnionMembers { public static S1 Create(int x) => throw null!; public static S1 Create(bool? x) => throw null!; public object? Value { get; } } } [System.Runtime.CompilerServices.Union] " + typeKind + @" S2 : S2.IUnionMembers { object? IUnionMembers.Value => throw null!; public interface IUnionMembers { public static S2 Create(int x) => throw null!; public static S2 Create(bool x) => throw null!; public object? Value { get; } } } class Program { static void Test2(S1 s) { if (s is int) { #line 100 _ = s switch { int => 1, bool => 3 }; } else { #line 200 _ = s switch { int => 1, bool => 3 }; } } static void Test4(S2 s) { if (s is int) { #line 300 _ = s switch { int => 1, bool => 3 }; } else { #line 400 _ = s switch { int => 1, bool => 3 }; } } } "; var comp = CreateCompilation([src, UnionAttributeSource]); comp.VerifyDiagnostics( // (200,19): warning CS8655: The switch expression does not handle some null inputs (it is not exhaustive). For example, the pattern 'null' is not covered. // _ = s switch { int => 1, bool => 3 }; Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustiveForNull, "switch").WithArguments("null").WithLocation(200, 19) ); } [Fact] public void NullableAnalysis_MemberProvider_23_State_From_NotType_Test() { var src = @" #nullable enable [System.Runtime.CompilerServices.Union] struct S1 : S1.IUnionMembers { object? IUnionMembers.Value => throw null!; public interface IUnionMembers { public static S1 Create(int x) => throw null!; public static S1 Create(bool? x) => throw null!; public object? Value { get; } } } [System.Runtime.CompilerServices.Union] struct S2 : S2.IUnionMembers { object? IUnionMembers.Value => throw null!; public interface IUnionMembers { public static S2 Create(int x) => throw null!; public static S2 Create(bool x) => throw null!; public object? Value { get; } } } class Program { static void Test2(S1 s) { if (s is not int) { #line 100 _ = s switch { int => 1, bool => 3 }; } else { #line 200 _ = s switch { int => 1, bool => 3 }; } } static void Test4(S2 s) { if (s is not int) { #line 300 _ = s switch { int => 1, bool => 3 }; } else { #line 400 _ = s switch { int => 1, bool => 3 }; } } } "; var comp = CreateCompilation([src, UnionAttributeSource]); comp.VerifyDiagnostics( // (100,19): warning CS8655: The switch expression does not handle some null inputs (it is not exhaustive). For example, the pattern 'null' is not covered. // _ = s switch { int => 1, bool => 3 }; Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustiveForNull, "switch").WithArguments("null").WithLocation(100, 19) ); } [Fact] public void NullableAnalysis_MemberProvider_24_State_From_NotType_Test_Class() { var src = @" #nullable enable [System.Runtime.CompilerServices.Union] class S1 : S1.IUnionMembers { object? IUnionMembers.Value => throw null!; public interface IUnionMembers { public static S1 Create(int x) => throw null!; public static S1 Create(bool? x) => throw null!; public object? Value { get; } } } [System.Runtime.CompilerServices.Union] class S2 : S2.IUnionMembers { object? IUnionMembers.Value => throw null!; public interface IUnionMembers { public static S2 Create(int x) => throw null!; public static S2 Create(bool x) => throw null!; public object? Value { get; } } } class Program { static void Test2(S1 s) { if (s is not int) { #line 100 _ = s switch { int => 1, bool => 3 }; } else { #line 200 _ = s switch { int => 1, bool => 3 }; } } static void Test4(S2 s) { if (s is not int) { #line 300 _ = s switch { int => 1, bool => 3 }; } else { #line 400 _ = s switch { int => 1, bool => 3 }; } } } "; var comp = CreateCompilation([src, UnionAttributeSource]); comp.VerifyDiagnostics( // (100,19): warning CS8655: The switch expression does not handle some null inputs (it is not exhaustive). For example, the pattern 'null' is not covered. // _ = s switch { int => 1, bool => 3 }; Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustiveForNull, "switch").WithArguments("null").WithLocation(100, 19) ); var src2 = @" #nullable enable class S1 { public bool? Value => throw null!; } class Program { static void Test2(S1 s) { _ = s.Value; if (s is not { Value: bool }) { #line 1000 _ = s switch { { Value: bool } => 1 }; } else { #line 2000 _ = s switch { { Value: bool } => 1 }; } } } "; var comp2 = CreateCompilation(src2); comp2.VerifyDiagnostics( // (1000,19): warning CS8655: The switch expression does not handle some null inputs (it is not exhaustive). For example, the pattern '{ Value: null }' is not covered. // _ = s switch { { Value: bool } => 1 }; Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustiveForNull, "switch").WithArguments("{ Value: null }").WithLocation(1000, 19) ); } [Theory] [CombinatorialData] public void NullableAnalysis_MemberProvider_25_State_From_Value_Test([CombinatorialValues("class", "struct")] string typeKind) { var src = @" #nullable enable [System.Runtime.CompilerServices.Union] " + typeKind + @" S1 : S1.IUnionMembers { object? IUnionMembers.Value => throw null!; public interface IUnionMembers { public static S1 Create(int x) => throw null!; public static S1 Create(bool? x) => throw null!; public object? Value { get; } } } [System.Runtime.CompilerServices.Union] " + typeKind + @" S2 : S2.IUnionMembers { object? IUnionMembers.Value => throw null!; public interface IUnionMembers { public static S2 Create(int x) => throw null!; public static S2 Create(bool x) => throw null!; public object? Value { get; } } } class Program { static void Test2(S1 s) { if (s is 1) { #line 100 _ = s switch { int => 1, bool => 3 }; } else { #line 200 _ = s switch { int => 1, bool => 3 }; } } static void Test4(S2 s) { if (s is 1) { #line 300 _ = s switch { int => 1, bool => 3 }; } else { #line 400 _ = s switch { int => 1, bool => 3 }; } } } "; var comp = CreateCompilation([src, UnionAttributeSource]); comp.VerifyDiagnostics( // (200,19): warning CS8655: The switch expression does not handle some null inputs (it is not exhaustive). For example, the pattern 'null' is not covered. // _ = s switch { int => 1, bool => 3 }; Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustiveForNull, "switch").WithArguments("null").WithLocation(200, 19) ); } [Fact] public void NullableAnalysis_MemberProvider_26_State_From_NotValue_Test() { var src = @" #nullable enable [System.Runtime.CompilerServices.Union] struct S1 : S1.IUnionMembers { object? IUnionMembers.Value => throw null!; public interface IUnionMembers { public static S1 Create(int x) => throw null!; public static S1 Create(bool? x) => throw null!; public object? Value { get; } } } [System.Runtime.CompilerServices.Union] struct S2 : S2.IUnionMembers { object? IUnionMembers.Value => throw null!; public interface IUnionMembers { public static S2 Create(int x) => throw null!; public static S2 Create(bool x) => throw null!; public object? Value { get; } } } class Program { static void Test2(S1 s) { if (s is not 1) { #line 100 _ = s switch { int => 1, bool => 3 }; } else { #line 200 _ = s switch { int => 1, bool => 3 }; } } static void Test4(S2 s) { if (s is not 1) { #line 300 _ = s switch { int => 1, bool => 3 }; } else { #line 400 _ = s switch { int => 1, bool => 3 }; } } } "; var comp = CreateCompilation([src, UnionAttributeSource]); comp.VerifyDiagnostics( // (100,19): warning CS8655: The switch expression does not handle some null inputs (it is not exhaustive). For example, the pattern 'null' is not covered. // _ = s switch { int => 1, bool => 3 }; Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustiveForNull, "switch").WithArguments("null").WithLocation(100, 19) ); } [Fact] public void NullableAnalysis_MemberProvider_27_State_From_NotValue_Test_Class() { var src = @" #nullable enable [System.Runtime.CompilerServices.Union] class S1 : S1.IUnionMembers { object? IUnionMembers.Value => throw null!; public interface IUnionMembers { public static S1 Create(int x) => throw null!; public static S1 Create(bool? x) => throw null!; public object? Value { get; } } } [System.Runtime.CompilerServices.Union] class S2 : S2.IUnionMembers { object? IUnionMembers.Value => throw null!; public interface IUnionMembers { public static S2 Create(int x) => throw null!; public static S2 Create(bool x) => throw null!; public object? Value { get; } } } class Program { static void Test2(S1 s) { if (s is not 1) { #line 100 _ = s switch { int => 1, bool => 3 }; } else { #line 200 _ = s switch { int => 1, bool => 3 }; } } static void Test4(S2 s) { if (s is not 1) { #line 300 _ = s switch { int => 1, bool => 3 }; } else { #line 400 _ = s switch { int => 1, bool => 3 }; } } } "; var comp = CreateCompilation([src, UnionAttributeSource]); comp.VerifyDiagnostics( // (100,19): warning CS8655: The switch expression does not handle some null inputs (it is not exhaustive). For example, the pattern 'null' is not covered. // _ = s switch { int => 1, bool => 3 }; Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustiveForNull, "switch").WithArguments("null").WithLocation(100, 19) ); var src2 = @" #nullable enable class S1 { public bool? Value => throw null!; } class Program { static void Test2(S1 s) { _ = s.Value; if (s is not { Value: true }) { #line 1000 _ = s switch { { Value: bool } => 1 }; } else { #line 2000 _ = s switch { { Value: bool } => 1 }; } } } "; var comp2 = CreateCompilation(src2); comp2.VerifyDiagnostics( // (1000,19): warning CS8655: The switch expression does not handle some null inputs (it is not exhaustive). For example, the pattern '{ Value: null }' is not covered. // _ = s switch { { Value: bool } => 1 }; Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustiveForNull, "switch").WithArguments("{ Value: null }").WithLocation(1000, 19) ); } [Fact] public void NullableAnalysis_MemberProvider_28_ValuePropertyOfTheInterfaceIsTargetedToImplementPatternMatching() { var src = @" #nullable enable [System.Runtime.CompilerServices.Union] struct S1 : S1.IUnionMembers { [System.Diagnostics.CodeAnalysis.MemberNotNull(nameof(OtherProp))] object? IUnionMembers.Value => throw null!; public string? OtherProp => throw null!; public interface IUnionMembers { public static S1 Create(int x) => throw null!; public static S1 Create(bool? x) => throw null!; public object? Value { get; } } } public interface I1 { object? Value { get; } } struct S2 : I1 { public S2(int x) => throw null!; public S2(bool? x) => throw null!; [System.Diagnostics.CodeAnalysis.MemberNotNull(nameof(OtherProp))] object? I1.Value => throw null!; public string? OtherProp => throw null!; } class Program { static void Test2(S1 s) { #line 200 _ = s switch { bool => s.OtherProp.ToString(), _ => """" }; } static void Test3(S2 s) { #line 300 _ = s switch { I1 and { Value: bool } => s.OtherProp.ToString(), _ => """" }; } } "; var comp = CreateCompilation([src, UnionAttributeSource, MemberNotNullAttributeDefinition]); comp.VerifyDiagnostics( // (200,33): warning CS8602: Dereference of a possibly null reference. // _ = s switch { bool => s.OtherProp.ToString(), _ => "" }; Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "s.OtherProp").WithLocation(200, 33), // (300,51): warning CS8602: Dereference of a possibly null reference. // _ = s switch { I1 and { Value: bool } => s.OtherProp.ToString(), _ => "" }; Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "s.OtherProp").WithLocation(300, 51) ); } [Fact] public void NullableAnalysis_MemberProvider_29_ValuePropertyOfTheInterfaceIsTargetedToImplementPatternMatching() { var src = @" #nullable enable [System.Runtime.CompilerServices.Union] struct S1 : S1.IUnionMembers { [System.Diagnostics.CodeAnalysis.MemberNotNull(nameof(OtherProp))] object? IUnionMembers.Value => throw null!; string? IUnionMembers.OtherProp => throw null!; public string? OtherProp => throw null!; public interface IUnionMembers { public static S1 Create(int x) => throw null!; public static S1 Create(bool? x) => throw null!; [System.Diagnostics.CodeAnalysis.MemberNotNull(nameof(OtherProp))] public object? Value { get; } string? OtherProp { get; } } } [System.Runtime.CompilerServices.Union] struct S2 : S2.IUnionMembers { [System.Diagnostics.CodeAnalysis.MemberNotNull(nameof(OtherProp))] object? IUnionMembers.Value => throw null!; public string? OtherProp => throw null!; public interface IUnionMembers { public static S2 Create(int x) => throw null!; public static S2 Create(bool? x) => throw null!; [System.Diagnostics.CodeAnalysis.MemberNotNull(nameof(OtherProp))] public object? Value { get; } string? OtherProp { get; } } } class Program { static void Test2(S1 s) { #line 200 _ = s switch { bool => s.OtherProp.ToString(), _ => """" }; } static void Test3(S2 s) { #line 300 _ = s switch { bool => s.OtherProp.ToString(), _ => """" }; } } "; var comp = CreateCompilation([src, MemberNotNullAttributeDefinition, UnionAttributeSource]); comp.VerifyDiagnostics( // (200,33): warning CS8602: Dereference of a possibly null reference. // _ = s switch { bool => s.OtherProp.ToString(), _ => "" }; Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "s.OtherProp").WithLocation(200, 33), // (300,33): warning CS8602: Dereference of a possibly null reference. // _ = s switch { bool => s.OtherProp.ToString(), _ => "" }; Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "s.OtherProp").WithLocation(300, 33) ); } [Fact] public void NullableAnalysis_MemberProvider_30_ValuePropertyOfTheInterfaceIsTargetedToImplementPatternMatching() { var src = @" #nullable enable [System.Runtime.CompilerServices.Union] struct S1 : S1.IUnionMembers { [System.Diagnostics.CodeAnalysis.MemberNotNull(nameof(OtherProp))] object? IUnionMembers.Value => throw null!; public string? OtherProp => throw null!; public interface IUnionMembers { public static S1 Create(int x) => throw null!; public static S1 Create(bool? x) => throw null!; #line 100 [System.Diagnostics.CodeAnalysis.MemberNotNull(nameof(S1.OtherProp))] public object? Value { get; } } } class Program { static void Test2(S1 s) { #line 200 _ = s switch { bool => s.OtherProp.ToString(), _ => """" }; } } "; var comp = CreateCompilation([src, MemberNotNullAttributeDefinition, UnionAttributeSource]); comp.VerifyDiagnostics( // (100,10): warning CS8776: Member 'OtherProp' cannot be used in this attribute. // [System.Diagnostics.CodeAnalysis.MemberNotNull(nameof(S1.OtherProp))] Diagnostic(ErrorCode.WRN_MemberNotNullBadMember, "System.Diagnostics.CodeAnalysis.MemberNotNull(nameof(S1.OtherProp))").WithArguments("OtherProp").WithLocation(100, 10), // (200,33): warning CS8602: Dereference of a possibly null reference. // _ = s switch { bool => s.OtherProp.ToString(), _ => "" }; Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "s.OtherProp").WithLocation(200, 33) ); } [Theory] [CombinatorialData] public void NullableAnalysis_MemberProvider_31_Conversion_Value_Check([CombinatorialValues("class", "struct")] string typeKind) { var src = @" #nullable enable [System.Runtime.CompilerServices.Union] " + typeKind + @" S1 : S1.IUnionMembers { public S1(string x) => throw null!; public S1(bool? x) => throw null!; object? IUnionMembers.Value => throw null!; public interface IUnionMembers { public static S1 Create(string x) => throw null!; public static S1 Create(bool? x) => throw null!; public object? Value { get; } } } class Program { static void Test1(string? x) { #line 100 S1 s = x; x.ToString(); } static void Test2(string? x) { #line 200 var s = new S1(x); x.ToString(); } } "; var comp = CreateCompilation([src, UnionAttributeSource]); comp.VerifyDiagnostics( // (100,16): warning CS8604: Possible null reference argument for parameter 'x' in 'S1 IUnionMembers.Create(string x)'. // S1 s = x; Diagnostic(ErrorCode.WRN_NullReferenceArgument, "x").WithArguments("x", "S1 IUnionMembers.Create(string x)").WithLocation(100, 16), // (200,24): warning CS8604: Possible null reference argument for parameter 'x' in 'S1.S1(string x)'. // var s = new S1(x); Diagnostic(ErrorCode.WRN_NullReferenceArgument, "x").WithArguments("x", "S1.S1(string x)").WithLocation(200, 24) ); } [Theory] [CombinatorialData] public void NullableAnalysis_MemberProvider_32_Conversion_Value_Check([CombinatorialValues("class", "struct")] string typeKind) { var src = @" #nullable enable [System.Runtime.CompilerServices.Union] " + typeKind + @" S1 : S1.IUnionMembers { public S1([System.Diagnostics.CodeAnalysis.DisallowNull] string? x) => throw null!; public S1([System.Diagnostics.CodeAnalysis.DisallowNull] bool? x) => throw null!; object? IUnionMembers.Value => throw null!; public interface IUnionMembers { public static S1 Create([System.Diagnostics.CodeAnalysis.DisallowNull] string? x) => throw null!; public static S1 Create([System.Diagnostics.CodeAnalysis.DisallowNull] bool? x) => throw null!; public object? Value { get; } } } class Program { static void Test1(string? x) { #line 100 S1 s = x; x.ToString(); } static void Test2(string? x) { #line 200 var s = new S1(x); x.ToString(); } static void Test3(bool? x) { #line 300 S1 s = x; x.Value.ToString(); } static void Test4(bool? x) { #line 400 var s = new S1(x); x.Value.ToString(); } } "; var comp = CreateCompilation([src, UnionAttributeSource, DisallowNullAttributeDefinition]); comp.VerifyDiagnostics( // (100,16): warning CS8604: Possible null reference argument for parameter 'x' in 'S1.S1(string? x)'. // S1 s = x; Diagnostic(ErrorCode.WRN_NullReferenceArgument, "x").WithArguments("x", "S1 IUnionMembers.Create(string? x)").WithLocation(100, 16), // (200,24): warning CS8604: Possible null reference argument for parameter 'x' in 'S1.S1(string? x)'. // var s = new S1(x); Diagnostic(ErrorCode.WRN_NullReferenceArgument, "x").WithArguments("x", "S1.S1(string? x)").WithLocation(200, 24), // (300,16): warning CS8607: A possible null value may not be used for a type marked with [NotNull] or [DisallowNull] // S1 s = x; Diagnostic(ErrorCode.WRN_DisallowNullAttributeForbidsMaybeNullAssignment, "x").WithLocation(300, 16), // (400,24): warning CS8607: A possible null value may not be used for a type marked with [NotNull] or [DisallowNull] // var s = new S1(x); Diagnostic(ErrorCode.WRN_DisallowNullAttributeForbidsMaybeNullAssignment, "x").WithLocation(400, 24) ); } [Fact] public void NullableAnalysis_MemberProvider_33_State_From_Default_NullableOfUnion() { var src = @" #nullable enable [System.Runtime.CompilerServices.Union] struct S1 : S1.IUnionMembers { object? IUnionMembers.Value => throw null!; public interface IUnionMembers { public static S1 Create(int x) => throw null!; public static S1 Create(bool? x) => throw null!; public object? Value { get; } } } [System.Runtime.CompilerServices.Union] struct S2 : S2.IUnionMembers { object? IUnionMembers.Value => throw null!; public interface IUnionMembers { public static S2 Create(int x) => throw null!; public static S2 Create(bool x) => throw null!; public object? Value { get; } } } class Program { static void Test1() { #line 100 S1? s = default(S1); _ = s.Value switch { int => 1, bool => 3 }; } static void Test3() { #line 300 S2? s = default(S2); _ = s.Value switch { int => 1, bool => 3 }; } } "; var comp = CreateCompilation([src, UnionAttributeSource]); comp.VerifyDiagnostics( // (101,21): warning CS8655: The switch expression does not handle some null inputs (it is not exhaustive). For example, the pattern 'null' is not covered. // _ = s.Value switch { int => 1, bool => 3 }; Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustiveForNull, "switch").WithArguments("null").WithLocation(101, 21) ); } [Fact] public void NullableAnalysis_MemberProvider_34_State_From_Default_NullableOfUnion() { var src = @" #nullable enable [System.Runtime.CompilerServices.Union] struct S1 : S1.IUnionMembers { object? IUnionMembers.Value => throw null!; public interface IUnionMembers { public static S1 Create(int x) => throw null!; public static S1 Create(bool? x) => throw null!; public object? Value { get; } } } [System.Runtime.CompilerServices.Union] struct S2 : S2.IUnionMembers { object? IUnionMembers.Value => throw null!; public interface IUnionMembers { public static S2 Create(int x) => throw null!; public static S2 Create(bool x) => throw null!; public object? Value { get; } } } class Program { static void Test2(S1? s) { if (s is null) return; #line 200 _ = s.Value switch { int => 1, bool => 3 }; } static void Test4(S2? s) { if (s is null) return; #line 400 _ = s.Value switch { int => 1, bool => 3 }; } } "; var comp = CreateCompilation([src, UnionAttributeSource]); comp.VerifyDiagnostics(); } [Fact] public void NullableAnalysis_MemberProvider_35_State_From_Constructor_NullableOfUnion() { var src = @" #nullable enable [System.Runtime.CompilerServices.Union] struct S1 : S1.IUnionMembers { public S1(int x) => throw null!; public S1(string? x) => throw null!; public S1(bool? x) => throw null!; object? IUnionMembers.Value => throw null!; public interface IUnionMembers { public static S1 Create(int x) => throw null!; public static S1 Create(string? x) => throw null!; public static S1 Create(bool? x) => throw null!; public object? Value { get; } } } class Program { static void Test1() { #line 100 S1? s = new S1(1); _ = s.Value switch { int => 1, string => 2, bool => 3 }; } static void Test2() { #line 200 S1? s = new S1(""""); _ = s.Value switch { int => 1, string => 2, bool => 3 }; } static void Test3(string? x) { #line 300 S1? s = new S1(x); _ = s.Value switch { int => 1, string => 2, bool => 3 }; } static void Test4(bool x) { #line 400 S1? s = new S1(x); _ = s.Value switch { int => 1, string => 2, bool => 3 }; } static void Test5(bool? x) { #line 500 S1? s = new S1(x); _ = s.Value switch { int => 1, string => 2, bool => 3 }; } } "; var comp = CreateCompilation([src, UnionAttributeSource]); comp.VerifyDiagnostics( // (101,21): warning CS8655: The switch expression does not handle some null inputs (it is not exhaustive). For example, the pattern 'null' is not covered. // _ = s.Value switch { int => 1, string => 2, bool => 3 }; Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustiveForNull, "switch").WithArguments("null").WithLocation(101, 21), // (201,21): warning CS8655: The switch expression does not handle some null inputs (it is not exhaustive). For example, the pattern 'null' is not covered. // _ = s.Value switch { int => 1, string => 2, bool => 3 }; Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustiveForNull, "switch").WithArguments("null").WithLocation(201, 21), // (301,21): warning CS8655: The switch expression does not handle some null inputs (it is not exhaustive). For example, the pattern 'null' is not covered. // _ = s.Value switch { int => 1, string => 2, bool => 3 }; Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustiveForNull, "switch").WithArguments("null").WithLocation(301, 21), // (401,21): warning CS8655: The switch expression does not handle some null inputs (it is not exhaustive). For example, the pattern 'null' is not covered. // _ = s.Value switch { int => 1, string => 2, bool => 3 }; Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustiveForNull, "switch").WithArguments("null").WithLocation(401, 21), // (501,21): warning CS8655: The switch expression does not handle some null inputs (it is not exhaustive). For example, the pattern 'null' is not covered. // _ = s.Value switch { int => 1, string => 2, bool => 3 }; Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustiveForNull, "switch").WithArguments("null").WithLocation(501, 21) ); } [Fact] public void NullableAnalysis_MemberProvider_36_State_From_Conversion_NullableOfUnion() { var src = @" #nullable enable [System.Runtime.CompilerServices.Union] struct S1 : S1.IUnionMembers { object? IUnionMembers.Value => throw null!; public interface IUnionMembers { public static S1 Create(int x) => throw null!; public static S1 Create(string? x) => throw null!; public static S1 Create(bool? x) => throw null!; public object? Value { get; } } } class Program { static void Test1() { #line 100 S1? s = 1; _ = s.Value switch { int => 1, string => 2, bool => 3 }; } static void Test2() { #line 200 S1? s = """"; _ = s.Value switch { int => 1, string => 2, bool => 3 }; } static void Test3(string? x) { #line 300 S1? s = x; _ = s.Value switch { int => 1, string => 2, bool => 3 }; } static void Test4(bool x) { #line 400 S1? s = x; _ = s.Value switch { int => 1, string => 2, bool => 3 }; } static void Test5(bool? x) { #line 500 S1? s = x; _ = s.Value switch { int => 1, string => 2, bool => 3 }; } } "; var comp = CreateCompilation([src, UnionAttributeSource]); comp.VerifyDiagnostics( // (301,21): warning CS8655: The switch expression does not handle some null inputs (it is not exhaustive). For example, the pattern 'null' is not covered. // _ = s.Value switch { int => 1, string => 2, bool => 3 }; Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustiveForNull, "switch").WithArguments("null").WithLocation(301, 21), // (501,21): warning CS8655: The switch expression does not handle some null inputs (it is not exhaustive). For example, the pattern 'null' is not covered. // _ = s.Value switch { int => 1, string => 2, bool => 3 }; Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustiveForNull, "switch").WithArguments("null").WithLocation(501, 21) ); } [Fact] public void NullableAnalysis_MemberProvider_37_State_From_Conversion_TupleLiteral_NullableOfUnion() { var src = @" #nullable enable [System.Runtime.CompilerServices.Union] struct S1 : S1.IUnionMembers { object? IUnionMembers.Value => throw null!; public interface IUnionMembers { public static S1 Create(int x) => throw null!; public static S1 Create(string? x) => throw null!; public static S1 Create(bool? x) => throw null!; public object? Value { get; } } } class Program { static void Test1() { #line 100 (S1?, int) s = (1, 1); _ = s.Item1.Value switch { int => 1, string => 2, bool => 3 }; } static void Test2() { #line 200 (S1?, int) s = ("""", 1); _ = s.Item1.Value switch { int => 1, string => 2, bool => 3 }; } static void Test3(string? x) { #line 300 (S1?, int) s = (x, 1); _ = s.Item1.Value switch { int => 1, string => 2, bool => 3 }; } static void Test4(bool x) { #line 400 (S1?, int) s = (x, 1); _ = s.Item1.Value switch { int => 1, string => 2, bool => 3 }; } static void Test5(bool? x) { #line 500 (S1?, int) s = (x, 1); _ = s.Item1.Value switch { int => 1, string => 2, bool => 3 }; } } "; var comp = CreateCompilation([src, UnionAttributeSource]); comp.VerifyDiagnostics( // (301,27): warning CS8655: The switch expression does not handle some null inputs (it is not exhaustive). For example, the pattern 'null' is not covered. // _ = s.Item1.Value switch { int => 1, string => 2, bool => 3 }; Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustiveForNull, "switch").WithArguments("null").WithLocation(301, 27), // (501,27): warning CS8655: The switch expression does not handle some null inputs (it is not exhaustive). For example, the pattern 'null' is not covered. // _ = s.Item1.Value switch { int => 1, string => 2, bool => 3 }; Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustiveForNull, "switch").WithArguments("null").WithLocation(501, 27) ); } [Fact] public void NullableAnalysis_MemberProvider_38_State_From_Conversion_TupleValue_NullableOfUnion() { var src = @" #nullable enable [System.Runtime.CompilerServices.Union] struct S1 : S1.IUnionMembers { object? IUnionMembers.Value => throw null!; public interface IUnionMembers { public static S1 Create(int x) => throw null!; public static S1 Create(string? x) => throw null!; public static S1 Create(bool? x) => throw null!; public object? Value { get; } } } class Program { static void Test1((int, int) x) { #line 100 (S1?, int) s = x; _ = s.Item1.Value switch { int => 1, string => 2, bool => 3 }; } static void Test2((string, int) x) { #line 200 (S1?, int) s = x; _ = s.Item1.Value switch { int => 1, string => 2, bool => 3 }; } static void Test3((string?, int) x) { #line 300 (S1?, int) s = x; _ = s.Item1.Value switch { int => 1, string => 2, bool => 3 }; } static void Test4((bool, int) x) { #line 400 (S1?, int) s = x; _ = s.Item1.Value switch { int => 1, string => 2, bool => 3 }; } static void Test5((bool?, int) x) { #line 500 (S1?, int) s = x; _ = s.Item1.Value switch { int => 1, string => 2, bool => 3 }; } } "; var comp = CreateCompilation([src, UnionAttributeSource]); comp.VerifyDiagnostics( // (301,27): warning CS8655: The switch expression does not handle some null inputs (it is not exhaustive). For example, the pattern 'null' is not covered. // _ = s.Item1.Value switch { int => 1, string => 2, bool => 3 }; Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustiveForNull, "switch").WithArguments("null").WithLocation(301, 27), // (501,27): warning CS8655: The switch expression does not handle some null inputs (it is not exhaustive). For example, the pattern 'null' is not covered. // _ = s.Item1.Value switch { int => 1, string => 2, bool => 3 }; Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustiveForNull, "switch").WithArguments("null").WithLocation(501, 27) ); } [Fact] public void NullableAnalysis_MemberProvider_39_State_From_Conversion_Cast_NullableOfUnion() { var src = @" #nullable enable [System.Runtime.CompilerServices.Union] struct S1 : S1.IUnionMembers { object? IUnionMembers.Value => throw null!; public interface IUnionMembers { public static S1 Create(int x) => throw null!; public static S1 Create(string? x) => throw null!; public static S1 Create(bool? x) => throw null!; public object? Value { get; } } } class Program { static void Test1() { #line 100 S1? s = (S1?)1; _ = s.Value switch { int => 1, string => 2, bool => 3 }; } static void Test2() { #line 200 S1? s = (S1?)""""; _ = s.Value switch { int => 1, string => 2, bool => 3 }; } static void Test3(string? x) { #line 300 S1? s = (S1?)x; _ = s.Value switch { int => 1, string => 2, bool => 3 }; } static void Test4(bool x) { #line 400 S1? s = (S1?)x; _ = s.Value switch { int => 1, string => 2, bool => 3 }; } static void Test5(bool? x) { #line 500 S1? s = (S1?)x; _ = s.Value switch { int => 1, string => 2, bool => 3 }; } } "; var comp = CreateCompilation([src, UnionAttributeSource]); comp.VerifyDiagnostics( // (301,21): warning CS8655: The switch expression does not handle some null inputs (it is not exhaustive). For example, the pattern 'null' is not covered. // _ = s.Value switch { int => 1, string => 2, bool => 3 }; Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustiveForNull, "switch").WithArguments("null").WithLocation(301, 21), // (501,21): warning CS8655: The switch expression does not handle some null inputs (it is not exhaustive). For example, the pattern 'null' is not covered. // _ = s.Value switch { int => 1, string => 2, bool => 3 }; Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustiveForNull, "switch").WithArguments("null").WithLocation(501, 21) ); } [Fact] public void NullableAnalysis_MemberProvider_40_State_From_Conversion_Cast_TupleLiteral_NullableOfUnion() { var src = @" #nullable enable [System.Runtime.CompilerServices.Union] struct S1 : S1.IUnionMembers { object? IUnionMembers.Value => throw null!; public interface IUnionMembers { public static S1 Create(int x) => throw null!; public static S1 Create(string? x) => throw null!; public static S1 Create(bool? x) => throw null!; public object? Value { get; } } } class Program { static void Test1() { #line 100 (S1?, int) s = ((S1?, int))(1, 1); _ = s.Item1.Value switch { int => 1, string => 2, bool => 3 }; } static void Test2() { #line 200 (S1?, int) s = ((S1?, int))("""", 1); _ = s.Item1.Value switch { int => 1, string => 2, bool => 3 }; } static void Test3(string? x) { #line 300 (S1?, int) s = ((S1?, int))(x, 1); _ = s.Item1.Value switch { int => 1, string => 2, bool => 3 }; } static void Test4(bool x) { #line 400 (S1?, int) s = ((S1?, int))(x, 1); _ = s.Item1.Value switch { int => 1, string => 2, bool => 3 }; } static void Test5(bool? x) { #line 500 (S1?, int) s = ((S1?, int))(x, 1); _ = s.Item1.Value switch { int => 1, string => 2, bool => 3 }; } } "; var comp = CreateCompilation([src, UnionAttributeSource]); comp.VerifyDiagnostics( // (301,27): warning CS8655: The switch expression does not handle some null inputs (it is not exhaustive). For example, the pattern 'null' is not covered. // _ = s.Item1.Value switch { int => 1, string => 2, bool => 3 }; Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustiveForNull, "switch").WithArguments("null").WithLocation(301, 27), // (501,27): warning CS8655: The switch expression does not handle some null inputs (it is not exhaustive). For example, the pattern 'null' is not covered. // _ = s.Item1.Value switch { int => 1, string => 2, bool => 3 }; Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustiveForNull, "switch").WithArguments("null").WithLocation(501, 27) ); } [Fact] public void NullableAnalysis_MemberProvider_41_State_From_Conversion_Cast_TupleValue_NullableOfUnion() { var src = @" #nullable enable [System.Runtime.CompilerServices.Union] struct S1 : S1.IUnionMembers { object? IUnionMembers.Value => throw null!; public interface IUnionMembers { public static S1 Create(int x) => throw null!; public static S1 Create(string? x) => throw null!; public static S1 Create(bool? x) => throw null!; public object? Value { get; } } } class Program { static void Test1((int, int) x) { #line 100 (S1?, int) s = ((S1?, int))x; _ = s.Item1.Value switch { int => 1, string => 2, bool => 3 }; } static void Test2((string, int) x) { #line 200 (S1?, int) s = ((S1?, int))x; _ = s.Item1.Value switch { int => 1, string => 2, bool => 3 }; } static void Test3((string?, int) x) { #line 300 (S1?, int) s = ((S1?, int))x; _ = s.Item1.Value switch { int => 1, string => 2, bool => 3 }; } static void Test4((bool, int) x) { #line 400 (S1?, int) s = ((S1?, int))x; _ = s.Item1.Value switch { int => 1, string => 2, bool => 3 }; } static void Test5((bool?, int) x) { #line 500 (S1?, int) s = ((S1?, int))x; _ = s.Item1.Value switch { int => 1, string => 2, bool => 3 }; } } "; var comp = CreateCompilation([src, UnionAttributeSource]); comp.VerifyDiagnostics( // (301,27): warning CS8655: The switch expression does not handle some null inputs (it is not exhaustive). For example, the pattern 'null' is not covered. // _ = s.Item1.Value switch { int => 1, string => 2, bool => 3 }; Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustiveForNull, "switch").WithArguments("null").WithLocation(301, 27), // (501,27): warning CS8655: The switch expression does not handle some null inputs (it is not exhaustive). For example, the pattern 'null' is not covered. // _ = s.Item1.Value switch { int => 1, string => 2, bool => 3 }; Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustiveForNull, "switch").WithArguments("null").WithLocation(501, 27) ); } [Fact] public void NullableAnalysis_MemberProvider_42_State_From_Null_Test_NullableOfUnion() { var src = @" #nullable enable [System.Runtime.CompilerServices.Union] struct S1 : S1.IUnionMembers { object? IUnionMembers.Value => throw null!; public interface IUnionMembers { public static S1 Create(int x) => throw null!; public static S1 Create(bool? x) => throw null!; public object? Value { get; } } } [System.Runtime.CompilerServices.Union] struct S2 : S2.IUnionMembers { object? IUnionMembers.Value => throw null!; public interface IUnionMembers { public static S2 Create(int x) => throw null!; public static S2 Create(bool x) => throw null!; public object? Value { get; } } } class Program { static void Test2(S1? s0) { if (s0 is null) return; if (s0.Value is null) { var s = s0; #line 100 _ = s.Value switch { int => 1, bool => 3 }; } else { var s = s0; #line 200 _ = s.Value switch { int => 1, bool => 3 }; } } static void Test4(S2? s0) { if (s0 is null) return; if (s0.Value is null) { var s = s0; #line 300 _ = s.Value switch { int => 1, bool => 3 }; } else { var s = s0; #line 400 _ = s.Value switch { int => 1, bool => 3 }; } } } "; var comp = CreateCompilation([src, UnionAttributeSource]); comp.VerifyDiagnostics( // (100,25): warning CS8655: The switch expression does not handle some null inputs (it is not exhaustive). For example, the pattern 'null' is not covered. // _ = s.Value switch { int => 1, bool => 3 }; Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustiveForNull, "switch").WithArguments("null").WithLocation(100, 25), // (300,25): warning CS8655: The switch expression does not handle some null inputs (it is not exhaustive). For example, the pattern 'null' is not covered. // _ = s.Value switch { int => 1, bool => 3 }; Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustiveForNull, "switch").WithArguments("null").WithLocation(300, 25) ); } [Fact] public void NullableAnalysis_MemberProvider_43_State_From_NotNull_Test_NullableOfUnion() { var src = @" #nullable enable [System.Runtime.CompilerServices.Union] struct S1 : S1.IUnionMembers { object? IUnionMembers.Value => throw null!; public interface IUnionMembers { public static S1 Create(int x) => throw null!; public static S1 Create(bool? x) => throw null!; public object? Value { get; } } } [System.Runtime.CompilerServices.Union] struct S2 : S2.IUnionMembers { object? IUnionMembers.Value => throw null!; public interface IUnionMembers { public static S2 Create(int x) => throw null!; public static S2 Create(bool x) => throw null!; public object? Value { get; } } } class Program { static void Test2(S1? s0) { if (s0 is null) return; if (s0.Value is not null) { var s = s0; #line 100 _ = s.Value switch { int => 1, bool => 3 }; } else { var s = s0; #line 200 _ = s.Value switch { int => 1, bool => 3 }; } } static void Test4(S2? s0) { if (s0 is null) return; if (s0.Value is not null) { var s = s0; #line 300 _ = s.Value switch { int => 1, bool => 3 }; } else { var s = s0; #line 400 _ = s.Value switch { int => 1, bool => 3 }; } } } "; var comp = CreateCompilation([src, UnionAttributeSource]); comp.VerifyDiagnostics( // (200,25): warning CS8655: The switch expression does not handle some null inputs (it is not exhaustive). For example, the pattern 'null' is not covered. // _ = s.Value switch { int => 1, bool => 3 }; Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustiveForNull, "switch").WithArguments("null").WithLocation(200, 25), // (400,25): warning CS8655: The switch expression does not handle some null inputs (it is not exhaustive). For example, the pattern 'null' is not covered. // _ = s.Value switch { int => 1, bool => 3 }; Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustiveForNull, "switch").WithArguments("null").WithLocation(400, 25) ); } [Fact] public void NullableAnalysis_MemberProvider_44_Conversion_Value_Check_ReinferConstructor() { var src = @" #nullable enable [System.Runtime.CompilerServices.Union] struct S1<T> : S1<T>.IUnionMembers { object? IUnionMembers.Value => throw null!; public interface IUnionMembers { public static S1<T> Create(T x) => throw null!; public static S1<T> Create(bool x) => throw null!; public object? Value { get; } } } class Program { static void Test1(string? x, string? y) { var s = GetS1(y); #line 100 s = x; x.ToString(); } static void Test2(string? x, string y) { var s = GetS1(y); #line 200 s = x; x.ToString(); } static S1<T> GetS1<T>(T x) { return default; } } "; var comp = CreateCompilation([src, UnionAttributeSource]); comp.VerifyDiagnostics( // (101,9): warning CS8602: Dereference of a possibly null reference. // x.ToString(); Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "x").WithLocation(101, 9), // (200,13): warning CS8604: Possible null reference argument for parameter 'x' in 'S1<string> IUnionMembers.Create(string x)'. // s = x; Diagnostic(ErrorCode.WRN_NullReferenceArgument, "x").WithArguments("x", "S1<string> IUnionMembers.Create(string x)").WithLocation(200, 13) ); } [Fact] public void NullableAnalysis_MemberProvider_45_ReinferConstructor() { var src = @" #nullable enable [System.Runtime.CompilerServices.Union] struct S1<T1, T2> : S1<T1, T2>.IUnionMembers { object? IUnionMembers.Value => throw null!; public interface IUnionMembers : IFactory<C1<T1>, S1<T1, T2>>, IFactory<C2<T2>, S1<T1, T2>> { public object? Value { get; } } } public interface IFactory<T, R> { public static R Create(T x) => throw null!; } class C1<T>; class C2<T>; class Program { static void Test2(C1<string> x, C2<string?> y) { var s = GetS1(x, y); s = x; s = y; } static S1<T1, T2> GetS1<T1, T2>(C1<T1> x, C2<T2> y) { return default; } } "; var comp = CreateCompilation([src, UnionAttributeSource]); comp.VerifyDiagnostics(); } [Fact] public void NonBoxingUnionMatching_01_HasValue_Struct() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } public object Value => throw null; public bool HasValue => _value != null; static void Main() { System.Console.Write(Test1(new S1(1))); System.Console.Write(Test1(new S1())); System.Console.Write(Test2(new S1(2))); System.Console.Write(Test2(new S1())); } static bool Test1(S1 u) { return u is null; } static bool Test2(S1 u) { return u is not null; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); var verifier = CompileAndVerify(comp, expectedOutput: "FalseTrueTrueFalse").VerifyDiagnostics(); verifier.VerifyIL("S1.Test1", @" { // Code size 11 (0xb) .maxstack 2 IL_0000: ldarga.s V_0 IL_0002: call ""bool S1.HasValue.get"" IL_0007: ldc.i4.0 IL_0008: ceq IL_000a: ret } "); verifier.VerifyIL("S1.Test2", @" { // Code size 14 (0xe) .maxstack 2 IL_0000: ldarga.s V_0 IL_0002: call ""bool S1.HasValue.get"" IL_0007: ldc.i4.0 IL_0008: ceq IL_000a: ldc.i4.0 IL_000b: ceq IL_000d: ret } "); } [Theory] [CombinatorialData] public void NonBoxingUnionMatching_02_HasValue_Struct([CombinatorialValues("internal", "private")] string accessibility) { var src = @" [System.Runtime.CompilerServices.Union] struct S1 { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } public object Value => _value; " + accessibility + @" bool HasValue => throw null; static void Main() { System.Console.Write(Test1(new S1(1))); System.Console.Write(Test1(new S1())); System.Console.Write(Test2(new S1(2))); System.Console.Write(Test2(new S1())); } static bool Test1(S1 u) { return u is null; } static bool Test2(S1 u) { return u is not null; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); var verifier = CompileAndVerify(comp, expectedOutput: "FalseTrueTrueFalse").VerifyDiagnostics(); verifier.VerifyIL("S1.Test1", @" { // Code size 11 (0xb) .maxstack 2 IL_0000: ldarga.s V_0 IL_0002: call ""object S1.Value.get"" IL_0007: ldnull IL_0008: ceq IL_000a: ret } "); verifier.VerifyIL("S1.Test2", @" { // Code size 14 (0xe) .maxstack 2 IL_0000: ldarga.s V_0 IL_0002: call ""object S1.Value.get"" IL_0007: ldnull IL_0008: ceq IL_000a: ldc.i4.0 IL_000b: ceq IL_000d: ret } "); } [Fact] public void NonBoxingUnionMatching_03_HasValue_Class() { var src = @" [System.Runtime.CompilerServices.Union] class S1 { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } public object Value => _value; public bool HasValue => _value != null; static void Main() { System.Console.Write(Test1(new S1(1))); System.Console.Write(Test1(new S1(null))); System.Console.Write(Test1(null)); System.Console.Write(Test2(new S1(2))); System.Console.Write(Test2(new S1(null))); System.Console.Write(Test2(null)); } static bool Test1(S1 u) { return u is null; } static bool Test2(S1 u) { return u is not null; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); var verifier = CompileAndVerify(comp, expectedOutput: "FalseTrueTrueTrueFalseFalse").VerifyDiagnostics(); verifier.VerifyIL("S1.Test1", @" { // Code size 19 (0x13) .maxstack 1 .locals init (bool V_0) IL_0000: ldarg.0 IL_0001: brfalse.s IL_000b IL_0003: ldarg.0 IL_0004: callvirt ""bool S1.HasValue.get"" IL_0009: brtrue.s IL_000f IL_000b: ldc.i4.1 IL_000c: stloc.0 IL_000d: br.s IL_0011 IL_000f: ldc.i4.0 IL_0010: stloc.0 IL_0011: ldloc.0 IL_0012: ret } "); verifier.VerifyIL("S1.Test2", @" { // Code size 22 (0x16) .maxstack 2 .locals init (bool V_0) IL_0000: ldarg.0 IL_0001: brfalse.s IL_000b IL_0003: ldarg.0 IL_0004: callvirt ""bool S1.HasValue.get"" IL_0009: brtrue.s IL_000f IL_000b: ldc.i4.1 IL_000c: stloc.0 IL_000d: br.s IL_0011 IL_000f: ldc.i4.0 IL_0010: stloc.0 IL_0011: ldloc.0 IL_0012: ldc.i4.0 IL_0013: ceq IL_0015: ret } "); } [Theory] [CombinatorialData] public void NonBoxingUnionMatching_04_HasValue_Class([CombinatorialValues("internal", "private", "protected", "private protected", "protected internal")] string accessibility) { var src = @" [System.Runtime.CompilerServices.Union] class S1 { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } public object Value => _value; " + accessibility + @" bool HasValue => throw null; static void Main() { System.Console.Write(Test1(new S1(1))); System.Console.Write(Test1(new S1(null))); System.Console.Write(Test1(null)); System.Console.Write(Test2(new S1(2))); System.Console.Write(Test2(new S1(null))); System.Console.Write(Test2(null)); } static bool Test1(S1 u) { return u is null; } static bool Test2(S1 u) { return u is not null; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); var verifier = CompileAndVerify(comp, expectedOutput: "FalseTrueTrueTrueFalseFalse").VerifyDiagnostics(); verifier.VerifyIL("S1.Test1", @" { // Code size 19 (0x13) .maxstack 1 .locals init (bool V_0) IL_0000: ldarg.0 IL_0001: brfalse.s IL_000b IL_0003: ldarg.0 IL_0004: callvirt ""object S1.Value.get"" IL_0009: brtrue.s IL_000f IL_000b: ldc.i4.1 IL_000c: stloc.0 IL_000d: br.s IL_0011 IL_000f: ldc.i4.0 IL_0010: stloc.0 IL_0011: ldloc.0 IL_0012: ret } "); verifier.VerifyIL("S1.Test2", @" { // Code size 22 (0x16) .maxstack 2 .locals init (bool V_0) IL_0000: ldarg.0 IL_0001: brfalse.s IL_000b IL_0003: ldarg.0 IL_0004: callvirt ""object S1.Value.get"" IL_0009: brtrue.s IL_000f IL_000b: ldc.i4.1 IL_000c: stloc.0 IL_000d: br.s IL_0011 IL_000f: ldc.i4.0 IL_0010: stloc.0 IL_0011: ldloc.0 IL_0012: ldc.i4.0 IL_0013: ceq IL_0015: ret } "); } [Fact] public void NonBoxingUnionMatching_05_HasValue() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } public object Value => _value; public bool HasValue => _value != null; static void Main() { System.Console.Write(Test2(new S1(1))); System.Console.Write(Test2(new S1())); System.Console.Write(Test2(new S1(2))); } static bool Test2(S1 u) { return u is not null and 1; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); var verifier = CompileAndVerify(comp, expectedOutput: "TrueFalseFalse").VerifyDiagnostics(); // The IL would be shorter without HasValue, but, I guess, we expect // non-boxing pattern to be fully implemented if HasValue is present. // The scenario is somewhat pathological as well, no actual need to have 'not null' // pattern in the code. verifier.VerifyIL("S1.Test2", @" { // Code size 37 (0x25) .maxstack 2 .locals init (object V_0) IL_0000: ldarga.s V_0 IL_0002: call ""bool S1.HasValue.get"" IL_0007: brfalse.s IL_0023 IL_0009: ldarga.s V_0 IL_000b: call ""object S1.Value.get"" IL_0010: stloc.0 IL_0011: ldloc.0 IL_0012: isinst ""int"" IL_0017: brfalse.s IL_0023 IL_0019: ldloc.0 IL_001a: unbox.any ""int"" IL_001f: ldc.i4.1 IL_0020: ceq IL_0022: ret IL_0023: ldc.i4.0 IL_0024: ret } "); } [Fact] public void NonBoxingUnionMatching_06_HasValue() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } public object Value => _value; public bool HasValue { get { System.Console.Write(""HasValue ""); return _value != null; } } static void Main() { System.Console.Write(Test2(new S1(1))); System.Console.Write(Test2(new S1())); System.Console.Write(Test2(new S1(""a""))); } static int Test2(S1 u) { #line 26 return u switch { null => 0, not null => 1}; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); var verifier = CompileAndVerify(comp, expectedOutput: "HasValue 1HasValue 0HasValue 1").VerifyDiagnostics(); verifier.VerifyIL("S1.Test2", @" { // Code size 17 (0x11) .maxstack 1 .locals init (int V_0) IL_0000: ldarga.s V_0 IL_0002: call ""bool S1.HasValue.get"" IL_0007: brtrue.s IL_000d IL_0009: ldc.i4.0 IL_000a: stloc.0 IL_000b: br.s IL_000f IL_000d: ldc.i4.1 IL_000e: stloc.0 IL_000f: ldloc.0 IL_0010: ret } "); } [Fact] public void NonBoxingUnionMatching_07_HasValue_Class_Inheritance() { var src = @" [System.Runtime.CompilerServices.Union] class C1 { private readonly object _value; public C1(int x) { _value = x; } public C1(string x) { _value = x; } public object Value => _value; public bool HasValue => _value != null; } [System.Runtime.CompilerServices.Union] class C2 : C1 { public C2(int x) : base(x) { } public C2(string x) : base(x) { } public new object Value => base.Value; } class Program { static void Main() { System.Console.Write(Test1(new C2(1))); System.Console.Write(Test1(new C2(null))); System.Console.Write(Test1(null)); } static bool Test1(C2 u) { return u is null; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); CompileAndVerify(comp, expectedOutput: "FalseTrueTrue").VerifyDiagnostics(); } [Fact] public void NonBoxingUnionMatching_08_HasValue_Class_Inheritance() { var src = @" abstract class C0 { public bool HasValue => HasValueImpl; public abstract bool HasValueImpl { get; } } [System.Runtime.CompilerServices.Union] class C1 : C0 { private readonly object _value; public C1(int x) { _value = x; } public C1(string x) { _value = x; } public object Value => _value; public override bool HasValueImpl => _value != null; } class Program { static void Main() { System.Console.Write(Test1(new C1(1))); System.Console.Write(Test1(new C1(null))); System.Console.Write(Test1(null)); } static bool Test1(C1 u) { return u is null; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); CompileAndVerify(comp, expectedOutput: "FalseTrueTrue").VerifyDiagnostics(); } [Fact] public void NonBoxingUnionMatching_09_HasValue_Class_Inheritance() { var src = @" [System.Runtime.CompilerServices.Union] class C1 { protected readonly object _value; public C1(int x) { _value = x; } public C1(string x) { _value = x; } public object Value => _value; } [System.Runtime.CompilerServices.Union] class C2 : C1 { public C2(int x) : base(x) { } public C2(string x) : base(x) { } public bool HasValue => _value != null; public new object Value => _value; } class Program { static void Main() { System.Console.Write(Test1(new C2(1))); System.Console.Write(Test1(new C2(null))); System.Console.Write(Test1(null)); } static bool Test1(C2 u) { return u is null; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); var verifier = CompileAndVerify(comp, expectedOutput: "FalseTrueTrue").VerifyDiagnostics(); verifier.VerifyIL("Program.Test1", @" { // Code size 19 (0x13) .maxstack 1 .locals init (bool V_0) IL_0000: ldarg.0 IL_0001: brfalse.s IL_000b IL_0003: ldarg.0 IL_0004: callvirt ""bool C2.HasValue.get"" IL_0009: brtrue.s IL_000f IL_000b: ldc.i4.1 IL_000c: stloc.0 IL_000d: br.s IL_0011 IL_000f: ldc.i4.0 IL_0010: stloc.0 IL_0011: ldloc.0 IL_0012: ret } "); } [Fact] public void NonBoxingUnionMatching_10_HasValue_Class_Inheritance() { var src = @" [System.Runtime.CompilerServices.Union] abstract class C1 { protected readonly object _value; public C1(int x) { _value = x; } public C1(string x) { _value = x; } public object Value => _value; public abstract bool HasValue { get; } } [System.Runtime.CompilerServices.Union] class C2 : C1 { public C2(int x) : base(x) { } public C2(string x) : base(x) { } public override bool HasValue => _value != null; public new object Value => _value; } [System.Runtime.CompilerServices.Union] abstract class C3 : C1 { public C3(int x) : base(x) { } public C3(string x) : base(x) { } public abstract override bool HasValue { get; } public new object Value => _value; } class C4 : C3 { public C4(int x) : base(x) { } public C4(string x) : base(x) { } public override bool HasValue => _value != null; } class Program { static void Main() { System.Console.Write(Test1(new C2(1))); System.Console.Write(Test1(new C2(null))); System.Console.Write(Test1(null)); System.Console.Write(Test2(new C2(1))); System.Console.Write(Test2(new C2(null))); System.Console.Write(Test2(null)); System.Console.Write(Test3(new C4(1))); System.Console.Write(Test3(new C4(null))); System.Console.Write(Test3(null)); } static bool Test1(C1 u) { return u is null; } static bool Test2(C2 u) { return u is null; } static bool Test3(C3 u) { return u is null; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); var verifier = CompileAndVerify(comp, expectedOutput: "FalseTrueTrueFalseTrueTrueFalseTrueTrue").VerifyDiagnostics(); verifier.VerifyIL("Program.Test1", @" { // Code size 19 (0x13) .maxstack 1 .locals init (bool V_0) IL_0000: ldarg.0 IL_0001: brfalse.s IL_000b IL_0003: ldarg.0 IL_0004: callvirt ""bool C1.HasValue.get"" IL_0009: brtrue.s IL_000f IL_000b: ldc.i4.1 IL_000c: stloc.0 IL_000d: br.s IL_0011 IL_000f: ldc.i4.0 IL_0010: stloc.0 IL_0011: ldloc.0 IL_0012: ret } "); verifier.VerifyIL("Program.Test2", @" { // Code size 19 (0x13) .maxstack 1 .locals init (bool V_0) IL_0000: ldarg.0 IL_0001: brfalse.s IL_000b IL_0003: ldarg.0 IL_0004: callvirt ""bool C1.HasValue.get"" IL_0009: brtrue.s IL_000f IL_000b: ldc.i4.1 IL_000c: stloc.0 IL_000d: br.s IL_0011 IL_000f: ldc.i4.0 IL_0010: stloc.0 IL_0011: ldloc.0 IL_0012: ret } "); verifier.VerifyIL("Program.Test3", @" { // Code size 19 (0x13) .maxstack 1 .locals init (bool V_0) IL_0000: ldarg.0 IL_0001: brfalse.s IL_000b IL_0003: ldarg.0 IL_0004: callvirt ""bool C1.HasValue.get"" IL_0009: brtrue.s IL_000f IL_000b: ldc.i4.1 IL_000c: stloc.0 IL_000d: br.s IL_0011 IL_000f: ldc.i4.0 IL_0010: stloc.0 IL_0011: ldloc.0 IL_0012: ret } "); } [Fact] public void NonBoxingUnionMatching_11_HasValue_NullableAnalysis() { var src = @" #nullable enable [System.Runtime.CompilerServices.Union] struct S1 { public S1(int x) => throw null!; public S1(bool? x) => throw null!; public object? Value => throw null!; public bool HasValue => throw null!; } class Program { static void Test2(S1 s) { if (s.HasValue) { #line 100 _ = s switch { int => 1, bool => 3 }; } else { #line 200 _ = s switch { int => 1, bool => 3 }; } } static void Test4(S1 s) { if (!s.HasValue) { #line 300 _ = s switch { int => 1, bool => 3 }; } else { #line 400 _ = s switch { int => 1, bool => 3 }; } } } "; var comp = CreateCompilation([src, UnionAttributeSource]); comp.VerifyDiagnostics( // (200,19): warning CS8655: The switch expression does not handle some null inputs (it is not exhaustive). For example, the pattern 'null' is not covered. // _ = s switch { int => 1, bool => 3 }; Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustiveForNull, "switch").WithArguments("null").WithLocation(200, 19), // (300,19): warning CS8655: The switch expression does not handle some null inputs (it is not exhaustive). For example, the pattern 'null' is not covered. // _ = s switch { int => 1, bool => 3 }; Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustiveForNull, "switch").WithArguments("null").WithLocation(300, 19) ); } [Fact] public void NonBoxingUnionMatching_12_HasValue_NullableAnalysis_Generic() { var src = @" #nullable enable [System.Runtime.CompilerServices.Union] struct S1<T> { public S1(T x) => throw null!; public S1(bool? x) => throw null!; public object? Value => throw null!; public bool HasValue => throw null!; } class Program { static void Test2(S1<int> s) { if (s.HasValue) { #line 100 _ = s switch { int => 1, bool => 3 }; } else { #line 200 _ = s switch { int => 1, bool => 3 }; } } static void Test4(S1<int> s) { if (!s.HasValue) { #line 300 _ = s switch { int => 1, bool => 3 }; } else { #line 400 _ = s switch { int => 1, bool => 3 }; } } } "; var comp = CreateCompilation([src, UnionAttributeSource]); comp.VerifyDiagnostics( // (200,19): warning CS8655: The switch expression does not handle some null inputs (it is not exhaustive). For example, the pattern 'null' is not covered. // _ = s switch { int => 1, bool => 3 }; Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustiveForNull, "switch").WithArguments("null").WithLocation(200, 19), // (300,19): warning CS8655: The switch expression does not handle some null inputs (it is not exhaustive). For example, the pattern 'null' is not covered. // _ = s switch { int => 1, bool => 3 }; Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustiveForNull, "switch").WithArguments("null").WithLocation(300, 19) ); } [Fact] public void NonBoxingUnionMatching_13_HasValue_NullableAnalysis_Generic() { var src = @" #nullable enable [System.Runtime.CompilerServices.Union] struct S1<T> { public S1(int x) => throw null!; public S1(bool? x) => throw null!; public object? Value => throw null!; public T HasValue => throw null!; } class Program { static void Test2(S1<bool> s) { if (s.HasValue) { #line 100 _ = s switch { int => 1, bool => 3 }; } else { #line 200 _ = s switch { int => 1, bool => 3 }; } } static void Test4(S1<bool> s) { if (!s.HasValue) { #line 300 _ = s switch { int => 1, bool => 3 }; } else { #line 400 _ = s switch { int => 1, bool => 3 }; } } } "; var comp = CreateCompilation([src, UnionAttributeSource]); comp.VerifyDiagnostics( // (100,19): warning CS8655: The switch expression does not handle some null inputs (it is not exhaustive). For example, the pattern 'null' is not covered. // _ = s switch { int => 1, bool => 3 }; Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustiveForNull, "switch").WithArguments("null").WithLocation(100, 19), // (200,19): warning CS8655: The switch expression does not handle some null inputs (it is not exhaustive). For example, the pattern 'null' is not covered. // _ = s switch { int => 1, bool => 3 }; Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustiveForNull, "switch").WithArguments("null").WithLocation(200, 19), // (300,19): warning CS8655: The switch expression does not handle some null inputs (it is not exhaustive). For example, the pattern 'null' is not covered. // _ = s switch { int => 1, bool => 3 }; Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustiveForNull, "switch").WithArguments("null").WithLocation(300, 19), // (400,19): warning CS8655: The switch expression does not handle some null inputs (it is not exhaustive). For example, the pattern 'null' is not covered. // _ = s switch { int => 1, bool => 3 }; Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustiveForNull, "switch").WithArguments("null").WithLocation(400, 19) ); } [Fact] public void NonBoxingUnionMatching_14_NullableAnalysis_ValuePropertyOfTheInterfaceIsTargetedNotValuePropertyOfTheType() { var src = @" #nullable enable [System.Runtime.CompilerServices.Union] struct S1 { public S1(int x) => throw null!; public S1(bool? x) => throw null!; public object? Value => throw null!; public bool HasValue => throw null!; } class Program { static void Test2(S1 s) { if (s.HasValue) { #line 100 s.Value.ToString(); } else { #line 200 s.Value.ToString(); } } static void Test4(S1 s) { if (!s.HasValue) { #line 300 s.Value.ToString(); } else { #line 400 s.Value.ToString(); } } } "; var comp = CreateCompilation([src, UnionAttributeSource]); comp.VerifyDiagnostics( // (200,13): warning CS8602: Dereference of a possibly null reference. // s.Value.ToString(); Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "s.Value").WithLocation(200, 13), // (300,13): warning CS8602: Dereference of a possibly null reference. // s.Value.ToString(); Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "s.Value").WithLocation(300, 13) ); } [Fact] public void NonBoxingUnionMatching_15_TryGetValue_Struct() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } public object Value => _value; public bool TryGetValue(out int x) { if (_value is int v) { x = v; return true; } x = 0; return false; } static void Main() { System.Console.Write(Test1(new S1(1))); System.Console.Write(Test1(new S1())); System.Console.Write(Test1(new S1(""a""))); System.Console.Write(Test2(new S1(2))); System.Console.Write(Test2(new S1())); System.Console.Write(Test2(new S1(""b""))); } static bool Test1(S1 u) { return u is int; } static bool Test2(S1 u) { return u is not int; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); var verifier = CompileAndVerify(comp, expectedOutput: "TrueFalseFalseFalseTrueTrue").VerifyDiagnostics(); verifier.VerifyIL("S1.Test1", @" { // Code size 10 (0xa) .maxstack 2 .locals init (int V_0) IL_0000: ldarga.s V_0 IL_0002: ldloca.s V_0 IL_0004: call ""bool S1.TryGetValue(out int)"" IL_0009: ret } "); verifier.VerifyIL("S1.Test2", @" { // Code size 13 (0xd) .maxstack 2 .locals init (int V_0) IL_0000: ldarga.s V_0 IL_0002: ldloca.s V_0 IL_0004: call ""bool S1.TryGetValue(out int)"" IL_0009: ldc.i4.0 IL_000a: ceq IL_000c: ret } "); } [Fact] public void NonBoxingUnionMatching_16_TryGetValue_Class() { var src = @" [System.Runtime.CompilerServices.Union] class S1 { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } public object Value => _value; public bool TryGetValue(out int x) { if (_value is int v) { x = v; return true; } x = 0; return false; } static void Main() { System.Console.Write(Test1(new S1(1))); System.Console.Write(Test1(new S1(null))); System.Console.Write(Test1(new S1(""a""))); System.Console.Write(Test1(null)); System.Console.Write(Test2(new S1(2))); System.Console.Write(Test2(new S1(null))); System.Console.Write(Test2(new S1(""b""))); System.Console.Write(Test2(null)); } static bool Test1(S1 u) { return u is int; } static bool Test2(S1 u) { return u is not int; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); var verifier = CompileAndVerify(comp, expectedOutput: "TrueFalseFalseFalseFalseTrueTrueTrue").VerifyDiagnostics(); verifier.VerifyIL("S1.Test1", @" { // Code size 14 (0xe) .maxstack 2 .locals init (int V_0) IL_0000: ldarg.0 IL_0001: brfalse.s IL_000c IL_0003: ldarg.0 IL_0004: ldloca.s V_0 IL_0006: callvirt ""bool S1.TryGetValue(out int)"" IL_000b: ret IL_000c: ldc.i4.0 IL_000d: ret } "); verifier.VerifyIL("S1.Test2", @" { // Code size 18 (0x12) .maxstack 2 .locals init (int V_0) IL_0000: ldarg.0 IL_0001: brfalse.s IL_000d IL_0003: ldarg.0 IL_0004: ldloca.s V_0 IL_0006: callvirt ""bool S1.TryGetValue(out int)"" IL_000b: br.s IL_000e IL_000d: ldc.i4.0 IL_000e: ldc.i4.0 IL_000f: ceq IL_0011: ret } "); } [Fact] public void NonBoxingUnionMatching_17_TryGetValue() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 { private readonly object _value; public S1(int x) { _value = x; } public S1(object x) { _value = x; } public object Value => _value; public bool TryGetValue(out object x) { x = _value; return x != null; } static void Main() { System.Console.Write(Test1(new S1(1))); System.Console.Write(Test1(new S1())); System.Console.Write(Test1(new S1(""a""))); System.Console.Write(Test2(new S1(2))); System.Console.Write(Test2(new S1())); System.Console.Write(Test2(new S1(""b""))); } static bool Test1(S1 u) { #line 100 return u is object; } static bool Test2(S1 u) { #line 200 return u is not object; } static bool Test3(S2 u) { #line 300 return u is object; } static bool Test4(S2 u) { #line 400 return u is not object; } } struct S2; "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); comp.VerifyDiagnostics( // (100,16): warning CS0183: The given expression is always of the provided ('object') type // return u is object; Diagnostic(ErrorCode.WRN_IsAlwaysTrue, "u is object").WithArguments("object").WithLocation(100, 16), // (200,16): error CS8518: An expression of type 'S1' can never match the provided pattern. // return u is not object; Diagnostic(ErrorCode.ERR_IsPatternImpossible, "u is not object").WithArguments("S1").WithLocation(200, 16), // (300,16): warning CS0183: The given expression is always of the provided ('object') type // return u is object; Diagnostic(ErrorCode.WRN_IsAlwaysTrue, "u is object").WithArguments("object").WithLocation(300, 16), // (400,16): error CS8518: An expression of type 'S2' can never match the provided pattern. // return u is not object; Diagnostic(ErrorCode.ERR_IsPatternImpossible, "u is not object").WithArguments("S2").WithLocation(400, 16) ); } [Fact] public void NonBoxingUnionMatching_18_TryGetValue_Plus_HasValue() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 { private readonly object _value; public S1(int x) { _value = x; } public S1(object x) { _value = x; } public object Value => _value; public bool TryGetValue(out object x) { x = _value; return x != null; } public bool HasValue => _value != null; static void Main() { System.Console.Write(Test1(new S1(1))); System.Console.Write(Test1(new S1())); System.Console.Write(Test1(new S1(""a""))); System.Console.Write(Test2(new S1(2))); System.Console.Write(Test2(new S1())); System.Console.Write(Test2(new S1(""b""))); } static bool Test1(S1 u) { #line 100 return u is object; } static bool Test2(S1 u) { #line 200 return u is not object; } static bool Test3(S2 u) { #line 300 return u is object; } static bool Test4(S2 u) { #line 400 return u is not object; } } struct S2; "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); comp.VerifyDiagnostics( // (100,16): warning CS0183: The given expression is always of the provided ('object') type // return u is object; Diagnostic(ErrorCode.WRN_IsAlwaysTrue, "u is object").WithArguments("object").WithLocation(100, 16), // (200,16): error CS8518: An expression of type 'S1' can never match the provided pattern. // return u is not object; Diagnostic(ErrorCode.ERR_IsPatternImpossible, "u is not object").WithArguments("S1").WithLocation(200, 16), // (300,16): warning CS0183: The given expression is always of the provided ('object') type // return u is object; Diagnostic(ErrorCode.WRN_IsAlwaysTrue, "u is object").WithArguments("object").WithLocation(300, 16), // (400,16): error CS8518: An expression of type 'S2' can never match the provided pattern. // return u is not object; Diagnostic(ErrorCode.ERR_IsPatternImpossible, "u is not object").WithArguments("S2").WithLocation(400, 16) ); } [Fact] public void NonBoxingUnionMatching_19_HasValue() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 { private readonly object _value; public S1(int x) { _value = x; } public S1(object x) { _value = x; } public object Value => _value; public bool HasValue => _value != null; static void Main() { System.Console.Write(Test1(new S1(1))); System.Console.Write(Test1(new S1())); System.Console.Write(Test1(new S1(""a""))); System.Console.Write(Test2(new S1(2))); System.Console.Write(Test2(new S1())); System.Console.Write(Test2(new S1(""b""))); } static bool Test1(S1 u) { #line 100 return u is object; } static bool Test2(S1 u) { #line 200 return u is not object; } static bool Test3(S2 u) { #line 300 return u is object; } static bool Test4(S2 u) { #line 400 return u is not object; } } struct S2; "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); comp.VerifyDiagnostics( // (100,16): warning CS0183: The given expression is always of the provided ('object') type // return u is object; Diagnostic(ErrorCode.WRN_IsAlwaysTrue, "u is object").WithArguments("object").WithLocation(100, 16), // (200,16): error CS8518: An expression of type 'S1' can never match the provided pattern. // return u is not object; Diagnostic(ErrorCode.ERR_IsPatternImpossible, "u is not object").WithArguments("S1").WithLocation(200, 16), // (300,16): warning CS0183: The given expression is always of the provided ('object') type // return u is object; Diagnostic(ErrorCode.WRN_IsAlwaysTrue, "u is object").WithArguments("object").WithLocation(300, 16), // (400,16): error CS8518: An expression of type 'S2' can never match the provided pattern. // return u is not object; Diagnostic(ErrorCode.ERR_IsPatternImpossible, "u is not object").WithArguments("S2").WithLocation(400, 16) ); } [Fact] public void NonBoxingUnionMatching_20_HasValue() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 { private readonly object _value; public S1(int x) { _value = x; } public S1(object x) { _value = x; } public object Value => _value; public bool HasValue => _value != null; static void Main() { System.Console.Write(Test1(new S1(1))); System.Console.Write(Test1(new S1())); System.Console.Write(Test1(new S1(""a""))); } static int Test1(S1 u) { return u switch { null => 0, int => 1, _ => 2}; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); var verifier = CompileAndVerify(comp, expectedOutput: "102").VerifyDiagnostics(); verifier.VerifyIL("S1.Test1", @" { // Code size 37 (0x25) .maxstack 1 .locals init (int V_0) IL_0000: ldarga.s V_0 IL_0002: call ""bool S1.HasValue.get"" IL_0007: brfalse.s IL_0019 IL_0009: ldarga.s V_0 IL_000b: call ""object S1.Value.get"" IL_0010: isinst ""int"" IL_0015: brtrue.s IL_001d IL_0017: br.s IL_0021 IL_0019: ldc.i4.0 IL_001a: stloc.0 IL_001b: br.s IL_0023 IL_001d: ldc.i4.1 IL_001e: stloc.0 IL_001f: br.s IL_0023 IL_0021: ldc.i4.2 IL_0022: stloc.0 IL_0023: ldloc.0 IL_0024: ret } "); } [Fact] public void NonBoxingUnionMatching_21_TryGetValue_Struct() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } public object Value => _value; public bool TryGetValue(out string x) { x = _value as string; return x != null; } static void Main() { System.Console.Write(Test1(new S1(1))); System.Console.Write(Test1(new S1())); System.Console.Write(Test1(new S1(""a""))); System.Console.Write(Test2(new S1(2))); System.Console.Write(Test2(new S1())); System.Console.Write(Test2(new S1(""b""))); } static bool Test1(S1 u) { return u is ""a""; } static bool Test2(S1 u) { return u is not ""b""; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); var verifier = CompileAndVerify(comp, expectedOutput: "FalseFalseTrueTrueTrueFalse").VerifyDiagnostics(); verifier.VerifyIL("S1.Test1", @" { // Code size 25 (0x19) .maxstack 2 .locals init (string V_0) IL_0000: ldarga.s V_0 IL_0002: ldloca.s V_0 IL_0004: call ""bool S1.TryGetValue(out string)"" IL_0009: brfalse.s IL_0017 IL_000b: ldloc.0 IL_000c: ldstr ""a"" IL_0011: call ""bool string.op_Equality(string, string)"" IL_0016: ret IL_0017: ldc.i4.0 IL_0018: ret } "); verifier.VerifyIL("S1.Test2", @" { // Code size 29 (0x1d) .maxstack 2 .locals init (string V_0) IL_0000: ldarga.s V_0 IL_0002: ldloca.s V_0 IL_0004: call ""bool S1.TryGetValue(out string)"" IL_0009: brfalse.s IL_0018 IL_000b: ldloc.0 IL_000c: ldstr ""b"" IL_0011: call ""bool string.op_Equality(string, string)"" IL_0016: br.s IL_0019 IL_0018: ldc.i4.0 IL_0019: ldc.i4.0 IL_001a: ceq IL_001c: ret } "); } [Fact] public void NonBoxingUnionMatching_22_TryGetValue_Class() { var src = @" [System.Runtime.CompilerServices.Union] class S1 { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } public object Value => _value; public bool TryGetValue(out string x) { x = _value as string; return x != null; } static void Main() { System.Console.Write(Test1(new S1(1))); System.Console.Write(Test1(new S1(null))); System.Console.Write(Test1(new S1(""a""))); System.Console.Write(Test1(null)); System.Console.Write(Test2(new S1(2))); System.Console.Write(Test2(new S1(null))); System.Console.Write(Test2(new S1(""b""))); System.Console.Write(Test2(null)); } static bool Test1(S1 u) { return u is ""a""; } static bool Test2(S1 u) { return u is not ""b""; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); var verifier = CompileAndVerify(comp, expectedOutput: "FalseFalseTrueFalseTrueTrueFalseTrue").VerifyDiagnostics(); verifier.VerifyIL("S1.Test1", @" { // Code size 27 (0x1b) .maxstack 2 .locals init (string V_0) IL_0000: ldarg.0 IL_0001: brfalse.s IL_0019 IL_0003: ldarg.0 IL_0004: ldloca.s V_0 IL_0006: callvirt ""bool S1.TryGetValue(out string)"" IL_000b: brfalse.s IL_0019 IL_000d: ldloc.0 IL_000e: ldstr ""a"" IL_0013: call ""bool string.op_Equality(string, string)"" IL_0018: ret IL_0019: ldc.i4.0 IL_001a: ret } "); verifier.VerifyIL("S1.Test2", @" { // Code size 31 (0x1f) .maxstack 2 .locals init (string V_0) IL_0000: ldarg.0 IL_0001: brfalse.s IL_001a IL_0003: ldarg.0 IL_0004: ldloca.s V_0 IL_0006: callvirt ""bool S1.TryGetValue(out string)"" IL_000b: brfalse.s IL_001a IL_000d: ldloc.0 IL_000e: ldstr ""b"" IL_0013: call ""bool string.op_Equality(string, string)"" IL_0018: br.s IL_001b IL_001a: ldc.i4.0 IL_001b: ldc.i4.0 IL_001c: ceq IL_001e: ret } "); } [Fact] public void NonBoxingUnionMatching_23_TryGetValue() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } public object Value => _value; public bool TryGetValue(out int x) { if (_value is int v) { x = v; return true; } x = 0; return false; } static void Main() { System.Console.Write(Test1((new S1(1), 1))); System.Console.Write(Test1((new S1(), 1))); System.Console.Write(Test1((new S1(""a""), 1))); } static bool Test1((S1, int) u) { return u is (int, 1) or (int, 2); } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); var verifier = CompileAndVerify(comp, expectedOutput: "TrueFalseFalse").VerifyDiagnostics(); verifier.VerifyIL("S1.Test1", @" { // Code size 39 (0x27) .maxstack 2 .locals init (S1 V_0, int V_1, int V_2, bool V_3) IL_0000: ldarg.0 IL_0001: ldfld ""S1 System.ValueTuple<S1, int>.Item1"" IL_0006: stloc.0 IL_0007: ldloca.s V_0 IL_0009: ldloca.s V_1 IL_000b: call ""bool S1.TryGetValue(out int)"" IL_0010: brfalse.s IL_0023 IL_0012: ldarg.0 IL_0013: ldfld ""int System.ValueTuple<S1, int>.Item2"" IL_0018: stloc.2 IL_0019: ldloc.2 IL_001a: ldc.i4.1 IL_001b: sub IL_001c: ldc.i4.1 IL_001d: bgt.un.s IL_0023 IL_001f: ldc.i4.1 IL_0020: stloc.3 IL_0021: br.s IL_0025 IL_0023: ldc.i4.0 IL_0024: stloc.3 IL_0025: ldloc.3 IL_0026: ret } "); } [Fact] public void NonBoxingUnionMatching_24_TryGetValue() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } public object Value { get { System.Console.Write(""get_Value ""); return _value; } } public bool TryGetValue(out int x) { System.Console.Write(""TryGetValue ""); if (_value is int v) { x = v; return true; } x = 0; return false; } static void Main() { System.Console.Write(Test1((new S1(1), 1))); System.Console.Write(""; ""); System.Console.Write(Test1((new S1(), 2))); System.Console.Write(""; ""); System.Console.Write(Test1((new S1(), 3))); System.Console.Write(""; ""); System.Console.Write(Test1((new S1(""a""), 1))); } static bool Test1((S1, int) u) { return u is (null, 2) or (int, 1); } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); var verifier = CompileAndVerify(comp, expectedOutput: "get_Value TryGetValue True; get_Value True; get_Value False; get_Value TryGetValue False").VerifyDiagnostics(); verifier.VerifyIL("S1.Test1", @" { // Code size 55 (0x37) .maxstack 2 .locals init (S1 V_0, int V_1, bool V_2) IL_0000: ldarg.0 IL_0001: ldfld ""S1 System.ValueTuple<S1, int>.Item1"" IL_0006: stloc.0 IL_0007: ldloca.s V_0 IL_0009: call ""object S1.Value.get"" IL_000e: brtrue.s IL_001b IL_0010: ldarg.0 IL_0011: ldfld ""int System.ValueTuple<S1, int>.Item2"" IL_0016: ldc.i4.2 IL_0017: beq.s IL_002f IL_0019: br.s IL_0033 IL_001b: ldloca.s V_0 IL_001d: ldloca.s V_1 IL_001f: call ""bool S1.TryGetValue(out int)"" IL_0024: brfalse.s IL_0033 IL_0026: ldarg.0 IL_0027: ldfld ""int System.ValueTuple<S1, int>.Item2"" IL_002c: ldc.i4.1 IL_002d: bne.un.s IL_0033 IL_002f: ldc.i4.1 IL_0030: stloc.2 IL_0031: br.s IL_0035 IL_0033: ldc.i4.0 IL_0034: stloc.2 IL_0035: ldloc.2 IL_0036: ret } "); } [Fact] public void NonBoxingUnionMatching_25_TryGetValue() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } public object Value { get { System.Console.Write(""get_Value ""); return _value; } } public bool TryGetValue(out int x) { System.Console.Write(""TryGetValue ""); if (_value is int v) { x = v; return true; } x = 0; return false; } static void Main() { System.Console.Write(Test1((new S1(1), 1))); System.Console.Write(""; ""); System.Console.Write(Test1((new S1(), 2))); System.Console.Write(""; ""); System.Console.Write(Test1((new S1(), 3))); System.Console.Write(""; ""); System.Console.Write(Test1((new S1(""a""), 1))); } static bool Test1((S1, int) u) { return u is (int, 1) or (null, 2); } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); var verifier = CompileAndVerify(comp, expectedOutput: "TryGetValue True; TryGetValue get_Value True; TryGetValue get_Value False; TryGetValue get_Value False").VerifyDiagnostics(); verifier.VerifyIL("S1.Test1", @" { // Code size 55 (0x37) .maxstack 2 .locals init (S1 V_0, int V_1, bool V_2) IL_0000: ldarg.0 IL_0001: ldfld ""S1 System.ValueTuple<S1, int>.Item1"" IL_0006: stloc.0 IL_0007: ldloca.s V_0 IL_0009: ldloca.s V_1 IL_000b: call ""bool S1.TryGetValue(out int)"" IL_0010: brfalse.s IL_001d IL_0012: ldarg.0 IL_0013: ldfld ""int System.ValueTuple<S1, int>.Item2"" IL_0018: ldc.i4.1 IL_0019: beq.s IL_002f IL_001b: br.s IL_0033 IL_001d: ldloca.s V_0 IL_001f: call ""object S1.Value.get"" IL_0024: brtrue.s IL_0033 IL_0026: ldarg.0 IL_0027: ldfld ""int System.ValueTuple<S1, int>.Item2"" IL_002c: ldc.i4.2 IL_002d: bne.un.s IL_0033 IL_002f: ldc.i4.1 IL_0030: stloc.2 IL_0031: br.s IL_0035 IL_0033: ldc.i4.0 IL_0034: stloc.2 IL_0035: ldloc.2 IL_0036: ret } "); } [Fact] public void NonBoxingUnionMatching_26_TryGetValue() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } public object Value { get { System.Console.Write(""get_Value ""); return _value; } } public bool TryGetValue(out int x) { System.Console.Write(""TryGetValue ""); if (_value is int v) { x = v; return true; } x = 0; return false; } static void Main() { System.Console.Write(Test1((new S1(1), 1))); System.Console.Write(""; ""); System.Console.Write(Test1((new S1(1), -1))); System.Console.Write(""; ""); System.Console.Write(Test1((new S1(), 2))); System.Console.Write(""; ""); System.Console.Write(Test1((new S1(), 3))); System.Console.Write(""; ""); System.Console.Write(Test1((new S1(""a""), 1))); System.Console.Write(""; ""); System.Console.Write(Test1((new S1(""a""), 2))); } static bool Test1((S1, int) u) { return u is (not null, 2) or (int, 1); } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); var verifier = CompileAndVerify(comp, expectedOutput: "get_Value TryGetValue True; get_Value TryGetValue False; get_Value False; get_Value False; get_Value TryGetValue False; get_Value True").VerifyDiagnostics(); verifier.VerifyIL("S1.Test1", @" { // Code size 50 (0x32) .maxstack 2 .locals init (S1 V_0, int V_1, int V_2, bool V_3) IL_0000: ldarg.0 IL_0001: ldfld ""S1 System.ValueTuple<S1, int>.Item1"" IL_0006: stloc.0 IL_0007: ldloca.s V_0 IL_0009: call ""object S1.Value.get"" IL_000e: brfalse.s IL_002e IL_0010: ldarg.0 IL_0011: ldfld ""int System.ValueTuple<S1, int>.Item2"" IL_0016: stloc.1 IL_0017: ldloc.1 IL_0018: ldc.i4.2 IL_0019: beq.s IL_002a IL_001b: ldloca.s V_0 IL_001d: ldloca.s V_2 IL_001f: call ""bool S1.TryGetValue(out int)"" IL_0024: brfalse.s IL_002e IL_0026: ldloc.1 IL_0027: ldc.i4.1 IL_0028: bne.un.s IL_002e IL_002a: ldc.i4.1 IL_002b: stloc.3 IL_002c: br.s IL_0030 IL_002e: ldc.i4.0 IL_002f: stloc.3 IL_0030: ldloc.3 IL_0031: ret } "); } [Fact] public void NonBoxingUnionMatching_27_TryGetValue() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } public object Value { get { System.Console.Write(""get_Value ""); return _value; } } public bool TryGetValue(out int x) { System.Console.Write(""TryGetValue ""); if (_value is int v) { x = v; return true; } x = 0; return false; } static void Main() { System.Console.Write(Test1((new S1(1), 1))); System.Console.Write(""; ""); System.Console.Write(Test1((new S1(1), -1))); System.Console.Write(""; ""); System.Console.Write(Test1((new S1(), 2))); System.Console.Write(""; ""); System.Console.Write(Test1((new S1(), 3))); System.Console.Write(""; ""); System.Console.Write(Test1((new S1(""a""), 1))); System.Console.Write(""; ""); System.Console.Write(Test1((new S1(""a""), 2))); } static bool Test1((S1, int) u) { return u is (int, 1) or (not null, 2); } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); var verifier = CompileAndVerify(comp, expectedOutput: "TryGetValue True; TryGetValue False; TryGetValue get_Value False; TryGetValue get_Value False; TryGetValue get_Value False; TryGetValue get_Value True").VerifyDiagnostics(); verifier.VerifyIL("S1.Test1", @" { // Code size 59 (0x3b) .maxstack 2 .locals init (S1 V_0, int V_1, int V_2, bool V_3) IL_0000: ldarg.0 IL_0001: ldfld ""S1 System.ValueTuple<S1, int>.Item1"" IL_0006: stloc.0 IL_0007: ldloca.s V_0 IL_0009: ldloca.s V_1 IL_000b: call ""bool S1.TryGetValue(out int)"" IL_0010: brfalse.s IL_001f IL_0012: ldarg.0 IL_0013: ldfld ""int System.ValueTuple<S1, int>.Item2"" IL_0018: stloc.2 IL_0019: ldloc.2 IL_001a: ldc.i4.1 IL_001b: beq.s IL_0033 IL_001d: br.s IL_002f IL_001f: ldloca.s V_0 IL_0021: call ""object S1.Value.get"" IL_0026: brfalse.s IL_0037 IL_0028: ldarg.0 IL_0029: ldfld ""int System.ValueTuple<S1, int>.Item2"" IL_002e: stloc.2 IL_002f: ldloc.2 IL_0030: ldc.i4.2 IL_0031: bne.un.s IL_0037 IL_0033: ldc.i4.1 IL_0034: stloc.3 IL_0035: br.s IL_0039 IL_0037: ldc.i4.0 IL_0038: stloc.3 IL_0039: ldloc.3 IL_003a: ret } "); } [Fact] public void NonBoxingUnionMatching_28_TryGetValue() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } public object Value { get { System.Console.Write(""get_Value ""); return _value; } } public bool TryGetValue(out int x) { System.Console.Write(""TryGetValue ""); if (_value is int v) { x = v; return true; } x = 0; return false; } static void Main() { System.Console.Write(Test1((new S1(1), 1))); System.Console.Write(""; ""); System.Console.Write(Test1((new S1(), 2))); System.Console.Write(""; ""); System.Console.Write(Test1((new S1(), 3))); System.Console.Write(""; ""); System.Console.Write(Test1((new S1(), 1))); System.Console.Write(""; ""); System.Console.Write(Test1((new S1(""a""), 1))); System.Console.Write(""; ""); System.Console.Write(Test1((new S1(""a""), 2))); } static bool Test1((S1, int) u) { return u is (null, 2) or (not int, 1); } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); var verifier = CompileAndVerify(comp, expectedOutput: "get_Value TryGetValue False; get_Value True; get_Value False; get_Value True; get_Value TryGetValue True; get_Value TryGetValue False").VerifyDiagnostics(); verifier.VerifyIL("S1.Test1", @" { // Code size 59 (0x3b) .maxstack 2 .locals init (S1 V_0, int V_1, int V_2, bool V_3) IL_0000: ldarg.0 IL_0001: ldfld ""S1 System.ValueTuple<S1, int>.Item1"" IL_0006: stloc.0 IL_0007: ldloca.s V_0 IL_0009: call ""object S1.Value.get"" IL_000e: brtrue.s IL_001d IL_0010: ldarg.0 IL_0011: ldfld ""int System.ValueTuple<S1, int>.Item2"" IL_0016: stloc.1 IL_0017: ldloc.1 IL_0018: ldc.i4.2 IL_0019: beq.s IL_0033 IL_001b: br.s IL_002f IL_001d: ldloca.s V_0 IL_001f: ldloca.s V_2 IL_0021: call ""bool S1.TryGetValue(out int)"" IL_0026: brtrue.s IL_0037 IL_0028: ldarg.0 IL_0029: ldfld ""int System.ValueTuple<S1, int>.Item2"" IL_002e: stloc.1 IL_002f: ldloc.1 IL_0030: ldc.i4.1 IL_0031: bne.un.s IL_0037 IL_0033: ldc.i4.1 IL_0034: stloc.3 IL_0035: br.s IL_0039 IL_0037: ldc.i4.0 IL_0038: stloc.3 IL_0039: ldloc.3 IL_003a: ret } "); } [Fact] public void NonBoxingUnionMatching_29_TryGetValue() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } public object Value { get { System.Console.Write(""get_Value ""); return _value; } } public bool TryGetValue(out int x) { System.Console.Write(""TryGetValue ""); if (_value is int v) { x = v; return true; } x = 0; return false; } static void Main() { System.Console.Write(Test1((new S1(1), 1))); System.Console.Write(""; ""); System.Console.Write(Test1((new S1(), 2))); System.Console.Write(""; ""); System.Console.Write(Test1((new S1(), 3))); System.Console.Write(""; ""); System.Console.Write(Test1((new S1(), 1))); System.Console.Write(""; ""); System.Console.Write(Test1((new S1(""a""), 1))); System.Console.Write(""; ""); System.Console.Write(Test1((new S1(""a""), 2))); } static bool Test1((S1, int) u) { return u is (not int, 1) or (null, 2); } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); var verifier = CompileAndVerify(comp, expectedOutput: "TryGetValue False; TryGetValue get_Value True; TryGetValue get_Value False; TryGetValue True; TryGetValue True; TryGetValue get_Value False").VerifyDiagnostics(); verifier.VerifyIL("S1.Test1", @" { // Code size 50 (0x32) .maxstack 2 .locals init (S1 V_0, int V_1, int V_2, bool V_3) IL_0000: ldarg.0 IL_0001: ldfld ""S1 System.ValueTuple<S1, int>.Item1"" IL_0006: stloc.0 IL_0007: ldloca.s V_0 IL_0009: ldloca.s V_1 IL_000b: call ""bool S1.TryGetValue(out int)"" IL_0010: brtrue.s IL_002e IL_0012: ldarg.0 IL_0013: ldfld ""int System.ValueTuple<S1, int>.Item2"" IL_0018: stloc.2 IL_0019: ldloc.2 IL_001a: ldc.i4.1 IL_001b: beq.s IL_002a IL_001d: ldloca.s V_0 IL_001f: call ""object S1.Value.get"" IL_0024: brtrue.s IL_002e IL_0026: ldloc.2 IL_0027: ldc.i4.2 IL_0028: bne.un.s IL_002e IL_002a: ldc.i4.1 IL_002b: stloc.3 IL_002c: br.s IL_0030 IL_002e: ldc.i4.0 IL_002f: stloc.3 IL_0030: ldloc.3 IL_0031: ret } "); } [Fact] public void NonBoxingUnionMatching_30_TryGetValue() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } public object Value { get { System.Console.Write(""get_Value ""); return _value; } } public bool HasValue { get { System.Console.Write(""HasValue ""); return _value != null; } } public bool TryGetValue(out int x) { System.Console.Write(""TryGetValue ""); if (_value is int v) { x = v; return true; } x = 0; return false; } static void Main() { System.Console.Write(Test1((new S1(1), 1))); System.Console.Write(""; ""); System.Console.Write(Test1((new S1(), 2))); System.Console.Write(""; ""); System.Console.Write(Test1((new S1(), 3))); System.Console.Write(""; ""); System.Console.Write(Test1((new S1(""a""), 1))); } static bool Test1((S1, int) u) { return u is (null, 2) or (int, 1); } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); var verifier = CompileAndVerify(comp, expectedOutput: "HasValue TryGetValue True; HasValue True; HasValue False; HasValue TryGetValue False").VerifyDiagnostics(); verifier.VerifyIL("S1.Test1", @" { // Code size 55 (0x37) .maxstack 2 .locals init (S1 V_0, int V_1, bool V_2) IL_0000: ldarg.0 IL_0001: ldfld ""S1 System.ValueTuple<S1, int>.Item1"" IL_0006: stloc.0 IL_0007: ldloca.s V_0 IL_0009: call ""bool S1.HasValue.get"" IL_000e: brtrue.s IL_001b IL_0010: ldarg.0 IL_0011: ldfld ""int System.ValueTuple<S1, int>.Item2"" IL_0016: ldc.i4.2 IL_0017: beq.s IL_002f IL_0019: br.s IL_0033 IL_001b: ldloca.s V_0 IL_001d: ldloca.s V_1 IL_001f: call ""bool S1.TryGetValue(out int)"" IL_0024: brfalse.s IL_0033 IL_0026: ldarg.0 IL_0027: ldfld ""int System.ValueTuple<S1, int>.Item2"" IL_002c: ldc.i4.1 IL_002d: bne.un.s IL_0033 IL_002f: ldc.i4.1 IL_0030: stloc.2 IL_0031: br.s IL_0035 IL_0033: ldc.i4.0 IL_0034: stloc.2 IL_0035: ldloc.2 IL_0036: ret } "); } [Fact] public void NonBoxingUnionMatching_31_TryGetValue() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } public object Value { get { System.Console.Write(""get_Value ""); return _value; } } public bool HasValue { get { System.Console.Write(""HasValue ""); return _value != null; } } public bool TryGetValue(out int x) { System.Console.Write(""TryGetValue ""); if (_value is int v) { x = v; return true; } x = 0; return false; } static void Main() { System.Console.Write(Test1((new S1(1), 1))); System.Console.Write(""; ""); System.Console.Write(Test1((new S1(), 2))); System.Console.Write(""; ""); System.Console.Write(Test1((new S1(), 3))); System.Console.Write(""; ""); System.Console.Write(Test1((new S1(""a""), 1))); } static bool Test1((S1, int) u) { return u is (int, 1) or (null, 2); } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); var verifier = CompileAndVerify(comp, expectedOutput: "TryGetValue True; TryGetValue HasValue True; TryGetValue HasValue False; TryGetValue HasValue False").VerifyDiagnostics(); verifier.VerifyIL("S1.Test1", @" { // Code size 55 (0x37) .maxstack 2 .locals init (S1 V_0, int V_1, bool V_2) IL_0000: ldarg.0 IL_0001: ldfld ""S1 System.ValueTuple<S1, int>.Item1"" IL_0006: stloc.0 IL_0007: ldloca.s V_0 IL_0009: ldloca.s V_1 IL_000b: call ""bool S1.TryGetValue(out int)"" IL_0010: brfalse.s IL_001d IL_0012: ldarg.0 IL_0013: ldfld ""int System.ValueTuple<S1, int>.Item2"" IL_0018: ldc.i4.1 IL_0019: beq.s IL_002f IL_001b: br.s IL_0033 IL_001d: ldloca.s V_0 IL_001f: call ""bool S1.HasValue.get"" IL_0024: brtrue.s IL_0033 IL_0026: ldarg.0 IL_0027: ldfld ""int System.ValueTuple<S1, int>.Item2"" IL_002c: ldc.i4.2 IL_002d: bne.un.s IL_0033 IL_002f: ldc.i4.1 IL_0030: stloc.2 IL_0031: br.s IL_0035 IL_0033: ldc.i4.0 IL_0034: stloc.2 IL_0035: ldloc.2 IL_0036: ret } "); } [Fact] public void NonBoxingUnionMatching_32_TryGetValue() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } public object Value { get { System.Console.Write(""get_Value ""); return _value; } } public bool HasValue { get { System.Console.Write(""HasValue ""); return _value != null; } } public bool TryGetValue(out int x) { System.Console.Write(""TryGetValue ""); if (_value is int v) { x = v; return true; } x = 0; return false; } static void Main() { System.Console.Write(Test1((new S1(1), 1))); System.Console.Write(""; ""); System.Console.Write(Test1((new S1(1), -1))); System.Console.Write(""; ""); System.Console.Write(Test1((new S1(), 2))); System.Console.Write(""; ""); System.Console.Write(Test1((new S1(), 3))); System.Console.Write(""; ""); System.Console.Write(Test1((new S1(""a""), 1))); System.Console.Write(""; ""); System.Console.Write(Test1((new S1(""a""), 2))); } static bool Test1((S1, int) u) { return u is (not null, 2) or (int, 1); } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); var verifier = CompileAndVerify(comp, expectedOutput: "HasValue TryGetValue True; HasValue TryGetValue False; HasValue False; HasValue False; HasValue TryGetValue False; HasValue True").VerifyDiagnostics(); verifier.VerifyIL("S1.Test1", @" { // Code size 50 (0x32) .maxstack 2 .locals init (S1 V_0, int V_1, int V_2, bool V_3) IL_0000: ldarg.0 IL_0001: ldfld ""S1 System.ValueTuple<S1, int>.Item1"" IL_0006: stloc.0 IL_0007: ldloca.s V_0 IL_0009: call ""bool S1.HasValue.get"" IL_000e: brfalse.s IL_002e IL_0010: ldarg.0 IL_0011: ldfld ""int System.ValueTuple<S1, int>.Item2"" IL_0016: stloc.1 IL_0017: ldloc.1 IL_0018: ldc.i4.2 IL_0019: beq.s IL_002a IL_001b: ldloca.s V_0 IL_001d: ldloca.s V_2 IL_001f: call ""bool S1.TryGetValue(out int)"" IL_0024: brfalse.s IL_002e IL_0026: ldloc.1 IL_0027: ldc.i4.1 IL_0028: bne.un.s IL_002e IL_002a: ldc.i4.1 IL_002b: stloc.3 IL_002c: br.s IL_0030 IL_002e: ldc.i4.0 IL_002f: stloc.3 IL_0030: ldloc.3 IL_0031: ret } "); } [Fact] public void NonBoxingUnionMatching_33_TryGetValue() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } public object Value { get { System.Console.Write(""get_Value ""); return _value; } } public bool HasValue { get { System.Console.Write(""HasValue ""); return _value != null; } } public bool TryGetValue(out int x) { System.Console.Write(""TryGetValue ""); if (_value is int v) { x = v; return true; } x = 0; return false; } static void Main() { System.Console.Write(Test1((new S1(1), 1))); System.Console.Write(""; ""); System.Console.Write(Test1((new S1(1), -1))); System.Console.Write(""; ""); System.Console.Write(Test1((new S1(), 2))); System.Console.Write(""; ""); System.Console.Write(Test1((new S1(), 3))); System.Console.Write(""; ""); System.Console.Write(Test1((new S1(""a""), 1))); System.Console.Write(""; ""); System.Console.Write(Test1((new S1(""a""), 2))); } static bool Test1((S1, int) u) { return u is (int, 1) or (not null, 2); } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); var verifier = CompileAndVerify(comp, expectedOutput: "TryGetValue True; TryGetValue False; TryGetValue HasValue False; TryGetValue HasValue False; TryGetValue HasValue False; TryGetValue HasValue True").VerifyDiagnostics(); verifier.VerifyIL("S1.Test1", @" { // Code size 59 (0x3b) .maxstack 2 .locals init (S1 V_0, int V_1, int V_2, bool V_3) IL_0000: ldarg.0 IL_0001: ldfld ""S1 System.ValueTuple<S1, int>.Item1"" IL_0006: stloc.0 IL_0007: ldloca.s V_0 IL_0009: ldloca.s V_1 IL_000b: call ""bool S1.TryGetValue(out int)"" IL_0010: brfalse.s IL_001f IL_0012: ldarg.0 IL_0013: ldfld ""int System.ValueTuple<S1, int>.Item2"" IL_0018: stloc.2 IL_0019: ldloc.2 IL_001a: ldc.i4.1 IL_001b: beq.s IL_0033 IL_001d: br.s IL_002f IL_001f: ldloca.s V_0 IL_0021: call ""bool S1.HasValue.get"" IL_0026: brfalse.s IL_0037 IL_0028: ldarg.0 IL_0029: ldfld ""int System.ValueTuple<S1, int>.Item2"" IL_002e: stloc.2 IL_002f: ldloc.2 IL_0030: ldc.i4.2 IL_0031: bne.un.s IL_0037 IL_0033: ldc.i4.1 IL_0034: stloc.3 IL_0035: br.s IL_0039 IL_0037: ldc.i4.0 IL_0038: stloc.3 IL_0039: ldloc.3 IL_003a: ret } "); } [Fact] public void NonBoxingUnionMatching_34_TryGetValue() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } public object Value { get { System.Console.Write(""get_Value ""); return _value; } } public bool HasValue { get { System.Console.Write(""HasValue ""); return _value != null; } } public bool TryGetValue(out int x) { System.Console.Write(""TryGetValue ""); if (_value is int v) { x = v; return true; } x = 0; return false; } static void Main() { System.Console.Write(Test1((new S1(1), 1))); System.Console.Write(""; ""); System.Console.Write(Test1((new S1(), 2))); System.Console.Write(""; ""); System.Console.Write(Test1((new S1(), 3))); System.Console.Write(""; ""); System.Console.Write(Test1((new S1(), 1))); System.Console.Write(""; ""); System.Console.Write(Test1((new S1(""a""), 1))); System.Console.Write(""; ""); System.Console.Write(Test1((new S1(""a""), 2))); } static bool Test1((S1, int) u) { return u is (null, 2) or (not int, 1); } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); var verifier = CompileAndVerify(comp, expectedOutput: "HasValue TryGetValue False; HasValue True; HasValue False; HasValue True; HasValue TryGetValue True; HasValue TryGetValue False").VerifyDiagnostics(); verifier.VerifyIL("S1.Test1", @" { // Code size 59 (0x3b) .maxstack 2 .locals init (S1 V_0, int V_1, int V_2, bool V_3) IL_0000: ldarg.0 IL_0001: ldfld ""S1 System.ValueTuple<S1, int>.Item1"" IL_0006: stloc.0 IL_0007: ldloca.s V_0 IL_0009: call ""bool S1.HasValue.get"" IL_000e: brtrue.s IL_001d IL_0010: ldarg.0 IL_0011: ldfld ""int System.ValueTuple<S1, int>.Item2"" IL_0016: stloc.1 IL_0017: ldloc.1 IL_0018: ldc.i4.2 IL_0019: beq.s IL_0033 IL_001b: br.s IL_002f IL_001d: ldloca.s V_0 IL_001f: ldloca.s V_2 IL_0021: call ""bool S1.TryGetValue(out int)"" IL_0026: brtrue.s IL_0037 IL_0028: ldarg.0 IL_0029: ldfld ""int System.ValueTuple<S1, int>.Item2"" IL_002e: stloc.1 IL_002f: ldloc.1 IL_0030: ldc.i4.1 IL_0031: bne.un.s IL_0037 IL_0033: ldc.i4.1 IL_0034: stloc.3 IL_0035: br.s IL_0039 IL_0037: ldc.i4.0 IL_0038: stloc.3 IL_0039: ldloc.3 IL_003a: ret } "); } [Fact] public void NonBoxingUnionMatching_35_TryGetValue() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } public object Value { get { System.Console.Write(""get_Value ""); return _value; } } public bool HasValue { get { System.Console.Write(""HasValue ""); return _value != null; } } public bool TryGetValue(out int x) { System.Console.Write(""TryGetValue ""); if (_value is int v) { x = v; return true; } x = 0; return false; } static void Main() { System.Console.Write(Test1((new S1(1), 1))); System.Console.Write(""; ""); System.Console.Write(Test1((new S1(), 2))); System.Console.Write(""; ""); System.Console.Write(Test1((new S1(), 3))); System.Console.Write(""; ""); System.Console.Write(Test1((new S1(), 1))); System.Console.Write(""; ""); System.Console.Write(Test1((new S1(""a""), 1))); System.Console.Write(""; ""); System.Console.Write(Test1((new S1(""a""), 2))); } static bool Test1((S1, int) u) { return u is (not int, 1) or (null, 2); } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); var verifier = CompileAndVerify(comp, expectedOutput: "TryGetValue False; TryGetValue HasValue True; TryGetValue HasValue False; TryGetValue True; TryGetValue True; TryGetValue HasValue False").VerifyDiagnostics(); verifier.VerifyIL("S1.Test1", @" { // Code size 50 (0x32) .maxstack 2 .locals init (S1 V_0, int V_1, int V_2, bool V_3) IL_0000: ldarg.0 IL_0001: ldfld ""S1 System.ValueTuple<S1, int>.Item1"" IL_0006: stloc.0 IL_0007: ldloca.s V_0 IL_0009: ldloca.s V_1 IL_000b: call ""bool S1.TryGetValue(out int)"" IL_0010: brtrue.s IL_002e IL_0012: ldarg.0 IL_0013: ldfld ""int System.ValueTuple<S1, int>.Item2"" IL_0018: stloc.2 IL_0019: ldloc.2 IL_001a: ldc.i4.1 IL_001b: beq.s IL_002a IL_001d: ldloca.s V_0 IL_001f: call ""bool S1.HasValue.get"" IL_0024: brtrue.s IL_002e IL_0026: ldloc.2 IL_0027: ldc.i4.2 IL_0028: bne.un.s IL_002e IL_002a: ldc.i4.1 IL_002b: stloc.3 IL_002c: br.s IL_0030 IL_002e: ldc.i4.0 IL_002f: stloc.3 IL_0030: ldloc.3 IL_0031: ret } "); } [Fact] public void NonBoxingUnionMatching_36_HasValue() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } public object Value { get { System.Console.Write(""get_Value ""); return _value; } } public bool HasValue { get { System.Console.Write(""HasValue ""); return _value != null; } } static void Main() { System.Console.Write(Test1((new S1(1), 1))); System.Console.Write(""; ""); System.Console.Write(Test1((new S1(), 2))); System.Console.Write(""; ""); System.Console.Write(Test1((new S1(), 3))); System.Console.Write(""; ""); System.Console.Write(Test1((new S1(""a""), 1))); } static bool Test1((S1, int) u) { return u is (null, 2) or (int, 1); } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); var verifier = CompileAndVerify(comp, expectedOutput: "HasValue get_Value True; HasValue True; HasValue False; HasValue get_Value False").VerifyDiagnostics(); verifier.VerifyIL("S1.Test1", @" { // Code size 58 (0x3a) .maxstack 2 .locals init (S1 V_0, bool V_1) IL_0000: ldarg.0 IL_0001: ldfld ""S1 System.ValueTuple<S1, int>.Item1"" IL_0006: stloc.0 IL_0007: ldloca.s V_0 IL_0009: call ""bool S1.HasValue.get"" IL_000e: brtrue.s IL_001b IL_0010: ldarg.0 IL_0011: ldfld ""int System.ValueTuple<S1, int>.Item2"" IL_0016: ldc.i4.2 IL_0017: beq.s IL_0032 IL_0019: br.s IL_0036 IL_001b: ldloca.s V_0 IL_001d: call ""object S1.Value.get"" IL_0022: isinst ""int"" IL_0027: brfalse.s IL_0036 IL_0029: ldarg.0 IL_002a: ldfld ""int System.ValueTuple<S1, int>.Item2"" IL_002f: ldc.i4.1 IL_0030: bne.un.s IL_0036 IL_0032: ldc.i4.1 IL_0033: stloc.1 IL_0034: br.s IL_0038 IL_0036: ldc.i4.0 IL_0037: stloc.1 IL_0038: ldloc.1 IL_0039: ret } "); } [Fact] public void NonBoxingUnionMatching_37_HasValue() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } public object Value { get { System.Console.Write(""get_Value ""); return _value; } } public bool HasValue { get { System.Console.Write(""HasValue ""); return _value != null; } } static void Main() { System.Console.Write(Test1((new S1(1), 1))); System.Console.Write(""; ""); System.Console.Write(Test1((new S1(), 2))); System.Console.Write(""; ""); System.Console.Write(Test1((new S1(), 3))); System.Console.Write(""; ""); System.Console.Write(Test1((new S1(""a""), 1))); } static bool Test1((S1, int) u) { return u is (int, 1) or (null, 2); } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); var verifier = CompileAndVerify(comp, expectedOutput: "get_Value True; get_Value HasValue True; get_Value HasValue False; get_Value HasValue False").VerifyDiagnostics(); verifier.VerifyIL("S1.Test1", @" { // Code size 58 (0x3a) .maxstack 2 .locals init (S1 V_0, bool V_1) IL_0000: ldarg.0 IL_0001: ldfld ""S1 System.ValueTuple<S1, int>.Item1"" IL_0006: stloc.0 IL_0007: ldloca.s V_0 IL_0009: call ""object S1.Value.get"" IL_000e: isinst ""int"" IL_0013: brfalse.s IL_0020 IL_0015: ldarg.0 IL_0016: ldfld ""int System.ValueTuple<S1, int>.Item2"" IL_001b: ldc.i4.1 IL_001c: beq.s IL_0032 IL_001e: br.s IL_0036 IL_0020: ldloca.s V_0 IL_0022: call ""bool S1.HasValue.get"" IL_0027: brtrue.s IL_0036 IL_0029: ldarg.0 IL_002a: ldfld ""int System.ValueTuple<S1, int>.Item2"" IL_002f: ldc.i4.2 IL_0030: bne.un.s IL_0036 IL_0032: ldc.i4.1 IL_0033: stloc.1 IL_0034: br.s IL_0038 IL_0036: ldc.i4.0 IL_0037: stloc.1 IL_0038: ldloc.1 IL_0039: ret } "); } [Fact] public void NonBoxingUnionMatching_38_HasValue() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } public object Value { get { System.Console.Write(""get_Value ""); return _value; } } public bool HasValue { get { System.Console.Write(""HasValue ""); return _value != null; } } static void Main() { System.Console.Write(Test1((new S1(1), 1))); System.Console.Write(""; ""); System.Console.Write(Test1((new S1(1), -1))); System.Console.Write(""; ""); System.Console.Write(Test1((new S1(), 2))); System.Console.Write(""; ""); System.Console.Write(Test1((new S1(), 3))); System.Console.Write(""; ""); System.Console.Write(Test1((new S1(""a""), 1))); System.Console.Write(""; ""); System.Console.Write(Test1((new S1(""a""), 2))); } static bool Test1((S1, int) u) { return u is (not null, 2) or (int, 1); } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); var verifier = CompileAndVerify(comp, expectedOutput: "HasValue get_Value True; HasValue get_Value False; HasValue False; HasValue False; HasValue get_Value False; HasValue True").VerifyDiagnostics(); verifier.VerifyIL("S1.Test1", @" { // Code size 53 (0x35) .maxstack 2 .locals init (S1 V_0, int V_1, bool V_2) IL_0000: ldarg.0 IL_0001: ldfld ""S1 System.ValueTuple<S1, int>.Item1"" IL_0006: stloc.0 IL_0007: ldloca.s V_0 IL_0009: call ""bool S1.HasValue.get"" IL_000e: brfalse.s IL_0031 IL_0010: ldarg.0 IL_0011: ldfld ""int System.ValueTuple<S1, int>.Item2"" IL_0016: stloc.1 IL_0017: ldloc.1 IL_0018: ldc.i4.2 IL_0019: beq.s IL_002d IL_001b: ldloca.s V_0 IL_001d: call ""object S1.Value.get"" IL_0022: isinst ""int"" IL_0027: brfalse.s IL_0031 IL_0029: ldloc.1 IL_002a: ldc.i4.1 IL_002b: bne.un.s IL_0031 IL_002d: ldc.i4.1 IL_002e: stloc.2 IL_002f: br.s IL_0033 IL_0031: ldc.i4.0 IL_0032: stloc.2 IL_0033: ldloc.2 IL_0034: ret } "); } [Fact] public void NonBoxingUnionMatching_39_HasValue() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } public object Value { get { System.Console.Write(""get_Value ""); return _value; } } public bool HasValue { get { System.Console.Write(""HasValue ""); return _value != null; } } static void Main() { System.Console.Write(Test1((new S1(1), 1))); System.Console.Write(""; ""); System.Console.Write(Test1((new S1(1), -1))); System.Console.Write(""; ""); System.Console.Write(Test1((new S1(), 2))); System.Console.Write(""; ""); System.Console.Write(Test1((new S1(), 3))); System.Console.Write(""; ""); System.Console.Write(Test1((new S1(""a""), 1))); System.Console.Write(""; ""); System.Console.Write(Test1((new S1(""a""), 2))); } static bool Test1((S1, int) u) { return u is (int, 1) or (not null, 2); } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); var verifier = CompileAndVerify(comp, expectedOutput: "get_Value True; get_Value False; get_Value HasValue False; get_Value HasValue False; get_Value HasValue False; get_Value HasValue True").VerifyDiagnostics(); verifier.VerifyIL("S1.Test1", @" { // Code size 62 (0x3e) .maxstack 2 .locals init (S1 V_0, int V_1, bool V_2) IL_0000: ldarg.0 IL_0001: ldfld ""S1 System.ValueTuple<S1, int>.Item1"" IL_0006: stloc.0 IL_0007: ldloca.s V_0 IL_0009: call ""object S1.Value.get"" IL_000e: isinst ""int"" IL_0013: brfalse.s IL_0022 IL_0015: ldarg.0 IL_0016: ldfld ""int System.ValueTuple<S1, int>.Item2"" IL_001b: stloc.1 IL_001c: ldloc.1 IL_001d: ldc.i4.1 IL_001e: beq.s IL_0036 IL_0020: br.s IL_0032 IL_0022: ldloca.s V_0 IL_0024: call ""bool S1.HasValue.get"" IL_0029: brfalse.s IL_003a IL_002b: ldarg.0 IL_002c: ldfld ""int System.ValueTuple<S1, int>.Item2"" IL_0031: stloc.1 IL_0032: ldloc.1 IL_0033: ldc.i4.2 IL_0034: bne.un.s IL_003a IL_0036: ldc.i4.1 IL_0037: stloc.2 IL_0038: br.s IL_003c IL_003a: ldc.i4.0 IL_003b: stloc.2 IL_003c: ldloc.2 IL_003d: ret } "); } [Fact] public void NonBoxingUnionMatching_40_HasValue() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } public object Value { get { System.Console.Write(""get_Value ""); return _value; } } public bool HasValue { get { System.Console.Write(""HasValue ""); return _value != null; } } static void Main() { System.Console.Write(Test1((new S1(1), 1))); System.Console.Write(""; ""); System.Console.Write(Test1((new S1(), 2))); System.Console.Write(""; ""); System.Console.Write(Test1((new S1(), 3))); System.Console.Write(""; ""); System.Console.Write(Test1((new S1(), 1))); System.Console.Write(""; ""); System.Console.Write(Test1((new S1(""a""), 1))); System.Console.Write(""; ""); System.Console.Write(Test1((new S1(""a""), 2))); } static bool Test1((S1, int) u) { return u is (null, 2) or (not int, 1); } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); var verifier = CompileAndVerify(comp, expectedOutput: "HasValue get_Value False; HasValue True; HasValue False; HasValue True; HasValue get_Value True; HasValue get_Value False").VerifyDiagnostics(); verifier.VerifyIL("S1.Test1", @" { // Code size 62 (0x3e) .maxstack 2 .locals init (S1 V_0, int V_1, bool V_2) IL_0000: ldarg.0 IL_0001: ldfld ""S1 System.ValueTuple<S1, int>.Item1"" IL_0006: stloc.0 IL_0007: ldloca.s V_0 IL_0009: call ""bool S1.HasValue.get"" IL_000e: brtrue.s IL_001d IL_0010: ldarg.0 IL_0011: ldfld ""int System.ValueTuple<S1, int>.Item2"" IL_0016: stloc.1 IL_0017: ldloc.1 IL_0018: ldc.i4.2 IL_0019: beq.s IL_0036 IL_001b: br.s IL_0032 IL_001d: ldloca.s V_0 IL_001f: call ""object S1.Value.get"" IL_0024: isinst ""int"" IL_0029: brtrue.s IL_003a IL_002b: ldarg.0 IL_002c: ldfld ""int System.ValueTuple<S1, int>.Item2"" IL_0031: stloc.1 IL_0032: ldloc.1 IL_0033: ldc.i4.1 IL_0034: bne.un.s IL_003a IL_0036: ldc.i4.1 IL_0037: stloc.2 IL_0038: br.s IL_003c IL_003a: ldc.i4.0 IL_003b: stloc.2 IL_003c: ldloc.2 IL_003d: ret } "); } [Fact] public void NonBoxingUnionMatching_41_HasValue() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } public object Value { get { System.Console.Write(""get_Value ""); return _value; } } public bool HasValue { get { System.Console.Write(""HasValue ""); return _value != null; } } static void Main() { System.Console.Write(Test1((new S1(1), 1))); System.Console.Write(""; ""); System.Console.Write(Test1((new S1(), 2))); System.Console.Write(""; ""); System.Console.Write(Test1((new S1(), 3))); System.Console.Write(""; ""); System.Console.Write(Test1((new S1(), 1))); System.Console.Write(""; ""); System.Console.Write(Test1((new S1(""a""), 1))); System.Console.Write(""; ""); System.Console.Write(Test1((new S1(""a""), 2))); } static bool Test1((S1, int) u) { return u is (not int, 1) or (null, 2); } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); var verifier = CompileAndVerify(comp, expectedOutput: "get_Value False; get_Value HasValue True; get_Value HasValue False; get_Value True; get_Value True; get_Value HasValue False").VerifyDiagnostics(); verifier.VerifyIL("S1.Test1", @" { // Code size 53 (0x35) .maxstack 2 .locals init (S1 V_0, int V_1, bool V_2) IL_0000: ldarg.0 IL_0001: ldfld ""S1 System.ValueTuple<S1, int>.Item1"" IL_0006: stloc.0 IL_0007: ldloca.s V_0 IL_0009: call ""object S1.Value.get"" IL_000e: isinst ""int"" IL_0013: brtrue.s IL_0031 IL_0015: ldarg.0 IL_0016: ldfld ""int System.ValueTuple<S1, int>.Item2"" IL_001b: stloc.1 IL_001c: ldloc.1 IL_001d: ldc.i4.1 IL_001e: beq.s IL_002d IL_0020: ldloca.s V_0 IL_0022: call ""bool S1.HasValue.get"" IL_0027: brtrue.s IL_0031 IL_0029: ldloc.1 IL_002a: ldc.i4.2 IL_002b: bne.un.s IL_0031 IL_002d: ldc.i4.1 IL_002e: stloc.2 IL_002f: br.s IL_0033 IL_0031: ldc.i4.0 IL_0032: stloc.2 IL_0033: ldloc.2 IL_0034: ret } "); } [Fact] public void NonBoxingUnionMatching_42_TryGetValue() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } public object Value { get { System.Console.Write(""get_Value ""); return _value; } } public bool HasValue { get { System.Console.Write(""HasValue ""); return _value != null; } } public bool TryGetValue(out int x) { System.Console.Write(""TryGetValue(int) ""); if (_value is int v) { x = v; return true; } x = 0; return false; } public bool TryGetValue(out string x) { System.Console.Write(""TryGetValue(string) ""); x = _value as string; return x != null; } static void Main() { System.Console.Write(Test1((new S1(1), 1))); System.Console.Write(""; ""); System.Console.Write(Test1((new S1(1), 2))); System.Console.Write(""; ""); System.Console.Write(Test1((new S1(1), 3))); System.Console.Write(""; ""); System.Console.Write(Test1((new S1(), 1))); System.Console.Write(""; ""); System.Console.Write(Test1((new S1(), 2))); System.Console.Write(""; ""); System.Console.Write(Test1((new S1(), 3))); System.Console.Write(""; ""); System.Console.Write(Test1((new S1(""a""), 1))); System.Console.Write(""; ""); System.Console.Write(Test1((new S1(""a""), 2))); System.Console.Write(""; ""); System.Console.Write(Test1((new S1(""a""), 3))); } static bool Test1((S1, int) u) { return u is (string, 2) or (int, 1); } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); var verifier = CompileAndVerify(comp, expectedOutput: "TryGetValue(string) TryGetValue(int) True; TryGetValue(string) TryGetValue(int) False; TryGetValue(string) TryGetValue(int) False; TryGetValue(string) TryGetValue(int) False; TryGetValue(string) TryGetValue(int) False; TryGetValue(string) TryGetValue(int) False; TryGetValue(string) False; TryGetValue(string) True; TryGetValue(string) False").VerifyDiagnostics(); verifier.VerifyIL("S1.Test1", @" { // Code size 57 (0x39) .maxstack 2 .locals init (S1 V_0, string V_1, int V_2, bool V_3) IL_0000: ldarg.0 IL_0001: ldfld ""S1 System.ValueTuple<S1, int>.Item1"" IL_0006: stloc.0 IL_0007: ldloca.s V_0 IL_0009: ldloca.s V_1 IL_000b: call ""bool S1.TryGetValue(out string)"" IL_0010: brfalse.s IL_001d IL_0012: ldarg.0 IL_0013: ldfld ""int System.ValueTuple<S1, int>.Item2"" IL_0018: ldc.i4.2 IL_0019: beq.s IL_0031 IL_001b: br.s IL_0035 IL_001d: ldloca.s V_0 IL_001f: ldloca.s V_2 IL_0021: call ""bool S1.TryGetValue(out int)"" IL_0026: brfalse.s IL_0035 IL_0028: ldarg.0 IL_0029: ldfld ""int System.ValueTuple<S1, int>.Item2"" IL_002e: ldc.i4.1 IL_002f: bne.un.s IL_0035 IL_0031: ldc.i4.1 IL_0032: stloc.3 IL_0033: br.s IL_0037 IL_0035: ldc.i4.0 IL_0036: stloc.3 IL_0037: ldloc.3 IL_0038: ret } "); } [Fact] public void NonBoxingUnionMatching_43_TryGetValue() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } public object Value { get { System.Console.Write(""get_Value ""); return _value; } } public bool HasValue { get { System.Console.Write(""HasValue ""); return _value != null; } } public bool TryGetValue(out string x) { System.Console.Write(""TryGetValue(string) ""); x = _value as string; return x != null; } static void Main() { System.Console.Write(Test1((new S1(1), 1))); System.Console.Write(""; ""); System.Console.Write(Test1((new S1(1), 2))); System.Console.Write(""; ""); System.Console.Write(Test1((new S1(1), 3))); System.Console.Write(""; ""); System.Console.Write(Test1((new S1(), 1))); System.Console.Write(""; ""); System.Console.Write(Test1((new S1(), 2))); System.Console.Write(""; ""); System.Console.Write(Test1((new S1(), 3))); System.Console.Write(""; ""); System.Console.Write(Test1((new S1(""a""), 1))); System.Console.Write(""; ""); System.Console.Write(Test1((new S1(""a""), 2))); System.Console.Write(""; ""); System.Console.Write(Test1((new S1(""a""), 3))); } static bool Test1((S1, int) u) { return u is (string, 2) or (int, 1); } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); var verifier = CompileAndVerify(comp, expectedOutput: "TryGetValue(string) get_Value True; TryGetValue(string) get_Value False; TryGetValue(string) get_Value False; TryGetValue(string) get_Value False; TryGetValue(string) get_Value False; TryGetValue(string) get_Value False; TryGetValue(string) False; TryGetValue(string) True; TryGetValue(string) False").VerifyDiagnostics(); verifier.VerifyIL("S1.Test1", @" { // Code size 60 (0x3c) .maxstack 2 .locals init (S1 V_0, string V_1, bool V_2) IL_0000: ldarg.0 IL_0001: ldfld ""S1 System.ValueTuple<S1, int>.Item1"" IL_0006: stloc.0 IL_0007: ldloca.s V_0 IL_0009: ldloca.s V_1 IL_000b: call ""bool S1.TryGetValue(out string)"" IL_0010: brfalse.s IL_001d IL_0012: ldarg.0 IL_0013: ldfld ""int System.ValueTuple<S1, int>.Item2"" IL_0018: ldc.i4.2 IL_0019: beq.s IL_0034 IL_001b: br.s IL_0038 IL_001d: ldloca.s V_0 IL_001f: call ""object S1.Value.get"" IL_0024: isinst ""int"" IL_0029: brfalse.s IL_0038 IL_002b: ldarg.0 IL_002c: ldfld ""int System.ValueTuple<S1, int>.Item2"" IL_0031: ldc.i4.1 IL_0032: bne.un.s IL_0038 IL_0034: ldc.i4.1 IL_0035: stloc.2 IL_0036: br.s IL_003a IL_0038: ldc.i4.0 IL_0039: stloc.2 IL_003a: ldloc.2 IL_003b: ret } "); } [Fact] public void NonBoxingUnionMatching_44_TryGetValue() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } public object Value { get { System.Console.Write(""get_Value ""); return _value; } } public bool HasValue { get { System.Console.Write(""HasValue ""); return _value != null; } } public bool TryGetValue(out int x) { System.Console.Write(""TryGetValue(int) ""); if (_value is int v) { x = v; return true; } x = 0; return false; } static void Main() { System.Console.Write(Test1((new S1(1), 1))); System.Console.Write(""; ""); System.Console.Write(Test1((new S1(1), 2))); System.Console.Write(""; ""); System.Console.Write(Test1((new S1(1), 3))); System.Console.Write(""; ""); System.Console.Write(Test1((new S1(), 1))); System.Console.Write(""; ""); System.Console.Write(Test1((new S1(), 2))); System.Console.Write(""; ""); System.Console.Write(Test1((new S1(), 3))); System.Console.Write(""; ""); System.Console.Write(Test1((new S1(""a""), 1))); System.Console.Write(""; ""); System.Console.Write(Test1((new S1(""a""), 2))); System.Console.Write(""; ""); System.Console.Write(Test1((new S1(""a""), 3))); } static bool Test1((S1, int) u) { return u is (string, 2) or (int, 1); } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); var verifier = CompileAndVerify(comp, expectedOutput: "get_Value TryGetValue(int) True; get_Value TryGetValue(int) False; get_Value TryGetValue(int) False; get_Value TryGetValue(int) False; get_Value TryGetValue(int) False; get_Value TryGetValue(int) False; get_Value False; get_Value True; get_Value False").VerifyDiagnostics(); verifier.VerifyIL("S1.Test1", @" { // Code size 60 (0x3c) .maxstack 2 .locals init (S1 V_0, int V_1, bool V_2) IL_0000: ldarg.0 IL_0001: ldfld ""S1 System.ValueTuple<S1, int>.Item1"" IL_0006: stloc.0 IL_0007: ldloca.s V_0 IL_0009: call ""object S1.Value.get"" IL_000e: isinst ""string"" IL_0013: brfalse.s IL_0020 IL_0015: ldarg.0 IL_0016: ldfld ""int System.ValueTuple<S1, int>.Item2"" IL_001b: ldc.i4.2 IL_001c: beq.s IL_0034 IL_001e: br.s IL_0038 IL_0020: ldloca.s V_0 IL_0022: ldloca.s V_1 IL_0024: call ""bool S1.TryGetValue(out int)"" IL_0029: brfalse.s IL_0038 IL_002b: ldarg.0 IL_002c: ldfld ""int System.ValueTuple<S1, int>.Item2"" IL_0031: ldc.i4.1 IL_0032: bne.un.s IL_0038 IL_0034: ldc.i4.1 IL_0035: stloc.2 IL_0036: br.s IL_003a IL_0038: ldc.i4.0 IL_0039: stloc.2 IL_003a: ldloc.2 IL_003b: ret } "); } [Fact] public void NonBoxingUnionMatching_45_TryGetValue() { var src = @" interface I1; class C11; class C12; class C13 : C12, I1; class C14 : I1; class C15 : I1; [System.Runtime.CompilerServices.Union] struct S1 { private readonly object _value; public S1(I1 x) { _value = x; } public S1(C11 x) { _value = x; } public S1(C12 x) { _value = x; } public S1(C14 x) { _value = x; } public object Value { get { System.Console.Write(""get_Value ""); return _value; } } public bool HasValue { get { System.Console.Write(""HasValue ""); return _value != null; } } public bool TryGetValue(out I1 x) { System.Console.Write(""TryGetValue(I1) ""); x = _value as I1; return x != null; } public bool TryGetValue(out C12 x) { System.Console.Write(""TryGetValue(C12) ""); x = _value as C12; return x != null; } static void Main() { S1[] s = [new S1(), new S1(new C11()), new S1(new C12()), new S1((C12)new C13()), new S1(new C14()), new S1(new C15())]; int[] i = [1, 2, 3]; foreach (var s1 in s) { foreach (var j in i) { var t = Test1((s1, j)); System.Console.WriteLine(); System.Console.WriteLine(t); } } } static bool Test1((S1, int) u) { return u is (C12 and I1, 2) or (I1, 1); } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); VerifyDecisionDagDump<IsPatternExpressionSyntax>(comp, @"[0]: t1 = t0.Item1; [1] [1]: TryGetValue(C12): (Item1, ReturnItem) t2 = t1; [2] [2]: t2.ReturnItem == True ? [3] : [7] [3]: t3 = (C12)t2.Item1; [4] [4]: t3 is I1 ? [5] : [12] [5]: t4 = t0.Item2; [6] [6]: t4 == 2 ? [11] : [10] [7]: TryGetValue(I1): (Item1, ReturnItem) t5 = t1; [8] [8]: t5.ReturnItem == True ? [9] : [12] [9]: t4 = t0.Item2; [10] [10]: t4 == 1 ? [11] : [12] [11]: leaf <isPatternSuccess> `(C12 and I1, 2) or (I1, 1)` [12]: leaf <isPatternFailure> `u is (C12 and I1, 2) or (I1, 1)` ", forLowering: true); var verifier = CompileAndVerify( comp, expectedOutput: @" TryGetValue(C12) TryGetValue(I1) False TryGetValue(C12) TryGetValue(I1) False TryGetValue(C12) TryGetValue(I1) False TryGetValue(C12) TryGetValue(I1) False TryGetValue(C12) TryGetValue(I1) False TryGetValue(C12) TryGetValue(I1) False TryGetValue(C12) False TryGetValue(C12) False TryGetValue(C12) False TryGetValue(C12) True TryGetValue(C12) True TryGetValue(C12) False TryGetValue(C12) TryGetValue(I1) True TryGetValue(C12) TryGetValue(I1) False TryGetValue(C12) TryGetValue(I1) False TryGetValue(C12) TryGetValue(I1) True TryGetValue(C12) TryGetValue(I1) False TryGetValue(C12) TryGetValue(I1) False ").VerifyDiagnostics(); verifier.VerifyIL("S1.Test1", @" { // Code size 72 (0x48) .maxstack 2 .locals init (S1 V_0, C12 V_1, int V_2, I1 V_3, bool V_4) IL_0000: ldarg.0 IL_0001: ldfld ""S1 System.ValueTuple<S1, int>.Item1"" IL_0006: stloc.0 IL_0007: ldloca.s V_0 IL_0009: ldloca.s V_1 IL_000b: call ""bool S1.TryGetValue(out C12)"" IL_0010: brfalse.s IL_0027 IL_0012: ldloc.1 IL_0013: isinst ""I1"" IL_0018: brfalse.s IL_0042 IL_001a: ldarg.0 IL_001b: ldfld ""int System.ValueTuple<S1, int>.Item2"" IL_0020: stloc.2 IL_0021: ldloc.2 IL_0022: ldc.i4.2 IL_0023: beq.s IL_003d IL_0025: br.s IL_0039 IL_0027: ldloca.s V_0 IL_0029: ldloca.s V_3 IL_002b: call ""bool S1.TryGetValue(out I1)"" IL_0030: brfalse.s IL_0042 IL_0032: ldarg.0 IL_0033: ldfld ""int System.ValueTuple<S1, int>.Item2"" IL_0038: stloc.2 IL_0039: ldloc.2 IL_003a: ldc.i4.1 IL_003b: bne.un.s IL_0042 IL_003d: ldc.i4.1 IL_003e: stloc.s V_4 IL_0040: br.s IL_0045 IL_0042: ldc.i4.0 IL_0043: stloc.s V_4 IL_0045: ldloc.s V_4 IL_0047: ret } "); } [Fact] public void NonBoxingUnionMatching_46_TryGetValue() { var src = @" interface I1; class C11; class C12; class C13 : C12, I1; class C14 : I1; class C15 : I1; [System.Runtime.CompilerServices.Union] struct S1 { private readonly object _value; public S1(I1 x) { _value = x; } public S1(C11 x) { _value = x; } public S1(C12 x) { _value = x; } public S1(C14 x) { _value = x; } public object Value { get { System.Console.Write(""get_Value ""); return _value; } } public bool HasValue { get { System.Console.Write(""HasValue ""); return _value != null; } } public bool TryGetValue(out I1 x) { System.Console.Write(""TryGetValue(I1) ""); x = _value as I1; return x != null; } public bool TryGetValue(out C12 x) { System.Console.Write(""TryGetValue(C12) ""); x = _value as C12; return x != null; } static void Main() { S1[] s = [new S1(), new S1(new C11()), new S1(new C12()), new S1((C12)new C13()), new S1(new C14()), new S1(new C15())]; int[] i = [1, 2, 3]; foreach (var s1 in s) { foreach (var j in i) { var t = Test1((s1, j)); System.Console.WriteLine(); System.Console.WriteLine(t); } } } static bool Test1((S1, int) u) { return u is (I1, 1) or (C12 and I1, 2); } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); VerifyDecisionDagDump<IsPatternExpressionSyntax>(comp, @"[0]: t1 = t0.Item1; [1] [1]: TryGetValue(I1): (Item1, ReturnItem) t2 = t1; [2] [2]: t2.ReturnItem == True ? [3] : [9] [3]: t3 = t0.Item2; [4] [4]: t3 == 1 ? [8] : [5] [5]: TryGetValue(C12): (Item1, ReturnItem) t4 = t1; [6] [6]: t4.ReturnItem == True ? [7] : [9] [7]: t3 == 2 ? [8] : [9] [8]: leaf <isPatternSuccess> `(I1, 1) or (C12 and I1, 2)` [9]: leaf <isPatternFailure> `u is (I1, 1) or (C12 and I1, 2)` ", forLowering: true); var verifier = CompileAndVerify( comp, expectedOutput: @" TryGetValue(I1) False TryGetValue(I1) False TryGetValue(I1) False TryGetValue(I1) False TryGetValue(I1) False TryGetValue(I1) False TryGetValue(I1) False TryGetValue(I1) False TryGetValue(I1) False TryGetValue(I1) True TryGetValue(I1) TryGetValue(C12) True TryGetValue(I1) TryGetValue(C12) False TryGetValue(I1) True TryGetValue(I1) TryGetValue(C12) False TryGetValue(I1) TryGetValue(C12) False TryGetValue(I1) True TryGetValue(I1) TryGetValue(C12) False TryGetValue(I1) TryGetValue(C12) False ").VerifyDiagnostics(); verifier.VerifyIL("S1.Test1", @" { // Code size 55 (0x37) .maxstack 2 .locals init (S1 V_0, I1 V_1, int V_2, C12 V_3, bool V_4) IL_0000: ldarg.0 IL_0001: ldfld ""S1 System.ValueTuple<S1, int>.Item1"" IL_0006: stloc.0 IL_0007: ldloca.s V_0 IL_0009: ldloca.s V_1 IL_000b: call ""bool S1.TryGetValue(out I1)"" IL_0010: brfalse.s IL_0031 IL_0012: ldarg.0 IL_0013: ldfld ""int System.ValueTuple<S1, int>.Item2"" IL_0018: stloc.2 IL_0019: ldloc.2 IL_001a: ldc.i4.1 IL_001b: beq.s IL_002c IL_001d: ldloca.s V_0 IL_001f: ldloca.s V_3 IL_0021: call ""bool S1.TryGetValue(out C12)"" IL_0026: brfalse.s IL_0031 IL_0028: ldloc.2 IL_0029: ldc.i4.2 IL_002a: bne.un.s IL_0031 IL_002c: ldc.i4.1 IL_002d: stloc.s V_4 IL_002f: br.s IL_0034 IL_0031: ldc.i4.0 IL_0032: stloc.s V_4 IL_0034: ldloc.s V_4 IL_0036: ret } "); } [Fact] public void NonBoxingUnionMatching_47_TryGetValue() { var src = @" interface I1; class C11; class C12; class C13 : C12, I1; class C14 : I1; class C15 : I1; [System.Runtime.CompilerServices.Union] struct S1 { private readonly object _value; public S1(I1 x) { _value = x; } public S1(C11 x) { _value = x; } public S1(C12 x) { _value = x; } public S1(C14 x) { _value = x; } public object Value { get { System.Console.Write(""get_Value ""); return _value; } } public bool HasValue { get { System.Console.Write(""HasValue ""); return _value != null; } } public bool TryGetValue(out I1 x) { System.Console.Write(""TryGetValue(I1) ""); x = _value as I1; return x != null; } static void Main() { S1[] s = [new S1(), new S1(new C11()), new S1(new C12()), new S1((C12)new C13()), new S1(new C14()), new S1(new C15())]; int[] i = [1, 2, 3]; foreach (var s1 in s) { foreach (var j in i) { var t = Test1((s1, j)); System.Console.WriteLine(); System.Console.WriteLine(t); } } } static bool Test1((S1, int) u) { return u is (C12 and I1, 2) or (I1, 1); } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); VerifyDecisionDagDump<IsPatternExpressionSyntax>(comp, @"[0]: t1 = t0.Item1; [1] [1]: t2 = t1.Value; [2] [2]: t2 is C12 ? [3] : [7] [3]: t3 = (C12)t2; [4] [4]: t3 is I1 ? [5] : [12] [5]: t4 = t0.Item2; [6] [6]: t4 == 2 ? [11] : [10] [7]: TryGetValue(I1): (Item1, ReturnItem) t5 = t1; [8] [8]: t5.ReturnItem == True ? [9] : [12] [9]: t4 = t0.Item2; [10] [10]: t4 == 1 ? [11] : [12] [11]: leaf <isPatternSuccess> `(C12 and I1, 2) or (I1, 1)` [12]: leaf <isPatternFailure> `u is (C12 and I1, 2) or (I1, 1)` ", forLowering: true); var verifier = CompileAndVerify( comp, expectedOutput: @" get_Value TryGetValue(I1) False get_Value TryGetValue(I1) False get_Value TryGetValue(I1) False get_Value TryGetValue(I1) False get_Value TryGetValue(I1) False get_Value TryGetValue(I1) False get_Value False get_Value False get_Value False get_Value True get_Value True get_Value False get_Value TryGetValue(I1) True get_Value TryGetValue(I1) False get_Value TryGetValue(I1) False get_Value TryGetValue(I1) True get_Value TryGetValue(I1) False get_Value TryGetValue(I1) False ").VerifyDiagnostics(); verifier.VerifyIL("S1.Test1", @" { // Code size 77 (0x4d) .maxstack 2 .locals init (S1 V_0, C12 V_1, int V_2, I1 V_3, bool V_4) IL_0000: ldarg.0 IL_0001: ldfld ""S1 System.ValueTuple<S1, int>.Item1"" IL_0006: stloc.0 IL_0007: ldloca.s V_0 IL_0009: call ""object S1.Value.get"" IL_000e: isinst ""C12"" IL_0013: stloc.1 IL_0014: ldloc.1 IL_0015: brfalse.s IL_002c IL_0017: ldloc.1 IL_0018: isinst ""I1"" IL_001d: brfalse.s IL_0047 IL_001f: ldarg.0 IL_0020: ldfld ""int System.ValueTuple<S1, int>.Item2"" IL_0025: stloc.2 IL_0026: ldloc.2 IL_0027: ldc.i4.2 IL_0028: beq.s IL_0042 IL_002a: br.s IL_003e IL_002c: ldloca.s V_0 IL_002e: ldloca.s V_3 IL_0030: call ""bool S1.TryGetValue(out I1)"" IL_0035: brfalse.s IL_0047 IL_0037: ldarg.0 IL_0038: ldfld ""int System.ValueTuple<S1, int>.Item2"" IL_003d: stloc.2 IL_003e: ldloc.2 IL_003f: ldc.i4.1 IL_0040: bne.un.s IL_0047 IL_0042: ldc.i4.1 IL_0043: stloc.s V_4 IL_0045: br.s IL_004a IL_0047: ldc.i4.0 IL_0048: stloc.s V_4 IL_004a: ldloc.s V_4 IL_004c: ret } "); } [Fact] public void NonBoxingUnionMatching_48_TryGetValue() { var src = @" interface I1; class C11; class C12; class C13 : C12, I1; class C14 : I1; class C15 : I1; [System.Runtime.CompilerServices.Union] struct S1 { private readonly object _value; public S1(I1 x) { _value = x; } public S1(C11 x) { _value = x; } public S1(C12 x) { _value = x; } public S1(C14 x) { _value = x; } public object Value { get { System.Console.Write(""get_Value ""); return _value; } } public bool HasValue { get { System.Console.Write(""HasValue ""); return _value != null; } } public bool TryGetValue(out I1 x) { System.Console.Write(""TryGetValue(I1) ""); x = _value as I1; return x != null; } static void Main() { S1[] s = [new S1(), new S1(new C11()), new S1(new C12()), new S1((C12)new C13()), new S1(new C14()), new S1(new C15())]; int[] i = [1, 2, 3]; foreach (var s1 in s) { foreach (var j in i) { var t = Test1((s1, j)); System.Console.WriteLine(); System.Console.WriteLine(t); } } } static bool Test1((S1, int) u) { return u is (I1, 1) or (C12 and I1, 2); } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); var verifier = CompileAndVerify( comp, expectedOutput: @" TryGetValue(I1) False TryGetValue(I1) False TryGetValue(I1) False TryGetValue(I1) False TryGetValue(I1) False TryGetValue(I1) False TryGetValue(I1) False TryGetValue(I1) False TryGetValue(I1) False TryGetValue(I1) True TryGetValue(I1) get_Value True TryGetValue(I1) get_Value False TryGetValue(I1) True TryGetValue(I1) get_Value False TryGetValue(I1) get_Value False TryGetValue(I1) True TryGetValue(I1) get_Value False TryGetValue(I1) get_Value False ").VerifyDiagnostics(); verifier.VerifyIL("S1.Test1", @" { // Code size 55 (0x37) .maxstack 2 .locals init (S1 V_0, I1 V_1, int V_2, bool V_3) IL_0000: ldarg.0 IL_0001: ldfld ""S1 System.ValueTuple<S1, int>.Item1"" IL_0006: stloc.0 IL_0007: ldloca.s V_0 IL_0009: ldloca.s V_1 IL_000b: call ""bool S1.TryGetValue(out I1)"" IL_0010: brfalse.s IL_0033 IL_0012: ldarg.0 IL_0013: ldfld ""int System.ValueTuple<S1, int>.Item2"" IL_0018: stloc.2 IL_0019: ldloc.2 IL_001a: ldc.i4.1 IL_001b: beq.s IL_002f IL_001d: ldloca.s V_0 IL_001f: call ""object S1.Value.get"" IL_0024: isinst ""C12"" IL_0029: brfalse.s IL_0033 IL_002b: ldloc.2 IL_002c: ldc.i4.2 IL_002d: bne.un.s IL_0033 IL_002f: ldc.i4.1 IL_0030: stloc.3 IL_0031: br.s IL_0035 IL_0033: ldc.i4.0 IL_0034: stloc.3 IL_0035: ldloc.3 IL_0036: ret } "); } [Fact] public void NonBoxingUnionMatching_49_TryGetValue() { var src = @" interface I1; class C11; class C12; class C13 : C12, I1; class C14 : I1; class C15 : I1; [System.Runtime.CompilerServices.Union] struct S1 { private readonly object _value; public S1(I1 x) { _value = x; } public S1(C11 x) { _value = x; } public S1(C12 x) { _value = x; } public S1(C14 x) { _value = x; } public object Value { get { System.Console.Write(""get_Value ""); return _value; } } public bool HasValue { get { System.Console.Write(""HasValue ""); return _value != null; } } public bool TryGetValue(out C12 x) { System.Console.Write(""TryGetValue(C12) ""); x = _value as C12; return x != null; } static void Main() { S1[] s = [new S1(), new S1(new C11()), new S1(new C12()), new S1((C12)new C13()), new S1(new C14()), new S1(new C15())]; int[] i = [1, 2, 3]; foreach (var s1 in s) { foreach (var j in i) { var t = Test1((s1, j)); System.Console.WriteLine(); System.Console.WriteLine(t); } } } static bool Test1((S1, int) u) { return u is (C12 and I1, 2) or (I1, 1); } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); VerifyDecisionDagDump<IsPatternExpressionSyntax>(comp, @"[0]: t1 = t0.Item1; [1] [1]: TryGetValue(C12): (Item1, ReturnItem) t2 = t1; [2] [2]: t2.ReturnItem == True ? [3] : [7] [3]: t3 = (C12)t2.Item1; [4] [4]: t3 is I1 ? [5] : [12] [5]: t4 = t0.Item2; [6] [6]: t4 == 2 ? [11] : [10] [7]: t5 = t1.Value; [8] [8]: t5 is I1 ? [9] : [12] [9]: t4 = t0.Item2; [10] [10]: t4 == 1 ? [11] : [12] [11]: leaf <isPatternSuccess> `(C12 and I1, 2) or (I1, 1)` [12]: leaf <isPatternFailure> `u is (C12 and I1, 2) or (I1, 1)` ", forLowering: true); var verifier = CompileAndVerify( comp, expectedOutput: @" TryGetValue(C12) get_Value False TryGetValue(C12) get_Value False TryGetValue(C12) get_Value False TryGetValue(C12) get_Value False TryGetValue(C12) get_Value False TryGetValue(C12) get_Value False TryGetValue(C12) False TryGetValue(C12) False TryGetValue(C12) False TryGetValue(C12) True TryGetValue(C12) True TryGetValue(C12) False TryGetValue(C12) get_Value True TryGetValue(C12) get_Value False TryGetValue(C12) get_Value False TryGetValue(C12) get_Value True TryGetValue(C12) get_Value False TryGetValue(C12) get_Value False ").VerifyDiagnostics(); verifier.VerifyIL("S1.Test1", @" { // Code size 72 (0x48) .maxstack 2 .locals init (S1 V_0, C12 V_1, int V_2, bool V_3) IL_0000: ldarg.0 IL_0001: ldfld ""S1 System.ValueTuple<S1, int>.Item1"" IL_0006: stloc.0 IL_0007: ldloca.s V_0 IL_0009: ldloca.s V_1 IL_000b: call ""bool S1.TryGetValue(out C12)"" IL_0010: brfalse.s IL_0027 IL_0012: ldloc.1 IL_0013: isinst ""I1"" IL_0018: brfalse.s IL_0044 IL_001a: ldarg.0 IL_001b: ldfld ""int System.ValueTuple<S1, int>.Item2"" IL_0020: stloc.2 IL_0021: ldloc.2 IL_0022: ldc.i4.2 IL_0023: beq.s IL_0040 IL_0025: br.s IL_003c IL_0027: ldloca.s V_0 IL_0029: call ""object S1.Value.get"" IL_002e: isinst ""I1"" IL_0033: brfalse.s IL_0044 IL_0035: ldarg.0 IL_0036: ldfld ""int System.ValueTuple<S1, int>.Item2"" IL_003b: stloc.2 IL_003c: ldloc.2 IL_003d: ldc.i4.1 IL_003e: bne.un.s IL_0044 IL_0040: ldc.i4.1 IL_0041: stloc.3 IL_0042: br.s IL_0046 IL_0044: ldc.i4.0 IL_0045: stloc.3 IL_0046: ldloc.3 IL_0047: ret } "); } [Fact] public void NonBoxingUnionMatching_50_TryGetValue() { var src = @" interface I1; class C11; class C12; class C13 : C12, I1; class C14 : I1; class C15 : I1; [System.Runtime.CompilerServices.Union] struct S1 { private readonly object _value; public S1(I1 x) { _value = x; } public S1(C11 x) { _value = x; } public S1(C12 x) { _value = x; } public S1(C14 x) { _value = x; } public object Value { get { System.Console.Write(""get_Value ""); return _value; } } public bool HasValue { get { System.Console.Write(""HasValue ""); return _value != null; } } public bool TryGetValue(out C12 x) { System.Console.Write(""TryGetValue(C12) ""); x = _value as C12; return x != null; } static void Main() { S1[] s = [new S1(), new S1(new C11()), new S1(new C12()), new S1((C12)new C13()), new S1(new C14()), new S1(new C15())]; int[] i = [1, 2, 3]; foreach (var s1 in s) { foreach (var j in i) { var t = Test1((s1, j)); System.Console.WriteLine(); System.Console.WriteLine(t); } } } static bool Test1((S1, int) u) { return u is (I1, 1) or (C12 and I1, 2); } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); VerifyDecisionDagDump<IsPatternExpressionSyntax>(comp, @"[0]: t1 = t0.Item1; [1] [1]: t2 = t1.Value; [2] [2]: t2 is I1 ? [3] : [9] [3]: t3 = t0.Item2; [4] [4]: t3 == 1 ? [8] : [5] [5]: TryGetValue(C12): (Item1, ReturnItem) t4 = t1; [6] [6]: t4.ReturnItem == True ? [7] : [9] [7]: t3 == 2 ? [8] : [9] [8]: leaf <isPatternSuccess> `(I1, 1) or (C12 and I1, 2)` [9]: leaf <isPatternFailure> `u is (I1, 1) or (C12 and I1, 2)` ", forLowering: true); var verifier = CompileAndVerify( comp, expectedOutput: @" get_Value False get_Value False get_Value False get_Value False get_Value False get_Value False get_Value False get_Value False get_Value False get_Value True get_Value TryGetValue(C12) True get_Value TryGetValue(C12) False get_Value True get_Value TryGetValue(C12) False get_Value TryGetValue(C12) False get_Value True get_Value TryGetValue(C12) False get_Value TryGetValue(C12) False ").VerifyDiagnostics(); verifier.VerifyIL("S1.Test1", @" { // Code size 55 (0x37) .maxstack 2 .locals init (S1 V_0, int V_1, C12 V_2, bool V_3) IL_0000: ldarg.0 IL_0001: ldfld ""S1 System.ValueTuple<S1, int>.Item1"" IL_0006: stloc.0 IL_0007: ldloca.s V_0 IL_0009: call ""object S1.Value.get"" IL_000e: isinst ""I1"" IL_0013: brfalse.s IL_0033 IL_0015: ldarg.0 IL_0016: ldfld ""int System.ValueTuple<S1, int>.Item2"" IL_001b: stloc.1 IL_001c: ldloc.1 IL_001d: ldc.i4.1 IL_001e: beq.s IL_002f IL_0020: ldloca.s V_0 IL_0022: ldloca.s V_2 IL_0024: call ""bool S1.TryGetValue(out C12)"" IL_0029: brfalse.s IL_0033 IL_002b: ldloc.1 IL_002c: ldc.i4.2 IL_002d: bne.un.s IL_0033 IL_002f: ldc.i4.1 IL_0030: stloc.3 IL_0031: br.s IL_0035 IL_0033: ldc.i4.0 IL_0034: stloc.3 IL_0035: ldloc.3 IL_0036: ret } "); } [Fact] public void NonBoxingUnionMatching_51_TryGetValue() { var src = @" interface I1 { int F {get;} } class C11; class C12; class C13(int f) : C12, I1 { public int F => f; } class C14(int f) : I1 { public int F => f; } class C15(int f) : I1 { public int F => f; } [System.Runtime.CompilerServices.Union] struct S1 { private readonly object _value; public S1(I1 x) { _value = x; } public S1(C11 x) { _value = x; } public S1(C12 x) { _value = x; } public S1(C14 x) { _value = x; } public object Value { get { System.Console.Write(""get_Value ""); return _value; } } public bool HasValue { get { System.Console.Write(""HasValue ""); return _value != null; } } public bool TryGetValue(out I1 x) { System.Console.Write(""TryGetValue(I1) ""); x = _value as I1; return x != null; } public bool TryGetValue(out C12 x) { System.Console.Write(""TryGetValue(C12) ""); x = _value as C12; return x != null; } static void Main() { S1[] s = [new S1(), new S1(new C11()), new S1(new C12()), new S1((C12)new C13(1)), new S1(new C14(1)), new S1(new C15(1)), new S1((C12)new C13(2)), new S1(new C14(2)), new S1(new C15(2))]; int[] i = [1, 2, 3]; foreach (var s1 in s) { foreach (var j in i) { var t = Test1((s1, j)); System.Console.WriteLine(); System.Console.WriteLine(t); } } } static bool Test1((S1, int) u) { return u is (C12 and I1 and { F: 1 }, 2) or (I1 and { F: 1 }, 1); } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); VerifyDecisionDagDump<IsPatternExpressionSyntax>(comp, @"[0]: t1 = t0.Item1; [1] [1]: TryGetValue(C12): (Item1, ReturnItem) t2 = t1; [2] [2]: t2.ReturnItem == True ? [3] : [10] [3]: t3 = (C12)t2.Item1; [4] [4]: t3 is I1 ? [5] : [18] [5]: t4 = (I1)t3; [6] [6]: t5 = t4.F; [7] [7]: t5 == 1 ? [8] : [18] [8]: t6 = t0.Item2; [9] [9]: t6 == 2 ? [17] : [16] [10]: TryGetValue(I1): (Item1, ReturnItem) t7 = t1; [11] [11]: t7.ReturnItem == True ? [12] : [18] [12]: t4 = (I1)t7.Item1; [13] [13]: t5 = t4.F; [14] [14]: t5 == 1 ? [15] : [18] [15]: t6 = t0.Item2; [16] [16]: t6 == 1 ? [17] : [18] [17]: leaf <isPatternSuccess> `(C12 and I1 and { F: 1 }, 2) or (I1 and { F: 1 }, 1)` [18]: leaf <isPatternFailure> `u is (C12 and I1 and { F: 1 }, 2) or (I1 and { F: 1 }, 1)` ", forLowering: true); var verifier = CompileAndVerify( comp, expectedOutput: @" TryGetValue(C12) TryGetValue(I1) False TryGetValue(C12) TryGetValue(I1) False TryGetValue(C12) TryGetValue(I1) False TryGetValue(C12) TryGetValue(I1) False TryGetValue(C12) TryGetValue(I1) False TryGetValue(C12) TryGetValue(I1) False TryGetValue(C12) False TryGetValue(C12) False TryGetValue(C12) False TryGetValue(C12) True TryGetValue(C12) True TryGetValue(C12) False TryGetValue(C12) TryGetValue(I1) True TryGetValue(C12) TryGetValue(I1) False TryGetValue(C12) TryGetValue(I1) False TryGetValue(C12) TryGetValue(I1) True TryGetValue(C12) TryGetValue(I1) False TryGetValue(C12) TryGetValue(I1) False TryGetValue(C12) False TryGetValue(C12) False TryGetValue(C12) False TryGetValue(C12) TryGetValue(I1) False TryGetValue(C12) TryGetValue(I1) False TryGetValue(C12) TryGetValue(I1) False TryGetValue(C12) TryGetValue(I1) False TryGetValue(C12) TryGetValue(I1) False TryGetValue(C12) TryGetValue(I1) False ").VerifyDiagnostics(); verifier.VerifyIL("S1.Test1", @" { // Code size 95 (0x5f) .maxstack 2 .locals init (S1 V_0, C12 V_1, I1 V_2, int V_3, I1 V_4, bool V_5) IL_0000: ldarg.0 IL_0001: ldfld ""S1 System.ValueTuple<S1, int>.Item1"" IL_0006: stloc.0 IL_0007: ldloca.s V_0 IL_0009: ldloca.s V_1 IL_000b: call ""bool S1.TryGetValue(out C12)"" IL_0010: brfalse.s IL_0032 IL_0012: ldloc.1 IL_0013: isinst ""I1"" IL_0018: stloc.2 IL_0019: ldloc.2 IL_001a: brfalse.s IL_0059 IL_001c: ldloc.2 IL_001d: callvirt ""int I1.F.get"" IL_0022: ldc.i4.1 IL_0023: bne.un.s IL_0059 IL_0025: ldarg.0 IL_0026: ldfld ""int System.ValueTuple<S1, int>.Item2"" IL_002b: stloc.3 IL_002c: ldloc.3 IL_002d: ldc.i4.2 IL_002e: beq.s IL_0054 IL_0030: br.s IL_0050 IL_0032: ldloca.s V_0 IL_0034: ldloca.s V_4 IL_0036: call ""bool S1.TryGetValue(out I1)"" IL_003b: brfalse.s IL_0059 IL_003d: ldloc.s V_4 IL_003f: stloc.2 IL_0040: ldloc.2 IL_0041: callvirt ""int I1.F.get"" IL_0046: ldc.i4.1 IL_0047: bne.un.s IL_0059 IL_0049: ldarg.0 IL_004a: ldfld ""int System.ValueTuple<S1, int>.Item2"" IL_004f: stloc.3 IL_0050: ldloc.3 IL_0051: ldc.i4.1 IL_0052: bne.un.s IL_0059 IL_0054: ldc.i4.1 IL_0055: stloc.s V_5 IL_0057: br.s IL_005c IL_0059: ldc.i4.0 IL_005a: stloc.s V_5 IL_005c: ldloc.s V_5 IL_005e: ret } "); } [Fact] public void NonBoxingUnionMatching_52_TryGetValue() { var src = @" using System; class C11; class C12 : IComparable { public int CompareTo(object obj) => throw null; } [System.Runtime.CompilerServices.Union] struct S1 { private readonly object _value; public S1(C11 x) { _value = x; } public S1(int x) { _value = x; } public S1(string x) { _value = x; } public S1(IComparable x) { _value = x; } public object Value { get { System.Console.Write(""get_Value ""); return _value; } } public bool HasValue { get { System.Console.Write(""HasValue ""); return _value != null; } } public bool TryGetValue(out int x) { System.Console.Write(""TryGetValue(int) ""); if (_value is int) { x = (int)_value; return true; } x = 0; return false; } public bool TryGetValue(out IComparable x) { System.Console.Write(""TryGetValue(IComparable) ""); x = _value as IComparable; return x != null; } static void Main() { S1[] s = [new S1(), new S1(new C11()), new S1(new C12()), new S1(1), new S1(""1""), new S1(2), new S1(""2""), new S1(3), new S1(""3"")]; int[] i = [1, 2, 3]; foreach (var s1 in s) { foreach (var j in i) { var t = Test1((s1, j)); System.Console.WriteLine(); System.Console.WriteLine(t); } } } static bool Test1((S1, int) u) { return u is (System.IComparable and int and 1, 2) or (int and (1 or 3), 1); } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); VerifyDecisionDagDump<IsPatternExpressionSyntax>(comp, @"[0]: t1 = t0.Item1; [1] [1]: TryGetValue(System.IComparable): (Item1, ReturnItem) t2 = t1; [2] [2]: t2.ReturnItem == True ? [3] : [13] [3]: t3 = (System.IComparable)t2.Item1; [4] [4]: t3 is int ? [5] : [13] [5]: t4 = (int)t3; [6] [6]: t4 == 1 ? [7] : [9] [7]: t5 = t0.Item2; [8] [8]: t5 == 2 ? [12] : [11] [9]: t4 == 3 ? [10] : [13] [10]: t5 = t0.Item2; [11] [11]: t5 == 1 ? [12] : [13] [12]: leaf <isPatternSuccess> `(System.IComparable and int and 1, 2) or (int and (1 or 3), 1)` [13]: leaf <isPatternFailure> `u is (System.IComparable and int and 1, 2) or (int and (1 or 3), 1)` ", forLowering: true); CompilationVerifier verifier = CompileAndVerify( comp, expectedOutput: @" TryGetValue(IComparable) False TryGetValue(IComparable) False TryGetValue(IComparable) False TryGetValue(IComparable) False TryGetValue(IComparable) False TryGetValue(IComparable) False TryGetValue(IComparable) False TryGetValue(IComparable) False TryGetValue(IComparable) False TryGetValue(IComparable) True TryGetValue(IComparable) True TryGetValue(IComparable) False TryGetValue(IComparable) False TryGetValue(IComparable) False TryGetValue(IComparable) False TryGetValue(IComparable) False TryGetValue(IComparable) False TryGetValue(IComparable) False TryGetValue(IComparable) False TryGetValue(IComparable) False TryGetValue(IComparable) False TryGetValue(IComparable) True TryGetValue(IComparable) False TryGetValue(IComparable) False TryGetValue(IComparable) False TryGetValue(IComparable) False TryGetValue(IComparable) False ").VerifyDiagnostics(); verifier.VerifyIL("S1.Test1", @" { // Code size 84 (0x54) .maxstack 2 .locals init (S1 V_0, System.IComparable V_1, System.IComparable V_2, int V_3, int V_4, bool V_5) IL_0000: ldarg.0 IL_0001: ldfld ""S1 System.ValueTuple<S1, int>.Item1"" IL_0006: stloc.0 IL_0007: ldloca.s V_0 IL_0009: ldloca.s V_1 IL_000b: call ""bool S1.TryGetValue(out System.IComparable)"" IL_0010: brfalse.s IL_004e IL_0012: ldloc.1 IL_0013: stloc.2 IL_0014: ldloc.2 IL_0015: isinst ""int"" IL_001a: brfalse.s IL_004e IL_001c: ldloc.2 IL_001d: unbox.any ""int"" IL_0022: stloc.3 IL_0023: ldloc.3 IL_0024: ldc.i4.1 IL_0025: beq.s IL_002d IL_0027: ldloc.3 IL_0028: ldc.i4.3 IL_0029: beq.s IL_003c IL_002b: br.s IL_004e IL_002d: ldarg.0 IL_002e: ldfld ""int System.ValueTuple<S1, int>.Item2"" IL_0033: stloc.s V_4 IL_0035: ldloc.s V_4 IL_0037: ldc.i4.2 IL_0038: beq.s IL_0049 IL_003a: br.s IL_0044 IL_003c: ldarg.0 IL_003d: ldfld ""int System.ValueTuple<S1, int>.Item2"" IL_0042: stloc.s V_4 IL_0044: ldloc.s V_4 IL_0046: ldc.i4.1 IL_0047: bne.un.s IL_004e IL_0049: ldc.i4.1 IL_004a: stloc.s V_5 IL_004c: br.s IL_0051 IL_004e: ldc.i4.0 IL_004f: stloc.s V_5 IL_0051: ldloc.s V_5 IL_0053: ret } "); } [Fact] public void NonBoxingUnionMatching_53_TryGetValue() { var src = @" using System; class C11; class C12; [System.Runtime.CompilerServices.Union] struct S1 { private readonly object _value; public S1(C11 x) { _value = x; } public S1(int x) { _value = x; } public S1(string x) { _value = x; } public S1(IComparable x) { _value = x; } public S1(C12 x) { _value = x; } public object Value { get { System.Console.Write(""get_Value ""); return _value; } } public bool HasValue { get { System.Console.Write(""HasValue ""); return _value != null; } } public bool TryGetValue(out int x) { System.Console.Write(""TryGetValue(int) ""); if (_value is int) { x = (int)_value; return true; } x = 0; return false; } public bool TryGetValue(out IComparable x) { System.Console.Write(""TryGetValue(IComparable) ""); x = _value as IComparable; return x != null; } static void Main() { S1[] s = [new S1(), new S1(new C11()), new S1(new C12()), new S1(1), new S1(""1""), new S1(2), new S1(""2""), new S1(3), new S1(""3"")]; int[] i = [1, 2, 3]; foreach (var s1 in s) { foreach (var j in i) { var t = Test1((s1, j)); System.Console.WriteLine(); System.Console.WriteLine(t); } } } static bool Test1((S1, int) u) { return u is (int and 1, 2) or (System.IComparable and { AsInt: 3 }, 1); } } static class IComparableExtensions { extension(IComparable c) { public int? AsInt { get { c.GetHashCode(); // We do not expect null inputs var result = c as int?; if (result.HasValue && result.Value == 0) { throw new Exception(""Unexpected 0 value""); } return result; } } } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); VerifyDecisionDagDump<IsPatternExpressionSyntax>(comp, @"[0]: t1 = t0.Item1; [1] [1]: TryGetValue(int): (Item1, ReturnItem) t2 = t1; [2] [2]: t2.ReturnItem == True ? [3] : [15] [3]: t3 = (int)t2.Item1; [4] [4]: t3 == 1 ? [5] : [13] [5]: t4 = t0.Item2; [6] [6]: t4 == 2 ? [24] : [7] [7]: t5 = (System.IComparable)t2.Item1; [8] [8]: PassThrough t5; [9] [9]: t7 = t5.AsInt; [10] [10]: t7 != null ? [11] : [25] [11]: t8 = (int)t7; [12] [12]: t8 == 3 ? [23] : [25] [13]: t5 = (System.IComparable)t2.Item1; [14] [14]: PassThrough t5; [18] [15]: TryGetValue(System.IComparable): (Item1, ReturnItem) t9 = t1; [16] [16]: t9.ReturnItem == True ? [17] : [25] [17]: t5 = (System.IComparable)t9.Item1; [18] [18]: t7 = t5.AsInt; [19] [19]: t7 != null ? [20] : [25] [20]: t8 = (int)t7; [21] [21]: t8 == 3 ? [22] : [25] [22]: t4 = t0.Item2; [23] [23]: t4 == 1 ? [24] : [25] [24]: leaf <isPatternSuccess> `(int and 1, 2) or (System.IComparable and { AsInt: 3 }, 1)` [25]: leaf <isPatternFailure> `u is (int and 1, 2) or (System.IComparable and { AsInt: 3 }, 1)` ", forLowering: true); var verifier = CompileAndVerify( comp, expectedOutput: @" TryGetValue(int) TryGetValue(IComparable) False TryGetValue(int) TryGetValue(IComparable) False TryGetValue(int) TryGetValue(IComparable) False TryGetValue(int) TryGetValue(IComparable) False TryGetValue(int) TryGetValue(IComparable) False TryGetValue(int) TryGetValue(IComparable) False TryGetValue(int) TryGetValue(IComparable) False TryGetValue(int) TryGetValue(IComparable) False TryGetValue(int) TryGetValue(IComparable) False TryGetValue(int) False TryGetValue(int) True TryGetValue(int) False TryGetValue(int) TryGetValue(IComparable) False TryGetValue(int) TryGetValue(IComparable) False TryGetValue(int) TryGetValue(IComparable) False TryGetValue(int) False TryGetValue(int) False TryGetValue(int) False TryGetValue(int) TryGetValue(IComparable) False TryGetValue(int) TryGetValue(IComparable) False TryGetValue(int) TryGetValue(IComparable) False TryGetValue(int) True TryGetValue(int) False TryGetValue(int) False TryGetValue(int) TryGetValue(IComparable) False TryGetValue(int) TryGetValue(IComparable) False TryGetValue(int) TryGetValue(IComparable) False ").VerifyDiagnostics(); verifier.VerifyIL("S1.Test1", @" { // Code size 141 (0x8d) .maxstack 2 .locals init (S1 V_0, int V_1, int V_2, System.IComparable V_3, int? V_4, System.IComparable V_5, bool V_6) IL_0000: ldarg.0 IL_0001: ldfld ""S1 System.ValueTuple<S1, int>.Item1"" IL_0006: stloc.0 IL_0007: ldloca.s V_0 IL_0009: ldloca.s V_1 IL_000b: call ""bool S1.TryGetValue(out int)"" IL_0010: brfalse.s IL_004e IL_0012: ldloc.1 IL_0013: ldc.i4.1 IL_0014: bne.un.s IL_0045 IL_0016: ldarg.0 IL_0017: ldfld ""int System.ValueTuple<S1, int>.Item2"" IL_001c: stloc.2 IL_001d: ldloc.2 IL_001e: ldc.i4.2 IL_001f: beq.s IL_0082 IL_0021: ldloc.1 IL_0022: box ""int"" IL_0027: stloc.3 IL_0028: ldloc.3 IL_0029: call ""int? IComparableExtensions.get_AsInt(System.IComparable)"" IL_002e: stloc.s V_4 IL_0030: ldloca.s V_4 IL_0032: call ""bool int?.HasValue.get"" IL_0037: brfalse.s IL_0087 IL_0039: ldloca.s V_4 IL_003b: call ""int int?.GetValueOrDefault()"" IL_0040: ldc.i4.3 IL_0041: beq.s IL_007e IL_0043: br.s IL_0087 IL_0045: ldloc.1 IL_0046: box ""int"" IL_004b: stloc.3 IL_004c: br.s IL_005c IL_004e: ldloca.s V_0 IL_0050: ldloca.s V_5 IL_0052: call ""bool S1.TryGetValue(out System.IComparable)"" IL_0057: brfalse.s IL_0087 IL_0059: ldloc.s V_5 IL_005b: stloc.3 IL_005c: ldloc.3 IL_005d: call ""int? IComparableExtensions.get_AsInt(System.IComparable)"" IL_0062: stloc.s V_4 IL_0064: ldloca.s V_4 IL_0066: call ""bool int?.HasValue.get"" IL_006b: brfalse.s IL_0087 IL_006d: ldloca.s V_4 IL_006f: call ""int int?.GetValueOrDefault()"" IL_0074: ldc.i4.3 IL_0075: bne.un.s IL_0087 IL_0077: ldarg.0 IL_0078: ldfld ""int System.ValueTuple<S1, int>.Item2"" IL_007d: stloc.2 IL_007e: ldloc.2 IL_007f: ldc.i4.1 IL_0080: bne.un.s IL_0087 IL_0082: ldc.i4.1 IL_0083: stloc.s V_6 IL_0085: br.s IL_008a IL_0087: ldc.i4.0 IL_0088: stloc.s V_6 IL_008a: ldloc.s V_6 IL_008c: ret } "); } [Fact] public void NonBoxingUnionMatching_54_TryGetValue() { var src = @" using System; class C11; class C12 : IConvertible { public TypeCode GetTypeCode() => throw null; public bool ToBoolean(IFormatProvider provider) => throw null; public byte ToByte(IFormatProvider provider) => throw null; public char ToChar(IFormatProvider provider) => throw null; public DateTime ToDateTime(IFormatProvider provider) => throw null; public decimal ToDecimal(IFormatProvider provider) => throw null; public double ToDouble(IFormatProvider provider) => throw null; public short ToInt16(IFormatProvider provider) => throw null; public int ToInt32(IFormatProvider provider) => throw null; public long ToInt64(IFormatProvider provider) => throw null; public sbyte ToSByte(IFormatProvider provider) => throw null; public float ToSingle(IFormatProvider provider) => throw null; public string ToString(IFormatProvider provider) => throw null; public object ToType(Type conversionType, IFormatProvider provider) => throw null; public ushort ToUInt16(IFormatProvider provider) => throw null; public uint ToUInt32(IFormatProvider provider) => throw null; public ulong ToUInt64(IFormatProvider provider) => throw null; } [System.Runtime.CompilerServices.Union] struct S1 { private readonly object _value; public S1(C11 x) { _value = x; } public S1(int x) { _value = x; } public S1(string x) { _value = x; } public S1(IComparable x) { _value = x; } public S1(IConvertible x) { _value = x; } public object Value { get { System.Console.Write(""get_Value ""); return _value; } } public bool HasValue { get { System.Console.Write(""HasValue ""); return _value != null; } } public bool TryGetValue(out int x) { System.Console.Write(""TryGetValue(int) ""); if (_value is int) { x = (int)_value; return true; } x = 0; return false; } public bool TryGetValue(out IComparable x) { System.Console.Write(""TryGetValue(IComparable) ""); x = _value as IComparable; return x != null; } public bool TryGetValue(out IConvertible x) { System.Console.Write(""TryGetValue(IConvertible) ""); x = _value as IConvertible; return x != null; } static void Main() { S1[] s = [new S1(), new S1(new C11()), new S1(new C12()), new S1(1), new S1(""1""), new S1(2), new S1(""2""), new S1(3), new S1(""3"")]; int[] i = [1, 2, 3]; foreach (var s1 in s) { foreach (var j in i) { var t = Test1((s1, j)); System.Console.WriteLine(); System.Console.WriteLine(t); } } } static bool Test1((S1, int) u) { return u is (IConvertible and int and 1, 2) or (System.IComparable and { AsInt: 3 }, 1); } } static class IComparableExtensions { extension(IComparable c) { public int? AsInt { get { c.GetHashCode(); // We do not expect null inputs var result = c as int?; if (result.HasValue && result.Value == 0) { throw new Exception(""Unexpected 0 value""); } return result; } } } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); VerifyDecisionDagDump<IsPatternExpressionSyntax>(comp, @"[0]: t1 = t0.Item1; [1] [1]: TryGetValue(System.IConvertible): (Item1, ReturnItem) t2 = t1; [2] [2]: t2.ReturnItem == True ? [3] : [17] [3]: t3 = (System.IConvertible)t2.Item1; [4] [4]: t3 is int ? [5] : [17] [5]: t4 = (int)t3; [6] [6]: t4 == 1 ? [7] : [15] [7]: t5 = t0.Item2; [8] [8]: t5 == 2 ? [26] : [9] [9]: t6 = (System.IComparable)t3; [10] [10]: PassThrough t6; [11] [11]: t8 = t6.AsInt; [12] [12]: t8 != null ? [13] : [27] [13]: t9 = (int)t8; [14] [14]: t9 == 3 ? [25] : [27] [15]: t6 = (System.IComparable)t3; [16] [16]: PassThrough t6; [20] [17]: TryGetValue(System.IComparable): (Item1, ReturnItem) t10 = t1; [18] [18]: t10.ReturnItem == True ? [19] : [27] [19]: t6 = (System.IComparable)t10.Item1; [20] [20]: t8 = t6.AsInt; [21] [21]: t8 != null ? [22] : [27] [22]: t9 = (int)t8; [23] [23]: t9 == 3 ? [24] : [27] [24]: t5 = t0.Item2; [25] [25]: t5 == 1 ? [26] : [27] [26]: leaf <isPatternSuccess> `(IConvertible and int and 1, 2) or (System.IComparable and { AsInt: 3 }, 1)` [27]: leaf <isPatternFailure> `u is (IConvertible and int and 1, 2) or (System.IComparable and { AsInt: 3 }, 1)` ", forLowering: true); var verifier = CompileAndVerify( comp, expectedOutput: @" TryGetValue(IConvertible) TryGetValue(IComparable) False TryGetValue(IConvertible) TryGetValue(IComparable) False TryGetValue(IConvertible) TryGetValue(IComparable) False TryGetValue(IConvertible) TryGetValue(IComparable) False TryGetValue(IConvertible) TryGetValue(IComparable) False TryGetValue(IConvertible) TryGetValue(IComparable) False TryGetValue(IConvertible) TryGetValue(IComparable) False TryGetValue(IConvertible) TryGetValue(IComparable) False TryGetValue(IConvertible) TryGetValue(IComparable) False TryGetValue(IConvertible) False TryGetValue(IConvertible) True TryGetValue(IConvertible) False TryGetValue(IConvertible) TryGetValue(IComparable) False TryGetValue(IConvertible) TryGetValue(IComparable) False TryGetValue(IConvertible) TryGetValue(IComparable) False TryGetValue(IConvertible) False TryGetValue(IConvertible) False TryGetValue(IConvertible) False TryGetValue(IConvertible) TryGetValue(IComparable) False TryGetValue(IConvertible) TryGetValue(IComparable) False TryGetValue(IConvertible) TryGetValue(IComparable) False TryGetValue(IConvertible) True TryGetValue(IConvertible) False TryGetValue(IConvertible) False TryGetValue(IConvertible) TryGetValue(IComparable) False TryGetValue(IConvertible) TryGetValue(IComparable) False TryGetValue(IConvertible) TryGetValue(IComparable) False ").VerifyDiagnostics(); verifier.VerifyIL("S1.Test1", @" { // Code size 161 (0xa1) .maxstack 2 .locals init (S1 V_0, System.IConvertible V_1, System.IConvertible V_2, int V_3, System.IComparable V_4, int? V_5, System.IComparable V_6, bool V_7) IL_0000: ldarg.0 IL_0001: ldfld ""S1 System.ValueTuple<S1, int>.Item1"" IL_0006: stloc.0 IL_0007: ldloca.s V_0 IL_0009: ldloca.s V_1 IL_000b: call ""bool S1.TryGetValue(out System.IConvertible)"" IL_0010: brfalse.s IL_0060 IL_0012: ldloc.1 IL_0013: stloc.2 IL_0014: ldloc.2 IL_0015: isinst ""int"" IL_001a: brfalse.s IL_0060 IL_001c: ldloc.2 IL_001d: unbox.any ""int"" IL_0022: ldc.i4.1 IL_0023: bne.un.s IL_0056 IL_0025: ldarg.0 IL_0026: ldfld ""int System.ValueTuple<S1, int>.Item2"" IL_002b: stloc.3 IL_002c: ldloc.3 IL_002d: ldc.i4.2 IL_002e: beq.s IL_0096 IL_0030: ldloc.2 IL_0031: castclass ""System.IComparable"" IL_0036: stloc.s V_4 IL_0038: ldloc.s V_4 IL_003a: call ""int? IComparableExtensions.get_AsInt(System.IComparable)"" IL_003f: stloc.s V_5 IL_0041: ldloca.s V_5 IL_0043: call ""bool int?.HasValue.get"" IL_0048: brfalse.s IL_009b IL_004a: ldloca.s V_5 IL_004c: call ""int int?.GetValueOrDefault()"" IL_0051: ldc.i4.3 IL_0052: beq.s IL_0092 IL_0054: br.s IL_009b IL_0056: ldloc.2 IL_0057: castclass ""System.IComparable"" IL_005c: stloc.s V_4 IL_005e: br.s IL_006f IL_0060: ldloca.s V_0 IL_0062: ldloca.s V_6 IL_0064: call ""bool S1.TryGetValue(out System.IComparable)"" IL_0069: brfalse.s IL_009b IL_006b: ldloc.s V_6 IL_006d: stloc.s V_4 IL_006f: ldloc.s V_4 IL_0071: call ""int? IComparableExtensions.get_AsInt(System.IComparable)"" IL_0076: stloc.s V_5 IL_0078: ldloca.s V_5 IL_007a: call ""bool int?.HasValue.get"" IL_007f: brfalse.s IL_009b IL_0081: ldloca.s V_5 IL_0083: call ""int int?.GetValueOrDefault()"" IL_0088: ldc.i4.3 IL_0089: bne.un.s IL_009b IL_008b: ldarg.0 IL_008c: ldfld ""int System.ValueTuple<S1, int>.Item2"" IL_0091: stloc.3 IL_0092: ldloc.3 IL_0093: ldc.i4.1 IL_0094: bne.un.s IL_009b IL_0096: ldc.i4.1 IL_0097: stloc.s V_7 IL_0099: br.s IL_009e IL_009b: ldc.i4.0 IL_009c: stloc.s V_7 IL_009e: ldloc.s V_7 IL_00a0: ret } "); } [Fact] public void NonBoxingUnionMatching_55_TryGetValue() { var src = @" using System; class C11; class C12 : IConvertible { public TypeCode GetTypeCode() => throw null; public bool ToBoolean(IFormatProvider provider) => throw null; public byte ToByte(IFormatProvider provider) => throw null; public char ToChar(IFormatProvider provider) => throw null; public DateTime ToDateTime(IFormatProvider provider) => throw null; public decimal ToDecimal(IFormatProvider provider) => throw null; public double ToDouble(IFormatProvider provider) => throw null; public short ToInt16(IFormatProvider provider) => throw null; public int ToInt32(IFormatProvider provider) => throw null; public long ToInt64(IFormatProvider provider) => throw null; public sbyte ToSByte(IFormatProvider provider) => throw null; public float ToSingle(IFormatProvider provider) => throw null; public string ToString(IFormatProvider provider) => throw null; public object ToType(Type conversionType, IFormatProvider provider) => throw null; public ushort ToUInt16(IFormatProvider provider) => throw null; public uint ToUInt32(IFormatProvider provider) => throw null; public ulong ToUInt64(IFormatProvider provider) => throw null; } [System.Runtime.CompilerServices.Union] struct S1 { private readonly object _value; public S1(C11 x) { _value = x; } public S1(int x) { _value = x; } public S1(string x) { _value = x; } public S1(IComparable x) { _value = x; } public S1(IConvertible x) { _value = x; } public object Value { get { System.Console.Write(""get_Value ""); return _value; } } public bool HasValue { get { System.Console.Write(""HasValue ""); return _value != null; } } public bool TryGetValue(out int x) { System.Console.Write(""TryGetValue(int) ""); if (_value is int) { x = (int)_value; return true; } x = 0; return false; } public bool TryGetValue(out IComparable x) { System.Console.Write(""TryGetValue(IComparable) ""); x = _value as IComparable; return x != null; } public bool TryGetValue(out IConvertible x) { System.Console.Write(""TryGetValue(IConvertible) ""); x = _value as IConvertible; return x != null; } public bool TryGetValue(out string x) { System.Console.Write(""TryGetValue(string) ""); x = _value as string; return x != null; } static void Main() { S1[] s = [new S1(), new S1(new C11()), new S1(new C12()), new S1(1), new S1(""1""), new S1(2), new S1(""2""), new S1(3), new S1(""3"")]; int[] i = [1, 2, 3]; foreach (var s1 in s) { foreach (var j in i) { var t = Test1((s1, j)); System.Console.WriteLine(); System.Console.WriteLine(t); } } } static bool Test1((S1, int) u) { return u is (int and 1, 2) or (string and ""3"", 3) or (System.IComparable and { AsInt: 3 }, 1); } } static class IComparableExtensions { extension(IComparable c) { public int? AsInt { get { c.GetHashCode(); // We do not expect null inputs var result = c as int?; if (result.HasValue && result.Value == 0) { throw new Exception(""Unexpected 0 value""); } return result; } } } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); VerifyDecisionDagDump<IsPatternExpressionSyntax>(comp, @"[0]: t1 = t0.Item1; [1] [1]: TryGetValue(int): (Item1, ReturnItem) t2 = t1; [2] [2]: t2.ReturnItem == True ? [3] : [11] [3]: t3 = (int)t2.Item1; [4] [4]: t3 == 1 ? [5] : [9] [5]: t4 = t0.Item2; [6] [6]: t4 == 2 ? [34] : [7] [7]: t5 = (System.IComparable)t2.Item1; [8] [8]: PassThrough t5; [19] [9]: t5 = (System.IComparable)t2.Item1; [10] [10]: PassThrough t5; [28] [11]: TryGetValue(string): (Item1, ReturnItem) t7 = t1; [12] [12]: t7.ReturnItem == True ? [13] : [25] [13]: t8 = (string)t7.Item1; [14] [14]: t8 == ""3"" ? [15] : [23] [15]: t4 = t0.Item2; [16] [16]: t4 == 3 ? [34] : [17] [17]: t5 = (System.IComparable)t7.Item1; [18] [18]: PassThrough t5; [19] [19]: t10 = t5.AsInt; [20] [20]: t10 != null ? [21] : [35] [21]: t11 = (int)t10; [22] [22]: t11 == 3 ? [33] : [35] [23]: t5 = (System.IComparable)t7.Item1; [24] [24]: PassThrough t5; [28] [25]: TryGetValue(System.IComparable): (Item1, ReturnItem) t12 = t1; [26] [26]: t12.ReturnItem == True ? [27] : [35] [27]: t5 = (System.IComparable)t12.Item1; [28] [28]: t10 = t5.AsInt; [29] [29]: t10 != null ? [30] : [35] [30]: t11 = (int)t10; [31] [31]: t11 == 3 ? [32] : [35] [32]: t4 = t0.Item2; [33] [33]: t4 == 1 ? [34] : [35] [34]: leaf <isPatternSuccess> `(int and 1, 2) or (string and ""3"", 3) or (System.IComparable and { AsInt: 3 }, 1)` [35]: leaf <isPatternFailure> `u is (int and 1, 2) or (string and ""3"", 3) or (System.IComparable and { AsInt: 3 }, 1)` ", forLowering: true); var verifier = CompileAndVerify( comp, expectedOutput: @" TryGetValue(int) TryGetValue(string) TryGetValue(IComparable) False TryGetValue(int) TryGetValue(string) TryGetValue(IComparable) False TryGetValue(int) TryGetValue(string) TryGetValue(IComparable) False TryGetValue(int) TryGetValue(string) TryGetValue(IComparable) False TryGetValue(int) TryGetValue(string) TryGetValue(IComparable) False TryGetValue(int) TryGetValue(string) TryGetValue(IComparable) False TryGetValue(int) TryGetValue(string) TryGetValue(IComparable) False TryGetValue(int) TryGetValue(string) TryGetValue(IComparable) False TryGetValue(int) TryGetValue(string) TryGetValue(IComparable) False TryGetValue(int) False TryGetValue(int) True TryGetValue(int) False TryGetValue(int) TryGetValue(string) False TryGetValue(int) TryGetValue(string) False TryGetValue(int) TryGetValue(string) False TryGetValue(int) False TryGetValue(int) False TryGetValue(int) False TryGetValue(int) TryGetValue(string) False TryGetValue(int) TryGetValue(string) False TryGetValue(int) TryGetValue(string) False TryGetValue(int) True TryGetValue(int) False TryGetValue(int) False TryGetValue(int) TryGetValue(string) False TryGetValue(int) TryGetValue(string) False TryGetValue(int) TryGetValue(string) True ").VerifyDiagnostics(); verifier.VerifyIL("S1.Test1", @" { // Code size 190 (0xbe) .maxstack 2 .locals init (S1 V_0, int V_1, int V_2, System.IComparable V_3, string V_4, int? V_5, System.IComparable V_6, bool V_7) IL_0000: ldarg.0 IL_0001: ldfld ""S1 System.ValueTuple<S1, int>.Item1"" IL_0006: stloc.0 IL_0007: ldloca.s V_0 IL_0009: ldloca.s V_1 IL_000b: call ""bool S1.TryGetValue(out int)"" IL_0010: brfalse.s IL_0036 IL_0012: ldloc.1 IL_0013: ldc.i4.1 IL_0014: bne.un.s IL_002d IL_0016: ldarg.0 IL_0017: ldfld ""int System.ValueTuple<S1, int>.Item2"" IL_001c: stloc.2 IL_001d: ldloc.2 IL_001e: ldc.i4.2 IL_001f: beq IL_00b3 IL_0024: ldloc.1 IL_0025: box ""int"" IL_002a: stloc.3 IL_002b: br.s IL_005d IL_002d: ldloc.1 IL_002e: box ""int"" IL_0033: stloc.3 IL_0034: br.s IL_008d IL_0036: ldloca.s V_0 IL_0038: ldloca.s V_4 IL_003a: call ""bool S1.TryGetValue(out string)"" IL_003f: brfalse.s IL_007f IL_0041: ldloc.s V_4 IL_0043: ldstr ""3"" IL_0048: call ""bool string.op_Equality(string, string)"" IL_004d: brfalse.s IL_007a IL_004f: ldarg.0 IL_0050: ldfld ""int System.ValueTuple<S1, int>.Item2"" IL_0055: stloc.2 IL_0056: ldloc.2 IL_0057: ldc.i4.3 IL_0058: beq.s IL_00b3 IL_005a: ldloc.s V_4 IL_005c: stloc.3 IL_005d: ldloc.3 IL_005e: call ""int? IComparableExtensions.get_AsInt(System.IComparable)"" IL_0063: stloc.s V_5 IL_0065: ldloca.s V_5 IL_0067: call ""bool int?.HasValue.get"" IL_006c: brfalse.s IL_00b8 IL_006e: ldloca.s V_5 IL_0070: call ""int int?.GetValueOrDefault()"" IL_0075: ldc.i4.3 IL_0076: beq.s IL_00af IL_0078: br.s IL_00b8 IL_007a: ldloc.s V_4 IL_007c: stloc.3 IL_007d: br.s IL_008d IL_007f: ldloca.s V_0 IL_0081: ldloca.s V_6 IL_0083: call ""bool S1.TryGetValue(out System.IComparable)"" IL_0088: brfalse.s IL_00b8 IL_008a: ldloc.s V_6 IL_008c: stloc.3 IL_008d: ldloc.3 IL_008e: call ""int? IComparableExtensions.get_AsInt(System.IComparable)"" IL_0093: stloc.s V_5 IL_0095: ldloca.s V_5 IL_0097: call ""bool int?.HasValue.get"" IL_009c: brfalse.s IL_00b8 IL_009e: ldloca.s V_5 IL_00a0: call ""int int?.GetValueOrDefault()"" IL_00a5: ldc.i4.3 IL_00a6: bne.un.s IL_00b8 IL_00a8: ldarg.0 IL_00a9: ldfld ""int System.ValueTuple<S1, int>.Item2"" IL_00ae: stloc.2 IL_00af: ldloc.2 IL_00b0: ldc.i4.1 IL_00b1: bne.un.s IL_00b8 IL_00b3: ldc.i4.1 IL_00b4: stloc.s V_7 IL_00b6: br.s IL_00bb IL_00b8: ldc.i4.0 IL_00b9: stloc.s V_7 IL_00bb: ldloc.s V_7 IL_00bd: ret } "); } [Fact] public void NonBoxingUnionMatching_56_TryGetValue() { var src = @" using System; class C11; class C12 : IConvertible { public TypeCode GetTypeCode() => throw null; public bool ToBoolean(IFormatProvider provider) => throw null; public byte ToByte(IFormatProvider provider) => throw null; public char ToChar(IFormatProvider provider) => throw null; public DateTime ToDateTime(IFormatProvider provider) => throw null; public decimal ToDecimal(IFormatProvider provider) => throw null; public double ToDouble(IFormatProvider provider) => throw null; public short ToInt16(IFormatProvider provider) => throw null; public int ToInt32(IFormatProvider provider) => throw null; public long ToInt64(IFormatProvider provider) => throw null; public sbyte ToSByte(IFormatProvider provider) => throw null; public float ToSingle(IFormatProvider provider) => throw null; public string ToString(IFormatProvider provider) => throw null; public object ToType(Type conversionType, IFormatProvider provider) => throw null; public ushort ToUInt16(IFormatProvider provider) => throw null; public uint ToUInt32(IFormatProvider provider) => throw null; public ulong ToUInt64(IFormatProvider provider) => throw null; } [System.Runtime.CompilerServices.Union] struct S1 { private readonly object _value; public S1(C11 x) { _value = x; } public S1(int x) { _value = x; } public S1(string x) { _value = x; } public S1(IComparable x) { _value = x; } public S1(IConvertible x) { _value = x; } public object Value { get { System.Console.Write(""get_Value ""); return _value; } } public bool HasValue { get { System.Console.Write(""HasValue ""); return _value != null; } } public bool TryGetValue(out int x) { System.Console.Write(""TryGetValue(int) ""); if (_value is int) { x = (int)_value; return true; } x = 0; return false; } public bool TryGetValue(out IComparable x) { System.Console.Write(""TryGetValue(IComparable) ""); x = _value as IComparable; return x != null; } public bool TryGetValue(out IConvertible x) { System.Console.Write(""TryGetValue(IConvertible) ""); x = _value as IConvertible; return x != null; } public bool TryGetValue(out string x) { System.Console.Write(""TryGetValue(string) ""); x = _value as string; return x != null; } static void Main() { S1[] s = [new S1(), new S1(new C11()), new S1(new C12()), new S1(1), new S1(""1""), new S1(2), new S1(""2""), new S1(3), new S1(""3"")]; int[] i = [1, 2, 3]; foreach (var s1 in s) { foreach (var j in i) { var t = Test1((s1, j)); System.Console.WriteLine(); System.Console.WriteLine(t); } } } static bool Test1((S1, int) u) { return u is (IConvertible and int and 1, 2) or (string and ""3"", 3) or (System.IComparable and { AsInt: 3 }, 1); } } static class IComparableExtensions { extension(IComparable c) { public int? AsInt { get { c.GetHashCode(); // We do not expect null inputs var result = c as int?; if (result.HasValue && result.Value == 0) { throw new Exception(""Unexpected 0 value""); } return result; } } } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); VerifyDecisionDagDump<IsPatternExpressionSyntax>(comp, @"[0]: t1 = t0.Item1; [1] [1]: TryGetValue(System.IConvertible): (Item1, ReturnItem) t2 = t1; [2] [2]: t2.ReturnItem == True ? [3] : [27] [3]: t3 = (System.IConvertible)t2.Item1; [4] [4]: t3 is int ? [5] : [13] [5]: t4 = (int)t3; [6] [6]: t4 == 1 ? [7] : [11] [7]: t5 = t0.Item2; [8] [8]: t5 == 2 ? [36] : [9] [9]: t6 = (System.IComparable)t3; [10] [10]: PassThrough t6; [21] [11]: t6 = (System.IComparable)t3; [12] [12]: PassThrough t6; [30] [13]: TryGetValue(string): (Item1, ReturnItem) t8 = t1; [14] [14]: t8.ReturnItem == True ? [15] : [27] [15]: t9 = (string)t8.Item1; [16] [16]: t9 == ""3"" ? [17] : [25] [17]: t5 = t0.Item2; [18] [18]: t5 == 3 ? [36] : [19] [19]: t6 = (System.IComparable)t8.Item1; [20] [20]: PassThrough t6; [21] [21]: t11 = t6.AsInt; [22] [22]: t11 != null ? [23] : [37] [23]: t12 = (int)t11; [24] [24]: t12 == 3 ? [35] : [37] [25]: t6 = (System.IComparable)t8.Item1; [26] [26]: PassThrough t6; [30] [27]: TryGetValue(System.IComparable): (Item1, ReturnItem) t13 = t1; [28] [28]: t13.ReturnItem == True ? [29] : [37] [29]: t6 = (System.IComparable)t13.Item1; [30] [30]: t11 = t6.AsInt; [31] [31]: t11 != null ? [32] : [37] [32]: t12 = (int)t11; [33] [33]: t12 == 3 ? [34] : [37] [34]: t5 = t0.Item2; [35] [35]: t5 == 1 ? [36] : [37] [36]: leaf <isPatternSuccess> `(IConvertible and int and 1, 2) or (string and ""3"", 3) or (System.IComparable and { AsInt: 3 }, 1)` [37]: leaf <isPatternFailure> `u is (IConvertible and int and 1, 2) or (string and ""3"", 3) or (System.IComparable and { AsInt: 3 }, 1)` ", forLowering: true); var verifier = CompileAndVerify( comp, expectedOutput: @" TryGetValue(IConvertible) TryGetValue(IComparable) False TryGetValue(IConvertible) TryGetValue(IComparable) False TryGetValue(IConvertible) TryGetValue(IComparable) False TryGetValue(IConvertible) TryGetValue(IComparable) False TryGetValue(IConvertible) TryGetValue(IComparable) False TryGetValue(IConvertible) TryGetValue(IComparable) False TryGetValue(IConvertible) TryGetValue(string) TryGetValue(IComparable) False TryGetValue(IConvertible) TryGetValue(string) TryGetValue(IComparable) False TryGetValue(IConvertible) TryGetValue(string) TryGetValue(IComparable) False TryGetValue(IConvertible) False TryGetValue(IConvertible) True TryGetValue(IConvertible) False TryGetValue(IConvertible) TryGetValue(string) False TryGetValue(IConvertible) TryGetValue(string) False TryGetValue(IConvertible) TryGetValue(string) False TryGetValue(IConvertible) False TryGetValue(IConvertible) False TryGetValue(IConvertible) False TryGetValue(IConvertible) TryGetValue(string) False TryGetValue(IConvertible) TryGetValue(string) False TryGetValue(IConvertible) TryGetValue(string) False TryGetValue(IConvertible) True TryGetValue(IConvertible) False TryGetValue(IConvertible) False TryGetValue(IConvertible) TryGetValue(string) False TryGetValue(IConvertible) TryGetValue(string) False TryGetValue(IConvertible) TryGetValue(string) True ").VerifyDiagnostics(); verifier.VerifyIL("S1.Test1", @" { // Code size 215 (0xd7) .maxstack 2 .locals init (S1 V_0, System.IConvertible V_1, System.IConvertible V_2, int V_3, System.IComparable V_4, string V_5, int? V_6, System.IComparable V_7, bool V_8) IL_0000: ldarg.0 IL_0001: ldfld ""S1 System.ValueTuple<S1, int>.Item1"" IL_0006: stloc.0 IL_0007: ldloca.s V_0 IL_0009: ldloca.s V_1 IL_000b: call ""bool S1.TryGetValue(out System.IConvertible)"" IL_0010: brfalse IL_0096 IL_0015: ldloc.1 IL_0016: stloc.2 IL_0017: ldloc.2 IL_0018: isinst ""int"" IL_001d: brfalse.s IL_004a IL_001f: ldloc.2 IL_0020: unbox.any ""int"" IL_0025: ldc.i4.1 IL_0026: bne.un.s IL_0040 IL_0028: ldarg.0 IL_0029: ldfld ""int System.ValueTuple<S1, int>.Item2"" IL_002e: stloc.3 IL_002f: ldloc.3 IL_0030: ldc.i4.2 IL_0031: beq IL_00cc IL_0036: ldloc.2 IL_0037: castclass ""System.IComparable"" IL_003c: stloc.s V_4 IL_003e: br.s IL_0072 IL_0040: ldloc.2 IL_0041: castclass ""System.IComparable"" IL_0046: stloc.s V_4 IL_0048: br.s IL_00a5 IL_004a: ldloca.s V_0 IL_004c: ldloca.s V_5 IL_004e: call ""bool S1.TryGetValue(out string)"" IL_0053: brfalse.s IL_0096 IL_0055: ldloc.s V_5 IL_0057: ldstr ""3"" IL_005c: call ""bool string.op_Equality(string, string)"" IL_0061: brfalse.s IL_0090 IL_0063: ldarg.0 IL_0064: ldfld ""int System.ValueTuple<S1, int>.Item2"" IL_0069: stloc.3 IL_006a: ldloc.3 IL_006b: ldc.i4.3 IL_006c: beq.s IL_00cc IL_006e: ldloc.s V_5 IL_0070: stloc.s V_4 IL_0072: ldloc.s V_4 IL_0074: call ""int? IComparableExtensions.get_AsInt(System.IComparable)"" IL_0079: stloc.s V_6 IL_007b: ldloca.s V_6 IL_007d: call ""bool int?.HasValue.get"" IL_0082: brfalse.s IL_00d1 IL_0084: ldloca.s V_6 IL_0086: call ""int int?.GetValueOrDefault()"" IL_008b: ldc.i4.3 IL_008c: beq.s IL_00c8 IL_008e: br.s IL_00d1 IL_0090: ldloc.s V_5 IL_0092: stloc.s V_4 IL_0094: br.s IL_00a5 IL_0096: ldloca.s V_0 IL_0098: ldloca.s V_7 IL_009a: call ""bool S1.TryGetValue(out System.IComparable)"" IL_009f: brfalse.s IL_00d1 IL_00a1: ldloc.s V_7 IL_00a3: stloc.s V_4 IL_00a5: ldloc.s V_4 IL_00a7: call ""int? IComparableExtensions.get_AsInt(System.IComparable)"" IL_00ac: stloc.s V_6 IL_00ae: ldloca.s V_6 IL_00b0: call ""bool int?.HasValue.get"" IL_00b5: brfalse.s IL_00d1 IL_00b7: ldloca.s V_6 IL_00b9: call ""int int?.GetValueOrDefault()"" IL_00be: ldc.i4.3 IL_00bf: bne.un.s IL_00d1 IL_00c1: ldarg.0 IL_00c2: ldfld ""int System.ValueTuple<S1, int>.Item2"" IL_00c7: stloc.3 IL_00c8: ldloc.3 IL_00c9: ldc.i4.1 IL_00ca: bne.un.s IL_00d1 IL_00cc: ldc.i4.1 IL_00cd: stloc.s V_8 IL_00cf: br.s IL_00d4 IL_00d1: ldc.i4.0 IL_00d2: stloc.s V_8 IL_00d4: ldloc.s V_8 IL_00d6: ret } "); } [Fact] public void NonBoxingUnionMatching_57_TryGetValue() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } public object Value { get { System.Console.Write(""get_Value ""); return _value; } } public bool TryGetValue(out int x) { System.Console.Write(""TryGetValue ""); if (_value is int v) { x = v; return true; } x = 0; return false; } static void Main() { System.Console.Write(Test1((new S1(1), 1))); System.Console.Write(""; ""); System.Console.Write(Test1((new S1(), 2))); System.Console.Write(""; ""); System.Console.Write(Test1((new S1(1), 2))); System.Console.Write(""; ""); System.Console.Write(Test1((new S1(""a""), 1))); } static bool Test1((S1, int) u) { return u is (1, 1) or (1, 2); } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); var verifier = CompileAndVerify(comp, expectedOutput: "TryGetValue True; TryGetValue False; TryGetValue True; TryGetValue False").VerifyDiagnostics(); verifier.VerifyIL("S1.Test1", @" { // Code size 43 (0x2b) .maxstack 2 .locals init (S1 V_0, int V_1, int V_2, bool V_3) IL_0000: ldarg.0 IL_0001: ldfld ""S1 System.ValueTuple<S1, int>.Item1"" IL_0006: stloc.0 IL_0007: ldloca.s V_0 IL_0009: ldloca.s V_1 IL_000b: call ""bool S1.TryGetValue(out int)"" IL_0010: brfalse.s IL_0027 IL_0012: ldloc.1 IL_0013: ldc.i4.1 IL_0014: bne.un.s IL_0027 IL_0016: ldarg.0 IL_0017: ldfld ""int System.ValueTuple<S1, int>.Item2"" IL_001c: stloc.2 IL_001d: ldloc.2 IL_001e: ldc.i4.1 IL_001f: sub IL_0020: ldc.i4.1 IL_0021: bgt.un.s IL_0027 IL_0023: ldc.i4.1 IL_0024: stloc.3 IL_0025: br.s IL_0029 IL_0027: ldc.i4.0 IL_0028: stloc.3 IL_0029: ldloc.3 IL_002a: ret } "); } [Fact] public void NonBoxingUnionMatching_58_TryGetValue() { var src = @" class C1(int f1, int f2) { public int F11 = f1; public int F12 = f2; } class C2(int f11, int f12, int f2) : C1(f11, f12) { public int F2 = f2; } class C3(int f1, int f2) : C1(f1, f2) { } [System.Runtime.CompilerServices.Union] struct S1 { private readonly object _value; public S1(C1 x) { _value = x; } public S1(C2 x) { _value = x; } public S1(C3 x) { _value = x; } public object Value { get { System.Console.Write(""get_Value ""); return _value; } } static void Main() { S1[] s = [new S1(), new S1(new C3(1, 1)), new S1(new C3(1, 3)), new S1(new C3(2, 3)), new S1(new C3(2, 4)), new S1(new C2(1, 1, 1)), new S1(new C2(1, 3, 1)), new S1(new C2(2, 3, 1)), new S1(new C2(2, 4, 1)), new S1(new C2(1, 1, 2)), new S1(new C2(1, 3, 2)), new S1(new C2(2, 3, 2)), new S1(new C2(2, 4, 2))]; foreach (var s1 in s) { var t = Test1(s1); System.Console.WriteLine(); System.Console.WriteLine(t); } } static bool Test1(S1 u) { return u is not ((C1 { F11: 1 } or C2 { F2: 2 }) and C1 { F12: 3 }); } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); VerifyDecisionDagDump<IsPatternExpressionSyntax>(comp, @"[0]: t1 = t0.Value; [1] [1]: t1 is C1 ? [2] : [12] [2]: t2 = (C1)t1; [3] [3]: t3 = t2.F11; [4] [4]: t3 == 1 ? [9] : [5] [5]: t1 is C2 ? [6] : [12] [6]: t4 = (C2)t1; [7] [7]: t5 = t4.F2; [8] [8]: t5 == 2 ? [9] : [12] [9]: t6 = t2.F12; [10] [10]: t6 == 3 ? [11] : [12] [11]: leaf <isPatternFailure> `(C1 { F11: 1 } or C2 { F2: 2 }) and C1 { F12: 3 }` [12]: leaf <isPatternSuccess> `u is not ((C1 { F11: 1 } or C2 { F2: 2 }) and C1 { F12: 3 })` ", forLowering: true); var verifier = CompileAndVerify(comp, expectedOutput: @" get_Value True get_Value True get_Value False get_Value True get_Value True get_Value True get_Value False get_Value True get_Value True get_Value True get_Value False get_Value False get_Value True ").VerifyDiagnostics(); verifier.VerifyIL("S1.Test1", @" { // Code size 66 (0x42) .maxstack 2 .locals init (object V_0, C1 V_1, C2 V_2, bool V_3) IL_0000: ldarga.s V_0 IL_0002: call ""object S1.Value.get"" IL_0007: stloc.0 IL_0008: ldloc.0 IL_0009: isinst ""C1"" IL_000e: stloc.1 IL_000f: ldloc.1 IL_0010: brfalse.s IL_003b IL_0012: ldloc.1 IL_0013: ldfld ""int C1.F11"" IL_0018: ldc.i4.1 IL_0019: beq.s IL_002e IL_001b: ldloc.0 IL_001c: isinst ""C2"" IL_0021: stloc.2 IL_0022: ldloc.2 IL_0023: brfalse.s IL_003b IL_0025: ldloc.2 IL_0026: ldfld ""int C2.F2"" IL_002b: ldc.i4.2 IL_002c: bne.un.s IL_003b IL_002e: ldloc.1 IL_002f: ldfld ""int C1.F12"" IL_0034: ldc.i4.3 IL_0035: bne.un.s IL_003b IL_0037: ldc.i4.1 IL_0038: stloc.3 IL_0039: br.s IL_003d IL_003b: ldc.i4.0 IL_003c: stloc.3 IL_003d: ldloc.3 IL_003e: ldc.i4.0 IL_003f: ceq IL_0041: ret } "); } [Fact] public void NonBoxingUnionMatching_59_TryGetValue() { var src = @" class C1(int f1, int f2) { public int F11 = f1; public int F12 = f2; } class C2(int f11, int f12, int f2) : C1(f11, f12) { public int F2 = f2; } class C3(int f1, int f2) : C1(f1, f2) { } [System.Runtime.CompilerServices.Union] struct S1 { private readonly object _value; public S1(C1 x) { _value = x; } public S1(C2 x) { _value = x; } public S1(C3 x) { _value = x; } public object Value { get { System.Console.Write(""get_Value ""); return _value; } } public bool TryGetValue(out C1 x) { System.Console.Write(""TryGetValue(C1) ""); x = _value as C1; return x != null; } public bool TryGetValue(out C2 x) { System.Console.Write(""TryGetValue(C2) ""); x = _value as C2; return x != null; } public bool TryGetValue(out C3 x) { System.Console.Write(""TryGetValue(C3) ""); x = _value as C3; return x != null; } static void Main() { S1[] s = [new S1(), new S1(new C3(1, 1)), new S1(new C3(1, 3)), new S1(new C3(2, 3)), new S1(new C3(2, 4)), new S1(new C2(1, 1, 1)), new S1(new C2(1, 3, 1)), new S1(new C2(2, 3, 1)), new S1(new C2(2, 4, 1)), new S1(new C2(1, 1, 2)), new S1(new C2(1, 3, 2)), new S1(new C2(2, 3, 2)), new S1(new C2(2, 4, 2))]; foreach (var s1 in s) { var t = Test1(s1); System.Console.WriteLine(); System.Console.WriteLine(t); } } static bool Test1(S1 u) { return u is not ((C1 { F11: 1 } or C2 { F2: 2 }) and C1 { F12: 3 }); } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); VerifyDecisionDagDump<IsPatternExpressionSyntax>(comp, @"[0]: TryGetValue(C1): (Item1, ReturnItem) t1 = t0; [1] [1]: t1.ReturnItem == True ? [2] : [13] [2]: t2 = (C1)t1.Item1; [3] [3]: t3 = t2.F11; [4] [4]: t3 == 1 ? [10] : [5] [5]: TryGetValue(C2): (Item1, ReturnItem) t4 = t0; [6] [6]: t4.ReturnItem == True ? [7] : [13] [7]: t5 = (C2)t4.Item1; [8] [8]: t6 = t5.F2; [9] [9]: t6 == 2 ? [10] : [13] [10]: t7 = t2.F12; [11] [11]: t7 == 3 ? [12] : [13] [12]: leaf <isPatternFailure> `(C1 { F11: 1 } or C2 { F2: 2 }) and C1 { F12: 3 }` [13]: leaf <isPatternSuccess> `u is not ((C1 { F11: 1 } or C2 { F2: 2 }) and C1 { F12: 3 })` ", forLowering: true); var verifier = CompileAndVerify(comp, expectedOutput: @" TryGetValue(C1) True TryGetValue(C1) True TryGetValue(C1) False TryGetValue(C1) TryGetValue(C2) True TryGetValue(C1) TryGetValue(C2) True TryGetValue(C1) True TryGetValue(C1) False TryGetValue(C1) TryGetValue(C2) True TryGetValue(C1) TryGetValue(C2) True TryGetValue(C1) True TryGetValue(C1) False TryGetValue(C1) TryGetValue(C2) False TryGetValue(C1) TryGetValue(C2) True ").VerifyDiagnostics(); verifier.VerifyIL("S1.Test1", @" { // Code size 62 (0x3e) .maxstack 2 .locals init (C1 V_0, C1 V_1, C2 V_2, bool V_3) IL_0000: ldarga.s V_0 IL_0002: ldloca.s V_0 IL_0004: call ""bool S1.TryGetValue(out C1)"" IL_0009: brfalse.s IL_0037 IL_000b: ldloc.0 IL_000c: stloc.1 IL_000d: ldloc.1 IL_000e: ldfld ""int C1.F11"" IL_0013: ldc.i4.1 IL_0014: beq.s IL_002a IL_0016: ldarga.s V_0 IL_0018: ldloca.s V_2 IL_001a: call ""bool S1.TryGetValue(out C2)"" IL_001f: brfalse.s IL_0037 IL_0021: ldloc.2 IL_0022: ldfld ""int C2.F2"" IL_0027: ldc.i4.2 IL_0028: bne.un.s IL_0037 IL_002a: ldloc.1 IL_002b: ldfld ""int C1.F12"" IL_0030: ldc.i4.3 IL_0031: bne.un.s IL_0037 IL_0033: ldc.i4.1 IL_0034: stloc.3 IL_0035: br.s IL_0039 IL_0037: ldc.i4.0 IL_0038: stloc.3 IL_0039: ldloc.3 IL_003a: ldc.i4.0 IL_003b: ceq IL_003d: ret } "); } [Fact] public void NonBoxingUnionMatching_60_TryGetValue() { var src = @" class C1(int f1, int f2) { public int F11 = f1; public int F12 = f2; } class C2(int f11, int f12, int f2) : C1(f11, f12) { public int F2 = f2; } class C3(int f1, int f2) : C1(f1, f2) { } [System.Runtime.CompilerServices.Union] struct S1 { private readonly object _value; public S1(C1 x) { _value = x; } public S1(C2 x) { _value = x; } public S1(C3 x) { _value = x; } public object Value { get { System.Console.Write(""get_Value ""); return _value; } } public bool TryGetValue(out C1 x) { System.Console.Write(""TryGetValue(C1) ""); x = _value as C1; return x != null; } public bool TryGetValue(out C2 x) { System.Console.Write(""TryGetValue(C2) ""); x = _value as C2; return x != null; } public bool TryGetValue(out C3 x) { System.Console.Write(""TryGetValue(C3) ""); x = _value as C3; return x != null; } static void Main() { S1[] s = [new S1(), new S1(new C3(1, 1)), new S1(new C3(1, 3)), new S1(new C3(2, 3)), new S1(new C3(2, 4)), new S1(new C2(1, 1, 1)), new S1(new C2(1, 3, 1)), new S1(new C2(2, 3, 1)), new S1(new C2(2, 4, 1)), new S1(new C2(1, 1, 2)), new S1(new C2(1, 3, 2)), new S1(new C2(2, 3, 2)), new S1(new C2(2, 4, 2))]; foreach (var s1 in s) { var t = Test1(s1); System.Console.WriteLine(); System.Console.WriteLine(t); } } static bool Test1(S1 u) { return u is not ((C2 { F2: 2 } or C1 { F11: 1 }) and C1 { F12: 3 }); } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); VerifyDecisionDagDump<IsPatternExpressionSyntax>(comp, @"[0]: TryGetValue(C2): (Item1, ReturnItem) t1 = t0; [1] [1]: t1.ReturnItem == True ? [2] : [11] [2]: t2 = (C2)t1.Item1; [3] [3]: t3 = t2.F2; [4] [4]: t3 == 2 ? [5] : [6] [5]: t4 = (C1)t1.Item1; [10] [6]: t4 = (C1)t1.Item1; [7] [7]: PassThrough t4; [8] [8]: t6 = t4.F11; [9] [9]: t6 == 1 ? [10] : [19] [10]: PassThrough t4; [16] [11]: TryGetValue(C1): (Item1, ReturnItem) t7 = t0; [12] [12]: t7.ReturnItem == True ? [13] : [19] [13]: t4 = (C1)t7.Item1; [14] [14]: t6 = t4.F11; [15] [15]: t6 == 1 ? [16] : [19] [16]: t8 = t4.F12; [17] [17]: t8 == 3 ? [18] : [19] [18]: leaf <isPatternFailure> `(C2 { F2: 2 } or C1 { F11: 1 }) and C1 { F12: 3 }` [19]: leaf <isPatternSuccess> `u is not ((C2 { F2: 2 } or C1 { F11: 1 }) and C1 { F12: 3 })` ", forLowering: true); var verifier = CompileAndVerify(comp, expectedOutput: @" TryGetValue(C2) TryGetValue(C1) True TryGetValue(C2) TryGetValue(C1) True TryGetValue(C2) TryGetValue(C1) False TryGetValue(C2) TryGetValue(C1) True TryGetValue(C2) TryGetValue(C1) True TryGetValue(C2) True TryGetValue(C2) False TryGetValue(C2) True TryGetValue(C2) True TryGetValue(C2) True TryGetValue(C2) False TryGetValue(C2) False TryGetValue(C2) True ").VerifyDiagnostics(); verifier.VerifyIL("S1.Test1", @" { // Code size 79 (0x4f) .maxstack 2 .locals init (C2 V_0, C1 V_1, C1 V_2, bool V_3) IL_0000: ldarga.s V_0 IL_0002: ldloca.s V_0 IL_0004: call ""bool S1.TryGetValue(out C2)"" IL_0009: brfalse.s IL_0025 IL_000b: ldloc.0 IL_000c: ldfld ""int C2.F2"" IL_0011: ldc.i4.2 IL_0012: bne.un.s IL_0018 IL_0014: ldloc.0 IL_0015: stloc.1 IL_0016: br.s IL_003b IL_0018: ldloc.0 IL_0019: stloc.1 IL_001a: ldloc.1 IL_001b: ldfld ""int C1.F11"" IL_0020: ldc.i4.1 IL_0021: bne.un.s IL_0048 IL_0023: br.s IL_003b IL_0025: ldarga.s V_0 IL_0027: ldloca.s V_2 IL_0029: call ""bool S1.TryGetValue(out C1)"" IL_002e: brfalse.s IL_0048 IL_0030: ldloc.2 IL_0031: stloc.1 IL_0032: ldloc.1 IL_0033: ldfld ""int C1.F11"" IL_0038: ldc.i4.1 IL_0039: bne.un.s IL_0048 IL_003b: ldloc.1 IL_003c: ldfld ""int C1.F12"" IL_0041: ldc.i4.3 IL_0042: bne.un.s IL_0048 IL_0044: ldc.i4.1 IL_0045: stloc.3 IL_0046: br.s IL_004a IL_0048: ldc.i4.0 IL_0049: stloc.3 IL_004a: ldloc.3 IL_004b: ldc.i4.0 IL_004c: ceq IL_004e: ret } "); } [Fact] public void NonBoxingUnionMatching_61_TryGetValue() { var src = @" class C1(int f1, int f2) { public int F11 = f1; public int F12 = f2; } class C2(int f11, int f12, int f2) : C1(f11, f12) { public int F2 = f2; } class C3(int f1, int f2) : C1(f1, f2) { } [System.Runtime.CompilerServices.Union] struct S1 { private readonly object _value; public S1(C1 x) { _value = x; } public S1(C2 x) { _value = x; } public S1(C3 x) { _value = x; } public object Value { get { System.Console.Write(""get_Value ""); return _value; } } public bool TryGetValue(out C2 x) { System.Console.Write(""TryGetValue(C2) ""); x = _value as C2; return x != null; } public bool TryGetValue(out C3 x) { System.Console.Write(""TryGetValue(C3) ""); x = _value as C3; return x != null; } static void Main() { S1[] s = [new S1(), new S1(new C3(1, 1)), new S1(new C3(1, 3)), new S1(new C3(2, 3)), new S1(new C3(2, 4)), new S1(new C2(1, 1, 1)), new S1(new C2(1, 3, 1)), new S1(new C2(2, 3, 1)), new S1(new C2(2, 4, 1)), new S1(new C2(1, 1, 2)), new S1(new C2(1, 3, 2)), new S1(new C2(2, 3, 2)), new S1(new C2(2, 4, 2))]; foreach (var s1 in s) { var t = Test1(s1); System.Console.WriteLine(); System.Console.WriteLine(t); } } static bool Test1(S1 u) { return u is not ((C1 { F11: 1 } or C2 { F2: 2 }) and C1 { F12: 3 }); } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); VerifyDecisionDagDump<IsPatternExpressionSyntax>(comp, @"[0]: t1 = t0.Value; [1] [1]: t1 is C1 ? [2] : [13] [2]: t2 = (C1)t1; [3] [3]: t3 = t2.F11; [4] [4]: t3 == 1 ? [10] : [5] [5]: TryGetValue(C2): (Item1, ReturnItem) t4 = t0; [6] [6]: t4.ReturnItem == True ? [7] : [13] [7]: t5 = (C2)t4.Item1; [8] [8]: t6 = t5.F2; [9] [9]: t6 == 2 ? [10] : [13] [10]: t7 = t2.F12; [11] [11]: t7 == 3 ? [12] : [13] [12]: leaf <isPatternFailure> `(C1 { F11: 1 } or C2 { F2: 2 }) and C1 { F12: 3 }` [13]: leaf <isPatternSuccess> `u is not ((C1 { F11: 1 } or C2 { F2: 2 }) and C1 { F12: 3 })` ", forLowering: true); var verifier = CompileAndVerify(comp, expectedOutput: @" get_Value True get_Value True get_Value False get_Value TryGetValue(C2) True get_Value TryGetValue(C2) True get_Value True get_Value False get_Value TryGetValue(C2) True get_Value TryGetValue(C2) True get_Value True get_Value False get_Value TryGetValue(C2) False get_Value TryGetValue(C2) True ").VerifyDiagnostics(); verifier.VerifyIL("S1.Test1", @" { // Code size 65 (0x41) .maxstack 2 .locals init (C1 V_0, C2 V_1, bool V_2) IL_0000: ldarga.s V_0 IL_0002: call ""object S1.Value.get"" IL_0007: isinst ""C1"" IL_000c: stloc.0 IL_000d: ldloc.0 IL_000e: brfalse.s IL_003a IL_0010: ldloc.0 IL_0011: ldfld ""int C1.F11"" IL_0016: ldc.i4.1 IL_0017: beq.s IL_002d IL_0019: ldarga.s V_0 IL_001b: ldloca.s V_1 IL_001d: call ""bool S1.TryGetValue(out C2)"" IL_0022: brfalse.s IL_003a IL_0024: ldloc.1 IL_0025: ldfld ""int C2.F2"" IL_002a: ldc.i4.2 IL_002b: bne.un.s IL_003a IL_002d: ldloc.0 IL_002e: ldfld ""int C1.F12"" IL_0033: ldc.i4.3 IL_0034: bne.un.s IL_003a IL_0036: ldc.i4.1 IL_0037: stloc.2 IL_0038: br.s IL_003c IL_003a: ldc.i4.0 IL_003b: stloc.2 IL_003c: ldloc.2 IL_003d: ldc.i4.0 IL_003e: ceq IL_0040: ret } "); } [Fact] public void NonBoxingUnionMatching_62_TryGetValue() { var src = @" class C1(int f1, int f2) { public int F11 = f1; public int F12 = f2; } class C2(int f11, int f12, int f2) : C1(f11, f12) { public int F2 = f2; } class C3(int f1, int f2) : C1(f1, f2) { } [System.Runtime.CompilerServices.Union] struct S1 { private readonly object _value; public S1(C1 x) { _value = x; } public S1(C2 x) { _value = x; } public S1(C3 x) { _value = x; } public object Value { get { System.Console.Write(""get_Value ""); return _value; } } public bool TryGetValue(out C2 x) { System.Console.Write(""TryGetValue(C2) ""); x = _value as C2; return x != null; } public bool TryGetValue(out C3 x) { System.Console.Write(""TryGetValue(C3) ""); x = _value as C3; return x != null; } static void Main() { S1[] s = [new S1(), new S1(new C3(1, 1)), new S1(new C3(1, 3)), new S1(new C3(2, 3)), new S1(new C3(2, 4)), new S1(new C2(1, 1, 1)), new S1(new C2(1, 3, 1)), new S1(new C2(2, 3, 1)), new S1(new C2(2, 4, 1)), new S1(new C2(1, 1, 2)), new S1(new C2(1, 3, 2)), new S1(new C2(2, 3, 2)), new S1(new C2(2, 4, 2))]; foreach (var s1 in s) { var t = Test1(s1); System.Console.WriteLine(); System.Console.WriteLine(t); } } static bool Test1(S1 u) { return u is not ((C2 { F2: 2 } or C1 { F11: 1 }) and C1 { F12: 3 }); } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); VerifyDecisionDagDump<IsPatternExpressionSyntax>(comp, @"[0]: TryGetValue(C2): (Item1, ReturnItem) t1 = t0; [1] [1]: t1.ReturnItem == True ? [2] : [11] [2]: t2 = (C2)t1.Item1; [3] [3]: t3 = t2.F2; [4] [4]: t3 == 2 ? [5] : [6] [5]: t4 = (C1)t1.Item1; [10] [6]: t4 = (C1)t1.Item1; [7] [7]: PassThrough t4; [8] [8]: t6 = t4.F11; [9] [9]: t6 == 1 ? [10] : [19] [10]: PassThrough t4; [16] [11]: t7 = t0.Value; [12] [12]: t7 is C1 ? [13] : [19] [13]: t4 = (C1)t7; [14] [14]: t6 = t4.F11; [15] [15]: t6 == 1 ? [16] : [19] [16]: t8 = t4.F12; [17] [17]: t8 == 3 ? [18] : [19] [18]: leaf <isPatternFailure> `(C2 { F2: 2 } or C1 { F11: 1 }) and C1 { F12: 3 }` [19]: leaf <isPatternSuccess> `u is not ((C2 { F2: 2 } or C1 { F11: 1 }) and C1 { F12: 3 })` ", forLowering: true); var verifier = CompileAndVerify(comp, expectedOutput: @" TryGetValue(C2) get_Value True TryGetValue(C2) get_Value True TryGetValue(C2) get_Value False TryGetValue(C2) get_Value True TryGetValue(C2) get_Value True TryGetValue(C2) True TryGetValue(C2) False TryGetValue(C2) True TryGetValue(C2) True TryGetValue(C2) True TryGetValue(C2) False TryGetValue(C2) False TryGetValue(C2) True ").VerifyDiagnostics(); verifier.VerifyIL("S1.Test1", @" { // Code size 82 (0x52) .maxstack 2 .locals init (C2 V_0, C1 V_1, bool V_2) IL_0000: ldarga.s V_0 IL_0002: ldloca.s V_0 IL_0004: call ""bool S1.TryGetValue(out C2)"" IL_0009: brfalse.s IL_0025 IL_000b: ldloc.0 IL_000c: ldfld ""int C2.F2"" IL_0011: ldc.i4.2 IL_0012: bne.un.s IL_0018 IL_0014: ldloc.0 IL_0015: stloc.1 IL_0016: br.s IL_003e IL_0018: ldloc.0 IL_0019: stloc.1 IL_001a: ldloc.1 IL_001b: ldfld ""int C1.F11"" IL_0020: ldc.i4.1 IL_0021: bne.un.s IL_004b IL_0023: br.s IL_003e IL_0025: ldarga.s V_0 IL_0027: call ""object S1.Value.get"" IL_002c: isinst ""C1"" IL_0031: stloc.1 IL_0032: ldloc.1 IL_0033: brfalse.s IL_004b IL_0035: ldloc.1 IL_0036: ldfld ""int C1.F11"" IL_003b: ldc.i4.1 IL_003c: bne.un.s IL_004b IL_003e: ldloc.1 IL_003f: ldfld ""int C1.F12"" IL_0044: ldc.i4.3 IL_0045: bne.un.s IL_004b IL_0047: ldc.i4.1 IL_0048: stloc.2 IL_0049: br.s IL_004d IL_004b: ldc.i4.0 IL_004c: stloc.2 IL_004d: ldloc.2 IL_004e: ldc.i4.0 IL_004f: ceq IL_0051: ret } "); } [Fact] public void NonBoxingUnionMatching_63_TryGetValue() { var src = @" class C1(int f1, int f2) { public int F11 = f1; public int F12 = f2; } class C2(int f11, int f12, int f2) : C1(f11, f12) { public int F2 = f2; } class C3(int f1, int f2) : C1(f1, f2) { } [System.Runtime.CompilerServices.Union] struct S1 { private readonly object _value; public S1(C1 x) { _value = x; } public S1(C2 x) { _value = x; } public S1(C3 x) { _value = x; } public object Value { get { System.Console.Write(""get_Value ""); return _value; } } public bool TryGetValue(out C1 x) { System.Console.Write(""TryGetValue(C1) ""); x = _value as C1; return x != null; } public bool TryGetValue(out C3 x) { System.Console.Write(""TryGetValue(C3) ""); x = _value as C3; return x != null; } static void Main() { S1[] s = [new S1(), new S1(new C3(1, 1)), new S1(new C3(1, 3)), new S1(new C3(2, 3)), new S1(new C3(2, 4)), new S1(new C2(1, 1, 1)), new S1(new C2(1, 3, 1)), new S1(new C2(2, 3, 1)), new S1(new C2(2, 4, 1)), new S1(new C2(1, 1, 2)), new S1(new C2(1, 3, 2)), new S1(new C2(2, 3, 2)), new S1(new C2(2, 4, 2))]; foreach (var s1 in s) { var t = Test1(s1); System.Console.WriteLine(); System.Console.WriteLine(t); } } static bool Test1(S1 u) { return u is not ((C1 { F11: 1 } or C2 { F2: 2 }) and C1 { F12: 3 }); } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); VerifyDecisionDagDump<IsPatternExpressionSyntax>(comp, @"[0]: TryGetValue(C1): (Item1, ReturnItem) t1 = t0; [1] [1]: t1.ReturnItem == True ? [2] : [12] [2]: t2 = (C1)t1.Item1; [3] [3]: t3 = t2.F11; [4] [4]: t3 == 1 ? [9] : [5] [5]: t2 is C2 ? [6] : [12] [6]: t4 = (C2)t2; [7] [7]: t5 = t4.F2; [8] [8]: t5 == 2 ? [9] : [12] [9]: t6 = t2.F12; [10] [10]: t6 == 3 ? [11] : [12] [11]: leaf <isPatternFailure> `(C1 { F11: 1 } or C2 { F2: 2 }) and C1 { F12: 3 }` [12]: leaf <isPatternSuccess> `u is not ((C1 { F11: 1 } or C2 { F2: 2 }) and C1 { F12: 3 })` ", forLowering: true); var verifier = CompileAndVerify(comp, expectedOutput: @" TryGetValue(C1) True TryGetValue(C1) True TryGetValue(C1) False TryGetValue(C1) True TryGetValue(C1) True TryGetValue(C1) True TryGetValue(C1) False TryGetValue(C1) True TryGetValue(C1) True TryGetValue(C1) True TryGetValue(C1) False TryGetValue(C1) False TryGetValue(C1) True ").VerifyDiagnostics(); verifier.VerifyIL("S1.Test1", @" { // Code size 61 (0x3d) .maxstack 2 .locals init (C1 V_0, C1 V_1, C2 V_2, bool V_3) IL_0000: ldarga.s V_0 IL_0002: ldloca.s V_0 IL_0004: call ""bool S1.TryGetValue(out C1)"" IL_0009: brfalse.s IL_0036 IL_000b: ldloc.0 IL_000c: stloc.1 IL_000d: ldloc.1 IL_000e: ldfld ""int C1.F11"" IL_0013: ldc.i4.1 IL_0014: beq.s IL_0029 IL_0016: ldloc.1 IL_0017: isinst ""C2"" IL_001c: stloc.2 IL_001d: ldloc.2 IL_001e: brfalse.s IL_0036 IL_0020: ldloc.2 IL_0021: ldfld ""int C2.F2"" IL_0026: ldc.i4.2 IL_0027: bne.un.s IL_0036 IL_0029: ldloc.1 IL_002a: ldfld ""int C1.F12"" IL_002f: ldc.i4.3 IL_0030: bne.un.s IL_0036 IL_0032: ldc.i4.1 IL_0033: stloc.3 IL_0034: br.s IL_0038 IL_0036: ldc.i4.0 IL_0037: stloc.3 IL_0038: ldloc.3 IL_0039: ldc.i4.0 IL_003a: ceq IL_003c: ret } "); } [Fact] public void NonBoxingUnionMatching_64_TryGetValue() { var src = @" class C1(int f1, int f2) { public int F11 = f1; public int F12 = f2; } class C2(int f11, int f12, int f2) : C1(f11, f12) { public int F2 = f2; } class C3(int f1, int f2) : C1(f1, f2) { } [System.Runtime.CompilerServices.Union] struct S1 { private readonly object _value; public S1(C1 x) { _value = x; } public S1(C2 x) { _value = x; } public S1(C3 x) { _value = x; } public object Value { get { System.Console.Write(""get_Value ""); return _value; } } public bool TryGetValue(out C1 x) { System.Console.Write(""TryGetValue(C1) ""); x = _value as C1; return x != null; } public bool TryGetValue(out C3 x) { System.Console.Write(""TryGetValue(C3) ""); x = _value as C3; return x != null; } static void Main() { S1[] s = [new S1(), new S1(new C3(1, 1)), new S1(new C3(1, 3)), new S1(new C3(2, 3)), new S1(new C3(2, 4)), new S1(new C2(1, 1, 1)), new S1(new C2(1, 3, 1)), new S1(new C2(2, 3, 1)), new S1(new C2(2, 4, 1)), new S1(new C2(1, 1, 2)), new S1(new C2(1, 3, 2)), new S1(new C2(2, 3, 2)), new S1(new C2(2, 4, 2))]; foreach (var s1 in s) { var t = Test1(s1); System.Console.WriteLine(); System.Console.WriteLine(t); } } static bool Test1(S1 u) { return u is not ((C2 { F2: 2 } or C1 { F11: 1 }) and C1 { F12: 3 }); } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); VerifyDecisionDagDump<IsPatternExpressionSyntax>(comp, @"[0]: TryGetValue(C1): (Item1, ReturnItem) t1 = t0; [1] [1]: t1.ReturnItem == True ? [2] : [12] [2]: t2 = (C1)t1.Item1; [3] [3]: t2 is C2 ? [4] : [7] [4]: t3 = (C2)t2; [5] [5]: t4 = t3.F2; [6] [6]: t4 == 2 ? [9] : [7] [7]: t5 = t2.F11; [8] [8]: t5 == 1 ? [9] : [12] [9]: t6 = t2.F12; [10] [10]: t6 == 3 ? [11] : [12] [11]: leaf <isPatternFailure> `(C2 { F2: 2 } or C1 { F11: 1 }) and C1 { F12: 3 }` [12]: leaf <isPatternSuccess> `u is not ((C2 { F2: 2 } or C1 { F11: 1 }) and C1 { F12: 3 })` ", forLowering: true); var verifier = CompileAndVerify(comp, expectedOutput: @" TryGetValue(C1) True TryGetValue(C1) True TryGetValue(C1) False TryGetValue(C1) True TryGetValue(C1) True TryGetValue(C1) True TryGetValue(C1) False TryGetValue(C1) True TryGetValue(C1) True TryGetValue(C1) True TryGetValue(C1) False TryGetValue(C1) False TryGetValue(C1) True ").VerifyDiagnostics(); verifier.VerifyIL("S1.Test1", @" { // Code size 61 (0x3d) .maxstack 2 .locals init (C1 V_0, C1 V_1, C2 V_2, bool V_3) IL_0000: ldarga.s V_0 IL_0002: ldloca.s V_0 IL_0004: call ""bool S1.TryGetValue(out C1)"" IL_0009: brfalse.s IL_0036 IL_000b: ldloc.0 IL_000c: stloc.1 IL_000d: ldloc.1 IL_000e: isinst ""C2"" IL_0013: stloc.2 IL_0014: ldloc.2 IL_0015: brfalse.s IL_0020 IL_0017: ldloc.2 IL_0018: ldfld ""int C2.F2"" IL_001d: ldc.i4.2 IL_001e: beq.s IL_0029 IL_0020: ldloc.1 IL_0021: ldfld ""int C1.F11"" IL_0026: ldc.i4.1 IL_0027: bne.un.s IL_0036 IL_0029: ldloc.1 IL_002a: ldfld ""int C1.F12"" IL_002f: ldc.i4.3 IL_0030: bne.un.s IL_0036 IL_0032: ldc.i4.1 IL_0033: stloc.3 IL_0034: br.s IL_0038 IL_0036: ldc.i4.0 IL_0037: stloc.3 IL_0038: ldloc.3 IL_0039: ldc.i4.0 IL_003a: ceq IL_003c: ret } "); } [Fact] public void NonBoxingUnionMatching_65_TryGetValue() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 { private readonly object _value; public S1(int x) { _value = x; } public S1(System.Runtime.CompilerServices.ITuple x) { _value = x; } public object Value { get { System.Console.Write(""get_Value ""); return _value; } } public bool TryGetValue(out System.Runtime.CompilerServices.ITuple x) { System.Console.Write(""TryGetValue(ITuple) ""); x = _value as System.Runtime.CompilerServices.ITuple; return x != null; } } class Program { static void Main() { System.Console.Write(Test1(new S1(10))); System.Console.Write(' '); System.Console.Write(Test1(default)); System.Console.Write(' '); System.Console.Write(Test1(new S1(new C()))); } static bool Test1(S1 u) { return u is (_, 10); } } public class C : System.Runtime.CompilerServices.ITuple { int System.Runtime.CompilerServices.ITuple.Length => 2; object System.Runtime.CompilerServices.ITuple.this[int i] => i * 10; } "; var comp = CreateCompilation([src, UnionAttributeSource], targetFramework: TargetFramework.NetCoreApp, options: TestOptions.ReleaseExe); comp.VerifyDiagnostics( // (38,21): error CS1061: 'S1' does not contain a definition for 'Deconstruct' and no accessible extension method 'Deconstruct' accepting a first argument of type 'S1' could be found (are you missing a using directive or an assembly reference?) // return u is (_, 10); Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "(_, 10)").WithArguments("S1", "Deconstruct").WithLocation(38, 21), // (38,21): error CS8129: No suitable 'Deconstruct' instance or extension method was found for type 'S1', with 2 out parameters and a void return type. // return u is (_, 10); Diagnostic(ErrorCode.ERR_MissingDeconstruct, "(_, 10)").WithArguments("S1", "2").WithLocation(38, 21) ); } [Fact] public void NonBoxingUnionMatching_66_TryGetValue() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 { private readonly object _value; public S1(S2<int> x) { _value = x; } public S1(S2<string> x) { _value = x; } public S1(S2<object> x) { _value = x; } public object Value { get { System.Console.Write(""get_Value ""); return _value; } } public bool TryGetValue(out S2<int> x) { System.Console.Write(""TryGetValue(S2<int>) ""); if (_value is S2<int> s2) { x = s2; return true; } x = default; return false; } public bool TryGetValue(out S2<string> x) { System.Console.Write(""TryGetValue(S2<string>) ""); if (_value is S2<string> s2) { x = s2; return true; } x = default; return false; } public bool TryGetValue(out S2<object> x) { System.Console.Write(""TryGetValue(S2<object>) ""); if (_value is S2<object> s2) { x = s2; return true; } x = default; return false; } } struct S2<T> { public T Value; public void Deconstruct(out T value, out int x) { value = Value; x = 0; } } class A; class B; class Program { static void Main() { System.Console.Write(Test1(new S1(new S2<int>() { Value = 10 }))); System.Console.Write(' '); System.Console.Write(Test1(default)); System.Console.Write(' '); System.Console.Write(Test1(new S1(new S2<string>() { Value = ""11"" }))); System.Console.Write(' '); System.Console.Write(Test1(new S1(new S2<int>() { Value = 0 }))); System.Console.Write(' '); System.Console.Write(' '); System.Console.Write(Test2(new S1(new S2<int>() { Value = 10 }))); System.Console.Write(' '); System.Console.Write(Test2(default)); System.Console.Write(' '); System.Console.Write(Test2(new S1(new S2<string>() { Value = ""11"" }))); System.Console.Write(' '); System.Console.Write(Test2(new S1(new S2<int>() { Value = 0 }))); System.Console.Write(' '); System.Console.Write(Test2(new S1(new S2<int>() { Value = 11 }))); System.Console.Write(' '); System.Console.Write(' '); System.Console.Write(Test3(new S1(new S2<int>() { Value = 11 }))); System.Console.Write(' '); System.Console.Write(Test3(default)); System.Console.Write(' '); System.Console.Write(Test3(new S1(new S2<string>() { Value = ""11"" }))); } static bool Test1(S1 u) { return u is S2<int> (10, _); } static bool Test2(S1 u) { return u is S2<int> (10 or 11, _); } static bool Test3(S1 u) { return u is S2<string> (""11"", _) and (['1', '1'], _); } } "; var comp = CreateCompilation([src, UnionAttributeSource], targetFramework: TargetFramework.NetCoreApp, options: TestOptions.ReleaseExe); CompileAndVerify( comp, expectedOutput: ExecutionConditionUtil.IsMonoOrCoreClr ? "TryGetValue(S2<int>) True TryGetValue(S2<int>) False TryGetValue(S2<int>) False TryGetValue(S2<int>) False TryGetValue(S2<int>) True TryGetValue(S2<int>) False TryGetValue(S2<int>) False TryGetValue(S2<int>) False TryGetValue(S2<int>) True TryGetValue(S2<string>) False TryGetValue(S2<string>) False TryGetValue(S2<string>) True" : null, verify: Verification.FailsPEVerify).VerifyDiagnostics(); } [Fact] public void NonBoxingUnionMatching_67_TryGetValue() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } public object Value { get { System.Console.Write(""get_Value ""); return _value; } } public bool TryGetValue(out int x) { System.Console.Write(""TryGetValue(int) ""); if (_value is int s2) { x = s2; return true; } x = default; return false; } } class Program { static void Main() { System.Console.Write(Test1(new S1(10))); System.Console.Write(' '); System.Console.Write(Test1(default)); System.Console.Write(' '); System.Console.Write(Test1(new S1(""11""))); System.Console.Write(' '); System.Console.Write(Test1(new S1(0))); System.Console.Write(' '); System.Console.Write(' '); System.Console.Write(Test2(new S1(10))); System.Console.Write(' '); System.Console.Write(Test2(default)); System.Console.Write(' '); System.Console.Write(Test2(new S1(""11""))); System.Console.Write(' '); System.Console.Write(Test2(new S1(0))); System.Console.Write(' '); System.Console.Write(Test2(new S1(11))); } static bool Test1(S1 u) { return u is int x; } static bool Test2(S1 u) { return u is int x ? (x == 10 || x == 11) : false; } } "; var comp = CreateCompilation([src, UnionAttributeSource], targetFramework: TargetFramework.NetLatest, options: TestOptions.ReleaseExe); CompileAndVerify( comp, expectedOutput: "TryGetValue(int) True TryGetValue(int) False TryGetValue(int) False TryGetValue(int) True TryGetValue(int) True TryGetValue(int) False TryGetValue(int) False TryGetValue(int) False TryGetValue(int) True" ).VerifyDiagnostics(); } [Fact] public void NonBoxingUnionMatching_68_TryGetValue() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } public object Value { get { System.Console.Write(""get_Value ""); return _value; } } public bool TryGetValue(out int x) { System.Console.Write(""TryGetValue(int) ""); if (_value is int s2) { x = s2; return true; } x = default; return false; } } class Program { static void Main() { System.Console.Write(Test1(new S1(10))); System.Console.Write(' '); System.Console.Write(Test1(default)); System.Console.Write(' '); System.Console.Write(Test1(new S1(""11""))); System.Console.Write(' '); System.Console.Write(Test1(new S1(0))); System.Console.Write(' '); System.Console.Write(' '); System.Console.Write(Test2(new S1(10))); System.Console.Write(' '); System.Console.Write(Test2(default)); System.Console.Write(' '); System.Console.Write(Test2(new S1(""11""))); System.Console.Write(' '); System.Console.Write(Test2(new S1(0))); System.Console.Write(' '); System.Console.Write(Test2(new S1(11))); } static bool Test1(S1 u) { return u is >=10; } static bool Test2(S1 u) { return u is <10 or 11; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); CompileAndVerify( comp, expectedOutput: "TryGetValue(int) True TryGetValue(int) False TryGetValue(int) False TryGetValue(int) False TryGetValue(int) False TryGetValue(int) False TryGetValue(int) False TryGetValue(int) True TryGetValue(int) True" ).VerifyDiagnostics(); } [Fact] public void NonBoxingUnionMatching_69_TryGetValue_NullableAnalysis() { var src = @" #nullable enable [System.Runtime.CompilerServices.Union] struct S1 { public S1(string? x) => throw null!; public S1(bool? x) => throw null!; public object? Value => throw null!; public bool TryGetValue(out string? x) => throw null!; } class Program { static void Test2(S1 s) { if (s.TryGetValue(out var value)) { #line 100 value.ToString(); _ = s switch { string => 1, bool => 3 }; } else { #line 200 value.ToString(); _ = s switch { string => 1, bool => 3 }; } } static void Test4(S1 s) { if (!s.TryGetValue(out var value)) { #line 300 value.ToString(); _ = s switch { string => 1, bool => 3 }; } else { #line 400 value.ToString(); _ = s switch { string => 1, bool => 3 }; } } } "; var comp = CreateCompilation([src, UnionAttributeSource]); comp.VerifyDiagnostics( // (200,13): warning CS8602: Dereference of a possibly null reference. // value.ToString(); Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "value").WithLocation(200, 13), // (201,19): warning CS8655: The switch expression does not handle some null inputs (it is not exhaustive). For example, the pattern 'null' is not covered. // _ = s switch { string => 1, bool => 3 }; Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustiveForNull, "switch").WithArguments("null").WithLocation(201, 19), // (300,13): warning CS8602: Dereference of a possibly null reference. // value.ToString(); Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "value").WithLocation(300, 13), // (301,19): warning CS8655: The switch expression does not handle some null inputs (it is not exhaustive). For example, the pattern 'null' is not covered. // _ = s switch { string => 1, bool => 3 }; Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustiveForNull, "switch").WithArguments("null").WithLocation(301, 19) ); } [Fact] public void NonBoxingUnionMatching_70_TryGetValue_NullableAnalysis() { var src = @" #nullable enable [System.Runtime.CompilerServices.Union] struct S1 { public S1(string? x) => throw null!; public S1(bool? x) => throw null!; public object? Value => throw null!; public bool TryGetValue(out string? x) => throw null!; } class Program { static void Test2(S1 s) { if (s.Value is null) return; if (s.TryGetValue(out var value)) { #line 100 value.ToString(); _ = s switch { string => 1, bool => 3 }; } else { #line 200 value.ToString(); _ = s switch { string => 1, bool => 3 }; } } static void Test4(S1 s) { if (s.Value is null) return; if (!s.TryGetValue(out var value)) { #line 300 value.ToString(); _ = s switch { string => 1, bool => 3 }; } else { #line 400 value.ToString(); _ = s switch { string => 1, bool => 3 }; } } } "; var comp = CreateCompilation([src, UnionAttributeSource]); comp.VerifyDiagnostics( // (200,13): warning CS8602: Dereference of a possibly null reference. // value.ToString(); Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "value").WithLocation(200, 13), // (300,13): warning CS8602: Dereference of a possibly null reference. // value.ToString(); Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "value").WithLocation(300, 13) ); } [Fact] public void NonBoxingUnionMatching_71_TryGetValue_NullableAnalysis() { var src = @" #nullable enable [System.Runtime.CompilerServices.Union] struct S1 { public S1(string? x) => throw null!; public S1(bool? x) => throw null!; public object? Value => throw null!; [System.Diagnostics.CodeAnalysis.MemberNotNullWhen(true, nameof(Value))] public bool TryGetValue([System.Diagnostics.CodeAnalysis.NotNullWhen(true)]out string? x) => throw null!; } class Program { static void Test2(S1 s) { if (s.TryGetValue(out var value)) { #line 100 value.ToString(); _ = s switch { string => 1, bool => 3 }; } else { #line 200 value.ToString(); _ = s switch { string => 1, bool => 3 }; } } static void Test4(S1 s) { if (!s.TryGetValue(out var value)) { #line 300 value.ToString(); _ = s switch { string => 1, bool => 3 }; } else { #line 400 value.ToString(); _ = s switch { string => 1, bool => 3 }; } } } "; var comp = CreateCompilation([src, UnionAttributeSource, MemberNotNullWhenAttributeDefinition, NotNullWhenAttributeDefinition]); comp.VerifyDiagnostics( // (200,13): warning CS8602: Dereference of a possibly null reference. // value.ToString(); Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "value").WithLocation(200, 13), // (201,19): warning CS8655: The switch expression does not handle some null inputs (it is not exhaustive). For example, the pattern 'null' is not covered. // _ = s switch { string => 1, bool => 3 }; Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustiveForNull, "switch").WithArguments("null").WithLocation(201, 19), // (300,13): warning CS8602: Dereference of a possibly null reference. // value.ToString(); Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "value").WithLocation(300, 13), // (301,19): warning CS8655: The switch expression does not handle some null inputs (it is not exhaustive). For example, the pattern 'null' is not covered. // _ = s switch { string => 1, bool => 3 }; Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustiveForNull, "switch").WithArguments("null").WithLocation(301, 19) ); } [Fact] public void NonBoxingUnionMatching_72_TryGetValue_NullableAnalysis() { var src = @" #nullable enable [System.Runtime.CompilerServices.Union] struct S1 { public S1(string? x) => throw null!; public S1(bool? x) => throw null!; public object? Value => throw null!; [System.Diagnostics.CodeAnalysis.MemberNotNullWhen(true, nameof(Value))] public bool TryGetValue([System.Diagnostics.CodeAnalysis.NotNullWhen(true)]out string? x) => throw null!; } class Program { static void Test2(S1 s) { if (s.Value is null) return; if (s.TryGetValue(out var value)) { #line 100 value.ToString(); _ = s switch { string => 1, bool => 3 }; } else { #line 200 value.ToString(); _ = s switch { string => 1, bool => 3 }; } } static void Test4(S1 s) { if (s.Value is null) return; if (!s.TryGetValue(out var value)) { #line 300 value.ToString(); _ = s switch { string => 1, bool => 3 }; } else { #line 400 value.ToString(); _ = s switch { string => 1, bool => 3 }; } } } "; var comp = CreateCompilation([src, UnionAttributeSource, MemberNotNullWhenAttributeDefinition, NotNullWhenAttributeDefinition]); comp.VerifyDiagnostics( // (200,13): warning CS8602: Dereference of a possibly null reference. // value.ToString(); Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "value").WithLocation(200, 13), // (300,13): warning CS8602: Dereference of a possibly null reference. // value.ToString(); Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "value").WithLocation(300, 13) ); } [Fact] public void NonBoxingUnionMatching_73_TryGetValue_NullableAnalysis() { var src = @" #nullable enable [System.Runtime.CompilerServices.Union] struct S1 { public S1(int? x) => throw null!; public S1(bool? x) => throw null!; public object? Value => throw null!; public bool TryGetValue(out string? x) => throw null!; } class Program { static void Test2(S1 s) { if (s.TryGetValue(out var value)) { #line 100 value.ToString(); _ = s switch { int => 1, bool => 3 }; } else { #line 200 value.ToString(); _ = s switch { int => 1, bool => 3 }; } } static void Test4(S1 s) { if (!s.TryGetValue(out var value)) { #line 300 value.ToString(); _ = s switch { int => 1, bool => 3 }; } else { #line 400 value.ToString(); _ = s switch { int => 1, bool => 3 }; } } } "; var comp = CreateCompilation([src, UnionAttributeSource]); comp.VerifyDiagnostics( // (100,13): warning CS8602: Dereference of a possibly null reference. // value.ToString(); Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "value").WithLocation(100, 13), // (101,19): warning CS8655: The switch expression does not handle some null inputs (it is not exhaustive). For example, the pattern 'null' is not covered. // _ = s switch { int => 1, bool => 3 }; Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustiveForNull, "switch").WithArguments("null").WithLocation(101, 19), // (200,13): warning CS8602: Dereference of a possibly null reference. // value.ToString(); Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "value").WithLocation(200, 13), // (201,19): warning CS8655: The switch expression does not handle some null inputs (it is not exhaustive). For example, the pattern 'null' is not covered. // _ = s switch { int => 1, bool => 3 }; Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustiveForNull, "switch").WithArguments("null").WithLocation(201, 19), // (300,13): warning CS8602: Dereference of a possibly null reference. // value.ToString(); Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "value").WithLocation(300, 13), // (301,19): warning CS8655: The switch expression does not handle some null inputs (it is not exhaustive). For example, the pattern 'null' is not covered. // _ = s switch { int => 1, bool => 3 }; Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustiveForNull, "switch").WithArguments("null").WithLocation(301, 19), // (400,13): warning CS8602: Dereference of a possibly null reference. // value.ToString(); Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "value").WithLocation(400, 13), // (401,19): warning CS8655: The switch expression does not handle some null inputs (it is not exhaustive). For example, the pattern 'null' is not covered. // _ = s switch { int => 1, bool => 3 }; Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustiveForNull, "switch").WithArguments("null").WithLocation(401, 19) ); } [Fact] public void NonBoxingUnionMatching_74_TryGetValue_NullableAnalysis_Generic() { var src = @" #nullable enable [System.Runtime.CompilerServices.Union] struct S1<T> { public S1(T x) => throw null!; public S1(bool? x) => throw null!; public object? Value => throw null!; public bool TryGetValue(out T x) => throw null!; } class Program { static void Test2(S1<string?> s) { if (s.TryGetValue(out var value)) { #line 100 value.ToString(); _ = s switch { string => 1, bool => 3 }; } else { #line 200 value.ToString(); _ = s switch { string => 1, bool => 3 }; } } static void Test4(S1<string?> s) { if (!s.TryGetValue(out var value)) { #line 300 value.ToString(); _ = s switch { string => 1, bool => 3 }; } else { #line 400 value.ToString(); _ = s switch { string => 1, bool => 3 }; } } } "; var comp = CreateCompilation([src, UnionAttributeSource]); comp.VerifyDiagnostics( // (200,13): warning CS8602: Dereference of a possibly null reference. // value.ToString(); Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "value").WithLocation(200, 13), // (201,19): warning CS8655: The switch expression does not handle some null inputs (it is not exhaustive). For example, the pattern 'null' is not covered. // _ = s switch { string => 1, bool => 3 }; Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustiveForNull, "switch").WithArguments("null").WithLocation(201, 19), // (300,13): warning CS8602: Dereference of a possibly null reference. // value.ToString(); Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "value").WithLocation(300, 13), // (301,19): warning CS8655: The switch expression does not handle some null inputs (it is not exhaustive). For example, the pattern 'null' is not covered. // _ = s switch { string => 1, bool => 3 }; Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustiveForNull, "switch").WithArguments("null").WithLocation(301, 19) ); } [Fact] public void NonBoxingUnionMatching_75_TryGetValue_NullableAnalysis_Generic() { var src = @" #nullable enable [System.Runtime.CompilerServices.Union] struct S1<T> { public S1(T x) => throw null!; public S1(bool? x) => throw null!; public object? Value => throw null!; public bool TryGetValue(out string? x) => throw null!; } class Program { static void Test2(S1<string?> s) { if (s.TryGetValue(out var value)) { #line 100 value.ToString(); _ = s switch { string => 1, bool => 3 }; } else { #line 200 value.ToString(); _ = s switch { string => 1, bool => 3 }; } } static void Test4(S1<string?> s) { if (!s.TryGetValue(out var value)) { #line 300 value.ToString(); _ = s switch { string => 1, bool => 3 }; } else { #line 400 value.ToString(); _ = s switch { string => 1, bool => 3 }; } } } "; var comp = CreateCompilation([src, UnionAttributeSource]); comp.VerifyDiagnostics( // (100,13): warning CS8602: Dereference of a possibly null reference. // value.ToString(); Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "value").WithLocation(100, 13), // (101,19): warning CS8655: The switch expression does not handle some null inputs (it is not exhaustive). For example, the pattern 'null' is not covered. // _ = s switch { string => 1, bool => 3 }; Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustiveForNull, "switch").WithArguments("null").WithLocation(101, 19), // (200,13): warning CS8602: Dereference of a possibly null reference. // value.ToString(); Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "value").WithLocation(200, 13), // (201,19): warning CS8655: The switch expression does not handle some null inputs (it is not exhaustive). For example, the pattern 'null' is not covered. // _ = s switch { string => 1, bool => 3 }; Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustiveForNull, "switch").WithArguments("null").WithLocation(201, 19), // (300,13): warning CS8602: Dereference of a possibly null reference. // value.ToString(); Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "value").WithLocation(300, 13), // (301,19): warning CS8655: The switch expression does not handle some null inputs (it is not exhaustive). For example, the pattern 'null' is not covered. // _ = s switch { string => 1, bool => 3 }; Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustiveForNull, "switch").WithArguments("null").WithLocation(301, 19), // (400,13): warning CS8602: Dereference of a possibly null reference. // value.ToString(); Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "value").WithLocation(400, 13), // (401,19): warning CS8655: The switch expression does not handle some null inputs (it is not exhaustive). For example, the pattern 'null' is not covered. // _ = s switch { string => 1, bool => 3 }; Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustiveForNull, "switch").WithArguments("null").WithLocation(401, 19) ); } [Fact] public void NonBoxingUnionMatching_76_TryGetValue_NullableAnalysis_Generic() { var src = @" #nullable enable [System.Runtime.CompilerServices.Union] struct S1<T> { public S1(string? x) => throw null!; public S1(bool? x) => throw null!; public object? Value => throw null!; public T TryGetValue(out string? x) => throw null!; } class Program { static void Test2(S1<bool> s) { if (s.TryGetValue(out var value)) { #line 100 value.ToString(); _ = s switch { string => 1, bool => 3 }; } else { #line 200 value.ToString(); _ = s switch { string => 1, bool => 3 }; } } static void Test4(S1<bool> s) { if (!s.TryGetValue(out var value)) { #line 300 value.ToString(); _ = s switch { string => 1, bool => 3 }; } else { #line 400 value.ToString(); _ = s switch { string => 1, bool => 3 }; } } } "; var comp = CreateCompilation([src, UnionAttributeSource]); comp.VerifyDiagnostics( // (100,13): warning CS8602: Dereference of a possibly null reference. // value.ToString(); Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "value").WithLocation(100, 13), // (101,19): warning CS8655: The switch expression does not handle some null inputs (it is not exhaustive). For example, the pattern 'null' is not covered. // _ = s switch { string => 1, bool => 3 }; Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustiveForNull, "switch").WithArguments("null").WithLocation(101, 19), // (200,13): warning CS8602: Dereference of a possibly null reference. // value.ToString(); Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "value").WithLocation(200, 13), // (201,19): warning CS8655: The switch expression does not handle some null inputs (it is not exhaustive). For example, the pattern 'null' is not covered. // _ = s switch { string => 1, bool => 3 }; Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustiveForNull, "switch").WithArguments("null").WithLocation(201, 19), // (300,13): warning CS8602: Dereference of a possibly null reference. // value.ToString(); Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "value").WithLocation(300, 13), // (301,19): warning CS8655: The switch expression does not handle some null inputs (it is not exhaustive). For example, the pattern 'null' is not covered. // _ = s switch { string => 1, bool => 3 }; Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustiveForNull, "switch").WithArguments("null").WithLocation(301, 19), // (400,13): warning CS8602: Dereference of a possibly null reference. // value.ToString(); Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "value").WithLocation(400, 13), // (401,19): warning CS8655: The switch expression does not handle some null inputs (it is not exhaustive). For example, the pattern 'null' is not covered. // _ = s switch { string => 1, bool => 3 }; Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustiveForNull, "switch").WithArguments("null").WithLocation(401, 19) ); } [Fact] public void NonBoxingUnionMatching_77_TryGetValue() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 { private readonly object _value; public S1(int? x) { _value = x; } public S1(string x) { _value = x; } public object Value => _value; public bool TryGetValue(out int x) { if (_value is int v) { x = v; return true; } x = 0; return false; } static void Main() { System.Console.Write(Test1(new S1(1))); System.Console.Write(Test1(new S1())); System.Console.Write(Test1(new S1(""a""))); System.Console.Write(Test2(new S1(2))); System.Console.Write(Test2(new S1())); System.Console.Write(Test2(new S1(""b""))); } static bool Test1(S1 u) { return u is int; } static bool Test2(S1 u) { return u is not int; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); var verifier = CompileAndVerify(comp, expectedOutput: "TrueFalseFalseFalseTrueTrue").VerifyDiagnostics(); verifier.VerifyIL("S1.Test1", @" { // Code size 10 (0xa) .maxstack 2 .locals init (int V_0) IL_0000: ldarga.s V_0 IL_0002: ldloca.s V_0 IL_0004: call ""bool S1.TryGetValue(out int)"" IL_0009: ret } "); verifier.VerifyIL("S1.Test2", @" { // Code size 13 (0xd) .maxstack 2 .locals init (int V_0) IL_0000: ldarga.s V_0 IL_0002: ldloca.s V_0 IL_0004: call ""bool S1.TryGetValue(out int)"" IL_0009: ldc.i4.0 IL_000a: ceq IL_000c: ret } "); } [Fact] public void NonBoxingUnionMatching_78_HasValue_Struct_Direct_Value_Matching() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } public object Value => throw null; public bool HasValue => _value != null; static void Main() { System.Console.Write(Test1(new S1(1))); System.Console.Write(Test1(new S1())); System.Console.Write(Test2(new S1(2))); System.Console.Write(Test2(new S1())); } static bool Test1(object u) { return u is S1 { Value: null }; } static bool Test2(object u) { return u is S1 { Value: not null }; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); var verifier = CompileAndVerify(comp, expectedOutput: "FalseTrueTrueFalse").VerifyDiagnostics(); verifier.VerifyIL("S1.Test1", @" { // Code size 28 (0x1c) .maxstack 2 .locals init (S1 V_0) IL_0000: ldarg.0 IL_0001: isinst ""S1"" IL_0006: brfalse.s IL_001a IL_0008: ldarg.0 IL_0009: unbox.any ""S1"" IL_000e: stloc.0 IL_000f: ldloca.s V_0 IL_0011: call ""bool S1.HasValue.get"" IL_0016: ldc.i4.0 IL_0017: ceq IL_0019: ret IL_001a: ldc.i4.0 IL_001b: ret } "); verifier.VerifyIL("S1.Test2", @" { // Code size 25 (0x19) .maxstack 1 .locals init (S1 V_0) IL_0000: ldarg.0 IL_0001: isinst ""S1"" IL_0006: brfalse.s IL_0017 IL_0008: ldarg.0 IL_0009: unbox.any ""S1"" IL_000e: stloc.0 IL_000f: ldloca.s V_0 IL_0011: call ""bool S1.HasValue.get"" IL_0016: ret IL_0017: ldc.i4.0 IL_0018: ret } "); } [Theory] [CombinatorialData] public void NonBoxingUnionMatching_79_HasValue_Struct_Direct_Value_Matching(bool field) { var src = @" [System.Runtime.CompilerServices.Union] struct S1 { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } public object Value => throw null; public bool HasValue => _value != null; static void Main() { System.Console.Write(Test1(new S2(new S1(1)))); System.Console.Write(Test1(new S2(new S1()))); System.Console.Write(Test2(new S2(new S1(2)))); System.Console.Write(Test2(new S2(new S1()))); } static bool Test1(S2 u) { return u is { S1.Value: null }; } static bool Test2(S2 u) { return u is { S1.Value: not null }; } } struct S2 { public S2(S1 s1) { S1 = s1; } public S1 S1" + (field ? ";" : " { get; }") + @" } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); CompileAndVerify(comp, expectedOutput: "FalseTrueTrueFalse").VerifyDiagnostics(); } [Theory] [CombinatorialData] public void NonBoxingUnionMatching_80_HasValue_Struct_Direct_Value_Matching(bool field) { var src = @" [System.Runtime.CompilerServices.Union] struct S1 { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } public object Value => throw null; public bool HasValue => _value != null; static void Main() { System.Console.Write(Test1(new S2(new S1(1)))); System.Console.Write(Test1(new S2(new S1()))); System.Console.Write(Test1(new S2(null))); System.Console.Write(Test2(new S2(new S1(2)))); System.Console.Write(Test2(new S2(new S1()))); System.Console.Write(Test2(new S2(null))); } static bool Test1(S2 u) { return u is { S1.Value: null }; } static bool Test2(S2 u) { return u is { S1.Value: not null }; } } struct S2 { public S2(S1? s1) { S1 = s1; } public S1? S1" + (field ? ";" : " { get; }") + @" } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); CompileAndVerify(comp, expectedOutput: "FalseTrueFalseTrueFalseFalse").VerifyDiagnostics(); } [Fact] public void NonBoxingUnionMatching_81_TryGetValue_Direct_Value_Matching() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } public object Value { get { System.Console.Write(""get_Value ""); return _value; } } public bool HasValue { get { System.Console.Write(""HasValue ""); return _value != null; } } public bool TryGetValue(out int x) { System.Console.Write(""TryGetValue(int) ""); if (_value is int v) { x = v; return true; } x = 0; return false; } public bool TryGetValue(out string x) { System.Console.Write(""TryGetValue(string) ""); x = _value as string; return x != null; } static void Main() { System.Console.Write(Test1((new S1(1), 1))); System.Console.Write(""; ""); System.Console.Write(Test1((new S1(1), 2))); System.Console.Write(""; ""); System.Console.Write(Test1((new S1(1), 3))); System.Console.Write(""; ""); System.Console.Write(Test1((new S1(), 1))); System.Console.Write(""; ""); System.Console.Write(Test1((new S1(), 2))); System.Console.Write(""; ""); System.Console.Write(Test1((new S1(), 3))); System.Console.Write(""; ""); System.Console.Write(Test1((new S1(""a""), 1))); System.Console.Write(""; ""); System.Console.Write(Test1((new S1(""a""), 2))); System.Console.Write(""; ""); System.Console.Write(Test1((new S1(""a""), 3))); } static bool Test1((object, int) u) { return u is (S1 { Value: string }, 2) or (S1 { Value: int }, 1); } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); CompileAndVerify(comp, expectedOutput: "TryGetValue(string) TryGetValue(int) True; TryGetValue(string) TryGetValue(int) False; TryGetValue(string) TryGetValue(int) False; TryGetValue(string) TryGetValue(int) False; TryGetValue(string) TryGetValue(int) False; TryGetValue(string) TryGetValue(int) False; TryGetValue(string) False; TryGetValue(string) True; TryGetValue(string) False").VerifyDiagnostics(); } [Theory] [CombinatorialData] public void NonBoxingUnionMatching_82_TryGetValue_Direct_Value_Matching(bool field) { var src = @" [System.Runtime.CompilerServices.Union] struct S1 { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } public object Value { get { System.Console.Write(""get_Value ""); return _value; } } public bool HasValue { get { System.Console.Write(""HasValue ""); return _value != null; } } public bool TryGetValue(out int x) { System.Console.Write(""TryGetValue(int) ""); if (_value is int v) { x = v; return true; } x = 0; return false; } public bool TryGetValue(out string x) { System.Console.Write(""TryGetValue(string) ""); x = _value as string; return x != null; } static void Main() { System.Console.Write(Test1((new S2(new S1(1)), 1))); System.Console.Write(""; ""); System.Console.Write(Test1((new S2(new S1(1)), 2))); System.Console.Write(""; ""); System.Console.Write(Test1((new S2(new S1(1)), 3))); System.Console.Write(""; ""); System.Console.Write(Test1((new S2(new S1()), 1))); System.Console.Write(""; ""); System.Console.Write(Test1((new S2(new S1()), 2))); System.Console.Write(""; ""); System.Console.Write(Test1((new S2(new S1()), 3))); System.Console.Write(""; ""); System.Console.Write(Test1((new S2(new S1(""a"")), 1))); System.Console.Write(""; ""); System.Console.Write(Test1((new S2(new S1(""a"")), 2))); System.Console.Write(""; ""); System.Console.Write(Test1((new S2(new S1(""a"")), 3))); } static bool Test1((S2, int) u) { return u is ({ S1.Value: string }, 2) or ({ S1.Value: int }, 1); } } struct S2 { public S2(S1 s1) { S1 = s1; } public S1 S1" + (field ? ";" : " { get; }") + @" } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); CompileAndVerify(comp, expectedOutput: "TryGetValue(string) TryGetValue(int) True; TryGetValue(string) TryGetValue(int) False; TryGetValue(string) TryGetValue(int) False; TryGetValue(string) TryGetValue(int) False; TryGetValue(string) TryGetValue(int) False; TryGetValue(string) TryGetValue(int) False; TryGetValue(string) False; TryGetValue(string) True; TryGetValue(string) False").VerifyDiagnostics(); } [Theory] [CombinatorialData] public void NonBoxingUnionMatching_83_TryGetValue_Direct_Value_Matching(bool field) { var src = @" [System.Runtime.CompilerServices.Union] struct S1 { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } public object Value { get { System.Console.Write(""get_Value ""); return _value; } } public bool HasValue { get { System.Console.Write(""HasValue ""); return _value != null; } } public bool TryGetValue(out int x) { System.Console.Write(""TryGetValue(int) ""); if (_value is int v) { x = v; return true; } x = 0; return false; } public bool TryGetValue(out string x) { System.Console.Write(""TryGetValue(string) ""); x = _value as string; return x != null; } static void Main() { System.Console.Write(Test1((new S2(new S1(1)), 1))); System.Console.Write(""; ""); System.Console.Write(Test1((new S2(new S1(1)), 2))); System.Console.Write(""; ""); System.Console.Write(Test1((new S2(new S1(1)), 3))); System.Console.Write(""; ""); System.Console.Write(Test1((new S2(new S1()), 1))); System.Console.Write(""; ""); System.Console.Write(Test1((new S2(new S1()), 2))); System.Console.Write(""; ""); System.Console.Write(Test1((new S2(new S1()), 3))); System.Console.Write(""; ""); System.Console.Write(Test1((new S2(new S1(""a"")), 1))); System.Console.Write(""; ""); System.Console.Write(Test1((new S2(new S1(""a"")), 2))); System.Console.Write(""; ""); System.Console.Write(Test1((new S2(new S1(""a"")), 3))); System.Console.Write(""; ""); System.Console.Write(Test1((new S2(null), 1))); System.Console.Write(""; ""); System.Console.Write(Test1((new S2(null), 2))); System.Console.Write(""; ""); System.Console.Write(Test1((new S2(null), 3))); } static bool Test1((S2, int) u) { return u is ({ S1.Value: string }, 2) or ({ S1.Value: int }, 1); } } struct S2 { public S2(S1? s1) { S1 = s1; } public S1? S1" + (field ? ";" : " { get; }") + @" } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); CompileAndVerify(comp, expectedOutput: "TryGetValue(string) TryGetValue(int) True; TryGetValue(string) TryGetValue(int) False; TryGetValue(string) TryGetValue(int) False; TryGetValue(string) TryGetValue(int) False; TryGetValue(string) TryGetValue(int) False; TryGetValue(string) TryGetValue(int) False; TryGetValue(string) False; TryGetValue(string) True; TryGetValue(string) False; False; False; False").VerifyDiagnostics(); } [Fact] public void NonBoxingUnionMatching_84() { var src = @" class C1; class C2; [System.Runtime.CompilerServices.Union] struct S1 { private readonly object _value; public S1(C1 x) { _value = x; } public S1(C2 x) { _value = x; } public object Value { get { System.Console.Write(""get_Value ""); return _value; } } public bool HasValue { get { System.Console.Write(""get_HasValue ""); return _value is not null; } } static void Main() { System.Console.WriteLine(Test1(default)); System.Console.WriteLine(Test1(new C1())); System.Console.WriteLine(Test1(new C2())); } static int Test1(S1 u) { return u switch { not C1 => 2, object => 1 }; } static int Test2(S2 u) { return u switch { not { Value: C1 } => 2, object => 1 }; } } struct S2 { public object Value => throw null; } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); VerifyDecisionDagDump<SwitchExpressionSyntax>(comp, @"[0]: t1 = t0.Value; [1] [1]: t1 is C1 ? [2] : [3] [2]: leaf <arm> `object => 1` [3]: leaf <arm> `not C1 => 2` ", forLowering: true); CompileAndVerify(comp, expectedOutput: @" get_Value 2 get_Value 1 get_Value 2 ").VerifyDiagnostics(); } [Fact] public void NonBoxingUnionMatching_MemberProvider_HasValue_01_Struct() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 : S1.IUnionMembers { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } object IUnionMembers.Value => throw null; bool IUnionMembers.HasValue => _value != null; public interface IUnionMembers { public static S1 Create(int x) => new S1(x); public static S1 Create(string x) => new S1(x); public object Value { get; } public bool HasValue { get;} } static void Main() { System.Console.Write(Test1(new S1(1))); System.Console.Write(Test1(new S1())); System.Console.Write(Test2(new S1(2))); System.Console.Write(Test2(new S1())); } static bool Test1(S1 u) { return u is null; } static bool Test2(S1 u) { return u is not null; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); var verifier = CompileAndVerify(comp, expectedOutput: "FalseTrueTrueFalse").VerifyDiagnostics(); verifier.VerifyIL("S1.Test1", @" { // Code size 17 (0x11) .maxstack 2 IL_0000: ldarga.s V_0 IL_0002: constrained. ""S1"" IL_0008: callvirt ""bool S1.IUnionMembers.HasValue.get"" IL_000d: ldc.i4.0 IL_000e: ceq IL_0010: ret } "); verifier.VerifyIL("S1.Test2", @" { // Code size 20 (0x14) .maxstack 2 IL_0000: ldarga.s V_0 IL_0002: constrained. ""S1"" IL_0008: callvirt ""bool S1.IUnionMembers.HasValue.get"" IL_000d: ldc.i4.0 IL_000e: ceq IL_0010: ldc.i4.0 IL_0011: ceq IL_0013: ret } "); } [Fact] public void NonBoxingUnionMatching_MemberProvider_HasValue_02_Class() { var src = @" [System.Runtime.CompilerServices.Union] class S1 : S1.IUnionMembers { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } object IUnionMembers.Value => throw null; bool IUnionMembers.HasValue => _value != null; public interface IUnionMembers { public static S1 Create(int x) => new S1(x); public static S1 Create(string x) => new S1(x); public object Value { get; } public bool HasValue { get;} } static void Main() { System.Console.Write(Test1(new S1(1))); System.Console.Write(Test1(new S1(null))); System.Console.Write(Test1(null)); System.Console.Write(Test2(new S1(2))); System.Console.Write(Test2(new S1(null))); System.Console.Write(Test2(null)); } static bool Test1(S1 u) { return u is null; } static bool Test2(S1 u) { return u is not null; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); var verifier = CompileAndVerify(comp, expectedOutput: "FalseTrueTrueTrueFalseFalse").VerifyDiagnostics(); verifier.VerifyIL("S1.Test1", @" { // Code size 19 (0x13) .maxstack 1 .locals init (bool V_0) IL_0000: ldarg.0 IL_0001: brfalse.s IL_000b IL_0003: ldarg.0 IL_0004: callvirt ""bool S1.IUnionMembers.HasValue.get"" IL_0009: brtrue.s IL_000f IL_000b: ldc.i4.1 IL_000c: stloc.0 IL_000d: br.s IL_0011 IL_000f: ldc.i4.0 IL_0010: stloc.0 IL_0011: ldloc.0 IL_0012: ret } "); verifier.VerifyIL("S1.Test2", @" { // Code size 22 (0x16) .maxstack 2 .locals init (bool V_0) IL_0000: ldarg.0 IL_0001: brfalse.s IL_000b IL_0003: ldarg.0 IL_0004: callvirt ""bool S1.IUnionMembers.HasValue.get"" IL_0009: brtrue.s IL_000f IL_000b: ldc.i4.1 IL_000c: stloc.0 IL_000d: br.s IL_0011 IL_000f: ldc.i4.0 IL_0010: stloc.0 IL_0011: ldloc.0 IL_0012: ldc.i4.0 IL_0013: ceq IL_0015: ret } "); } [Fact] public void NonBoxingUnionMatching_MemberProvider_HasValue_03_MemberFromTypeNotUsed() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 : S1.IUnionMembers { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } public bool HasValue => throw null; object IUnionMembers.Value => throw null; bool IUnionMembers.HasValue => _value != null; public interface IUnionMembers { public static S1 Create(int x) => new S1(x); public static S1 Create(string x) => new S1(x); public object Value { get; } public bool HasValue { get;} } static void Main() { System.Console.Write(Test1(new S1(1))); System.Console.Write(Test1(new S1())); System.Console.Write(Test2(new S1(2))); System.Console.Write(Test2(new S1())); } static bool Test1(S1 u) { return u is null; } static bool Test2(S1 u) { return u is not null; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); var verifier = CompileAndVerify(comp, expectedOutput: "FalseTrueTrueFalse").VerifyDiagnostics(); verifier.VerifyIL("S1.Test1", @" { // Code size 17 (0x11) .maxstack 2 IL_0000: ldarga.s V_0 IL_0002: constrained. ""S1"" IL_0008: callvirt ""bool S1.IUnionMembers.HasValue.get"" IL_000d: ldc.i4.0 IL_000e: ceq IL_0010: ret } "); verifier.VerifyIL("S1.Test2", @" { // Code size 20 (0x14) .maxstack 2 IL_0000: ldarga.s V_0 IL_0002: constrained. ""S1"" IL_0008: callvirt ""bool S1.IUnionMembers.HasValue.get"" IL_000d: ldc.i4.0 IL_000e: ceq IL_0010: ldc.i4.0 IL_0011: ceq IL_0013: ret } "); } [Fact] public void NonBoxingUnionMatching_MemberProvider_HasValue_04_MemberFromTypeNotUsed() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 : S1.IUnionMembers { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } public bool HasValue => throw null; object IUnionMembers.Value => _value; public interface IUnionMembers { public static S1 Create(int x) => new S1(x); public static S1 Create(string x) => new S1(x); public object Value { get; } } static void Main() { System.Console.Write(Test1(new S1(1))); System.Console.Write(Test1(new S1())); System.Console.Write(Test2(new S1(2))); System.Console.Write(Test2(new S1())); } static bool Test1(S1 u) { return u is null; } static bool Test2(S1 u) { return u is not null; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); var verifier = CompileAndVerify(comp, expectedOutput: "FalseTrueTrueFalse").VerifyDiagnostics(); verifier.VerifyIL("S1.Test1", @" { // Code size 17 (0x11) .maxstack 2 IL_0000: ldarga.s V_0 IL_0002: constrained. ""S1"" IL_0008: callvirt ""object S1.IUnionMembers.Value.get"" IL_000d: ldnull IL_000e: ceq IL_0010: ret } "); verifier.VerifyIL("S1.Test2", @" { // Code size 20 (0x14) .maxstack 2 IL_0000: ldarga.s V_0 IL_0002: constrained. ""S1"" IL_0008: callvirt ""object S1.IUnionMembers.Value.get"" IL_000d: ldnull IL_000e: ceq IL_0010: ldc.i4.0 IL_0011: ceq IL_0013: ret } "); } [Fact] public void NonBoxingUnionMatching_MemberProvider_HasValue_05_Generic() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 : S1.IUnionMembers<bool> { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } public object Value => _value; object IUnionMembers<bool>.Value => throw null; bool IUnionMembers<bool>.HasValue => throw null; public interface IUnionMembers<T> { public static S1 Create(int x) => throw null; public object Value { get; } public T HasValue { get;} } } class Program { static void Main() { System.Console.Write(Test1(new S1(10))); System.Console.Write(Test1(default)); System.Console.Write(Test1(new S1(""11""))); } static bool Test1(S1 u) { return u is null; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); var verifier = CompileAndVerify(comp, expectedOutput: "FalseTrueFalse").VerifyDiagnostics(); verifier.VerifyIL("Program.Test1", @" { // Code size 11 (0xb) .maxstack 2 IL_0000: ldarga.s V_0 IL_0002: call ""object S1.Value.get"" IL_0007: ldnull IL_0008: ceq IL_000a: ret } "); } [Fact] public void NonBoxingUnionMatching_MemberProvider_HasValue_06_Generic() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 : S1.IUnionMembers { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } public object Value => throw null; object IUnionMembers.Value => throw null; bool IUnionMembers.HasValue => _value != null; public interface IUnionMembers<T>; public interface IUnionMembers { public static S1 Create(int x) => new S1(x); public static S1 Create(string x) => new S1(x); public object Value { get; } public bool HasValue { get; } } public interface IUnionMembers<T, S>; } class Program { static void Main() { System.Console.Write(Test1(new S1(10))); System.Console.Write(Test1(default)); System.Console.Write(Test1(new S1(""11""))); } static bool Test1(S1 u) { return u is null; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); CompileAndVerify(comp, expectedOutput: "FalseTrueFalse").VerifyDiagnostics(); } [Fact] public void NonBoxingUnionMatching_MemberProvider_HasValue_07_InGenericUnion() { var src = @" [System.Runtime.CompilerServices.Union] struct S1<T> : S1<T>.IUnionMembers { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } public object Value => throw null; object IUnionMembers.Value => throw null; bool IUnionMembers.HasValue => _value != null; public interface IUnionMembers { public static S1<T> Create(int x) => new S1<T>(x); public static S1<T> Create(string x) => new S1<T>(x); public object Value { get; } public bool HasValue { get; } } } class Program { static void Main() { System.Console.Write(Test1(new S1<long>(10))); System.Console.Write(Test1(default)); System.Console.Write(Test1(new S1<long>(""11""))); System.Console.Write(Test1(new S1<long>(0))); } static bool Test1(S1<long> u) { return u is null; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); CompileAndVerify(comp, expectedOutput: "FalseTrueFalseFalse").VerifyDiagnostics(); } [Fact] public void NonBoxingUnionMatching_MemberProvider_HasValue_08_WrongGenericSubstitution() { var src = @" [System.Runtime.CompilerServices.Union] struct S1<T> : S1<long>.IUnionMembers { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } public object Value => throw null; public bool HasValue => _value != null; object S1<long>.IUnionMembers.Value => throw null; bool S1<long>.IUnionMembers.HasValue => throw null; public interface IUnionMembers { public static S1<T> Create(int x) => throw null; public static S1<T> Create(string x) => throw null; public object Value { get; } public bool HasValue { get; } } } class Program { static void Main() { System.Console.Write(Test1(new S1<long>(10))); System.Console.Write(Test1(default)); System.Console.Write(Test1(new S1<long>(""11""))); System.Console.Write(Test1(new S1<long>(0))); } static bool Test1(S1<long> u) { return u is null; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); CompileAndVerify(comp, expectedOutput: "FalseTrueFalseFalse").VerifyDiagnostics(); } [Theory] [CombinatorialData] public void NonBoxingUnionMatching_MemberProvider_HasValue_09_Provider_NotPublic([CombinatorialValues("", "private", "internal", "protected", "internal protected", "private protected")] string accessibility) { var src = @" [System.Runtime.CompilerServices.Union] class S1 : S1.IUnionMembers { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } public object Value => throw null; public bool HasValue => _value != null; object IUnionMembers.Value => throw null; bool IUnionMembers.HasValue => throw null; " + accessibility + @" interface IUnionMembers { public static S1 Create(int x) => new S1(x); public static S1 Create(string x) => new S1(x); public object Value { get; } public bool HasValue { get; } } } class Program { static void Main() { System.Console.Write(Test1(new S1(10))); System.Console.Write(Test1(default)); System.Console.Write(Test1(new S1(""11""))); System.Console.Write(Test1(new S1(0))); } static bool Test1(S1 u) { return u is null; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); var verifier = CompileAndVerify(comp, expectedOutput: "FalseTrueFalseFalse").VerifyDiagnostics(); verifier.VerifyIL("Program.Test1", @" { // Code size 19 (0x13) .maxstack 1 .locals init (bool V_0) IL_0000: ldarg.0 IL_0001: brfalse.s IL_000b IL_0003: ldarg.0 IL_0004: callvirt ""bool S1.HasValue.get"" IL_0009: brtrue.s IL_000f IL_000b: ldc.i4.1 IL_000c: stloc.0 IL_000d: br.s IL_0011 IL_000f: ldc.i4.0 IL_0010: stloc.0 IL_0011: ldloc.0 IL_0012: ret } "); } [Fact] public void NonBoxingUnionMatching_MemberProvider_HasValue_10_WrongType() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 : S1.IUnionMembers { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } public bool HasValue => throw null; object IUnionMembers.Value => _value; System.IComparable IUnionMembers.HasValue => _value != null; public interface IUnionMembers { public static S1 Create(int x) => new S1(x); public static S1 Create(string x) => new S1(x); public object Value { get; } public System.IComparable HasValue { get;} } static void Main() { System.Console.Write(Test1(new S1(1))); System.Console.Write(Test1(new S1())); } static bool Test1(S1 u) { return u is null; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); var verifier = CompileAndVerify(comp, expectedOutput: "FalseTrue").VerifyDiagnostics(); verifier.VerifyIL("S1.Test1", @" { // Code size 17 (0x11) .maxstack 2 IL_0000: ldarga.s V_0 IL_0002: constrained. ""S1"" IL_0008: callvirt ""object S1.IUnionMembers.Value.get"" IL_000d: ldnull IL_000e: ceq IL_0010: ret } "); } [Fact] public void NonBoxingUnionMatching_MemberProvider_HasValue_11_WrongType() { var src = @" [System.Runtime.CompilerServices.Union] struct S1<T> : S1<T>.IUnionMembers { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } public object Value => throw null; public bool HasValue => throw null; object IUnionMembers.Value => _value; T IUnionMembers.HasValue => throw null; public interface IUnionMembers { public static S1<T> Create(int x) => new S1<T>(x); public static S1<T> Create(string x) => new S1<T>(x); public object Value { get; } public T HasValue { get; } } } class Program { static void Main() { System.Console.Write(Test1(new S1<bool>(1))); System.Console.Write(Test1(new S1<bool>())); } static bool Test1(S1<bool> u) { return u is null; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); var verifier = CompileAndVerify(comp, expectedOutput: "FalseTrue").VerifyDiagnostics(); verifier.VerifyIL("Program.Test1", @" { // Code size 17 (0x11) .maxstack 2 IL_0000: ldarga.s V_0 IL_0002: constrained. ""S1<bool>"" IL_0008: callvirt ""object S1<bool>.IUnionMembers.Value.get"" IL_000d: ldnull IL_000e: ceq IL_0010: ret } "); } [Theory] [CombinatorialData] public void NonBoxingUnionMatching_MemberProvider_HasValue_12_WrongRefKind([CombinatorialValues("ref", "ref readonly")] string refModifier) { var src = @" [System.Runtime.CompilerServices.Union] struct S1 : S1.IUnionMembers { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } public object Value => throw null; public bool HasValue => throw null; object IUnionMembers.Value => _value; " + refModifier + @" bool IUnionMembers.HasValue => throw null; public interface IUnionMembers { public static S1 Create(int x) => new S1(x); public static S1 Create(string x) => new S1(x); public object Value { get; } public " + refModifier + @" bool HasValue { get; } } } class Program { static void Main() { System.Console.Write(Test1(new S1(1))); System.Console.Write(Test1(new S1())); } static bool Test1(S1 u) { return u is null; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); CompileAndVerify(comp, expectedOutput: "FalseTrue").VerifyDiagnostics(); } [Fact] public void NonBoxingUnionMatching_MemberProvider_HasValue_13_Static() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 : S1.IUnionMembers { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } public object Value => _value; public bool HasValue => throw null; public interface IUnionMembers { public static S1 Create(int x) => new S1(x); public static S1 Create(string x) => new S1(x); public object Value { get; } public static bool HasValue => throw null; } } class Program { static void Main() { System.Console.Write(Test1(new S1(1))); System.Console.Write(Test1(new S1())); } static bool Test1(S1 u) { return u is null; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); CompileAndVerify(comp, expectedOutput: "FalseTrue").VerifyDiagnostics(); } [Fact] public void NonBoxingUnionMatching_MemberProvider_HasValue_14_NotVirtual() { var src = @" [System.Runtime.CompilerServices.Union] class S1 : S1.IUnionMembers { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } public object Value => throw null; public bool HasValue => throw null; public interface IUnionMembers { public static S1 Create(int x) => new S1(x); public static S1 Create(string x) => new S1(x); public object Value { get; } public sealed bool HasValue => ((S1)this)._value != null; } } class Program { static void Main() { System.Console.Write(Test1(new S1(10))); System.Console.Write(Test1(default)); System.Console.Write(Test1(new S1(""11""))); System.Console.Write(Test1(new S1(0))); } static bool Test1(S1 u) { return u is not null; } } "; var comp = CreateCompilation([src, UnionAttributeSource], targetFramework: TargetFramework.NetCoreApp, options: TestOptions.ReleaseExe); var verifier = CompileAndVerify(comp, expectedOutput: ExecutionConditionUtil.IsMonoOrCoreClr ? "TrueFalseTrueTrue" : null, verify: Verification.FailsPEVerify).VerifyDiagnostics(); verifier.VerifyIL("Program.Test1", @" { // Code size 22 (0x16) .maxstack 2 .locals init (bool V_0) IL_0000: ldarg.0 IL_0001: brfalse.s IL_000b IL_0003: ldarg.0 IL_0004: callvirt ""bool S1.IUnionMembers.HasValue.get"" IL_0009: brtrue.s IL_000f IL_000b: ldc.i4.1 IL_000c: stloc.0 IL_000d: br.s IL_0011 IL_000f: ldc.i4.0 IL_0010: stloc.0 IL_0011: ldloc.0 IL_0012: ldc.i4.0 IL_0013: ceq IL_0015: ret } "); } [Fact] public void NonBoxingUnionMatching_MemberProvider_HasValue_15_Inherited() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 : S1.IUnionMembers { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } object IUnionMembers.Value => throw null; bool IUnionMembersBase.HasValue => _value != null; public interface IUnionMembers : IUnionMembersBase { public static S1 Create(int x) => new S1(x); public static S1 Create(string x) => new S1(x); public object Value { get; } } public interface IUnionMembersBase { public bool HasValue { get; } } } class Program { static void Main() { System.Console.Write(Test1(new S1(1))); System.Console.Write(Test1(new S1())); } static bool Test1(S1 u) { return u is null; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); var verifier = CompileAndVerify(comp, expectedOutput: "FalseTrue").VerifyDiagnostics(); verifier.VerifyIL("Program.Test1", @" { // Code size 17 (0x11) .maxstack 2 IL_0000: ldarga.s V_0 IL_0002: constrained. ""S1"" IL_0008: callvirt ""bool S1.IUnionMembersBase.HasValue.get"" IL_000d: ldc.i4.0 IL_000e: ceq IL_0010: ret } "); } [Fact] public void NonBoxingUnionMatching_MemberProvider_HasValue_16_NullableAnalysis() { var src = @" #nullable enable [System.Runtime.CompilerServices.Union] struct S1 : S1.IUnionMembers { public S1(int x) => throw null!; public S1(bool? x) => throw null!; public object? Value => throw null!; public bool HasValue => throw null!; public interface IUnionMembers { public static S1 Create(int x) => new S1(x); public static S1 Create(bool? x) => new S1(x); public object? Value { get; } public bool HasValue { get; } } } class Program { static void Test2(S1 s) { if (s.HasValue) { #line 100 _ = s switch { int => 1, bool => 3 }; } else { #line 200 _ = s switch { int => 1, bool => 3 }; } } static void Test4(S1 s) { if (!s.HasValue) { #line 300 _ = s switch { int => 1, bool => 3 }; } else { #line 400 _ = s switch { int => 1, bool => 3 }; } } } "; var comp = CreateCompilation([src, UnionAttributeSource]); comp.VerifyDiagnostics( // (100,19): warning CS8655: The switch expression does not handle some null inputs (it is not exhaustive). For example, the pattern 'null' is not covered. // _ = s switch { int => 1, bool => 3 }; Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustiveForNull, "switch").WithArguments("null").WithLocation(100, 19), // (200,19): warning CS8655: The switch expression does not handle some null inputs (it is not exhaustive). For example, the pattern 'null' is not covered. // _ = s switch { int => 1, bool => 3 }; Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustiveForNull, "switch").WithArguments("null").WithLocation(200, 19), // (300,19): warning CS8655: The switch expression does not handle some null inputs (it is not exhaustive). For example, the pattern 'null' is not covered. // _ = s switch { int => 1, bool => 3 }; Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustiveForNull, "switch").WithArguments("null").WithLocation(300, 19), // (400,19): warning CS8655: The switch expression does not handle some null inputs (it is not exhaustive). For example, the pattern 'null' is not covered. // _ = s switch { int => 1, bool => 3 }; Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustiveForNull, "switch").WithArguments("null").WithLocation(400, 19) ); } [Fact] public void NonBoxingUnionMatching_MemberProvider_HasValue_17_NullableAnalysis() { var src = @" #nullable enable [System.Runtime.CompilerServices.Union] struct S1 : S1.IUnionMembers { public S1(int x) => throw null!; public S1(bool? x) => throw null!; public object? Value => throw null!; public bool HasValue => throw null!; public interface IUnionMembers { public static S1 Create(int x) => new S1(x); public static S1 Create(bool? x) => new S1(x); public object? Value { get; } } } class Program { static void Test2(S1 s) { if (s.HasValue) { #line 100 _ = s switch { int => 1, bool => 3 }; } else { #line 200 _ = s switch { int => 1, bool => 3 }; } } static void Test4(S1 s) { if (!s.HasValue) { #line 300 _ = s switch { int => 1, bool => 3 }; } else { #line 400 _ = s switch { int => 1, bool => 3 }; } } } "; var comp = CreateCompilation([src, UnionAttributeSource]); comp.VerifyDiagnostics( // (100,19): warning CS8655: The switch expression does not handle some null inputs (it is not exhaustive). For example, the pattern 'null' is not covered. // _ = s switch { int => 1, bool => 3 }; Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustiveForNull, "switch").WithArguments("null").WithLocation(100, 19), // (200,19): warning CS8655: The switch expression does not handle some null inputs (it is not exhaustive). For example, the pattern 'null' is not covered. // _ = s switch { int => 1, bool => 3 }; Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustiveForNull, "switch").WithArguments("null").WithLocation(200, 19), // (300,19): warning CS8655: The switch expression does not handle some null inputs (it is not exhaustive). For example, the pattern 'null' is not covered. // _ = s switch { int => 1, bool => 3 }; Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustiveForNull, "switch").WithArguments("null").WithLocation(300, 19), // (400,19): warning CS8655: The switch expression does not handle some null inputs (it is not exhaustive). For example, the pattern 'null' is not covered. // _ = s switch { int => 1, bool => 3 }; Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustiveForNull, "switch").WithArguments("null").WithLocation(400, 19) ); } [Theory] [CombinatorialData] public void NonBoxingUnionMatching_MemberProvider_HasValue_18_NotPublic([CombinatorialValues("internal", "protected", "internal protected", "private protected")] string accessibility) { var src = @" [System.Runtime.CompilerServices.Union] struct S1 : S1.IUnionMembers { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } public object Value => _value; bool IUnionMembers.HasValue => throw null; public interface IUnionMembers { public static S1 Create(int x) => new S1(x); public static S1 Create(string x) => new S1(x); public object Value { get; } " + accessibility + @" abstract bool HasValue { get; } } } class Program { static void Main() { System.Console.Write(Test1(new S1(1))); System.Console.Write(Test1(new S1())); } static bool Test1(S1 u) { return u is null; } } "; var comp = CreateCompilation([src, UnionAttributeSource], targetFramework: TargetFramework.NetCoreApp, options: TestOptions.ReleaseExe); CompileAndVerify(comp, expectedOutput: ExecutionConditionUtil.IsMonoOrCoreClr ? "FalseTrue" : null, verify: Verification.FailsPEVerify).VerifyDiagnostics(); } [Theory] [CombinatorialData] public void NonBoxingUnionMatching_MemberProvider_HasValue_19_NotPublic([CombinatorialValues("private", "internal", "protected", "internal protected", "private protected")] string accessibility) { var src = @" [System.Runtime.CompilerServices.Union] struct S1 : S1.IUnionMembers { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } public object Value => _value; " + (accessibility == "private" ? "" : "bool IUnionMembers.HasValue => throw null;") + @" public interface IUnionMembers { public static S1 Create(int x) => new S1(x); public static S1 Create(string x) => new S1(x); public object Value { get; } " + accessibility + @" bool HasValue { get" + (accessibility == "private" ? " => throw null" : "") + @"; } } } class Program { static void Main() { System.Console.Write(Test1(new S1(1))); System.Console.Write(Test1(new S1())); } static bool Test1(S1 u) { return u is null; } } "; var comp = CreateCompilation([src, UnionAttributeSource], targetFramework: TargetFramework.NetCoreApp, options: TestOptions.ReleaseExe); CompileAndVerify(comp, expectedOutput: ExecutionConditionUtil.IsMonoOrCoreClr ? "FalseTrue" : null, verify: Verification.FailsPEVerify).VerifyDiagnostics(); } [Theory] [CombinatorialData] public void NonBoxingUnionMatching_MemberProvider_HasValue_20_NotPublic_Get([CombinatorialValues("private", "internal", "protected", "internal protected", "private protected")] string accessibility) { var src = @" [System.Runtime.CompilerServices.Union] struct S1 : S1.IUnionMembers { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } public object Value => _value; " + (accessibility == "private" ? "" : "bool IUnionMembers.HasValue { get => throw null; set => throw null; }") + @" public interface IUnionMembers { public static S1 Create(int x) => new S1(x); public static S1 Create(string x) => new S1(x); public object Value { get; } public bool HasValue { " + accessibility + @" get" + (accessibility == "private" ? " => throw null" : "") + @"; set" + (accessibility == "private" ? " => throw null" : "") + @"; } } } class Program { static void Main() { System.Console.Write(Test1(new S1(1))); System.Console.Write(Test1(new S1())); } static bool Test1(S1 u) { return u is null; } } "; var comp = CreateCompilation([src, UnionAttributeSource], targetFramework: TargetFramework.NetCoreApp, options: TestOptions.ReleaseExe); CompileAndVerify(comp, expectedOutput: ExecutionConditionUtil.IsMonoOrCoreClr ? "FalseTrue" : null, verify: Verification.FailsPEVerify).VerifyDiagnostics(); } [Fact] public void NonBoxingUnionMatching_MemberProvider_HasValue_Inheritance_01_Missing() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 : S1.IUnionMembers { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } object IUnionMembers.Value => _value; public interface IUnionMembers : IUnionMembersBase { public static S1 Create(int x) => new S1(x); public static S1 Create(string x) => new S1(x); public object Value { get; } } public interface IUnionMembersBase { } } class Program { static void Main() { System.Console.Write(Test1(new S1(1))); System.Console.Write(Test1(new S1())); } static bool Test1(S1 u) { return u is null; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); var verifier = CompileAndVerify(comp, expectedOutput: "FalseTrue").VerifyDiagnostics(); verifier.VerifyIL("Program.Test1", @" { // Code size 17 (0x11) .maxstack 2 IL_0000: ldarga.s V_0 IL_0002: constrained. ""S1"" IL_0008: callvirt ""object S1.IUnionMembers.Value.get"" IL_000d: ldnull IL_000e: ceq IL_0010: ret } "); } [Fact] public void NonBoxingUnionMatching_MemberProvider_HasValue_Inheritance_02_Ambiguous() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 : S1.IUnionMembers { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } object IUnionMembers.Value => _value; public bool HasValue => throw null; public interface IUnionMembers : IUnionMembersBase1, IUnionMembersBase2 { public static S1 Create(int x) => new S1(x); public static S1 Create(string x) => new S1(x); public object Value { get; } } public interface IUnionMembersBase1 { public bool HasValue { get; } } public interface IUnionMembersBase2 { public bool HasValue { get; } } } class Program { static void Main() { System.Console.Write(Test1(new S1(1))); System.Console.Write(Test1(new S1())); } static bool Test1(S1 u) { return u is null; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); var verifier = CompileAndVerify(comp, expectedOutput: "FalseTrue").VerifyDiagnostics(); verifier.VerifyIL("Program.Test1", @" { // Code size 17 (0x11) .maxstack 2 IL_0000: ldarga.s V_0 IL_0002: constrained. ""S1"" IL_0008: callvirt ""object S1.IUnionMembers.Value.get"" IL_000d: ldnull IL_000e: ceq IL_0010: ret } "); } [Fact] public void NonBoxingUnionMatching_MemberProvider_HasValue_Inheritance_03_Ambiguous() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 : S1.IUnionMembers { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } object IUnionMembers.Value => _value; public bool HasValue => throw null; public interface IUnionMembers : IUnionMembersBase1, IUnionMembersBase2 { public static S1 Create(int x) => new S1(x); public static S1 Create(string x) => new S1(x); public object Value { get; } } public interface IUnionMembersBase1 : IUnionMembersBase3 { public bool HasValue { get; } } public interface IUnionMembersBase2 : IUnionMembersBase3 { public bool HasValue { get; } } public interface IUnionMembersBase3 { } } class Program { static void Main() { System.Console.Write(Test1(new S1(1))); System.Console.Write(Test1(new S1())); } static bool Test1(S1 u) { return u is null; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); var verifier = CompileAndVerify(comp, expectedOutput: "FalseTrue").VerifyDiagnostics(); verifier.VerifyIL("Program.Test1", @" { // Code size 17 (0x11) .maxstack 2 IL_0000: ldarga.s V_0 IL_0002: constrained. ""S1"" IL_0008: callvirt ""object S1.IUnionMembers.Value.get"" IL_000d: ldnull IL_000e: ceq IL_0010: ret } "); } [Fact] public void NonBoxingUnionMatching_MemberProvider_HasValue_Inheritance_04_Generic() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 : S1.IUnionMembers { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } object IUnionMembers.Value => throw null; bool IUnionMembersBase<bool>.HasValue => _value is not null; public interface IUnionMembers : IUnionMembersBase<bool> { public static S1 Create(int x) => new S1(x); public static S1 Create(string x) => new S1(x); public object Value { get; } } public interface IUnionMembersBase<T> { public T HasValue { get; } } } class Program { static void Main() { System.Console.Write(Test1(new S1(1))); System.Console.Write(Test1(new S1())); } static bool Test1(S1 u) { return u is null; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); var verifier = CompileAndVerify(comp, expectedOutput: "FalseTrue").VerifyDiagnostics(); verifier.VerifyIL("Program.Test1", @" { // Code size 17 (0x11) .maxstack 2 IL_0000: ldarga.s V_0 IL_0002: constrained. ""S1"" IL_0008: callvirt ""bool S1.IUnionMembersBase<bool>.HasValue.get"" IL_000d: ldc.i4.0 IL_000e: ceq IL_0010: ret } "); } [Fact] public void NonBoxingUnionMatching_MemberProvider_HasValue_Inheritance_05_InGenericUnion() { var src = @" [System.Runtime.CompilerServices.Union] struct S1<T> : S1<T>.IUnionMembers { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } object IUnionMembers.Value => throw null; bool IUnionMembersBase.HasValue => _value is not null; public interface IUnionMembers : IUnionMembersBase { public static S1<T> Create(int x) => new S1<T>(x); public static S1<T> Create(string x) => new S1<T>(x); public object Value { get; } } public interface IUnionMembersBase { public bool HasValue { get; } } } class Program { static void Main() { System.Console.Write(Test1(new S1<long>(1))); System.Console.Write(Test1(new S1<long>())); } static bool Test1(S1<long> u) { return u is null; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); var verifier = CompileAndVerify(comp, expectedOutput: "FalseTrue").VerifyDiagnostics(); verifier.VerifyIL("Program.Test1", @" { // Code size 17 (0x11) .maxstack 2 IL_0000: ldarga.s V_0 IL_0002: constrained. ""S1<long>"" IL_0008: callvirt ""bool S1<long>.IUnionMembersBase.HasValue.get"" IL_000d: ldc.i4.0 IL_000e: ceq IL_0010: ret } "); } [Fact] public void NonBoxingUnionMatching_MemberProvider_HasValue_Inheritance_06_InGenericUnion() { var src = @" [System.Runtime.CompilerServices.Union] struct S1<T> : S1<T>.IUnionMembers { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } object IUnionMembers.Value => throw null; bool IUnionMembersBase.HasValue => _value is not null; public interface IUnionMembers : IUnionMembersBase { public static S1<T> Create(int x) => new S1<T>(x); public static S1<T> Create(string x) => new S1<T>(x); public object Value { get; } } } public interface IUnionMembersBase { public bool HasValue { get; } } class Program { static void Main() { System.Console.Write(Test1(new S1<long>(1))); System.Console.Write(Test1(new S1<long>())); } static bool Test1(S1<long> u) { return u is null; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); var verifier = CompileAndVerify(comp, expectedOutput: "FalseTrue").VerifyDiagnostics(); verifier.VerifyIL("Program.Test1", @" { // Code size 17 (0x11) .maxstack 2 IL_0000: ldarga.s V_0 IL_0002: constrained. ""S1<long>"" IL_0008: callvirt ""bool IUnionMembersBase.HasValue.get"" IL_000d: ldc.i4.0 IL_000e: ceq IL_0010: ret } "); } [Fact] public void NonBoxingUnionMatching_MemberProvider_HasValue_Inheritance_07_InGenericUnion() { var src = @" [System.Runtime.CompilerServices.Union] struct S1<T> : S1<T>.IUnionMembers { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } object IUnionMembers.Value => throw null; bool IUnionMembersBase<T>.HasValue => _value is not null; public interface IUnionMembers : IUnionMembersBase<T> { public static S1<T> Create(int x) => new S1<T>(x); public static S1<T> Create(string x) => new S1<T>(x); public object Value { get; } } } public interface IUnionMembersBase<T> { public bool HasValue { get; } } class Program { static void Main() { System.Console.Write(Test1(new S1<long>(1))); System.Console.Write(Test1(new S1<long>())); } static bool Test1(S1<long> u) { return u is null; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); var verifier = CompileAndVerify(comp, expectedOutput: "FalseTrue").VerifyDiagnostics(); verifier.VerifyIL("Program.Test1", @" { // Code size 17 (0x11) .maxstack 2 IL_0000: ldarga.s V_0 IL_0002: constrained. ""S1<long>"" IL_0008: callvirt ""bool IUnionMembersBase<long>.HasValue.get"" IL_000d: ldc.i4.0 IL_000e: ceq IL_0010: ret } "); } [Theory] [CombinatorialData] public void NonBoxingUnionMatching_MemberProvider_HasValue_Inheritance_08_Provider_NotPublic([CombinatorialValues("internal", "internal protected")] string accessibility) { var src = @" [System.Runtime.CompilerServices.Union] class S1 : S1.IUnionMembers { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } object IUnionMembers.Value => throw null; bool IUnionMembersBase.HasValue => _value != null; public interface IUnionMembers : IUnionMembersBase { public static S1 Create(int x) => new S1(x); public static S1 Create(string x) => new S1(x); public object Value { get; } } " + accessibility + @" interface IUnionMembersBase { public bool HasValue { get; } } } class Program { static void Main() { System.Console.Write(Test1(new S1(1))); System.Console.Write(Test1(new S1(null))); System.Console.Write(Test1(null)); } static bool Test1(S1 u) { return u is null; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); var verifier = CompileAndVerify(comp, expectedOutput: "FalseTrueTrue").VerifyDiagnostics(); verifier.VerifyIL("Program.Test1", @" { // Code size 19 (0x13) .maxstack 1 .locals init (bool V_0) IL_0000: ldarg.0 IL_0001: brfalse.s IL_000b IL_0003: ldarg.0 IL_0004: callvirt ""bool S1.IUnionMembersBase.HasValue.get"" IL_0009: brtrue.s IL_000f IL_000b: ldc.i4.1 IL_000c: stloc.0 IL_000d: br.s IL_0011 IL_000f: ldc.i4.0 IL_0010: stloc.0 IL_0011: ldloc.0 IL_0012: ret } "); } [Theory] [CombinatorialData] public void NonBoxingUnionMatching_MemberProvider_HasValue_Inheritance_09_Provider_NotPublic([CombinatorialValues("", "private", "internal", "protected", "internal protected", "private protected")] string accessibility) { var src = @" [System.Runtime.CompilerServices.Union] public class S1 : S1.IUnionMembers { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } object IUnionMembers.Value => throw null; bool IUnionMembersBase.HasValue => _value != null; public interface IUnionMembers : IUnionMembersBase { public static S1 Create(int x) => new S1(x); public static S1 Create(string x) => new S1(x); public object Value { get; } } " + accessibility + @" interface IUnionMembersBase { public bool HasValue { get; } } } class Program { static void Main() { System.Console.Write(Test1(new S1(1))); System.Console.Write(Test1(new S1(null))); System.Console.Write(Test1(null)); } static bool Test1(S1 u) { return u is null; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); comp.VerifyEmitDiagnostics( // (11,22): error CS0061: Inconsistent accessibility: base interface 'S1.IUnionMembersBase' is less accessible than interface 'S1.IUnionMembers' // public interface IUnionMembers : IUnionMembersBase Diagnostic(ErrorCode.ERR_BadVisBaseInterface, "IUnionMembers").WithArguments("S1.IUnionMembers", "S1.IUnionMembersBase").WithLocation(11, 22) ); } [Theory] [CombinatorialData] public void NonBoxingUnionMatching_MemberProvider_HasValue_Inheritance_10_NotPublic([CombinatorialValues("private", "internal", "protected", "internal protected", "private protected")] string accessibility) { var src = @" [System.Runtime.CompilerServices.Union] struct S1 : S1.IUnionMembers { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } object IUnionMembers.Value => _value; " + (accessibility == "private" ? "" : "bool IUnionMembersBase.HasValue => throw null;") + @" public interface IUnionMembers : IUnionMembersBase { public static S1 Create(int x) => new S1(x); public static S1 Create(string x) => new S1(x); public object Value { get; } } public interface IUnionMembersBase { " + accessibility + @" bool HasValue { get" + (accessibility == "private" ? " => throw null" : "") + @"; } } } class Program { static void Main() { System.Console.Write(Test1(new S1(1))); System.Console.Write(Test1(new S1())); } static bool Test1(S1 u) { return u is null; } } "; var comp = CreateCompilation([src, UnionAttributeSource], targetFramework: TargetFramework.NetCoreApp, options: TestOptions.ReleaseExe); var verifier = CompileAndVerify(comp, expectedOutput: ExecutionConditionUtil.IsMonoOrCoreClr ? "FalseTrue" : null, verify: Verification.FailsPEVerify).VerifyDiagnostics(); verifier.VerifyIL("Program.Test1", @" { // Code size 17 (0x11) .maxstack 2 IL_0000: ldarga.s V_0 IL_0002: constrained. ""S1"" IL_0008: callvirt ""object S1.IUnionMembers.Value.get"" IL_000d: ldnull IL_000e: ceq IL_0010: ret } "); } [Theory] [CombinatorialData] public void NonBoxingUnionMatching_MemberProvider_HasValue_Inheritance_11_NotPublic_Get([CombinatorialValues("private", "internal", "protected", "internal protected", "private protected")] string accessibility) { var src = @" [System.Runtime.CompilerServices.Union] struct S1 : S1.IUnionMembers { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } object IUnionMembers.Value => _value; " + (accessibility == "private" ? "" : "bool IUnionMembersBase.HasValue { get => throw null; set => throw null; }") + @" public interface IUnionMembers : IUnionMembersBase { public static S1 Create(int x) => new S1(x); public static S1 Create(string x) => new S1(x); public object Value { get; } } public interface IUnionMembersBase { public bool HasValue { " + accessibility + @" get" + (accessibility == "private" ? " => throw null" : "") + @"; set" + (accessibility == "private" ? " => throw null" : "") + @"; } } } class Program { static void Main() { System.Console.Write(Test1(new S1(1))); System.Console.Write(Test1(new S1())); } static bool Test1(S1 u) { return u is null; } } "; var comp = CreateCompilation([src, UnionAttributeSource], targetFramework: TargetFramework.NetCoreApp, options: TestOptions.ReleaseExe); var verifier = CompileAndVerify(comp, expectedOutput: ExecutionConditionUtil.IsMonoOrCoreClr ? "FalseTrue" : null, verify: Verification.FailsPEVerify).VerifyDiagnostics(); verifier.VerifyIL("Program.Test1", @" { // Code size 17 (0x11) .maxstack 2 IL_0000: ldarga.s V_0 IL_0002: constrained. ""S1"" IL_0008: callvirt ""object S1.IUnionMembers.Value.get"" IL_000d: ldnull IL_000e: ceq IL_0010: ret } "); } [Fact] public void NonBoxingUnionMatching_MemberProvider_HasValue_Inheritance_12_WrongType() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 : S1.IUnionMembers { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } object IUnionMembers.Value => _value; System.IComparable IUnionMembersBase.HasValue => throw null; public interface IUnionMembers : IUnionMembersBase { public static S1 Create(int x) => new S1(x); public static S1 Create(string x) => new S1(x); public object Value { get; } } public interface IUnionMembersBase { public System.IComparable HasValue { get; } } } class Program { static void Main() { System.Console.Write(Test1(new S1(1))); System.Console.Write(Test1(new S1())); } static bool Test1(S1 u) { return u is null; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); var verifier = CompileAndVerify(comp, expectedOutput: "FalseTrue").VerifyDiagnostics(); verifier.VerifyIL("Program.Test1", @" { // Code size 17 (0x11) .maxstack 2 IL_0000: ldarga.s V_0 IL_0002: constrained. ""S1"" IL_0008: callvirt ""object S1.IUnionMembers.Value.get"" IL_000d: ldnull IL_000e: ceq IL_0010: ret } "); } [Fact] public void NonBoxingUnionMatching_MemberProvider_HasValue_Inheritance_13_WrongType() { var src = @" [System.Runtime.CompilerServices.Union] struct S1<T> : S1<T>.IUnionMembers { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } object IUnionMembers.Value => _value; T IUnionMembersBase.HasValue => throw null; public interface IUnionMembers : IUnionMembersBase { public static S1<T> Create(int x) => new S1<T>(x); public static S1<T> Create(string x) => new S1<T>(x); public object Value { get; } } public interface IUnionMembersBase { public T HasValue { get; } } } class Program { static void Main() { System.Console.Write(Test1(new S1<bool>(1))); System.Console.Write(Test1(new S1<bool>())); } static bool Test1(S1<bool> u) { return u is null; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); var verifier = CompileAndVerify(comp, expectedOutput: "FalseTrue").VerifyDiagnostics(); verifier.VerifyIL("Program.Test1", @" { // Code size 17 (0x11) .maxstack 2 IL_0000: ldarga.s V_0 IL_0002: constrained. ""S1<bool>"" IL_0008: callvirt ""object S1<bool>.IUnionMembers.Value.get"" IL_000d: ldnull IL_000e: ceq IL_0010: ret } "); } [Theory] [CombinatorialData] public void NonBoxingUnionMatching_MemberProvider_HasValue_Inheritance_14_WrongRefKind([CombinatorialValues("ref", "ref readonly")] string refModifier) { var src = @" [System.Runtime.CompilerServices.Union] struct S1 : S1.IUnionMembers { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } object IUnionMembers.Value => _value; " + refModifier + @" bool IUnionMembersBase.HasValue => throw null; public interface IUnionMembers : IUnionMembersBase { public static S1 Create(int x) => new S1(x); public static S1 Create(string x) => new S1(x); public object Value { get; } } public interface IUnionMembersBase { public " + refModifier + @" bool HasValue { get; } } } class Program { static void Main() { System.Console.Write(Test1(new S1(1))); System.Console.Write(Test1(new S1())); } static bool Test1(S1 u) { return u is null; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); var verifier = CompileAndVerify(comp, expectedOutput: "FalseTrue").VerifyDiagnostics(); verifier.VerifyIL("Program.Test1", @" { // Code size 17 (0x11) .maxstack 2 IL_0000: ldarga.s V_0 IL_0002: constrained. ""S1"" IL_0008: callvirt ""object S1.IUnionMembers.Value.get"" IL_000d: ldnull IL_000e: ceq IL_0010: ret } "); } [Fact] public void NonBoxingUnionMatching_MemberProvider_HasValue_Inheritance_15_Static() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 : S1.IUnionMembers { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } object IUnionMembers.Value => _value; public interface IUnionMembers : IUnionMembersBase { public static S1 Create(int x) => new S1(x); public static S1 Create(string x) => new S1(x); public object Value { get; } } public interface IUnionMembersBase { public static bool HasValue => throw null; } } class Program { static void Main() { System.Console.Write(Test1(new S1(1))); System.Console.Write(Test1(new S1())); } static bool Test1(S1 u) { return u is null; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); var verifier = CompileAndVerify(comp, expectedOutput: "FalseTrue").VerifyDiagnostics(); verifier.VerifyIL("Program.Test1", @" { // Code size 17 (0x11) .maxstack 2 IL_0000: ldarga.s V_0 IL_0002: constrained. ""S1"" IL_0008: callvirt ""object S1.IUnionMembers.Value.get"" IL_000d: ldnull IL_000e: ceq IL_0010: ret } "); } [Fact] public void NonBoxingUnionMatching_MemberProvider_HasValue_Inheritance_16_NotVirtual() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 : S1.IUnionMembers { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } object IUnionMembers.Value => throw null; public interface IUnionMembers : IUnionMembersBase { public static S1 Create(int x) => new S1(x); public static S1 Create(string x) => new S1(x); public object Value { get; } } public interface IUnionMembersBase { public sealed bool HasValue => ((S1)this)._value != null; } } class Program { static void Main() { System.Console.Write(Test1(new S1(1))); System.Console.Write(Test1(new S1())); } static bool Test1(S1 u) { return u is null; } } "; var comp = CreateCompilation([src, UnionAttributeSource], targetFramework: TargetFramework.NetCoreApp, options: TestOptions.ReleaseExe); var verifier = CompileAndVerify(comp, expectedOutput: ExecutionConditionUtil.IsMonoOrCoreClr ? "FalseTrue" : null, verify: Verification.FailsPEVerify).VerifyDiagnostics(); verifier.VerifyIL("Program.Test1", @" { // Code size 15 (0xf) .maxstack 2 IL_0000: ldarg.0 IL_0001: box ""S1"" IL_0006: call ""bool S1.IUnionMembersBase.HasValue.get"" IL_000b: ldc.i4.0 IL_000c: ceq IL_000e: ret } "); } [Fact] public void NonBoxingUnionMatching_MemberProvider_HasValue_Inheritance_17_Shadowing() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 : S1.IUnionMembers { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } object IUnionMembers.Value => throw null; bool IUnionMembers.HasValue => _value != null; bool IUnionMembersBase.HasValue => throw null; public interface IUnionMembers : IUnionMembersBase { public static S1 Create(int x) => new S1(x); public static S1 Create(string x) => new S1(x); public object Value { get; } new public bool HasValue { get; } } public interface IUnionMembersBase { public bool HasValue { get; } } } class Program { static void Main() { System.Console.Write(Test1(new S1(1))); System.Console.Write(Test1(new S1())); } static bool Test1(S1 u) { return u is null; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); var verifier = CompileAndVerify(comp, expectedOutput: "FalseTrue").VerifyDiagnostics(); verifier.VerifyIL("Program.Test1", @" { // Code size 17 (0x11) .maxstack 2 IL_0000: ldarga.s V_0 IL_0002: constrained. ""S1"" IL_0008: callvirt ""bool S1.IUnionMembers.HasValue.get"" IL_000d: ldc.i4.0 IL_000e: ceq IL_0010: ret } "); } [Fact] public void NonBoxingUnionMatching_MemberProvider_HasValue_Inheritance_18_Shadowing() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 : S1.IUnionMembers { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } object IUnionMembers.Value => throw null; bool IBase2.HasValue => _value != null; bool IBase1.HasValue => throw null; public interface IUnionMembers : IBase1, IBase2 { public static S1 Create(int x) => new S1(x); public static S1 Create(string x) => new S1(x); public object Value { get; } } public interface IBase2 : IBase1 { new public bool HasValue { get; } } public interface IBase1 { public bool HasValue { get; } } } class Program { static void Main() { System.Console.Write(Test1(new S1(1))); System.Console.Write(Test1(new S1())); } static bool Test1(S1 u) { return u is null; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); var verifier = CompileAndVerify(comp, expectedOutput: "FalseTrue").VerifyDiagnostics(); verifier.VerifyIL("Program.Test1", @" { // Code size 17 (0x11) .maxstack 2 IL_0000: ldarga.s V_0 IL_0002: constrained. ""S1"" IL_0008: callvirt ""bool S1.IBase2.HasValue.get"" IL_000d: ldc.i4.0 IL_000e: ceq IL_0010: ret } "); } [Fact] public void NonBoxingUnionMatching_MemberProvider_HasValue_Inheritance_19_Shadowing() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 : S1.IUnionMembers { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } object IUnionMembers.Value => throw null; bool IUnionMembers.HasValue => _value != null; bool IBase<bool>.HasValue => throw null; public interface IUnionMembers : IBase<bool> { public static S1 Create(int x) => new S1(x); public static S1 Create(string x) => new S1(x); public object Value { get; } new public bool HasValue { get; } } public interface IBase<T> { public T HasValue { get; } } } class Program { static void Main() { System.Console.Write(Test1(new S1(1))); System.Console.Write(Test1(new S1())); } static bool Test1(S1 u) { return u is null; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); var verifier = CompileAndVerify(comp, expectedOutput: "FalseTrue").VerifyDiagnostics(); verifier.VerifyIL("Program.Test1", @" { // Code size 17 (0x11) .maxstack 2 IL_0000: ldarga.s V_0 IL_0002: constrained. ""S1"" IL_0008: callvirt ""bool S1.IUnionMembers.HasValue.get"" IL_000d: ldc.i4.0 IL_000e: ceq IL_0010: ret } "); } [Fact] public void NonBoxingUnionMatching_MemberProvider_HasValue_Inheritance_20_Shadowing() { var src = @" [System.Runtime.CompilerServices.Union] struct S1<T> : S1<T>.IUnionMembers { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } object IUnionMembers.Value => throw null; bool IUnionMembers.HasValue => _value != null; T IBase<T>.HasValue => throw null; public interface IUnionMembers : IBase<T> { public static S1<T> Create(int x) => new S1<T>(x); public static S1<T> Create(string x) => new S1<T>(x); public object Value { get; } new public bool HasValue { get; } } } public interface IBase<T> { public T HasValue { get; } } class Program { static void Main() { System.Console.Write(Test1(new S1<bool>(1))); System.Console.Write(Test1(new S1<bool>())); } static bool Test1(S1<bool> u) { return u is null; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); var verifier = CompileAndVerify(comp, expectedOutput: "FalseTrue").VerifyDiagnostics(); verifier.VerifyIL("Program.Test1", @" { // Code size 17 (0x11) .maxstack 2 IL_0000: ldarga.s V_0 IL_0002: constrained. ""S1<bool>"" IL_0008: callvirt ""bool S1<bool>.IUnionMembers.HasValue.get"" IL_000d: ldc.i4.0 IL_000e: ceq IL_0010: ret } "); } [Fact] public void NonBoxingUnionMatching_MemberProvider_HasValue_Inheritance_21_Shadowing() { var src = @" [System.Runtime.CompilerServices.Union] struct S1<T> : S1<T>.IUnionMembers { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } object IUnionMembers.Value => throw null; bool IUnionMembers.HasValue => _value != null; bool IBase<T>.HasValue => throw null; public interface IUnionMembers : IBase<T> { public static S1<T> Create(int x) => new S1<T>(x); public static S1<T> Create(string x) => new S1<T>(x); public object Value { get; } new public bool HasValue { get; } } } public interface IBase<T> { public bool HasValue { get; } } class Program { static void Main() { System.Console.Write(Test1(new S1<bool>(1))); System.Console.Write(Test1(new S1<bool>())); } static bool Test1(S1<bool> u) { return u is null; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); var verifier = CompileAndVerify(comp, expectedOutput: "FalseTrue").VerifyDiagnostics(); verifier.VerifyIL("Program.Test1", @" { // Code size 17 (0x11) .maxstack 2 IL_0000: ldarga.s V_0 IL_0002: constrained. ""S1<bool>"" IL_0008: callvirt ""bool S1<bool>.IUnionMembers.HasValue.get"" IL_000d: ldc.i4.0 IL_000e: ceq IL_0010: ret } "); } [Fact] public void NonBoxingUnionMatching_MemberProvider_HasValue_Inheritance_22_Shadowing() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 : S1.IUnionMembers { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } object IUnionMembers.Value => throw null; bool IBase2.HasValue => _value != null; bool IBase1.HasValue => throw null; bool IBase0.HasValue => throw null; public interface IUnionMembers : IBase0, IBase1, IBase2 { public static S1 Create(int x) => new S1(x); public static S1 Create(string x) => new S1(x); public object Value { get; } } public interface IBase2 : IBase1 { new public bool HasValue { get; } } public interface IBase1 : IBase0 { new public bool HasValue { get; } } public interface IBase0 { public bool HasValue { get; } } } class Program { static void Main() { System.Console.Write(Test1(new S1(1))); System.Console.Write(Test1(new S1())); } static bool Test1(S1 u) { return u is null; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); var verifier = CompileAndVerify(comp, expectedOutput: "FalseTrue").VerifyDiagnostics(); verifier.VerifyIL("Program.Test1", @" { // Code size 17 (0x11) .maxstack 2 IL_0000: ldarga.s V_0 IL_0002: constrained. ""S1"" IL_0008: callvirt ""bool S1.IBase2.HasValue.get"" IL_000d: ldc.i4.0 IL_000e: ceq IL_0010: ret } "); } [Fact] public void NonBoxingUnionMatching_MemberProvider_HasValue_Inheritance_23_Shadowing() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 : S1.IUnionMembers { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } object IUnionMembers.Value => throw null; bool IUnionMembersBase.HasValue => _value != null; int IUnionMembers.HasValue => throw null; public interface IUnionMembers : IUnionMembersBase { public static S1 Create(int x) => new S1(x); public static S1 Create(string x) => new S1(x); public object Value { get; } new public int HasValue { get; } } public interface IUnionMembersBase { public bool HasValue { get; } } } class Program { static void Main() { System.Console.Write(Test1(new S1(1))); System.Console.Write(Test1(new S1())); } static bool Test1(S1 u) { return u is null; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); var verifier = CompileAndVerify(comp, expectedOutput: "FalseTrue").VerifyDiagnostics(); verifier.VerifyIL("Program.Test1", @" { // Code size 17 (0x11) .maxstack 2 IL_0000: ldarga.s V_0 IL_0002: constrained. ""S1"" IL_0008: callvirt ""bool S1.IUnionMembersBase.HasValue.get"" IL_000d: ldc.i4.0 IL_000e: ceq IL_0010: ret } "); } [Fact] public void NonBoxingUnionMatching_MemberProvider_HasValue_Inheritance_24_Shadowing() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 : S1.IUnionMembers { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } object IUnionMembers.Value => throw null; bool IUnionMembersBase.HasValue => _value != null; bool IUnionMembers.HasValue() => throw null; public interface IUnionMembers : IUnionMembersBase { public static S1 Create(int x) => new S1(x); public static S1 Create(string x) => new S1(x); public object Value { get; } new public bool HasValue(); } public interface IUnionMembersBase { public bool HasValue { get; } } } class Program { static void Main() { System.Console.Write(Test1(new S1(1))); System.Console.Write(Test1(new S1())); } static bool Test1(S1 u) { return u is null; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); var verifier = CompileAndVerify(comp, expectedOutput: "FalseTrue").VerifyDiagnostics(); verifier.VerifyIL("Program.Test1", @" { // Code size 17 (0x11) .maxstack 2 IL_0000: ldarga.s V_0 IL_0002: constrained. ""S1"" IL_0008: callvirt ""bool S1.IUnionMembersBase.HasValue.get"" IL_000d: ldc.i4.0 IL_000e: ceq IL_0010: ret } "); } [Fact] public void NonBoxingUnionMatching_MemberProvider_HasValue_Inheritance_25_Shadowing() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 : S1.IUnionMembers { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } object IUnionMembers.Value => throw null; bool IBase1.HasValue => _value != null; int IBase2.HasValue => throw null; public interface IUnionMembers : IBase2, IBase1 { public static S1 Create(int x) => new S1(x); public static S1 Create(string x) => new S1(x); public object Value { get; } } public interface IBase2 : IBase1 { new public int HasValue { get; } } public interface IBase1 { public bool HasValue { get; } } } class Program { static void Main() { System.Console.Write(Test1(new S1(1))); System.Console.Write(Test1(new S1())); } static bool Test1(S1 u) { return u is null; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); var verifier = CompileAndVerify(comp, expectedOutput: "FalseTrue").VerifyDiagnostics(); verifier.VerifyIL("Program.Test1", @" { // Code size 17 (0x11) .maxstack 2 IL_0000: ldarga.s V_0 IL_0002: constrained. ""S1"" IL_0008: callvirt ""bool S1.IBase1.HasValue.get"" IL_000d: ldc.i4.0 IL_000e: ceq IL_0010: ret } "); } [Fact] public void NonBoxingUnionMatching_MemberProvider_HasValue_Inheritance_26_Shadowing() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 : S1.IUnionMembers { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } object IUnionMembers.Value => throw null; bool IBase1.HasValue => _value != null; bool IBase2.HasValue() => throw null; public interface IUnionMembers : IBase2, IBase1 { public static S1 Create(int x) => new S1(x); public static S1 Create(string x) => new S1(x); public object Value { get; } } public interface IBase2 : IBase1 { new public bool HasValue(); } public interface IBase1 { public bool HasValue { get; } } } class Program { static void Main() { System.Console.Write(Test1(new S1(1))); System.Console.Write(Test1(new S1())); } static bool Test1(S1 u) { return u is null; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); var verifier = CompileAndVerify(comp, expectedOutput: "FalseTrue").VerifyDiagnostics(); verifier.VerifyIL("Program.Test1", @" { // Code size 17 (0x11) .maxstack 2 IL_0000: ldarga.s V_0 IL_0002: constrained. ""S1"" IL_0008: callvirt ""bool S1.IBase1.HasValue.get"" IL_000d: ldc.i4.0 IL_000e: ceq IL_0010: ret } "); } [Fact] public void NonBoxingUnionMatching_MemberProvider_TryGetValue_01_Struct() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 : S1.IUnionMembers { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } object IUnionMembers.Value => throw null; bool IUnionMembers.TryGetValue(out int x) { if (_value is int v) { x = v; return true; } x = 0; return false; } public interface IUnionMembers { public static S1 Create(int x) => new S1(x); public static S1 Create(string x) => new S1(x); public object Value { get; } public bool TryGetValue(out int x); } static void Main() { System.Console.Write(Test1(new S1(1))); System.Console.Write(Test1(new S1())); System.Console.Write(Test1(new S1(""a""))); System.Console.Write(Test2(new S1(2))); System.Console.Write(Test2(new S1())); System.Console.Write(Test2(new S1(""b""))); } static bool Test1(S1 u) { return u is int; } static bool Test2(S1 u) { return u is not int; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); var verifier = CompileAndVerify(comp, expectedOutput: "TrueFalseFalseFalseTrueTrue").VerifyDiagnostics(); verifier.VerifyIL("S1.Test1", @" { // Code size 16 (0x10) .maxstack 2 .locals init (int V_0) IL_0000: ldarga.s V_0 IL_0002: ldloca.s V_0 IL_0004: constrained. ""S1"" IL_000a: callvirt ""bool S1.IUnionMembers.TryGetValue(out int)"" IL_000f: ret } "); verifier.VerifyIL("S1.Test2", @" { // Code size 19 (0x13) .maxstack 2 .locals init (int V_0) IL_0000: ldarga.s V_0 IL_0002: ldloca.s V_0 IL_0004: constrained. ""S1"" IL_000a: callvirt ""bool S1.IUnionMembers.TryGetValue(out int)"" IL_000f: ldc.i4.0 IL_0010: ceq IL_0012: ret } "); } [Fact] public void NonBoxingUnionMatching_MemberProvider_TryGetValue_02_Class() { var src = @" [System.Runtime.CompilerServices.Union] class S1 : S1.IUnionMembers { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } object IUnionMembers.Value => throw null; bool IUnionMembers.TryGetValue(out int x) { if (_value is int v) { x = v; return true; } x = 0; return false; } public interface IUnionMembers { public static S1 Create(int x) => new S1(x); public static S1 Create(string x) => new S1(x); public object Value { get; } public bool TryGetValue(out int x); } static void Main() { System.Console.Write(Test1(new S1(1))); System.Console.Write(Test1(new S1(null))); System.Console.Write(Test1(new S1(""a""))); System.Console.Write(Test1(null)); System.Console.Write(Test2(new S1(2))); System.Console.Write(Test2(new S1(null))); System.Console.Write(Test2(new S1(""b""))); System.Console.Write(Test2(null)); } static bool Test1(S1 u) { return u is int; } static bool Test2(S1 u) { return u is not int; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); var verifier = CompileAndVerify(comp, expectedOutput: "TrueFalseFalseFalseFalseTrueTrueTrue").VerifyDiagnostics(); verifier.VerifyIL("S1.Test1", @" { // Code size 14 (0xe) .maxstack 2 .locals init (int V_0) IL_0000: ldarg.0 IL_0001: brfalse.s IL_000c IL_0003: ldarg.0 IL_0004: ldloca.s V_0 IL_0006: callvirt ""bool S1.IUnionMembers.TryGetValue(out int)"" IL_000b: ret IL_000c: ldc.i4.0 IL_000d: ret } "); verifier.VerifyIL("S1.Test2", @" { // Code size 18 (0x12) .maxstack 2 .locals init (int V_0) IL_0000: ldarg.0 IL_0001: brfalse.s IL_000d IL_0003: ldarg.0 IL_0004: ldloca.s V_0 IL_0006: callvirt ""bool S1.IUnionMembers.TryGetValue(out int)"" IL_000b: br.s IL_000e IL_000d: ldc.i4.0 IL_000e: ldc.i4.0 IL_000f: ceq IL_0011: ret } "); } [Fact] public void NonBoxingUnionMatching_MemberProvider_TryGetValue_03_MemberFromTypeNotUsed() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 : S1.IUnionMembers { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } public bool TryGetValue(out int x) => throw null; object IUnionMembers.Value => throw null; bool IUnionMembers.TryGetValue(out int x) { if (_value is int v) { x = v; return true; } x = 0; return false; } public interface IUnionMembers { public static S1 Create(int x) => new S1(x); public static S1 Create(string x) => new S1(x); public object Value { get; } public bool TryGetValue(out int x); } static void Main() { System.Console.Write(Test1(new S1(1))); System.Console.Write(Test1(new S1())); System.Console.Write(Test2(new S1(2))); System.Console.Write(Test2(new S1())); } static bool Test1(S1 u) { return u is not int; } static bool Test2(S1 u) { return u is int; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); var verifier = CompileAndVerify(comp, expectedOutput: "FalseTrueTrueFalse").VerifyDiagnostics(); verifier.VerifyIL("S1.Test1", @" { // Code size 19 (0x13) .maxstack 2 .locals init (int V_0) IL_0000: ldarga.s V_0 IL_0002: ldloca.s V_0 IL_0004: constrained. ""S1"" IL_000a: callvirt ""bool S1.IUnionMembers.TryGetValue(out int)"" IL_000f: ldc.i4.0 IL_0010: ceq IL_0012: ret } "); verifier.VerifyIL("S1.Test2", @" { // Code size 16 (0x10) .maxstack 2 .locals init (int V_0) IL_0000: ldarga.s V_0 IL_0002: ldloca.s V_0 IL_0004: constrained. ""S1"" IL_000a: callvirt ""bool S1.IUnionMembers.TryGetValue(out int)"" IL_000f: ret } "); } [Fact] public void NonBoxingUnionMatching_MemberProvider_TryGetValue_04_MemberFromTypeNotUsed() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 : S1.IUnionMembers { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } public bool TryGetValue(out int x) => throw null; object IUnionMembers.Value => _value; public interface IUnionMembers { public static S1 Create(int x) => new S1(x); public static S1 Create(string x) => new S1(x); public object Value { get; } } static void Main() { System.Console.Write(Test1(new S1(1))); System.Console.Write(Test1(new S1())); System.Console.Write(Test2(new S1(2))); System.Console.Write(Test2(new S1())); } static bool Test1(S1 u) { return u is not int; } static bool Test2(S1 u) { return u is int; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); var verifier = CompileAndVerify(comp, expectedOutput: "FalseTrueTrueFalse").VerifyDiagnostics(); verifier.VerifyIL("S1.Test1", @" { // Code size 25 (0x19) .maxstack 2 IL_0000: ldarga.s V_0 IL_0002: constrained. ""S1"" IL_0008: callvirt ""object S1.IUnionMembers.Value.get"" IL_000d: isinst ""int"" IL_0012: ldnull IL_0013: cgt.un IL_0015: ldc.i4.0 IL_0016: ceq IL_0018: ret } "); verifier.VerifyIL("S1.Test2", @" { // Code size 22 (0x16) .maxstack 2 IL_0000: ldarga.s V_0 IL_0002: constrained. ""S1"" IL_0008: callvirt ""object S1.IUnionMembers.Value.get"" IL_000d: isinst ""int"" IL_0012: ldnull IL_0013: cgt.un IL_0015: ret } "); } [Fact] public void NonBoxingUnionMatching_MemberProvider_TryGetValue_05_Generic() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 : S1.IUnionMembers<int> { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } public object Value => _value; object IUnionMembers<int>.Value => throw null; bool IUnionMembers<int>.TryGetValue(out int x) => throw null; public interface IUnionMembers<T> { public static S1 Create(int x) => throw null; public object Value { get; } public bool TryGetValue(out T x); } } class Program { static void Main() { System.Console.Write(Test1(new S1(10))); System.Console.Write(Test1(default)); System.Console.Write(Test1(new S1(""11""))); } static bool Test1(S1 u) { return u is int; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); var verifier = CompileAndVerify(comp, expectedOutput: "TrueFalseFalse").VerifyDiagnostics(); verifier.VerifyIL("Program.Test1", @" { // Code size 16 (0x10) .maxstack 2 IL_0000: ldarga.s V_0 IL_0002: call ""object S1.Value.get"" IL_0007: isinst ""int"" IL_000c: ldnull IL_000d: cgt.un IL_000f: ret } "); } [Fact] public void NonBoxingUnionMatching_MemberProvider_TryGetValue_06_Generic() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 : S1.IUnionMembers { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } public object Value => throw null; object IUnionMembers.Value => throw null; bool IUnionMembers.TryGetValue(out int x) { if (_value is int v) { x = v; return true; } x = 0; return false; } public interface IUnionMembers<T>; public interface IUnionMembers { public static S1 Create(int x) => new S1(x); public static S1 Create(string x) => new S1(x); public object Value { get; } public bool TryGetValue(out int x); } public interface IUnionMembers<T, S>; } class Program { static void Main() { System.Console.Write(Test1(new S1(10))); System.Console.Write(Test1(default)); System.Console.Write(Test1(new S1(""11""))); } static bool Test1(S1 u) { return u is int; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); CompileAndVerify(comp, expectedOutput: "TrueFalseFalse").VerifyDiagnostics(); } [Fact] public void NonBoxingUnionMatching_MemberProvider_TryGetValue_07_InGenericUnion() { var src = @" [System.Runtime.CompilerServices.Union] struct S1<T> : S1<T>.IUnionMembers { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } public object Value => throw null; object IUnionMembers.Value => throw null; bool IUnionMembers.TryGetValue(out int x) { if (_value is int v) { x = v; return true; } x = 0; return false; } public interface IUnionMembers { public static S1<T> Create(int x) => new S1<T>(x); public static S1<T> Create(string x) => new S1<T>(x); public object Value { get; } public bool TryGetValue(out int x); } } class Program { static void Main() { System.Console.Write(Test1(new S1<long>(10))); System.Console.Write(Test1(default)); System.Console.Write(Test1(new S1<long>(""11""))); System.Console.Write(Test1(new S1<long>(0))); } static bool Test1(S1<long> u) { return u is int; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); CompileAndVerify(comp, expectedOutput: "TrueFalseFalseTrue").VerifyDiagnostics(); } [Fact] public void NonBoxingUnionMatching_MemberProvider_TryGetValue_08_WrongGenericSubstitution() { var src = @" [System.Runtime.CompilerServices.Union] struct S1<T> : S1<long>.IUnionMembers { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } public object Value => throw null; public bool TryGetValue(out int x) { if (_value is int v) { x = v; return true; } x = 0; return false; } object S1<long>.IUnionMembers.Value => throw null; bool S1<long>.IUnionMembers.TryGetValue(out int x) => throw null; public interface IUnionMembers { public static S1<T> Create(int x) => throw null; public static S1<T> Create(string x) => throw null; public object Value { get; } public bool TryGetValue(out int x); } } class Program { static void Main() { System.Console.Write(Test1(new S1<long>(10))); System.Console.Write(Test1(default)); System.Console.Write(Test1(new S1<long>(""11""))); System.Console.Write(Test1(new S1<long>(0))); } static bool Test1(S1<long> u) { return u is int; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); CompileAndVerify(comp, expectedOutput: "TrueFalseFalseTrue").VerifyDiagnostics(); } [Theory] [CombinatorialData] public void NonBoxingUnionMatching_MemberProvider_TryGetValue_09_Provider_NotPublic([CombinatorialValues("", "private", "internal", "protected", "internal protected", "private protected")] string accessibility) { var src = @" [System.Runtime.CompilerServices.Union] class S1 : S1.IUnionMembers { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } public object Value => throw null; public bool TryGetValue(out int x) { if (_value is int v) { x = v; return true; } x = 0; return false; } object IUnionMembers.Value => throw null; bool IUnionMembers.TryGetValue(out int x) => throw null; " + accessibility + @" interface IUnionMembers { public static S1 Create(int x) => new S1(x); public static S1 Create(string x) => new S1(x); public object Value { get; } public bool TryGetValue(out int x); } } class Program { static void Main() { System.Console.Write(Test1(new S1(10))); System.Console.Write(Test1(default)); System.Console.Write(Test1(new S1(""11""))); System.Console.Write(Test1(new S1(0))); } static bool Test1(S1 u) { return u is int; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); var verifier = CompileAndVerify(comp, expectedOutput: "TrueFalseFalseTrue").VerifyDiagnostics(); verifier.VerifyIL("Program.Test1", @" { // Code size 14 (0xe) .maxstack 2 .locals init (int V_0) IL_0000: ldarg.0 IL_0001: brfalse.s IL_000c IL_0003: ldarg.0 IL_0004: ldloca.s V_0 IL_0006: callvirt ""bool S1.TryGetValue(out int)"" IL_000b: ret IL_000c: ldc.i4.0 IL_000d: ret } "); } [Fact] public void NonBoxingUnionMatching_MemberProvider_TryGetValue_10_WrongType() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 : S1.IUnionMembers { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } public bool TryGetValue(out int x) => throw null; object IUnionMembers.Value => _value; System.IComparable IUnionMembers.TryGetValue(out int x) => throw null; public interface IUnionMembers { public static S1 Create(int x) => new S1(x); public static S1 Create(string x) => new S1(x); public object Value { get; } public System.IComparable TryGetValue(out int x); } static void Main() { System.Console.Write(Test1(new S1(1))); System.Console.Write(Test1(new S1())); } static bool Test1(S1 u) { return u is int; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); var verifier = CompileAndVerify(comp, expectedOutput: "TrueFalse").VerifyDiagnostics(); verifier.VerifyIL("S1.Test1", @" { // Code size 22 (0x16) .maxstack 2 IL_0000: ldarga.s V_0 IL_0002: constrained. ""S1"" IL_0008: callvirt ""object S1.IUnionMembers.Value.get"" IL_000d: isinst ""int"" IL_0012: ldnull IL_0013: cgt.un IL_0015: ret } "); } [Fact] public void NonBoxingUnionMatching_MemberProvider_TryGetValue_11_WrongType() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 : S1.IUnionMembers { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } public bool TryGetValue(out int x) => throw null; object IUnionMembers.Value => _value; bool IUnionMembers.TryGetValue(out string x) => throw null; public interface IUnionMembers { public static S1 Create(int x) => new S1(x); public static S1 Create(string x) => new S1(x); public object Value { get; } public bool TryGetValue(out string x); } static void Main() { System.Console.Write(Test1(new S1(1))); System.Console.Write(Test1(new S1())); } static bool Test1(S1 u) { return u is int; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); var verifier = CompileAndVerify(comp, expectedOutput: "TrueFalse").VerifyDiagnostics(); verifier.VerifyIL("S1.Test1", @" { // Code size 22 (0x16) .maxstack 2 IL_0000: ldarga.s V_0 IL_0002: constrained. ""S1"" IL_0008: callvirt ""object S1.IUnionMembers.Value.get"" IL_000d: isinst ""int"" IL_0012: ldnull IL_0013: cgt.un IL_0015: ret } "); } [Fact] public void NonBoxingUnionMatching_MemberProvider_TryGetValue_12_WrongType() { var src = @" [System.Runtime.CompilerServices.Union] struct S1<T> : S1<T>.IUnionMembers { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } public object Value => throw null; public bool TryGetValue(out int x) => throw null; object IUnionMembers.Value => _value; T IUnionMembers.TryGetValue(out int x) => throw null; public interface IUnionMembers { public static S1<T> Create(int x) => new S1<T>(x); public static S1<T> Create(string x) => new S1<T>(x); public object Value { get; } public T TryGetValue(out int x); } } class Program { static void Main() { System.Console.Write(Test1(new S1<bool>(1))); System.Console.Write(Test1(new S1<bool>())); } static bool Test1(S1<bool> u) { return u is int; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); var verifier = CompileAndVerify(comp, expectedOutput: "TrueFalse").VerifyDiagnostics(); verifier.VerifyIL("Program.Test1", @" { // Code size 22 (0x16) .maxstack 2 IL_0000: ldarga.s V_0 IL_0002: constrained. ""S1<bool>"" IL_0008: callvirt ""object S1<bool>.IUnionMembers.Value.get"" IL_000d: isinst ""int"" IL_0012: ldnull IL_0013: cgt.un IL_0015: ret } "); } [Fact] public void NonBoxingUnionMatching_MemberProvider_TryGetValue_13_WrongType() { var src = @" [System.Runtime.CompilerServices.Union] struct S1<T> : S1<T>.IUnionMembers { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } public object Value => throw null; public bool TryGetValue(out int x) => throw null; object IUnionMembers.Value => _value; bool IUnionMembers.TryGetValue(out T x) => throw null; public interface IUnionMembers { public static S1<T> Create(int x) => new S1<T>(x); public static S1<T> Create(string x) => new S1<T>(x); public object Value { get; } public bool TryGetValue(out T x); } } class Program { static void Main() { System.Console.Write(Test1(new S1<int>(1))); System.Console.Write(Test1(new S1<int>())); } static bool Test1(S1<int> u) { return u is int; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); var verifier = CompileAndVerify(comp, expectedOutput: "TrueFalse").VerifyDiagnostics(); verifier.VerifyIL("Program.Test1", @" { // Code size 22 (0x16) .maxstack 2 IL_0000: ldarga.s V_0 IL_0002: constrained. ""S1<int>"" IL_0008: callvirt ""object S1<int>.IUnionMembers.Value.get"" IL_000d: isinst ""int"" IL_0012: ldnull IL_0013: cgt.un IL_0015: ret } "); } [Theory] [CombinatorialData] public void NonBoxingUnionMatching_MemberProvider_TryGetValue_14_WrongRefKind([CombinatorialValues("ref", "ref readonly")] string refModifier) { var src = @" [System.Runtime.CompilerServices.Union] struct S1 : S1.IUnionMembers { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } public object Value => throw null; public bool TryGetValue(out int x) => throw null; object IUnionMembers.Value => _value; " + refModifier + @" bool IUnionMembers.TryGetValue(out int x) => throw null; public interface IUnionMembers { public static S1 Create(int x) => new S1(x); public static S1 Create(string x) => new S1(x); public object Value { get; } public " + refModifier + @" bool TryGetValue(out int x); } } class Program { static void Main() { System.Console.Write(Test1(new S1(1))); System.Console.Write(Test1(new S1())); } static bool Test1(S1 u) { return u is int; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); CompileAndVerify(comp, expectedOutput: "TrueFalse").VerifyDiagnostics(); } [Theory] [CombinatorialData] public void NonBoxingUnionMatching_MemberProvider_TryGetValue_15_WrongRefKind([CombinatorialValues("", "in", "ref", "ref readonly")] string refModifier) { var src = @" [System.Runtime.CompilerServices.Union] struct S1 : S1.IUnionMembers { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } public object Value => throw null; public bool TryGetValue(out int x) => throw null; object IUnionMembers.Value => _value; bool IUnionMembers.TryGetValue(" + refModifier + @" int x) => throw null; public interface IUnionMembers { public static S1 Create(int x) => new S1(x); public static S1 Create(string x) => new S1(x); public object Value { get; } public bool TryGetValue(" + refModifier + @" int x); } } class Program { static void Main() { System.Console.Write(Test1(new S1(1))); System.Console.Write(Test1(new S1())); } static bool Test1(S1 u) { return u is int; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); CompileAndVerify(comp, expectedOutput: "TrueFalse").VerifyDiagnostics(); } [Fact] public void NonBoxingUnionMatching_MemberProvider_TryGetValue_16_Static() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 : S1.IUnionMembers { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } public object Value => _value; public bool TryGetValue(out int x) => throw null; public interface IUnionMembers { public static S1 Create(int x) => new S1(x); public static S1 Create(string x) => new S1(x); public object Value { get; } public static bool TryGetValue(out int x) => throw null; } } class Program { static void Main() { System.Console.Write(Test1(new S1(1))); System.Console.Write(Test1(new S1())); } static bool Test1(S1 u) { return u is int; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); CompileAndVerify(comp, expectedOutput: "TrueFalse").VerifyDiagnostics(); } [Fact] public void NonBoxingUnionMatching_MemberProvider_TryGetValue_17_NotVirtual() { var src = @" [System.Runtime.CompilerServices.Union] class S1 : S1.IUnionMembers { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } public object Value => throw null; public bool TryGetValue(out int x) => throw null; public interface IUnionMembers { public static S1 Create(int x) => new S1(x); public static S1 Create(string x) => new S1(x); public object Value { get; } public sealed bool TryGetValue(out int x) { if (((S1)this)._value is int v) { x = v; return true; } x = 0; return false; } } } class Program { static void Main() { System.Console.Write(Test1(new S1(10))); System.Console.Write(Test1(default)); System.Console.Write(Test1(new S1(""11""))); System.Console.Write(Test1(new S1(0))); } static bool Test1(S1 u) { return u is int; } } "; var comp = CreateCompilation([src, UnionAttributeSource], targetFramework: TargetFramework.NetCoreApp, options: TestOptions.ReleaseExe); var verifier = CompileAndVerify(comp, expectedOutput: ExecutionConditionUtil.IsMonoOrCoreClr ? "TrueFalseFalseTrue" : null, verify: Verification.FailsPEVerify).VerifyDiagnostics(); verifier.VerifyIL("Program.Test1", @" { // Code size 14 (0xe) .maxstack 2 .locals init (int V_0) IL_0000: ldarg.0 IL_0001: brfalse.s IL_000c IL_0003: ldarg.0 IL_0004: ldloca.s V_0 IL_0006: callvirt ""bool S1.IUnionMembers.TryGetValue(out int)"" IL_000b: ret IL_000c: ldc.i4.0 IL_000d: ret } "); } [Fact] public void NonBoxingUnionMatching_MemberProvider_TryGetValue_18_NullableAnalysis() { var src = @" #nullable enable [System.Runtime.CompilerServices.Union] struct S1 : S1.IUnionMembers { public S1(int x) => throw null!; public S1(bool? x) => throw null!; public object? Value => throw null!; public bool TryGetValue(out int x) => throw null!; public interface IUnionMembers { public static S1 Create(int x) => new S1(x); public static S1 Create(bool? x) => new S1(x); public object? Value { get; } public bool TryGetValue(out int x); } } class Program { static void Test2(S1 s) { if (s.TryGetValue(out int _)) { #line 100 _ = s switch { int => 1, bool => 3 }; } else { #line 200 _ = s switch { int => 1, bool => 3 }; } } static void Test4(S1 s) { if (!s.TryGetValue(out int _)) { #line 300 _ = s switch { int => 1, bool => 3 }; } else { #line 400 _ = s switch { int => 1, bool => 3 }; } } } "; var comp = CreateCompilation([src, UnionAttributeSource]); comp.VerifyDiagnostics( // (100,19): warning CS8655: The switch expression does not handle some null inputs (it is not exhaustive). For example, the pattern 'null' is not covered. // _ = s switch { int => 1, bool => 3 }; Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustiveForNull, "switch").WithArguments("null").WithLocation(100, 19), // (200,19): warning CS8655: The switch expression does not handle some null inputs (it is not exhaustive). For example, the pattern 'null' is not covered. // _ = s switch { int => 1, bool => 3 }; Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustiveForNull, "switch").WithArguments("null").WithLocation(200, 19), // (300,19): warning CS8655: The switch expression does not handle some null inputs (it is not exhaustive). For example, the pattern 'null' is not covered. // _ = s switch { int => 1, bool => 3 }; Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustiveForNull, "switch").WithArguments("null").WithLocation(300, 19), // (400,19): warning CS8655: The switch expression does not handle some null inputs (it is not exhaustive). For example, the pattern 'null' is not covered. // _ = s switch { int => 1, bool => 3 }; Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustiveForNull, "switch").WithArguments("null").WithLocation(400, 19) ); } [Fact] public void NonBoxingUnionMatching_MemberProvider_TryGetValue_19_NullableAnalysis() { var src = @" #nullable enable [System.Runtime.CompilerServices.Union] struct S1 : S1.IUnionMembers { public S1(int x) => throw null!; public S1(bool? x) => throw null!; public object? Value => throw null!; public bool TryGetValue(out int x) => throw null!; public interface IUnionMembers { public static S1 Create(int x) => new S1(x); public static S1 Create(bool? x) => new S1(x); public object? Value { get; } } } class Program { static void Test2(S1 s) { if (s.TryGetValue(out int _)) { #line 100 _ = s switch { int => 1, bool => 3 }; } else { #line 200 _ = s switch { int => 1, bool => 3 }; } } static void Test4(S1 s) { if (!s.TryGetValue(out int _)) { #line 300 _ = s switch { int => 1, bool => 3 }; } else { #line 400 _ = s switch { int => 1, bool => 3 }; } } } "; var comp = CreateCompilation([src, UnionAttributeSource]); comp.VerifyDiagnostics( // (100,19): warning CS8655: The switch expression does not handle some null inputs (it is not exhaustive). For example, the pattern 'null' is not covered. // _ = s switch { int => 1, bool => 3 }; Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustiveForNull, "switch").WithArguments("null").WithLocation(100, 19), // (200,19): warning CS8655: The switch expression does not handle some null inputs (it is not exhaustive). For example, the pattern 'null' is not covered. // _ = s switch { int => 1, bool => 3 }; Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustiveForNull, "switch").WithArguments("null").WithLocation(200, 19), // (300,19): warning CS8655: The switch expression does not handle some null inputs (it is not exhaustive). For example, the pattern 'null' is not covered. // _ = s switch { int => 1, bool => 3 }; Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustiveForNull, "switch").WithArguments("null").WithLocation(300, 19), // (400,19): warning CS8655: The switch expression does not handle some null inputs (it is not exhaustive). For example, the pattern 'null' is not covered. // _ = s switch { int => 1, bool => 3 }; Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustiveForNull, "switch").WithArguments("null").WithLocation(400, 19) ); } [Theory] [CombinatorialData] public void NonBoxingUnionMatching_MemberProvider_TryGetValue_20_NotPublic([CombinatorialValues("internal", "protected", "internal protected", "private protected")] string accessibility) { var src = @" [System.Runtime.CompilerServices.Union] struct S1 : S1.IUnionMembers { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } public object Value => _value; bool IUnionMembers.TryGetValue(out int x) => throw null; public interface IUnionMembers { public static S1 Create(int x) => new S1(x); public static S1 Create(string x) => new S1(x); public object Value { get; } " + accessibility + @" abstract bool TryGetValue(out int x); } } class Program { static void Main() { System.Console.Write(Test1(new S1(1))); System.Console.Write(Test1(new S1())); } static bool Test1(S1 u) { return u is int; } } "; var comp = CreateCompilation([src, UnionAttributeSource], targetFramework: TargetFramework.NetCoreApp, options: TestOptions.ReleaseExe); CompileAndVerify(comp, expectedOutput: ExecutionConditionUtil.IsMonoOrCoreClr ? "TrueFalse" : null, verify: Verification.FailsPEVerify).VerifyDiagnostics(); } [Fact] public void NonBoxingUnionMatching_MemberProvider_TryGetValue_21_NotPublic() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 : S1.IUnionMembers { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } public object Value => _value; public interface IUnionMembers { public static S1 Create(int x) => new S1(x); public static S1 Create(string x) => new S1(x); public object Value { get; } private bool TryGetValue(out int x) => throw null; } } class Program { static void Main() { System.Console.Write(Test1(new S1(1))); System.Console.Write(Test1(new S1())); } static bool Test1(S1 u) { return u is int; } } "; var comp = CreateCompilation([src, UnionAttributeSource], targetFramework: TargetFramework.NetCoreApp, options: TestOptions.ReleaseExe); CompileAndVerify(comp, expectedOutput: ExecutionConditionUtil.IsMonoOrCoreClr ? "TrueFalse" : null, verify: Verification.FailsPEVerify).VerifyDiagnostics(); } [Fact] public void NonBoxingUnionMatching_MemberProvider_TryGetValue_22_Generic() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 : S1.IUnionMembers { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } public object Value => _value; bool IUnionMembers.TryGetValue<T>(out int x) => throw null; public interface IUnionMembers { public static S1 Create(int x) => new S1(x); public static S1 Create(string x) => new S1(x); public object Value { get; } public bool TryGetValue<T>(out int x); } } class Program { static void Main() { System.Console.Write(Test1(new S1(1))); System.Console.Write(Test1(new S1())); } static bool Test1(S1 u) { return u is int; } } "; var comp = CreateCompilation([src, UnionAttributeSource], targetFramework: TargetFramework.NetCoreApp, options: TestOptions.ReleaseExe); CompileAndVerify(comp, expectedOutput: ExecutionConditionUtil.IsMonoOrCoreClr ? "TrueFalse" : null, verify: Verification.FailsPEVerify).VerifyDiagnostics(); } [Fact] public void NonBoxingUnionMatching_MemberProvider_TryGetValue_23_WrongParameterKind() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 : S1.IUnionMembers { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } public object Value => throw null; public bool TryGetValue(out int x) => throw null; object IUnionMembers.Value => _value; bool IUnionMembers.TryGetValue() => throw null; bool IUnionMembers.TryGetValue(out int x, out int y) => throw null; public interface IUnionMembers { public static S1 Create(int x) => new S1(x); public static S1 Create(string x) => new S1(x); public object Value { get; } public bool TryGetValue(); public bool TryGetValue(out int x, out int y); } } class Program { static void Main() { System.Console.Write(Test1(new S1(1))); System.Console.Write(Test1(new S1())); } static bool Test1(S1 u) { return u is int; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); CompileAndVerify(comp, expectedOutput: "TrueFalse").VerifyDiagnostics(); } [Fact] public void NonBoxingUnionMatching_MemberProvider_TryGetValue_24_Overloaded() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 : S1.IUnionMembers { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } public object Value => throw null; public bool TryGetValue(out int x) => throw null; object IUnionMembers.Value => throw null; bool IUnionMembers.TryGetValue(out int x, out int y) => throw null; bool IUnionMembers.TryGetValue(out int x) { if (_value is int v) { x = v; return true; } x = 0; return false; } bool IUnionMembers.TryGetValue() => throw null; public interface IUnionMembers { public static S1 Create(int x) => new S1(x); public static S1 Create(string x) => new S1(x); public object Value { get; } public bool TryGetValue(out int x, out int y); public bool TryGetValue(out int x); public bool TryGetValue(); } } class Program { static void Main() { System.Console.Write(Test1(new S1(1))); System.Console.Write(Test1(new S1())); } static bool Test1(S1 u) { return u is int; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); CompileAndVerify(comp, expectedOutput: "TrueFalse").VerifyDiagnostics(); } [Fact] public void NonBoxingUnionMatching_MemberProvider_TryGetValue_Inheritance_01() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 : S1.IUnionMembers { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } public object Value => throw null; bool IUnionMembersBase.TryGetValue(out int x) { if (_value is int v) { x = v; return true; } x = 0; return false; } public interface IUnionMembers : IUnionMembersBase { public static S1 Create(int x) => new S1(x); public static S1 Create(string x) => new S1(x); public object Value { get; } } public interface IUnionMembersBase { public bool TryGetValue(out int x); } } class Program { static void Main() { System.Console.Write(Test1(new S1(1))); System.Console.Write(Test1(new S1())); } static bool Test1(S1 u) { return u is int; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); var verifier = CompileAndVerify(comp, expectedOutput: "TrueFalse").VerifyDiagnostics(); verifier.VerifyIL("Program.Test1", @" { // Code size 16 (0x10) .maxstack 2 .locals init (int V_0) IL_0000: ldarga.s V_0 IL_0002: ldloca.s V_0 IL_0004: constrained. ""S1"" IL_000a: callvirt ""bool S1.IUnionMembersBase.TryGetValue(out int)"" IL_000f: ret } "); } [Fact] public void NonBoxingUnionMatching_MemberProvider_TryGetValue_Inheritance_02() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 : S1.IUnionMembers { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } public object Value => throw null; bool IBase1.TryGetValue(out int x) { if (_value is int v) { x = v; return true; } x = 0; return false; } public interface IUnionMembers : IBase2 { public static S1 Create(int x) => new S1(x); public static S1 Create(string x) => new S1(x); public object Value { get; } } public interface IBase2 : IBase1; public interface IBase1 { public bool TryGetValue(out int x); } } class Program { static void Main() { System.Console.Write(Test1(new S1(1))); System.Console.Write(Test1(new S1())); } static bool Test1(S1 u) { return u is int; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); var verifier = CompileAndVerify(comp, expectedOutput: "TrueFalse").VerifyDiagnostics(); verifier.VerifyIL("Program.Test1", @" { // Code size 16 (0x10) .maxstack 2 .locals init (int V_0) IL_0000: ldarga.s V_0 IL_0002: ldloca.s V_0 IL_0004: constrained. ""S1"" IL_000a: callvirt ""bool S1.IBase1.TryGetValue(out int)"" IL_000f: ret } "); } [Fact] public void NonBoxingUnionMatching_MemberProvider_TryGetValue_Inheritance_03_Generic() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 : S1.IUnionMembers { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } public object Value => throw null; bool IUnionMembersBase<int>.TryGetValue(out int x) { if (_value is int v) { x = v; return true; } x = 0; return false; } public interface IUnionMembers : IUnionMembersBase<int> { public static S1 Create(int x) => new S1(x); public static S1 Create(string x) => new S1(x); public object Value { get; } } public interface IUnionMembersBase<T> { public bool TryGetValue(out T x); } } class Program { static void Main() { System.Console.Write(Test1(new S1(1))); System.Console.Write(Test1(new S1())); } static bool Test1(S1 u) { return u is int; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); var verifier = CompileAndVerify(comp, expectedOutput: "TrueFalse").VerifyDiagnostics(); verifier.VerifyIL("Program.Test1", @" { // Code size 16 (0x10) .maxstack 2 .locals init (int V_0) IL_0000: ldarga.s V_0 IL_0002: ldloca.s V_0 IL_0004: constrained. ""S1"" IL_000a: callvirt ""bool S1.IUnionMembersBase<int>.TryGetValue(out int)"" IL_000f: ret } "); } [Fact] public void NonBoxingUnionMatching_MemberProvider_TryGetValue_Inheritance_04_Generic() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 : S1.IUnionMembers { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } public object Value => throw null; bool IUnionMembersBase<bool>.TryGetValue(out int x) { if (_value is int v) { x = v; return true; } x = 0; return false; } public interface IUnionMembers : IUnionMembersBase<bool> { public static S1 Create(int x) => new S1(x); public static S1 Create(string x) => new S1(x); public object Value { get; } } } public interface IUnionMembersBase<T> { public T TryGetValue(out int x); } class Program { static void Main() { System.Console.Write(Test1(new S1(1))); System.Console.Write(Test1(new S1())); } static bool Test1(S1 u) { return u is int; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); var verifier = CompileAndVerify(comp, expectedOutput: "TrueFalse").VerifyDiagnostics(); verifier.VerifyIL("Program.Test1", @" { // Code size 16 (0x10) .maxstack 2 .locals init (int V_0) IL_0000: ldarga.s V_0 IL_0002: ldloca.s V_0 IL_0004: constrained. ""S1"" IL_000a: callvirt ""bool IUnionMembersBase<bool>.TryGetValue(out int)"" IL_000f: ret } "); } [Fact] public void NonBoxingUnionMatching_MemberProvider_TryGetValue_Inheritance_05_InGenericUnion() { var src = @" [System.Runtime.CompilerServices.Union] struct S1<T> : S1<T>.IUnionMembers { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } public object Value => throw null; object IUnionMembers.Value => throw null; bool IUnionMembersBase.TryGetValue(out int x) { if (_value is int v) { x = v; return true; } x = 0; return false; } public interface IUnionMembers : IUnionMembersBase { public static S1<T> Create(int x) => new S1<T>(x); public static S1<T> Create(string x) => new S1<T>(x); public object Value { get; } } public interface IUnionMembersBase { public bool TryGetValue(out int x); } } class Program { static void Main() { System.Console.Write(Test1(new S1<long>(10))); System.Console.Write(Test1(default)); System.Console.Write(Test1(new S1<long>(""11""))); System.Console.Write(Test1(new S1<long>(0))); } static bool Test1(S1<long> u) { return u is int; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); var verifier = CompileAndVerify(comp, expectedOutput: "TrueFalseFalseTrue").VerifyDiagnostics(); verifier.VerifyIL("Program.Test1", @" { // Code size 16 (0x10) .maxstack 2 .locals init (int V_0) IL_0000: ldarga.s V_0 IL_0002: ldloca.s V_0 IL_0004: constrained. ""S1<long>"" IL_000a: callvirt ""bool S1<long>.IUnionMembersBase.TryGetValue(out int)"" IL_000f: ret } "); } [Fact] public void NonBoxingUnionMatching_MemberProvider_TryGetValue_Inheritance_06_InGenericUnion() { var src = @" [System.Runtime.CompilerServices.Union] struct S1<T> : S1<T>.IUnionMembers { private readonly object _value; public S1(T x) { _value = x; } public S1(string x) { _value = x; } public object Value => throw null; object IUnionMembers.Value => throw null; bool IUnionMembersBase.TryGetValue(out T x) { if (_value is T v) { x = v; return true; } x = default; return false; } public interface IUnionMembers : IUnionMembersBase { public static S1<T> Create(T x) => new S1<T>(x); public static S1<T> Create(string x) => new S1<T>(x); public object Value { get; } } public interface IUnionMembersBase { public bool TryGetValue(out T x); } } class Program { static void Main() { System.Console.Write(Test1(new S1<int>(10))); System.Console.Write(Test1(default)); System.Console.Write(Test1(new S1<int>(""11""))); System.Console.Write(Test1(new S1<int>(0))); } static bool Test1(S1<int> u) { return u is int; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); var verifier = CompileAndVerify(comp, expectedOutput: "TrueFalseFalseTrue").VerifyDiagnostics(); verifier.VerifyIL("Program.Test1", @" { // Code size 16 (0x10) .maxstack 2 .locals init (int V_0) IL_0000: ldarga.s V_0 IL_0002: ldloca.s V_0 IL_0004: constrained. ""S1<int>"" IL_000a: callvirt ""bool S1<int>.IUnionMembersBase.TryGetValue(out int)"" IL_000f: ret } "); } [Fact] public void NonBoxingUnionMatching_MemberProvider_TryGetValue_Inheritance_07_InGenericUnion() { var src = @" [System.Runtime.CompilerServices.Union] struct S1<T> : S1<T>.IUnionMembers { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } public object Value => throw null; object IUnionMembers.Value => throw null; bool IUnionMembersBase<bool, int>.TryGetValue(out int x) { if (_value is int v) { x = v; return true; } x = 0; return false; } int IUnionMembersBase<int, string>.TryGetValue(out string x) => throw null; public interface IUnionMembers : IUnionMembersBase<int, string>, IUnionMembersBase<bool, int> { public static S1<T> Create(int x) => new S1<T>(x); public static S1<T> Create(string x) => new S1<T>(x); public object Value { get; } } public interface IUnionMembersBase<T1, T2> { public T1 TryGetValue(out T2 x); } } class Program { static void Main() { System.Console.Write(Test1(new S1<long>(10))); System.Console.Write(Test1(default)); System.Console.Write(Test1(new S1<long>(""11""))); System.Console.Write(Test1(new S1<long>(0))); } static bool Test1(S1<long> u) { return u is int; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); var verifier = CompileAndVerify(comp, expectedOutput: "TrueFalseFalseTrue").VerifyDiagnostics(); verifier.VerifyIL("Program.Test1", @" { // Code size 16 (0x10) .maxstack 2 .locals init (int V_0) IL_0000: ldarga.s V_0 IL_0002: ldloca.s V_0 IL_0004: constrained. ""S1<long>"" IL_000a: callvirt ""bool S1<long>.IUnionMembersBase<bool, int>.TryGetValue(out int)"" IL_000f: ret } "); } [Theory] [CombinatorialData] public void NonBoxingUnionMatching_MemberProvider_TryGetValue_Inheritance_08_Provider_NotPublic([CombinatorialValues("internal", "internal protected")] string accessibility) { var src = @" [System.Runtime.CompilerServices.Union] class S1 : S1.IUnionMembers { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } public object Value => throw null; public bool TryGetValue(out int x) => throw null; object IUnionMembers.Value => throw null; bool IUnionMembersBase.TryGetValue(out int x) { if (_value is int v) { x = v; return true; } x = 0; return false; } public interface IUnionMembers : IUnionMembersBase { public static S1 Create(int x) => new S1(x); public static S1 Create(string x) => new S1(x); public object Value { get; } } " + accessibility + @" interface IUnionMembersBase { public bool TryGetValue(out int x); } } class Program { static void Main() { System.Console.Write(Test1(new S1(10))); System.Console.Write(Test1(default)); System.Console.Write(Test1(new S1(""11""))); System.Console.Write(Test1(new S1(0))); } static bool Test1(S1 u) { return u is int; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); var verifier = CompileAndVerify(comp, expectedOutput: "TrueFalseFalseTrue").VerifyDiagnostics(); verifier.VerifyIL("Program.Test1", @" { // Code size 14 (0xe) .maxstack 2 .locals init (int V_0) IL_0000: ldarg.0 IL_0001: brfalse.s IL_000c IL_0003: ldarg.0 IL_0004: ldloca.s V_0 IL_0006: callvirt ""bool S1.IUnionMembersBase.TryGetValue(out int)"" IL_000b: ret IL_000c: ldc.i4.0 IL_000d: ret } "); } [Theory] [CombinatorialData] public void NonBoxingUnionMatching_MemberProvider_TryGetValue_Inheritance_09_Provider_NotPublic([CombinatorialValues("", "private", "internal", "protected", "internal protected", "private protected")] string accessibility) { var src = @" [System.Runtime.CompilerServices.Union] public class S1 : S1.IUnionMembers { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } public object Value => throw null; public bool TryGetValue(out int x) => throw null; object IUnionMembers.Value => throw null; bool IUnionMembersBase.TryGetValue(out int x) { if (_value is int v) { x = v; return true; } x = 0; return false; } public interface IUnionMembers : IUnionMembersBase { public static S1 Create(int x) => new S1(x); public static S1 Create(string x) => new S1(x); public object Value { get; } } " + accessibility + @" interface IUnionMembersBase { public bool TryGetValue(out int x); } } "; var comp = CreateCompilation([src, UnionAttributeSource]); comp.VerifyDiagnostics( // (14,22): error CS0061: Inconsistent accessibility: base interface 'S1.IUnionMembersBase' is less accessible than interface 'S1.IUnionMembers' // public interface IUnionMembers : IUnionMembersBase Diagnostic(ErrorCode.ERR_BadVisBaseInterface, "IUnionMembers").WithArguments("S1.IUnionMembers", "S1.IUnionMembersBase").WithLocation(14, 22) ); } [Fact] public void NonBoxingUnionMatching_MemberProvider_TryGetValue_Inheritance_10_WrongType() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 : S1.IUnionMembers { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } public bool TryGetValue(out int x) => throw null; object IUnionMembers.Value => _value; System.IComparable IUnionMembersBase.TryGetValue(out int x) => throw null; public interface IUnionMembers : IUnionMembersBase { public static S1 Create(int x) => new S1(x); public static S1 Create(string x) => new S1(x); public object Value { get; } } public interface IUnionMembersBase { public System.IComparable TryGetValue(out int x); } static void Main() { System.Console.Write(Test1(new S1(1))); System.Console.Write(Test1(new S1())); } static bool Test1(S1 u) { return u is int; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); var verifier = CompileAndVerify(comp, expectedOutput: "TrueFalse").VerifyDiagnostics(); verifier.VerifyIL("S1.Test1", @" { // Code size 22 (0x16) .maxstack 2 IL_0000: ldarga.s V_0 IL_0002: constrained. ""S1"" IL_0008: callvirt ""object S1.IUnionMembers.Value.get"" IL_000d: isinst ""int"" IL_0012: ldnull IL_0013: cgt.un IL_0015: ret } "); } [Fact] public void NonBoxingUnionMatching_MemberProvider_TryGetValue_Inheritance_11_WrongType() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 : S1.IUnionMembers { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } public bool TryGetValue(out int x) => throw null; object IUnionMembers.Value => _value; bool IUnionMembersBase.TryGetValue(out string x) => throw null; public interface IUnionMembers : IUnionMembersBase { public static S1 Create(int x) => new S1(x); public static S1 Create(string x) => new S1(x); public object Value { get; } } public interface IUnionMembersBase { public bool TryGetValue(out string x); } static void Main() { System.Console.Write(Test1(new S1(1))); System.Console.Write(Test1(new S1())); } static bool Test1(S1 u) { return u is int; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); var verifier = CompileAndVerify(comp, expectedOutput: "TrueFalse").VerifyDiagnostics(); verifier.VerifyIL("S1.Test1", @" { // Code size 22 (0x16) .maxstack 2 IL_0000: ldarga.s V_0 IL_0002: constrained. ""S1"" IL_0008: callvirt ""object S1.IUnionMembers.Value.get"" IL_000d: isinst ""int"" IL_0012: ldnull IL_0013: cgt.un IL_0015: ret } "); } [Fact] public void NonBoxingUnionMatching_MemberProvider_TryGetValue_Inheritance_12_WrongType() { var src = @" [System.Runtime.CompilerServices.Union] struct S1<T> : S1<T>.IUnionMembers { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } public object Value => throw null; public bool TryGetValue(out int x) => throw null; object IUnionMembers.Value => _value; T IUnionMembersBase.TryGetValue(out int x) => throw null; public interface IUnionMembers : IUnionMembersBase { public static S1<T> Create(int x) => new S1<T>(x); public static S1<T> Create(string x) => new S1<T>(x); public object Value { get; } } public interface IUnionMembersBase { public T TryGetValue(out int x); } } class Program { static void Main() { System.Console.Write(Test1(new S1<bool>(1))); System.Console.Write(Test1(new S1<bool>())); } static bool Test1(S1<bool> u) { return u is int; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); var verifier = CompileAndVerify(comp, expectedOutput: "TrueFalse").VerifyDiagnostics(); verifier.VerifyIL("Program.Test1", @" { // Code size 22 (0x16) .maxstack 2 IL_0000: ldarga.s V_0 IL_0002: constrained. ""S1<bool>"" IL_0008: callvirt ""object S1<bool>.IUnionMembers.Value.get"" IL_000d: isinst ""int"" IL_0012: ldnull IL_0013: cgt.un IL_0015: ret } "); } [Fact] public void NonBoxingUnionMatching_MemberProvider_TryGetValue_Inheritance_13_WrongType() { var src = @" [System.Runtime.CompilerServices.Union] struct S1<T> : S1<T>.IUnionMembers { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } public object Value => throw null; public bool TryGetValue(out int x) => throw null; object IUnionMembers.Value => _value; T IUnionMembersBase<T>.TryGetValue(out int x) => throw null; public interface IUnionMembers : IUnionMembersBase<T> { public static S1<T> Create(int x) => new S1<T>(x); public static S1<T> Create(string x) => new S1<T>(x); public object Value { get; } } } public interface IUnionMembersBase<T> { public T TryGetValue(out int x); } class Program { static void Main() { System.Console.Write(Test1(new S1<bool>(1))); System.Console.Write(Test1(new S1<bool>())); } static bool Test1(S1<bool> u) { return u is int; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); var verifier = CompileAndVerify(comp, expectedOutput: "TrueFalse").VerifyDiagnostics(); verifier.VerifyIL("Program.Test1", @" { // Code size 22 (0x16) .maxstack 2 IL_0000: ldarga.s V_0 IL_0002: constrained. ""S1<bool>"" IL_0008: callvirt ""object S1<bool>.IUnionMembers.Value.get"" IL_000d: isinst ""int"" IL_0012: ldnull IL_0013: cgt.un IL_0015: ret } "); } [Fact] public void NonBoxingUnionMatching_MemberProvider_TryGetValue_Inheritance_14_WrongType() { var src = @" [System.Runtime.CompilerServices.Union] struct S1<T> : S1<T>.IUnionMembers { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } public object Value => throw null; public bool TryGetValue(out int x) => throw null; object IUnionMembers.Value => _value; bool IUnionMembersBase.TryGetValue(out T x) => throw null; public interface IUnionMembers : IUnionMembersBase { public static S1<T> Create(int x) => new S1<T>(x); public static S1<T> Create(string x) => new S1<T>(x); public object Value { get; } } public interface IUnionMembersBase { public bool TryGetValue(out T x); } } class Program { static void Main() { System.Console.Write(Test1(new S1<int>(1))); System.Console.Write(Test1(new S1<int>())); } static bool Test1(S1<int> u) { return u is int; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); var verifier = CompileAndVerify(comp, expectedOutput: "TrueFalse").VerifyDiagnostics(); verifier.VerifyIL("Program.Test1", @" { // Code size 22 (0x16) .maxstack 2 IL_0000: ldarga.s V_0 IL_0002: constrained. ""S1<int>"" IL_0008: callvirt ""object S1<int>.IUnionMembers.Value.get"" IL_000d: isinst ""int"" IL_0012: ldnull IL_0013: cgt.un IL_0015: ret } "); } [Fact] public void NonBoxingUnionMatching_MemberProvider_TryGetValue_Inheritance_15_WrongType() { var src = @" [System.Runtime.CompilerServices.Union] struct S1<T> : S1<T>.IUnionMembers { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } public object Value => throw null; public bool TryGetValue(out int x) => throw null; object IUnionMembers.Value => _value; bool IUnionMembersBase<T>.TryGetValue(out T x) => throw null; public interface IUnionMembers : IUnionMembersBase<T> { public static S1<T> Create(int x) => new S1<T>(x); public static S1<T> Create(string x) => new S1<T>(x); public object Value { get; } } } public interface IUnionMembersBase<T> { public bool TryGetValue(out T x); } class Program { static void Main() { System.Console.Write(Test1(new S1<int>(1))); System.Console.Write(Test1(new S1<int>())); } static bool Test1(S1<int> u) { return u is int; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); var verifier = CompileAndVerify(comp, expectedOutput: "TrueFalse").VerifyDiagnostics(); verifier.VerifyIL("Program.Test1", @" { // Code size 22 (0x16) .maxstack 2 IL_0000: ldarga.s V_0 IL_0002: constrained. ""S1<int>"" IL_0008: callvirt ""object S1<int>.IUnionMembers.Value.get"" IL_000d: isinst ""int"" IL_0012: ldnull IL_0013: cgt.un IL_0015: ret } "); } [Theory] [CombinatorialData] public void NonBoxingUnionMatching_MemberProvider_TryGetValue_Inheritance_16_WrongRefKind([CombinatorialValues("ref", "ref readonly")] string refModifier) { var src = @" [System.Runtime.CompilerServices.Union] struct S1 : S1.IUnionMembers { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } public object Value => throw null; public bool TryGetValue(out int x) => throw null; object IUnionMembers.Value => _value; " + refModifier + @" bool IUnionMembersBase.TryGetValue(out int x) => throw null; public interface IUnionMembers : IUnionMembersBase { public static S1 Create(int x) => new S1(x); public static S1 Create(string x) => new S1(x); public object Value { get; } } public interface IUnionMembersBase { public " + refModifier + @" bool TryGetValue(out int x); } } class Program { static void Main() { System.Console.Write(Test1(new S1(1))); System.Console.Write(Test1(new S1())); } static bool Test1(S1 u) { return u is int; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); CompileAndVerify(comp, expectedOutput: "TrueFalse").VerifyDiagnostics(); } [Theory] [CombinatorialData] public void NonBoxingUnionMatching_MemberProvider_TryGetValue_Inheritance_17_WrongRefKind([CombinatorialValues("", "in", "ref", "ref readonly")] string refModifier) { var src = @" [System.Runtime.CompilerServices.Union] struct S1 : S1.IUnionMembers { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } public object Value => throw null; public bool TryGetValue(out int x) => throw null; object IUnionMembers.Value => _value; bool IUnionMembersBase.TryGetValue(" + refModifier + @" int x) => throw null; public interface IUnionMembers : IUnionMembersBase { public static S1 Create(int x) => new S1(x); public static S1 Create(string x) => new S1(x); public object Value { get; } } public interface IUnionMembersBase { public bool TryGetValue(" + refModifier + @" int x); } } class Program { static void Main() { System.Console.Write(Test1(new S1(1))); System.Console.Write(Test1(new S1())); } static bool Test1(S1 u) { return u is int; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); CompileAndVerify(comp, expectedOutput: "TrueFalse").VerifyDiagnostics(); } [Fact] public void NonBoxingUnionMatching_MemberProvider_TryGetValue_Inheritance_18_Static() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 : S1.IUnionMembers { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } public object Value => _value; public bool TryGetValue(out int x) => throw null; public interface IUnionMembers : IUnionMembersBase { public static S1 Create(int x) => new S1(x); public static S1 Create(string x) => new S1(x); public object Value { get; } } public interface IUnionMembersBase { public static bool TryGetValue(out int x) => throw null; } } class Program { static void Main() { System.Console.Write(Test1(new S1(1))); System.Console.Write(Test1(new S1())); } static bool Test1(S1 u) { return u is int; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); CompileAndVerify(comp, expectedOutput: "TrueFalse").VerifyDiagnostics(); } [Fact] public void NonBoxingUnionMatching_MemberProvider_TryGetValue_Inheritance_19_NotVirtual() { var src = @" [System.Runtime.CompilerServices.Union] class S1 : S1.IUnionMembers { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } public object Value => throw null; public bool TryGetValue(out int x) => throw null; public interface IUnionMembers : IUnionMembersBase { public static S1 Create(int x) => new S1(x); public static S1 Create(string x) => new S1(x); public object Value { get; } } public interface IUnionMembersBase { public sealed bool TryGetValue(out int x) { if (((S1)this)._value is int v) { x = v; return true; } x = 0; return false; } } } class Program { static void Main() { System.Console.Write(Test1(new S1(10))); System.Console.Write(Test1(default)); System.Console.Write(Test1(new S1(""11""))); System.Console.Write(Test1(new S1(0))); } static bool Test1(S1 u) { return u is int; } } "; var comp = CreateCompilation([src, UnionAttributeSource], targetFramework: TargetFramework.NetCoreApp, options: TestOptions.ReleaseExe); var verifier = CompileAndVerify(comp, expectedOutput: ExecutionConditionUtil.IsMonoOrCoreClr ? "TrueFalseFalseTrue" : null, verify: Verification.FailsPEVerify).VerifyDiagnostics(); verifier.VerifyIL("Program.Test1", @" { // Code size 14 (0xe) .maxstack 2 .locals init (int V_0) IL_0000: ldarg.0 IL_0001: brfalse.s IL_000c IL_0003: ldarg.0 IL_0004: ldloca.s V_0 IL_0006: callvirt ""bool S1.IUnionMembersBase.TryGetValue(out int)"" IL_000b: ret IL_000c: ldc.i4.0 IL_000d: ret } "); } [Theory] [CombinatorialData] public void NonBoxingUnionMatching_MemberProvider_TryGetValue_Inheritance_20_NotPublic([CombinatorialValues("internal", "protected", "internal protected", "private protected")] string accessibility) { var src = @" [System.Runtime.CompilerServices.Union] struct S1 : S1.IUnionMembers { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } public object Value => _value; bool IUnionMembersBase.TryGetValue(out int x) => throw null; public interface IUnionMembers : IUnionMembersBase { public static S1 Create(int x) => new S1(x); public static S1 Create(string x) => new S1(x); public object Value { get; } } public interface IUnionMembersBase { " + accessibility + @" abstract bool TryGetValue(out int x); } } class Program { static void Main() { System.Console.Write(Test1(new S1(1))); System.Console.Write(Test1(new S1())); } static bool Test1(S1 u) { return u is int; } } "; var comp = CreateCompilation([src, UnionAttributeSource], targetFramework: TargetFramework.NetCoreApp, options: TestOptions.ReleaseExe); CompileAndVerify(comp, expectedOutput: ExecutionConditionUtil.IsMonoOrCoreClr ? "TrueFalse" : null, verify: Verification.FailsPEVerify).VerifyDiagnostics(); } [Fact] public void NonBoxingUnionMatching_MemberProvider_TryGetValue_Inheritance_21_NotPublic() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 : S1.IUnionMembers { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } public object Value => _value; public interface IUnionMembers : IUnionMembersBase { public static S1 Create(int x) => new S1(x); public static S1 Create(string x) => new S1(x); public object Value { get; } } public interface IUnionMembersBase { private bool TryGetValue(out int x) => throw null; } } class Program { static void Main() { System.Console.Write(Test1(new S1(1))); System.Console.Write(Test1(new S1())); } static bool Test1(S1 u) { return u is int; } } "; var comp = CreateCompilation([src, UnionAttributeSource], targetFramework: TargetFramework.NetCoreApp, options: TestOptions.ReleaseExe); CompileAndVerify(comp, expectedOutput: ExecutionConditionUtil.IsMonoOrCoreClr ? "TrueFalse" : null, verify: Verification.FailsPEVerify).VerifyDiagnostics(); } [Fact] public void NonBoxingUnionMatching_MemberProvider_TryGetValue_Inheritance_22_Generic() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 : S1.IUnionMembers { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } public object Value => _value; bool IUnionMembersBase.TryGetValue<T>(out int x) => throw null; public interface IUnionMembers : IUnionMembersBase { public static S1 Create(int x) => new S1(x); public static S1 Create(string x) => new S1(x); public object Value { get; } } public interface IUnionMembersBase { public bool TryGetValue<T>(out int x); } } class Program { static void Main() { System.Console.Write(Test1(new S1(1))); System.Console.Write(Test1(new S1())); } static bool Test1(S1 u) { return u is int; } } "; var comp = CreateCompilation([src, UnionAttributeSource], targetFramework: TargetFramework.NetCoreApp, options: TestOptions.ReleaseExe); CompileAndVerify(comp, expectedOutput: ExecutionConditionUtil.IsMonoOrCoreClr ? "TrueFalse" : null, verify: Verification.FailsPEVerify).VerifyDiagnostics(); } [Fact] public void NonBoxingUnionMatching_MemberProvider_TryGetValue_Inheritance_23_WrongSignature() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 : S1.IUnionMembers { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } public object Value => throw null; public bool TryGetValue(out int x) => throw null; object IUnionMembers.Value => _value; bool IUnionMembersBase.TryGetValue() => throw null; bool IUnionMembersBase.TryGetValue(out int x, out int y) => throw null; public interface IUnionMembers : IUnionMembersBase { public static S1 Create(int x) => new S1(x); public static S1 Create(string x) => new S1(x); public object Value { get; } } public interface IUnionMembersBase { public bool TryGetValue(); public bool TryGetValue(out int x, out int y); } } class Program { static void Main() { System.Console.Write(Test1(new S1(1))); System.Console.Write(Test1(new S1())); } static bool Test1(S1 u) { return u is int; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); CompileAndVerify(comp, expectedOutput: "TrueFalse").VerifyDiagnostics(); } [Fact] public void NonBoxingUnionMatching_MemberProvider_TryGetValue_Inheritance_24_Overloaded() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 : S1.IUnionMembers { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } public object Value => throw null; public bool TryGetValue(out int x) => throw null; object IUnionMembers.Value => throw null; bool IUnionMembersBase.TryGetValue(out int x, out int y) => throw null; bool IUnionMembersBase.TryGetValue(out int x) { if (_value is int v) { x = v; return true; } x = 0; return false; } bool IUnionMembersBase.TryGetValue() => throw null; public interface IUnionMembers : IUnionMembersBase { public static S1 Create(int x) => new S1(x); public static S1 Create(string x) => new S1(x); public object Value { get; } } public interface IUnionMembersBase { public bool TryGetValue(out int x, out int y); public bool TryGetValue(out int x); public bool TryGetValue(); } } class Program { static void Main() { System.Console.Write(Test1(new S1(1))); System.Console.Write(Test1(new S1())); } static bool Test1(S1 u) { return u is int; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); CompileAndVerify(comp, expectedOutput: "TrueFalse").VerifyDiagnostics(); } [Fact] public void NonBoxingUnionMatching_MemberProvider_TryGetValue_Inheritance_25_NotDefined() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 : S1.IUnionMembers { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } public object Value => throw null; public bool TryGetValue(out int x) => throw null; object IUnionMembers.Value => _value; public interface IUnionMembers : IUnionMembersBase { public static S1 Create(int x) => new S1(x); public static S1 Create(string x) => new S1(x); public object Value { get; } } public interface IUnionMembersBase { } } class Program { static void Main() { System.Console.Write(Test1(new S1(1))); System.Console.Write(Test1(new S1())); } static bool Test1(S1 u) { return u is int; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); CompileAndVerify(comp, expectedOutput: "TrueFalse").VerifyDiagnostics(); } [Fact] public void NonBoxingUnionMatching_MemberProvider_TryGetValue_Inheritance_26_Shadowing() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 : S1.IUnionMembers { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } public object Value => throw null; bool IUnionMembers.TryGetValue(out int x) { if (_value is int v) { x = v; return true; } x = 0; return false; } bool IUnionMembersBase.TryGetValue(out int x) => throw null; public interface IUnionMembers : IUnionMembersBase { public static S1 Create(int x) => new S1(x); public static S1 Create(string x) => new S1(x); public object Value { get; } public new bool TryGetValue(out int x); } public interface IUnionMembersBase { public bool TryGetValue(out int x); } } class Program { static void Main() { System.Console.Write(Test1(new S1(1))); System.Console.Write(Test1(new S1())); } static bool Test1(S1 u) { return u is int; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); var verifier = CompileAndVerify(comp, expectedOutput: "TrueFalse").VerifyDiagnostics(); verifier.VerifyIL("Program.Test1", @" { // Code size 16 (0x10) .maxstack 2 .locals init (int V_0) IL_0000: ldarga.s V_0 IL_0002: ldloca.s V_0 IL_0004: constrained. ""S1"" IL_000a: callvirt ""bool S1.IUnionMembers.TryGetValue(out int)"" IL_000f: ret } "); } [Fact] public void NonBoxingUnionMatching_MemberProvider_TryGetValue_Inheritance_27_Shadowing() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 : S1.IUnionMembers { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } public object Value => throw null; bool IBase2.TryGetValue(out int x) { if (_value is int v) { x = v; return true; } x = 0; return false; } bool IBase1.TryGetValue(out int x) => throw null; public interface IUnionMembers : IBase1, IBase2 { public static S1 Create(int x) => new S1(x); public static S1 Create(string x) => new S1(x); public object Value { get; } } public interface IBase2 : IBase1 { public new bool TryGetValue(out int x); } public interface IBase1 { public bool TryGetValue(out int x); } } class Program { static void Main() { System.Console.Write(Test1(new S1(1))); System.Console.Write(Test1(new S1())); } static bool Test1(S1 u) { return u is int; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); var verifier = CompileAndVerify(comp, expectedOutput: "TrueFalse").VerifyDiagnostics(); verifier.VerifyIL("Program.Test1", @" { // Code size 16 (0x10) .maxstack 2 .locals init (int V_0) IL_0000: ldarga.s V_0 IL_0002: ldloca.s V_0 IL_0004: constrained. ""S1"" IL_000a: callvirt ""bool S1.IBase2.TryGetValue(out int)"" IL_000f: ret } "); } [Fact] public void NonBoxingUnionMatching_MemberProvider_TryGetValue_Inheritance_28_Shadowing() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 : S1.IUnionMembers { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } public object Value => throw null; bool IBase2.TryGetValue(out int x) { if (_value is int v) { x = v; return true; } x = 0; return false; } bool IBase1.TryGetValue(out int x) => throw null; bool IBase0.TryGetValue(out int x) => throw null; public interface IUnionMembers : IBase0, IBase1, IBase2 { public static S1 Create(int x) => new S1(x); public static S1 Create(string x) => new S1(x); public object Value { get; } } public interface IBase2 : IBase1 { public new bool TryGetValue(out int x); } public interface IBase1 : IBase0 { public new bool TryGetValue(out int x); } public interface IBase0 { public bool TryGetValue(out int x); } } class Program { static void Main() { System.Console.Write(Test1(new S1(1))); System.Console.Write(Test1(new S1())); } static bool Test1(S1 u) { return u is int; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); var verifier = CompileAndVerify(comp, expectedOutput: "TrueFalse").VerifyDiagnostics(); verifier.VerifyIL("Program.Test1", @" { // Code size 16 (0x10) .maxstack 2 .locals init (int V_0) IL_0000: ldarga.s V_0 IL_0002: ldloca.s V_0 IL_0004: constrained. ""S1"" IL_000a: callvirt ""bool S1.IBase2.TryGetValue(out int)"" IL_000f: ret } "); } [Fact] public void NonBoxingUnionMatching_MemberProvider_TryGetValue_Inheritance_29_Shadowing() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 : S1.IUnionMembers { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } public object Value => throw null; bool IUnionMembersBase.TryGetValue(out int x) { if (_value is int v) { x = v; return true; } x = 0; return false; } int IUnionMembers.TryGetValue(out int x) => throw null; public interface IUnionMembers : IUnionMembersBase { public static S1 Create(int x) => new S1(x); public static S1 Create(string x) => new S1(x); public object Value { get; } public new int TryGetValue(out int x); } public interface IUnionMembersBase { public bool TryGetValue(out int x); } } class Program { static void Main() { System.Console.Write(Test1(new S1(1))); System.Console.Write(Test1(new S1())); } static bool Test1(S1 u) { return u is int; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); var verifier = CompileAndVerify(comp, expectedOutput: "TrueFalse").VerifyDiagnostics(); verifier.VerifyIL("Program.Test1", @" { // Code size 16 (0x10) .maxstack 2 .locals init (int V_0) IL_0000: ldarga.s V_0 IL_0002: ldloca.s V_0 IL_0004: constrained. ""S1"" IL_000a: callvirt ""bool S1.IUnionMembersBase.TryGetValue(out int)"" IL_000f: ret } "); } [Fact] public void NonBoxingUnionMatching_MemberProvider_TryGetValue_Inheritance_30_Shadowing() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 : S1.IUnionMembers { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } public object Value => throw null; bool IUnionMembersBase.TryGetValue(out int x) { if (_value is int v) { x = v; return true; } x = 0; return false; } bool IUnionMembers.TryGetValue => throw null; public interface IUnionMembers : IUnionMembersBase { public static S1 Create(int x) => new S1(x); public static S1 Create(string x) => new S1(x); public object Value { get; } public new bool TryGetValue { get; } } public interface IUnionMembersBase { public bool TryGetValue(out int x); } } class Program { static void Main() { System.Console.Write(Test1(new S1(1))); System.Console.Write(Test1(new S1())); } static bool Test1(S1 u) { return u is int; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); var verifier = CompileAndVerify(comp, expectedOutput: "TrueFalse").VerifyDiagnostics(); verifier.VerifyIL("Program.Test1", @" { // Code size 16 (0x10) .maxstack 2 .locals init (int V_0) IL_0000: ldarga.s V_0 IL_0002: ldloca.s V_0 IL_0004: constrained. ""S1"" IL_000a: callvirt ""bool S1.IUnionMembersBase.TryGetValue(out int)"" IL_000f: ret } "); } [Fact] public void NonBoxingUnionMatching_MemberProvider_TryGetValue_Inheritance_31_Shadowing() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 : S1.IUnionMembers { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } public object Value => throw null; int IBase2.TryGetValue(out int x) => throw null; bool IBase1.TryGetValue(out int x) { if (_value is int v) { x = v; return true; } x = 0; return false; } public interface IUnionMembers : IBase2, IBase1 { public static S1 Create(int x) => new S1(x); public static S1 Create(string x) => new S1(x); public object Value { get; } } public interface IBase2 : IBase1 { public new int TryGetValue(out int x); } public interface IBase1 { public bool TryGetValue(out int x); } } class Program { static void Main() { System.Console.Write(Test1(new S1(1))); System.Console.Write(Test1(new S1())); } static bool Test1(S1 u) { return u is int; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); var verifier = CompileAndVerify(comp, expectedOutput: "TrueFalse").VerifyDiagnostics(); verifier.VerifyIL("Program.Test1", @" { // Code size 16 (0x10) .maxstack 2 .locals init (int V_0) IL_0000: ldarga.s V_0 IL_0002: ldloca.s V_0 IL_0004: constrained. ""S1"" IL_000a: callvirt ""bool S1.IBase1.TryGetValue(out int)"" IL_000f: ret } "); } [Fact] public void NonBoxingUnionMatching_MemberProvider_TryGetValue_Inheritance_32_Shadowing() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 : S1.IUnionMembers { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } public object Value => throw null; bool IBase2.TryGetValue => throw null; bool IBase1.TryGetValue(out int x) { if (_value is int v) { x = v; return true; } x = 0; return false; } public interface IUnionMembers : IBase2, IBase1 { public static S1 Create(int x) => new S1(x); public static S1 Create(string x) => new S1(x); public object Value { get; } } public interface IBase2 : IBase1 { public new bool TryGetValue { get; } } public interface IBase1 { public bool TryGetValue(out int x); } } class Program { static void Main() { System.Console.Write(Test1(new S1(1))); System.Console.Write(Test1(new S1())); } static bool Test1(S1 u) { return u is int; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); var verifier = CompileAndVerify(comp, expectedOutput: "TrueFalse").VerifyDiagnostics(); verifier.VerifyIL("Program.Test1", @" { // Code size 16 (0x10) .maxstack 2 .locals init (int V_0) IL_0000: ldarga.s V_0 IL_0002: ldloca.s V_0 IL_0004: constrained. ""S1"" IL_000a: callvirt ""bool S1.IBase1.TryGetValue(out int)"" IL_000f: ret } "); } [Theory] [CombinatorialData] public void NonBoxingUnionMatching_MemberProvider_TryGetValue_Inheritance_33_ImplicitReferenceConversion_Vs_Identity( [CombinatorialValues(new string[] { "C1", "C2" }, new string[] { "C2", "C1" })] string[] types) { var src = @" [System.Runtime.CompilerServices.Union] struct S1 : S1.IUnionMembers { private readonly object _value; public S1(C1 x) { _value = x; } public S1(C2 x) { _value = x; } public object Value => throw null; public bool TryGetValue(out C1 value) => throw null; public bool TryGetValue(out C2 value) { if (_value is C2) { value = (C2)_value; return true; } else { value = null; return false; } } public interface IUnionMembers : IUnionMembersBase { public static S1 Create(C1 x) => new S1(x); public static S1 Create(C2 x) => new S1(x); public object Value { get; } public bool TryGetValue(out " + types[0] + @" value); } public interface IUnionMembersBase { public bool TryGetValue(out " + types[1] + @" value); } } class C1; class C2 : C1; class Program { static void Main() { System.Console.Write(Test1(new S1(new C1()))); System.Console.Write(Test1(default)); System.Console.Write(Test1(new S1(new C2()))); } static bool Test1(S1 u) { return u is C2; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); CompileAndVerify(comp, expectedOutput: "FalseFalseTrue").VerifyDiagnostics(); } [Theory] [CombinatorialData] public void NonBoxingUnionMatching_MemberProvider_TryGetValue_Inheritance_34_ImplicitReferenceConversion_Vs_Identity( [CombinatorialValues(new string[] { "C1", "C2" }, new string[] { "C2", "C1" })] string[] types) { var src = @" [System.Runtime.CompilerServices.Union] struct S1 : S1.IUnionMembers { private readonly object _value; public S1(C1 x) { _value = x; } public S1(C2 x) { _value = x; } public object Value => throw null; public bool TryGetValue(out C1 value) => throw null; public bool TryGetValue(out C2 value) { if (_value is C2) { value = (C2)_value; return true; } else { value = null; return false; } } public interface IUnionMembers : IBase2 { public static S1 Create(C1 x) => new S1(x); public static S1 Create(C2 x) => new S1(x); public object Value { get; } } public interface IBase2 : IBase1 { public bool TryGetValue(out " + types[0] + @" value); } public interface IBase1 { public bool TryGetValue(out " + types[1] + @" value); } } class C1; class C2 : C1; class Program { static void Main() { System.Console.Write(Test1(new S1(new C1()))); System.Console.Write(Test1(default)); System.Console.Write(Test1(new S1(new C2()))); } static bool Test1(S1 u) { return u is C2; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); CompileAndVerify(comp, expectedOutput: "FalseFalseTrue").VerifyDiagnostics(); } [Theory] [CombinatorialData] public void NonBoxingUnionMatching_MemberProvider_TryGetValue_Inheritance_35_ImplicitReferenceConversion_Determinism( [CombinatorialValues(new string[] { "C1", "C0" }, new string[] { "C0", "C1" })] string[] types) { var src1 = @" [System.Runtime.CompilerServices.Union] public struct S1 : S1.IUnionMembers { private readonly object _value; public S1(C1 x) { _value = x; } public S1(C0 x) { _value = x; } public object Value => throw null; public bool TryGetValue(out " + types[0] + @" value) { if (_value is " + types[0] + @") { value = (" + types[0] + @")_value; return true; } else { value = null; return false; } } public bool TryGetValue(out " + types[1] + @" value) => throw null; public interface IUnionMembers : IUnionMembersBase { public static S1 Create(C1 x) => new S1(x); public static S1 Create(C0 x) => new S1(x); public object Value { get; } public bool TryGetValue(out " + types[0] + @" value); } public interface IUnionMembersBase { public bool TryGetValue(out " + types[1] + @" value); } } public class C0; public class C1 : C0; public class C2 : C1; "; var src2 = @" class Program { static void Main() { System.Console.Write(Test1(new S1(new C1()))); System.Console.Write(Test1(default)); System.Console.Write(Test1(new S1(new C2()))); } static bool Test1(S1 u) { return u is C2; } } "; var comp1 = CreateCompilation([src1, src2, UnionAttributeSource], options: TestOptions.ReleaseExe); CompileAndVerify(comp1, expectedOutput: "FalseFalseTrue").VerifyDiagnostics(); var comp2 = CreateCompilation(src2, references: [comp1.EmitToImageReference()], options: TestOptions.ReleaseExe); CompileAndVerify(comp2, expectedOutput: "FalseFalseTrue").VerifyDiagnostics(); } [Theory] [CombinatorialData] public void NonBoxingUnionMatching_MemberProvider_TryGetValue_Inheritance_36_ImplicitReferenceConversion_Determinism( [CombinatorialValues(new string[] { "C1", "C0" }, new string[] { "C0", "C1" })] string[] types) { var src1 = @" [System.Runtime.CompilerServices.Union] public struct S1 : S1.IUnionMembers { private readonly object _value; public S1(C1 x) { _value = x; } public S1(C0 x) { _value = x; } public object Value => throw null; public bool TryGetValue(out " + types[0] + @" value) { if (_value is " + types[0] + @") { value = (" + types[0] + @")_value; return true; } else { value = null; return false; } } public bool TryGetValue(out " + types[1] + @" value) => throw null; public interface IUnionMembers : IBase2 { public static S1 Create(C1 x) => new S1(x); public static S1 Create(C0 x) => new S1(x); public object Value { get; } } public interface IBase2 : IBase1 { public bool TryGetValue(out " + types[0] + @" value); } public interface IBase1 { public bool TryGetValue(out " + types[1] + @" value); } } public class C0; public class C1 : C0; public class C2 : C1; "; var src2 = @" class Program { static void Main() { System.Console.Write(Test1(new S1(new C1()))); System.Console.Write(Test1(default)); System.Console.Write(Test1(new S1(new C2()))); } static bool Test1(S1 u) { return u is C2; } } "; var comp1 = CreateCompilation([src1, src2, UnionAttributeSource], options: TestOptions.ReleaseExe); CompileAndVerify(comp1, expectedOutput: "FalseFalseTrue").VerifyDiagnostics(); var comp2 = CreateCompilation(src2, references: [comp1.EmitToImageReference()], options: TestOptions.ReleaseExe); CompileAndVerify(comp2, expectedOutput: "FalseFalseTrue").VerifyDiagnostics(); } [Theory] [CombinatorialData] [WorkItem("https://github.com/dotnet/roslyn/issues/82636")] public void NonBoxingUnionMatching_MemberProvider_TryGetValue_Inheritance_37_ImplicitReferenceConversion_Determinism( [CombinatorialValues(new string[] { "C1", "C0" }, new string[] { "C0", "C1" })] string[] types) { var src1 = @" [System.Runtime.CompilerServices.Union] public struct S1 : S1.IUnionMembers { private readonly object _value; public S1(C1 x) { _value = x; } public S1(C0 x) { _value = x; } public object Value => throw null; public bool TryGetValue(out " + types[0] + @" value) { if (_value is " + types[0] + @") { value = (" + types[0] + @")_value; return true; } else { value = null; return false; } } public bool TryGetValue(out " + types[1] + @" value) => throw null; public interface IUnionMembers : IBase0, IBase2 { public static S1 Create(C1 x) => new S1(x); public static S1 Create(C0 x) => new S1(x); public object Value { get; } } public interface IBase2 : IBase1, IBase0 { } public interface IBase1 { public bool TryGetValue(out " + types[1] + @" value); } public interface IBase0 { public bool TryGetValue(out " + types[0] + @" value); } } public class C0; public class C1 : C0; public class C2 : C1; "; var src2 = @" class Program { static void Main() { System.Console.Write(Test1(new S1(new C1()))); System.Console.Write(Test1(default)); System.Console.Write(Test1(new S1(new C2()))); } static bool Test1(S1 u) { return u is C2; } } "; var comp1 = CreateCompilation([src1, src2, UnionAttributeSource], options: TestOptions.ReleaseExe); CompileAndVerify(comp1, expectedOutput: "FalseFalseTrue").VerifyDiagnostics(); var comp2 = CreateCompilation(src2, references: [comp1.EmitToImageReference()], options: TestOptions.ReleaseExe); CompileAndVerify(comp2, expectedOutput: "FalseFalseTrue").VerifyDiagnostics(); } [Theory] [CombinatorialData] public void NonBoxingUnionMatching_MemberProvider_TryGetValue_Inheritance_38_BoxingConversion_Vs_Identity( [CombinatorialValues(new string[] { "System.IComparable", "int" }, new string[] { "int", "System.IComparable" })] string[] types) { var src = @" [System.Runtime.CompilerServices.Union] struct S1 : S1.IUnionMembers { private readonly object _value; public S1(System.IComparable x) { _value = x; } public S1(int x) { _value = x; } public object Value => throw null; public bool TryGetValue(out System.IComparable value) => throw null; public bool TryGetValue(out int value) { if (_value is int) { value = (int)_value; return true; } else { value = 0; return false; } } public interface IUnionMembers : IUnionMembersBase { public static S1 Create(System.IComparable x) => new S1(x); public static S1 Create(int x) => new S1(x); public object Value { get; } public bool TryGetValue(out " + types[0] + @" value); } public interface IUnionMembersBase { public bool TryGetValue(out " + types[1] + @" value); } } class Program { static void Main() { System.Console.Write(Test1(new S1(""""))); System.Console.Write(Test1(default)); System.Console.Write(Test1(new S1(1))); } static bool Test1(S1 u) { return u is 1; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); CompileAndVerify(comp, expectedOutput: "FalseFalseTrue").VerifyDiagnostics(); } [Theory] [CombinatorialData] public void NonBoxingUnionMatching_MemberProvider_TryGetValue_Inheritance_39_BoxingConversion_Vs_Identity( [CombinatorialValues(new string[] { "System.IComparable", "int" }, new string[] { "int", "System.IComparable" })] string[] types) { var src = @" [System.Runtime.CompilerServices.Union] struct S1 : S1.IUnionMembers { private readonly object _value; public S1(System.IComparable x) { _value = x; } public S1(int x) { _value = x; } public object Value => throw null; public bool TryGetValue(out System.IComparable value) => throw null; public bool TryGetValue(out int value) { if (_value is int) { value = (int)_value; return true; } else { value = 0; return false; } } public interface IUnionMembers : IBase2 { public static S1 Create(System.IComparable x) => new S1(x); public static S1 Create(int x) => new S1(x); public object Value { get; } } public interface IBase2 : IBase1 { public bool TryGetValue(out " + types[0] + @" value); } public interface IBase1 { public bool TryGetValue(out " + types[1] + @" value); } } class Program { static void Main() { System.Console.Write(Test1(new S1(""""))); System.Console.Write(Test1(default)); System.Console.Write(Test1(new S1(1))); } static bool Test1(S1 u) { return u is 1; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); CompileAndVerify(comp, expectedOutput: "FalseFalseTrue").VerifyDiagnostics(); } [Theory] [CombinatorialData] public void NonBoxingUnionMatching_MemberProvider_TryGetValue_Inheritance_40_BoxingConversion_Determinism( [CombinatorialValues(new string[] { "System.IComparable", "System.IConvertible" }, new string[] { "System.IConvertible", "System.IComparable" })] string[] types) { var src1 = @" [System.Runtime.CompilerServices.Union] public struct S1 : S1.IUnionMembers { private readonly object _value; public S1(System.IComparable x) { _value = x; } public S1(System.IConvertible x) { _value = x; } public object Value => throw null; public bool TryGetValue(out " + types[0] + @" value) { if (_value is " + types[0] + @") { value = (" + types[0] + @")_value; return true; } else { value = null; return false; } } public bool TryGetValue(out " + types[1] + @" value) => throw null; public interface IUnionMembers : IUnionMembersBase { public static S1 Create(System.IComparable x) => new S1(x); public static S1 Create(System.IConvertible x) => new S1(x); public object Value { get; } public bool TryGetValue(out " + types[0] + @" value); } public interface IUnionMembersBase { public bool TryGetValue(out " + types[1] + @" value); } } "; var src2 = @" class Program { static void Main() { System.Console.Write(Test1(new S1((System.IComparable)""""))); System.Console.Write(Test1(default)); System.Console.Write(Test1(new S1((System.IComparable)1))); } static bool Test1(S1 u) { return u is 1; } } "; var comp1 = CreateCompilation([src1, src2, UnionAttributeSource], options: TestOptions.ReleaseExe); CompileAndVerify(comp1, expectedOutput: "FalseFalseTrue").VerifyDiagnostics(); var comp2 = CreateCompilation(src2, references: [comp1.EmitToImageReference()], options: TestOptions.ReleaseExe); CompileAndVerify(comp2, expectedOutput: "FalseFalseTrue").VerifyDiagnostics(); } [Theory] [CombinatorialData] public void NonBoxingUnionMatching_MemberProvider_TryGetValue_Inheritance_41_BoxingConversion_Determinism( [CombinatorialValues(new string[] { "System.IComparable", "System.IConvertible" }, new string[] { "System.IConvertible", "System.IComparable" })] string[] types) { var src1 = @" [System.Runtime.CompilerServices.Union] public struct S1 : S1.IUnionMembers { private readonly object _value; public S1(System.IComparable x) { _value = x; } public S1(System.IConvertible x) { _value = x; } public object Value => throw null; public bool TryGetValue(out " + types[0] + @" value) { if (_value is " + types[0] + @") { value = (" + types[0] + @")_value; return true; } else { value = null; return false; } } public bool TryGetValue(out " + types[1] + @" value) => throw null; public interface IUnionMembers : IBase2 { public static S1 Create(System.IComparable x) => new S1(x); public static S1 Create(System.IConvertible x) => new S1(x); public object Value { get; } } public interface IBase2 : IBase1 { public bool TryGetValue(out " + types[0] + @" value); } public interface IBase1 { public bool TryGetValue(out " + types[1] + @" value); } } "; var src2 = @" class Program { static void Main() { System.Console.Write(Test1(new S1((System.IComparable)""""))); System.Console.Write(Test1(default)); System.Console.Write(Test1(new S1((System.IComparable)1))); } static bool Test1(S1 u) { return u is 1; } } "; var comp1 = CreateCompilation([src1, src2, UnionAttributeSource], options: TestOptions.ReleaseExe); CompileAndVerify(comp1, expectedOutput: "FalseFalseTrue").VerifyDiagnostics(); var comp2 = CreateCompilation(src2, references: [comp1.EmitToImageReference()], options: TestOptions.ReleaseExe); CompileAndVerify(comp2, expectedOutput: "FalseFalseTrue").VerifyDiagnostics(); } [Theory] [CombinatorialData] public void NonBoxingUnionMatching_MemberProvider_TryGetValue_Inheritance_42_BoxingConversion_Determinism( [CombinatorialValues(new string[] { "System.IComparable", "System.IConvertible" }, new string[] { "System.IConvertible", "System.IComparable" })] string[] types) { var src1 = @" [System.Runtime.CompilerServices.Union] public struct S1 : S1.IUnionMembers { private readonly object _value; public S1(System.IComparable x) { _value = x; } public S1(System.IConvertible x) { _value = x; } public object Value => throw null; public bool TryGetValue(out " + types[0] + @" value) { if (_value is " + types[0] + @") { value = (" + types[0] + @")_value; return true; } else { value = null; return false; } } public bool TryGetValue(out " + types[1] + @" value) => throw null; public interface IUnionMembers : IBase2 { public static S1 Create(System.IComparable x) => new S1(x); public static S1 Create(System.IConvertible x) => new S1(x); public object Value { get; } } public interface IBase2 : IBase1, IBase0 { } public interface IBase1 { public bool TryGetValue(out " + types[0] + @" value); } public interface IBase0 { public bool TryGetValue(out " + types[1] + @" value); } } "; var src2 = @" class Program { static void Main() { System.Console.Write(Test1(new S1((System.IComparable)""""))); System.Console.Write(Test1(default)); System.Console.Write(Test1(new S1((System.IComparable)1))); } static bool Test1(S1 u) { return u is 1; } } "; var comp1 = CreateCompilation([src1, src2, UnionAttributeSource], options: TestOptions.ReleaseExe); CompileAndVerify(comp1, expectedOutput: "FalseFalseTrue").VerifyDiagnostics(); var comp2 = CreateCompilation(src2, references: [comp1.EmitToImageReference()], options: TestOptions.ReleaseExe); CompileAndVerify(comp2, expectedOutput: "FalseFalseTrue").VerifyDiagnostics(); } [Fact] public void NonBoxingUnionMatching_MemberProvider_TryGetValue_Inheritance_43_Identity_Determinism() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 : S1.IUnionMembers { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } public object Value => throw null; int IBase2.TryGetValue(out int x) => throw null; bool IBase1.TryGetValue(out int x) { if (_value is int v) { x = v; return true; } x = 0; return false; } public interface IUnionMembers : IBase2, IBase1 { public static S1 Create(int x) => new S1(x); public static S1 Create(string x) => new S1(x); public object Value { get; } } public interface IBase2 : IBase1 { public new int TryGetValue(out int x); } public interface IBase1 { public bool TryGetValue(out int x); } } class Program { static void Main() { System.Console.Write(Test1(new S1(1))); System.Console.Write(Test1(new S1())); } static bool Test1(S1 u) { return u is int; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); var verifier = CompileAndVerify(comp, expectedOutput: "TrueFalse").VerifyDiagnostics(); verifier.VerifyIL("Program.Test1", @" { // Code size 16 (0x10) .maxstack 2 .locals init (int V_0) IL_0000: ldarga.s V_0 IL_0002: ldloca.s V_0 IL_0004: constrained. ""S1"" IL_000a: callvirt ""bool S1.IBase1.TryGetValue(out int)"" IL_000f: ret } "); } [Fact] public void NonBoxingUnionMatching_MemberProvider_Misc_01() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 : S1.IUnionMembers { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } object IUnionMembers.Value { get { System.Console.Write(""get_Value ""); return _value; } } bool IUnionMembers.TryGetValue(out int x) { System.Console.Write(""TryGetValue ""); if (_value is int v) { x = v; return true; } x = 0; return false; } public interface IUnionMembers { public static S1 Create(int x) => new S1(x); public static S1 Create(string x) => new S1(x); public object Value { get; } public bool TryGetValue(out int x); } static void Main() { System.Console.Write(Test1((new S1(1), 1))); System.Console.Write(""; ""); System.Console.Write(Test1((new S1(), 2))); System.Console.Write(""; ""); System.Console.Write(Test1((new S1(), 3))); System.Console.Write(""; ""); System.Console.Write(Test1((new S1(""a""), 1))); } static bool Test1((S1, int) u) { return u is (null, 2) or (int, 1); } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); var verifier = CompileAndVerify(comp, expectedOutput: "get_Value TryGetValue True; get_Value True; get_Value False; get_Value TryGetValue False").VerifyDiagnostics(); verifier.VerifyIL("S1.Test1", @" { // Code size 67 (0x43) .maxstack 2 .locals init (S1 V_0, int V_1, bool V_2) IL_0000: ldarg.0 IL_0001: ldfld ""S1 System.ValueTuple<S1, int>.Item1"" IL_0006: stloc.0 IL_0007: ldloca.s V_0 IL_0009: constrained. ""S1"" IL_000f: callvirt ""object S1.IUnionMembers.Value.get"" IL_0014: brtrue.s IL_0021 IL_0016: ldarg.0 IL_0017: ldfld ""int System.ValueTuple<S1, int>.Item2"" IL_001c: ldc.i4.2 IL_001d: beq.s IL_003b IL_001f: br.s IL_003f IL_0021: ldloca.s V_0 IL_0023: ldloca.s V_1 IL_0025: constrained. ""S1"" IL_002b: callvirt ""bool S1.IUnionMembers.TryGetValue(out int)"" IL_0030: brfalse.s IL_003f IL_0032: ldarg.0 IL_0033: ldfld ""int System.ValueTuple<S1, int>.Item2"" IL_0038: ldc.i4.1 IL_0039: bne.un.s IL_003f IL_003b: ldc.i4.1 IL_003c: stloc.2 IL_003d: br.s IL_0041 IL_003f: ldc.i4.0 IL_0040: stloc.2 IL_0041: ldloc.2 IL_0042: ret } "); } [Fact] public void NonBoxingUnionMatching_MemberProvider_Misc_02() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 : S1.IUnionMembers { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } object IUnionMembers.Value { get { System.Console.Write(""get_Value ""); return _value; } } bool IUnionMembers.TryGetValue(out int x) { System.Console.Write(""TryGetValue ""); if (_value is int v) { x = v; return true; } x = 0; return false; } public interface IUnionMembers { public static S1 Create(int x) => new S1(x); public static S1 Create(string x) => new S1(x); public object Value { get; } public bool TryGetValue(out int x); } static void Main() { System.Console.Write(Test1((new S1(1), 1))); System.Console.Write(""; ""); System.Console.Write(Test1((new S1(), 2))); System.Console.Write(""; ""); System.Console.Write(Test1((new S1(), 3))); System.Console.Write(""; ""); System.Console.Write(Test1((new S1(""a""), 1))); } static bool Test1((S1, int) u) { return u is (int, 1) or (null, 2); } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); var verifier = CompileAndVerify(comp, expectedOutput: "TryGetValue True; TryGetValue get_Value True; TryGetValue get_Value False; TryGetValue get_Value False").VerifyDiagnostics(); verifier.VerifyIL("S1.Test1", @" { // Code size 67 (0x43) .maxstack 2 .locals init (S1 V_0, int V_1, bool V_2) IL_0000: ldarg.0 IL_0001: ldfld ""S1 System.ValueTuple<S1, int>.Item1"" IL_0006: stloc.0 IL_0007: ldloca.s V_0 IL_0009: ldloca.s V_1 IL_000b: constrained. ""S1"" IL_0011: callvirt ""bool S1.IUnionMembers.TryGetValue(out int)"" IL_0016: brfalse.s IL_0023 IL_0018: ldarg.0 IL_0019: ldfld ""int System.ValueTuple<S1, int>.Item2"" IL_001e: ldc.i4.1 IL_001f: beq.s IL_003b IL_0021: br.s IL_003f IL_0023: ldloca.s V_0 IL_0025: constrained. ""S1"" IL_002b: callvirt ""object S1.IUnionMembers.Value.get"" IL_0030: brtrue.s IL_003f IL_0032: ldarg.0 IL_0033: ldfld ""int System.ValueTuple<S1, int>.Item2"" IL_0038: ldc.i4.2 IL_0039: bne.un.s IL_003f IL_003b: ldc.i4.1 IL_003c: stloc.2 IL_003d: br.s IL_0041 IL_003f: ldc.i4.0 IL_0040: stloc.2 IL_0041: ldloc.2 IL_0042: ret } "); } [Fact] public void NonBoxingUnionMatching_MemberProvider_Misc_031() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 : S1.IUnionMembers { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } object IUnionMembers.Value { get { System.Console.Write(""get_Value ""); return _value; } } bool IUnionMembers.TryGetValue(out int x) { System.Console.Write(""TryGetValue ""); if (_value is int v) { x = v; return true; } x = 0; return false; } public interface IUnionMembers { public static S1 Create(int x) => new S1(x); public static S1 Create(string x) => new S1(x); public object Value { get; } public bool TryGetValue(out int x); } static void Main() { System.Console.Write(Test1((new S1(1), 1))); System.Console.Write(""; ""); System.Console.Write(Test1((new S1(1), -1))); System.Console.Write(""; ""); System.Console.Write(Test1((new S1(), 2))); System.Console.Write(""; ""); System.Console.Write(Test1((new S1(), 3))); System.Console.Write(""; ""); System.Console.Write(Test1((new S1(""a""), 1))); System.Console.Write(""; ""); System.Console.Write(Test1((new S1(""a""), 2))); } static bool Test1((S1, int) u) { return u is (not null, 2) or (int, 1); } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); var verifier = CompileAndVerify(comp, expectedOutput: "get_Value TryGetValue True; get_Value TryGetValue False; get_Value False; get_Value False; get_Value TryGetValue False; get_Value True").VerifyDiagnostics(); verifier.VerifyIL("S1.Test1", @" { // Code size 62 (0x3e) .maxstack 2 .locals init (S1 V_0, int V_1, int V_2, bool V_3) IL_0000: ldarg.0 IL_0001: ldfld ""S1 System.ValueTuple<S1, int>.Item1"" IL_0006: stloc.0 IL_0007: ldloca.s V_0 IL_0009: constrained. ""S1"" IL_000f: callvirt ""object S1.IUnionMembers.Value.get"" IL_0014: brfalse.s IL_003a IL_0016: ldarg.0 IL_0017: ldfld ""int System.ValueTuple<S1, int>.Item2"" IL_001c: stloc.1 IL_001d: ldloc.1 IL_001e: ldc.i4.2 IL_001f: beq.s IL_0036 IL_0021: ldloca.s V_0 IL_0023: ldloca.s V_2 IL_0025: constrained. ""S1"" IL_002b: callvirt ""bool S1.IUnionMembers.TryGetValue(out int)"" IL_0030: brfalse.s IL_003a IL_0032: ldloc.1 IL_0033: ldc.i4.1 IL_0034: bne.un.s IL_003a IL_0036: ldc.i4.1 IL_0037: stloc.3 IL_0038: br.s IL_003c IL_003a: ldc.i4.0 IL_003b: stloc.3 IL_003c: ldloc.3 IL_003d: ret } "); } [Fact] public void NonBoxingUnionMatching_MemberProvider_Misc_04() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 : S1.IUnionMembers { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } object IUnionMembers.Value { get { System.Console.Write(""get_Value ""); return _value; } } bool IUnionMembers.TryGetValue(out int x) { System.Console.Write(""TryGetValue ""); if (_value is int v) { x = v; return true; } x = 0; return false; } public interface IUnionMembers { public static S1 Create(int x) => new S1(x); public static S1 Create(string x) => new S1(x); public object Value { get; } public bool TryGetValue(out int x); } static void Main() { System.Console.Write(Test1((new S1(1), 1))); System.Console.Write(""; ""); System.Console.Write(Test1((new S1(1), -1))); System.Console.Write(""; ""); System.Console.Write(Test1((new S1(), 2))); System.Console.Write(""; ""); System.Console.Write(Test1((new S1(), 3))); System.Console.Write(""; ""); System.Console.Write(Test1((new S1(""a""), 1))); System.Console.Write(""; ""); System.Console.Write(Test1((new S1(""a""), 2))); } static bool Test1((S1, int) u) { return u is (int, 1) or (not null, 2); } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); var verifier = CompileAndVerify(comp, expectedOutput: "TryGetValue True; TryGetValue False; TryGetValue get_Value False; TryGetValue get_Value False; TryGetValue get_Value False; TryGetValue get_Value True").VerifyDiagnostics(); verifier.VerifyIL("S1.Test1", @" { // Code size 71 (0x47) .maxstack 2 .locals init (S1 V_0, int V_1, int V_2, bool V_3) IL_0000: ldarg.0 IL_0001: ldfld ""S1 System.ValueTuple<S1, int>.Item1"" IL_0006: stloc.0 IL_0007: ldloca.s V_0 IL_0009: ldloca.s V_1 IL_000b: constrained. ""S1"" IL_0011: callvirt ""bool S1.IUnionMembers.TryGetValue(out int)"" IL_0016: brfalse.s IL_0025 IL_0018: ldarg.0 IL_0019: ldfld ""int System.ValueTuple<S1, int>.Item2"" IL_001e: stloc.2 IL_001f: ldloc.2 IL_0020: ldc.i4.1 IL_0021: beq.s IL_003f IL_0023: br.s IL_003b IL_0025: ldloca.s V_0 IL_0027: constrained. ""S1"" IL_002d: callvirt ""object S1.IUnionMembers.Value.get"" IL_0032: brfalse.s IL_0043 IL_0034: ldarg.0 IL_0035: ldfld ""int System.ValueTuple<S1, int>.Item2"" IL_003a: stloc.2 IL_003b: ldloc.2 IL_003c: ldc.i4.2 IL_003d: bne.un.s IL_0043 IL_003f: ldc.i4.1 IL_0040: stloc.3 IL_0041: br.s IL_0045 IL_0043: ldc.i4.0 IL_0044: stloc.3 IL_0045: ldloc.3 IL_0046: ret } "); } [Fact] public void NonBoxingUnionMatching_MemberProvider_Misc_05() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 : S1.IUnionMembers { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } object IUnionMembers.Value { get { System.Console.Write(""get_Value ""); return _value; } } bool IUnionMembers.TryGetValue(out int x) { System.Console.Write(""TryGetValue ""); if (_value is int v) { x = v; return true; } x = 0; return false; } public interface IUnionMembers { public static S1 Create(int x) => new S1(x); public static S1 Create(string x) => new S1(x); public object Value { get; } public bool TryGetValue(out int x); } static void Main() { System.Console.Write(Test1((new S1(1), 1))); System.Console.Write(""; ""); System.Console.Write(Test1((new S1(), 2))); System.Console.Write(""; ""); System.Console.Write(Test1((new S1(), 3))); System.Console.Write(""; ""); System.Console.Write(Test1((new S1(), 1))); System.Console.Write(""; ""); System.Console.Write(Test1((new S1(""a""), 1))); System.Console.Write(""; ""); System.Console.Write(Test1((new S1(""a""), 2))); } static bool Test1((S1, int) u) { return u is (null, 2) or (not int, 1); } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); var verifier = CompileAndVerify(comp, expectedOutput: "get_Value TryGetValue False; get_Value True; get_Value False; get_Value True; get_Value TryGetValue True; get_Value TryGetValue False").VerifyDiagnostics(); verifier.VerifyIL("S1.Test1", @" { // Code size 71 (0x47) .maxstack 2 .locals init (S1 V_0, int V_1, int V_2, bool V_3) IL_0000: ldarg.0 IL_0001: ldfld ""S1 System.ValueTuple<S1, int>.Item1"" IL_0006: stloc.0 IL_0007: ldloca.s V_0 IL_0009: constrained. ""S1"" IL_000f: callvirt ""object S1.IUnionMembers.Value.get"" IL_0014: brtrue.s IL_0023 IL_0016: ldarg.0 IL_0017: ldfld ""int System.ValueTuple<S1, int>.Item2"" IL_001c: stloc.1 IL_001d: ldloc.1 IL_001e: ldc.i4.2 IL_001f: beq.s IL_003f IL_0021: br.s IL_003b IL_0023: ldloca.s V_0 IL_0025: ldloca.s V_2 IL_0027: constrained. ""S1"" IL_002d: callvirt ""bool S1.IUnionMembers.TryGetValue(out int)"" IL_0032: brtrue.s IL_0043 IL_0034: ldarg.0 IL_0035: ldfld ""int System.ValueTuple<S1, int>.Item2"" IL_003a: stloc.1 IL_003b: ldloc.1 IL_003c: ldc.i4.1 IL_003d: bne.un.s IL_0043 IL_003f: ldc.i4.1 IL_0040: stloc.3 IL_0041: br.s IL_0045 IL_0043: ldc.i4.0 IL_0044: stloc.3 IL_0045: ldloc.3 IL_0046: ret } "); } [Fact] public void NonBoxingUnionMatching_MemberProvider_Misc_06() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 : S1.IUnionMembers { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } object IUnionMembers.Value { get { System.Console.Write(""get_Value ""); return _value; } } bool IUnionMembers.TryGetValue(out int x) { System.Console.Write(""TryGetValue ""); if (_value is int v) { x = v; return true; } x = 0; return false; } public interface IUnionMembers { public static S1 Create(int x) => new S1(x); public static S1 Create(string x) => new S1(x); public object Value { get; } public bool TryGetValue(out int x); } static void Main() { System.Console.Write(Test1((new S1(1), 1))); System.Console.Write(""; ""); System.Console.Write(Test1((new S1(), 2))); System.Console.Write(""; ""); System.Console.Write(Test1((new S1(), 3))); System.Console.Write(""; ""); System.Console.Write(Test1((new S1(), 1))); System.Console.Write(""; ""); System.Console.Write(Test1((new S1(""a""), 1))); System.Console.Write(""; ""); System.Console.Write(Test1((new S1(""a""), 2))); } static bool Test1((S1, int) u) { return u is (not int, 1) or (null, 2); } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); var verifier = CompileAndVerify(comp, expectedOutput: "TryGetValue False; TryGetValue get_Value True; TryGetValue get_Value False; TryGetValue True; TryGetValue True; TryGetValue get_Value False").VerifyDiagnostics(); verifier.VerifyIL("S1.Test1", @" { // Code size 62 (0x3e) .maxstack 2 .locals init (S1 V_0, int V_1, int V_2, bool V_3) IL_0000: ldarg.0 IL_0001: ldfld ""S1 System.ValueTuple<S1, int>.Item1"" IL_0006: stloc.0 IL_0007: ldloca.s V_0 IL_0009: ldloca.s V_1 IL_000b: constrained. ""S1"" IL_0011: callvirt ""bool S1.IUnionMembers.TryGetValue(out int)"" IL_0016: brtrue.s IL_003a IL_0018: ldarg.0 IL_0019: ldfld ""int System.ValueTuple<S1, int>.Item2"" IL_001e: stloc.2 IL_001f: ldloc.2 IL_0020: ldc.i4.1 IL_0021: beq.s IL_0036 IL_0023: ldloca.s V_0 IL_0025: constrained. ""S1"" IL_002b: callvirt ""object S1.IUnionMembers.Value.get"" IL_0030: brtrue.s IL_003a IL_0032: ldloc.2 IL_0033: ldc.i4.2 IL_0034: bne.un.s IL_003a IL_0036: ldc.i4.1 IL_0037: stloc.3 IL_0038: br.s IL_003c IL_003a: ldc.i4.0 IL_003b: stloc.3 IL_003c: ldloc.3 IL_003d: ret } "); } [Fact] public void NonBoxingUnionMatching_MemberProvider_Misc_07() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 : S1.IUnionMembers { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } object IUnionMembers.Value { get { System.Console.Write(""get_Value ""); return _value; } } bool IUnionMembers.HasValue { get { System.Console.Write(""HasValue ""); return _value != null; } } bool IUnionMembers.TryGetValue(out int x) { System.Console.Write(""TryGetValue ""); if (_value is int v) { x = v; return true; } x = 0; return false; } public interface IUnionMembers { public static S1 Create(int x) => new S1(x); public static S1 Create(string x) => new S1(x); public object Value { get; } public bool HasValue { get; } public bool TryGetValue(out int x); } static void Main() { System.Console.Write(Test1((new S1(1), 1))); System.Console.Write(""; ""); System.Console.Write(Test1((new S1(), 2))); System.Console.Write(""; ""); System.Console.Write(Test1((new S1(), 3))); System.Console.Write(""; ""); System.Console.Write(Test1((new S1(""a""), 1))); } static bool Test1((S1, int) u) { return u is (null, 2) or (int, 1); } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); var verifier = CompileAndVerify(comp, expectedOutput: "HasValue TryGetValue True; HasValue True; HasValue False; HasValue TryGetValue False").VerifyDiagnostics(); verifier.VerifyIL("S1.Test1", @" { // Code size 67 (0x43) .maxstack 2 .locals init (S1 V_0, int V_1, bool V_2) IL_0000: ldarg.0 IL_0001: ldfld ""S1 System.ValueTuple<S1, int>.Item1"" IL_0006: stloc.0 IL_0007: ldloca.s V_0 IL_0009: constrained. ""S1"" IL_000f: callvirt ""bool S1.IUnionMembers.HasValue.get"" IL_0014: brtrue.s IL_0021 IL_0016: ldarg.0 IL_0017: ldfld ""int System.ValueTuple<S1, int>.Item2"" IL_001c: ldc.i4.2 IL_001d: beq.s IL_003b IL_001f: br.s IL_003f IL_0021: ldloca.s V_0 IL_0023: ldloca.s V_1 IL_0025: constrained. ""S1"" IL_002b: callvirt ""bool S1.IUnionMembers.TryGetValue(out int)"" IL_0030: brfalse.s IL_003f IL_0032: ldarg.0 IL_0033: ldfld ""int System.ValueTuple<S1, int>.Item2"" IL_0038: ldc.i4.1 IL_0039: bne.un.s IL_003f IL_003b: ldc.i4.1 IL_003c: stloc.2 IL_003d: br.s IL_0041 IL_003f: ldc.i4.0 IL_0040: stloc.2 IL_0041: ldloc.2 IL_0042: ret } "); } [Fact] public void NonBoxingUnionMatching_MemberProvider_Misc_08() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 : S1.IUnionMembers { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } object IUnionMembers.Value { get { System.Console.Write(""get_Value ""); return _value; } } bool IUnionMembers.HasValue { get { System.Console.Write(""HasValue ""); return _value != null; } } bool IUnionMembers.TryGetValue(out int x) { System.Console.Write(""TryGetValue ""); if (_value is int v) { x = v; return true; } x = 0; return false; } public interface IUnionMembers { public static S1 Create(int x) => new S1(x); public static S1 Create(string x) => new S1(x); public object Value { get; } public bool HasValue { get; } public bool TryGetValue(out int x); } static void Main() { System.Console.Write(Test1((new S1(1), 1))); System.Console.Write(""; ""); System.Console.Write(Test1((new S1(), 2))); System.Console.Write(""; ""); System.Console.Write(Test1((new S1(), 3))); System.Console.Write(""; ""); System.Console.Write(Test1((new S1(""a""), 1))); } static bool Test1((S1, int) u) { return u is (int, 1) or (null, 2); } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); var verifier = CompileAndVerify(comp, expectedOutput: "TryGetValue True; TryGetValue HasValue True; TryGetValue HasValue False; TryGetValue HasValue False").VerifyDiagnostics(); verifier.VerifyIL("S1.Test1", @" { // Code size 67 (0x43) .maxstack 2 .locals init (S1 V_0, int V_1, bool V_2) IL_0000: ldarg.0 IL_0001: ldfld ""S1 System.ValueTuple<S1, int>.Item1"" IL_0006: stloc.0 IL_0007: ldloca.s V_0 IL_0009: ldloca.s V_1 IL_000b: constrained. ""S1"" IL_0011: callvirt ""bool S1.IUnionMembers.TryGetValue(out int)"" IL_0016: brfalse.s IL_0023 IL_0018: ldarg.0 IL_0019: ldfld ""int System.ValueTuple<S1, int>.Item2"" IL_001e: ldc.i4.1 IL_001f: beq.s IL_003b IL_0021: br.s IL_003f IL_0023: ldloca.s V_0 IL_0025: constrained. ""S1"" IL_002b: callvirt ""bool S1.IUnionMembers.HasValue.get"" IL_0030: brtrue.s IL_003f IL_0032: ldarg.0 IL_0033: ldfld ""int System.ValueTuple<S1, int>.Item2"" IL_0038: ldc.i4.2 IL_0039: bne.un.s IL_003f IL_003b: ldc.i4.1 IL_003c: stloc.2 IL_003d: br.s IL_0041 IL_003f: ldc.i4.0 IL_0040: stloc.2 IL_0041: ldloc.2 IL_0042: ret } "); } [Fact] public void NonBoxingUnionMatching_MemberProvider_Misc_09() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 : S1.IUnionMembers { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } object IUnionMembers.Value { get { System.Console.Write(""get_Value ""); return _value; } } bool IUnionMembers.HasValue { get { System.Console.Write(""HasValue ""); return _value != null; } } bool IUnionMembers.TryGetValue(out int x) { System.Console.Write(""TryGetValue ""); if (_value is int v) { x = v; return true; } x = 0; return false; } public interface IUnionMembers { public static S1 Create(int x) => new S1(x); public static S1 Create(string x) => new S1(x); public object Value { get; } public bool HasValue { get; } public bool TryGetValue(out int x); } static void Main() { System.Console.Write(Test1((new S1(1), 1))); System.Console.Write(""; ""); System.Console.Write(Test1((new S1(1), -1))); System.Console.Write(""; ""); System.Console.Write(Test1((new S1(), 2))); System.Console.Write(""; ""); System.Console.Write(Test1((new S1(), 3))); System.Console.Write(""; ""); System.Console.Write(Test1((new S1(""a""), 1))); System.Console.Write(""; ""); System.Console.Write(Test1((new S1(""a""), 2))); } static bool Test1((S1, int) u) { return u is (not null, 2) or (int, 1); } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); var verifier = CompileAndVerify(comp, expectedOutput: "HasValue TryGetValue True; HasValue TryGetValue False; HasValue False; HasValue False; HasValue TryGetValue False; HasValue True").VerifyDiagnostics(); verifier.VerifyIL("S1.Test1", @" { // Code size 62 (0x3e) .maxstack 2 .locals init (S1 V_0, int V_1, int V_2, bool V_3) IL_0000: ldarg.0 IL_0001: ldfld ""S1 System.ValueTuple<S1, int>.Item1"" IL_0006: stloc.0 IL_0007: ldloca.s V_0 IL_0009: constrained. ""S1"" IL_000f: callvirt ""bool S1.IUnionMembers.HasValue.get"" IL_0014: brfalse.s IL_003a IL_0016: ldarg.0 IL_0017: ldfld ""int System.ValueTuple<S1, int>.Item2"" IL_001c: stloc.1 IL_001d: ldloc.1 IL_001e: ldc.i4.2 IL_001f: beq.s IL_0036 IL_0021: ldloca.s V_0 IL_0023: ldloca.s V_2 IL_0025: constrained. ""S1"" IL_002b: callvirt ""bool S1.IUnionMembers.TryGetValue(out int)"" IL_0030: brfalse.s IL_003a IL_0032: ldloc.1 IL_0033: ldc.i4.1 IL_0034: bne.un.s IL_003a IL_0036: ldc.i4.1 IL_0037: stloc.3 IL_0038: br.s IL_003c IL_003a: ldc.i4.0 IL_003b: stloc.3 IL_003c: ldloc.3 IL_003d: ret } "); } [Fact] public void NonBoxingUnionMatching_MemberProvider_Misc_10() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 : S1.IUnionMembers { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } object IUnionMembers.Value { get { System.Console.Write(""get_Value ""); return _value; } } bool IUnionMembers.HasValue { get { System.Console.Write(""HasValue ""); return _value != null; } } bool IUnionMembers.TryGetValue(out int x) { System.Console.Write(""TryGetValue ""); if (_value is int v) { x = v; return true; } x = 0; return false; } public interface IUnionMembers { public static S1 Create(int x) => new S1(x); public static S1 Create(string x) => new S1(x); public object Value { get; } public bool HasValue { get; } public bool TryGetValue(out int x); } static void Main() { System.Console.Write(Test1((new S1(1), 1))); System.Console.Write(""; ""); System.Console.Write(Test1((new S1(1), -1))); System.Console.Write(""; ""); System.Console.Write(Test1((new S1(), 2))); System.Console.Write(""; ""); System.Console.Write(Test1((new S1(), 3))); System.Console.Write(""; ""); System.Console.Write(Test1((new S1(""a""), 1))); System.Console.Write(""; ""); System.Console.Write(Test1((new S1(""a""), 2))); } static bool Test1((S1, int) u) { return u is (int, 1) or (not null, 2); } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); var verifier = CompileAndVerify(comp, expectedOutput: "TryGetValue True; TryGetValue False; TryGetValue HasValue False; TryGetValue HasValue False; TryGetValue HasValue False; TryGetValue HasValue True").VerifyDiagnostics(); verifier.VerifyIL("S1.Test1", @" { // Code size 71 (0x47) .maxstack 2 .locals init (S1 V_0, int V_1, int V_2, bool V_3) IL_0000: ldarg.0 IL_0001: ldfld ""S1 System.ValueTuple<S1, int>.Item1"" IL_0006: stloc.0 IL_0007: ldloca.s V_0 IL_0009: ldloca.s V_1 IL_000b: constrained. ""S1"" IL_0011: callvirt ""bool S1.IUnionMembers.TryGetValue(out int)"" IL_0016: brfalse.s IL_0025 IL_0018: ldarg.0 IL_0019: ldfld ""int System.ValueTuple<S1, int>.Item2"" IL_001e: stloc.2 IL_001f: ldloc.2 IL_0020: ldc.i4.1 IL_0021: beq.s IL_003f IL_0023: br.s IL_003b IL_0025: ldloca.s V_0 IL_0027: constrained. ""S1"" IL_002d: callvirt ""bool S1.IUnionMembers.HasValue.get"" IL_0032: brfalse.s IL_0043 IL_0034: ldarg.0 IL_0035: ldfld ""int System.ValueTuple<S1, int>.Item2"" IL_003a: stloc.2 IL_003b: ldloc.2 IL_003c: ldc.i4.2 IL_003d: bne.un.s IL_0043 IL_003f: ldc.i4.1 IL_0040: stloc.3 IL_0041: br.s IL_0045 IL_0043: ldc.i4.0 IL_0044: stloc.3 IL_0045: ldloc.3 IL_0046: ret } "); } [Fact] public void NonBoxingUnionMatching_MemberProvider_Misc_11() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 : S1.IUnionMembers { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } object IUnionMembers.Value { get { System.Console.Write(""get_Value ""); return _value; } } bool IUnionMembers.HasValue { get { System.Console.Write(""HasValue ""); return _value != null; } } bool IUnionMembers.TryGetValue(out int x) { System.Console.Write(""TryGetValue ""); if (_value is int v) { x = v; return true; } x = 0; return false; } public interface IUnionMembers { public static S1 Create(int x) => new S1(x); public static S1 Create(string x) => new S1(x); public object Value { get; } public bool HasValue { get; } public bool TryGetValue(out int x); } static void Main() { System.Console.Write(Test1((new S1(1), 1))); System.Console.Write(""; ""); System.Console.Write(Test1((new S1(), 2))); System.Console.Write(""; ""); System.Console.Write(Test1((new S1(), 3))); System.Console.Write(""; ""); System.Console.Write(Test1((new S1(), 1))); System.Console.Write(""; ""); System.Console.Write(Test1((new S1(""a""), 1))); System.Console.Write(""; ""); System.Console.Write(Test1((new S1(""a""), 2))); } static bool Test1((S1, int) u) { return u is (null, 2) or (not int, 1); } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); var verifier = CompileAndVerify(comp, expectedOutput: "HasValue TryGetValue False; HasValue True; HasValue False; HasValue True; HasValue TryGetValue True; HasValue TryGetValue False").VerifyDiagnostics(); verifier.VerifyIL("S1.Test1", @" { // Code size 71 (0x47) .maxstack 2 .locals init (S1 V_0, int V_1, int V_2, bool V_3) IL_0000: ldarg.0 IL_0001: ldfld ""S1 System.ValueTuple<S1, int>.Item1"" IL_0006: stloc.0 IL_0007: ldloca.s V_0 IL_0009: constrained. ""S1"" IL_000f: callvirt ""bool S1.IUnionMembers.HasValue.get"" IL_0014: brtrue.s IL_0023 IL_0016: ldarg.0 IL_0017: ldfld ""int System.ValueTuple<S1, int>.Item2"" IL_001c: stloc.1 IL_001d: ldloc.1 IL_001e: ldc.i4.2 IL_001f: beq.s IL_003f IL_0021: br.s IL_003b IL_0023: ldloca.s V_0 IL_0025: ldloca.s V_2 IL_0027: constrained. ""S1"" IL_002d: callvirt ""bool S1.IUnionMembers.TryGetValue(out int)"" IL_0032: brtrue.s IL_0043 IL_0034: ldarg.0 IL_0035: ldfld ""int System.ValueTuple<S1, int>.Item2"" IL_003a: stloc.1 IL_003b: ldloc.1 IL_003c: ldc.i4.1 IL_003d: bne.un.s IL_0043 IL_003f: ldc.i4.1 IL_0040: stloc.3 IL_0041: br.s IL_0045 IL_0043: ldc.i4.0 IL_0044: stloc.3 IL_0045: ldloc.3 IL_0046: ret } "); } [Fact] public void NonBoxingUnionMatching_MemberProvider_Misc_12() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 : S1.IUnionMembers { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } object IUnionMembers.Value { get { System.Console.Write(""get_Value ""); return _value; } } bool IUnionMembers.HasValue { get { System.Console.Write(""HasValue ""); return _value != null; } } bool IUnionMembers.TryGetValue(out int x) { System.Console.Write(""TryGetValue ""); if (_value is int v) { x = v; return true; } x = 0; return false; } public interface IUnionMembers { public static S1 Create(int x) => new S1(x); public static S1 Create(string x) => new S1(x); public object Value { get; } public bool HasValue { get; } public bool TryGetValue(out int x); } static void Main() { System.Console.Write(Test1((new S1(1), 1))); System.Console.Write(""; ""); System.Console.Write(Test1((new S1(), 2))); System.Console.Write(""; ""); System.Console.Write(Test1((new S1(), 3))); System.Console.Write(""; ""); System.Console.Write(Test1((new S1(), 1))); System.Console.Write(""; ""); System.Console.Write(Test1((new S1(""a""), 1))); System.Console.Write(""; ""); System.Console.Write(Test1((new S1(""a""), 2))); } static bool Test1((S1, int) u) { return u is (not int, 1) or (null, 2); } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); var verifier = CompileAndVerify(comp, expectedOutput: "TryGetValue False; TryGetValue HasValue True; TryGetValue HasValue False; TryGetValue True; TryGetValue True; TryGetValue HasValue False").VerifyDiagnostics(); verifier.VerifyIL("S1.Test1", @" { // Code size 62 (0x3e) .maxstack 2 .locals init (S1 V_0, int V_1, int V_2, bool V_3) IL_0000: ldarg.0 IL_0001: ldfld ""S1 System.ValueTuple<S1, int>.Item1"" IL_0006: stloc.0 IL_0007: ldloca.s V_0 IL_0009: ldloca.s V_1 IL_000b: constrained. ""S1"" IL_0011: callvirt ""bool S1.IUnionMembers.TryGetValue(out int)"" IL_0016: brtrue.s IL_003a IL_0018: ldarg.0 IL_0019: ldfld ""int System.ValueTuple<S1, int>.Item2"" IL_001e: stloc.2 IL_001f: ldloc.2 IL_0020: ldc.i4.1 IL_0021: beq.s IL_0036 IL_0023: ldloca.s V_0 IL_0025: constrained. ""S1"" IL_002b: callvirt ""bool S1.IUnionMembers.HasValue.get"" IL_0030: brtrue.s IL_003a IL_0032: ldloc.2 IL_0033: ldc.i4.2 IL_0034: bne.un.s IL_003a IL_0036: ldc.i4.1 IL_0037: stloc.3 IL_0038: br.s IL_003c IL_003a: ldc.i4.0 IL_003b: stloc.3 IL_003c: ldloc.3 IL_003d: ret } "); } [Fact] public void NonBoxingUnionMatching_MemberProvider_Misc_13() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 : S1.IUnionMembers { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } object IUnionMembers.Value { get { System.Console.Write(""get_Value ""); return _value; } } bool IUnionMembers.HasValue { get { System.Console.Write(""HasValue ""); return _value != null; } } public interface IUnionMembers { public static S1 Create(int x) => new S1(x); public static S1 Create(string x) => new S1(x); public object Value { get; } public bool HasValue { get; } } static void Main() { System.Console.Write(Test1((new S1(1), 1))); System.Console.Write(""; ""); System.Console.Write(Test1((new S1(), 2))); System.Console.Write(""; ""); System.Console.Write(Test1((new S1(), 3))); System.Console.Write(""; ""); System.Console.Write(Test1((new S1(""a""), 1))); } static bool Test1((S1, int) u) { return u is (null, 2) or (int, 1); } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); var verifier = CompileAndVerify(comp, expectedOutput: "HasValue get_Value True; HasValue True; HasValue False; HasValue get_Value False").VerifyDiagnostics(); verifier.VerifyIL("S1.Test1", @" { // Code size 70 (0x46) .maxstack 2 .locals init (S1 V_0, bool V_1) IL_0000: ldarg.0 IL_0001: ldfld ""S1 System.ValueTuple<S1, int>.Item1"" IL_0006: stloc.0 IL_0007: ldloca.s V_0 IL_0009: constrained. ""S1"" IL_000f: callvirt ""bool S1.IUnionMembers.HasValue.get"" IL_0014: brtrue.s IL_0021 IL_0016: ldarg.0 IL_0017: ldfld ""int System.ValueTuple<S1, int>.Item2"" IL_001c: ldc.i4.2 IL_001d: beq.s IL_003e IL_001f: br.s IL_0042 IL_0021: ldloca.s V_0 IL_0023: constrained. ""S1"" IL_0029: callvirt ""object S1.IUnionMembers.Value.get"" IL_002e: isinst ""int"" IL_0033: brfalse.s IL_0042 IL_0035: ldarg.0 IL_0036: ldfld ""int System.ValueTuple<S1, int>.Item2"" IL_003b: ldc.i4.1 IL_003c: bne.un.s IL_0042 IL_003e: ldc.i4.1 IL_003f: stloc.1 IL_0040: br.s IL_0044 IL_0042: ldc.i4.0 IL_0043: stloc.1 IL_0044: ldloc.1 IL_0045: ret } "); } [Fact] public void NonBoxingUnionMatching_MemberProvider_Misc_14() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 : S1.IUnionMembers { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } object IUnionMembers.Value { get { System.Console.Write(""get_Value ""); return _value; } } bool IUnionMembers.HasValue { get { System.Console.Write(""HasValue ""); return _value != null; } } public interface IUnionMembers { public static S1 Create(int x) => new S1(x); public static S1 Create(string x) => new S1(x); public object Value { get; } public bool HasValue { get; } } static void Main() { System.Console.Write(Test1((new S1(1), 1))); System.Console.Write(""; ""); System.Console.Write(Test1((new S1(), 2))); System.Console.Write(""; ""); System.Console.Write(Test1((new S1(), 3))); System.Console.Write(""; ""); System.Console.Write(Test1((new S1(""a""), 1))); } static bool Test1((S1, int) u) { return u is (int, 1) or (null, 2); } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); var verifier = CompileAndVerify(comp, expectedOutput: "get_Value True; get_Value HasValue True; get_Value HasValue False; get_Value HasValue False").VerifyDiagnostics(); verifier.VerifyIL("S1.Test1", @" { // Code size 70 (0x46) .maxstack 2 .locals init (S1 V_0, bool V_1) IL_0000: ldarg.0 IL_0001: ldfld ""S1 System.ValueTuple<S1, int>.Item1"" IL_0006: stloc.0 IL_0007: ldloca.s V_0 IL_0009: constrained. ""S1"" IL_000f: callvirt ""object S1.IUnionMembers.Value.get"" IL_0014: isinst ""int"" IL_0019: brfalse.s IL_0026 IL_001b: ldarg.0 IL_001c: ldfld ""int System.ValueTuple<S1, int>.Item2"" IL_0021: ldc.i4.1 IL_0022: beq.s IL_003e IL_0024: br.s IL_0042 IL_0026: ldloca.s V_0 IL_0028: constrained. ""S1"" IL_002e: callvirt ""bool S1.IUnionMembers.HasValue.get"" IL_0033: brtrue.s IL_0042 IL_0035: ldarg.0 IL_0036: ldfld ""int System.ValueTuple<S1, int>.Item2"" IL_003b: ldc.i4.2 IL_003c: bne.un.s IL_0042 IL_003e: ldc.i4.1 IL_003f: stloc.1 IL_0040: br.s IL_0044 IL_0042: ldc.i4.0 IL_0043: stloc.1 IL_0044: ldloc.1 IL_0045: ret } "); } [Fact] public void NonBoxingUnionMatching_MemberProvider_Misc_15() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 : S1.IUnionMembers { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } object IUnionMembers.Value { get { System.Console.Write(""get_Value ""); return _value; } } bool IUnionMembers.HasValue { get { System.Console.Write(""HasValue ""); return _value != null; } } public interface IUnionMembers { public static S1 Create(int x) => new S1(x); public static S1 Create(string x) => new S1(x); public object Value { get; } public bool HasValue { get; } } static void Main() { System.Console.Write(Test1((new S1(1), 1))); System.Console.Write(""; ""); System.Console.Write(Test1((new S1(1), -1))); System.Console.Write(""; ""); System.Console.Write(Test1((new S1(), 2))); System.Console.Write(""; ""); System.Console.Write(Test1((new S1(), 3))); System.Console.Write(""; ""); System.Console.Write(Test1((new S1(""a""), 1))); System.Console.Write(""; ""); System.Console.Write(Test1((new S1(""a""), 2))); } static bool Test1((S1, int) u) { return u is (not null, 2) or (int, 1); } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); var verifier = CompileAndVerify(comp, expectedOutput: "HasValue get_Value True; HasValue get_Value False; HasValue False; HasValue False; HasValue get_Value False; HasValue True").VerifyDiagnostics(); verifier.VerifyIL("S1.Test1", @" { // Code size 65 (0x41) .maxstack 2 .locals init (S1 V_0, int V_1, bool V_2) IL_0000: ldarg.0 IL_0001: ldfld ""S1 System.ValueTuple<S1, int>.Item1"" IL_0006: stloc.0 IL_0007: ldloca.s V_0 IL_0009: constrained. ""S1"" IL_000f: callvirt ""bool S1.IUnionMembers.HasValue.get"" IL_0014: brfalse.s IL_003d IL_0016: ldarg.0 IL_0017: ldfld ""int System.ValueTuple<S1, int>.Item2"" IL_001c: stloc.1 IL_001d: ldloc.1 IL_001e: ldc.i4.2 IL_001f: beq.s IL_0039 IL_0021: ldloca.s V_0 IL_0023: constrained. ""S1"" IL_0029: callvirt ""object S1.IUnionMembers.Value.get"" IL_002e: isinst ""int"" IL_0033: brfalse.s IL_003d IL_0035: ldloc.1 IL_0036: ldc.i4.1 IL_0037: bne.un.s IL_003d IL_0039: ldc.i4.1 IL_003a: stloc.2 IL_003b: br.s IL_003f IL_003d: ldc.i4.0 IL_003e: stloc.2 IL_003f: ldloc.2 IL_0040: ret } "); } [Fact] public void NonBoxingUnionMatching_MemberProvider_Misc_16() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 : S1.IUnionMembers { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } object IUnionMembers.Value { get { System.Console.Write(""get_Value ""); return _value; } } bool IUnionMembers.HasValue { get { System.Console.Write(""HasValue ""); return _value != null; } } public interface IUnionMembers { public static S1 Create(int x) => new S1(x); public static S1 Create(string x) => new S1(x); public object Value { get; } public bool HasValue { get; } } static void Main() { System.Console.Write(Test1((new S1(1), 1))); System.Console.Write(""; ""); System.Console.Write(Test1((new S1(1), -1))); System.Console.Write(""; ""); System.Console.Write(Test1((new S1(), 2))); System.Console.Write(""; ""); System.Console.Write(Test1((new S1(), 3))); System.Console.Write(""; ""); System.Console.Write(Test1((new S1(""a""), 1))); System.Console.Write(""; ""); System.Console.Write(Test1((new S1(""a""), 2))); } static bool Test1((S1, int) u) { return u is (int, 1) or (not null, 2); } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); var verifier = CompileAndVerify(comp, expectedOutput: "get_Value True; get_Value False; get_Value HasValue False; get_Value HasValue False; get_Value HasValue False; get_Value HasValue True").VerifyDiagnostics(); verifier.VerifyIL("S1.Test1", @" { // Code size 74 (0x4a) .maxstack 2 .locals init (S1 V_0, int V_1, bool V_2) IL_0000: ldarg.0 IL_0001: ldfld ""S1 System.ValueTuple<S1, int>.Item1"" IL_0006: stloc.0 IL_0007: ldloca.s V_0 IL_0009: constrained. ""S1"" IL_000f: callvirt ""object S1.IUnionMembers.Value.get"" IL_0014: isinst ""int"" IL_0019: brfalse.s IL_0028 IL_001b: ldarg.0 IL_001c: ldfld ""int System.ValueTuple<S1, int>.Item2"" IL_0021: stloc.1 IL_0022: ldloc.1 IL_0023: ldc.i4.1 IL_0024: beq.s IL_0042 IL_0026: br.s IL_003e IL_0028: ldloca.s V_0 IL_002a: constrained. ""S1"" IL_0030: callvirt ""bool S1.IUnionMembers.HasValue.get"" IL_0035: brfalse.s IL_0046 IL_0037: ldarg.0 IL_0038: ldfld ""int System.ValueTuple<S1, int>.Item2"" IL_003d: stloc.1 IL_003e: ldloc.1 IL_003f: ldc.i4.2 IL_0040: bne.un.s IL_0046 IL_0042: ldc.i4.1 IL_0043: stloc.2 IL_0044: br.s IL_0048 IL_0046: ldc.i4.0 IL_0047: stloc.2 IL_0048: ldloc.2 IL_0049: ret } "); } [Fact] public void NonBoxingUnionMatching_MemberProvider_Misc_17() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 : S1.IUnionMembers { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } object IUnionMembers.Value { get { System.Console.Write(""get_Value ""); return _value; } } bool IUnionMembers.HasValue { get { System.Console.Write(""HasValue ""); return _value != null; } } public interface IUnionMembers { public static S1 Create(int x) => new S1(x); public static S1 Create(string x) => new S1(x); public object Value { get; } public bool HasValue { get; } } static void Main() { System.Console.Write(Test1((new S1(1), 1))); System.Console.Write(""; ""); System.Console.Write(Test1((new S1(), 2))); System.Console.Write(""; ""); System.Console.Write(Test1((new S1(), 3))); System.Console.Write(""; ""); System.Console.Write(Test1((new S1(), 1))); System.Console.Write(""; ""); System.Console.Write(Test1((new S1(""a""), 1))); System.Console.Write(""; ""); System.Console.Write(Test1((new S1(""a""), 2))); } static bool Test1((S1, int) u) { return u is (null, 2) or (not int, 1); } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); var verifier = CompileAndVerify(comp, expectedOutput: "HasValue get_Value False; HasValue True; HasValue False; HasValue True; HasValue get_Value True; HasValue get_Value False").VerifyDiagnostics(); verifier.VerifyIL("S1.Test1", @" { // Code size 74 (0x4a) .maxstack 2 .locals init (S1 V_0, int V_1, bool V_2) IL_0000: ldarg.0 IL_0001: ldfld ""S1 System.ValueTuple<S1, int>.Item1"" IL_0006: stloc.0 IL_0007: ldloca.s V_0 IL_0009: constrained. ""S1"" IL_000f: callvirt ""bool S1.IUnionMembers.HasValue.get"" IL_0014: brtrue.s IL_0023 IL_0016: ldarg.0 IL_0017: ldfld ""int System.ValueTuple<S1, int>.Item2"" IL_001c: stloc.1 IL_001d: ldloc.1 IL_001e: ldc.i4.2 IL_001f: beq.s IL_0042 IL_0021: br.s IL_003e IL_0023: ldloca.s V_0 IL_0025: constrained. ""S1"" IL_002b: callvirt ""object S1.IUnionMembers.Value.get"" IL_0030: isinst ""int"" IL_0035: brtrue.s IL_0046 IL_0037: ldarg.0 IL_0038: ldfld ""int System.ValueTuple<S1, int>.Item2"" IL_003d: stloc.1 IL_003e: ldloc.1 IL_003f: ldc.i4.1 IL_0040: bne.un.s IL_0046 IL_0042: ldc.i4.1 IL_0043: stloc.2 IL_0044: br.s IL_0048 IL_0046: ldc.i4.0 IL_0047: stloc.2 IL_0048: ldloc.2 IL_0049: ret } "); } [Fact] public void NonBoxingUnionMatching_MemberProvider_Misc_18() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 : S1.IUnionMembers { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } object IUnionMembers.Value { get { System.Console.Write(""get_Value ""); return _value; } } bool IUnionMembers.HasValue { get { System.Console.Write(""HasValue ""); return _value != null; } } public interface IUnionMembers { public static S1 Create(int x) => new S1(x); public static S1 Create(string x) => new S1(x); public object Value { get; } public bool HasValue { get; } } static void Main() { System.Console.Write(Test1((new S1(1), 1))); System.Console.Write(""; ""); System.Console.Write(Test1((new S1(), 2))); System.Console.Write(""; ""); System.Console.Write(Test1((new S1(), 3))); System.Console.Write(""; ""); System.Console.Write(Test1((new S1(), 1))); System.Console.Write(""; ""); System.Console.Write(Test1((new S1(""a""), 1))); System.Console.Write(""; ""); System.Console.Write(Test1((new S1(""a""), 2))); } static bool Test1((S1, int) u) { return u is (not int, 1) or (null, 2); } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); var verifier = CompileAndVerify(comp, expectedOutput: "get_Value False; get_Value HasValue True; get_Value HasValue False; get_Value True; get_Value True; get_Value HasValue False").VerifyDiagnostics(); verifier.VerifyIL("S1.Test1", @" { // Code size 65 (0x41) .maxstack 2 .locals init (S1 V_0, int V_1, bool V_2) IL_0000: ldarg.0 IL_0001: ldfld ""S1 System.ValueTuple<S1, int>.Item1"" IL_0006: stloc.0 IL_0007: ldloca.s V_0 IL_0009: constrained. ""S1"" IL_000f: callvirt ""object S1.IUnionMembers.Value.get"" IL_0014: isinst ""int"" IL_0019: brtrue.s IL_003d IL_001b: ldarg.0 IL_001c: ldfld ""int System.ValueTuple<S1, int>.Item2"" IL_0021: stloc.1 IL_0022: ldloc.1 IL_0023: ldc.i4.1 IL_0024: beq.s IL_0039 IL_0026: ldloca.s V_0 IL_0028: constrained. ""S1"" IL_002e: callvirt ""bool S1.IUnionMembers.HasValue.get"" IL_0033: brtrue.s IL_003d IL_0035: ldloc.1 IL_0036: ldc.i4.2 IL_0037: bne.un.s IL_003d IL_0039: ldc.i4.1 IL_003a: stloc.2 IL_003b: br.s IL_003f IL_003d: ldc.i4.0 IL_003e: stloc.2 IL_003f: ldloc.2 IL_0040: ret } "); } [Fact] public void NonBoxingUnionMatching_MemberProvider_Misc_19() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 : S1.IUnionMembers { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } object IUnionMembers.Value { get { System.Console.Write(""get_Value ""); return _value; } } bool IUnionMembers.HasValue { get { System.Console.Write(""HasValue ""); return _value != null; } } bool IUnionMembers.TryGetValue(out int x) { System.Console.Write(""TryGetValue(int) ""); if (_value is int v) { x = v; return true; } x = 0; return false; } bool IUnionMembers.TryGetValue(out string x) { System.Console.Write(""TryGetValue(string) ""); x = _value as string; return x != null; } public interface IUnionMembers { public static S1 Create(int x) => new S1(x); public static S1 Create(string x) => new S1(x); public object Value { get; } public bool HasValue { get; } public bool TryGetValue(out int x); public bool TryGetValue(out string x); } static void Main() { System.Console.Write(Test1((new S1(1), 1))); System.Console.Write(""; ""); System.Console.Write(Test1((new S1(1), 2))); System.Console.Write(""; ""); System.Console.Write(Test1((new S1(1), 3))); System.Console.Write(""; ""); System.Console.Write(Test1((new S1(), 1))); System.Console.Write(""; ""); System.Console.Write(Test1((new S1(), 2))); System.Console.Write(""; ""); System.Console.Write(Test1((new S1(), 3))); System.Console.Write(""; ""); System.Console.Write(Test1((new S1(""a""), 1))); System.Console.Write(""; ""); System.Console.Write(Test1((new S1(""a""), 2))); System.Console.Write(""; ""); System.Console.Write(Test1((new S1(""a""), 3))); } static bool Test1((S1, int) u) { return u is (string, 2) or (int, 1); } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); var verifier = CompileAndVerify(comp, expectedOutput: "TryGetValue(string) TryGetValue(int) True; TryGetValue(string) TryGetValue(int) False; TryGetValue(string) TryGetValue(int) False; TryGetValue(string) TryGetValue(int) False; TryGetValue(string) TryGetValue(int) False; TryGetValue(string) TryGetValue(int) False; TryGetValue(string) False; TryGetValue(string) True; TryGetValue(string) False").VerifyDiagnostics(); verifier.VerifyIL("S1.Test1", @" { // Code size 69 (0x45) .maxstack 2 .locals init (S1 V_0, string V_1, int V_2, bool V_3) IL_0000: ldarg.0 IL_0001: ldfld ""S1 System.ValueTuple<S1, int>.Item1"" IL_0006: stloc.0 IL_0007: ldloca.s V_0 IL_0009: ldloca.s V_1 IL_000b: constrained. ""S1"" IL_0011: callvirt ""bool S1.IUnionMembers.TryGetValue(out string)"" IL_0016: brfalse.s IL_0023 IL_0018: ldarg.0 IL_0019: ldfld ""int System.ValueTuple<S1, int>.Item2"" IL_001e: ldc.i4.2 IL_001f: beq.s IL_003d IL_0021: br.s IL_0041 IL_0023: ldloca.s V_0 IL_0025: ldloca.s V_2 IL_0027: constrained. ""S1"" IL_002d: callvirt ""bool S1.IUnionMembers.TryGetValue(out int)"" IL_0032: brfalse.s IL_0041 IL_0034: ldarg.0 IL_0035: ldfld ""int System.ValueTuple<S1, int>.Item2"" IL_003a: ldc.i4.1 IL_003b: bne.un.s IL_0041 IL_003d: ldc.i4.1 IL_003e: stloc.3 IL_003f: br.s IL_0043 IL_0041: ldc.i4.0 IL_0042: stloc.3 IL_0043: ldloc.3 IL_0044: ret } "); } [Fact] public void NonBoxingUnionMatching_MemberProvider_Misc_20() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 : S1.IUnionMembers { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } object IUnionMembers.Value { get { System.Console.Write(""get_Value ""); return _value; } } bool IUnionMembers.HasValue { get { System.Console.Write(""HasValue ""); return _value != null; } } bool IUnionMembers.TryGetValue(out string x) { System.Console.Write(""TryGetValue(string) ""); x = _value as string; return x != null; } public interface IUnionMembers { public static S1 Create(int x) => new S1(x); public static S1 Create(string x) => new S1(x); public object Value { get; } public bool HasValue { get; } public bool TryGetValue(out string x); } static void Main() { System.Console.Write(Test1((new S1(1), 1))); System.Console.Write(""; ""); System.Console.Write(Test1((new S1(1), 2))); System.Console.Write(""; ""); System.Console.Write(Test1((new S1(1), 3))); System.Console.Write(""; ""); System.Console.Write(Test1((new S1(), 1))); System.Console.Write(""; ""); System.Console.Write(Test1((new S1(), 2))); System.Console.Write(""; ""); System.Console.Write(Test1((new S1(), 3))); System.Console.Write(""; ""); System.Console.Write(Test1((new S1(""a""), 1))); System.Console.Write(""; ""); System.Console.Write(Test1((new S1(""a""), 2))); System.Console.Write(""; ""); System.Console.Write(Test1((new S1(""a""), 3))); } static bool Test1((S1, int) u) { return u is (string, 2) or (int, 1); } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); var verifier = CompileAndVerify(comp, expectedOutput: "TryGetValue(string) get_Value True; TryGetValue(string) get_Value False; TryGetValue(string) get_Value False; TryGetValue(string) get_Value False; TryGetValue(string) get_Value False; TryGetValue(string) get_Value False; TryGetValue(string) False; TryGetValue(string) True; TryGetValue(string) False").VerifyDiagnostics(); verifier.VerifyIL("S1.Test1", @" { // Code size 72 (0x48) .maxstack 2 .locals init (S1 V_0, string V_1, bool V_2) IL_0000: ldarg.0 IL_0001: ldfld ""S1 System.ValueTuple<S1, int>.Item1"" IL_0006: stloc.0 IL_0007: ldloca.s V_0 IL_0009: ldloca.s V_1 IL_000b: constrained. ""S1"" IL_0011: callvirt ""bool S1.IUnionMembers.TryGetValue(out string)"" IL_0016: brfalse.s IL_0023 IL_0018: ldarg.0 IL_0019: ldfld ""int System.ValueTuple<S1, int>.Item2"" IL_001e: ldc.i4.2 IL_001f: beq.s IL_0040 IL_0021: br.s IL_0044 IL_0023: ldloca.s V_0 IL_0025: constrained. ""S1"" IL_002b: callvirt ""object S1.IUnionMembers.Value.get"" IL_0030: isinst ""int"" IL_0035: brfalse.s IL_0044 IL_0037: ldarg.0 IL_0038: ldfld ""int System.ValueTuple<S1, int>.Item2"" IL_003d: ldc.i4.1 IL_003e: bne.un.s IL_0044 IL_0040: ldc.i4.1 IL_0041: stloc.2 IL_0042: br.s IL_0046 IL_0044: ldc.i4.0 IL_0045: stloc.2 IL_0046: ldloc.2 IL_0047: ret } "); } [Fact] public void NonBoxingUnionMatching_MemberProvider_Misc_21() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 : S1.IUnionMembers { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } object IUnionMembers.Value { get { System.Console.Write(""get_Value ""); return _value; } } bool IUnionMembers.HasValue { get { System.Console.Write(""HasValue ""); return _value != null; } } bool IUnionMembers.TryGetValue(out int x) { System.Console.Write(""TryGetValue(int) ""); if (_value is int v) { x = v; return true; } x = 0; return false; } public interface IUnionMembers { public static S1 Create(int x) => new S1(x); public static S1 Create(string x) => new S1(x); public object Value { get; } public bool HasValue { get; } public bool TryGetValue(out int x); } static void Main() { System.Console.Write(Test1((new S1(1), 1))); System.Console.Write(""; ""); System.Console.Write(Test1((new S1(1), 2))); System.Console.Write(""; ""); System.Console.Write(Test1((new S1(1), 3))); System.Console.Write(""; ""); System.Console.Write(Test1((new S1(), 1))); System.Console.Write(""; ""); System.Console.Write(Test1((new S1(), 2))); System.Console.Write(""; ""); System.Console.Write(Test1((new S1(), 3))); System.Console.Write(""; ""); System.Console.Write(Test1((new S1(""a""), 1))); System.Console.Write(""; ""); System.Console.Write(Test1((new S1(""a""), 2))); System.Console.Write(""; ""); System.Console.Write(Test1((new S1(""a""), 3))); } static bool Test1((S1, int) u) { return u is (string, 2) or (int, 1); } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); var verifier = CompileAndVerify(comp, expectedOutput: "get_Value TryGetValue(int) True; get_Value TryGetValue(int) False; get_Value TryGetValue(int) False; get_Value TryGetValue(int) False; get_Value TryGetValue(int) False; get_Value TryGetValue(int) False; get_Value False; get_Value True; get_Value False").VerifyDiagnostics(); verifier.VerifyIL("S1.Test1", @" { // Code size 72 (0x48) .maxstack 2 .locals init (S1 V_0, int V_1, bool V_2) IL_0000: ldarg.0 IL_0001: ldfld ""S1 System.ValueTuple<S1, int>.Item1"" IL_0006: stloc.0 IL_0007: ldloca.s V_0 IL_0009: constrained. ""S1"" IL_000f: callvirt ""object S1.IUnionMembers.Value.get"" IL_0014: isinst ""string"" IL_0019: brfalse.s IL_0026 IL_001b: ldarg.0 IL_001c: ldfld ""int System.ValueTuple<S1, int>.Item2"" IL_0021: ldc.i4.2 IL_0022: beq.s IL_0040 IL_0024: br.s IL_0044 IL_0026: ldloca.s V_0 IL_0028: ldloca.s V_1 IL_002a: constrained. ""S1"" IL_0030: callvirt ""bool S1.IUnionMembers.TryGetValue(out int)"" IL_0035: brfalse.s IL_0044 IL_0037: ldarg.0 IL_0038: ldfld ""int System.ValueTuple<S1, int>.Item2"" IL_003d: ldc.i4.1 IL_003e: bne.un.s IL_0044 IL_0040: ldc.i4.1 IL_0041: stloc.2 IL_0042: br.s IL_0046 IL_0044: ldc.i4.0 IL_0045: stloc.2 IL_0046: ldloc.2 IL_0047: ret } "); } [Fact] public void NonBoxingUnionMatching_MemberProvider_Misc_22() { var src = @" interface I1; class C11; class C12; class C13 : C12, I1; class C14 : I1; class C15 : I1; [System.Runtime.CompilerServices.Union] struct S1 : S1.IUnionMembers { private readonly object _value; public S1(I1 x) { _value = x; } public S1(C11 x) { _value = x; } public S1(C12 x) { _value = x; } public S1(C14 x) { _value = x; } object IUnionMembers.Value { get { System.Console.Write(""get_Value ""); return _value; } } bool IUnionMembers.HasValue { get { System.Console.Write(""HasValue ""); return _value != null; } } bool IUnionMembers.TryGetValue(out I1 x) { System.Console.Write(""TryGetValue(I1) ""); x = _value as I1; return x != null; } bool IUnionMembers.TryGetValue(out C12 x) { System.Console.Write(""TryGetValue(C12) ""); x = _value as C12; return x != null; } public interface IUnionMembers { public static S1 Create(I1 x) => new S1(x); public static S1 Create(C11 x) => new S1(x); public static S1 Create(C12 x) => new S1(x); public static S1 Create(C14 x) => new S1(x); public object Value { get; } public bool HasValue { get; } public bool TryGetValue(out I1 x); public bool TryGetValue(out C12 x); } static void Main() { S1[] s = [new S1(), new S1(new C11()), new S1(new C12()), new S1((C12)new C13()), new S1(new C14()), new S1(new C15())]; int[] i = [1, 2, 3]; foreach (var s1 in s) { foreach (var j in i) { var t = Test1((s1, j)); System.Console.WriteLine(); System.Console.WriteLine(t); } } } static bool Test1((S1, int) u) { return u is (C12 and I1, 2) or (I1, 1); } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); VerifyDecisionDagDump<IsPatternExpressionSyntax>(comp, @"[0]: t1 = t0.Item1; [1] [1]: TryGetValue(C12): (Item1, ReturnItem) t2 = t1; [2] [2]: t2.ReturnItem == True ? [3] : [7] [3]: t3 = (C12)t2.Item1; [4] [4]: t3 is I1 ? [5] : [12] [5]: t4 = t0.Item2; [6] [6]: t4 == 2 ? [11] : [10] [7]: TryGetValue(I1): (Item1, ReturnItem) t5 = t1; [8] [8]: t5.ReturnItem == True ? [9] : [12] [9]: t4 = t0.Item2; [10] [10]: t4 == 1 ? [11] : [12] [11]: leaf <isPatternSuccess> `(C12 and I1, 2) or (I1, 1)` [12]: leaf <isPatternFailure> `u is (C12 and I1, 2) or (I1, 1)` ", forLowering: true); var verifier = CompileAndVerify( comp, expectedOutput: @" TryGetValue(C12) TryGetValue(I1) False TryGetValue(C12) TryGetValue(I1) False TryGetValue(C12) TryGetValue(I1) False TryGetValue(C12) TryGetValue(I1) False TryGetValue(C12) TryGetValue(I1) False TryGetValue(C12) TryGetValue(I1) False TryGetValue(C12) False TryGetValue(C12) False TryGetValue(C12) False TryGetValue(C12) True TryGetValue(C12) True TryGetValue(C12) False TryGetValue(C12) TryGetValue(I1) True TryGetValue(C12) TryGetValue(I1) False TryGetValue(C12) TryGetValue(I1) False TryGetValue(C12) TryGetValue(I1) True TryGetValue(C12) TryGetValue(I1) False TryGetValue(C12) TryGetValue(I1) False ").VerifyDiagnostics(); verifier.VerifyIL("S1.Test1", @" { // Code size 84 (0x54) .maxstack 2 .locals init (S1 V_0, C12 V_1, int V_2, I1 V_3, bool V_4) IL_0000: ldarg.0 IL_0001: ldfld ""S1 System.ValueTuple<S1, int>.Item1"" IL_0006: stloc.0 IL_0007: ldloca.s V_0 IL_0009: ldloca.s V_1 IL_000b: constrained. ""S1"" IL_0011: callvirt ""bool S1.IUnionMembers.TryGetValue(out C12)"" IL_0016: brfalse.s IL_002d IL_0018: ldloc.1 IL_0019: isinst ""I1"" IL_001e: brfalse.s IL_004e IL_0020: ldarg.0 IL_0021: ldfld ""int System.ValueTuple<S1, int>.Item2"" IL_0026: stloc.2 IL_0027: ldloc.2 IL_0028: ldc.i4.2 IL_0029: beq.s IL_0049 IL_002b: br.s IL_0045 IL_002d: ldloca.s V_0 IL_002f: ldloca.s V_3 IL_0031: constrained. ""S1"" IL_0037: callvirt ""bool S1.IUnionMembers.TryGetValue(out I1)"" IL_003c: brfalse.s IL_004e IL_003e: ldarg.0 IL_003f: ldfld ""int System.ValueTuple<S1, int>.Item2"" IL_0044: stloc.2 IL_0045: ldloc.2 IL_0046: ldc.i4.1 IL_0047: bne.un.s IL_004e IL_0049: ldc.i4.1 IL_004a: stloc.s V_4 IL_004c: br.s IL_0051 IL_004e: ldc.i4.0 IL_004f: stloc.s V_4 IL_0051: ldloc.s V_4 IL_0053: ret } "); } [Fact] public void NonBoxingUnionMatching_MemberProvider_Misc_23() { var src = @" interface I1; class C11; class C12; class C13 : C12, I1; class C14 : I1; class C15 : I1; [System.Runtime.CompilerServices.Union] struct S1 : S1.IUnionMembers { private readonly object _value; public S1(I1 x) { _value = x; } public S1(C11 x) { _value = x; } public S1(C12 x) { _value = x; } public S1(C14 x) { _value = x; } object IUnionMembers.Value { get { System.Console.Write(""get_Value ""); return _value; } } bool IUnionMembers.HasValue { get { System.Console.Write(""HasValue ""); return _value != null; } } bool IUnionMembers.TryGetValue(out I1 x) { System.Console.Write(""TryGetValue(I1) ""); x = _value as I1; return x != null; } bool IUnionMembers.TryGetValue(out C12 x) { System.Console.Write(""TryGetValue(C12) ""); x = _value as C12; return x != null; } public interface IUnionMembers { public static S1 Create(I1 x) => new S1(x); public static S1 Create(C11 x) => new S1(x); public static S1 Create(C12 x) => new S1(x); public static S1 Create(C14 x) => new S1(x); public object Value { get; } public bool HasValue { get; } public bool TryGetValue(out I1 x); public bool TryGetValue(out C12 x); } static void Main() { S1[] s = [new S1(), new S1(new C11()), new S1(new C12()), new S1((C12)new C13()), new S1(new C14()), new S1(new C15())]; int[] i = [1, 2, 3]; foreach (var s1 in s) { foreach (var j in i) { var t = Test1((s1, j)); System.Console.WriteLine(); System.Console.WriteLine(t); } } } static bool Test1((S1, int) u) { return u is (I1, 1) or (C12 and I1, 2); } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); VerifyDecisionDagDump<IsPatternExpressionSyntax>(comp, @"[0]: t1 = t0.Item1; [1] [1]: TryGetValue(I1): (Item1, ReturnItem) t2 = t1; [2] [2]: t2.ReturnItem == True ? [3] : [9] [3]: t3 = t0.Item2; [4] [4]: t3 == 1 ? [8] : [5] [5]: TryGetValue(C12): (Item1, ReturnItem) t4 = t1; [6] [6]: t4.ReturnItem == True ? [7] : [9] [7]: t3 == 2 ? [8] : [9] [8]: leaf <isPatternSuccess> `(I1, 1) or (C12 and I1, 2)` [9]: leaf <isPatternFailure> `u is (I1, 1) or (C12 and I1, 2)` ", forLowering: true); var verifier = CompileAndVerify( comp, expectedOutput: @" TryGetValue(I1) False TryGetValue(I1) False TryGetValue(I1) False TryGetValue(I1) False TryGetValue(I1) False TryGetValue(I1) False TryGetValue(I1) False TryGetValue(I1) False TryGetValue(I1) False TryGetValue(I1) True TryGetValue(I1) TryGetValue(C12) True TryGetValue(I1) TryGetValue(C12) False TryGetValue(I1) True TryGetValue(I1) TryGetValue(C12) False TryGetValue(I1) TryGetValue(C12) False TryGetValue(I1) True TryGetValue(I1) TryGetValue(C12) False TryGetValue(I1) TryGetValue(C12) False ").VerifyDiagnostics(); verifier.VerifyIL("S1.Test1", @" { // Code size 67 (0x43) .maxstack 2 .locals init (S1 V_0, I1 V_1, int V_2, C12 V_3, bool V_4) IL_0000: ldarg.0 IL_0001: ldfld ""S1 System.ValueTuple<S1, int>.Item1"" IL_0006: stloc.0 IL_0007: ldloca.s V_0 IL_0009: ldloca.s V_1 IL_000b: constrained. ""S1"" IL_0011: callvirt ""bool S1.IUnionMembers.TryGetValue(out I1)"" IL_0016: brfalse.s IL_003d IL_0018: ldarg.0 IL_0019: ldfld ""int System.ValueTuple<S1, int>.Item2"" IL_001e: stloc.2 IL_001f: ldloc.2 IL_0020: ldc.i4.1 IL_0021: beq.s IL_0038 IL_0023: ldloca.s V_0 IL_0025: ldloca.s V_3 IL_0027: constrained. ""S1"" IL_002d: callvirt ""bool S1.IUnionMembers.TryGetValue(out C12)"" IL_0032: brfalse.s IL_003d IL_0034: ldloc.2 IL_0035: ldc.i4.2 IL_0036: bne.un.s IL_003d IL_0038: ldc.i4.1 IL_0039: stloc.s V_4 IL_003b: br.s IL_0040 IL_003d: ldc.i4.0 IL_003e: stloc.s V_4 IL_0040: ldloc.s V_4 IL_0042: ret } "); } [Fact] public void NonBoxingUnionMatching_MemberProvider_Misc_24() { var src = @" interface I1; class C11; class C12; class C13 : C12, I1; class C14 : I1; class C15 : I1; [System.Runtime.CompilerServices.Union] struct S1 : S1.IUnionMembers { private readonly object _value; public S1(I1 x) { _value = x; } public S1(C11 x) { _value = x; } public S1(C12 x) { _value = x; } public S1(C14 x) { _value = x; } object IUnionMembers.Value { get { System.Console.Write(""get_Value ""); return _value; } } bool IUnionMembers.HasValue { get { System.Console.Write(""HasValue ""); return _value != null; } } bool IUnionMembers.TryGetValue(out I1 x) { System.Console.Write(""TryGetValue(I1) ""); x = _value as I1; return x != null; } public interface IUnionMembers { public static S1 Create(I1 x) => new S1(x); public static S1 Create(C11 x) => new S1(x); public static S1 Create(C12 x) => new S1(x); public static S1 Create(C14 x) => new S1(x); public object Value { get; } public bool HasValue { get; } public bool TryGetValue(out I1 x); } static void Main() { S1[] s = [new S1(), new S1(new C11()), new S1(new C12()), new S1((C12)new C13()), new S1(new C14()), new S1(new C15())]; int[] i = [1, 2, 3]; foreach (var s1 in s) { foreach (var j in i) { var t = Test1((s1, j)); System.Console.WriteLine(); System.Console.WriteLine(t); } } } static bool Test1((S1, int) u) { return u is (C12 and I1, 2) or (I1, 1); } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); VerifyDecisionDagDump<IsPatternExpressionSyntax>(comp, @"[0]: t1 = t0.Item1; [1] [1]: t2 = t1.Value; [2] [2]: t2 is C12 ? [3] : [7] [3]: t3 = (C12)t2; [4] [4]: t3 is I1 ? [5] : [12] [5]: t4 = t0.Item2; [6] [6]: t4 == 2 ? [11] : [10] [7]: TryGetValue(I1): (Item1, ReturnItem) t5 = t1; [8] [8]: t5.ReturnItem == True ? [9] : [12] [9]: t4 = t0.Item2; [10] [10]: t4 == 1 ? [11] : [12] [11]: leaf <isPatternSuccess> `(C12 and I1, 2) or (I1, 1)` [12]: leaf <isPatternFailure> `u is (C12 and I1, 2) or (I1, 1)` ", forLowering: true); var verifier = CompileAndVerify( comp, expectedOutput: @" get_Value TryGetValue(I1) False get_Value TryGetValue(I1) False get_Value TryGetValue(I1) False get_Value TryGetValue(I1) False get_Value TryGetValue(I1) False get_Value TryGetValue(I1) False get_Value False get_Value False get_Value False get_Value True get_Value True get_Value False get_Value TryGetValue(I1) True get_Value TryGetValue(I1) False get_Value TryGetValue(I1) False get_Value TryGetValue(I1) True get_Value TryGetValue(I1) False get_Value TryGetValue(I1) False ").VerifyDiagnostics(); verifier.VerifyIL("S1.Test1", @" { // Code size 89 (0x59) .maxstack 2 .locals init (S1 V_0, C12 V_1, int V_2, I1 V_3, bool V_4) IL_0000: ldarg.0 IL_0001: ldfld ""S1 System.ValueTuple<S1, int>.Item1"" IL_0006: stloc.0 IL_0007: ldloca.s V_0 IL_0009: constrained. ""S1"" IL_000f: callvirt ""object S1.IUnionMembers.Value.get"" IL_0014: isinst ""C12"" IL_0019: stloc.1 IL_001a: ldloc.1 IL_001b: brfalse.s IL_0032 IL_001d: ldloc.1 IL_001e: isinst ""I1"" IL_0023: brfalse.s IL_0053 IL_0025: ldarg.0 IL_0026: ldfld ""int System.ValueTuple<S1, int>.Item2"" IL_002b: stloc.2 IL_002c: ldloc.2 IL_002d: ldc.i4.2 IL_002e: beq.s IL_004e IL_0030: br.s IL_004a IL_0032: ldloca.s V_0 IL_0034: ldloca.s V_3 IL_0036: constrained. ""S1"" IL_003c: callvirt ""bool S1.IUnionMembers.TryGetValue(out I1)"" IL_0041: brfalse.s IL_0053 IL_0043: ldarg.0 IL_0044: ldfld ""int System.ValueTuple<S1, int>.Item2"" IL_0049: stloc.2 IL_004a: ldloc.2 IL_004b: ldc.i4.1 IL_004c: bne.un.s IL_0053 IL_004e: ldc.i4.1 IL_004f: stloc.s V_4 IL_0051: br.s IL_0056 IL_0053: ldc.i4.0 IL_0054: stloc.s V_4 IL_0056: ldloc.s V_4 IL_0058: ret } "); } [Fact] public void NonBoxingUnionMatching_MemberProvider_Misc_25() { var src = @" interface I1; class C11; class C12; class C13 : C12, I1; class C14 : I1; class C15 : I1; [System.Runtime.CompilerServices.Union] struct S1 : S1.IUnionMembers { private readonly object _value; public S1(I1 x) { _value = x; } public S1(C11 x) { _value = x; } public S1(C12 x) { _value = x; } public S1(C14 x) { _value = x; } object IUnionMembers.Value { get { System.Console.Write(""get_Value ""); return _value; } } bool IUnionMembers.HasValue { get { System.Console.Write(""HasValue ""); return _value != null; } } bool IUnionMembers.TryGetValue(out I1 x) { System.Console.Write(""TryGetValue(I1) ""); x = _value as I1; return x != null; } public interface IUnionMembers { public static S1 Create(I1 x) => new S1(x); public static S1 Create(C11 x) => new S1(x); public static S1 Create(C12 x) => new S1(x); public static S1 Create(C14 x) => new S1(x); public object Value { get; } public bool HasValue { get; } public bool TryGetValue(out I1 x); } static void Main() { S1[] s = [new S1(), new S1(new C11()), new S1(new C12()), new S1((C12)new C13()), new S1(new C14()), new S1(new C15())]; int[] i = [1, 2, 3]; foreach (var s1 in s) { foreach (var j in i) { var t = Test1((s1, j)); System.Console.WriteLine(); System.Console.WriteLine(t); } } } static bool Test1((S1, int) u) { return u is (I1, 1) or (C12 and I1, 2); } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); var verifier = CompileAndVerify( comp, expectedOutput: @" TryGetValue(I1) False TryGetValue(I1) False TryGetValue(I1) False TryGetValue(I1) False TryGetValue(I1) False TryGetValue(I1) False TryGetValue(I1) False TryGetValue(I1) False TryGetValue(I1) False TryGetValue(I1) True TryGetValue(I1) get_Value True TryGetValue(I1) get_Value False TryGetValue(I1) True TryGetValue(I1) get_Value False TryGetValue(I1) get_Value False TryGetValue(I1) True TryGetValue(I1) get_Value False TryGetValue(I1) get_Value False ").VerifyDiagnostics(); verifier.VerifyIL("S1.Test1", @" { // Code size 67 (0x43) .maxstack 2 .locals init (S1 V_0, I1 V_1, int V_2, bool V_3) IL_0000: ldarg.0 IL_0001: ldfld ""S1 System.ValueTuple<S1, int>.Item1"" IL_0006: stloc.0 IL_0007: ldloca.s V_0 IL_0009: ldloca.s V_1 IL_000b: constrained. ""S1"" IL_0011: callvirt ""bool S1.IUnionMembers.TryGetValue(out I1)"" IL_0016: brfalse.s IL_003f IL_0018: ldarg.0 IL_0019: ldfld ""int System.ValueTuple<S1, int>.Item2"" IL_001e: stloc.2 IL_001f: ldloc.2 IL_0020: ldc.i4.1 IL_0021: beq.s IL_003b IL_0023: ldloca.s V_0 IL_0025: constrained. ""S1"" IL_002b: callvirt ""object S1.IUnionMembers.Value.get"" IL_0030: isinst ""C12"" IL_0035: brfalse.s IL_003f IL_0037: ldloc.2 IL_0038: ldc.i4.2 IL_0039: bne.un.s IL_003f IL_003b: ldc.i4.1 IL_003c: stloc.3 IL_003d: br.s IL_0041 IL_003f: ldc.i4.0 IL_0040: stloc.3 IL_0041: ldloc.3 IL_0042: ret } "); } [Fact] public void NonBoxingUnionMatching_MemberProvider_Misc_26() { var src = @" interface I1; class C11; class C12; class C13 : C12, I1; class C14 : I1; class C15 : I1; [System.Runtime.CompilerServices.Union] struct S1 : S1.IUnionMembers { private readonly object _value; public S1(I1 x) { _value = x; } public S1(C11 x) { _value = x; } public S1(C12 x) { _value = x; } public S1(C14 x) { _value = x; } object IUnionMembers.Value { get { System.Console.Write(""get_Value ""); return _value; } } bool IUnionMembers.HasValue { get { System.Console.Write(""HasValue ""); return _value != null; } } bool IUnionMembers.TryGetValue(out C12 x) { System.Console.Write(""TryGetValue(C12) ""); x = _value as C12; return x != null; } public interface IUnionMembers { public static S1 Create(I1 x) => new S1(x); public static S1 Create(C11 x) => new S1(x); public static S1 Create(C12 x) => new S1(x); public static S1 Create(C14 x) => new S1(x); public object Value { get; } public bool HasValue { get; } public bool TryGetValue(out C12 x); } static void Main() { S1[] s = [new S1(), new S1(new C11()), new S1(new C12()), new S1((C12)new C13()), new S1(new C14()), new S1(new C15())]; int[] i = [1, 2, 3]; foreach (var s1 in s) { foreach (var j in i) { var t = Test1((s1, j)); System.Console.WriteLine(); System.Console.WriteLine(t); } } } static bool Test1((S1, int) u) { return u is (C12 and I1, 2) or (I1, 1); } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); VerifyDecisionDagDump<IsPatternExpressionSyntax>(comp, @"[0]: t1 = t0.Item1; [1] [1]: TryGetValue(C12): (Item1, ReturnItem) t2 = t1; [2] [2]: t2.ReturnItem == True ? [3] : [7] [3]: t3 = (C12)t2.Item1; [4] [4]: t3 is I1 ? [5] : [12] [5]: t4 = t0.Item2; [6] [6]: t4 == 2 ? [11] : [10] [7]: t5 = t1.Value; [8] [8]: t5 is I1 ? [9] : [12] [9]: t4 = t0.Item2; [10] [10]: t4 == 1 ? [11] : [12] [11]: leaf <isPatternSuccess> `(C12 and I1, 2) or (I1, 1)` [12]: leaf <isPatternFailure> `u is (C12 and I1, 2) or (I1, 1)` ", forLowering: true); var verifier = CompileAndVerify( comp, expectedOutput: @" TryGetValue(C12) get_Value False TryGetValue(C12) get_Value False TryGetValue(C12) get_Value False TryGetValue(C12) get_Value False TryGetValue(C12) get_Value False TryGetValue(C12) get_Value False TryGetValue(C12) False TryGetValue(C12) False TryGetValue(C12) False TryGetValue(C12) True TryGetValue(C12) True TryGetValue(C12) False TryGetValue(C12) get_Value True TryGetValue(C12) get_Value False TryGetValue(C12) get_Value False TryGetValue(C12) get_Value True TryGetValue(C12) get_Value False TryGetValue(C12) get_Value False ").VerifyDiagnostics(); verifier.VerifyIL("S1.Test1", @" { // Code size 84 (0x54) .maxstack 2 .locals init (S1 V_0, C12 V_1, int V_2, bool V_3) IL_0000: ldarg.0 IL_0001: ldfld ""S1 System.ValueTuple<S1, int>.Item1"" IL_0006: stloc.0 IL_0007: ldloca.s V_0 IL_0009: ldloca.s V_1 IL_000b: constrained. ""S1"" IL_0011: callvirt ""bool S1.IUnionMembers.TryGetValue(out C12)"" IL_0016: brfalse.s IL_002d IL_0018: ldloc.1 IL_0019: isinst ""I1"" IL_001e: brfalse.s IL_0050 IL_0020: ldarg.0 IL_0021: ldfld ""int System.ValueTuple<S1, int>.Item2"" IL_0026: stloc.2 IL_0027: ldloc.2 IL_0028: ldc.i4.2 IL_0029: beq.s IL_004c IL_002b: br.s IL_0048 IL_002d: ldloca.s V_0 IL_002f: constrained. ""S1"" IL_0035: callvirt ""object S1.IUnionMembers.Value.get"" IL_003a: isinst ""I1"" IL_003f: brfalse.s IL_0050 IL_0041: ldarg.0 IL_0042: ldfld ""int System.ValueTuple<S1, int>.Item2"" IL_0047: stloc.2 IL_0048: ldloc.2 IL_0049: ldc.i4.1 IL_004a: bne.un.s IL_0050 IL_004c: ldc.i4.1 IL_004d: stloc.3 IL_004e: br.s IL_0052 IL_0050: ldc.i4.0 IL_0051: stloc.3 IL_0052: ldloc.3 IL_0053: ret } "); } [Fact] public void NonBoxingUnionMatching_MemberProvider_Misc_27() { var src = @" interface I1; class C11; class C12; class C13 : C12, I1; class C14 : I1; class C15 : I1; [System.Runtime.CompilerServices.Union] struct S1 : S1.IUnionMembers { private readonly object _value; public S1(I1 x) { _value = x; } public S1(C11 x) { _value = x; } public S1(C12 x) { _value = x; } public S1(C14 x) { _value = x; } object IUnionMembers.Value { get { System.Console.Write(""get_Value ""); return _value; } } bool IUnionMembers.HasValue { get { System.Console.Write(""HasValue ""); return _value != null; } } bool IUnionMembers.TryGetValue(out C12 x) { System.Console.Write(""TryGetValue(C12) ""); x = _value as C12; return x != null; } public interface IUnionMembers { public static S1 Create(I1 x) => new S1(x); public static S1 Create(C11 x) => new S1(x); public static S1 Create(C12 x) => new S1(x); public static S1 Create(C14 x) => new S1(x); public object Value { get; } public bool HasValue { get; } public bool TryGetValue(out C12 x); } static void Main() { S1[] s = [new S1(), new S1(new C11()), new S1(new C12()), new S1((C12)new C13()), new S1(new C14()), new S1(new C15())]; int[] i = [1, 2, 3]; foreach (var s1 in s) { foreach (var j in i) { var t = Test1((s1, j)); System.Console.WriteLine(); System.Console.WriteLine(t); } } } static bool Test1((S1, int) u) { return u is (I1, 1) or (C12 and I1, 2); } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); VerifyDecisionDagDump<IsPatternExpressionSyntax>(comp, @"[0]: t1 = t0.Item1; [1] [1]: t2 = t1.Value; [2] [2]: t2 is I1 ? [3] : [9] [3]: t3 = t0.Item2; [4] [4]: t3 == 1 ? [8] : [5] [5]: TryGetValue(C12): (Item1, ReturnItem) t4 = t1; [6] [6]: t4.ReturnItem == True ? [7] : [9] [7]: t3 == 2 ? [8] : [9] [8]: leaf <isPatternSuccess> `(I1, 1) or (C12 and I1, 2)` [9]: leaf <isPatternFailure> `u is (I1, 1) or (C12 and I1, 2)` ", forLowering: true); var verifier = CompileAndVerify( comp, expectedOutput: @" get_Value False get_Value False get_Value False get_Value False get_Value False get_Value False get_Value False get_Value False get_Value False get_Value True get_Value TryGetValue(C12) True get_Value TryGetValue(C12) False get_Value True get_Value TryGetValue(C12) False get_Value TryGetValue(C12) False get_Value True get_Value TryGetValue(C12) False get_Value TryGetValue(C12) False ").VerifyDiagnostics(); verifier.VerifyIL("S1.Test1", @" { // Code size 67 (0x43) .maxstack 2 .locals init (S1 V_0, int V_1, C12 V_2, bool V_3) IL_0000: ldarg.0 IL_0001: ldfld ""S1 System.ValueTuple<S1, int>.Item1"" IL_0006: stloc.0 IL_0007: ldloca.s V_0 IL_0009: constrained. ""S1"" IL_000f: callvirt ""object S1.IUnionMembers.Value.get"" IL_0014: isinst ""I1"" IL_0019: brfalse.s IL_003f IL_001b: ldarg.0 IL_001c: ldfld ""int System.ValueTuple<S1, int>.Item2"" IL_0021: stloc.1 IL_0022: ldloc.1 IL_0023: ldc.i4.1 IL_0024: beq.s IL_003b IL_0026: ldloca.s V_0 IL_0028: ldloca.s V_2 IL_002a: constrained. ""S1"" IL_0030: callvirt ""bool S1.IUnionMembers.TryGetValue(out C12)"" IL_0035: brfalse.s IL_003f IL_0037: ldloc.1 IL_0038: ldc.i4.2 IL_0039: bne.un.s IL_003f IL_003b: ldc.i4.1 IL_003c: stloc.3 IL_003d: br.s IL_0041 IL_003f: ldc.i4.0 IL_0040: stloc.3 IL_0041: ldloc.3 IL_0042: ret } "); } [Fact] public void NonBoxingUnionMatching_MemberProvider_Misc_28() { var src = @" interface I1 { int F {get;} } class C11; class C12; class C13(int f) : C12, I1 { public int F => f; } class C14(int f) : I1 { public int F => f; } class C15(int f) : I1 { public int F => f; } [System.Runtime.CompilerServices.Union] struct S1 : S1.IUnionMembers { private readonly object _value; public S1(I1 x) { _value = x; } public S1(C11 x) { _value = x; } public S1(C12 x) { _value = x; } public S1(C14 x) { _value = x; } object IUnionMembers.Value { get { System.Console.Write(""get_Value ""); return _value; } } bool IUnionMembers.HasValue { get { System.Console.Write(""HasValue ""); return _value != null; } } bool IUnionMembers.TryGetValue(out I1 x) { System.Console.Write(""TryGetValue(I1) ""); x = _value as I1; return x != null; } bool IUnionMembers.TryGetValue(out C12 x) { System.Console.Write(""TryGetValue(C12) ""); x = _value as C12; return x != null; } public interface IUnionMembers { public static S1 Create(I1 x) => new S1(x); public static S1 Create(C11 x) => new S1(x); public static S1 Create(C12 x) => new S1(x); public static S1 Create(C14 x) => new S1(x); public object Value { get; } public bool HasValue { get; } public bool TryGetValue(out I1 x); public bool TryGetValue(out C12 x); } static void Main() { S1[] s = [new S1(), new S1(new C11()), new S1(new C12()), new S1((C12)new C13(1)), new S1(new C14(1)), new S1(new C15(1)), new S1((C12)new C13(2)), new S1(new C14(2)), new S1(new C15(2))]; int[] i = [1, 2, 3]; foreach (var s1 in s) { foreach (var j in i) { var t = Test1((s1, j)); System.Console.WriteLine(); System.Console.WriteLine(t); } } } static bool Test1((S1, int) u) { return u is (C12 and I1 and { F: 1 }, 2) or (I1 and { F: 1 }, 1); } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); VerifyDecisionDagDump<IsPatternExpressionSyntax>(comp, @"[0]: t1 = t0.Item1; [1] [1]: TryGetValue(C12): (Item1, ReturnItem) t2 = t1; [2] [2]: t2.ReturnItem == True ? [3] : [10] [3]: t3 = (C12)t2.Item1; [4] [4]: t3 is I1 ? [5] : [18] [5]: t4 = (I1)t3; [6] [6]: t5 = t4.F; [7] [7]: t5 == 1 ? [8] : [18] [8]: t6 = t0.Item2; [9] [9]: t6 == 2 ? [17] : [16] [10]: TryGetValue(I1): (Item1, ReturnItem) t7 = t1; [11] [11]: t7.ReturnItem == True ? [12] : [18] [12]: t4 = (I1)t7.Item1; [13] [13]: t5 = t4.F; [14] [14]: t5 == 1 ? [15] : [18] [15]: t6 = t0.Item2; [16] [16]: t6 == 1 ? [17] : [18] [17]: leaf <isPatternSuccess> `(C12 and I1 and { F: 1 }, 2) or (I1 and { F: 1 }, 1)` [18]: leaf <isPatternFailure> `u is (C12 and I1 and { F: 1 }, 2) or (I1 and { F: 1 }, 1)` ", forLowering: true); var verifier = CompileAndVerify( comp, expectedOutput: @" TryGetValue(C12) TryGetValue(I1) False TryGetValue(C12) TryGetValue(I1) False TryGetValue(C12) TryGetValue(I1) False TryGetValue(C12) TryGetValue(I1) False TryGetValue(C12) TryGetValue(I1) False TryGetValue(C12) TryGetValue(I1) False TryGetValue(C12) False TryGetValue(C12) False TryGetValue(C12) False TryGetValue(C12) True TryGetValue(C12) True TryGetValue(C12) False TryGetValue(C12) TryGetValue(I1) True TryGetValue(C12) TryGetValue(I1) False TryGetValue(C12) TryGetValue(I1) False TryGetValue(C12) TryGetValue(I1) True TryGetValue(C12) TryGetValue(I1) False TryGetValue(C12) TryGetValue(I1) False TryGetValue(C12) False TryGetValue(C12) False TryGetValue(C12) False TryGetValue(C12) TryGetValue(I1) False TryGetValue(C12) TryGetValue(I1) False TryGetValue(C12) TryGetValue(I1) False TryGetValue(C12) TryGetValue(I1) False TryGetValue(C12) TryGetValue(I1) False TryGetValue(C12) TryGetValue(I1) False ").VerifyDiagnostics(); verifier.VerifyIL("S1.Test1", @" { // Code size 107 (0x6b) .maxstack 2 .locals init (S1 V_0, C12 V_1, I1 V_2, int V_3, I1 V_4, bool V_5) IL_0000: ldarg.0 IL_0001: ldfld ""S1 System.ValueTuple<S1, int>.Item1"" IL_0006: stloc.0 IL_0007: ldloca.s V_0 IL_0009: ldloca.s V_1 IL_000b: constrained. ""S1"" IL_0011: callvirt ""bool S1.IUnionMembers.TryGetValue(out C12)"" IL_0016: brfalse.s IL_0038 IL_0018: ldloc.1 IL_0019: isinst ""I1"" IL_001e: stloc.2 IL_001f: ldloc.2 IL_0020: brfalse.s IL_0065 IL_0022: ldloc.2 IL_0023: callvirt ""int I1.F.get"" IL_0028: ldc.i4.1 IL_0029: bne.un.s IL_0065 IL_002b: ldarg.0 IL_002c: ldfld ""int System.ValueTuple<S1, int>.Item2"" IL_0031: stloc.3 IL_0032: ldloc.3 IL_0033: ldc.i4.2 IL_0034: beq.s IL_0060 IL_0036: br.s IL_005c IL_0038: ldloca.s V_0 IL_003a: ldloca.s V_4 IL_003c: constrained. ""S1"" IL_0042: callvirt ""bool S1.IUnionMembers.TryGetValue(out I1)"" IL_0047: brfalse.s IL_0065 IL_0049: ldloc.s V_4 IL_004b: stloc.2 IL_004c: ldloc.2 IL_004d: callvirt ""int I1.F.get"" IL_0052: ldc.i4.1 IL_0053: bne.un.s IL_0065 IL_0055: ldarg.0 IL_0056: ldfld ""int System.ValueTuple<S1, int>.Item2"" IL_005b: stloc.3 IL_005c: ldloc.3 IL_005d: ldc.i4.1 IL_005e: bne.un.s IL_0065 IL_0060: ldc.i4.1 IL_0061: stloc.s V_5 IL_0063: br.s IL_0068 IL_0065: ldc.i4.0 IL_0066: stloc.s V_5 IL_0068: ldloc.s V_5 IL_006a: ret } "); } [Fact] public void NonBoxingUnionMatching_MemberProvider_Misc_29() { var src = @" using System; class C11; class C12 : IComparable { public int CompareTo(object obj) => throw null; } [System.Runtime.CompilerServices.Union] struct S1 : S1.IUnionMembers { private readonly object _value; public S1(C11 x) { _value = x; } public S1(int x) { _value = x; } public S1(string x) { _value = x; } public S1(IComparable x) { _value = x; } object IUnionMembers.Value { get { System.Console.Write(""get_Value ""); return _value; } } bool IUnionMembers.HasValue { get { System.Console.Write(""HasValue ""); return _value != null; } } bool IUnionMembers.TryGetValue(out int x) { System.Console.Write(""TryGetValue(int) ""); if (_value is int) { x = (int)_value; return true; } x = 0; return false; } bool IUnionMembers.TryGetValue(out IComparable x) { System.Console.Write(""TryGetValue(IComparable) ""); x = _value as IComparable; return x != null; } public interface IUnionMembers { public static S1 Create(C11 x) => new S1(x); public static S1 Create(int x) => new S1(x); public static S1 Create(string x) => new S1(x); public static S1 Create(IComparable x) => new S1(x); public object Value { get; } public bool HasValue { get; } public bool TryGetValue(out int x); public bool TryGetValue(out IComparable x); } static void Main() { S1[] s = [new S1(), new S1(new C11()), new S1(new C12()), new S1(1), new S1(""1""), new S1(2), new S1(""2""), new S1(3), new S1(""3"")]; int[] i = [1, 2, 3]; foreach (var s1 in s) { foreach (var j in i) { var t = Test1((s1, j)); System.Console.WriteLine(); System.Console.WriteLine(t); } } } static bool Test1((S1, int) u) { return u is (System.IComparable and int and 1, 2) or (int and (1 or 3), 1); } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); VerifyDecisionDagDump<IsPatternExpressionSyntax>(comp, @"[0]: t1 = t0.Item1; [1] [1]: TryGetValue(System.IComparable): (Item1, ReturnItem) t2 = t1; [2] [2]: t2.ReturnItem == True ? [3] : [13] [3]: t3 = (System.IComparable)t2.Item1; [4] [4]: t3 is int ? [5] : [13] [5]: t4 = (int)t3; [6] [6]: t4 == 1 ? [7] : [9] [7]: t5 = t0.Item2; [8] [8]: t5 == 2 ? [12] : [11] [9]: t4 == 3 ? [10] : [13] [10]: t5 = t0.Item2; [11] [11]: t5 == 1 ? [12] : [13] [12]: leaf <isPatternSuccess> `(System.IComparable and int and 1, 2) or (int and (1 or 3), 1)` [13]: leaf <isPatternFailure> `u is (System.IComparable and int and 1, 2) or (int and (1 or 3), 1)` ", forLowering: true); CompilationVerifier verifier = CompileAndVerify( comp, expectedOutput: @" TryGetValue(IComparable) False TryGetValue(IComparable) False TryGetValue(IComparable) False TryGetValue(IComparable) False TryGetValue(IComparable) False TryGetValue(IComparable) False TryGetValue(IComparable) False TryGetValue(IComparable) False TryGetValue(IComparable) False TryGetValue(IComparable) True TryGetValue(IComparable) True TryGetValue(IComparable) False TryGetValue(IComparable) False TryGetValue(IComparable) False TryGetValue(IComparable) False TryGetValue(IComparable) False TryGetValue(IComparable) False TryGetValue(IComparable) False TryGetValue(IComparable) False TryGetValue(IComparable) False TryGetValue(IComparable) False TryGetValue(IComparable) True TryGetValue(IComparable) False TryGetValue(IComparable) False TryGetValue(IComparable) False TryGetValue(IComparable) False TryGetValue(IComparable) False ").VerifyDiagnostics(); verifier.VerifyIL("S1.Test1", @" { // Code size 90 (0x5a) .maxstack 2 .locals init (S1 V_0, System.IComparable V_1, System.IComparable V_2, int V_3, int V_4, bool V_5) IL_0000: ldarg.0 IL_0001: ldfld ""S1 System.ValueTuple<S1, int>.Item1"" IL_0006: stloc.0 IL_0007: ldloca.s V_0 IL_0009: ldloca.s V_1 IL_000b: constrained. ""S1"" IL_0011: callvirt ""bool S1.IUnionMembers.TryGetValue(out System.IComparable)"" IL_0016: brfalse.s IL_0054 IL_0018: ldloc.1 IL_0019: stloc.2 IL_001a: ldloc.2 IL_001b: isinst ""int"" IL_0020: brfalse.s IL_0054 IL_0022: ldloc.2 IL_0023: unbox.any ""int"" IL_0028: stloc.3 IL_0029: ldloc.3 IL_002a: ldc.i4.1 IL_002b: beq.s IL_0033 IL_002d: ldloc.3 IL_002e: ldc.i4.3 IL_002f: beq.s IL_0042 IL_0031: br.s IL_0054 IL_0033: ldarg.0 IL_0034: ldfld ""int System.ValueTuple<S1, int>.Item2"" IL_0039: stloc.s V_4 IL_003b: ldloc.s V_4 IL_003d: ldc.i4.2 IL_003e: beq.s IL_004f IL_0040: br.s IL_004a IL_0042: ldarg.0 IL_0043: ldfld ""int System.ValueTuple<S1, int>.Item2"" IL_0048: stloc.s V_4 IL_004a: ldloc.s V_4 IL_004c: ldc.i4.1 IL_004d: bne.un.s IL_0054 IL_004f: ldc.i4.1 IL_0050: stloc.s V_5 IL_0052: br.s IL_0057 IL_0054: ldc.i4.0 IL_0055: stloc.s V_5 IL_0057: ldloc.s V_5 IL_0059: ret } "); } [Fact] public void NonBoxingUnionMatching_MemberProvider_Misc_30() { var src = @" using System; class C11; class C12; [System.Runtime.CompilerServices.Union] struct S1 : S1.IUnionMembers { private readonly object _value; public S1(C11 x) { _value = x; } public S1(int x) { _value = x; } public S1(string x) { _value = x; } public S1(IComparable x) { _value = x; } public S1(C12 x) { _value = x; } object IUnionMembers.Value { get { System.Console.Write(""get_Value ""); return _value; } } bool IUnionMembers.HasValue { get { System.Console.Write(""HasValue ""); return _value != null; } } bool IUnionMembers.TryGetValue(out int x) { System.Console.Write(""TryGetValue(int) ""); if (_value is int) { x = (int)_value; return true; } x = 0; return false; } bool IUnionMembers.TryGetValue(out IComparable x) { System.Console.Write(""TryGetValue(IComparable) ""); x = _value as IComparable; return x != null; } public interface IUnionMembers { public static S1 Create(C11 x) => new S1(x); public static S1 Create(int x) => new S1(x); public static S1 Create(string x) => new S1(x); public static S1 Create(IComparable x) => new S1(x); public static S1 Create(C12 x) => new S1(x); public object Value { get; } public bool HasValue { get; } public bool TryGetValue(out int x); public bool TryGetValue(out IComparable x); } static void Main() { S1[] s = [new S1(), new S1(new C11()), new S1(new C12()), new S1(1), new S1(""1""), new S1(2), new S1(""2""), new S1(3), new S1(""3"")]; int[] i = [1, 2, 3]; foreach (var s1 in s) { foreach (var j in i) { var t = Test1((s1, j)); System.Console.WriteLine(); System.Console.WriteLine(t); } } } static bool Test1((S1, int) u) { return u is (int and 1, 2) or (System.IComparable and { AsInt: 3 }, 1); } } static class IComparableExtensions { extension(IComparable c) { public int? AsInt { get { c.GetHashCode(); // We do not expect null inputs var result = c as int?; if (result.HasValue && result.Value == 0) { throw new Exception(""Unexpected 0 value""); } return result; } } } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); VerifyDecisionDagDump<IsPatternExpressionSyntax>(comp, @"[0]: t1 = t0.Item1; [1] [1]: TryGetValue(int): (Item1, ReturnItem) t2 = t1; [2] [2]: t2.ReturnItem == True ? [3] : [15] [3]: t3 = (int)t2.Item1; [4] [4]: t3 == 1 ? [5] : [13] [5]: t4 = t0.Item2; [6] [6]: t4 == 2 ? [24] : [7] [7]: t5 = (System.IComparable)t2.Item1; [8] [8]: PassThrough t5; [9] [9]: t7 = t5.AsInt; [10] [10]: t7 != null ? [11] : [25] [11]: t8 = (int)t7; [12] [12]: t8 == 3 ? [23] : [25] [13]: t5 = (System.IComparable)t2.Item1; [14] [14]: PassThrough t5; [18] [15]: TryGetValue(System.IComparable): (Item1, ReturnItem) t9 = t1; [16] [16]: t9.ReturnItem == True ? [17] : [25] [17]: t5 = (System.IComparable)t9.Item1; [18] [18]: t7 = t5.AsInt; [19] [19]: t7 != null ? [20] : [25] [20]: t8 = (int)t7; [21] [21]: t8 == 3 ? [22] : [25] [22]: t4 = t0.Item2; [23] [23]: t4 == 1 ? [24] : [25] [24]: leaf <isPatternSuccess> `(int and 1, 2) or (System.IComparable and { AsInt: 3 }, 1)` [25]: leaf <isPatternFailure> `u is (int and 1, 2) or (System.IComparable and { AsInt: 3 }, 1)` ", forLowering: true); var verifier = CompileAndVerify( comp, expectedOutput: @" TryGetValue(int) TryGetValue(IComparable) False TryGetValue(int) TryGetValue(IComparable) False TryGetValue(int) TryGetValue(IComparable) False TryGetValue(int) TryGetValue(IComparable) False TryGetValue(int) TryGetValue(IComparable) False TryGetValue(int) TryGetValue(IComparable) False TryGetValue(int) TryGetValue(IComparable) False TryGetValue(int) TryGetValue(IComparable) False TryGetValue(int) TryGetValue(IComparable) False TryGetValue(int) False TryGetValue(int) True TryGetValue(int) False TryGetValue(int) TryGetValue(IComparable) False TryGetValue(int) TryGetValue(IComparable) False TryGetValue(int) TryGetValue(IComparable) False TryGetValue(int) False TryGetValue(int) False TryGetValue(int) False TryGetValue(int) TryGetValue(IComparable) False TryGetValue(int) TryGetValue(IComparable) False TryGetValue(int) TryGetValue(IComparable) False TryGetValue(int) True TryGetValue(int) False TryGetValue(int) False TryGetValue(int) TryGetValue(IComparable) False TryGetValue(int) TryGetValue(IComparable) False TryGetValue(int) TryGetValue(IComparable) False ").VerifyDiagnostics(); verifier.VerifyIL("S1.Test1", @" { // Code size 153 (0x99) .maxstack 2 .locals init (S1 V_0, int V_1, int V_2, System.IComparable V_3, int? V_4, System.IComparable V_5, bool V_6) IL_0000: ldarg.0 IL_0001: ldfld ""S1 System.ValueTuple<S1, int>.Item1"" IL_0006: stloc.0 IL_0007: ldloca.s V_0 IL_0009: ldloca.s V_1 IL_000b: constrained. ""S1"" IL_0011: callvirt ""bool S1.IUnionMembers.TryGetValue(out int)"" IL_0016: brfalse.s IL_0054 IL_0018: ldloc.1 IL_0019: ldc.i4.1 IL_001a: bne.un.s IL_004b IL_001c: ldarg.0 IL_001d: ldfld ""int System.ValueTuple<S1, int>.Item2"" IL_0022: stloc.2 IL_0023: ldloc.2 IL_0024: ldc.i4.2 IL_0025: beq.s IL_008e IL_0027: ldloc.1 IL_0028: box ""int"" IL_002d: stloc.3 IL_002e: ldloc.3 IL_002f: call ""int? IComparableExtensions.get_AsInt(System.IComparable)"" IL_0034: stloc.s V_4 IL_0036: ldloca.s V_4 IL_0038: call ""bool int?.HasValue.get"" IL_003d: brfalse.s IL_0093 IL_003f: ldloca.s V_4 IL_0041: call ""int int?.GetValueOrDefault()"" IL_0046: ldc.i4.3 IL_0047: beq.s IL_008a IL_0049: br.s IL_0093 IL_004b: ldloc.1 IL_004c: box ""int"" IL_0051: stloc.3 IL_0052: br.s IL_0068 IL_0054: ldloca.s V_0 IL_0056: ldloca.s V_5 IL_0058: constrained. ""S1"" IL_005e: callvirt ""bool S1.IUnionMembers.TryGetValue(out System.IComparable)"" IL_0063: brfalse.s IL_0093 IL_0065: ldloc.s V_5 IL_0067: stloc.3 IL_0068: ldloc.3 IL_0069: call ""int? IComparableExtensions.get_AsInt(System.IComparable)"" IL_006e: stloc.s V_4 IL_0070: ldloca.s V_4 IL_0072: call ""bool int?.HasValue.get"" IL_0077: brfalse.s IL_0093 IL_0079: ldloca.s V_4 IL_007b: call ""int int?.GetValueOrDefault()"" IL_0080: ldc.i4.3 IL_0081: bne.un.s IL_0093 IL_0083: ldarg.0 IL_0084: ldfld ""int System.ValueTuple<S1, int>.Item2"" IL_0089: stloc.2 IL_008a: ldloc.2 IL_008b: ldc.i4.1 IL_008c: bne.un.s IL_0093 IL_008e: ldc.i4.1 IL_008f: stloc.s V_6 IL_0091: br.s IL_0096 IL_0093: ldc.i4.0 IL_0094: stloc.s V_6 IL_0096: ldloc.s V_6 IL_0098: ret } "); } [Fact] public void NonBoxingUnionMatching_MemberProvider_Misc_31() { var src = @" using System; class C11; class C12 : IConvertible { public TypeCode GetTypeCode() => throw null; public bool ToBoolean(IFormatProvider provider) => throw null; public byte ToByte(IFormatProvider provider) => throw null; public char ToChar(IFormatProvider provider) => throw null; public DateTime ToDateTime(IFormatProvider provider) => throw null; public decimal ToDecimal(IFormatProvider provider) => throw null; public double ToDouble(IFormatProvider provider) => throw null; public short ToInt16(IFormatProvider provider) => throw null; public int ToInt32(IFormatProvider provider) => throw null; public long ToInt64(IFormatProvider provider) => throw null; public sbyte ToSByte(IFormatProvider provider) => throw null; public float ToSingle(IFormatProvider provider) => throw null; public string ToString(IFormatProvider provider) => throw null; public object ToType(Type conversionType, IFormatProvider provider) => throw null; public ushort ToUInt16(IFormatProvider provider) => throw null; public uint ToUInt32(IFormatProvider provider) => throw null; public ulong ToUInt64(IFormatProvider provider) => throw null; } [System.Runtime.CompilerServices.Union] struct S1 : S1.IUnionMembers { private readonly object _value; public S1(C11 x) { _value = x; } public S1(int x) { _value = x; } public S1(string x) { _value = x; } public S1(IComparable x) { _value = x; } public S1(IConvertible x) { _value = x; } object IUnionMembers.Value { get { System.Console.Write(""get_Value ""); return _value; } } bool IUnionMembers.HasValue { get { System.Console.Write(""HasValue ""); return _value != null; } } bool IUnionMembers.TryGetValue(out int x) { System.Console.Write(""TryGetValue(int) ""); if (_value is int) { x = (int)_value; return true; } x = 0; return false; } bool IUnionMembers.TryGetValue(out IComparable x) { System.Console.Write(""TryGetValue(IComparable) ""); x = _value as IComparable; return x != null; } bool IUnionMembers.TryGetValue(out IConvertible x) { System.Console.Write(""TryGetValue(IConvertible) ""); x = _value as IConvertible; return x != null; } public interface IUnionMembers { public static S1 Create(C11 x) => new S1(x); public static S1 Create(int x) => new S1(x); public static S1 Create(string x) => new S1(x); public static S1 Create(IComparable x) => new S1(x); public static S1 Create(IConvertible x) => new S1(x); public object Value { get; } public bool HasValue { get; } public bool TryGetValue(out int x); public bool TryGetValue(out IComparable x); public bool TryGetValue(out IConvertible x); } static void Main() { S1[] s = [new S1(), new S1(new C11()), new S1(new C12()), new S1(1), new S1(""1""), new S1(2), new S1(""2""), new S1(3), new S1(""3"")]; int[] i = [1, 2, 3]; foreach (var s1 in s) { foreach (var j in i) { var t = Test1((s1, j)); System.Console.WriteLine(); System.Console.WriteLine(t); } } } static bool Test1((S1, int) u) { return u is (IConvertible and int and 1, 2) or (System.IComparable and { AsInt: 3 }, 1); } } static class IComparableExtensions { extension(IComparable c) { public int? AsInt { get { c.GetHashCode(); // We do not expect null inputs var result = c as int?; if (result.HasValue && result.Value == 0) { throw new Exception(""Unexpected 0 value""); } return result; } } } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); VerifyDecisionDagDump<IsPatternExpressionSyntax>(comp, @"[0]: t1 = t0.Item1; [1] [1]: TryGetValue(System.IConvertible): (Item1, ReturnItem) t2 = t1; [2] [2]: t2.ReturnItem == True ? [3] : [17] [3]: t3 = (System.IConvertible)t2.Item1; [4] [4]: t3 is int ? [5] : [17] [5]: t4 = (int)t3; [6] [6]: t4 == 1 ? [7] : [15] [7]: t5 = t0.Item2; [8] [8]: t5 == 2 ? [26] : [9] [9]: t6 = (System.IComparable)t3; [10] [10]: PassThrough t6; [11] [11]: t8 = t6.AsInt; [12] [12]: t8 != null ? [13] : [27] [13]: t9 = (int)t8; [14] [14]: t9 == 3 ? [25] : [27] [15]: t6 = (System.IComparable)t3; [16] [16]: PassThrough t6; [20] [17]: TryGetValue(System.IComparable): (Item1, ReturnItem) t10 = t1; [18] [18]: t10.ReturnItem == True ? [19] : [27] [19]: t6 = (System.IComparable)t10.Item1; [20] [20]: t8 = t6.AsInt; [21] [21]: t8 != null ? [22] : [27] [22]: t9 = (int)t8; [23] [23]: t9 == 3 ? [24] : [27] [24]: t5 = t0.Item2; [25] [25]: t5 == 1 ? [26] : [27] [26]: leaf <isPatternSuccess> `(IConvertible and int and 1, 2) or (System.IComparable and { AsInt: 3 }, 1)` [27]: leaf <isPatternFailure> `u is (IConvertible and int and 1, 2) or (System.IComparable and { AsInt: 3 }, 1)` ", forLowering: true); var verifier = CompileAndVerify( comp, expectedOutput: @" TryGetValue(IConvertible) TryGetValue(IComparable) False TryGetValue(IConvertible) TryGetValue(IComparable) False TryGetValue(IConvertible) TryGetValue(IComparable) False TryGetValue(IConvertible) TryGetValue(IComparable) False TryGetValue(IConvertible) TryGetValue(IComparable) False TryGetValue(IConvertible) TryGetValue(IComparable) False TryGetValue(IConvertible) TryGetValue(IComparable) False TryGetValue(IConvertible) TryGetValue(IComparable) False TryGetValue(IConvertible) TryGetValue(IComparable) False TryGetValue(IConvertible) False TryGetValue(IConvertible) True TryGetValue(IConvertible) False TryGetValue(IConvertible) TryGetValue(IComparable) False TryGetValue(IConvertible) TryGetValue(IComparable) False TryGetValue(IConvertible) TryGetValue(IComparable) False TryGetValue(IConvertible) False TryGetValue(IConvertible) False TryGetValue(IConvertible) False TryGetValue(IConvertible) TryGetValue(IComparable) False TryGetValue(IConvertible) TryGetValue(IComparable) False TryGetValue(IConvertible) TryGetValue(IComparable) False TryGetValue(IConvertible) True TryGetValue(IConvertible) False TryGetValue(IConvertible) False TryGetValue(IConvertible) TryGetValue(IComparable) False TryGetValue(IConvertible) TryGetValue(IComparable) False TryGetValue(IConvertible) TryGetValue(IComparable) False ").VerifyDiagnostics(); verifier.VerifyIL("S1.Test1", @" { // Code size 173 (0xad) .maxstack 2 .locals init (S1 V_0, System.IConvertible V_1, System.IConvertible V_2, int V_3, System.IComparable V_4, int? V_5, System.IComparable V_6, bool V_7) IL_0000: ldarg.0 IL_0001: ldfld ""S1 System.ValueTuple<S1, int>.Item1"" IL_0006: stloc.0 IL_0007: ldloca.s V_0 IL_0009: ldloca.s V_1 IL_000b: constrained. ""S1"" IL_0011: callvirt ""bool S1.IUnionMembers.TryGetValue(out System.IConvertible)"" IL_0016: brfalse.s IL_0066 IL_0018: ldloc.1 IL_0019: stloc.2 IL_001a: ldloc.2 IL_001b: isinst ""int"" IL_0020: brfalse.s IL_0066 IL_0022: ldloc.2 IL_0023: unbox.any ""int"" IL_0028: ldc.i4.1 IL_0029: bne.un.s IL_005c IL_002b: ldarg.0 IL_002c: ldfld ""int System.ValueTuple<S1, int>.Item2"" IL_0031: stloc.3 IL_0032: ldloc.3 IL_0033: ldc.i4.2 IL_0034: beq.s IL_00a2 IL_0036: ldloc.2 IL_0037: castclass ""System.IComparable"" IL_003c: stloc.s V_4 IL_003e: ldloc.s V_4 IL_0040: call ""int? IComparableExtensions.get_AsInt(System.IComparable)"" IL_0045: stloc.s V_5 IL_0047: ldloca.s V_5 IL_0049: call ""bool int?.HasValue.get"" IL_004e: brfalse.s IL_00a7 IL_0050: ldloca.s V_5 IL_0052: call ""int int?.GetValueOrDefault()"" IL_0057: ldc.i4.3 IL_0058: beq.s IL_009e IL_005a: br.s IL_00a7 IL_005c: ldloc.2 IL_005d: castclass ""System.IComparable"" IL_0062: stloc.s V_4 IL_0064: br.s IL_007b IL_0066: ldloca.s V_0 IL_0068: ldloca.s V_6 IL_006a: constrained. ""S1"" IL_0070: callvirt ""bool S1.IUnionMembers.TryGetValue(out System.IComparable)"" IL_0075: brfalse.s IL_00a7 IL_0077: ldloc.s V_6 IL_0079: stloc.s V_4 IL_007b: ldloc.s V_4 IL_007d: call ""int? IComparableExtensions.get_AsInt(System.IComparable)"" IL_0082: stloc.s V_5 IL_0084: ldloca.s V_5 IL_0086: call ""bool int?.HasValue.get"" IL_008b: brfalse.s IL_00a7 IL_008d: ldloca.s V_5 IL_008f: call ""int int?.GetValueOrDefault()"" IL_0094: ldc.i4.3 IL_0095: bne.un.s IL_00a7 IL_0097: ldarg.0 IL_0098: ldfld ""int System.ValueTuple<S1, int>.Item2"" IL_009d: stloc.3 IL_009e: ldloc.3 IL_009f: ldc.i4.1 IL_00a0: bne.un.s IL_00a7 IL_00a2: ldc.i4.1 IL_00a3: stloc.s V_7 IL_00a5: br.s IL_00aa IL_00a7: ldc.i4.0 IL_00a8: stloc.s V_7 IL_00aa: ldloc.s V_7 IL_00ac: ret } "); } [Fact] public void NonBoxingUnionMatching_MemberProvider_Misc_32() { var src = @" using System; class C11; class C12 : IConvertible { public TypeCode GetTypeCode() => throw null; public bool ToBoolean(IFormatProvider provider) => throw null; public byte ToByte(IFormatProvider provider) => throw null; public char ToChar(IFormatProvider provider) => throw null; public DateTime ToDateTime(IFormatProvider provider) => throw null; public decimal ToDecimal(IFormatProvider provider) => throw null; public double ToDouble(IFormatProvider provider) => throw null; public short ToInt16(IFormatProvider provider) => throw null; public int ToInt32(IFormatProvider provider) => throw null; public long ToInt64(IFormatProvider provider) => throw null; public sbyte ToSByte(IFormatProvider provider) => throw null; public float ToSingle(IFormatProvider provider) => throw null; public string ToString(IFormatProvider provider) => throw null; public object ToType(Type conversionType, IFormatProvider provider) => throw null; public ushort ToUInt16(IFormatProvider provider) => throw null; public uint ToUInt32(IFormatProvider provider) => throw null; public ulong ToUInt64(IFormatProvider provider) => throw null; } [System.Runtime.CompilerServices.Union] struct S1 : S1.IUnionMembers { private readonly object _value; public S1(C11 x) { _value = x; } public S1(int x) { _value = x; } public S1(string x) { _value = x; } public S1(IComparable x) { _value = x; } public S1(IConvertible x) { _value = x; } object IUnionMembers.Value { get { System.Console.Write(""get_Value ""); return _value; } } bool IUnionMembers.HasValue { get { System.Console.Write(""HasValue ""); return _value != null; } } bool IUnionMembers.TryGetValue(out int x) { System.Console.Write(""TryGetValue(int) ""); if (_value is int) { x = (int)_value; return true; } x = 0; return false; } bool IUnionMembers.TryGetValue(out IComparable x) { System.Console.Write(""TryGetValue(IComparable) ""); x = _value as IComparable; return x != null; } bool IUnionMembers.TryGetValue(out IConvertible x) { System.Console.Write(""TryGetValue(IConvertible) ""); x = _value as IConvertible; return x != null; } bool IUnionMembers.TryGetValue(out string x) { System.Console.Write(""TryGetValue(string) ""); x = _value as string; return x != null; } public interface IUnionMembers { public static S1 Create(C11 x) => new S1(x); public static S1 Create(int x) => new S1(x); public static S1 Create(string x) => new S1(x); public static S1 Create(IComparable x) => new S1(x); public static S1 Create(IConvertible x) => new S1(x); public object Value { get; } public bool HasValue { get; } public bool TryGetValue(out int x); public bool TryGetValue(out IComparable x); public bool TryGetValue(out IConvertible x); public bool TryGetValue(out string x); } static void Main() { S1[] s = [new S1(), new S1(new C11()), new S1(new C12()), new S1(1), new S1(""1""), new S1(2), new S1(""2""), new S1(3), new S1(""3"")]; int[] i = [1, 2, 3]; foreach (var s1 in s) { foreach (var j in i) { var t = Test1((s1, j)); System.Console.WriteLine(); System.Console.WriteLine(t); } } } static bool Test1((S1, int) u) { return u is (int and 1, 2) or (string and ""3"", 3) or (System.IComparable and { AsInt: 3 }, 1); } } static class IComparableExtensions { extension(IComparable c) { public int? AsInt { get { c.GetHashCode(); // We do not expect null inputs var result = c as int?; if (result.HasValue && result.Value == 0) { throw new Exception(""Unexpected 0 value""); } return result; } } } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); VerifyDecisionDagDump<IsPatternExpressionSyntax>(comp, @"[0]: t1 = t0.Item1; [1] [1]: TryGetValue(int): (Item1, ReturnItem) t2 = t1; [2] [2]: t2.ReturnItem == True ? [3] : [11] [3]: t3 = (int)t2.Item1; [4] [4]: t3 == 1 ? [5] : [9] [5]: t4 = t0.Item2; [6] [6]: t4 == 2 ? [34] : [7] [7]: t5 = (System.IComparable)t2.Item1; [8] [8]: PassThrough t5; [19] [9]: t5 = (System.IComparable)t2.Item1; [10] [10]: PassThrough t5; [28] [11]: TryGetValue(string): (Item1, ReturnItem) t7 = t1; [12] [12]: t7.ReturnItem == True ? [13] : [25] [13]: t8 = (string)t7.Item1; [14] [14]: t8 == ""3"" ? [15] : [23] [15]: t4 = t0.Item2; [16] [16]: t4 == 3 ? [34] : [17] [17]: t5 = (System.IComparable)t7.Item1; [18] [18]: PassThrough t5; [19] [19]: t10 = t5.AsInt; [20] [20]: t10 != null ? [21] : [35] [21]: t11 = (int)t10; [22] [22]: t11 == 3 ? [33] : [35] [23]: t5 = (System.IComparable)t7.Item1; [24] [24]: PassThrough t5; [28] [25]: TryGetValue(System.IComparable): (Item1, ReturnItem) t12 = t1; [26] [26]: t12.ReturnItem == True ? [27] : [35] [27]: t5 = (System.IComparable)t12.Item1; [28] [28]: t10 = t5.AsInt; [29] [29]: t10 != null ? [30] : [35] [30]: t11 = (int)t10; [31] [31]: t11 == 3 ? [32] : [35] [32]: t4 = t0.Item2; [33] [33]: t4 == 1 ? [34] : [35] [34]: leaf <isPatternSuccess> `(int and 1, 2) or (string and ""3"", 3) or (System.IComparable and { AsInt: 3 }, 1)` [35]: leaf <isPatternFailure> `u is (int and 1, 2) or (string and ""3"", 3) or (System.IComparable and { AsInt: 3 }, 1)` ", forLowering: true); var verifier = CompileAndVerify( comp, expectedOutput: @" TryGetValue(int) TryGetValue(string) TryGetValue(IComparable) False TryGetValue(int) TryGetValue(string) TryGetValue(IComparable) False TryGetValue(int) TryGetValue(string) TryGetValue(IComparable) False TryGetValue(int) TryGetValue(string) TryGetValue(IComparable) False TryGetValue(int) TryGetValue(string) TryGetValue(IComparable) False TryGetValue(int) TryGetValue(string) TryGetValue(IComparable) False TryGetValue(int) TryGetValue(string) TryGetValue(IComparable) False TryGetValue(int) TryGetValue(string) TryGetValue(IComparable) False TryGetValue(int) TryGetValue(string) TryGetValue(IComparable) False TryGetValue(int) False TryGetValue(int) True TryGetValue(int) False TryGetValue(int) TryGetValue(string) False TryGetValue(int) TryGetValue(string) False TryGetValue(int) TryGetValue(string) False TryGetValue(int) False TryGetValue(int) False TryGetValue(int) False TryGetValue(int) TryGetValue(string) False TryGetValue(int) TryGetValue(string) False TryGetValue(int) TryGetValue(string) False TryGetValue(int) True TryGetValue(int) False TryGetValue(int) False TryGetValue(int) TryGetValue(string) False TryGetValue(int) TryGetValue(string) False TryGetValue(int) TryGetValue(string) True ").VerifyDiagnostics(); verifier.VerifyIL("S1.Test1", @" { // Code size 208 (0xd0) .maxstack 2 .locals init (S1 V_0, int V_1, int V_2, System.IComparable V_3, string V_4, int? V_5, System.IComparable V_6, bool V_7) IL_0000: ldarg.0 IL_0001: ldfld ""S1 System.ValueTuple<S1, int>.Item1"" IL_0006: stloc.0 IL_0007: ldloca.s V_0 IL_0009: ldloca.s V_1 IL_000b: constrained. ""S1"" IL_0011: callvirt ""bool S1.IUnionMembers.TryGetValue(out int)"" IL_0016: brfalse.s IL_003c IL_0018: ldloc.1 IL_0019: ldc.i4.1 IL_001a: bne.un.s IL_0033 IL_001c: ldarg.0 IL_001d: ldfld ""int System.ValueTuple<S1, int>.Item2"" IL_0022: stloc.2 IL_0023: ldloc.2 IL_0024: ldc.i4.2 IL_0025: beq IL_00c5 IL_002a: ldloc.1 IL_002b: box ""int"" IL_0030: stloc.3 IL_0031: br.s IL_0069 IL_0033: ldloc.1 IL_0034: box ""int"" IL_0039: stloc.3 IL_003a: br.s IL_009f IL_003c: ldloca.s V_0 IL_003e: ldloca.s V_4 IL_0040: constrained. ""S1"" IL_0046: callvirt ""bool S1.IUnionMembers.TryGetValue(out string)"" IL_004b: brfalse.s IL_008b IL_004d: ldloc.s V_4 IL_004f: ldstr ""3"" IL_0054: call ""bool string.op_Equality(string, string)"" IL_0059: brfalse.s IL_0086 IL_005b: ldarg.0 IL_005c: ldfld ""int System.ValueTuple<S1, int>.Item2"" IL_0061: stloc.2 IL_0062: ldloc.2 IL_0063: ldc.i4.3 IL_0064: beq.s IL_00c5 IL_0066: ldloc.s V_4 IL_0068: stloc.3 IL_0069: ldloc.3 IL_006a: call ""int? IComparableExtensions.get_AsInt(System.IComparable)"" IL_006f: stloc.s V_5 IL_0071: ldloca.s V_5 IL_0073: call ""bool int?.HasValue.get"" IL_0078: brfalse.s IL_00ca IL_007a: ldloca.s V_5 IL_007c: call ""int int?.GetValueOrDefault()"" IL_0081: ldc.i4.3 IL_0082: beq.s IL_00c1 IL_0084: br.s IL_00ca IL_0086: ldloc.s V_4 IL_0088: stloc.3 IL_0089: br.s IL_009f IL_008b: ldloca.s V_0 IL_008d: ldloca.s V_6 IL_008f: constrained. ""S1"" IL_0095: callvirt ""bool S1.IUnionMembers.TryGetValue(out System.IComparable)"" IL_009a: brfalse.s IL_00ca IL_009c: ldloc.s V_6 IL_009e: stloc.3 IL_009f: ldloc.3 IL_00a0: call ""int? IComparableExtensions.get_AsInt(System.IComparable)"" IL_00a5: stloc.s V_5 IL_00a7: ldloca.s V_5 IL_00a9: call ""bool int?.HasValue.get"" IL_00ae: brfalse.s IL_00ca IL_00b0: ldloca.s V_5 IL_00b2: call ""int int?.GetValueOrDefault()"" IL_00b7: ldc.i4.3 IL_00b8: bne.un.s IL_00ca IL_00ba: ldarg.0 IL_00bb: ldfld ""int System.ValueTuple<S1, int>.Item2"" IL_00c0: stloc.2 IL_00c1: ldloc.2 IL_00c2: ldc.i4.1 IL_00c3: bne.un.s IL_00ca IL_00c5: ldc.i4.1 IL_00c6: stloc.s V_7 IL_00c8: br.s IL_00cd IL_00ca: ldc.i4.0 IL_00cb: stloc.s V_7 IL_00cd: ldloc.s V_7 IL_00cf: ret } "); } [Fact] public void NonBoxingUnionMatching_MemberProvider_Misc_33() { var src = @" using System; class C11; class C12 : IConvertible { public TypeCode GetTypeCode() => throw null; public bool ToBoolean(IFormatProvider provider) => throw null; public byte ToByte(IFormatProvider provider) => throw null; public char ToChar(IFormatProvider provider) => throw null; public DateTime ToDateTime(IFormatProvider provider) => throw null; public decimal ToDecimal(IFormatProvider provider) => throw null; public double ToDouble(IFormatProvider provider) => throw null; public short ToInt16(IFormatProvider provider) => throw null; public int ToInt32(IFormatProvider provider) => throw null; public long ToInt64(IFormatProvider provider) => throw null; public sbyte ToSByte(IFormatProvider provider) => throw null; public float ToSingle(IFormatProvider provider) => throw null; public string ToString(IFormatProvider provider) => throw null; public object ToType(Type conversionType, IFormatProvider provider) => throw null; public ushort ToUInt16(IFormatProvider provider) => throw null; public uint ToUInt32(IFormatProvider provider) => throw null; public ulong ToUInt64(IFormatProvider provider) => throw null; } [System.Runtime.CompilerServices.Union] struct S1 : S1.IUnionMembers { private readonly object _value; public S1(C11 x) { _value = x; } public S1(int x) { _value = x; } public S1(string x) { _value = x; } public S1(IComparable x) { _value = x; } public S1(IConvertible x) { _value = x; } object IUnionMembers.Value { get { System.Console.Write(""get_Value ""); return _value; } } bool IUnionMembers.HasValue { get { System.Console.Write(""HasValue ""); return _value != null; } } bool IUnionMembers.TryGetValue(out int x) { System.Console.Write(""TryGetValue(int) ""); if (_value is int) { x = (int)_value; return true; } x = 0; return false; } bool IUnionMembers.TryGetValue(out IComparable x) { System.Console.Write(""TryGetValue(IComparable) ""); x = _value as IComparable; return x != null; } bool IUnionMembers.TryGetValue(out IConvertible x) { System.Console.Write(""TryGetValue(IConvertible) ""); x = _value as IConvertible; return x != null; } bool IUnionMembers.TryGetValue(out string x) { System.Console.Write(""TryGetValue(string) ""); x = _value as string; return x != null; } public interface IUnionMembers { public static S1 Create(C11 x) => new S1(x); public static S1 Create(int x) => new S1(x); public static S1 Create(string x) => new S1(x); public static S1 Create(IComparable x) => new S1(x); public static S1 Create(IConvertible x) => new S1(x); public object Value { get; } public bool HasValue { get; } public bool TryGetValue(out int x); public bool TryGetValue(out IComparable x); public bool TryGetValue(out IConvertible x); public bool TryGetValue(out string x); } static void Main() { S1[] s = [new S1(), new S1(new C11()), new S1(new C12()), new S1(1), new S1(""1""), new S1(2), new S1(""2""), new S1(3), new S1(""3"")]; int[] i = [1, 2, 3]; foreach (var s1 in s) { foreach (var j in i) { var t = Test1((s1, j)); System.Console.WriteLine(); System.Console.WriteLine(t); } } } static bool Test1((S1, int) u) { return u is (IConvertible and int and 1, 2) or (string and ""3"", 3) or (System.IComparable and { AsInt: 3 }, 1); } } static class IComparableExtensions { extension(IComparable c) { public int? AsInt { get { c.GetHashCode(); // We do not expect null inputs var result = c as int?; if (result.HasValue && result.Value == 0) { throw new Exception(""Unexpected 0 value""); } return result; } } } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); VerifyDecisionDagDump<IsPatternExpressionSyntax>(comp, @"[0]: t1 = t0.Item1; [1] [1]: TryGetValue(System.IConvertible): (Item1, ReturnItem) t2 = t1; [2] [2]: t2.ReturnItem == True ? [3] : [27] [3]: t3 = (System.IConvertible)t2.Item1; [4] [4]: t3 is int ? [5] : [13] [5]: t4 = (int)t3; [6] [6]: t4 == 1 ? [7] : [11] [7]: t5 = t0.Item2; [8] [8]: t5 == 2 ? [36] : [9] [9]: t6 = (System.IComparable)t3; [10] [10]: PassThrough t6; [21] [11]: t6 = (System.IComparable)t3; [12] [12]: PassThrough t6; [30] [13]: TryGetValue(string): (Item1, ReturnItem) t8 = t1; [14] [14]: t8.ReturnItem == True ? [15] : [27] [15]: t9 = (string)t8.Item1; [16] [16]: t9 == ""3"" ? [17] : [25] [17]: t5 = t0.Item2; [18] [18]: t5 == 3 ? [36] : [19] [19]: t6 = (System.IComparable)t8.Item1; [20] [20]: PassThrough t6; [21] [21]: t11 = t6.AsInt; [22] [22]: t11 != null ? [23] : [37] [23]: t12 = (int)t11; [24] [24]: t12 == 3 ? [35] : [37] [25]: t6 = (System.IComparable)t8.Item1; [26] [26]: PassThrough t6; [30] [27]: TryGetValue(System.IComparable): (Item1, ReturnItem) t13 = t1; [28] [28]: t13.ReturnItem == True ? [29] : [37] [29]: t6 = (System.IComparable)t13.Item1; [30] [30]: t11 = t6.AsInt; [31] [31]: t11 != null ? [32] : [37] [32]: t12 = (int)t11; [33] [33]: t12 == 3 ? [34] : [37] [34]: t5 = t0.Item2; [35] [35]: t5 == 1 ? [36] : [37] [36]: leaf <isPatternSuccess> `(IConvertible and int and 1, 2) or (string and ""3"", 3) or (System.IComparable and { AsInt: 3 }, 1)` [37]: leaf <isPatternFailure> `u is (IConvertible and int and 1, 2) or (string and ""3"", 3) or (System.IComparable and { AsInt: 3 }, 1)` ", forLowering: true); var verifier = CompileAndVerify( comp, expectedOutput: @" TryGetValue(IConvertible) TryGetValue(IComparable) False TryGetValue(IConvertible) TryGetValue(IComparable) False TryGetValue(IConvertible) TryGetValue(IComparable) False TryGetValue(IConvertible) TryGetValue(IComparable) False TryGetValue(IConvertible) TryGetValue(IComparable) False TryGetValue(IConvertible) TryGetValue(IComparable) False TryGetValue(IConvertible) TryGetValue(string) TryGetValue(IComparable) False TryGetValue(IConvertible) TryGetValue(string) TryGetValue(IComparable) False TryGetValue(IConvertible) TryGetValue(string) TryGetValue(IComparable) False TryGetValue(IConvertible) False TryGetValue(IConvertible) True TryGetValue(IConvertible) False TryGetValue(IConvertible) TryGetValue(string) False TryGetValue(IConvertible) TryGetValue(string) False TryGetValue(IConvertible) TryGetValue(string) False TryGetValue(IConvertible) False TryGetValue(IConvertible) False TryGetValue(IConvertible) False TryGetValue(IConvertible) TryGetValue(string) False TryGetValue(IConvertible) TryGetValue(string) False TryGetValue(IConvertible) TryGetValue(string) False TryGetValue(IConvertible) True TryGetValue(IConvertible) False TryGetValue(IConvertible) False TryGetValue(IConvertible) TryGetValue(string) False TryGetValue(IConvertible) TryGetValue(string) False TryGetValue(IConvertible) TryGetValue(string) True ").VerifyDiagnostics(); verifier.VerifyIL("S1.Test1", @" { // Code size 233 (0xe9) .maxstack 2 .locals init (S1 V_0, System.IConvertible V_1, System.IConvertible V_2, int V_3, System.IComparable V_4, string V_5, int? V_6, System.IComparable V_7, bool V_8) IL_0000: ldarg.0 IL_0001: ldfld ""S1 System.ValueTuple<S1, int>.Item1"" IL_0006: stloc.0 IL_0007: ldloca.s V_0 IL_0009: ldloca.s V_1 IL_000b: constrained. ""S1"" IL_0011: callvirt ""bool S1.IUnionMembers.TryGetValue(out System.IConvertible)"" IL_0016: brfalse IL_00a2 IL_001b: ldloc.1 IL_001c: stloc.2 IL_001d: ldloc.2 IL_001e: isinst ""int"" IL_0023: brfalse.s IL_0050 IL_0025: ldloc.2 IL_0026: unbox.any ""int"" IL_002b: ldc.i4.1 IL_002c: bne.un.s IL_0046 IL_002e: ldarg.0 IL_002f: ldfld ""int System.ValueTuple<S1, int>.Item2"" IL_0034: stloc.3 IL_0035: ldloc.3 IL_0036: ldc.i4.2 IL_0037: beq IL_00de IL_003c: ldloc.2 IL_003d: castclass ""System.IComparable"" IL_0042: stloc.s V_4 IL_0044: br.s IL_007e IL_0046: ldloc.2 IL_0047: castclass ""System.IComparable"" IL_004c: stloc.s V_4 IL_004e: br.s IL_00b7 IL_0050: ldloca.s V_0 IL_0052: ldloca.s V_5 IL_0054: constrained. ""S1"" IL_005a: callvirt ""bool S1.IUnionMembers.TryGetValue(out string)"" IL_005f: brfalse.s IL_00a2 IL_0061: ldloc.s V_5 IL_0063: ldstr ""3"" IL_0068: call ""bool string.op_Equality(string, string)"" IL_006d: brfalse.s IL_009c IL_006f: ldarg.0 IL_0070: ldfld ""int System.ValueTuple<S1, int>.Item2"" IL_0075: stloc.3 IL_0076: ldloc.3 IL_0077: ldc.i4.3 IL_0078: beq.s IL_00de IL_007a: ldloc.s V_5 IL_007c: stloc.s V_4 IL_007e: ldloc.s V_4 IL_0080: call ""int? IComparableExtensions.get_AsInt(System.IComparable)"" IL_0085: stloc.s V_6 IL_0087: ldloca.s V_6 IL_0089: call ""bool int?.HasValue.get"" IL_008e: brfalse.s IL_00e3 IL_0090: ldloca.s V_6 IL_0092: call ""int int?.GetValueOrDefault()"" IL_0097: ldc.i4.3 IL_0098: beq.s IL_00da IL_009a: br.s IL_00e3 IL_009c: ldloc.s V_5 IL_009e: stloc.s V_4 IL_00a0: br.s IL_00b7 IL_00a2: ldloca.s V_0 IL_00a4: ldloca.s V_7 IL_00a6: constrained. ""S1"" IL_00ac: callvirt ""bool S1.IUnionMembers.TryGetValue(out System.IComparable)"" IL_00b1: brfalse.s IL_00e3 IL_00b3: ldloc.s V_7 IL_00b5: stloc.s V_4 IL_00b7: ldloc.s V_4 IL_00b9: call ""int? IComparableExtensions.get_AsInt(System.IComparable)"" IL_00be: stloc.s V_6 IL_00c0: ldloca.s V_6 IL_00c2: call ""bool int?.HasValue.get"" IL_00c7: brfalse.s IL_00e3 IL_00c9: ldloca.s V_6 IL_00cb: call ""int int?.GetValueOrDefault()"" IL_00d0: ldc.i4.3 IL_00d1: bne.un.s IL_00e3 IL_00d3: ldarg.0 IL_00d4: ldfld ""int System.ValueTuple<S1, int>.Item2"" IL_00d9: stloc.3 IL_00da: ldloc.3 IL_00db: ldc.i4.1 IL_00dc: bne.un.s IL_00e3 IL_00de: ldc.i4.1 IL_00df: stloc.s V_8 IL_00e1: br.s IL_00e6 IL_00e3: ldc.i4.0 IL_00e4: stloc.s V_8 IL_00e6: ldloc.s V_8 IL_00e8: ret } "); } [Fact] public void NonBoxingUnionMatching_MemberProvider_Misc_34() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 : S1.IUnionMembers { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } object IUnionMembers.Value { get { System.Console.Write(""get_Value ""); return _value; } } bool IUnionMembers.TryGetValue(out int x) { System.Console.Write(""TryGetValue ""); if (_value is int v) { x = v; return true; } x = 0; return false; } public interface IUnionMembers { public static S1 Create(int x) => new S1(x); public static S1 Create(string x) => new S1(x); public object Value { get; } public bool TryGetValue(out int x); } static void Main() { System.Console.Write(Test1((new S1(1), 1))); System.Console.Write(""; ""); System.Console.Write(Test1((new S1(), 2))); System.Console.Write(""; ""); System.Console.Write(Test1((new S1(1), 2))); System.Console.Write(""; ""); System.Console.Write(Test1((new S1(""a""), 1))); } static bool Test1((S1, int) u) { return u is (1, 1) or (1, 2); } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); var verifier = CompileAndVerify(comp, expectedOutput: "TryGetValue True; TryGetValue False; TryGetValue True; TryGetValue False").VerifyDiagnostics(); verifier.VerifyIL("S1.Test1", @" { // Code size 49 (0x31) .maxstack 2 .locals init (S1 V_0, int V_1, int V_2, bool V_3) IL_0000: ldarg.0 IL_0001: ldfld ""S1 System.ValueTuple<S1, int>.Item1"" IL_0006: stloc.0 IL_0007: ldloca.s V_0 IL_0009: ldloca.s V_1 IL_000b: constrained. ""S1"" IL_0011: callvirt ""bool S1.IUnionMembers.TryGetValue(out int)"" IL_0016: brfalse.s IL_002d IL_0018: ldloc.1 IL_0019: ldc.i4.1 IL_001a: bne.un.s IL_002d IL_001c: ldarg.0 IL_001d: ldfld ""int System.ValueTuple<S1, int>.Item2"" IL_0022: stloc.2 IL_0023: ldloc.2 IL_0024: ldc.i4.1 IL_0025: sub IL_0026: ldc.i4.1 IL_0027: bgt.un.s IL_002d IL_0029: ldc.i4.1 IL_002a: stloc.3 IL_002b: br.s IL_002f IL_002d: ldc.i4.0 IL_002e: stloc.3 IL_002f: ldloc.3 IL_0030: ret } "); } [Fact] public void NonBoxingUnionMatching_MemberProvider_Misc_35() { var src = @" class C1(int f1, int f2) { public int F11 = f1; public int F12 = f2; } class C2(int f11, int f12, int f2) : C1(f11, f12) { public int F2 = f2; } class C3(int f1, int f2) : C1(f1, f2) { } [System.Runtime.CompilerServices.Union] struct S1 : S1.IUnionMembers { private readonly object _value; public S1(C1 x) { _value = x; } public S1(C2 x) { _value = x; } public S1(C3 x) { _value = x; } object IUnionMembers.Value { get { System.Console.Write(""get_Value ""); return _value; } } public interface IUnionMembers { public static S1 Create(C1 x) => new S1(x); public static S1 Create(C2 x) => new S1(x); public static S1 Create(C3 x) => new S1(x); public object Value { get; } } static void Main() { S1[] s = [new S1(), new S1(new C3(1, 1)), new S1(new C3(1, 3)), new S1(new C3(2, 3)), new S1(new C3(2, 4)), new S1(new C2(1, 1, 1)), new S1(new C2(1, 3, 1)), new S1(new C2(2, 3, 1)), new S1(new C2(2, 4, 1)), new S1(new C2(1, 1, 2)), new S1(new C2(1, 3, 2)), new S1(new C2(2, 3, 2)), new S1(new C2(2, 4, 2))]; foreach (var s1 in s) { var t = Test1(s1); System.Console.WriteLine(); System.Console.WriteLine(t); } } static bool Test1(S1 u) { return u is not ((C1 { F11: 1 } or C2 { F2: 2 }) and C1 { F12: 3 }); } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); VerifyDecisionDagDump<IsPatternExpressionSyntax>(comp, @"[0]: t1 = t0.Value; [1] [1]: t1 is C1 ? [2] : [12] [2]: t2 = (C1)t1; [3] [3]: t3 = t2.F11; [4] [4]: t3 == 1 ? [9] : [5] [5]: t1 is C2 ? [6] : [12] [6]: t4 = (C2)t1; [7] [7]: t5 = t4.F2; [8] [8]: t5 == 2 ? [9] : [12] [9]: t6 = t2.F12; [10] [10]: t6 == 3 ? [11] : [12] [11]: leaf <isPatternFailure> `(C1 { F11: 1 } or C2 { F2: 2 }) and C1 { F12: 3 }` [12]: leaf <isPatternSuccess> `u is not ((C1 { F11: 1 } or C2 { F2: 2 }) and C1 { F12: 3 })` ", forLowering: true); var verifier = CompileAndVerify(comp, expectedOutput: @" get_Value True get_Value True get_Value False get_Value True get_Value True get_Value True get_Value False get_Value True get_Value True get_Value True get_Value False get_Value False get_Value True ").VerifyDiagnostics(); verifier.VerifyIL("S1.Test1", @" { // Code size 72 (0x48) .maxstack 2 .locals init (object V_0, C1 V_1, C2 V_2, bool V_3) IL_0000: ldarga.s V_0 IL_0002: constrained. ""S1"" IL_0008: callvirt ""object S1.IUnionMembers.Value.get"" IL_000d: stloc.0 IL_000e: ldloc.0 IL_000f: isinst ""C1"" IL_0014: stloc.1 IL_0015: ldloc.1 IL_0016: brfalse.s IL_0041 IL_0018: ldloc.1 IL_0019: ldfld ""int C1.F11"" IL_001e: ldc.i4.1 IL_001f: beq.s IL_0034 IL_0021: ldloc.0 IL_0022: isinst ""C2"" IL_0027: stloc.2 IL_0028: ldloc.2 IL_0029: brfalse.s IL_0041 IL_002b: ldloc.2 IL_002c: ldfld ""int C2.F2"" IL_0031: ldc.i4.2 IL_0032: bne.un.s IL_0041 IL_0034: ldloc.1 IL_0035: ldfld ""int C1.F12"" IL_003a: ldc.i4.3 IL_003b: bne.un.s IL_0041 IL_003d: ldc.i4.1 IL_003e: stloc.3 IL_003f: br.s IL_0043 IL_0041: ldc.i4.0 IL_0042: stloc.3 IL_0043: ldloc.3 IL_0044: ldc.i4.0 IL_0045: ceq IL_0047: ret } "); } [Fact] public void NonBoxingUnionMatching_MemberProvider_Misc_36() { var src = @" class C1(int f1, int f2) { public int F11 = f1; public int F12 = f2; } class C2(int f11, int f12, int f2) : C1(f11, f12) { public int F2 = f2; } class C3(int f1, int f2) : C1(f1, f2) { } [System.Runtime.CompilerServices.Union] struct S1 : S1.IUnionMembers { private readonly object _value; public S1(C1 x) { _value = x; } public S1(C2 x) { _value = x; } public S1(C3 x) { _value = x; } object IUnionMembers.Value { get { System.Console.Write(""get_Value ""); return _value; } } bool IUnionMembers.TryGetValue(out C1 x) { System.Console.Write(""TryGetValue(C1) ""); x = _value as C1; return x != null; } bool IUnionMembers.TryGetValue(out C2 x) { System.Console.Write(""TryGetValue(C2) ""); x = _value as C2; return x != null; } bool IUnionMembers.TryGetValue(out C3 x) { System.Console.Write(""TryGetValue(C3) ""); x = _value as C3; return x != null; } public interface IUnionMembers { public static S1 Create(C1 x) => new S1(x); public static S1 Create(C2 x) => new S1(x); public static S1 Create(C3 x) => new S1(x); public object Value { get; } public bool TryGetValue(out C1 x); public bool TryGetValue(out C2 x); public bool TryGetValue(out C3 x); } static void Main() { S1[] s = [new S1(), new S1(new C3(1, 1)), new S1(new C3(1, 3)), new S1(new C3(2, 3)), new S1(new C3(2, 4)), new S1(new C2(1, 1, 1)), new S1(new C2(1, 3, 1)), new S1(new C2(2, 3, 1)), new S1(new C2(2, 4, 1)), new S1(new C2(1, 1, 2)), new S1(new C2(1, 3, 2)), new S1(new C2(2, 3, 2)), new S1(new C2(2, 4, 2))]; foreach (var s1 in s) { var t = Test1(s1); System.Console.WriteLine(); System.Console.WriteLine(t); } } static bool Test1(S1 u) { return u is not ((C1 { F11: 1 } or C2 { F2: 2 }) and C1 { F12: 3 }); } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); VerifyDecisionDagDump<IsPatternExpressionSyntax>(comp, @"[0]: TryGetValue(C1): (Item1, ReturnItem) t1 = t0; [1] [1]: t1.ReturnItem == True ? [2] : [13] [2]: t2 = (C1)t1.Item1; [3] [3]: t3 = t2.F11; [4] [4]: t3 == 1 ? [10] : [5] [5]: TryGetValue(C2): (Item1, ReturnItem) t4 = t0; [6] [6]: t4.ReturnItem == True ? [7] : [13] [7]: t5 = (C2)t4.Item1; [8] [8]: t6 = t5.F2; [9] [9]: t6 == 2 ? [10] : [13] [10]: t7 = t2.F12; [11] [11]: t7 == 3 ? [12] : [13] [12]: leaf <isPatternFailure> `(C1 { F11: 1 } or C2 { F2: 2 }) and C1 { F12: 3 }` [13]: leaf <isPatternSuccess> `u is not ((C1 { F11: 1 } or C2 { F2: 2 }) and C1 { F12: 3 })` ", forLowering: true); var verifier = CompileAndVerify(comp, expectedOutput: @" TryGetValue(C1) True TryGetValue(C1) True TryGetValue(C1) False TryGetValue(C1) TryGetValue(C2) True TryGetValue(C1) TryGetValue(C2) True TryGetValue(C1) True TryGetValue(C1) False TryGetValue(C1) TryGetValue(C2) True TryGetValue(C1) TryGetValue(C2) True TryGetValue(C1) True TryGetValue(C1) False TryGetValue(C1) TryGetValue(C2) False TryGetValue(C1) TryGetValue(C2) True ").VerifyDiagnostics(); verifier.VerifyIL("S1.Test1", @" { // Code size 74 (0x4a) .maxstack 2 .locals init (C1 V_0, C1 V_1, C2 V_2, bool V_3) IL_0000: ldarga.s V_0 IL_0002: ldloca.s V_0 IL_0004: constrained. ""S1"" IL_000a: callvirt ""bool S1.IUnionMembers.TryGetValue(out C1)"" IL_000f: brfalse.s IL_0043 IL_0011: ldloc.0 IL_0012: stloc.1 IL_0013: ldloc.1 IL_0014: ldfld ""int C1.F11"" IL_0019: ldc.i4.1 IL_001a: beq.s IL_0036 IL_001c: ldarga.s V_0 IL_001e: ldloca.s V_2 IL_0020: constrained. ""S1"" IL_0026: callvirt ""bool S1.IUnionMembers.TryGetValue(out C2)"" IL_002b: brfalse.s IL_0043 IL_002d: ldloc.2 IL_002e: ldfld ""int C2.F2"" IL_0033: ldc.i4.2 IL_0034: bne.un.s IL_0043 IL_0036: ldloc.1 IL_0037: ldfld ""int C1.F12"" IL_003c: ldc.i4.3 IL_003d: bne.un.s IL_0043 IL_003f: ldc.i4.1 IL_0040: stloc.3 IL_0041: br.s IL_0045 IL_0043: ldc.i4.0 IL_0044: stloc.3 IL_0045: ldloc.3 IL_0046: ldc.i4.0 IL_0047: ceq IL_0049: ret } "); } [Fact] public void NonBoxingUnionMatching_MemberProvider_Misc_37() { var src = @" class C1(int f1, int f2) { public int F11 = f1; public int F12 = f2; } class C2(int f11, int f12, int f2) : C1(f11, f12) { public int F2 = f2; } class C3(int f1, int f2) : C1(f1, f2) { } [System.Runtime.CompilerServices.Union] struct S1 : S1.IUnionMembers { private readonly object _value; public S1(C1 x) { _value = x; } public S1(C2 x) { _value = x; } public S1(C3 x) { _value = x; } object IUnionMembers.Value { get { System.Console.Write(""get_Value ""); return _value; } } bool IUnionMembers.TryGetValue(out C1 x) { System.Console.Write(""TryGetValue(C1) ""); x = _value as C1; return x != null; } bool IUnionMembers.TryGetValue(out C2 x) { System.Console.Write(""TryGetValue(C2) ""); x = _value as C2; return x != null; } bool IUnionMembers.TryGetValue(out C3 x) { System.Console.Write(""TryGetValue(C3) ""); x = _value as C3; return x != null; } public interface IUnionMembers { public static S1 Create(C1 x) => new S1(x); public static S1 Create(C2 x) => new S1(x); public static S1 Create(C3 x) => new S1(x); public object Value { get; } public bool TryGetValue(out C1 x); public bool TryGetValue(out C2 x); public bool TryGetValue(out C3 x); } static void Main() { S1[] s = [new S1(), new S1(new C3(1, 1)), new S1(new C3(1, 3)), new S1(new C3(2, 3)), new S1(new C3(2, 4)), new S1(new C2(1, 1, 1)), new S1(new C2(1, 3, 1)), new S1(new C2(2, 3, 1)), new S1(new C2(2, 4, 1)), new S1(new C2(1, 1, 2)), new S1(new C2(1, 3, 2)), new S1(new C2(2, 3, 2)), new S1(new C2(2, 4, 2))]; foreach (var s1 in s) { var t = Test1(s1); System.Console.WriteLine(); System.Console.WriteLine(t); } } static bool Test1(S1 u) { return u is not ((C2 { F2: 2 } or C1 { F11: 1 }) and C1 { F12: 3 }); } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); VerifyDecisionDagDump<IsPatternExpressionSyntax>(comp, @"[0]: TryGetValue(C2): (Item1, ReturnItem) t1 = t0; [1] [1]: t1.ReturnItem == True ? [2] : [11] [2]: t2 = (C2)t1.Item1; [3] [3]: t3 = t2.F2; [4] [4]: t3 == 2 ? [5] : [6] [5]: t4 = (C1)t1.Item1; [10] [6]: t4 = (C1)t1.Item1; [7] [7]: PassThrough t4; [8] [8]: t6 = t4.F11; [9] [9]: t6 == 1 ? [10] : [19] [10]: PassThrough t4; [16] [11]: TryGetValue(C1): (Item1, ReturnItem) t7 = t0; [12] [12]: t7.ReturnItem == True ? [13] : [19] [13]: t4 = (C1)t7.Item1; [14] [14]: t6 = t4.F11; [15] [15]: t6 == 1 ? [16] : [19] [16]: t8 = t4.F12; [17] [17]: t8 == 3 ? [18] : [19] [18]: leaf <isPatternFailure> `(C2 { F2: 2 } or C1 { F11: 1 }) and C1 { F12: 3 }` [19]: leaf <isPatternSuccess> `u is not ((C2 { F2: 2 } or C1 { F11: 1 }) and C1 { F12: 3 })` ", forLowering: true); var verifier = CompileAndVerify(comp, expectedOutput: @" TryGetValue(C2) TryGetValue(C1) True TryGetValue(C2) TryGetValue(C1) True TryGetValue(C2) TryGetValue(C1) False TryGetValue(C2) TryGetValue(C1) True TryGetValue(C2) TryGetValue(C1) True TryGetValue(C2) True TryGetValue(C2) False TryGetValue(C2) True TryGetValue(C2) True TryGetValue(C2) True TryGetValue(C2) False TryGetValue(C2) False TryGetValue(C2) True ").VerifyDiagnostics(); verifier.VerifyIL("S1.Test1", @" { // Code size 91 (0x5b) .maxstack 2 .locals init (C2 V_0, C1 V_1, C1 V_2, bool V_3) IL_0000: ldarga.s V_0 IL_0002: ldloca.s V_0 IL_0004: constrained. ""S1"" IL_000a: callvirt ""bool S1.IUnionMembers.TryGetValue(out C2)"" IL_000f: brfalse.s IL_002b IL_0011: ldloc.0 IL_0012: ldfld ""int C2.F2"" IL_0017: ldc.i4.2 IL_0018: bne.un.s IL_001e IL_001a: ldloc.0 IL_001b: stloc.1 IL_001c: br.s IL_0047 IL_001e: ldloc.0 IL_001f: stloc.1 IL_0020: ldloc.1 IL_0021: ldfld ""int C1.F11"" IL_0026: ldc.i4.1 IL_0027: bne.un.s IL_0054 IL_0029: br.s IL_0047 IL_002b: ldarga.s V_0 IL_002d: ldloca.s V_2 IL_002f: constrained. ""S1"" IL_0035: callvirt ""bool S1.IUnionMembers.TryGetValue(out C1)"" IL_003a: brfalse.s IL_0054 IL_003c: ldloc.2 IL_003d: stloc.1 IL_003e: ldloc.1 IL_003f: ldfld ""int C1.F11"" IL_0044: ldc.i4.1 IL_0045: bne.un.s IL_0054 IL_0047: ldloc.1 IL_0048: ldfld ""int C1.F12"" IL_004d: ldc.i4.3 IL_004e: bne.un.s IL_0054 IL_0050: ldc.i4.1 IL_0051: stloc.3 IL_0052: br.s IL_0056 IL_0054: ldc.i4.0 IL_0055: stloc.3 IL_0056: ldloc.3 IL_0057: ldc.i4.0 IL_0058: ceq IL_005a: ret } "); } [Fact] public void NonBoxingUnionMatching_MemberProvider_Misc_38() { var src = @" class C1(int f1, int f2) { public int F11 = f1; public int F12 = f2; } class C2(int f11, int f12, int f2) : C1(f11, f12) { public int F2 = f2; } class C3(int f1, int f2) : C1(f1, f2) { } [System.Runtime.CompilerServices.Union] struct S1 : S1.IUnionMembers { private readonly object _value; public S1(C1 x) { _value = x; } public S1(C2 x) { _value = x; } public S1(C3 x) { _value = x; } object IUnionMembers.Value { get { System.Console.Write(""get_Value ""); return _value; } } bool IUnionMembers.TryGetValue(out C2 x) { System.Console.Write(""TryGetValue(C2) ""); x = _value as C2; return x != null; } bool IUnionMembers.TryGetValue(out C3 x) { System.Console.Write(""TryGetValue(C3) ""); x = _value as C3; return x != null; } public interface IUnionMembers { public static S1 Create(C1 x) => new S1(x); public static S1 Create(C2 x) => new S1(x); public static S1 Create(C3 x) => new S1(x); public object Value { get; } public bool TryGetValue(out C2 x); public bool TryGetValue(out C3 x); } static void Main() { S1[] s = [new S1(), new S1(new C3(1, 1)), new S1(new C3(1, 3)), new S1(new C3(2, 3)), new S1(new C3(2, 4)), new S1(new C2(1, 1, 1)), new S1(new C2(1, 3, 1)), new S1(new C2(2, 3, 1)), new S1(new C2(2, 4, 1)), new S1(new C2(1, 1, 2)), new S1(new C2(1, 3, 2)), new S1(new C2(2, 3, 2)), new S1(new C2(2, 4, 2))]; foreach (var s1 in s) { var t = Test1(s1); System.Console.WriteLine(); System.Console.WriteLine(t); } } static bool Test1(S1 u) { return u is not ((C1 { F11: 1 } or C2 { F2: 2 }) and C1 { F12: 3 }); } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); VerifyDecisionDagDump<IsPatternExpressionSyntax>(comp, @"[0]: t1 = t0.Value; [1] [1]: t1 is C1 ? [2] : [13] [2]: t2 = (C1)t1; [3] [3]: t3 = t2.F11; [4] [4]: t3 == 1 ? [10] : [5] [5]: TryGetValue(C2): (Item1, ReturnItem) t4 = t0; [6] [6]: t4.ReturnItem == True ? [7] : [13] [7]: t5 = (C2)t4.Item1; [8] [8]: t6 = t5.F2; [9] [9]: t6 == 2 ? [10] : [13] [10]: t7 = t2.F12; [11] [11]: t7 == 3 ? [12] : [13] [12]: leaf <isPatternFailure> `(C1 { F11: 1 } or C2 { F2: 2 }) and C1 { F12: 3 }` [13]: leaf <isPatternSuccess> `u is not ((C1 { F11: 1 } or C2 { F2: 2 }) and C1 { F12: 3 })` ", forLowering: true); var verifier = CompileAndVerify(comp, expectedOutput: @" get_Value True get_Value True get_Value False get_Value TryGetValue(C2) True get_Value TryGetValue(C2) True get_Value True get_Value False get_Value TryGetValue(C2) True get_Value TryGetValue(C2) True get_Value True get_Value False get_Value TryGetValue(C2) False get_Value TryGetValue(C2) True ").VerifyDiagnostics(); verifier.VerifyIL("S1.Test1", @" { // Code size 77 (0x4d) .maxstack 2 .locals init (C1 V_0, C2 V_1, bool V_2) IL_0000: ldarga.s V_0 IL_0002: constrained. ""S1"" IL_0008: callvirt ""object S1.IUnionMembers.Value.get"" IL_000d: isinst ""C1"" IL_0012: stloc.0 IL_0013: ldloc.0 IL_0014: brfalse.s IL_0046 IL_0016: ldloc.0 IL_0017: ldfld ""int C1.F11"" IL_001c: ldc.i4.1 IL_001d: beq.s IL_0039 IL_001f: ldarga.s V_0 IL_0021: ldloca.s V_1 IL_0023: constrained. ""S1"" IL_0029: callvirt ""bool S1.IUnionMembers.TryGetValue(out C2)"" IL_002e: brfalse.s IL_0046 IL_0030: ldloc.1 IL_0031: ldfld ""int C2.F2"" IL_0036: ldc.i4.2 IL_0037: bne.un.s IL_0046 IL_0039: ldloc.0 IL_003a: ldfld ""int C1.F12"" IL_003f: ldc.i4.3 IL_0040: bne.un.s IL_0046 IL_0042: ldc.i4.1 IL_0043: stloc.2 IL_0044: br.s IL_0048 IL_0046: ldc.i4.0 IL_0047: stloc.2 IL_0048: ldloc.2 IL_0049: ldc.i4.0 IL_004a: ceq IL_004c: ret } "); } [Fact] public void NonBoxingUnionMatching_MemberProvider_Misc_39() { var src = @" class C1(int f1, int f2) { public int F11 = f1; public int F12 = f2; } class C2(int f11, int f12, int f2) : C1(f11, f12) { public int F2 = f2; } class C3(int f1, int f2) : C1(f1, f2) { } [System.Runtime.CompilerServices.Union] struct S1 : S1.IUnionMembers { private readonly object _value; public S1(C1 x) { _value = x; } public S1(C2 x) { _value = x; } public S1(C3 x) { _value = x; } object IUnionMembers.Value { get { System.Console.Write(""get_Value ""); return _value; } } bool IUnionMembers.TryGetValue(out C2 x) { System.Console.Write(""TryGetValue(C2) ""); x = _value as C2; return x != null; } bool IUnionMembers.TryGetValue(out C3 x) { System.Console.Write(""TryGetValue(C3) ""); x = _value as C3; return x != null; } public interface IUnionMembers { public static S1 Create(C1 x) => new S1(x); public static S1 Create(C2 x) => new S1(x); public static S1 Create(C3 x) => new S1(x); public object Value { get; } public bool TryGetValue(out C2 x); public bool TryGetValue(out C3 x); } static void Main() { S1[] s = [new S1(), new S1(new C3(1, 1)), new S1(new C3(1, 3)), new S1(new C3(2, 3)), new S1(new C3(2, 4)), new S1(new C2(1, 1, 1)), new S1(new C2(1, 3, 1)), new S1(new C2(2, 3, 1)), new S1(new C2(2, 4, 1)), new S1(new C2(1, 1, 2)), new S1(new C2(1, 3, 2)), new S1(new C2(2, 3, 2)), new S1(new C2(2, 4, 2))]; foreach (var s1 in s) { var t = Test1(s1); System.Console.WriteLine(); System.Console.WriteLine(t); } } static bool Test1(S1 u) { return u is not ((C2 { F2: 2 } or C1 { F11: 1 }) and C1 { F12: 3 }); } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); VerifyDecisionDagDump<IsPatternExpressionSyntax>(comp, @"[0]: TryGetValue(C2): (Item1, ReturnItem) t1 = t0; [1] [1]: t1.ReturnItem == True ? [2] : [11] [2]: t2 = (C2)t1.Item1; [3] [3]: t3 = t2.F2; [4] [4]: t3 == 2 ? [5] : [6] [5]: t4 = (C1)t1.Item1; [10] [6]: t4 = (C1)t1.Item1; [7] [7]: PassThrough t4; [8] [8]: t6 = t4.F11; [9] [9]: t6 == 1 ? [10] : [19] [10]: PassThrough t4; [16] [11]: t7 = t0.Value; [12] [12]: t7 is C1 ? [13] : [19] [13]: t4 = (C1)t7; [14] [14]: t6 = t4.F11; [15] [15]: t6 == 1 ? [16] : [19] [16]: t8 = t4.F12; [17] [17]: t8 == 3 ? [18] : [19] [18]: leaf <isPatternFailure> `(C2 { F2: 2 } or C1 { F11: 1 }) and C1 { F12: 3 }` [19]: leaf <isPatternSuccess> `u is not ((C2 { F2: 2 } or C1 { F11: 1 }) and C1 { F12: 3 })` ", forLowering: true); var verifier = CompileAndVerify(comp, expectedOutput: @" TryGetValue(C2) get_Value True TryGetValue(C2) get_Value True TryGetValue(C2) get_Value False TryGetValue(C2) get_Value True TryGetValue(C2) get_Value True TryGetValue(C2) True TryGetValue(C2) False TryGetValue(C2) True TryGetValue(C2) True TryGetValue(C2) True TryGetValue(C2) False TryGetValue(C2) False TryGetValue(C2) True ").VerifyDiagnostics(); verifier.VerifyIL("S1.Test1", @" { // Code size 94 (0x5e) .maxstack 2 .locals init (C2 V_0, C1 V_1, bool V_2) IL_0000: ldarga.s V_0 IL_0002: ldloca.s V_0 IL_0004: constrained. ""S1"" IL_000a: callvirt ""bool S1.IUnionMembers.TryGetValue(out C2)"" IL_000f: brfalse.s IL_002b IL_0011: ldloc.0 IL_0012: ldfld ""int C2.F2"" IL_0017: ldc.i4.2 IL_0018: bne.un.s IL_001e IL_001a: ldloc.0 IL_001b: stloc.1 IL_001c: br.s IL_004a IL_001e: ldloc.0 IL_001f: stloc.1 IL_0020: ldloc.1 IL_0021: ldfld ""int C1.F11"" IL_0026: ldc.i4.1 IL_0027: bne.un.s IL_0057 IL_0029: br.s IL_004a IL_002b: ldarga.s V_0 IL_002d: constrained. ""S1"" IL_0033: callvirt ""object S1.IUnionMembers.Value.get"" IL_0038: isinst ""C1"" IL_003d: stloc.1 IL_003e: ldloc.1 IL_003f: brfalse.s IL_0057 IL_0041: ldloc.1 IL_0042: ldfld ""int C1.F11"" IL_0047: ldc.i4.1 IL_0048: bne.un.s IL_0057 IL_004a: ldloc.1 IL_004b: ldfld ""int C1.F12"" IL_0050: ldc.i4.3 IL_0051: bne.un.s IL_0057 IL_0053: ldc.i4.1 IL_0054: stloc.2 IL_0055: br.s IL_0059 IL_0057: ldc.i4.0 IL_0058: stloc.2 IL_0059: ldloc.2 IL_005a: ldc.i4.0 IL_005b: ceq IL_005d: ret } "); } [Fact] public void NonBoxingUnionMatching_MemberProvider_Misc_40() { var src = @" class C1(int f1, int f2) { public int F11 = f1; public int F12 = f2; } class C2(int f11, int f12, int f2) : C1(f11, f12) { public int F2 = f2; } class C3(int f1, int f2) : C1(f1, f2) { } [System.Runtime.CompilerServices.Union] struct S1 : S1.IUnionMembers { private readonly object _value; public S1(C1 x) { _value = x; } public S1(C2 x) { _value = x; } public S1(C3 x) { _value = x; } object IUnionMembers.Value { get { System.Console.Write(""get_Value ""); return _value; } } bool IUnionMembers.TryGetValue(out C1 x) { System.Console.Write(""TryGetValue(C1) ""); x = _value as C1; return x != null; } bool IUnionMembers.TryGetValue(out C3 x) { System.Console.Write(""TryGetValue(C3) ""); x = _value as C3; return x != null; } public interface IUnionMembers { public static S1 Create(C1 x) => new S1(x); public static S1 Create(C2 x) => new S1(x); public static S1 Create(C3 x) => new S1(x); public object Value { get; } public bool TryGetValue(out C1 x); public bool TryGetValue(out C3 x); } static void Main() { S1[] s = [new S1(), new S1(new C3(1, 1)), new S1(new C3(1, 3)), new S1(new C3(2, 3)), new S1(new C3(2, 4)), new S1(new C2(1, 1, 1)), new S1(new C2(1, 3, 1)), new S1(new C2(2, 3, 1)), new S1(new C2(2, 4, 1)), new S1(new C2(1, 1, 2)), new S1(new C2(1, 3, 2)), new S1(new C2(2, 3, 2)), new S1(new C2(2, 4, 2))]; foreach (var s1 in s) { var t = Test1(s1); System.Console.WriteLine(); System.Console.WriteLine(t); } } static bool Test1(S1 u) { return u is not ((C1 { F11: 1 } or C2 { F2: 2 }) and C1 { F12: 3 }); } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); VerifyDecisionDagDump<IsPatternExpressionSyntax>(comp, @"[0]: TryGetValue(C1): (Item1, ReturnItem) t1 = t0; [1] [1]: t1.ReturnItem == True ? [2] : [12] [2]: t2 = (C1)t1.Item1; [3] [3]: t3 = t2.F11; [4] [4]: t3 == 1 ? [9] : [5] [5]: t2 is C2 ? [6] : [12] [6]: t4 = (C2)t2; [7] [7]: t5 = t4.F2; [8] [8]: t5 == 2 ? [9] : [12] [9]: t6 = t2.F12; [10] [10]: t6 == 3 ? [11] : [12] [11]: leaf <isPatternFailure> `(C1 { F11: 1 } or C2 { F2: 2 }) and C1 { F12: 3 }` [12]: leaf <isPatternSuccess> `u is not ((C1 { F11: 1 } or C2 { F2: 2 }) and C1 { F12: 3 })` ", forLowering: true); var verifier = CompileAndVerify(comp, expectedOutput: @" TryGetValue(C1) True TryGetValue(C1) True TryGetValue(C1) False TryGetValue(C1) True TryGetValue(C1) True TryGetValue(C1) True TryGetValue(C1) False TryGetValue(C1) True TryGetValue(C1) True TryGetValue(C1) True TryGetValue(C1) False TryGetValue(C1) False TryGetValue(C1) True ").VerifyDiagnostics(); verifier.VerifyIL("S1.Test1", @" { // Code size 67 (0x43) .maxstack 2 .locals init (C1 V_0, C1 V_1, C2 V_2, bool V_3) IL_0000: ldarga.s V_0 IL_0002: ldloca.s V_0 IL_0004: constrained. ""S1"" IL_000a: callvirt ""bool S1.IUnionMembers.TryGetValue(out C1)"" IL_000f: brfalse.s IL_003c IL_0011: ldloc.0 IL_0012: stloc.1 IL_0013: ldloc.1 IL_0014: ldfld ""int C1.F11"" IL_0019: ldc.i4.1 IL_001a: beq.s IL_002f IL_001c: ldloc.1 IL_001d: isinst ""C2"" IL_0022: stloc.2 IL_0023: ldloc.2 IL_0024: brfalse.s IL_003c IL_0026: ldloc.2 IL_0027: ldfld ""int C2.F2"" IL_002c: ldc.i4.2 IL_002d: bne.un.s IL_003c IL_002f: ldloc.1 IL_0030: ldfld ""int C1.F12"" IL_0035: ldc.i4.3 IL_0036: bne.un.s IL_003c IL_0038: ldc.i4.1 IL_0039: stloc.3 IL_003a: br.s IL_003e IL_003c: ldc.i4.0 IL_003d: stloc.3 IL_003e: ldloc.3 IL_003f: ldc.i4.0 IL_0040: ceq IL_0042: ret } "); } [Fact] public void NonBoxingUnionMatching_MemberProvider_Misc_41() { var src = @" class C1(int f1, int f2) { public int F11 = f1; public int F12 = f2; } class C2(int f11, int f12, int f2) : C1(f11, f12) { public int F2 = f2; } class C3(int f1, int f2) : C1(f1, f2) { } [System.Runtime.CompilerServices.Union] struct S1 : S1.IUnionMembers { private readonly object _value; public S1(C1 x) { _value = x; } public S1(C2 x) { _value = x; } public S1(C3 x) { _value = x; } object IUnionMembers.Value { get { System.Console.Write(""get_Value ""); return _value; } } bool IUnionMembers.TryGetValue(out C1 x) { System.Console.Write(""TryGetValue(C1) ""); x = _value as C1; return x != null; } bool IUnionMembers.TryGetValue(out C3 x) { System.Console.Write(""TryGetValue(C3) ""); x = _value as C3; return x != null; } public interface IUnionMembers { public static S1 Create(C1 x) => new S1(x); public static S1 Create(C2 x) => new S1(x); public static S1 Create(C3 x) => new S1(x); public object Value { get; } public bool TryGetValue(out C1 x); public bool TryGetValue(out C3 x); } static void Main() { S1[] s = [new S1(), new S1(new C3(1, 1)), new S1(new C3(1, 3)), new S1(new C3(2, 3)), new S1(new C3(2, 4)), new S1(new C2(1, 1, 1)), new S1(new C2(1, 3, 1)), new S1(new C2(2, 3, 1)), new S1(new C2(2, 4, 1)), new S1(new C2(1, 1, 2)), new S1(new C2(1, 3, 2)), new S1(new C2(2, 3, 2)), new S1(new C2(2, 4, 2))]; foreach (var s1 in s) { var t = Test1(s1); System.Console.WriteLine(); System.Console.WriteLine(t); } } static bool Test1(S1 u) { return u is not ((C2 { F2: 2 } or C1 { F11: 1 }) and C1 { F12: 3 }); } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); VerifyDecisionDagDump<IsPatternExpressionSyntax>(comp, @"[0]: TryGetValue(C1): (Item1, ReturnItem) t1 = t0; [1] [1]: t1.ReturnItem == True ? [2] : [12] [2]: t2 = (C1)t1.Item1; [3] [3]: t2 is C2 ? [4] : [7] [4]: t3 = (C2)t2; [5] [5]: t4 = t3.F2; [6] [6]: t4 == 2 ? [9] : [7] [7]: t5 = t2.F11; [8] [8]: t5 == 1 ? [9] : [12] [9]: t6 = t2.F12; [10] [10]: t6 == 3 ? [11] : [12] [11]: leaf <isPatternFailure> `(C2 { F2: 2 } or C1 { F11: 1 }) and C1 { F12: 3 }` [12]: leaf <isPatternSuccess> `u is not ((C2 { F2: 2 } or C1 { F11: 1 }) and C1 { F12: 3 })` ", forLowering: true); var verifier = CompileAndVerify(comp, expectedOutput: @" TryGetValue(C1) True TryGetValue(C1) True TryGetValue(C1) False TryGetValue(C1) True TryGetValue(C1) True TryGetValue(C1) True TryGetValue(C1) False TryGetValue(C1) True TryGetValue(C1) True TryGetValue(C1) True TryGetValue(C1) False TryGetValue(C1) False TryGetValue(C1) True ").VerifyDiagnostics(); verifier.VerifyIL("S1.Test1", @" { // Code size 67 (0x43) .maxstack 2 .locals init (C1 V_0, C1 V_1, C2 V_2, bool V_3) IL_0000: ldarga.s V_0 IL_0002: ldloca.s V_0 IL_0004: constrained. ""S1"" IL_000a: callvirt ""bool S1.IUnionMembers.TryGetValue(out C1)"" IL_000f: brfalse.s IL_003c IL_0011: ldloc.0 IL_0012: stloc.1 IL_0013: ldloc.1 IL_0014: isinst ""C2"" IL_0019: stloc.2 IL_001a: ldloc.2 IL_001b: brfalse.s IL_0026 IL_001d: ldloc.2 IL_001e: ldfld ""int C2.F2"" IL_0023: ldc.i4.2 IL_0024: beq.s IL_002f IL_0026: ldloc.1 IL_0027: ldfld ""int C1.F11"" IL_002c: ldc.i4.1 IL_002d: bne.un.s IL_003c IL_002f: ldloc.1 IL_0030: ldfld ""int C1.F12"" IL_0035: ldc.i4.3 IL_0036: bne.un.s IL_003c IL_0038: ldc.i4.1 IL_0039: stloc.3 IL_003a: br.s IL_003e IL_003c: ldc.i4.0 IL_003d: stloc.3 IL_003e: ldloc.3 IL_003f: ldc.i4.0 IL_0040: ceq IL_0042: ret } "); } [Fact] public void NonBoxingUnionMatching_MemberProvider_Misc_42() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 : S1.IUnionMembers { private readonly object _value; public S1(int x) { _value = x; } public S1(System.Runtime.CompilerServices.ITuple x) { _value = x; } object IUnionMembers.Value { get { System.Console.Write(""get_Value ""); return _value; } } bool IUnionMembers.TryGetValue(out System.Runtime.CompilerServices.ITuple x) { System.Console.Write(""TryGetValue(ITuple) ""); x = _value as System.Runtime.CompilerServices.ITuple; return x != null; } public interface IUnionMembers { public static S1 Create(int x) => new S1(x); public static S1 Create(System.Runtime.CompilerServices.ITuple x) => new S1(x); public object Value { get; } public bool TryGetValue(out System.Runtime.CompilerServices.ITuple x); } } class Program { static void Main() { System.Console.Write(Test1(new S1(10))); System.Console.Write(' '); System.Console.Write(Test1(default)); System.Console.Write(' '); System.Console.Write(Test1(new S1(new C()))); } static bool Test1(S1 u) { return u is (_, 10); } } public class C : System.Runtime.CompilerServices.ITuple { int System.Runtime.CompilerServices.ITuple.Length => 2; object System.Runtime.CompilerServices.ITuple.this[int i] => i * 10; } "; var comp = CreateCompilation([src, UnionAttributeSource], targetFramework: TargetFramework.NetCoreApp, options: TestOptions.ReleaseExe); comp.VerifyDiagnostics( // (46,21): error CS1061: 'S1' does not contain a definition for 'Deconstruct' and no accessible extension method 'Deconstruct' accepting a first argument of type 'S1' could be found (are you missing a using directive or an assembly reference?) // return u is (_, 10); Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "(_, 10)").WithArguments("S1", "Deconstruct").WithLocation(46, 21), // (46,21): error CS8129: No suitable 'Deconstruct' instance or extension method was found for type 'S1', with 2 out parameters and a void return type. // return u is (_, 10); Diagnostic(ErrorCode.ERR_MissingDeconstruct, "(_, 10)").WithArguments("S1", "2").WithLocation(46, 21) ); } [Fact] public void NonBoxingUnionMatching_MemberProvider_Misc_43() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 : S1.IUnionMembers { private readonly object _value; public S1(S2<int> x) { _value = x; } public S1(S2<string> x) { _value = x; } public S1(S2<object> x) { _value = x; } object IUnionMembers.Value { get { System.Console.Write(""get_Value ""); return _value; } } bool IUnionMembers.TryGetValue(out S2<int> x) { System.Console.Write(""TryGetValue(S2<int>) ""); if (_value is S2<int> s2) { x = s2; return true; } x = default; return false; } bool IUnionMembers.TryGetValue(out S2<string> x) { System.Console.Write(""TryGetValue(S2<string>) ""); if (_value is S2<string> s2) { x = s2; return true; } x = default; return false; } bool IUnionMembers.TryGetValue(out S2<object> x) { System.Console.Write(""TryGetValue(S2<object>) ""); if (_value is S2<object> s2) { x = s2; return true; } x = default; return false; } public interface IUnionMembers { public static S1 Create(S2<int> x) => new S1(x); public static S1 Create(S2<string> x) => new S1(x); public static S1 Create(S2<object> x) => new S1(x); public object Value { get; } public bool TryGetValue(out S2<int> x); public bool TryGetValue(out S2<string> x); public bool TryGetValue(out S2<object> x); } } struct S2<T> { public T Value; public void Deconstruct(out T value, out int x) { value = Value; x = 0; } } class A; class B; class Program { static void Main() { System.Console.Write(Test1(new S1(new S2<int>() { Value = 10 }))); System.Console.Write(' '); System.Console.Write(Test1(default)); System.Console.Write(' '); System.Console.Write(Test1(new S1(new S2<string>() { Value = ""11"" }))); System.Console.Write(' '); System.Console.Write(Test1(new S1(new S2<int>() { Value = 0 }))); System.Console.Write(' '); System.Console.Write(' '); System.Console.Write(Test2(new S1(new S2<int>() { Value = 10 }))); System.Console.Write(' '); System.Console.Write(Test2(default)); System.Console.Write(' '); System.Console.Write(Test2(new S1(new S2<string>() { Value = ""11"" }))); System.Console.Write(' '); System.Console.Write(Test2(new S1(new S2<int>() { Value = 0 }))); System.Console.Write(' '); System.Console.Write(Test2(new S1(new S2<int>() { Value = 11 }))); System.Console.Write(' '); System.Console.Write(' '); System.Console.Write(Test3(new S1(new S2<int>() { Value = 11 }))); System.Console.Write(' '); System.Console.Write(Test3(default)); System.Console.Write(' '); System.Console.Write(Test3(new S1(new S2<string>() { Value = ""11"" }))); } static bool Test1(S1 u) { return u is S2<int> (10, _); } static bool Test2(S1 u) { return u is S2<int> (10 or 11, _); } static bool Test3(S1 u) { return u is S2<string> (""11"", _) and (['1', '1'], _); } } "; var comp = CreateCompilation([src, UnionAttributeSource], targetFramework: TargetFramework.NetCoreApp, options: TestOptions.ReleaseExe); CompileAndVerify( comp, expectedOutput: ExecutionConditionUtil.IsMonoOrCoreClr ? "TryGetValue(S2<int>) True TryGetValue(S2<int>) False TryGetValue(S2<int>) False TryGetValue(S2<int>) False TryGetValue(S2<int>) True TryGetValue(S2<int>) False TryGetValue(S2<int>) False TryGetValue(S2<int>) False TryGetValue(S2<int>) True TryGetValue(S2<string>) False TryGetValue(S2<string>) False TryGetValue(S2<string>) True" : null, verify: Verification.FailsPEVerify).VerifyDiagnostics(); } [Fact] public void NonBoxingUnionMatching_MemberProvider_Misc_44() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 : S1.IUnionMembers { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } object IUnionMembers.Value { get { System.Console.Write(""get_Value ""); return _value; } } bool IUnionMembers.TryGetValue(out int x) { System.Console.Write(""TryGetValue(int) ""); if (_value is int s2) { x = s2; return true; } x = default; return false; } public interface IUnionMembers { public static S1 Create(int x) => new S1(x); public static S1 Create(string x) => new S1(x); public object Value { get; } public bool TryGetValue(out int x); } } class Program { static void Main() { System.Console.Write(Test1(new S1(10))); System.Console.Write(' '); System.Console.Write(Test1(default)); System.Console.Write(' '); System.Console.Write(Test1(new S1(""11""))); System.Console.Write(' '); System.Console.Write(Test1(new S1(0))); System.Console.Write(' '); System.Console.Write(' '); System.Console.Write(Test2(new S1(10))); System.Console.Write(' '); System.Console.Write(Test2(default)); System.Console.Write(' '); System.Console.Write(Test2(new S1(""11""))); System.Console.Write(' '); System.Console.Write(Test2(new S1(0))); System.Console.Write(' '); System.Console.Write(Test2(new S1(11))); } static bool Test1(S1 u) { return u is int x; } static bool Test2(S1 u) { return u is int x ? (x == 10 || x == 11) : false; } } "; var comp = CreateCompilation([src, UnionAttributeSource], targetFramework: TargetFramework.NetLatest, options: TestOptions.ReleaseExe); CompileAndVerify( comp, expectedOutput: "TryGetValue(int) True TryGetValue(int) False TryGetValue(int) False TryGetValue(int) True TryGetValue(int) True TryGetValue(int) False TryGetValue(int) False TryGetValue(int) False TryGetValue(int) True" ).VerifyDiagnostics(); } [Fact] public void NonBoxingUnionMatching_MemberProvider_Misc_45() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 : S1.IUnionMembers { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } object IUnionMembers.Value { get { System.Console.Write(""get_Value ""); return _value; } } bool IUnionMembers.TryGetValue(out int x) { System.Console.Write(""TryGetValue(int) ""); if (_value is int s2) { x = s2; return true; } x = default; return false; } public interface IUnionMembers { public static S1 Create(int x) => new S1(x); public static S1 Create(string x) => new S1(x); public object Value { get; } public bool TryGetValue(out int x); } } class Program { static void Main() { System.Console.Write(Test1(new S1(10))); System.Console.Write(' '); System.Console.Write(Test1(default)); System.Console.Write(' '); System.Console.Write(Test1(new S1(""11""))); System.Console.Write(' '); System.Console.Write(Test1(new S1(0))); System.Console.Write(' '); System.Console.Write(' '); System.Console.Write(Test2(new S1(10))); System.Console.Write(' '); System.Console.Write(Test2(default)); System.Console.Write(' '); System.Console.Write(Test2(new S1(""11""))); System.Console.Write(' '); System.Console.Write(Test2(new S1(0))); System.Console.Write(' '); System.Console.Write(Test2(new S1(11))); } static bool Test1(S1 u) { return u is >=10; } static bool Test2(S1 u) { return u is <10 or 11; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); CompileAndVerify( comp, expectedOutput: "TryGetValue(int) True TryGetValue(int) False TryGetValue(int) False TryGetValue(int) False TryGetValue(int) False TryGetValue(int) False TryGetValue(int) False TryGetValue(int) True TryGetValue(int) True" ).VerifyDiagnostics(); } [Fact] public void UnionDeclaration_01() { var unionSrc = @" public #line 100 union S1(bool, int) { } "; var consumer = @" class Program { static void Main() { System.Console.Write(Test(10)); System.Console.Write(Test(11)); System.Console.Write(Test(true)); System.Console.Write(Test(false)); System.Console.Write(Test(default)); } static int Test(S1 u) { return u switch { 10 => 1, true => 2, int => 3, bool => 4, _ => 5 }; } } "; var comp1 = CreateCompilation([unionSrc, UnionAttributeSource, IUnionSource, consumer], options: TestOptions.DebugExe); var s1 = comp1.GetTypeByMetadataName("S1"); Assert.True(s1.IsUnionType); Assert.False(s1.IsRecordStruct); Assert.False(s1.IsRecord); VerifyCaseTypes(comp1, "S1", ["System.Boolean", "System.Int32"]); var members = s1.GetMembers(); Assert.Equal(6, members.Length); AssertEx.SequenceEqual(["System.Object? S1.Value.field", "System.Object? S1.Value { get; }", "readonly System.Object? S1.Value.get", "S1.S1(System.Boolean value)", "S1.S1(System.Int32 value)", "S1.S1()"], members.Select(s => s.ToTestDisplayString(includeNonNullable: true))); Assert.False(members[0].IsStatic); Assert.True(members[0].IsImplicitlyDeclared); Assert.False(members[1].IsStatic); Assert.True(members[1].IsImplicitlyDeclared); Assert.False(members[2].IsStatic); Assert.True(members[2].IsImplicitlyDeclared); Assert.False(members[^3].IsStatic); Assert.True(members[^3].IsImplicitlyDeclared); Assert.False(members[^2].IsStatic); Assert.True(members[^2].IsImplicitlyDeclared); var tree = comp1.SyntaxTrees.First(); var model = comp1.GetSemanticModel(tree); var s1Decl = tree.GetRoot().DescendantNodes().OfType<TypeDeclarationSyntax>().Single(); Assert.Equal("S1", s1Decl.Identifier.ToString()); Assert.Empty(members[0].DeclaringSyntaxReferences); Assert.Equal(s1Decl, members[1].DeclaringSyntaxReferences.Single().GetSyntax()); Assert.Equal(s1Decl, members[2].DeclaringSyntaxReferences.Single().GetSyntax()); Assert.Empty(members[^3].DeclaringSyntaxReferences); Assert.Empty(members[^2].DeclaringSyntaxReferences); var location = members[0].Locations.Single(); Assert.Equal(members[1].Locations.Single(), location); location = members[1].Locations.Single(); Assert.Equal(s1Decl, location.SourceTree.GetRoot().FindNode(location.SourceSpan)); location = members[2].Locations.Single(); Assert.Equal(s1Decl, location.SourceTree.GetRoot().FindNode(location.SourceSpan)); location = members[^3].Locations.Single(); Assert.Equal("bool", location.SourceTree.GetRoot().FindNode(location.SourceSpan).ToString()); location = members[^2].Locations.Single(); Assert.Equal("int", location.SourceTree.GetRoot().FindNode(location.SourceSpan).ToString()); Assert.Same(s1, model.GetDeclaredSymbol(s1Decl).GetSymbol()); Assert.Null(model.GetDeclaredSymbol(s1Decl.ParameterList)); Assert.Null(model.GetDeclaredSymbol(s1Decl.ParameterList.Parameters[0])); Assert.Null(model.GetDeclaredSymbol(s1Decl.ParameterList.Parameters[0].Type)); Assert.Null(model.GetDeclaredSymbol(s1Decl.ParameterList.Parameters[1])); Assert.Null(model.GetDeclaredSymbol(s1Decl.ParameterList.Parameters[1].Type)); var typeInfo = model.GetTypeInfo(s1Decl.ParameterList.Parameters[0].Type); Assert.Equal("System.Boolean", typeInfo.Type.ToTestDisplayString()); Assert.Equal("System.Boolean", typeInfo.ConvertedType.ToTestDisplayString()); typeInfo = model.GetTypeInfo(s1Decl.ParameterList.Parameters[1].Type); Assert.Equal("System.Int32", typeInfo.Type.ToTestDisplayString()); Assert.Equal("System.Int32", typeInfo.ConvertedType.ToTestDisplayString()); var verifier = CompileAndVerify(comp1, expectedOutput: "13245").VerifyDiagnostics(); verifier.VerifyTypeIL("S1", @" .class public sequential ansi sealed beforefieldinit S1 extends [netstandard]System.ValueType implements System.Runtime.CompilerServices.IUnion { .custom instance void System.Runtime.CompilerServices.NullableContextAttribute::.ctor(uint8) = ( 01 00 02 00 00 ) .custom instance void System.Runtime.CompilerServices.NullableAttribute::.ctor(uint8) = ( 01 00 00 00 00 ) .custom instance void System.Runtime.CompilerServices.UnionAttribute::.ctor() = ( 01 00 00 00 ) .interfaceimpl type System.Runtime.CompilerServices.IUnion .custom instance void System.Runtime.CompilerServices.NullableAttribute::.ctor(uint8) = ( 01 00 00 00 00 ) // Fields .field private initonly object '<Value>k__BackingField' .custom instance void [netstandard]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) .custom instance void [netstandard]System.Diagnostics.DebuggerBrowsableAttribute::.ctor(valuetype [netstandard]System.Diagnostics.DebuggerBrowsableState) = ( 01 00 00 00 00 00 00 00 ) // Methods .method public final hidebysig specialname newslot virtual instance object get_Value () cil managed { .custom instance void System.Runtime.CompilerServices.IsReadOnlyAttribute::.ctor() = ( 01 00 00 00 ) .custom instance void [netstandard]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) // Method begins at RVA 0x20a2 // Code size 7 (0x7) .maxstack 8 IL_0000: ldarg.0 IL_0001: ldfld object S1::'<Value>k__BackingField' IL_0006: ret } // end of method S1::get_Value .method public hidebysig specialname rtspecialname instance void .ctor ( bool 'value' ) cil managed { .custom instance void [netstandard]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) // Method begins at RVA 0x20aa // Code size 14 (0xe) .maxstack 8 IL_0000: ldarg.0 IL_0001: ldarg.1 IL_0002: box [netstandard]System.Boolean IL_0007: stfld object S1::'<Value>k__BackingField' IL_000c: nop IL_000d: ret } // end of method S1::.ctor .method public hidebysig specialname rtspecialname instance void .ctor ( int32 'value' ) cil managed { .custom instance void [netstandard]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) // Method begins at RVA 0x20b9 // Code size 14 (0xe) .maxstack 8 IL_0000: ldarg.0 IL_0001: ldarg.1 IL_0002: box [netstandard]System.Int32 IL_0007: stfld object S1::'<Value>k__BackingField' IL_000c: nop IL_000d: ret } // end of method S1::.ctor // Properties .property instance object Value() { .get instance object S1::get_Value() } } // end of class S1 ".Replace("[netstandard]", ExecutionConditionUtil.IsMonoOrCoreClr ? "[netstandard]" : "[mscorlib]")); var comp2 = CreateCompilation(consumer, references: [verifier.GetImageReference()], options: TestOptions.DebugExe); var s12 = comp2.GetTypeByMetadataName("S1"); Assert.True(s12.IsUnionType); VerifyCaseTypes(comp2, "S1", ["System.Boolean", "System.Int32"]); members = s12.GetMembers(); AssertEx.SequenceEqual(["System.Object? S1.<Value>k__BackingField", "S1.S1()", "readonly System.Object? S1.Value.get", "S1.S1(System.Boolean value)", "S1.S1(System.Int32 value)", "readonly System.Object? S1.Value { get; }"], members.Select(s => s.ToTestDisplayString(includeNonNullable: true))); CompileAndVerify(comp2, expectedOutput: "13245").VerifyDiagnostics(); var unionAttributeSource = @" namespace System.Runtime.CompilerServices { public class UnionAttribute : System.Attribute { } } "; var ref1 = CreateCompilation(unionAttributeSource).EmitToImageReference(); var ref2 = CreateCompilation(unionAttributeSource).EmitToImageReference(); var comp3 = CreateCompilation([unionSrc, IUnionSource], references: [ref1, ref2]); comp3.VerifyEmitDiagnostics( // (100,7): error CS0656: Missing compiler required member 'System.Runtime.CompilerServices.UnionAttribute..ctor' // union S1(bool, int) Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "S1").WithArguments("System.Runtime.CompilerServices.UnionAttribute", ".ctor").WithLocation(100, 7) ); var comp4 = CreateCompilation(["extern alias ref1; [ref1::System.Runtime.CompilerServices.Union]" + unionSrc, IUnionSource], references: [ref1.WithAliases(["ref1"]), ref2.WithAliases(["ref2"])]); verifier = CompileAndVerify( comp4, symbolValidator: (m) => { var s1 = m.GlobalNamespace.GetTypeMember("S1"); Assert.Equal("S1", s1.Name); CSharpAttributeData attr = s1.GetAttributes().Where(a => a.AttributeClass.Name.StartsWith("Union")).Single(); AssertEx.Equal("System.Runtime.CompilerServices.UnionAttribute", attr.ToString()); Assert.NotEqual(s1.ContainingModule, attr.AttributeClass.ContainingModule); }).VerifyDiagnostics(); var comp5 = CreateCompilation(consumer, references: [verifier.GetImageReference()], options: TestOptions.DebugExe); CompileAndVerify(comp5, expectedOutput: "13245").VerifyDiagnostics(); var comp6 = CreateCompilation(["[System.Runtime.CompilerServices.Union]" + unionSrc, UnionAttributeSource, IUnionSource], references: [ref1.WithAliases(["ref1"]), ref2.WithAliases(["ref2"])]); verifier = CompileAndVerify( comp6, symbolValidator: (m) => { var s1 = m.GlobalNamespace.GetTypeMember("S1"); Assert.Equal("S1", s1.Name); CSharpAttributeData attr = s1.GetAttributes().Where(a => a.AttributeClass.Name.StartsWith("Union")).Single(); AssertEx.Equal("System.Runtime.CompilerServices.UnionAttribute", attr.ToString()); Assert.Same(s1.ContainingModule, attr.AttributeClass.ContainingModule); }).VerifyDiagnostics(); var comp7 = CreateCompilation(consumer, references: [verifier.GetImageReference()], options: TestOptions.DebugExe); CompileAndVerify(comp7, expectedOutput: "13245").VerifyDiagnostics(); } [Fact] public void UnionDeclaration_02() { var src = @" partial #line 100 union S1(int, bool) { } partial #line 200 union S1(int, long) { } "; var comp = CreateCompilation([src, UnionAttributeSource, IUnionSource]); comp.VerifyEmitDiagnostics( // (200,9): error CS8863: Only a single partial type declaration may have a parameter list // union S1(int, long) Diagnostic(ErrorCode.ERR_MultipleRecordParameterLists, "(int, long)").WithLocation(200, 9) ); Assert.True(comp.GetTypeByMetadataName("S1").IsUnionType); VerifyCaseTypes(comp, "S1", ["System.Int32", "System.Boolean"]); } [Fact] public void UnionDeclaration_03() { var src = @" partial union S1(int, bool) { } partial union S1 { } "; var comp = CreateCompilation([src, UnionAttributeSource, IUnionSource]); comp.VerifyEmitDiagnostics(); Assert.True(comp.GetTypeByMetadataName("S1").IsUnionType); VerifyCaseTypes(comp, "S1", ["System.Int32", "System.Boolean"]); } [Fact] public void UnionDeclaration_04() { var src = @" partial union S1 { } partial union S1(int, bool) { } "; var comp = CreateCompilation([src, UnionAttributeSource, IUnionSource]); comp.VerifyEmitDiagnostics(); Assert.True(comp.GetTypeByMetadataName("S1").IsUnionType); VerifyCaseTypes(comp, "S1", ["System.Int32", "System.Boolean"]); } [Fact] public void UnionDeclaration_05() { var src = @" partial struct S1 { } partial union S1(int, bool) { } "; var comp = CreateCompilation([src, UnionAttributeSource, IUnionSource]); comp.VerifyEmitDiagnostics( // (6,15): error CS0261: Partial declarations of 'S1' must be all classes, all record classes, all structs, all unions, all record structs, or all interfaces // partial union S1(int, bool) Diagnostic(ErrorCode.ERR_PartialTypeKindConflict, "S1").WithArguments("S1").WithLocation(6, 15) ); } [Fact] public void UnionDeclaration_06() { var src = @" partial union S1(int, bool) { } partial record S1 { } "; var comp = CreateCompilation([src, UnionAttributeSource, IUnionSource]); comp.VerifyEmitDiagnostics( // (6,16): error CS0261: Partial declarations of 'S1' must be all classes, all record classes, all structs, all unions, all record structs, or all interfaces // partial record S1 Diagnostic(ErrorCode.ERR_PartialTypeKindConflict, "S1").WithArguments("S1").WithLocation(6, 16) ); } [Fact] public void UnionDeclaration_07() { var src = @" static union S1(int, bool) { } "; var comp = CreateCompilation([src, UnionAttributeSource, IUnionSource]); comp.VerifyEmitDiagnostics( // (2,14): error CS0106: The modifier 'static' is not valid for this item // static union S1(int, bool) Diagnostic(ErrorCode.ERR_BadMemberFlag, "S1").WithArguments("static").WithLocation(2, 14) ); } [Fact] public void UnionDeclaration_08() { var src = @" #line 100 union S1(int, int) { } "; var comp = CreateCompilation([src, UnionAttributeSource, IUnionSource]); // https://github.com/dotnet/roslyn/issues/82636: Consider reporting a more informative error. comp.VerifyEmitDiagnostics( // (100,15): error CS0111: Type 'S1' already defines a member called 'S1' with the same parameter types // union S1(int, int) Diagnostic(ErrorCode.ERR_MemberAlreadyExists, "int").WithArguments("S1", "S1").WithLocation(100, 15) ); } [Fact] public void UnionDeclaration_09() { var src = @" #line 100 union S1(int, __arglist) { } "; var comp = CreateCompilation([src, UnionAttributeSource, IUnionSource]); comp.VerifyEmitDiagnostics( // (100,15): error CS1669: __arglist is not valid in this context // union S1(int, __arglist) Diagnostic(ErrorCode.ERR_IllegalVarArgs, "__arglist").WithLocation(100, 15) ); } [Fact] public void UnionDeclaration_10() { var src = @" #line 100 union S1; "; var comp = CreateCompilation([src, UnionAttributeSource, IUnionSource]); comp.VerifyEmitDiagnostics( // (100,7): error CS9370: A union declaration must specify at least one case type. // union S1; Diagnostic(ErrorCode.ERR_UnionDeclarationNeedsCaseTypes, "S1").WithLocation(100, 7) ); Assert.True(comp.GetTypeByMetadataName("S1").IsUnionType); VerifyCaseTypes(comp, "S1", []); } [Fact] public void UnionDeclaration_11() { var src = @" #line 100 union S1(); "; var comp = CreateCompilation([src, UnionAttributeSource, IUnionSource]); // https://github.com/dotnet/roslyn/issues/82636: Consider repoting a more informative error. Perhaps something like: "A union declaration must specify at least one case type." comp.VerifyEmitDiagnostics( // (100,10): error CS1031: Type expected // union S1(); Diagnostic(ErrorCode.ERR_TypeExpected, ")").WithLocation(100, 10) ); Assert.True(comp.GetTypeByMetadataName("S1").IsUnionType); VerifyCaseTypes(comp, "S1", ["?"]); } [Fact] public void UnionDeclaration_12_MissingUnionAttribute() { var unionSrc = @" #line 2 union S1(int, bool) { } "; var comp = CreateCompilation([unionSrc, IUnionSource]); comp.VerifyEmitDiagnostics( // (2,7): error CS0656: Missing compiler required member 'System.Runtime.CompilerServices.UnionAttribute..ctor' // union S1(int, bool) Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "S1").WithArguments("System.Runtime.CompilerServices.UnionAttribute", ".ctor").WithLocation(2, 7) ); Assert.True(comp.GetTypeByMetadataName("S1").IsUnionType); VerifyCaseTypes(comp, "S1", ["System.Int32", "System.Boolean"]); } [Fact] public void UnionDeclaration_13() { var src = @" union S1( #nullable enable string? #nullable restore ); "; var comp = CreateCompilation([src, UnionAttributeSource, IUnionSource]); Assert.True(comp.GetTypeByMetadataName("S1").IsUnionType); VerifyCaseTypes(comp, "S1", ["System.String"]); CompileAndVerify(comp, symbolValidator: verify, sourceSymbolValidator: verify).VerifyDiagnostics(); void verify(ModuleSymbol m) { var s1 = m.GlobalNamespace.GetTypeMember("S1"); AssertEx.Equal("S1..ctor(System.String? value)", s1.InstanceConstructors.Where(c => c.ParameterCount == 1).Single().ToTestDisplayString()); } } [Fact] public void UnionDeclaration_14() { var src = @" union S1<T>(T); "; var comp = CreateCompilation([src, UnionAttributeSource, IUnionSource]); Assert.True(comp.GetTypeByMetadataName("S1`1").IsUnionType); VerifyCaseTypes(comp, "S1`1", ["T"]); comp.VerifyEmitDiagnostics(); } [Fact] public void UnionDeclaration_15() { var src = @" #line 100 union S1(System.ArgIterator, int); "; var comp = CreateCompilation([src, UnionAttributeSource, IUnionSource], targetFramework: TargetFramework.NetCoreApp); Assert.True(comp.GetTypeByMetadataName("S1").IsUnionType); VerifyCaseTypes(comp, "S1", ["System.ArgIterator", "System.Int32"]); comp.VerifyEmitDiagnostics( // (100,10): error CS9371: Cannot convert type 'ArgIterator' to 'object' via an implicit reference or boxing conversion // union S1(System.ArgIterator, int); Diagnostic(ErrorCode.ERR_NoImplicitConversionToObject, "System.ArgIterator").WithArguments("System.ArgIterator").WithLocation(100, 10) ); } [Fact] public void UnionDeclaration_16() { var src = @" #pragma warning disable CS1718 // Comparison made to same variable; did you mean to compare something else? union S1(C1); class C1 { public override int GetHashCode() => 1; public override bool Equals(object obj) => obj is C1; } class Program { static void Main() { var s11 = new S1(new C1()); var s12 = new S1(new C1()); var s13 = new S1(); System.Console.WriteLine(s11.ToString()); System.Console.WriteLine(s13.ToString()); System.Console.WriteLine(s11.Equals(s11)); System.Console.WriteLine(s11.Equals(s12)); System.Console.WriteLine(s11.Equals(s13)); System.Console.WriteLine(s13.Equals(s13)); } } "; var comp1 = CreateCompilation([src, UnionAttributeSource, IUnionSource], options: TestOptions.DebugExe); CompileAndVerify(comp1, expectedOutput: @" S1 S1 True True False True ").VerifyDiagnostics(); } [Fact] public void UnionDeclaration_17() { var src = @" union S1(C1) { public void OtherMember() { System.Console.Write(1); } } class C1 { } class Program { static void Main() { default(S1).OtherMember(); } } "; var comp1 = CreateCompilation([src, UnionAttributeSource, IUnionSource], options: TestOptions.DebugExe); CompileAndVerify(comp1, expectedOutput: "1").VerifyDiagnostics(); } [Fact] public void UnionDeclaration_18() { var src = @" #line 100 union S1(System.Nullable<string>); "; var comp = CreateCompilation([src, UnionAttributeSource, IUnionSource], targetFramework: TargetFramework.NetCoreApp); Assert.True(comp.GetTypeByMetadataName("S1").IsUnionType); VerifyCaseTypes(comp, "S1", ["System.String?"]); comp.VerifyEmitDiagnostics( // (100,10): error CS9371: Cannot convert type 'string?' to 'object' via an implicit reference or boxing conversion // union S1(System.Nullable<string>); Diagnostic(ErrorCode.ERR_NoImplicitConversionToObject, "System.Nullable<string>").WithArguments("string?").WithLocation(100, 10), // (100,10): error CS0453: The type 'string' must be a non-nullable value type in order to use it as parameter 'T' in the generic type or method 'Nullable<T>' // union S1(System.Nullable<string>); Diagnostic(ErrorCode.ERR_ValConstraintNotSatisfied, "System.Nullable<string>").WithArguments("System.Nullable<T>", "T", "string").WithLocation(100, 10) ); } [Fact] public void UnionDeclaration_19_MissingObject() { var src = @" #line 100 union S1(int); "; var comp = CreateCompilation([src, UnionAttributeSource, IUnionSource]); comp.MakeTypeMissing(SpecialType.System_Object); comp.VerifyEmitDiagnostics( // (100,7): error CS0518: Predefined type 'System.Object' is not defined or imported // union S1(int); Diagnostic(ErrorCode.ERR_PredefinedTypeNotFound, "S1").WithArguments("System.Object").WithLocation(100, 7), // (100,7): error CS0518: Predefined type 'System.Object' is not defined or imported // union S1(int); Diagnostic(ErrorCode.ERR_PredefinedTypeNotFound, "S1").WithArguments("System.Object").WithLocation(100, 7), // (100000,9): error CS0518: Predefined type 'System.Object' is not defined or imported // object? Value { get; } Diagnostic(ErrorCode.ERR_PredefinedTypeNotFound, "object").WithArguments("System.Object").WithLocation(100000, 9) ); } [Fact] public void UnionDeclaration_20() { var src = @" #pragma warning disable CS1718 // Comparison made to same variable; did you mean to compare something else? union S1(object); class Program { static void Main() { var s11 = new S1(123); System.Console.WriteLine(s11.Value); } } "; var comp1 = CreateCompilation([src, UnionAttributeSource, IUnionSource], options: TestOptions.DebugExe); CompileAndVerify(comp1, expectedOutput: @"123").VerifyDiagnostics(); } [Fact] public void UnionDeclaration_21() { var src = @" #pragma warning disable CS1718 // Comparison made to same variable; did you mean to compare something else? union S1(int?); class Program { static void Main() { var s11 = new S1(123); System.Console.WriteLine(s11.Value); } } "; var comp1 = CreateCompilation([src, UnionAttributeSource, IUnionSource], options: TestOptions.DebugExe); CompileAndVerify(comp1, expectedOutput: @"123").VerifyDiagnostics(); } [Fact] public void UnionDeclaration_22_IUnion_Missing() { var unionSrc = @" #line 2 union S1(int, bool) { } "; var comp = CreateCompilation([unionSrc, UnionAttributeSource]); comp.VerifyEmitDiagnostics( // (2,7): error CS0518: Predefined type 'System.Runtime.CompilerServices.IUnion' is not defined or imported // union S1(int, bool) Diagnostic(ErrorCode.ERR_PredefinedTypeNotFound, "S1").WithArguments("System.Runtime.CompilerServices.IUnion").WithLocation(2, 7) ); Assert.True(comp.GetTypeByMetadataName("S1").IsUnionType); VerifyCaseTypes(comp, "S1", ["System.Int32", "System.Boolean"]); } [Fact] public void UnionDeclaration_22_IUnion_InBaseInterfaces() { var unionSrc = @" union S1(int, bool) : System.Runtime.CompilerServices.IUnion { } class Program { static void Main() { System.Console.Write(Test(10)); System.Console.Write(Test(11)); System.Console.Write(Test(true)); System.Console.Write(Test(false)); System.Console.Write(Test(default)); } static int Test(S1 u) { return ((System.Runtime.CompilerServices.IUnion)u).Value switch { 10 => 1, true => 2, int => 3, bool => 4, _ => 5 }; } } "; var comp = CreateCompilation([unionSrc, UnionAttributeSource, IUnionSource], options: TestOptions.DebugExe); CompileAndVerify(comp, symbolValidator: checkInterfaces, sourceSymbolValidator: checkInterfaces, expectedOutput: "13245").VerifyDiagnostics(); void checkInterfaces(ModuleSymbol m) { var s1 = m.GlobalNamespace.GetTypeMember("S1"); Assert.Equal("System.Runtime.CompilerServices.IUnion", s1.InterfacesNoUseSiteDiagnostics().Single().ToTestDisplayString()); } } [Fact] public void UnionDeclaration_23_IUnion() { var unionSrc = @" union S1(int, bool) { } class Program { static void Main() { System.Console.Write(Test(10)); System.Console.Write(Test(11)); System.Console.Write(Test(true)); System.Console.Write(Test(false)); System.Console.Write(Test(default)); } static int Test(S1 u) { return ((System.Runtime.CompilerServices.IUnion)u).Value switch { 10 => 1, true => 2, int => 3, bool => 4, _ => 5 }; } } "; var comp = CreateCompilation([unionSrc, UnionAttributeSource, IUnionSource], options: TestOptions.DebugExe); CompileAndVerify(comp, symbolValidator: checkInterfaces, sourceSymbolValidator: checkInterfaces, expectedOutput: "13245").VerifyDiagnostics(); void checkInterfaces(ModuleSymbol m) { var s1 = m.GlobalNamespace.GetTypeMember("S1"); Assert.Equal("System.Runtime.CompilerServices.IUnion", s1.InterfacesNoUseSiteDiagnostics().Single().ToTestDisplayString()); } } [Fact] public void UnionDeclaration_24_IUnion_ValueNullabilityMismatch() { var unionSrc = @" union S1(int, bool) { } namespace System.Runtime.CompilerServices { public interface IUnion { #nullable enable object Value { get; } #nullable disable } } "; var comp = CreateCompilation([unionSrc, UnionAttributeSource]); CompileAndVerify(comp).VerifyDiagnostics(); } [Fact] public void UnionDeclaration_25_IUnion_ValueMissing() { var unionSrc = @" union S1(int, bool) { } namespace System.Runtime.CompilerServices { public interface IUnion { } } "; var comp = CreateCompilation([unionSrc, UnionAttributeSource]); CompileAndVerify(comp).VerifyDiagnostics(); } [Fact] public void UnionDeclaration_26_IUnion_UnexpectedMember() { var unionSrc = @" union S1(int, bool) { } union S2(int, bool) { public void M() { } } union S3(int, bool) { void System.Runtime.CompilerServices.IUnion.M() { } } namespace System.Runtime.CompilerServices { public interface IUnion { void M(); } } "; var comp = CreateCompilation([unionSrc, UnionAttributeSource]); comp.VerifyDiagnostics( // (2,7): error CS0535: 'S1' does not implement interface member 'IUnion.M()' // union S1(int, bool) Diagnostic(ErrorCode.ERR_UnimplementedInterfaceMember, "S1").WithArguments("S1", "System.Runtime.CompilerServices.IUnion.M()").WithLocation(2, 7) ); } [Fact] public void UnionDeclaration_27_IUnion() { var unionSrc = @" union S1(int, bool) : I1 { } interface I1 : System.Runtime.CompilerServices.IUnion; class Program { static void Main() { System.Console.Write(Test(10)); System.Console.Write(Test(11)); System.Console.Write(Test(true)); System.Console.Write(Test(false)); System.Console.Write(Test(default)); } static int Test(S1 u) { return ((System.Runtime.CompilerServices.IUnion)u).Value switch { 10 => 1, true => 2, int => 3, bool => 4, _ => 5 }; } } "; var comp = CreateCompilation([unionSrc, UnionAttributeSource, IUnionSource], options: TestOptions.DebugExe); CompileAndVerify(comp, symbolValidator: checkInterfaces, sourceSymbolValidator: checkInterfaces, expectedOutput: "13245").VerifyDiagnostics(); void checkInterfaces(ModuleSymbol m) { var s1 = m.GlobalNamespace.GetTypeMember("S1"); AssertEx.SequenceEqual(["I1", "System.Runtime.CompilerServices.IUnion"], s1.InterfacesNoUseSiteDiagnostics().ToTestDisplayStrings()); } } [Fact] public void UnionDeclaration_28() { var unionSrc = @" #pragma warning disable CS0169 // The field 'S1.F' is never used union S1(int, bool) { int F1; } union S2(int, bool) { static int F2; } "; var comp = CreateCompilation([unionSrc, UnionAttributeSource, IUnionSource]); comp.VerifyDiagnostics( // (5,9): error CS9373: Instance fields, auto-properties or field-like events are not permitted in a 'union' declaration. // int F1; Diagnostic(ErrorCode.ERR_InstanceFieldInUnion, "F1").WithLocation(5, 9) ); } [Fact] public void UnionDeclaration_29() { var unionSrc = @" union S1(int, bool) { int P1 { get => 1; set {}} } union S2(int, bool) { int P2 { get; } } union S3(int, bool) { int P3 { set {field = value;} } } union S4(int, bool) { int P4 { get; set;} } union S5(int, bool) { int P5 { get => field; set {field = value;}} } interface I1 { int P0 { get; set; } } union S6(int, bool) : I1 { int I1.P0 { get; set; } } union S7(int, bool) { static int P7 { get; set;} } "; var comp = CreateCompilation([unionSrc, UnionAttributeSource, IUnionSource]); comp.VerifyDiagnostics( // (9,9): error CS9373: Instance fields, auto-properties or field-like events are not permitted in a 'union' declaration. // int P2 { get; } Diagnostic(ErrorCode.ERR_InstanceFieldInUnion, "P2").WithLocation(9, 9), // (14,9): error CS9373: Instance fields, auto-properties or field-like events are not permitted in a 'union' declaration. // int P3 { set {field = value;} } Diagnostic(ErrorCode.ERR_InstanceFieldInUnion, "P3").WithLocation(14, 9), // (19,9): error CS9373: Instance fields, auto-properties or field-like events are not permitted in a 'union' declaration. // int P4 { get; set;} Diagnostic(ErrorCode.ERR_InstanceFieldInUnion, "P4").WithLocation(19, 9), // (24,9): error CS9373: Instance fields, auto-properties or field-like events are not permitted in a 'union' declaration. // int P5 { get => field; set {field = value;}} Diagnostic(ErrorCode.ERR_InstanceFieldInUnion, "P5").WithLocation(24, 9), // (34,12): error CS9373: Instance fields, auto-properties or field-like events are not permitted in a 'union' declaration. // int I1.P0 { get; set; } Diagnostic(ErrorCode.ERR_InstanceFieldInUnion, "P0").WithLocation(34, 12) ); } [Fact] public void UnionDeclaration_30() { var unionSrc = @" #pragma warning disable CS0067 // The event 'S2.E2' is never used union S1(int, bool) { event System.Action E1 { add{} remove{}} } union S2(int, bool) { event System.Action E2; } interface I1 { event System.Action E0; } union S3(int, bool) : I1 { event System.Action I1.E0; } union S4(int, bool) { static event System.Action E4; } "; var comp = CreateCompilation([unionSrc, UnionAttributeSource, IUnionSource]); comp.VerifyDiagnostics( // (11,25): error CS9373: Instance fields, auto-properties or field-like events are not permitted in a 'union' declaration. // event System.Action E2; Diagnostic(ErrorCode.ERR_InstanceFieldInUnion, "E2").WithLocation(11, 25), // (19,23): error CS0535: 'S3' does not implement interface member 'I1.E0.add' // union S3(int, bool) : I1 Diagnostic(ErrorCode.ERR_UnimplementedInterfaceMember, "I1").WithArguments("S3", "I1.E0.add").WithLocation(19, 23), // (19,23): error CS0535: 'S3' does not implement interface member 'I1.E0.remove' // union S3(int, bool) : I1 Diagnostic(ErrorCode.ERR_UnimplementedInterfaceMember, "I1").WithArguments("S3", "I1.E0.remove").WithLocation(19, 23), // (21,28): error CS0071: An explicit interface implementation of an event must use event accessor syntax // event System.Action I1.E0; Diagnostic(ErrorCode.ERR_ExplicitEventFieldImpl, "E0").WithLocation(21, 28) ); } [Fact] public void UnionDeclaration_31() { var unionSrc = @" union S1(int, bool) { public S1(string x) : this(1) {} } union S2(int, bool) { public S2(ref string x) : this(1) {} } union S3(int, bool) { public S3(in string x) : this(1) {} } union S4(int, bool) { public S4(ref readonly string x) : this(1) {} } union S5(int, bool) { public S5(out string x) : this(1) { x = """"; } } union S6(int, bool) { S6(int x, bool y) : this(x) {} } union S7(int, bool) { public S7() : this(1) {} } union S8(int, bool) { private S8(string x) : this(1) {} } union S9(int, bool) { internal S9(string x) : this(1) {} } "; var comp = CreateCompilation([unionSrc, UnionAttributeSource, IUnionSource]); comp.VerifyDiagnostics( // (4,12): error CS9374: Explicitly declared public constructors with a single parameter are not permitted in a 'union' declaration. // public S1(string x) Diagnostic(ErrorCode.ERR_InstanceCtorWithOneParameterInUnion, "S1").WithLocation(4, 12), // (10,12): error CS9374: Explicitly declared public constructors with a single parameter are not permitted in a 'union' declaration. // public S2(ref string x) Diagnostic(ErrorCode.ERR_InstanceCtorWithOneParameterInUnion, "S2").WithLocation(10, 12), // (16,12): error CS9374: Explicitly declared public constructors with a single parameter are not permitted in a 'union' declaration. // public S3(in string x) Diagnostic(ErrorCode.ERR_InstanceCtorWithOneParameterInUnion, "S3").WithLocation(16, 12), // (22,12): error CS9374: Explicitly declared public constructors with a single parameter are not permitted in a 'union' declaration. // public S4(ref readonly string x) Diagnostic(ErrorCode.ERR_InstanceCtorWithOneParameterInUnion, "S4").WithLocation(22, 12), // (28,12): error CS9374: Explicitly declared public constructors with a single parameter are not permitted in a 'union' declaration. // public S5(out string x) Diagnostic(ErrorCode.ERR_InstanceCtorWithOneParameterInUnion, "S5").WithLocation(28, 12) ); VerifyCaseTypes(comp, "S8", ["System.Int32", "System.Boolean"]); VerifyCaseTypes(comp, "S9", ["System.Int32", "System.Boolean"]); } [Fact] public void UnionDeclaration_32() { var unionSrc = @" union S6(int, bool) { #line 4 S6(int x, bool y) {} } union S7(int, bool) { #line 10 public S7() {} } union S8(int, bool) { #line 16 S8(int x, bool y) {} S8(string x, bool y) : this(1) {} } union S9(int, bool) { S9(int x, bool y) : this() {} #line 30 public S9() {} } union S10(int, bool) { #line 36 S10(int x, bool y) {} public S10() : this(1) {} } union S11(int, bool) { static S11() {} } union S12(int, bool) { S12(int x, bool y) #line 53 : this() {} } union S13(int, bool) { S13(int x, bool y) : this("""", y) {} S13(string x, bool y) : this(y) {} } union S14(int, bool) { private S14(string x) {} } union S15(int, bool) { internal S15(string x) {} } union S16(int, bool) { public S16(string x) {} } "; var comp = CreateCompilation([unionSrc, UnionAttributeSource, IUnionSource]); comp.VerifyDiagnostics( // (4,5): error CS9375: A constructor declared in a 'union' declaration must have a 'this' initializer that calls a synthesized constructor or an explicitly declared constructor. // S6(int x, bool y) Diagnostic(ErrorCode.ERR_UnionConstructorCallsDefaultConstructor, "S6").WithLocation(4, 5), // (10,12): error CS9375: A constructor declared in a 'union' declaration must have a 'this' initializer that calls a synthesized constructor or an explicitly declared constructor. // public S7() Diagnostic(ErrorCode.ERR_UnionConstructorCallsDefaultConstructor, "S7").WithLocation(10, 12), // (16,5): error CS9375: A constructor declared in a 'union' declaration must have a 'this' initializer that calls a synthesized constructor or an explicitly declared constructor. // S8(int x, bool y) Diagnostic(ErrorCode.ERR_UnionConstructorCallsDefaultConstructor, "S8").WithLocation(16, 5), // (30,12): error CS9375: A constructor declared in a 'union' declaration must have a 'this' initializer that calls a synthesized constructor or an explicitly declared constructor. // public S9() Diagnostic(ErrorCode.ERR_UnionConstructorCallsDefaultConstructor, "S9").WithLocation(30, 12), // (36,5): error CS9375: A constructor declared in a 'union' declaration must have a 'this' initializer that calls a synthesized constructor or an explicitly declared constructor. // S10(int x, bool y) Diagnostic(ErrorCode.ERR_UnionConstructorCallsDefaultConstructor, "S10").WithLocation(36, 5), // (53,7): error CS9375: A constructor declared in a 'union' declaration must have a 'this' initializer that calls a synthesized constructor or an explicitly declared constructor. // : this() Diagnostic(ErrorCode.ERR_UnionConstructorCallsDefaultConstructor, "this").WithLocation(53, 7), // (70,13): error CS9375: A constructor declared in a 'union' declaration must have a 'this' initializer that calls a synthesized constructor or an explicitly declared constructor. // private S14(string x) Diagnostic(ErrorCode.ERR_UnionConstructorCallsDefaultConstructor, "S14").WithLocation(70, 13), // (76,14): error CS9375: A constructor declared in a 'union' declaration must have a 'this' initializer that calls a synthesized constructor or an explicitly declared constructor. // internal S15(string x) Diagnostic(ErrorCode.ERR_UnionConstructorCallsDefaultConstructor, "S15").WithLocation(76, 14), // (82,12): error CS9374: Explicitly declared public constructors with a single parameter are not permitted in a 'union' declaration. // public S16(string x) Diagnostic(ErrorCode.ERR_InstanceCtorWithOneParameterInUnion, "S16").WithLocation(82, 12), // (82,12): error CS9375: A constructor declared in a 'union' declaration must have a 'this' initializer that calls a synthesized constructor or an explicitly declared constructor. // public S16(string x) Diagnostic(ErrorCode.ERR_UnionConstructorCallsDefaultConstructor, "S16").WithLocation(82, 12) ); } [Fact] public void UnionDeclaration_33() { var unionSrc = @" union U1( #line 100 [Optional] byte, #line 200 out sbyte, #line 300 short name, #line 400 ushort = 0, #line 500 int = ) ; #line 600 union U2( /*a*/ int /*b*/); #line 700 union U3( int // c ); "; var comp = CreateCompilation([unionSrc, UnionAttributeSource, IUnionSource]); comp.VerifyDiagnostics( // (100,5): error CS1073: Unexpected token '[' // [Optional] byte, Diagnostic(ErrorCode.ERR_UnexpectedToken, "[").WithArguments("[").WithLocation(100, 5), // (200,5): error CS1073: Unexpected token 'out' // out sbyte, Diagnostic(ErrorCode.ERR_UnexpectedToken, "out").WithArguments("out").WithLocation(200, 5), // (300,11): error CS1073: Unexpected token 'name' // short name, Diagnostic(ErrorCode.ERR_UnexpectedToken, "name").WithArguments("name").WithLocation(300, 11), // (400,12): error CS1073: Unexpected token '=' // ushort = 0, Diagnostic(ErrorCode.ERR_UnexpectedToken, "=").WithArguments("=").WithLocation(400, 12), // (500,9): error CS1073: Unexpected token '=' // int = ) Diagnostic(ErrorCode.ERR_UnexpectedToken, "=").WithArguments("=").WithLocation(500, 9), // (500,11): error CS1525: Invalid expression term ')' // int = ) Diagnostic(ErrorCode.ERR_InvalidExprTerm, ")").WithArguments(")").WithLocation(500, 11) ); } [Fact] public void UnionDeclaration_34_SequencePoints() { var unionSrc = @" union S1(int, bool) { } "; var comp = CreateCompilation(unionSrc + UnionAttributeSource + IUnionSource, options: TestOptions.DebugDll); var verifier = CompileAndVerify(comp).VerifyDiagnostics(); verifier.VerifyMethodBody("S1..ctor(int)", @" { // Code size 14 (0xe) .maxstack 2 // sequence point: <hidden> IL_0000: ldarg.0 IL_0001: ldarg.1 IL_0002: box ""int"" IL_0007: stfld ""object S1.<Value>k__BackingField"" // sequence point: int IL_000c: nop IL_000d: ret } "); verifier.VerifyMethodBody("S1..ctor(bool)", @" { // Code size 14 (0xe) .maxstack 2 // sequence point: <hidden> IL_0000: ldarg.0 IL_0001: ldarg.1 IL_0002: box ""bool"" IL_0007: stfld ""object S1.<Value>k__BackingField"" // sequence point: bool IL_000c: nop IL_000d: ret } "); } [Fact] public void UnionDeclaration_35_LanguageVersion() { var src = @" union S1(int); "; var comp = CreateCompilation([src, UnionAttributeSource, IUnionSource], parseOptions: TestOptions.Regular14); comp.VerifyDiagnostics( // (2,1): error CS0246: The type or namespace name 'union' could not be found (are you missing a using directive or an assembly reference?) // union S1(int); Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "union").WithArguments("union").WithLocation(2, 1), // (2,7): error CS8112: Local function 'S1(int)' must declare a body because it is not marked 'static extern'. // union S1(int); Diagnostic(ErrorCode.ERR_LocalFunctionMissingBody, "S1").WithArguments("S1(int)").WithLocation(2, 7), // (2,7): warning CS8321: The local function 'S1' is declared but never used // union S1(int); Diagnostic(ErrorCode.WRN_UnreferencedLocalFunction, "S1").WithArguments("S1").WithLocation(2, 7), // (2,13): error CS1001: Identifier expected // union S1(int); Diagnostic(ErrorCode.ERR_IdentifierExpected, ")").WithLocation(2, 13) ); comp = CreateCompilation([src, UnionAttributeSource, IUnionSource], parseOptions: TestOptions.Regular15); comp.VerifyEmitDiagnostics(); comp = CreateCompilation([src, UnionAttributeSource, IUnionSource], parseOptions: TestOptions.RegularPreview); comp.VerifyEmitDiagnostics(); } [Fact] public void UnionDeclaration_36_LanguageVersion() { var comp = CreateCompilation([UnionAttributeSource, IUnionSource], parseOptions: TestOptions.Regular14). AddSyntaxTrees(createUnionDeclaration(TestOptions.Regular14).SyntaxTree); comp.VerifyDiagnostics( // (1,1): error CS9327: Feature 'unions' is not available in C# 14.0. Please use language version 15.0 or greater. // unionS1(int); Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion14, "union").WithArguments("unions", "15.0").WithLocation(1, 1) ); comp = CreateCompilation([UnionAttributeSource, IUnionSource], parseOptions: TestOptions.Regular15). AddSyntaxTrees(createUnionDeclaration(TestOptions.Regular15).SyntaxTree); comp.VerifyDiagnostics(); comp = CreateCompilation([UnionAttributeSource, IUnionSource], parseOptions: TestOptions.RegularPreview). AddSyntaxTrees(createUnionDeclaration(TestOptions.RegularPreview).SyntaxTree); comp.VerifyDiagnostics(); static CompilationUnitSyntax createUnionDeclaration(CSharpParseOptions parseOptions) { // union S1(int); var node = SyntaxFactory.CompilationUnit().AddMembers( SyntaxFactory.UnionDeclaration( attributeLists: default, modifiers: default, keyword: SyntaxFactory.Token(SyntaxKind.UnionKeyword), identifier: SyntaxFactory.Identifier("S1"), typeParameterList: null, parameterList: SyntaxFactory.ParameterList( SyntaxFactory.SeparatedList<ParameterSyntax>().Add( SyntaxFactory.Parameter(attributeLists: default, modifiers: default, type: SyntaxFactory.ParseTypeName("int"), identifier: default, @default: null))), baseList: null, constraintClauses: default, openBraceToken: default, members: default, closeBraceToken: default, semicolonToken: SyntaxFactory.Token(SyntaxKind.SemicolonToken))); node._syntaxTree = CSharpSyntaxTree.CreateWithoutClone(node, parseOptions); return node; } } [Fact] public void UnionDeclaration_37_CheckMemberForAttributes() { var src = @" class C1 { [System.Obsolete] public union S1(int); } class C2 { static void M1(C1.S1 x) {} } "; var comp = CreateCompilation([src, UnionAttributeSource, IUnionSource]); comp.VerifyDiagnostics( // (10,20): warning CS0612: 'C1.S1' is obsolete // static void M1(C1.S1 x) Diagnostic(ErrorCode.WRN_DeprecatedSymbol, "C1.S1").WithArguments("C1.S1").WithLocation(10, 20) ); Assert.True(((SourceMemberContainerTypeSymbol)comp.GetTypeByMetadataName("C1")).AnyMemberHasAttributes); } [Fact] public void UnionDeclaration_38_MemberProvider() { var src = @" union S1(int, bool) : S1.IUnionMembers { public interface IUnionMembers { public static S1 Create(string x) => throw null; public object Value { get; } } } union S2(int, bool) { public interface IUnionMembers { public static S2 Create(string x) => throw null; public object Value { get; } } } "; var comp = CreateCompilation([src, UnionAttributeSource, IUnionSource]); comp.VerifyEmitDiagnostics( // (2,7): error CS9387: A 'union' declaration cannot use a union member provider interface. // union S1(int, bool) : S1.IUnionMembers Diagnostic(ErrorCode.ERR_MemberProviderInUnionDeclaration, "S1").WithLocation(2, 7) ); Assert.True(comp.GetTypeByMetadataName("S1").IsUnionType); VerifyCaseTypes(comp, "S1", ["System.String"]); Assert.True(comp.GetTypeByMetadataName("S2").IsUnionType); VerifyCaseTypes(comp, "S2", ["System.Int32", "System.Boolean"]); } [Fact] public void ValueProperty_01() { var src = @" [System.Runtime.CompilerServices.Union] class S1 { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } public object Value => _value; } class Program { static void Main() { System.Console.Write(Test1(new S1(10))); System.Console.Write(Test1(default)); System.Console.Write(Test1(new S1(""11""))); System.Console.Write(Test1(new S1(0))); System.Console.Write(' '); System.Console.Write(Test4(new S1(11))); System.Console.Write(Test4(default)); System.Console.Write(Test4(new S1(""11""))); } static bool Test1(S1 u) { return u is 10; } static bool Test4(S1 u) { return u is null; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); CompileAndVerify(comp, expectedOutput: "TrueFalseFalseFalse FalseTrueFalse").VerifyDiagnostics(); } [Fact] public void ValueProperty_02() { var src = @" [System.Runtime.CompilerServices.Union] class S1<T> { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } public T Value => throw null; } class Program { static bool Test1(S1<object> u) { return u is 10; } static bool Test4(S1<object> u) { return u is null; } } "; var comp = CreateCompilation([src, UnionAttributeSource]); comp.VerifyDiagnostics( // (3,7): error CS9386: A union member provider type must have an instance 'Value' property of type 'object?' or 'object'. The property must have a public get accessor. // class S1<T> Diagnostic(ErrorCode.ERR_MissingUnionValueProperty, "S1").WithLocation(3, 7), // (15,21): error CS0656: Missing compiler required member 'S1<T>.Value' // return u is 10; Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "10").WithArguments("S1<T>", "Value").WithLocation(15, 21), // (20,21): error CS0656: Missing compiler required member 'S1<T>.Value' // return u is null; Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "null").WithArguments("S1<T>", "Value").WithLocation(20, 21) ); } [Fact] public void ValueProperty_03() { var src = @" class S0(object value) { private readonly object _value = value; public object Value => _value; } [System.Runtime.CompilerServices.Union] class S1<T> : S0 { public S1(int x) : base(x) {} public S1(string x) : base(x) {} public new T Value => throw null; } class Program { static void Main() { System.Console.Write(Test1(new S1<object>(10))); System.Console.Write(Test1(default)); System.Console.Write(Test1(new S1<object>(""11""))); System.Console.Write(Test1(new S1<object>(0))); System.Console.Write(' '); System.Console.Write(Test4(new S1<object>(11))); System.Console.Write(Test4(default)); System.Console.Write(Test4(new S1<object>(""11""))); } static bool Test1(S1<object> u) { return u is 10; } static bool Test4(S1<object> u) { return u is null; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); CompileAndVerify(comp, expectedOutput: "TrueFalseFalseFalse FalseTrueFalse").VerifyDiagnostics(); } [Fact] public void ValueProperty_04() { var src = @" class S0(object value) { private readonly object _value = value; public object Value => _value; } [System.Runtime.CompilerServices.Union] class S1 : S0 { public S1(int x) : base(x) {} public S1(string x) : base(x) {} } class Program { static void Main() { System.Console.Write(Test1(new S1(10))); System.Console.Write(Test1(default)); System.Console.Write(Test1(new S1(""11""))); System.Console.Write(Test1(new S1(0))); System.Console.Write(' '); System.Console.Write(Test4(new S1(11))); System.Console.Write(Test4(default)); System.Console.Write(Test4(new S1(""11""))); } static bool Test1(S1 u) { return u is 10; } static bool Test4(S1 u) { return u is null; } static int Test5(S0 u) { #line 100 return u switch { S1 and int => 1, S1 and string => 2, not S1 => 3 }; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); CompileAndVerify(comp, expectedOutput: "TrueFalseFalseFalse FalseTrueFalse").VerifyDiagnostics(); } [Fact] public void ValueProperty_05() { var src = @" class S01(object value) { private readonly object _value = value; public object Value => _value; } class S02(object value) : S01(value) { } [System.Runtime.CompilerServices.Union] class S1 : S02 { public S1(int x) : base(x) {} public S1(string x) : base(x) {} } class Program { static void Main() { System.Console.Write(Test1(new S1(10))); System.Console.Write(Test1(default)); System.Console.Write(Test1(new S1(""11""))); System.Console.Write(Test1(new S1(0))); System.Console.Write(' '); System.Console.Write(Test4(new S1(11))); System.Console.Write(Test4(default)); System.Console.Write(Test4(new S1(""11""))); } static bool Test1(S1 u) { return u is 10; } static bool Test4(S1 u) { return u is null; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); CompileAndVerify(comp, expectedOutput: "TrueFalseFalseFalse FalseTrueFalse").VerifyDiagnostics(); } [Fact] public void ValueProperty_06() { var src = @" class S0<T>(object value) { private readonly object _value = value; public T Value => (T)_value; } [System.Runtime.CompilerServices.Union] class S1 : S0<object> { public S1(int x) : base(x) {} public S1(string x) : base(x) {} } class Program { static void Main() { System.Console.Write(Test1(new S1(10))); System.Console.Write(Test1(default)); System.Console.Write(Test1(new S1(""11""))); System.Console.Write(Test1(new S1(0))); System.Console.Write(' '); System.Console.Write(Test4(new S1(11))); System.Console.Write(Test4(default)); System.Console.Write(Test4(new S1(""11""))); } static bool Test1(S1 u) { return u is 10; } static bool Test4(S1 u) { return u is null; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); CompileAndVerify(comp, expectedOutput: "TrueFalseFalseFalse FalseTrueFalse").VerifyDiagnostics(); } [Fact] public void ValueProperty_07() { var src = @" class S0<T1, T2>(object value) { private readonly object _value = value; public T1 Value => (T1)_value; } [System.Runtime.CompilerServices.Union] class S1<T> : S0<object, T> { public S1(int x) : base(x) {} public S1(string x) : base(x) {} } class Program { static void Main() { System.Console.Write(Test1(new S1<int>(10))); System.Console.Write(Test1(default)); System.Console.Write(Test1(new S1<int>(""11""))); System.Console.Write(Test1(new S1<int>(0))); System.Console.Write(' '); System.Console.Write(Test4(new S1<int>(11))); System.Console.Write(Test4(default)); System.Console.Write(Test4(new S1<int>(""11""))); } static bool Test1(S1<int> u) { return u is 10; } static bool Test4(S1<int> u) { return u is null; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); CompileAndVerify(comp, expectedOutput: "TrueFalseFalseFalse FalseTrueFalse").VerifyDiagnostics(); } [Fact] public void ValueProperty_08() { var src = @" class S01<T1, T2, T3>(object value) { private readonly object _value = value; public T1 Value => (T1)_value; } class S02<T1, T2>(object value) : S01<T1, T2, byte>(value) { } [System.Runtime.CompilerServices.Union] class S1<T> : S02<object, T> { public S1(int x) : base(x) {} public S1(string x) : base(x) {} } class Program { static void Main() { System.Console.Write(Test1(new S1<int>(10))); System.Console.Write(Test1(default)); System.Console.Write(Test1(new S1<int>(""11""))); System.Console.Write(Test1(new S1<int>(0))); System.Console.Write(' '); System.Console.Write(Test4(new S1<int>(11))); System.Console.Write(Test4(default)); System.Console.Write(Test4(new S1<int>(""11""))); } static bool Test1(S1<int> u) { return u is 10; } static bool Test4(S1<int> u) { return u is null; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); CompileAndVerify(comp, expectedOutput: "TrueFalseFalseFalse FalseTrueFalse").VerifyDiagnostics(); } [Fact] public void ValueProperty_09() { var src = @" class S0<T>(object value) { private readonly object _value = value; public T Value => (T)_value; } [System.Runtime.CompilerServices.Union] class S1<T> : S0<T> { public S1(int x) : base(x) {} public S1(string x) : base(x) {} } class Program { static bool Test1(S1<object> u) { return u is 10; } static bool Test4(S1<object> u) { return u is null; } } "; var comp = CreateCompilation([src, UnionAttributeSource]); comp.VerifyDiagnostics( // (9,7): error CS9386: A union member provider type must have an instance 'Value' property of type 'object?' or 'object'. The property must have a public get accessor. // class S1<T> : S0<T> Diagnostic(ErrorCode.ERR_MissingUnionValueProperty, "S1").WithLocation(9, 7), // (19,21): error CS0656: Missing compiler required member 'S1<T>.Value' // return u is 10; Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "10").WithArguments("S1<T>", "Value").WithLocation(19, 21), // (24,21): error CS0656: Missing compiler required member 'S1<T>.Value' // return u is null; Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "null").WithArguments("S1<T>", "Value").WithLocation(24, 21) ); } [Fact] public void ValueProperty_10() { var src = @" class S0(object value) { private readonly object _value = value; public object Value => _value; } [System.Runtime.CompilerServices.Union] class S1 : S0 { public S1(int x) : base(x) {} public S1(string x) : base(x) {} public S1(bool x) : base(x) {} } class Program { static void Main() { System.Console.Write(Test1(new S1(10))); System.Console.Write(Test1(default)); System.Console.Write(Test1(new S1(""11""))); System.Console.Write(Test1(new S1(true))); System.Console.Write(Test1(new S0(10))); System.Console.Write(Test1(new S0(""11""))); System.Console.Write(Test1(new S0(true))); } static bool Test1(S0 u) { return u is { Value: not (string or bool) } or S1 and string ; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); VerifyDecisionDagDump<IsPatternExpressionSyntax>(comp, @"[0]: t0 != null ? [1] : [5] [1]: t1 = t0.Value; [2] [2]: t1 is string ? [3] : [4] [3]: t0 is S1 ? [6] : [5] [4]: t1 is bool ? [5] : [6] [5]: leaf <isPatternFailure> `{ Value: not (string or bool) } or S1 and string` [6]: leaf <isPatternSuccess> `{ Value: not (string or bool) } or S1 and string` ", forLowering: true); var verifier = CompileAndVerify(comp, expectedOutput: "TrueFalseTrueFalseTrueFalseFalse").VerifyDiagnostics(); verifier.VerifyIL("Program.Test1", @" { // Code size 44 (0x2c) .maxstack 1 .locals init (object V_0, bool V_1) IL_0000: ldarg.0 IL_0001: brfalse.s IL_0028 IL_0003: ldarg.0 IL_0004: callvirt ""object S0.Value.get"" IL_0009: stloc.0 IL_000a: ldloc.0 IL_000b: isinst ""string"" IL_0010: brfalse.s IL_001c IL_0012: ldarg.0 IL_0013: isinst ""S1"" IL_0018: brtrue.s IL_0024 IL_001a: br.s IL_0028 IL_001c: ldloc.0 IL_001d: isinst ""bool"" IL_0022: brtrue.s IL_0028 IL_0024: ldc.i4.1 IL_0025: stloc.1 IL_0026: br.s IL_002a IL_0028: ldc.i4.0 IL_0029: stloc.1 IL_002a: ldloc.1 IL_002b: ret } "); } [Fact] public void ValueProperty_11() { var src = @" class S0(object value) { private readonly object _value = value; public object Value => _value; } [System.Runtime.CompilerServices.Union] class S1 : S0 { public S1(int x) : base(x) {} public S1(string x) : base(x) {} public S1(bool x) : base(x) {} } class Program { static void Main() { System.Console.Write(Test1(new S1(10))); System.Console.Write(Test1(default)); System.Console.Write(Test1(new S1(""11""))); System.Console.Write(Test1(new S1(true))); System.Console.Write(Test1(new S0(10))); System.Console.Write(Test1(new S0(""11""))); System.Console.Write(Test1(new S0(true))); } static bool Test1(S0 u) { return u is (S1 and string) or { Value: not (string or bool) } ; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); VerifyDecisionDagDump<IsPatternExpressionSyntax>(comp, @"[0]: t0 is S1 ? [1] : [5] [1]: t1 = (S1)t0; [2] [2]: t2 = t1.Value; [3] [3]: t2 is string ? [10] : [4] [4]: t2 is bool ? [9] : [10] [5]: t0 != null ? [6] : [9] [6]: t3 = t0.Value; [7] [7]: t3 is string ? [9] : [8] [8]: t3 is bool ? [9] : [10] [9]: leaf <isPatternFailure> `u is (S1 and string) or { Value: not (string or bool) }` [10]: leaf <isPatternSuccess> `(S1 and string) or { Value: not (string or bool) }` ", forLowering: true); var verifier = CompileAndVerify(comp, expectedOutput: "TrueFalseTrueFalseTrueFalseFalse").VerifyDiagnostics(); verifier.VerifyIL("Program.Test1", @" { // Code size 69 (0x45) .maxstack 1 .locals init (S1 V_0, object V_1, object V_2, bool V_3) IL_0000: ldarg.0 IL_0001: isinst ""S1"" IL_0006: stloc.0 IL_0007: ldloc.0 IL_0008: brfalse.s IL_0023 IL_000a: ldloc.0 IL_000b: callvirt ""object S0.Value.get"" IL_0010: stloc.1 IL_0011: ldloc.1 IL_0012: isinst ""string"" IL_0017: brtrue.s IL_003d IL_0019: ldloc.1 IL_001a: isinst ""bool"" IL_001f: brtrue.s IL_0041 IL_0021: br.s IL_003d IL_0023: ldarg.0 IL_0024: brfalse.s IL_0041 IL_0026: ldarg.0 IL_0027: callvirt ""object S0.Value.get"" IL_002c: stloc.2 IL_002d: ldloc.2 IL_002e: isinst ""string"" IL_0033: brtrue.s IL_0041 IL_0035: ldloc.2 IL_0036: isinst ""bool"" IL_003b: brtrue.s IL_0041 IL_003d: ldc.i4.1 IL_003e: stloc.3 IL_003f: br.s IL_0043 IL_0041: ldc.i4.0 IL_0042: stloc.3 IL_0043: ldloc.3 IL_0044: ret } "); } [Fact] public void ValueProperty_12_Override() { var src1 = @" class S0(object value) { private readonly object _value = value; public virtual object Value => _value; } [System.Runtime.CompilerServices.Union] class S1 : S0 { public S1(int x) : base(x) {} public S1(string x) : base(x) {} public S1(bool x) : base(x) {} public override object Value => base.Value; } class Program { static void Main() { System.Console.Write(Test1(new S1(10))); System.Console.Write(Test1(default)); System.Console.Write(Test1(new S1(""11""))); System.Console.Write(Test1(new S1(true))); System.Console.Write(Test1(new S0(10))); System.Console.Write(Test1(new S0(""11""))); System.Console.Write(Test1(new S0(true))); } static bool Test1(S0 u) { return u is { Value: not (string or bool) } or S1 and string ; } } "; var comp = CreateCompilation([src1, UnionAttributeSource], options: TestOptions.ReleaseExe); var expectedDag = @"[0]: t0 != null ? [1] : [9] [1]: t1 = t0.Value; [2] [2]: t1 is string ? [4] : [3] [3]: t1 is bool ? [4] : [8] [4]: t0 is S1 ? [5] : [9] [5]: t2 = (S1)t0; [6] [6]: t3 = t2.Value; [7] [7]: t3 is string ? [8] : [9]"; VerifyDecisionDagDump<IsPatternExpressionSyntax>(comp, expectedDag + @" [8]: leaf <isPatternSuccess> `{ Value: not (string or bool) } or S1 and string` [9]: leaf <isPatternFailure> `u is { Value: not (string or bool) } or S1 and string` ", forLowering: true); var expectedOutput = "TrueFalseTrueFalseTrueFalseFalse"; var verifier = CompileAndVerify(comp, expectedOutput: expectedOutput).VerifyDiagnostics(); var expectedIL = @" { // Code size 57 (0x39) .maxstack 1 .locals init (object V_0, S1 V_1, bool V_2) IL_0000: ldarg.0 IL_0001: brfalse.s IL_0035 IL_0003: ldarg.0 IL_0004: callvirt ""object S0.Value.get"" IL_0009: stloc.0 IL_000a: ldloc.0 IL_000b: isinst ""string"" IL_0010: brtrue.s IL_001a IL_0012: ldloc.0 IL_0013: isinst ""bool"" IL_0018: brfalse.s IL_0031 IL_001a: ldarg.0 IL_001b: isinst ""S1"" IL_0020: stloc.1 IL_0021: ldloc.1 IL_0022: brfalse.s IL_0035 IL_0024: ldloc.1 IL_0025: callvirt ""object S0.Value.get"" IL_002a: isinst ""string"" IL_002f: brfalse.s IL_0035 IL_0031: ldc.i4.1 IL_0032: stloc.2 IL_0033: br.s IL_0037 IL_0035: ldc.i4.0 IL_0036: stloc.2 IL_0037: ldloc.2 IL_0038: ret } "; verifier.VerifyIL("Program.Test1", expectedIL); var src2 = @" class S0(object value) { private readonly object _value = value; public virtual object Value => _value; } class S1 : S0 { public S1(int x) : base(x) {} public S1(string x) : base(x) {} public S1(bool x) : base(x) {} public override object Value => base.Value; } class Program { static void Main() { System.Console.Write(Test1(new S1(10))); System.Console.Write(Test1(default)); System.Console.Write(Test1(new S1(""11""))); System.Console.Write(Test1(new S1(true))); System.Console.Write(Test1(new S0(10))); System.Console.Write(Test1(new S0(""11""))); System.Console.Write(Test1(new S0(true))); } static bool Test1(S0 u) { return u is { Value: not (string or bool) } or S1 and { Value: string }; } } "; comp = CreateCompilation(src2, options: TestOptions.ReleaseExe); VerifyDecisionDagDump<IsPatternExpressionSyntax>(comp, expectedDag + @" [8]: leaf <isPatternSuccess> `{ Value: not (string or bool) } or S1 and { Value: string }` [9]: leaf <isPatternFailure> `{ Value: not (string or bool) } or S1 and { Value: string }` ", forLowering: true); verifier = CompileAndVerify(comp, expectedOutput: expectedOutput).VerifyDiagnostics(); verifier.VerifyIL("Program.Test1", expectedIL); } [Fact] public void ValueProperty_13_Override() { var src = @" class S0(object value) { protected readonly object _value = value; public virtual object Value => throw null; } [System.Runtime.CompilerServices.Union] class S1 : S0 { public S1(string x) : base(x) {} public override string Value => (string)_value; } class Program { static void Main() { System.Console.Write(Test1(new S1(""11""))); System.Console.Write(Test1(default)); System.Console.Write(Test1(new S1(null))); System.Console.Write(Test1(new S1(""10""))); } static bool Test1(S1 u) { return u is ""11"" ; } } "; var comp = CreateCompilation([src, UnionAttributeSource], targetFramework: TargetFramework.Net70, options: TestOptions.ReleaseExe); var verifier = CompileAndVerify(comp, expectedOutput: ExecutionConditionUtil.IsMonoOrCoreClr ? "TrueFalseFalseFalse" : null, verify: Verification.FailsPEVerify).VerifyDiagnostics(); verifier.VerifyIL("Program.Test1", @" { // Code size 32 (0x20) .maxstack 2 .locals init (string V_0) IL_0000: ldarg.0 IL_0001: brfalse.s IL_001e IL_0003: ldarg.0 IL_0004: callvirt ""object S0.Value.get"" IL_0009: isinst ""string"" IL_000e: stloc.0 IL_000f: ldloc.0 IL_0010: brfalse.s IL_001e IL_0012: ldloc.0 IL_0013: ldstr ""11"" IL_0018: call ""bool string.op_Equality(string, string)"" IL_001d: ret IL_001e: ldc.i4.0 IL_001f: ret } "); } [Fact] public void ValueProperty_14_Static() { var src = @" [System.Runtime.CompilerServices.Union] class S1 { public S1(int x) => throw null; public S1(string x) => throw null; public static object Value => throw null; } class Program { static bool Test1(S1 u) { return u is 10; } } "; var comp = CreateCompilation([src, UnionAttributeSource]); comp.VerifyDiagnostics( // (3,7): error CS9386: A union member provider type must have an instance 'Value' property of type 'object?' or 'object'. The property must have a public get accessor. // class S1 Diagnostic(ErrorCode.ERR_MissingUnionValueProperty, "S1").WithLocation(3, 7), // (14,21): error CS0656: Missing compiler required member 'S1.Value' // return u is 10; Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "10").WithArguments("S1", "Value").WithLocation(14, 21) ); } [Theory] [CombinatorialData] public void ValueProperty_15_NotPublic([CombinatorialValues("internal", "protected", "internal protected", "private protected")] string accessibility) { var src = @" [System.Runtime.CompilerServices.Union] class S1 { public S1(int x) => throw null; public S1(string x) => throw null; " + accessibility + @" object Value => throw null; } [System.Runtime.CompilerServices.Union] class S2 : S2.IUnionMembers { object IUnionMembers.Value => throw null; public interface IUnionMembers { public static S2 Create(int x) => throw null; public static S2 Create(string x) => throw null; " + accessibility + @" abstract object Value { get; } } } class Program { static bool Test1(S1 x) { return x is 10; } static bool Test2(S2 y) { return y is 10; } } "; var comp = CreateCompilation([src, UnionAttributeSource], targetFramework: TargetFramework.NetCoreApp); comp.VerifyDiagnostics( // (3,7): error CS9386: A union member provider type must have an instance 'Value' property of type 'object?' or 'object'. The property must have a public get accessor. // class S1 Diagnostic(ErrorCode.ERR_MissingUnionValueProperty, "S1").WithLocation(3, 7), // (11,7): error CS9386: A union member provider type must have an instance 'Value' property of type 'object?' or 'object'. The property must have a public get accessor. // class S2 : S2.IUnionMembers Diagnostic(ErrorCode.ERR_MissingUnionValueProperty, "S2").WithLocation(11, 7), // (27,21): error CS0656: Missing compiler required member 'S1.Value' // return x is 10; Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "10").WithArguments("S1", "Value").WithLocation(27, 21), // (32,21): error CS0656: Missing compiler required member 'S2.IUnionMembers.Value' // return y is 10; Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "10").WithArguments("S2.IUnionMembers", "Value").WithLocation(32, 21) ); } [Fact] public void ValueProperty_16_NotPublic() { var src = @" [System.Runtime.CompilerServices.Union] class S1 { public S1(int x) => throw null; public S1(string x) => throw null; private object Value => throw null; } [System.Runtime.CompilerServices.Union] class S2 : S2.IUnionMembers { public interface IUnionMembers { public static S2 Create(int x) => throw null; public static S2 Create(string x) => throw null; private object Value => throw null; } } class Program { static bool Test1(S1 x) { return x is 10; } static bool Test2(S2 y) { return y is 10; } } "; var comp = CreateCompilation([src, UnionAttributeSource], targetFramework: TargetFramework.NetCoreApp); comp.VerifyDiagnostics( // (3,7): error CS9386: A union member provider type must have an instance 'Value' property of type 'object?' or 'object'. The property must have a public get accessor. // class S1 Diagnostic(ErrorCode.ERR_MissingUnionValueProperty, "S1").WithLocation(3, 7), // (11,7): error CS9386: A union member provider type must have an instance 'Value' property of type 'object?' or 'object'. The property must have a public get accessor. // class S2 : S2.IUnionMembers Diagnostic(ErrorCode.ERR_MissingUnionValueProperty, "S2").WithLocation(11, 7), // (25,21): error CS0656: Missing compiler required member 'S1.Value' // return x is 10; Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "10").WithArguments("S1", "Value").WithLocation(25, 21), // (30,21): error CS0656: Missing compiler required member 'S2.IUnionMembers.Value' // return y is 10; Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "10").WithArguments("S2.IUnionMembers", "Value").WithLocation(30, 21) ); } [Fact] public void ValueProperty_17_Missing_Get() { var src = @" [System.Runtime.CompilerServices.Union] class S1 { public S1(int x) => throw null; public S1(string x) => throw null; public object Value { set => throw null; } } [System.Runtime.CompilerServices.Union] class S2 : S2.IUnionMembers { public object Value { set => throw null; } public interface IUnionMembers { public static S2 Create(int x) => throw null; public static S2 Create(string x) => throw null; public object Value { set; } } } class Program { static bool Test1(S1 x) { return x is 10; } static bool Test2(S2 y) { return y is 10; } } "; var comp = CreateCompilation([src, UnionAttributeSource]); comp.VerifyDiagnostics( // (3,7): error CS9386: A union member provider type must have an instance 'Value' property of type 'object?' or 'object'. The property must have a public get accessor. // class S1 Diagnostic(ErrorCode.ERR_MissingUnionValueProperty, "S1").WithLocation(3, 7), // (11,7): error CS9386: A union member provider type must have an instance 'Value' property of type 'object?' or 'object'. The property must have a public get accessor. // class S2 : S2.IUnionMembers Diagnostic(ErrorCode.ERR_MissingUnionValueProperty, "S2").WithLocation(11, 7), // (27,21): error CS0656: Missing compiler required member 'S1.Value' // return x is 10; Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "10").WithArguments("S1", "Value").WithLocation(27, 21), // (32,21): error CS0656: Missing compiler required member 'S2.IUnionMembers.Value' // return y is 10; Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "10").WithArguments("S2.IUnionMembers", "Value").WithLocation(32, 21) ); } [Fact] public void ValueProperty_17_With_Set() { var src = @" [System.Runtime.CompilerServices.Union] class S1 : S1.IUnionMembers { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } object IUnionMembers.Value { get => _value; set => throw null; } public interface IUnionMembers { public static S1 Create(int x) => throw null; public static S1 Create(string x) => throw null; public object Value { get; set; } } } class Program { static void Main() { System.Console.Write(Test1(new S1(10))); System.Console.Write(Test1(default)); System.Console.Write(Test1(new S1(""11""))); System.Console.Write(Test1(new S1(0))); } static bool Test1(S1 u) { return u is 10; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); CompileAndVerify(comp, expectedOutput: "TrueFalseFalseFalse").VerifyDiagnostics(); } [Fact] public void ValueProperty_18_With_Set() { var src = @" [System.Runtime.CompilerServices.Union] class S1 { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } public object Value { get => _value; set => throw null; } } class Program { static void Main() { System.Console.Write(Test1(new S1(10))); System.Console.Write(Test1(default)); System.Console.Write(Test1(new S1(""11""))); System.Console.Write(Test1(new S1(0))); } static bool Test1(S1 u) { return u is 10; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); CompileAndVerify(comp, expectedOutput: "TrueFalseFalseFalse").VerifyDiagnostics(); } [Theory] [CombinatorialData] public void ValueProperty_19_WrongRefKind([CombinatorialValues("ref", "ref readonly")] string refModifier) { var src = @" [System.Runtime.CompilerServices.Union] struct S1 { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } public " + refModifier + @" object Value => throw null; } class Program { static bool Test1(S1 u) { #line 21 return u is 10; } } "; var comp = CreateCompilation([src, UnionAttributeSource]); comp.VerifyDiagnostics( // (3,8): error CS9386: A union member provider type must have an instance 'Value' property of type 'object?' or 'object'. The property must have a public get accessor. // struct S1 Diagnostic(ErrorCode.ERR_MissingUnionValueProperty, "S1").WithLocation(3, 8), // (21,21): error CS0656: Missing compiler required member 'S1.Value' // return u is 10; Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "10").WithArguments("S1", "Value").WithLocation(21, 21) ); } [Fact] public void ValueProperty_20_Has_Parameters() { var src1 = @" <System.Runtime.CompilerServices.Union> public class S1 Sub New(x As Integer) End Sub Sub New(x As String) End Sub Readonly Property Value(Optional x as Integer = 0) As Object Get return Nothing End Get End Property end class namespace System.Runtime.CompilerServices public class UnionAttribute inherits System.Attribute end class end namespace "; var src2 = @" class Program { static bool Test1(S1 x) { return x is 10; } } "; var comp = CreateCompilation([src2], references: [CreateVisualBasicCompilation(src1).EmitToImageReference()]); comp.VerifyDiagnostics( // (6,21): error CS0656: Missing compiler required member 'S1.Value' // return x is 10; Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "10").WithArguments("S1", "Value").WithLocation(6, 21) ); } [Fact] public void ValueProperty_21_Overloaded() { var src1 = @" <System.Runtime.CompilerServices.Union> public class S1 Sub New(x As Integer) _Value = x End Sub Sub New(x As String) _Value = x End Sub Readonly Property Value(Optional x as Integer = 0) As Object Get return Nothing End Get End Property Readonly Property Value As Object Readonly Property Value(Optional x as Integer = 0, Optional y as Integer = 0) As Object Get return Nothing End Get End Property end class namespace System.Runtime.CompilerServices public class UnionAttribute inherits System.Attribute end class end namespace "; var src2 = @" class Program { static void Main() { System.Console.Write(Test1(new S1(10))); System.Console.Write(Test1(default)); System.Console.Write(Test1(new S1(""11""))); System.Console.Write(Test1(new S1(0))); } static bool Test1(S1 u) { return u is 10; } } "; var comp = CreateCompilation([src2], references: [CreateVisualBasicCompilation(src1).EmitToImageReference()], options: TestOptions.ReleaseExe); CompileAndVerify(comp, expectedOutput: "TrueFalseFalseFalse").VerifyDiagnostics(); } [Theory] [CombinatorialData] public void ValueProperty_22_NotPublic_Get([CombinatorialValues("private", "internal", "protected", "internal protected", "private protected")] string accessibility) { var src = @" [System.Runtime.CompilerServices.Union] class S1 { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } public object Value { " + accessibility + @" get => _value; set => throw null; } } class Program { static bool Test1(S1 u) { return u is 10; } } "; var comp = CreateCompilation([src, UnionAttributeSource]); comp.VerifyEmitDiagnostics( // (3,7): error CS9386: A union member provider type must have an instance 'Value' property of type 'object?' or 'object'. The property must have a public get accessor. // class S1 Diagnostic(ErrorCode.ERR_MissingUnionValueProperty, "S1").WithLocation(3, 7), // (19,21): error CS0656: Missing compiler required member 'S1.Value' // return u is 10; Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "10").WithArguments("S1", "Value").WithLocation(19, 21) ); } [Theory] [CombinatorialData] public void HasValueProperty_01([CombinatorialValues("class", "struct")] string typeKind) { var src = @" [System.Runtime.CompilerServices.Union] " + typeKind + @" S1 { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } public object Value => throw null; public bool HasValue => _value is not null; } class Program { static void Main() { System.Console.Write(Test1(new S1(10))); System.Console.Write(Test1(default)); } static bool Test1(S1 u) { return u is not null; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); CompileAndVerify(comp, expectedOutput: "TrueFalse").VerifyDiagnostics(); } [Fact] public void HasValueProperty_02() { var src = @" [System.Runtime.CompilerServices.Union] class S1<T> { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } public object Value => _value; public T HasValue => throw null; } class Program { static void Main() { System.Console.Write(Test1(new S1<bool>(10))); System.Console.Write(Test1(default)); } static bool Test1(S1<bool> u) { return u is not null; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); CompileAndVerify(comp, expectedOutput: "TrueFalse").VerifyDiagnostics(); } [Fact] public void HasValueProperty_03() { var src = @" class S0(object value) { private readonly object _value = value; public object Value => throw null; public bool HasValue => _value != null; } [System.Runtime.CompilerServices.Union] class S1<T> : S0 { public S1(int x) : base(x) {} public S1(string x) : base(x) {} public new T HasValue => throw null; } class Program { static void Main() { System.Console.Write(Test1(new S1<bool>(10))); System.Console.Write(Test1(default)); } static bool Test1(S1<bool> u) { return u is not null; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); CompileAndVerify(comp, expectedOutput: "TrueFalse").VerifyDiagnostics(); } [Fact] public void HasValueProperty_04() { var src = @" class S0(object value) { private readonly object _value = value; public object Value => throw null; public bool HasValue => _value is not null; } [System.Runtime.CompilerServices.Union] class S1 : S0 { public S1(int x) : base(x) {} public S1(string x) : base(x) {} } class Program { static void Main() { System.Console.Write(Test1(new S1(10))); System.Console.Write(Test1(default)); } static bool Test1(S1 u) { return u is not null; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); CompileAndVerify(comp, expectedOutput: "TrueFalse").VerifyDiagnostics(); } [Fact] public void HasValueProperty_05() { var src = @" class S01(object value) { private readonly object _value = value; public object Value => throw null; public bool HasValue => _value is not null; } class S02(object value) : S01(value) { } [System.Runtime.CompilerServices.Union] class S1 : S02 { public S1(int x) : base(x) {} public S1(string x) : base(x) {} } class Program { static void Main() { System.Console.Write(Test1(new S1(10))); System.Console.Write(Test1(default)); } static bool Test1(S1 u) { return u is not null; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); CompileAndVerify(comp, expectedOutput: "TrueFalse").VerifyDiagnostics(); } [Fact] public void HasValueProperty_06() { var src = @" class S0<T>(object value) { private readonly object _value = value; public object Value => throw null; public T HasValue => (T)(object)(_value != null); } [System.Runtime.CompilerServices.Union] class S1 : S0<bool> { public S1(int x) : base(x) {} public S1(string x) : base(x) {} } class Program { static void Main() { System.Console.Write(Test1(new S1(10))); System.Console.Write(Test1(default)); } static bool Test1(S1 u) { return u is not null; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); CompileAndVerify(comp, expectedOutput: "TrueFalse").VerifyDiagnostics(); } [Fact] public void HasValueProperty_07() { var src = @" class S0<T1, T2>(object value) { private readonly object _value = value; public object Value => throw null; public T1 HasValue => (T1)(object)(_value != null); } [System.Runtime.CompilerServices.Union] class S1<T> : S0<bool, T> { public S1(int x) : base(x) {} public S1(string x) : base(x) {} } class Program { static void Main() { System.Console.Write(Test1(new S1<int>(10))); System.Console.Write(Test1(default)); } static bool Test1(S1<int> u) { return u is not null; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); CompileAndVerify(comp, expectedOutput: "TrueFalse").VerifyDiagnostics(); } [Fact] public void HasValueProperty_08() { var src = @" class S01<T1, T2, T3>(object value) { private readonly object _value = value; public object Value => throw null; public T1 HasValue => (T1)(object)(_value != null); } class S02<T1, T2>(object value) : S01<T1, T2, byte>(value) { } [System.Runtime.CompilerServices.Union] class S1<T> : S02<bool, T> { public S1(int x) : base(x) {} public S1(string x) : base(x) {} } class Program { static void Main() { System.Console.Write(Test1(new S1<int>(10))); System.Console.Write(Test1(default)); } static bool Test1(S1<int> u) { return u is not null; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); CompileAndVerify(comp, expectedOutput: "TrueFalse").VerifyDiagnostics(); } [Fact] public void HasValueProperty_09() { var src = @" class S0<T>(object value) { private readonly object _value = value; public object Value => _value; public T HasValue => throw null; } [System.Runtime.CompilerServices.Union] class S1<T> : S0<T> { public S1(int x) : base(x) {} public S1(string x) : base(x) {} } class Program { static void Main() { System.Console.Write(Test1(new S1<bool>(10))); System.Console.Write(Test1(default)); } static bool Test1(S1<bool> u) { return u is not null; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); CompileAndVerify(comp, expectedOutput: "TrueFalse").VerifyDiagnostics(); } [Fact] public void HasValueProperty_10() { var src = @" class S0(object value) { private readonly object _value = value; public object Value => throw null; public bool HasValue => _value != null; } [System.Runtime.CompilerServices.Union] class S1 : S0 { public S1(int x) : base(x) {} public S1(string x) : base(x) {} public S1(bool x) : base(x) {} } class Program { static void Main() { System.Console.Write(Test1(new S1(10))); System.Console.Write(Test1(default)); System.Console.Write(Test1(new S1(""11""))); System.Console.Write(Test1(new S1(true))); System.Console.Write(Test1(new S0(10))); System.Console.Write(Test1(new S0(""11""))); System.Console.Write(Test1(new S0(true))); } static bool Test1(S0 u) { return u is { HasValue: false } or S1 and not null; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); VerifyDecisionDagDump<IsPatternExpressionSyntax>(comp, @"[0]: t0 != null ? [1] : [5] [1]: t1 = t0.HasValue; [2] [2]: t1 == False ? [4] : [3] [3]: t0 is S1 ? [4] : [5] [4]: leaf <isPatternSuccess> `{ HasValue: false } or S1 and not null` [5]: leaf <isPatternFailure> `u is { HasValue: false } or S1 and not null` ", forLowering: true); var verifier = CompileAndVerify(comp, expectedOutput: "TrueFalseTrueTrueFalseFalseFalse").VerifyDiagnostics(); verifier.VerifyIL("Program.Test1", @" { // Code size 27 (0x1b) .maxstack 1 .locals init (bool V_0) IL_0000: ldarg.0 IL_0001: brfalse.s IL_0017 IL_0003: ldarg.0 IL_0004: callvirt ""bool S0.HasValue.get"" IL_0009: brfalse.s IL_0013 IL_000b: ldarg.0 IL_000c: isinst ""S1"" IL_0011: brfalse.s IL_0017 IL_0013: ldc.i4.1 IL_0014: stloc.0 IL_0015: br.s IL_0019 IL_0017: ldc.i4.0 IL_0018: stloc.0 IL_0019: ldloc.0 IL_001a: ret } "); } [Fact] public void HasValueProperty_11() { var src = @" class S0(object value) { private readonly object _value = value; public object Value => throw null; public bool HasValue => _value != null; } [System.Runtime.CompilerServices.Union] class S1 : S0 { public S1(int x) : base(x) {} public S1(string x) : base(x) {} public S1(bool x) : base(x) {} } class Program { static void Main() { System.Console.Write(Test1(new S1(10))); System.Console.Write(Test1(default)); System.Console.Write(Test1(new S1(""11""))); System.Console.Write(Test1(new S1(true))); System.Console.Write(Test1(new S0(10))); System.Console.Write(Test1(new S0(""11""))); System.Console.Write(Test1(new S0(true))); } static bool Test1(S0 u) { return u is (S1 and not null) or { HasValue: false }; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); VerifyDecisionDagDump<IsPatternExpressionSyntax>(comp, @"[0]: t0 is S1 ? [4] : [1] [1]: t0 != null ? [2] : [5] [2]: t1 = t0.HasValue; [3] [3]: t1 == False ? [4] : [5] [4]: leaf <isPatternSuccess> `(S1 and not null) or { HasValue: false }` [5]: leaf <isPatternFailure> `u is (S1 and not null) or { HasValue: false }` ", forLowering: true); var verifier = CompileAndVerify(comp, expectedOutput: "TrueFalseTrueTrueFalseFalseFalse").VerifyDiagnostics(); verifier.VerifyIL("Program.Test1", @" { // Code size 27 (0x1b) .maxstack 1 .locals init (bool V_0) IL_0000: ldarg.0 IL_0001: isinst ""S1"" IL_0006: brtrue.s IL_0013 IL_0008: ldarg.0 IL_0009: brfalse.s IL_0017 IL_000b: ldarg.0 IL_000c: callvirt ""bool S0.HasValue.get"" IL_0011: brtrue.s IL_0017 IL_0013: ldc.i4.1 IL_0014: stloc.0 IL_0015: br.s IL_0019 IL_0017: ldc.i4.0 IL_0018: stloc.0 IL_0019: ldloc.0 IL_001a: ret } "); } [Fact] public void HasValueProperty_12_Override() { var src1 = @" class S0(object value) { private readonly object _value = value; public object Value => throw null; public virtual bool HasValue => _value != null; } [System.Runtime.CompilerServices.Union] class S1 : S0 { public S1(int x) : base(x) {} public S1(string x) : base(x) {} public S1(bool x) : base(x) {} public override bool HasValue => base.HasValue; } class Program { static void Main() { System.Console.Write(Test1(new S1(10))); System.Console.Write(Test1(default)); System.Console.Write(Test1(new S1(""11""))); System.Console.Write(Test1(new S1(true))); System.Console.Write(Test1(new S0(10))); System.Console.Write(Test1(new S0(""11""))); System.Console.Write(Test1(new S0(true))); } static bool Test1(S0 u) { return u is { HasValue: false } or S1 and not null; } } "; var comp = CreateCompilation([src1, UnionAttributeSource], options: TestOptions.ReleaseExe); VerifyDecisionDagDump<IsPatternExpressionSyntax>(comp, @"[0]: t0 != null ? [1] : [7] [1]: t1 = t0.HasValue; [2] [2]: t1 == False ? [8] : [3] [3]: t0 is S1 ? [4] : [7] [4]: t2 = (S1)t0; [5] [5]: t3 = t2.HasValue; [6] [6]: t3 == False ? [7] : [8] [7]: leaf <isPatternFailure> `u is { HasValue: false } or S1 and not null` [8]: leaf <isPatternSuccess> `{ HasValue: false } or S1 and not null` ", forLowering: true); var expectedOutput = "TrueFalseTrueTrueFalseFalseFalse"; var verifier = CompileAndVerify(comp, expectedOutput: expectedOutput).VerifyDiagnostics(); var expectedIL = @" { // Code size 37 (0x25) .maxstack 1 .locals init (S1 V_0, bool V_1) IL_0000: ldarg.0 IL_0001: brfalse.s IL_0021 IL_0003: ldarg.0 IL_0004: callvirt ""bool S0.HasValue.get"" IL_0009: brfalse.s IL_001d IL_000b: ldarg.0 IL_000c: isinst ""S1"" IL_0011: stloc.0 IL_0012: ldloc.0 IL_0013: brfalse.s IL_0021 IL_0015: ldloc.0 IL_0016: callvirt ""bool S0.HasValue.get"" IL_001b: brfalse.s IL_0021 IL_001d: ldc.i4.1 IL_001e: stloc.1 IL_001f: br.s IL_0023 IL_0021: ldc.i4.0 IL_0022: stloc.1 IL_0023: ldloc.1 IL_0024: ret } "; verifier.VerifyIL("Program.Test1", expectedIL); var src2 = @" class S0(object value) { private readonly object _value = value; public object Value => throw null; public virtual bool HasValue => _value != null; } class S1 : S0 { public S1(int x) : base(x) {} public S1(string x) : base(x) {} public S1(bool x) : base(x) {} public override bool HasValue => base.HasValue; } class Program { static void Main() { System.Console.Write(Test1(new S1(10))); System.Console.Write(Test1(default)); System.Console.Write(Test1(new S1(""11""))); System.Console.Write(Test1(new S1(true))); System.Console.Write(Test1(new S0(10))); System.Console.Write(Test1(new S0(""11""))); System.Console.Write(Test1(new S0(true))); } static bool Test1(S0 u) { return u is { HasValue: false } or S1 and { HasValue: true }; } } "; comp = CreateCompilation(src2, options: TestOptions.ReleaseExe); VerifyDecisionDagDump<IsPatternExpressionSyntax>(comp, @"[0]: t0 != null ? [1] : [8] [1]: t1 = t0.HasValue; [2] [2]: t1 == False ? [7] : [3] [3]: t0 is S1 ? [4] : [8] [4]: t2 = (S1)t0; [5] [5]: t3 = t2.HasValue; [6] [6]: t3 == True ? [7] : [8] [7]: leaf <isPatternSuccess> `{ HasValue: false } or S1 and { HasValue: true }` [8]: leaf <isPatternFailure> `{ HasValue: false } or S1 and { HasValue: true }` ", forLowering: true); verifier = CompileAndVerify(comp, expectedOutput: expectedOutput).VerifyDiagnostics(); verifier.VerifyIL("Program.Test1", expectedIL); } [Fact] public void HasValueProperty_13() { var src = @" #nullable enable public class S0 { public bool HasValue => throw null!; } [System.Runtime.CompilerServices.Union] public class S1 : S0 { public S1(string? x) {} public object? Value => throw null!; } class Program { static void Test2(S1 s) { if (s.HasValue) { #line 100 _ = s switch { string => 1 }; } else { #line 200 _ = s switch { string => 1 }; } } static void Test4(S1 s) { if (!s.HasValue) { #line 300 _ = s switch { string => 1 }; } else { #line 400 _ = s switch { string => 1 }; } } } "; var comp = CreateCompilation([src, UnionAttributeSource]); comp.VerifyDiagnostics( // (200,19): warning CS8655: The switch expression does not handle some null inputs (it is not exhaustive). For example, the pattern 'null' is not covered. // _ = s switch { string => 1 }; Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustiveForNull, "switch").WithArguments("null").WithLocation(200, 19), // (300,19): warning CS8655: The switch expression does not handle some null inputs (it is not exhaustive). For example, the pattern 'null' is not covered. // _ = s switch { string => 1 }; Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustiveForNull, "switch").WithArguments("null").WithLocation(300, 19) ); } [Fact] public void HasValueProperty_14_Static() { var src = @" [System.Runtime.CompilerServices.Union] class S1 { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } public object Value => _value; public static bool HasValue => throw null; } class Program { static void Main() { System.Console.Write(Test1(new S1(10))); System.Console.Write(Test1(default)); } static bool Test1(S1 u) { return u is not null; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); CompileAndVerify(comp, expectedOutput: "TrueFalse").VerifyDiagnostics(); } [Fact] public void HasValueProperty_15_Missing_Get() { var src = @" [System.Runtime.CompilerServices.Union] class S1 { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } public object Value => _value; public bool HasValue { set => throw null; } } class Program { static void Main() { System.Console.Write(Test1(new S1(10))); System.Console.Write(Test1(default)); } static bool Test1(S1 u) { return u is not null; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); CompileAndVerify(comp, expectedOutput: "TrueFalse").VerifyDiagnostics(); } [Fact] public void HasValueProperty_16_Missing_Get() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 : S1.IUnionMembers { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } public object Value => _value; bool IUnionMembers.HasValue { set => throw null; } public interface IUnionMembers { public static S1 Create(int x) => new S1(x); public static S1 Create(string x) => new S1(x); public object Value { get; } public bool HasValue { set; } } } class Program { static void Main() { System.Console.Write(Test1(new S1(1))); System.Console.Write(Test1(new S1())); } static bool Test1(S1 u) { return u is null; } } "; var comp = CreateCompilation([src, UnionAttributeSource], targetFramework: TargetFramework.NetCoreApp, options: TestOptions.ReleaseExe); CompileAndVerify(comp, expectedOutput: ExecutionConditionUtil.IsMonoOrCoreClr ? "FalseTrue" : null, verify: Verification.FailsPEVerify).VerifyDiagnostics(); } [Fact] public void HasValueProperty_17_With_Set() { var src = @" [System.Runtime.CompilerServices.Union] class S1 { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } public object Value => throw null; public bool HasValue { get => _value != null; set => throw null; } } class Program { static void Main() { System.Console.Write(Test1(new S1(10))); System.Console.Write(Test1(default)); } static bool Test1(S1 u) { return u is not null; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); CompileAndVerify(comp, expectedOutput: "TrueFalse").VerifyDiagnostics(); } [Fact] public void HasValueProperty_18_With_Set() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 : S1.IUnionMembers { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } public object Value => throw null; bool IUnionMembers.HasValue { get => _value != null; set => throw null; } public interface IUnionMembers { public static S1 Create(int x) => new S1(x); public static S1 Create(string x) => new S1(x); public object Value { get; } public bool HasValue { get; set; } } } class Program { static void Main() { System.Console.Write(Test1(new S1(1))); System.Console.Write(Test1(new S1())); } static bool Test1(S1 u) { return u is null; } } "; var comp = CreateCompilation([src, UnionAttributeSource], targetFramework: TargetFramework.NetCoreApp, options: TestOptions.ReleaseExe); CompileAndVerify(comp, expectedOutput: ExecutionConditionUtil.IsMonoOrCoreClr ? "FalseTrue" : null, verify: Verification.FailsPEVerify).VerifyDiagnostics(); } [Theory] [CombinatorialData] public void HasValueProperty_19_WrongRefKind([CombinatorialValues("ref", "ref readonly")] string refModifier) { var src = @" [System.Runtime.CompilerServices.Union] struct S1 { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } public object Value => _value; public " + refModifier + @" bool HasValue => throw null; } class Program { static void Main() { System.Console.Write(Test1(new S1(1))); System.Console.Write(Test1(new S1())); } static bool Test1(S1 u) { return u is null; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); CompileAndVerify(comp, expectedOutput: "FalseTrue").VerifyDiagnostics(); } [Fact] public void HasValueProperty_20_Has_Parameters() { var src1 = @" <System.Runtime.CompilerServices.Union> public class S1 Public Readonly Property Value As Object Sub New(x As Integer) _Value = x End Sub Sub New(x As String) _Value = x End Sub Readonly Property HasValue(Optional x as Integer = 0) As Boolean Get return False End Get End Property end class namespace System.Runtime.CompilerServices public class UnionAttribute inherits System.Attribute end class end namespace "; var src2 = @" class Program { static void Main() { System.Console.Write(Test1(new S1(1))); System.Console.Write(Test1(new S1(null))); } static bool Test1(S1 u) { return u is null; } } "; var comp = CreateCompilation([src2], references: [CreateVisualBasicCompilation(src1).EmitToImageReference()], options: TestOptions.ReleaseExe); CompileAndVerify(comp, expectedOutput: "FalseTrue").VerifyDiagnostics(); } [Fact] public void HasValueProperty_21_Overloaded() { var src1 = @" <System.Runtime.CompilerServices.Union> public class S1 Private _Value As Object Sub New(x As Integer) _Value = x End Sub Sub New(x As String) _Value = x End Sub Readonly Property Value As Object Get return Nothing End Get End Property Readonly Property HasValue(Optional x as Integer = 0) As Boolean Get return False End Get End Property Readonly Property HasValue As Boolean Get return _Value IsNot Nothing End Get End Property Readonly Property HasValue(Optional x as Integer = 0, Optional y as Integer = 0) As Boolean Get return False End Get End Property end class namespace System.Runtime.CompilerServices public class UnionAttribute inherits System.Attribute end class end namespace "; var src2 = @" class Program { static void Main() { System.Console.Write(Test1(new S1(1))); System.Console.Write(Test1(new S1(null))); } static bool Test1(S1 u) { return u is null; } } "; var comp = CreateCompilation([src2], references: [CreateVisualBasicCompilation(src1).EmitToImageReference()], options: TestOptions.ReleaseExe); CompileAndVerify(comp, expectedOutput: "FalseTrue").VerifyDiagnostics(); } [Fact] public void HasValueProperty_22_Bad() { // [System.Runtime.CompilerServices.Union] // class S1 // { // private readonly object _value; // public S1(int x) { _value = x; } // public S1(string x) { _value = x; } // public object Value => _value; // // [CompilerFeatureRequired("SomeFeatureIsRequired")] // public bool HasValue => throw null; // } var ilSource = @" .class public auto ansi beforefieldinit S1 extends [mscorlib]System.Object { .custom instance void System.Runtime.CompilerServices.UnionAttribute::.ctor() = ( 01 00 00 00 ) .field private initonly object _value .method public hidebysig specialname rtspecialname instance void .ctor ( int32 x ) cil managed { .maxstack 8 IL_0000: ldarg.0 IL_0001: call instance void [mscorlib]System.Object::.ctor() IL_0006: nop IL_0007: nop IL_0008: ldarg.0 IL_0009: ldarg.1 IL_000a: box [mscorlib]System.Int32 IL_000f: stfld object S1::_value IL_0014: ret } .method public hidebysig specialname rtspecialname instance void .ctor ( string x ) cil managed { .maxstack 8 IL_0000: ldarg.0 IL_0001: call instance void [mscorlib]System.Object::.ctor() IL_0006: nop IL_0007: nop IL_0008: ldarg.0 IL_0009: ldarg.1 IL_000a: stfld object S1::_value IL_000f: ret } .method public hidebysig specialname instance object get_Value () cil managed { .maxstack 8 IL_0000: ldarg.0 IL_0001: ldfld object S1::_value IL_0006: ret } .method public hidebysig specialname instance bool get_HasValue () cil managed { .maxstack 8 IL_0000: ldnull IL_0001: throw } .property instance object Value() { .get instance object S1::get_Value() } .property instance bool HasValue() { .custom instance void System.Runtime.CompilerServices.CompilerFeatureRequiredAttribute::.ctor(string) = ( 01 00 15 53 6f 6d 65 46 65 61 74 75 72 65 49 73 52 65 71 75 69 72 65 64 00 00 ) .get instance bool S1::get_HasValue() } } .class public auto ansi beforefieldinit System.Runtime.CompilerServices.UnionAttribute extends [mscorlib]System.Attribute { .method public hidebysig specialname rtspecialname instance void .ctor () cil managed { .maxstack 8 IL_0000: ldarg.0 IL_0001: call instance void [mscorlib]System.Attribute::.ctor() IL_0006: nop IL_0007: ret } } .class public auto ansi sealed beforefieldinit System.Runtime.CompilerServices.CompilerFeatureRequiredAttribute extends [mscorlib]System.Attribute { .custom instance void [mscorlib]System.AttributeUsageAttribute::.ctor(valuetype [mscorlib]System.AttributeTargets) = ( 01 00 ff 7f 00 00 02 00 54 02 0d 41 6c 6c 6f 77 4d 75 6c 74 69 70 6c 65 01 54 02 09 49 6e 68 65 72 69 74 65 64 00 ) .method public hidebysig specialname rtspecialname instance void .ctor ( string featureName ) cil managed { IL_000f: ret } } "; var src = @" class Program { static void Main() { System.Console.Write(Test1(new S1(10))); System.Console.Write(Test1(default)); } static bool Test1(S1 u) { return u is not null; } } "; var comp = CreateCompilationWithIL(src, ilSource, options: TestOptions.ReleaseExe); CompileAndVerify(comp, expectedOutput: "TrueFalse").VerifyDiagnostics(); } [Theory] [CombinatorialData] public void HasValueProperty_23_NotPublic([CombinatorialValues("private", "internal", "protected", "internal protected", "private protected")] string accessibility) { var src = @" [System.Runtime.CompilerServices.Union] class S1 { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } public object Value => _value; " + accessibility + @" bool HasValue => throw null; } class Program { static void Main() { System.Console.Write(Test1(new S1(10))); System.Console.Write(Test1(default)); } static bool Test1(S1 u) { return u is not null; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); CompileAndVerify(comp, expectedOutput: "TrueFalse").VerifyDiagnostics(); } [Theory] [CombinatorialData] public void HasValueProperty_24_NotPublic_Get([CombinatorialValues("private", "internal", "protected", "internal protected", "private protected")] string accessibility) { var src = @" [System.Runtime.CompilerServices.Union] class S1 { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } public object Value => _value; public bool HasValue { " + accessibility + @" get => throw null; set => throw null; } } class Program { static void Main() { System.Console.Write(Test1(new S1(10))); System.Console.Write(Test1(default)); } static bool Test1(S1 u) { return u is not null; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); CompileAndVerify(comp, expectedOutput: "TrueFalse").VerifyDiagnostics(); } [Theory] [CombinatorialData] public void TryGetValueMethod_01([CombinatorialValues("class", "struct")] string typeKind) { var src = @" [System.Runtime.CompilerServices.Union] " + typeKind + @" S1 { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } public object Value => throw null; public bool TryGetValue(out int value) { if (_value is int) { value = (int)_value; return true; } else { value = 0; return false; } } } class Program { static void Main() { System.Console.Write(Test1(new S1(10))); System.Console.Write(Test1(default)); System.Console.Write(Test1(new S1(""11""))); System.Console.Write(Test1(new S1(0))); System.Console.Write(Test1(new S1(null))); } static bool Test1(S1 u) { return u is 10; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); CompileAndVerify(comp, expectedOutput: "TrueFalseFalseFalseFalse").VerifyDiagnostics(); } [Fact] public void TryGetValueMethod_02() { var src = @" [System.Runtime.CompilerServices.Union] class S1<T> { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } public object Value => _value; public T TryGetValue(out int value) => throw null; } class Program { static void Main() { System.Console.Write(Test1(new S1<bool>(10))); System.Console.Write(Test1(new S1<bool>(0))); System.Console.Write(Test1(new S1<bool>(""10""))); System.Console.Write(Test1(new S1<bool>(null))); System.Console.Write(Test1(default)); } static bool Test1(S1<bool> u) { return u is 10; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); CompileAndVerify(comp, expectedOutput: "TrueFalseFalseFalseFalse").VerifyDiagnostics(); } [Fact] public void TryGetValueMethod_03() { var src = @" [System.Runtime.CompilerServices.Union] class S1<T> { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } public object Value => _value; public bool TryGetValue(out T value) => throw null; } class Program { static void Main() { System.Console.Write(Test1(new S1<int>(10))); System.Console.Write(Test1(new S1<int>(0))); System.Console.Write(Test1(new S1<int>(""10""))); System.Console.Write(Test1(new S1<int>(null))); System.Console.Write(Test1(default)); } static bool Test1(S1<int> u) { return u is 10; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); CompileAndVerify(comp, expectedOutput: "TrueFalseFalseFalseFalse").VerifyDiagnostics(); } [Fact] public void TryGetValueMethod_04() { var src = @" class S0(object value) { private readonly object _value = value; public object Value => throw null; public bool TryGetValue(out int value) { if (_value is int) { value = (int)_value; return true; } else { value = 0; return false; } } } [System.Runtime.CompilerServices.Union] class S1<T> : S0 { public S1(int x) : base(x) {} public S1(string x) : base(x) {} public new T TryGetValue(out int value) => throw null; } class Program { static void Main() { System.Console.Write(Test1(new S1<bool>(10))); System.Console.Write(Test1(new S1<bool>(0))); System.Console.Write(Test1(new S1<bool>(""10""))); System.Console.Write(Test1(new S1<bool>(null))); System.Console.Write(Test1(default)); } static bool Test1(S1<bool> u) { return u is 10; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); CompileAndVerify(comp, expectedOutput: "TrueFalseFalseFalseFalse").VerifyDiagnostics(); } [Fact] public void TryGetValueMethod_05_01() { var src = @" class S0(object value) { private readonly object _value = value; public object Value => throw null; public bool TryGetValue(out int value) { if (_value is int) { value = (int)_value; return true; } else { value = 0; return false; } } } [System.Runtime.CompilerServices.Union] class S1<T> : S0 { public S1(int x) : base(x) {} public S1(string x) : base(x) {} public bool TryGetValue(out T value) => throw null; } class Program { static void Main() { System.Console.Write(Test1(new S1<int>(10))); System.Console.Write(Test1(new S1<int>(0))); System.Console.Write(Test1(new S1<int>(""10""))); System.Console.Write(Test1(new S1<int>(null))); System.Console.Write(Test1(default)); } static bool Test1(S1<int> u) { return u is 10; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); CompileAndVerify(comp, expectedOutput: "TrueFalseFalseFalseFalse").VerifyDiagnostics(); } [Fact] public void TryGetValueMethod_05_02() { var src = @" class S0(object value) { private readonly object _value = value; public object Value => throw null; public bool TryGetValue(out int value) { if (_value is int) { value = (int)_value; return true; } else { value = 0; return false; } } } class S0<T>(object value) : S0(value) { public bool TryGetValue(out T value) => throw null; } [System.Runtime.CompilerServices.Union] class S1<T> : S0<T> { public S1(int x) : base(x) {} public S1(string x) : base(x) {} } class Program { static void Main() { System.Console.Write(Test1(new S1<int>(10))); System.Console.Write(Test1(new S1<int>(0))); System.Console.Write(Test1(new S1<int>(""10""))); System.Console.Write(Test1(new S1<int>(null))); System.Console.Write(Test1(default)); } static bool Test1(S1<int> u) { return u is 10; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); CompileAndVerify(comp, expectedOutput: "TrueFalseFalseFalseFalse").VerifyDiagnostics(); } [Fact] public void TryGetValueMethod_06() { var src = @" class S0(object value) { private readonly object _value = value; public object Value => throw null; public bool TryGetValue(out int value) { if (_value is int) { value = (int)_value; return true; } else { value = 0; return false; } } } [System.Runtime.CompilerServices.Union] class S1 : S0 { public S1(int x) : base(x) {} public S1(string x) : base(x) {} } class Program { static void Main() { System.Console.Write(Test1(new S1(10))); System.Console.Write(Test1(new S1(0))); System.Console.Write(Test1(new S1(""10""))); System.Console.Write(Test1(new S1(null))); System.Console.Write(Test1(default)); } static bool Test1(S1 u) { return u is 10; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); CompileAndVerify(comp, expectedOutput: "TrueFalseFalseFalseFalse").VerifyDiagnostics(); } [Fact] public void TryGetValueMethod_07() { var src = @" class S01(object value) { private readonly object _value = value; public object Value => throw null; public bool TryGetValue(out int value) { if (_value is int) { value = (int)_value; return true; } else { value = 0; return false; } } } class S02(object value) : S01(value) { } [System.Runtime.CompilerServices.Union] class S1 : S02 { public S1(int x) : base(x) {} public S1(string x) : base(x) {} } class Program { static void Main() { System.Console.Write(Test1(new S1(10))); System.Console.Write(Test1(new S1(0))); System.Console.Write(Test1(new S1(""10""))); System.Console.Write(Test1(new S1(null))); System.Console.Write(Test1(default)); } static bool Test1(S1 u) { return u is 10; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); CompileAndVerify(comp, expectedOutput: "TrueFalseFalseFalseFalse").VerifyDiagnostics(); } [Fact] public void TryGetValueMethod_08() { var src = @" class S0<T>(object value) { private readonly object _value = value; public object Value => throw null; public T TryGetValue(out int value) { if (_value is int) { value = (int)_value; return (T)(object)true; } else { value = 0; return (T)(object)false; } } } [System.Runtime.CompilerServices.Union] class S1 : S0<bool> { public S1(int x) : base(x) {} public S1(string x) : base(x) {} } class Program { static void Main() { System.Console.Write(Test1(new S1(10))); System.Console.Write(Test1(new S1(0))); System.Console.Write(Test1(new S1(""10""))); System.Console.Write(Test1(new S1(null))); System.Console.Write(Test1(default)); } static bool Test1(S1 u) { return u is 10; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); CompileAndVerify(comp, expectedOutput: "TrueFalseFalseFalseFalse").VerifyDiagnostics(); } [Fact] public void TryGetValueMethod_09() { var src = @" class S0<T>(object value) { private readonly object _value = value; public object Value => throw null; public bool TryGetValue(out T value) { if (_value is T) { value = (T)_value; return true; } else { value = default; return false; } } } [System.Runtime.CompilerServices.Union] class S1 : S0<int> { public S1(int x) : base(x) {} public S1(string x) : base(x) {} } class Program { static void Main() { System.Console.Write(Test1(new S1(10))); System.Console.Write(Test1(new S1(0))); System.Console.Write(Test1(new S1(""10""))); System.Console.Write(Test1(new S1(null))); System.Console.Write(Test1(default)); } static bool Test1(S1 u) { return u is 10; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); CompileAndVerify(comp, expectedOutput: "TrueFalseFalseFalseFalse").VerifyDiagnostics(); } [Fact] public void TryGetValueMethod_10() { var src = @" class S0<T1, T2>(object value) { private readonly object _value = value; public object Value => throw null; public T1 TryGetValue(out int value) { if (_value is int) { value = (int)_value; return (T1)(object)true; } else { value = 0; return (T1)(object)false; } } } [System.Runtime.CompilerServices.Union] class S1<T> : S0<bool, T> { public S1(int x) : base(x) {} public S1(string x) : base(x) {} } class Program { static void Main() { System.Console.Write(Test1(new S1<Program>(10))); System.Console.Write(Test1(new S1<Program>(0))); System.Console.Write(Test1(new S1<Program>(""10""))); System.Console.Write(Test1(new S1<Program>(null))); System.Console.Write(Test1(default)); } static bool Test1(S1<Program> u) { return u is 10; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); CompileAndVerify(comp, expectedOutput: "TrueFalseFalseFalseFalse").VerifyDiagnostics(); } [Fact] public void TryGetValueMethod_11() { var src = @" class S0<T1, T2>(object value) { private readonly object _value = value; public object Value => throw null; public bool TryGetValue(out T1 value) { if (_value is T1) { value = (T1)_value; return true; } else { value = default; return false; } } } [System.Runtime.CompilerServices.Union] class S1<T> : S0<int, T> { public S1(int x) : base(x) {} public S1(string x) : base(x) {} } class Program { static void Main() { System.Console.Write(Test1(new S1<Program>(10))); System.Console.Write(Test1(new S1<Program>(0))); System.Console.Write(Test1(new S1<Program>(""10""))); System.Console.Write(Test1(new S1<Program>(null))); System.Console.Write(Test1(default)); } static bool Test1(S1<Program> u) { return u is 10; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); CompileAndVerify(comp, expectedOutput: "TrueFalseFalseFalseFalse").VerifyDiagnostics(); } [Fact] public void TryGetValueMethod_12() { var src = @" class S0<T>(object value) { private readonly object _value = value; public object Value => _value; public T TryGetValue(out int value) => throw null; } [System.Runtime.CompilerServices.Union] class S1<T> : S0<T> { public S1(int x) : base(x) {} public S1(string x) : base(x) {} } class Program { static void Main() { System.Console.Write(Test1(new S1<bool>(10))); System.Console.Write(Test1(new S1<bool>(0))); System.Console.Write(Test1(new S1<bool>(""10""))); System.Console.Write(Test1(new S1<bool>(null))); System.Console.Write(Test1(default)); } static bool Test1(S1<bool> u) { return u is 10; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); CompileAndVerify(comp, expectedOutput: "TrueFalseFalseFalseFalse").VerifyDiagnostics(); } [Fact] public void TryGetValueMethod_13() { var src = @" class S0<T>(object value) { private readonly object _value = value; public object Value => _value; public bool TryGetValue(out T value) => throw null; } [System.Runtime.CompilerServices.Union] class S1<T> : S0<T> { public S1(int x) : base(x) {} public S1(string x) : base(x) {} } class Program { static void Main() { System.Console.Write(Test1(new S1<int>(10))); System.Console.Write(Test1(new S1<int>(0))); System.Console.Write(Test1(new S1<int>(""10""))); System.Console.Write(Test1(new S1<int>(null))); System.Console.Write(Test1(default)); } static bool Test1(S1<int> u) { return u is 10; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); CompileAndVerify(comp, expectedOutput: "TrueFalseFalseFalseFalse").VerifyDiagnostics(); } [Fact] public void TryGetValueMethod_14() { var src = @" class S0(object value) { private readonly object _value = value; public object Value => throw null; public bool TryGetValue(out int value) { if (_value is int) { value = (int)_value; return true; } else { value = 0; return false; } } } [System.Runtime.CompilerServices.Union] class S1 : S0 { public S1(int x) : base(x) {} public S1(string x) : base(x) {} public S1(bool x) : base(x) {} } class Program { static void Main() { System.Console.Write(Test1(new S1(10))); System.Console.Write(Test1(default)); System.Console.Write(Test1(new S1(""11""))); System.Console.Write(Test1(new S1(true))); System.Console.Write(Test1(new S0(10))); System.Console.Write(Test1(new S0(""11""))); System.Console.Write(Test1(new S0(true))); } static bool Test1(S0 u) { return u is S1 and 10; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); CompileAndVerify(comp, expectedOutput: "TrueFalseFalseFalseFalseFalseFalse").VerifyDiagnostics(); } [Fact] public void TryGetValueMethod_15_Override() { var src1 = @" class S0(object value) { protected readonly object _value = value; public object Value => throw null; public virtual bool TryGetValue(out int value) => throw null; } [System.Runtime.CompilerServices.Union] class S1 : S0 { public S1(int x) : base(x) {} public S1(string x) : base(x) {} public S1(bool x) : base(x) {} public override bool TryGetValue(out int value) { if (_value is int) { value = (int)_value; return true; } else { value = 0; return false; } } } class Program { static void Main() { System.Console.Write(Test1(new S1(10))); System.Console.Write(Test1(default)); System.Console.Write(Test1(new S1(""11""))); System.Console.Write(Test1(new S1(true))); } static bool Test1(S1 u) { return u is 10; } } "; var comp = CreateCompilation([src1, UnionAttributeSource], options: TestOptions.ReleaseExe); var verifier = CompileAndVerify(comp, expectedOutput: "TrueFalseFalseFalse").VerifyDiagnostics(); verifier.VerifyIL("Program.Test1", @" { // Code size 21 (0x15) .maxstack 2 .locals init (int V_0) IL_0000: ldarg.0 IL_0001: brfalse.s IL_0013 IL_0003: ldarg.0 IL_0004: ldloca.s V_0 IL_0006: callvirt ""bool S0.TryGetValue(out int)"" IL_000b: brfalse.s IL_0013 IL_000d: ldloc.0 IL_000e: ldc.i4.s 10 IL_0010: ceq IL_0012: ret IL_0013: ldc.i4.0 IL_0014: ret } "); } [Fact] public void TryGetValueMethod_16() { var src = @" [System.Runtime.CompilerServices.Union] class S1<T> { private readonly object _value; public S1(T x) { _value = x; } public S1(string x) { _value = x; } public object Value => throw null; public bool TryGetValue(out T value) { if (_value is T) { value = (T)_value; return true; } else { value = default; return false; } } public bool Test(out T value) { if (this is T and var val) { value = val; return true; } else { value = default; return false; } } } class Program { static void Main() { System.Console.Write((new S1<int>(10) ).Test(out var _)); System.Console.Write((new S1<int>(0)).Test(out var _)); System.Console.Write((new S1<int>(""10"")).Test(out var _)); System.Console.Write((new S1<int>(null)).Test(out var _)); System.Console.WriteLine(); System.Console.Write((new S1<int?>((int?)null)).Test(out var _)); System.Console.Write((new S1<int?>(4)).Test(out var x)); System.Console.Write(x); System.Console.WriteLine(); var s = new S1<int?>(4); System.Console.Write(s is 4); System.Console.Write(s is 1); } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); comp.VerifyDiagnostics( // (13,31): error CS8780: A variable may not be declared within a 'not' or an 'or' pattern or a union matching involving matching against either the instance, or its underlying value. // if (this is T and var val) Diagnostic(ErrorCode.ERR_DesignatorBeneathPatternCombinator, "val").WithLocation(13, 31) ); } [Fact] public void TryGetValueMethod_17() { var src = @" [System.Runtime.CompilerServices.Union] class S1<T> { private readonly object _value; public S1(T x) { _value = x; } public S1(string x) { _value = x; } public object Value => _value; public bool TryGetValue(out int value) => throw null; } class Program { static void Main() { System.Console.Write((new S1<int>(10)) is 10); System.Console.Write((new S1<int>(1)) is 10); } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); CompileAndVerify(comp, expectedOutput: @"TrueFalse").VerifyDiagnostics(); } [Fact] public void TryGetValueMethod_18() { var src = @" [System.Runtime.CompilerServices.Union] class S1<T> { private readonly object _value; public S1(T x) { _value = x; } public S1(int x) { _value = x; } public object Value => throw null; public bool TryGetValue(out T value) { if (_value is T) { value = (T)_value; return true; } else { value = default; return false; } } } class Program { static void Main() { System.Console.Write((new S1<int>(10)) is 10); System.Console.Write((new S1<int>(1)) is 10); } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); CompileAndVerify(comp, expectedOutput: @"TrueFalse").VerifyDiagnostics(); } [Theory] [CombinatorialData] public void TryGetValueMethod_19_Determinism( [CombinatorialValues( """ public S1(T x) { _value = x; } public S1(int x) { _value = x; } """, """ public S1(int x) { _value = x; } public S1(T x) { _value = x; } """)] string constructors, [CombinatorialValues( """ public bool TryGetValue(out T value) { if (_value is T) { value = (T)_value; return true; } else { value = default; return false; } } public bool TryGetValue(out int value) => throw null; """, """ public bool TryGetValue(out int value) { if (_value is int) { value = (int)_value; return true; } else { value = 0; return false; } } public bool TryGetValue(out T value) => throw null; """)] string tryGetValues) { var src1 = @" [System.Runtime.CompilerServices.Union] public class S1<T> { private readonly object _value; " + constructors + @" public object Value => throw null; " + tryGetValues + @" } "; var src2 = @" class Program { static void Main() { System.Console.Write((new S1<int>(10)) is 10); System.Console.Write((new S1<int>(1)) is 10); } } "; var comp1 = CreateCompilation([src1, src2, UnionAttributeSource], options: TestOptions.ReleaseExe); CompileAndVerify(comp1, expectedOutput: @"TrueFalse").VerifyDiagnostics(); var comp2 = CreateCompilation(src2, references: [comp1.EmitToImageReference()], options: TestOptions.ReleaseExe); CompileAndVerify(comp2, expectedOutput: @"TrueFalse").VerifyDiagnostics(); } [Theory] [CombinatorialData] public void TryGetValueMethod_20( [CombinatorialValues( """ public S1(string? x) {} public S1(T x) {} """, """ public S1(T x) {} public S1(string? x) {} """)] string constructors, [CombinatorialValues( """ public bool TryGetValue(out string? value) => throw null!; public bool TryGetValue(out T value) => throw null!; """, """ public bool TryGetValue(out T value) => throw null!; public bool TryGetValue(out string? value) => throw null!; """)] string tryGetValues) { var src = @" #nullable enable [System.Runtime.CompilerServices.Union] public class S1<T> { " + constructors + @" public object? Value => throw null!; " + tryGetValues + @" } class Program { static void Test2(S1<string?> s) { if (s.TryGetValue(out var value)) { #line 100 _ = s switch { string => 1 }; value.ToString(); } else { #line 200 _ = s switch { string => 1 }; value.ToString(); } } static void Test4(S1<string?> s) { if (!s.TryGetValue(out var value)) { #line 300 _ = s switch { string => 1 }; value.ToString(); } else { #line 400 _ = s switch { string => 1 }; value.ToString(); } } } "; var comp = CreateCompilation([src, UnionAttributeSource]); comp.VerifyDiagnostics( // (200,19): warning CS8655: The switch expression does not handle some null inputs (it is not exhaustive). For example, the pattern 'null' is not covered. // _ = s switch { string => 1 }; Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustiveForNull, "switch").WithArguments("null").WithLocation(200, 19), // (201,13): warning CS8602: Dereference of a possibly null reference. // value.ToString(); Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "value").WithLocation(201, 13), // (300,19): warning CS8655: The switch expression does not handle some null inputs (it is not exhaustive). For example, the pattern 'null' is not covered. // _ = s switch { string => 1 }; Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustiveForNull, "switch").WithArguments("null").WithLocation(300, 19), // (301,13): warning CS8602: Dereference of a possibly null reference. // value.ToString(); Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "value").WithLocation(301, 13) ); } [Theory] [CombinatorialData] public void TryGetValueMethod_21( [CombinatorialValues( """ public S1(string? x) {} public S1(T x) {} """, """ public S1(T x) {} public S1(string? x) {} """)] string constructors, [CombinatorialValues( """ public bool TryGetValue(out string? value) => throw null!; public bool TryGetValue(out T value) => throw null!; """, """ public bool TryGetValue(out T value) => throw null!; public bool TryGetValue(out string? value) => throw null!; """)] string tryGetValues) { var src = @" #nullable enable public class S0<T> { " + tryGetValues + @" } [System.Runtime.CompilerServices.Union] public class S1<T> : S0<T> { " + constructors + @" public object? Value => throw null!; } class Program { static void Test2(S1<string?> s) { if (s.TryGetValue(out var value)) { #line 100 _ = s switch { string => 1 }; value.ToString(); } else { #line 200 _ = s switch { string => 1 }; value.ToString(); } } static void Test4(S1<string?> s) { if (!s.TryGetValue(out var value)) { #line 300 _ = s switch { string => 1 }; value.ToString(); } else { #line 400 _ = s switch { string => 1 }; value.ToString(); } } } "; var comp = CreateCompilation([src, UnionAttributeSource]); comp.VerifyDiagnostics( // (200,19): warning CS8655: The switch expression does not handle some null inputs (it is not exhaustive). For example, the pattern 'null' is not covered. // _ = s switch { string => 1 }; Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustiveForNull, "switch").WithArguments("null").WithLocation(200, 19), // (201,13): warning CS8602: Dereference of a possibly null reference. // value.ToString(); Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "value").WithLocation(201, 13), // (300,19): warning CS8655: The switch expression does not handle some null inputs (it is not exhaustive). For example, the pattern 'null' is not covered. // _ = s switch { string => 1 }; Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustiveForNull, "switch").WithArguments("null").WithLocation(300, 19), // (301,13): warning CS8602: Dereference of a possibly null reference. // value.ToString(); Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "value").WithLocation(301, 13) ); } [Theory] [CombinatorialData] public void TryGetValueMethod_22( [CombinatorialValues( """ public S1(int? x) {} public bool TryGetValue(out T? value) => throw null!; """, """ public S1(T? x) {} public bool TryGetValue(out int? value) => throw null!; """)] string members) { var src = @" #nullable enable [System.Runtime.CompilerServices.Union] public class S1<T> where T : struct { " + members + @" public object Value => throw null!; } class Program { static void Test2(S1<int> s) { if (s.TryGetValue(out var value)) { #line 100 _ = s switch { int => 1 }; } else { #line 200 _ = s switch { int => 1 }; } } static void Test4(S1<int> s) { if (!s.TryGetValue(out var value)) { #line 300 _ = s switch { int => 1 }; } else { #line 400 _ = s switch { int => 1 }; } } } "; var comp = CreateCompilation([src, UnionAttributeSource]); comp.VerifyDiagnostics( // (100,19): warning CS8655: The switch expression does not handle some null inputs (it is not exhaustive). For example, the pattern 'null' is not covered. // _ = s switch { int => 1 }; Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustiveForNull, "switch").WithArguments("null").WithLocation(100, 19), // (200,19): warning CS8655: The switch expression does not handle some null inputs (it is not exhaustive). For example, the pattern 'null' is not covered. // _ = s switch { int => 1 }; Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustiveForNull, "switch").WithArguments("null").WithLocation(200, 19), // (300,19): warning CS8655: The switch expression does not handle some null inputs (it is not exhaustive). For example, the pattern 'null' is not covered. // _ = s switch { int => 1 }; Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustiveForNull, "switch").WithArguments("null").WithLocation(300, 19), // (400,19): warning CS8655: The switch expression does not handle some null inputs (it is not exhaustive). For example, the pattern 'null' is not covered. // _ = s switch { int => 1 }; Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustiveForNull, "switch").WithArguments("null").WithLocation(400, 19) ); } [Fact] public void TryGetValueMethod_23() { var src = @" #nullable enable public class S0 { public bool TryGetValue(out int value) => throw null!; } [System.Runtime.CompilerServices.Union] public class S1<T> : S0 where T : struct { public S1(T? x) {} public object Value => throw null!; } class Program { static void Test2(S1<int> s) { if (s.TryGetValue(out var value)) { #line 100 _ = s switch { int => 1 }; } else { #line 200 _ = s switch { int => 1 }; } } static void Test4(S1<int> s) { if (!s.TryGetValue(out var value)) { #line 300 _ = s switch { int => 1 }; } else { #line 400 _ = s switch { int => 1 }; } } } "; var comp = CreateCompilation([src, UnionAttributeSource]); comp.VerifyDiagnostics( // (100,19): warning CS8655: The switch expression does not handle some null inputs (it is not exhaustive). For example, the pattern 'null' is not covered. // _ = s switch { int => 1 }; Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustiveForNull, "switch").WithArguments("null").WithLocation(100, 19), // (200,19): warning CS8655: The switch expression does not handle some null inputs (it is not exhaustive). For example, the pattern 'null' is not covered. // _ = s switch { int => 1 }; Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustiveForNull, "switch").WithArguments("null").WithLocation(200, 19), // (300,19): warning CS8655: The switch expression does not handle some null inputs (it is not exhaustive). For example, the pattern 'null' is not covered. // _ = s switch { int => 1 }; Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustiveForNull, "switch").WithArguments("null").WithLocation(300, 19), // (400,19): warning CS8655: The switch expression does not handle some null inputs (it is not exhaustive). For example, the pattern 'null' is not covered. // _ = s switch { int => 1 }; Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustiveForNull, "switch").WithArguments("null").WithLocation(400, 19) ); } [Fact] public void TryGetValueMethod_24() { var src = @" #nullable enable public class S0<T> where T : struct { public bool TryGetValue(out T? value) => throw null!; } [System.Runtime.CompilerServices.Union] public class S1<T> : S0<T> where T : struct { public S1(int? x) {} public object Value => throw null!; } class Program { static void Test2(S1<int> s) { if (s.TryGetValue(out var value)) { #line 100 _ = s switch { int => 1 }; } else { #line 200 _ = s switch { int => 1 }; } } static void Test4(S1<int> s) { if (!s.TryGetValue(out var value)) { #line 300 _ = s switch { int => 1 }; } else { #line 400 _ = s switch { int => 1 }; } } } "; var comp = CreateCompilation([src, UnionAttributeSource]); comp.VerifyDiagnostics( // (100,19): warning CS8655: The switch expression does not handle some null inputs (it is not exhaustive). For example, the pattern 'null' is not covered. // _ = s switch { int => 1 }; Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustiveForNull, "switch").WithArguments("null").WithLocation(100, 19), // (200,19): warning CS8655: The switch expression does not handle some null inputs (it is not exhaustive). For example, the pattern 'null' is not covered. // _ = s switch { int => 1 }; Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustiveForNull, "switch").WithArguments("null").WithLocation(200, 19), // (300,19): warning CS8655: The switch expression does not handle some null inputs (it is not exhaustive). For example, the pattern 'null' is not covered. // _ = s switch { int => 1 }; Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustiveForNull, "switch").WithArguments("null").WithLocation(300, 19), // (400,19): warning CS8655: The switch expression does not handle some null inputs (it is not exhaustive). For example, the pattern 'null' is not covered. // _ = s switch { int => 1 }; Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustiveForNull, "switch").WithArguments("null").WithLocation(400, 19) ); } [Fact] public void TryGetValueMethod_25_ImplicitReferenceConversion() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 { private readonly object _value; public S1(C1 x) { _value = x; } public object Value => throw null; public bool TryGetValue(out C1 value) { if (_value is C1) { value = (C1)_value; return true; } else { value = null; return false; } } } class C1; class C2 : C1; class Program { static void Main() { System.Console.Write(Test1(new S1(new C1()))); System.Console.Write(Test1(default)); System.Console.Write(Test1(new S1(new C2()))); } static bool Test1(S1 u) { return u is C2; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); var verifier = CompileAndVerify(comp, expectedOutput: "FalseFalseTrue").VerifyDiagnostics(); VerifyDecisionDagDump<BinaryExpressionSyntax>(comp, @"[0]: TryGetValue(C1): (Item1, ReturnItem) t1 = t0; [1] [1]: t1.ReturnItem == True ? [2] : [5] [2]: t2 = (C1)t1.Item1; [3] [3]: t2 is C2 ? [4] : [5] [4]: leaf <isPatternSuccess> `u is C2` [5]: leaf <isPatternFailure> `u is C2` ", index: 1, forLowering: true); verifier.VerifyIL("Program.Test1", @" { // Code size 23 (0x17) .maxstack 2 .locals init (C1 V_0) IL_0000: ldarga.s V_0 IL_0002: ldloca.s V_0 IL_0004: call ""bool S1.TryGetValue(out C1)"" IL_0009: brfalse.s IL_0015 IL_000b: ldloc.0 IL_000c: isinst ""C2"" IL_0011: ldnull IL_0012: cgt.un IL_0014: ret IL_0015: ldc.i4.0 IL_0016: ret } "); } [Theory] [CombinatorialData] public void TryGetValueMethod_26_ImplicitReferenceConversion_Vs_Identity( [CombinatorialValues( """ public S1(C1 x) { _value = x; } public S1(C2 x) { _value = x; } """, """ public S1(C2 x) { _value = x; } public S1(C1 x) { _value = x; } """)] string constructors, [CombinatorialValues( """ public bool TryGetValue(out C1 value) => throw null; public bool TryGetValue(out C2 value) { if (_value is C2) { value = (C2)_value; return true; } else { value = null; return false; } } """, """ public bool TryGetValue(out C2 value) { if (_value is C2) { value = (C2)_value; return true; } else { value = null; return false; } } public bool TryGetValue(out C1 value) => throw null; """)] string tryGetValues) { var src = @" [System.Runtime.CompilerServices.Union] struct S1 { private readonly object _value; public object Value => throw null; " + constructors + tryGetValues + @" } class C1; class C2 : C1; class Program { static void Main() { System.Console.Write(Test1(new S1(new C1()))); System.Console.Write(Test1(default)); System.Console.Write(Test1(new S1(new C2()))); } static bool Test1(S1 u) { return u is C2; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); CompileAndVerify(comp, expectedOutput: "FalseFalseTrue").VerifyDiagnostics(); } [Theory] [CombinatorialData] public void TryGetValueMethod_27_ImplicitReferenceConversion_Vs_Identity( [CombinatorialValues( """ public S1(C1 x) : base(x) {} public S1(C2 x) : base(x) {} """, """ public S1(C2 x) : base(x) {} public S1(C1 x) : base(x) {} """)] string constructors, [CombinatorialValues( new[] { "public bool TryGetValue(out C1 value) => throw null;", "public bool TryGetValue(out C2 value) { if (_value is C2) { value = (C2)_value; return true; } else { value = null; return false; } }" }, new[] { "public bool TryGetValue(out C2 value) { if (_value is C2) { value = (C2)_value; return true; } else { value = null; return false; } }", "public bool TryGetValue(out C1 value) => throw null;" })] string[] tryGetValues) { var src = @" class S0(object value) { protected readonly object _value = value; " + tryGetValues[0] + @" } [System.Runtime.CompilerServices.Union] class S1 : S0 { public object Value => throw null; " + constructors + @" " + tryGetValues[1] + @" } class C1; class C2 : C1; class Program { static void Main() { System.Console.Write(Test1(new S1(new C1()))); System.Console.Write(Test1(default)); System.Console.Write(Test1(new S1(new C2()))); } static bool Test1(S1 u) { return u is C2; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); CompileAndVerify(comp, expectedOutput: "FalseFalseTrue").VerifyDiagnostics(); } [Theory] [CombinatorialData] public void TryGetValueMethod_28_ImplicitReferenceConversion_Determinism( [CombinatorialValues( """ public S1(C1 x) { _value = x; } public S1(C0 x) { _value = x; } """, """ public S1(C0 x) { _value = x; } public S1(C1 x) { _value = x; } """)] string constructors, [CombinatorialValues( """ public bool TryGetValue(out C0 value) { if (_value is C0) { value = (C0)_value; return true; } else { value = null; return false; } } public bool TryGetValue(out C1 value) => throw null; """, """ public bool TryGetValue(out C1 value) { if (_value is C1) { value = (C1)_value; return true; } else { value = null; return false; } } public bool TryGetValue(out C0 value) => throw null; """)] string tryGetValues) { var src1 = @" [System.Runtime.CompilerServices.Union] public struct S1 { private readonly object _value; public object Value => throw null; " + constructors + tryGetValues + @" } public class C0; public class C1 : C0; public class C2 : C1; "; var src2 = @" class Program { static void Main() { System.Console.Write(Test1(new S1(new C1()))); System.Console.Write(Test1(default)); System.Console.Write(Test1(new S1(new C2()))); } static bool Test1(S1 u) { return u is C2; } } "; var comp1 = CreateCompilation([src1, src2, UnionAttributeSource], options: TestOptions.ReleaseExe); CompileAndVerify(comp1, expectedOutput: "FalseFalseTrue").VerifyDiagnostics(); var comp2 = CreateCompilation(src2, references: [comp1.EmitToImageReference()], options: TestOptions.ReleaseExe); CompileAndVerify(comp2, expectedOutput: "FalseFalseTrue").VerifyDiagnostics(); } [Theory] [CombinatorialData] public void TryGetValueMethod_29_ImplicitReferenceConversion__Determinism( [CombinatorialValues( """ public S1(C1 x) : base(x) {} public S1(C0 x) : base(x) {} """, """ public S1(C0 x) : base(x) {} public S1(C1 x) : base(x) {} """)] string constructors, [CombinatorialValues( new[] { "public bool TryGetValue(out C1 value) => throw null;", "public bool TryGetValue(out C0 value) { if (_value is C0) { value = (C0)_value; return true; } else { value = null; return false; } }" }, new[] { "public bool TryGetValue(out C0 value) => throw null;", "public bool TryGetValue(out C1 value) { if (_value is C1) { value = (C1)_value; return true; } else { value = null; return false; } }" })] string[] tryGetValues) { var src1 = @" public class S0(object value) { protected readonly object _value = value; " + tryGetValues[0] + @" } [System.Runtime.CompilerServices.Union] public class S1 : S0 { public object Value => throw null; " + constructors + @" " + tryGetValues[1] + @" } public class C0; public class C1 : C0; public class C2 : C1; "; var src2 = @" class Program { static void Main() { System.Console.Write(Test1(new S1(new C1()))); System.Console.Write(Test1(default)); System.Console.Write(Test1(new S1(new C2()))); } static bool Test1(S1 u) { return u is C2; } } "; var comp1 = CreateCompilation([src1, src2, UnionAttributeSource], options: TestOptions.ReleaseExe); CompileAndVerify(comp1, expectedOutput: "FalseFalseTrue").VerifyDiagnostics(); var comp2 = CreateCompilation(src2, references: [comp1.EmitToImageReference()], options: TestOptions.ReleaseExe); CompileAndVerify(comp2, expectedOutput: "FalseFalseTrue").VerifyDiagnostics(); } [Fact] public void TryGetValueMethod_30_BoxingConversion() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 { private readonly object _value; public S1(System.IComparable x) { _value = x; } public object Value => throw null; public bool TryGetValue(out System.IComparable value) { if (_value is System.IComparable) { value = (System.IComparable)_value; return true; } else { value = null; return false; } } } class Program { static void Main() { System.Console.Write(Test1(new S1(""""))); System.Console.Write(Test1(default)); System.Console.Write(Test1(new S1(1))); } static bool Test1(S1 u) { return u is 1; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); var verifier = CompileAndVerify(comp, expectedOutput: "FalseFalseTrue").VerifyDiagnostics(); VerifyDecisionDagDump<IsPatternExpressionSyntax>(comp, @"[0]: TryGetValue(System.IComparable): (Item1, ReturnItem) t1 = t0; [1] [1]: t1.ReturnItem == True ? [2] : [7] [2]: t2 = (System.IComparable)t1.Item1; [3] [3]: t2 is int ? [4] : [7] [4]: t3 = (int)t2; [5] [5]: t3 == 1 ? [6] : [7] [6]: leaf <isPatternSuccess> `1` [7]: leaf <isPatternFailure> `u is 1` ", forLowering: true); verifier.VerifyIL("Program.Test1", @" { // Code size 33 (0x21) .maxstack 2 .locals init (System.IComparable V_0, System.IComparable V_1) IL_0000: ldarga.s V_0 IL_0002: ldloca.s V_0 IL_0004: call ""bool S1.TryGetValue(out System.IComparable)"" IL_0009: brfalse.s IL_001f IL_000b: ldloc.0 IL_000c: stloc.1 IL_000d: ldloc.1 IL_000e: isinst ""int"" IL_0013: brfalse.s IL_001f IL_0015: ldloc.1 IL_0016: unbox.any ""int"" IL_001b: ldc.i4.1 IL_001c: ceq IL_001e: ret IL_001f: ldc.i4.0 IL_0020: ret } "); } [Theory] [CombinatorialData] public void TryGetValueMethod_31_BoxingConversion_Vs_Identity( [CombinatorialValues( """ public S1(System.IComparable x) { _value = x; } public S1(int x) { _value = x; } """, """ public S1(int x) { _value = x; } public S1(System.IComparable x) { _value = x; } """)] string constructors, [CombinatorialValues( """ public bool TryGetValue(out System.IComparable value) => throw null; public bool TryGetValue(out int value) { if (_value is int) { value = (int)_value; return true; } else { value = 0; return false; } } """, """ public bool TryGetValue(out int value) { if (_value is int) { value = (int)_value; return true; } else { value = 0; return false; } } public bool TryGetValue(out System.IComparable value) => throw null; """)] string tryGetValues) { var src = @" [System.Runtime.CompilerServices.Union] struct S1 { private readonly object _value; public object Value => throw null; " + constructors + tryGetValues + @" } class Program { static void Main() { System.Console.Write(Test1(new S1(""""))); System.Console.Write(Test1(default)); System.Console.Write(Test1(new S1(1))); } static bool Test1(S1 u) { return u is 1; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); CompileAndVerify(comp, expectedOutput: "FalseFalseTrue").VerifyDiagnostics(); } [Theory] [CombinatorialData] public void TryGetValueMethod_32_BoxingConversion_Vs_Identity( [CombinatorialValues( """ public S1(System.IComparable x) : base(x) {} public S1(int x) : base(x) {} """, """ public S1(int x) : base(x) {} public S1(System.IComparable x) : base(x) {} """)] string constructors, [CombinatorialValues( new[] { "public bool TryGetValue(out System.IComparable value) => throw null;", "public bool TryGetValue(out int value) { if (_value is int) { value = (int)_value; return true; } else { value = 0; return false; } }" }, new[] { "public bool TryGetValue(out int value) { if (_value is int) { value = (int)_value; return true; } else { value = 0; return false; } }", "public bool TryGetValue(out System.IComparable value) => throw null;" })] string[] tryGetValues) { var src = @" class S0(object value) { protected readonly object _value = value; " + tryGetValues[0] + @" } [System.Runtime.CompilerServices.Union] class S1 : S0 { public object Value => throw null; " + constructors + @" " + tryGetValues[1] + @" } class Program { static void Main() { System.Console.Write(Test1(new S1(""""))); System.Console.Write(Test1(default)); System.Console.Write(Test1(new S1(1))); } static bool Test1(S1 u) { return u is 1; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); CompileAndVerify(comp, expectedOutput: "FalseFalseTrue").VerifyDiagnostics(); } [Theory] [CombinatorialData] public void TryGetValueMethod_33_BoxingConversion_Determinism( [CombinatorialValues( """ public S1(System.IComparable x) { _value = x; } public S1(System.IConvertible x) { _value = x; } """, """ public S1(System.IConvertible x) { _value = x; } public S1(System.IComparable x) { _value = x; } """)] string constructors, [CombinatorialValues( """ public bool TryGetValue(out System.IConvertible value) { if (_value is System.IConvertible) { value = (System.IConvertible)_value; return true; } else { value = 0; return false; } } public bool TryGetValue(out System.IComparable value) => throw null; """, """ public bool TryGetValue(out System.IComparable value) { if (_value is System.IComparable) { value = (System.IComparable)_value; return true; } else { value = 0; return false; } } public bool TryGetValue(out System.IConvertible value) => throw null; """)] string tryGetValues) { var src1 = @" [System.Runtime.CompilerServices.Union] public struct S1 { private readonly object _value; public object Value => throw null; " + constructors + tryGetValues + @" } "; var src2 = @" class Program { static void Main() { System.Console.Write(Test1(new S1((System.IComparable)""""))); System.Console.Write(Test1(default)); System.Console.Write(Test1(new S1((System.IComparable)1))); } static bool Test1(S1 u) { return u is 1; } } "; var comp1 = CreateCompilation([src1, src2, UnionAttributeSource], options: TestOptions.ReleaseExe); CompileAndVerify(comp1, expectedOutput: "FalseFalseTrue").VerifyDiagnostics(); var comp2 = CreateCompilation(src2, references: [comp1.EmitToImageReference()], options: TestOptions.ReleaseExe); CompileAndVerify(comp2, expectedOutput: "FalseFalseTrue").VerifyDiagnostics(); } [Theory] [CombinatorialData] public void TryGetValueMethod_34_BoxingConversion_Determinism( [CombinatorialValues( """ public S1(System.IComparable x) : base(x) {} public S1(System.IConvertible x) : base(x) {} """, """ public S1(System.IConvertible x) : base(x) {} public S1(System.IComparable x) : base(x) {} """)] string constructors, [CombinatorialValues( new[] { "public bool TryGetValue(out System.IComparable value) => throw null;", "public bool TryGetValue(out System.IConvertible value) { if (_value is System.IConvertible) { value = (System.IConvertible)_value; return true; } else { value = 0; return false; } }" }, new[] { "public bool TryGetValue(out System.IConvertible value) => throw null;", "public bool TryGetValue(out System.IComparable value) { if (_value is System.IComparable) { value = (System.IComparable)_value; return true; } else { value = 0; return false; } }" })] string[] tryGetValues) { var src1 = @" public class S0(object value) { protected readonly object _value = value; " + tryGetValues[0] + @" } [System.Runtime.CompilerServices.Union] public class S1 : S0 { public object Value => throw null; " + constructors + @" " + tryGetValues[1] + @" } "; var src2 = @" class Program { static void Main() { System.Console.Write(Test1(new S1((System.IConvertible)""""))); System.Console.Write(Test1(default)); System.Console.Write(Test1(new S1((System.IConvertible)1))); } static bool Test1(S1 u) { return u is 1; } } "; var comp1 = CreateCompilation([src1, src2, UnionAttributeSource], options: TestOptions.ReleaseExe); CompileAndVerify(comp1, expectedOutput: "FalseFalseTrue").VerifyDiagnostics(); var comp2 = CreateCompilation(src2, references: [comp1.EmitToImageReference()], options: TestOptions.ReleaseExe); CompileAndVerify(comp2, expectedOutput: "FalseFalseTrue").VerifyDiagnostics(); } [Fact] public void TryGetValueMethod_35_Dynamic() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 { private readonly object _value; public S1(dynamic x) { _value = x; } public object Value => throw null; public bool TryGetValue(out dynamic value) { value = (dynamic)_value; return value is not null; } } class C1; class C2 : C1; class Program { static void Main() { System.Console.Write(Test1(new S1(new C1()))); System.Console.Write(Test1(default)); System.Console.Write(Test1(new S1(new C2()))); } static bool Test1(S1 u) { return u is C2; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); CompileAndVerify(comp, expectedOutput: "FalseFalseTrue").VerifyDiagnostics(); } [Fact] public void TryGetValueMethod_36_Dynamic() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 { private readonly object _value; public S1(object x) { _value = x; } public object Value => throw null; public bool TryGetValue(out object value) { value = _value; return value is not null; } } class C1; struct S2; class Program { static void Main() { System.Console.Write(Test1(new S1(new C1()))); System.Console.Write(Test1(default)); System.Console.Write(Test1(new S1(new object()))); } static bool Test1(S1 u) { #line 100 return u is dynamic; } static bool Test2(S2 u) { #line 200 return u is dynamic; } static bool Test3(S1 u) { #line 300 return u switch { dynamic => true, _ => false }; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); comp.VerifyDiagnostics( // (100,16): warning CS1981: Using 'is' to test compatibility with 'dynamic' is essentially identical to testing compatibility with 'Object' and will succeed for all non-null values // return u is dynamic; Diagnostic(ErrorCode.WRN_IsDynamicIsConfusing, "u is dynamic").WithArguments("is", "dynamic", "Object").WithLocation(100, 16), // (100,16): warning CS0183: The given expression is always of the provided ('dynamic') type // return u is dynamic; Diagnostic(ErrorCode.WRN_IsAlwaysTrue, "u is dynamic").WithArguments("dynamic").WithLocation(100, 16), // (200,16): warning CS1981: Using 'is' to test compatibility with 'dynamic' is essentially identical to testing compatibility with 'Object' and will succeed for all non-null values // return u is dynamic; Diagnostic(ErrorCode.WRN_IsDynamicIsConfusing, "u is dynamic").WithArguments("is", "dynamic", "Object").WithLocation(200, 16), // (200,16): warning CS0183: The given expression is always of the provided ('dynamic') type // return u is dynamic; Diagnostic(ErrorCode.WRN_IsAlwaysTrue, "u is dynamic").WithArguments("dynamic").WithLocation(200, 16), // (300,27): error CS0103: The name 'dynamic' does not exist in the current context // return u switch { dynamic => true, _ => false }; Diagnostic(ErrorCode.ERR_NameNotInContext, "dynamic").WithArguments("dynamic").WithLocation(300, 27) ); } [Fact] public void TryGetValueMethod_37_UnsupportedConversion() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 { private readonly object _value; public S1(int x) { _value = x; } public S1(byte x) { _value = x; } public object Value => _value; public bool TryGetValue(out int value) => throw null; } class C1; class Program { static void Main() { System.Console.Write(Test1(new S1(1))); System.Console.Write(Test1(default)); System.Console.Write(Test1(new S1((byte)2))); } static bool Test1(S1 u) { return u is byte; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); CompileAndVerify(comp, expectedOutput: "FalseFalseTrue").VerifyDiagnostics(); } [Fact] public void TryGetValueMethod_38_ParameterTypeIsUnderlying() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 { private readonly object _value; public S1(int? x) { _value = x; } public S1(string x) { _value = x; } public object Value => throw null; public bool TryGetValue(out int x) { if (_value is int v) { x = v; return true; } x = 0; return false; } static void Main() { System.Console.Write(Test1(new S1(1))); System.Console.Write(Test1(new S1())); System.Console.Write(Test1(new S1(""a""))); System.Console.Write(Test2(new S1(2))); System.Console.Write(Test2(new S1())); System.Console.Write(Test2(new S1(""b""))); } static bool Test1(S1 u) { return u is int; } static bool Test2(S1 u) { return u is not int; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); var verifier = CompileAndVerify(comp, expectedOutput: "TrueFalseFalseFalseTrueTrue").VerifyDiagnostics(); verifier.VerifyIL("S1.Test1", @" { // Code size 10 (0xa) .maxstack 2 .locals init (int V_0) IL_0000: ldarga.s V_0 IL_0002: ldloca.s V_0 IL_0004: call ""bool S1.TryGetValue(out int)"" IL_0009: ret } "); verifier.VerifyIL("S1.Test2", @" { // Code size 13 (0xd) .maxstack 2 .locals init (int V_0) IL_0000: ldarga.s V_0 IL_0002: ldloca.s V_0 IL_0004: call ""bool S1.TryGetValue(out int)"" IL_0009: ldc.i4.0 IL_000a: ceq IL_000c: ret } "); } [Fact] public void TryGetValueMethod_39_NullableType() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 { private readonly object _value; public S1(int? x) { _value = x; } public S1(string x) { _value = x; } public object Value => throw null; public bool TryGetValue(out int? x) { if (_value is int v) { x = v; return true; } x = null; return false; } static void Main() { System.Console.Write(Test1(new S1(1))); System.Console.Write(Test1(new S1())); System.Console.Write(Test1(new S1(""a""))); System.Console.Write(Test2(new S1(2))); System.Console.Write(Test2(new S1())); System.Console.Write(Test2(new S1(""b""))); } static bool Test1(S1 u) { return u is int; } static bool Test2(S1 u) { return u is not int; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); var verifier = CompileAndVerify(comp, expectedOutput: "TrueFalseFalseFalseTrueTrue").VerifyDiagnostics(); verifier.VerifyIL("S1.Test1", @" { // Code size 10 (0xa) .maxstack 2 .locals init (int? V_0) IL_0000: ldarga.s V_0 IL_0002: ldloca.s V_0 IL_0004: call ""bool S1.TryGetValue(out int?)"" IL_0009: ret } "); verifier.VerifyIL("S1.Test2", @" { // Code size 13 (0xd) .maxstack 2 .locals init (int? V_0) IL_0000: ldarga.s V_0 IL_0002: ldloca.s V_0 IL_0004: call ""bool S1.TryGetValue(out int?)"" IL_0009: ldc.i4.0 IL_000a: ceq IL_000c: ret } "); } [Fact] public void TryGetValueMethod_40_NullableType() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 { private readonly object _value; public S1(int? x) { _value = x; } public S1(string x) { _value = x; } public object Value => _value; public bool TryGetValue(out int? x) { if (_value is int v) { x = v; return true; } x = null; return false; } static void Main() { System.Console.Write(Test1(new S1(1))); System.Console.Write(Test1(new S1())); System.Console.Write(Test1(new S1(""a""))); System.Console.Write(Test1(new S1(2))); } static bool Test1(S1 u) { return u is 2; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); VerifyDecisionDagDump<IsPatternExpressionSyntax>(comp, @"[0]: TryGetValue(int?): (Item1, ReturnItem) t1 = t0; [1] [1]: t1.ReturnItem == True ? [2] : [5] [2]: t2 = (int)t1.Item1; [3] [3]: t2 == 2 ? [4] : [5] [4]: leaf <isPatternSuccess> `2` [5]: leaf <isPatternFailure> `u is 2` ", index: 1, forLowering: true); var verifier = CompileAndVerify(comp, expectedOutput: "FalseFalseFalseTrue").VerifyDiagnostics(); verifier.VerifyIL("S1.Test1", @" { // Code size 24 (0x18) .maxstack 2 .locals init (int? V_0) IL_0000: ldarga.s V_0 IL_0002: ldloca.s V_0 IL_0004: call ""bool S1.TryGetValue(out int?)"" IL_0009: brfalse.s IL_0016 IL_000b: ldloca.s V_0 IL_000d: call ""int int?.GetValueOrDefault()"" IL_0012: ldc.i4.2 IL_0013: ceq IL_0015: ret IL_0016: ldc.i4.0 IL_0017: ret } "); } [Theory] [CombinatorialData] public void TryGetValueMethod_41_NullableType_IdentityWins( [CombinatorialValues( new[] { "public bool TryGetValue(out int? x) => throw null;", "public bool TryGetValue(out int x) { if (_value is int v) { x = v; return true; } x = 0; return false; }" }, new[] { "public bool TryGetValue(out int x) { if (_value is int v) { x = v; return true; } x = 0; return false; }", "public bool TryGetValue(out int? x) => throw null;" })] string[] tryGetValues) { var src = @" [System.Runtime.CompilerServices.Union] struct S1 { private readonly object _value; public S1(int? x) { _value = x; } public S1(int x) { _value = x; } public object Value => throw null; " + tryGetValues[0] + @" " + tryGetValues[1] + @" static void Main() { System.Console.Write(Test1(new S1(1))); System.Console.Write(Test1(new S1())); System.Console.Write(Test1(new S1((int?)2))); System.Console.Write(Test1(new S1(2))); } static bool Test1(S1 u) { return u is 2; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); CompileAndVerify(comp, expectedOutput: "FalseFalseTrueTrue").VerifyDiagnostics(); } [Theory] [CombinatorialData] public void TryGetValueMethod_42_NullableType_BoxingLoses( [CombinatorialValues( new[] { "public bool TryGetValue(out System.IComparable x) => throw null;", "public bool TryGetValue(out int? x) { if (_value is int v) { x = v; return true; } x = null; return false; }" }, new[] { "public bool TryGetValue(out int? x) { if (_value is int v) { x = v; return true; } x = null; return false; }", "public bool TryGetValue(out System.IComparable x) => throw null;" })] string[] tryGetValues) { var src = @" [System.Runtime.CompilerServices.Union] struct S1 { private readonly object _value; public S1(int? x) { _value = x; } public S1(System.IComparable x) { _value = x; } public object Value => throw null; " + tryGetValues[0] + @" " + tryGetValues[1] + @" static void Main() { System.Console.Write(Test1(new S1(1))); System.Console.Write(Test1(new S1())); System.Console.Write(Test1(new S1((int?)2))); System.Console.Write(Test1(new S1(2))); } static bool Test1(S1 u) { return u is 2; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); CompileAndVerify(comp, expectedOutput: "FalseFalseTrueTrue").VerifyDiagnostics(); } [Fact] public void TryGetValueMethod_43_NullableType_NullableAnalysis() { var src = @" #nullable enable [System.Runtime.CompilerServices.Union] struct S1 { public S1(string? x) => throw null!; public S1(bool? x) => throw null!; public object Value => throw null!; public bool TryGetValue(out bool? x) => throw null!; } class Program { static void Test2(S1 s) { if (s.TryGetValue(out var value)) { #line 100 value.Value.ToString(); _ = s switch { string => 1, bool => 3 }; } else { #line 200 value.Value.ToString(); _ = s switch { string => 1, bool => 3 }; } } static void Test4(S1 s) { if (!s.TryGetValue(out var value)) { #line 300 value.Value.ToString(); _ = s switch { string => 1, bool => 3 }; } else { #line 400 value.Value.ToString(); _ = s switch { string => 1, bool => 3 }; } } } "; var comp = CreateCompilation([src, UnionAttributeSource]); comp.VerifyDiagnostics( // (200,13): warning CS8629: Nullable value type may be null. // value.Value.ToString(); Diagnostic(ErrorCode.WRN_NullableValueTypeMayBeNull, "value").WithLocation(200, 13), // (201,19): warning CS8655: The switch expression does not handle some null inputs (it is not exhaustive). For example, the pattern 'null' is not covered. // _ = s switch { string => 1, bool => 3 }; Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustiveForNull, "switch").WithArguments("null").WithLocation(201, 19), // (300,13): warning CS8629: Nullable value type may be null. // value.Value.ToString(); Diagnostic(ErrorCode.WRN_NullableValueTypeMayBeNull, "value").WithLocation(300, 13), // (301,19): warning CS8655: The switch expression does not handle some null inputs (it is not exhaustive). For example, the pattern 'null' is not covered. // _ = s switch { string => 1, bool => 3 }; Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustiveForNull, "switch").WithArguments("null").WithLocation(301, 19) ); } [Fact] public void TryGetValueMethod_44_NullableType_NullableAnalysis() { var src = @" #nullable enable [System.Runtime.CompilerServices.Union] struct S1 { public S1(string? x) => throw null!; public S1(bool? x) => throw null!; public object Value => throw null!; public bool TryGetValue(out bool x) => throw null!; } class Program { static void Test2(S1 s) { if (s.TryGetValue(out var value)) { #line 101 _ = s switch { string => 1, bool => 3 }; } else { #line 201 _ = s switch { string => 1, bool => 3 }; } } static void Test4(S1 s) { if (!s.TryGetValue(out var value)) { #line 301 _ = s switch { string => 1, bool => 3 }; } else { #line 401 _ = s switch { string => 1, bool => 3 }; } } } "; var comp = CreateCompilation([src, UnionAttributeSource]); comp.VerifyDiagnostics( // (201,19): warning CS8655: The switch expression does not handle some null inputs (it is not exhaustive). For example, the pattern 'null' is not covered. // _ = s switch { string => 1, bool => 3 }; Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustiveForNull, "switch").WithArguments("null").WithLocation(201, 19), // (301,19): warning CS8655: The switch expression does not handle some null inputs (it is not exhaustive). For example, the pattern 'null' is not covered. // _ = s switch { string => 1, bool => 3 }; Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustiveForNull, "switch").WithArguments("null").WithLocation(301, 19) ); } [Fact] public void TryGetValueMethod_45_Static() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } public object Value => _value; public static bool TryGetValue(out int x) => throw null; } class Program { static void Main() { System.Console.Write(Test1(new S1(1))); System.Console.Write(Test1(new S1())); } static bool Test1(S1 u) { return u is int; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); CompileAndVerify(comp, expectedOutput: "TrueFalse").VerifyDiagnostics(); } [Theory] [CombinatorialData] public void TryGetValueMethod_46_NotPublic([CombinatorialValues("internal", "private")] string accessibility) { var src = @" [System.Runtime.CompilerServices.Union] struct S1 { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } public object Value => _value; " + accessibility + @" bool TryGetValue(out int x) => throw null; static void Main() { System.Console.Write(Test1(new S1(1))); System.Console.Write(Test1(new S1())); } static bool Test1(S1 u) { return u is int; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); CompileAndVerify(comp, expectedOutput: "TrueFalse").VerifyDiagnostics(); } [Theory] [CombinatorialData] public void TryGetValueMethod_47_NotPublic([CombinatorialValues("internal", "private", "protected", "private protected", "protected internal")] string accessibility) { var src = @" [System.Runtime.CompilerServices.Union] class S1 { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } public object Value => _value; " + accessibility + @" bool TryGetValue(out int x) => throw null; static void Main() { System.Console.Write(Test1(new S1(1))); System.Console.Write(Test1(new S1(null))); } static bool Test1(S1 u) { return u is int; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); CompileAndVerify(comp, expectedOutput: "TrueFalse").VerifyDiagnostics(); } [Fact] public void TryGetValueMethod_48_Generic() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } public object Value => _value; public bool TryGetValue<T>(out int x) => throw null; } class Program { static void Main() { System.Console.Write(Test1(new S1(1))); System.Console.Write(Test1(new S1())); } static bool Test1(S1 u) { return u is int; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); CompileAndVerify(comp, expectedOutput: "TrueFalse").VerifyDiagnostics(); } [Theory] [CombinatorialData] public void TryGetValueMethod_49_WrongRefKind([CombinatorialValues("ref", "ref readonly")] string refModifier) { var src = @" [System.Runtime.CompilerServices.Union] struct S1 { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } public object Value => _value; public " + refModifier + @" bool TryGetValue(out int x) => throw null; } class Program { static void Main() { System.Console.Write(Test1(new S1(1))); System.Console.Write(Test1(new S1())); } static bool Test1(S1 u) { return u is int; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); CompileAndVerify(comp, expectedOutput: "TrueFalse").VerifyDiagnostics(); } [Theory] [CombinatorialData] public void TryGetValueMethod_50_WrongRefKind([CombinatorialValues("", "in", "ref", "ref readonly")] string refModifier) { var src = @" [System.Runtime.CompilerServices.Union] struct S1 { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } public object Value => _value; public bool TryGetValue(" + refModifier + @" int x) => throw null; } class Program { static void Main() { System.Console.Write(Test1(new S1(1))); System.Console.Write(Test1(new S1())); } static bool Test1(S1 u) { return u is int; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); CompileAndVerify(comp, expectedOutput: "TrueFalse").VerifyDiagnostics(); } [Fact] public void TryGetValueMethod_51_WrongParameterCount() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } public object Value => _value; public bool TryGetValue() => throw null; public bool TryGetValue(out int x, out int y) => throw null; } class Program { static void Main() { System.Console.Write(Test1(new S1(1))); System.Console.Write(Test1(new S1())); } static bool Test1(S1 u) { return u is int; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); CompileAndVerify(comp, expectedOutput: "TrueFalse").VerifyDiagnostics(); } [Fact] public void TryGetValueMethod_52_Overloaded() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } public object Value => throw null; public bool TryGetValue(out int x, out int y) => throw null; public bool TryGetValue(out int x) { if (_value is int v) { x = v; return true; } x = 0; return false; } public bool TryGetValue() => throw null; } class Program { static void Main() { System.Console.Write(Test1(new S1(1))); System.Console.Write(Test1(new S1())); } static bool Test1(S1 u) { return u is int; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); CompileAndVerify(comp, expectedOutput: "TrueFalse").VerifyDiagnostics(); } [Fact] public void TryGetValueMethod_53_Bad() { // [System.Runtime.CompilerServices.Union] // class S1 // { // private readonly object _value; // public S1(int x) { _value = x; } // public S1(string x) { _value = x; } // public object Value => _value; // // [CompilerFeatureRequired("SomeFeatureIsRequired")] // public bool TryGetValue(out int x) => throw null; // } var ilSource = @" .class public auto ansi beforefieldinit S1 extends [mscorlib]System.Object { .custom instance void System.Runtime.CompilerServices.UnionAttribute::.ctor() = ( 01 00 00 00 ) .field private initonly object _value .method public hidebysig specialname rtspecialname instance void .ctor ( int32 x ) cil managed { .maxstack 8 IL_0000: ldarg.0 IL_0001: call instance void [mscorlib]System.Object::.ctor() IL_0006: nop IL_0007: nop IL_0008: ldarg.0 IL_0009: ldarg.1 IL_000a: box [mscorlib]System.Int32 IL_000f: stfld object S1::_value IL_0014: ret } .method public hidebysig specialname rtspecialname instance void .ctor ( string x ) cil managed { .maxstack 8 IL_0000: ldarg.0 IL_0001: call instance void [mscorlib]System.Object::.ctor() IL_0006: nop IL_0007: nop IL_0008: ldarg.0 IL_0009: ldarg.1 IL_000a: stfld object S1::_value IL_000f: ret } .method public hidebysig specialname instance object get_Value () cil managed { .maxstack 8 IL_0000: ldarg.0 IL_0001: ldfld object S1::_value IL_0006: ret } .method public hidebysig instance bool TryGetValue ( [out] int32& x ) cil managed { .custom instance void System.Runtime.CompilerServices.CompilerFeatureRequiredAttribute::.ctor(string) = ( 01 00 15 53 6f 6d 65 46 65 61 74 75 72 65 49 73 52 65 71 75 69 72 65 64 00 00 ) .maxstack 8 IL_0000: ldnull IL_0001: throw } .property instance object Value() { .get instance object S1::get_Value() } } .class public auto ansi beforefieldinit System.Runtime.CompilerServices.UnionAttribute extends [mscorlib]System.Attribute { .method public hidebysig specialname rtspecialname instance void .ctor () cil managed { .maxstack 8 IL_0000: ldarg.0 IL_0001: call instance void [mscorlib]System.Attribute::.ctor() IL_0006: nop IL_0007: ret } } .class public auto ansi sealed beforefieldinit System.Runtime.CompilerServices.CompilerFeatureRequiredAttribute extends [mscorlib]System.Attribute { .custom instance void [mscorlib]System.AttributeUsageAttribute::.ctor(valuetype [mscorlib]System.AttributeTargets) = ( 01 00 ff 7f 00 00 02 00 54 02 0d 41 6c 6c 6f 77 4d 75 6c 74 69 70 6c 65 01 54 02 09 49 6e 68 65 72 69 74 65 64 00 ) .method public hidebysig specialname rtspecialname instance void .ctor ( string featureName ) cil managed { IL_000f: ret } } "; var src = @" class Program { static void Main() { System.Console.Write(Test1(new S1(10))); System.Console.Write(Test1(default)); } static bool Test1(S1 u) { return u is int; } } "; var comp = CreateCompilationWithIL(src, ilSource, options: TestOptions.ReleaseExe); CompileAndVerify(comp, expectedOutput: "TrueFalse").VerifyDiagnostics(); } /// <summary> /// <see cref="UnionMatching_05_Constant_01"/> /// </summary> [Fact] public void UnionMatching_MemberProvider_Value_01() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 : S1.IUnionMembers { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } public object Value => throw null; object IUnionMembers.Value => _value; public interface IUnionMembers { public static S1 Create(int x) => new S1(x); public static S1 Create(string x) => new S1(x); public object Value { get; } } } class Program { static void Main() { System.Console.Write(Test1(new S1(10))); System.Console.Write(Test1(default)); System.Console.Write(Test1(new S1(""11""))); System.Console.Write(Test1(new S1(0))); System.Console.Write(' '); System.Console.Write(Test4(new S1(11))); System.Console.Write(Test4(default)); System.Console.Write(Test4(new S1(""11""))); System.Console.Write(' '); System.Console.Write(Test5(new S1(10))); System.Console.Write(Test5(default(S1))); System.Console.Write(Test5(new S1(""11""))); System.Console.Write(Test5(new S1(0))); System.Console.Write(Test5(null)); } static bool Test1(S1 u) { return u is 10; } static bool Test4(S1 u) { return u is null; } static bool Test5(S1? u) { return u is 10; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); var verifier = CompileAndVerify(comp, expectedOutput: "TrueFalseFalseFalse FalseTrueFalse TrueFalseFalseFalseFalse").VerifyDiagnostics(); verifier.VerifyIL("Program.Test1", @" { // Code size 35 (0x23) .maxstack 2 .locals init (object V_0) IL_0000: ldarga.s V_0 IL_0002: constrained. ""S1"" IL_0008: callvirt ""object S1.IUnionMembers.Value.get"" IL_000d: stloc.0 IL_000e: ldloc.0 IL_000f: isinst ""int"" IL_0014: brfalse.s IL_0021 IL_0016: ldloc.0 IL_0017: unbox.any ""int"" IL_001c: ldc.i4.s 10 IL_001e: ceq IL_0020: ret IL_0021: ldc.i4.0 IL_0022: ret } "); verifier.VerifyIL("Program.Test5", @" { // Code size 52 (0x34) .maxstack 2 .locals init (S1 V_0, object V_1) IL_0000: ldarga.s V_0 IL_0002: call ""bool S1?.HasValue.get"" IL_0007: brfalse.s IL_0032 IL_0009: ldarga.s V_0 IL_000b: call ""S1 S1?.GetValueOrDefault()"" IL_0010: stloc.0 IL_0011: ldloca.s V_0 IL_0013: constrained. ""S1"" IL_0019: callvirt ""object S1.IUnionMembers.Value.get"" IL_001e: stloc.1 IL_001f: ldloc.1 IL_0020: isinst ""int"" IL_0025: brfalse.s IL_0032 IL_0027: ldloc.1 IL_0028: unbox.any ""int"" IL_002d: ldc.i4.s 10 IL_002f: ceq IL_0031: ret IL_0032: ldc.i4.0 IL_0033: ret } "); } /// <summary> /// <see cref="UnionMatching_05_Constant_02"/> /// </summary> [Fact] public void UnionMatching_MemberProvider_Value_02() { var src = @" [System.Runtime.CompilerServices.Union] class S1 : S1.IUnionMembers { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } public object Value => throw null; object IUnionMembers.Value => _value; public interface IUnionMembers { public static S1 Create(int x) => new S1(x); public static S1 Create(string x) => new S1(x); public object Value { get; } } } class Program { static void Main() { System.Console.Write(Test1(new S1(10))); System.Console.Write(Test1(default)); System.Console.Write(Test1(new S1(""11""))); System.Console.Write(Test1(new S1(0))); System.Console.Write(' '); System.Console.Write(Test4(new S1(11))); System.Console.Write(Test4(default)); System.Console.Write(Test4(new S1(""11""))); } static bool Test1(S1 u) { return u is 10; } static bool Test4(S1 u) { return u is null; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); var verifier = CompileAndVerify(comp, expectedOutput: "TrueFalseFalseFalse FalseTrueFalse").VerifyDiagnostics(); verifier.VerifyIL("Program.Test1", @" { // Code size 31 (0x1f) .maxstack 2 .locals init (object V_0) IL_0000: ldarg.0 IL_0001: brfalse.s IL_001d IL_0003: ldarg.0 IL_0004: callvirt ""object S1.IUnionMembers.Value.get"" IL_0009: stloc.0 IL_000a: ldloc.0 IL_000b: isinst ""int"" IL_0010: brfalse.s IL_001d IL_0012: ldloc.0 IL_0013: unbox.any ""int"" IL_0018: ldc.i4.s 10 IL_001a: ceq IL_001c: ret IL_001d: ldc.i4.0 IL_001e: ret } "); } [Fact] public void UnionMatching_MemberProvider_Value_03_Missing() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 : S1.IUnionMembers { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } public object Value => throw null; public interface IUnionMembers { public static S1 Create(int x) => new S1(x); public static S1 Create(string x) => new S1(x); } } class Program { static bool Test1(S1 u) { return u is 10; } } "; var comp = CreateCompilation([src, UnionAttributeSource]); comp.VerifyDiagnostics( // (3,8): error CS9386: A union member provider type must have an instance 'Value' property of type 'object?' or 'object'. The property must have a public get accessor. // struct S1 : S1.IUnionMembers Diagnostic(ErrorCode.ERR_MissingUnionValueProperty, "S1").WithLocation(3, 8), // (21,21): error CS0656: Missing compiler required member 'S1.IUnionMembers.Value' // return u is 10; Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "10").WithArguments("S1.IUnionMembers", "Value").WithLocation(21, 21) ); } [Fact] public void UnionMatching_MemberProvider_Value_04_Generic() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 : S1.IUnionMembers<object> { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } public object Value => _value; object IUnionMembers<object>.Value => throw null; public interface IUnionMembers<T> { public static S1 Create(int x) => throw null; public T Value { get; } } } class Program { static void Main() { System.Console.Write(Test1(new S1(10))); System.Console.Write(Test1(default)); System.Console.Write(Test1(new S1(""11""))); System.Console.Write(Test1(new S1(0))); } static bool Test1(S1 u) { return u is 10; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); var verifier = CompileAndVerify(comp, expectedOutput: "TrueFalseFalseFalse").VerifyDiagnostics(); verifier.VerifyIL("Program.Test1", @" { // Code size 29 (0x1d) .maxstack 2 .locals init (object V_0) IL_0000: ldarga.s V_0 IL_0002: call ""object S1.Value.get"" IL_0007: stloc.0 IL_0008: ldloc.0 IL_0009: isinst ""int"" IL_000e: brfalse.s IL_001b IL_0010: ldloc.0 IL_0011: unbox.any ""int"" IL_0016: ldc.i4.s 10 IL_0018: ceq IL_001a: ret IL_001b: ldc.i4.0 IL_001c: ret } "); } [Fact] public void UnionMatching_MemberProvider_Value_05_Generic() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 : S1.IUnionMembers { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } public object Value => throw null; object IUnionMembers.Value => _value; public interface IUnionMembers<T>; public interface IUnionMembers { public static S1 Create(int x) => new S1(x); public static S1 Create(string x) => new S1(x); public object Value { get; } } public interface IUnionMembers<T, S>; } class Program { static void Main() { System.Console.Write(Test1(new S1(10))); System.Console.Write(Test1(default)); System.Console.Write(Test1(new S1(""11""))); System.Console.Write(Test1(new S1(0))); } static bool Test1(S1 u) { return u is 10; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); CompileAndVerify(comp, expectedOutput: "TrueFalseFalseFalse").VerifyDiagnostics(); } [Fact] public void UnionMatching_MemberProvider_Value_06_InGenericUnion() { var src = @" [System.Runtime.CompilerServices.Union] struct S1<T> : S1<T>.IUnionMembers { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } public object Value => throw null; object IUnionMembers.Value => _value; public interface IUnionMembers { public static S1<T> Create(int x) => new S1<T>(x); public static S1<T> Create(string x) => new S1<T>(x); public object Value { get; } } } class Program { static void Main() { System.Console.Write(Test1(new S1<long>(10))); System.Console.Write(Test1(default)); System.Console.Write(Test1(new S1<long>(""11""))); System.Console.Write(Test1(new S1<long>(0))); } static bool Test1(S1<long> u) { return u is 10; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); CompileAndVerify(comp, expectedOutput: "TrueFalseFalseFalse").VerifyDiagnostics(); } [Fact] public void UnionMatching_MemberProvider_Value_07_WrongGenericSubstitution() { var src = @" [System.Runtime.CompilerServices.Union] struct S1<T> : S1<long>.IUnionMembers { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } public object Value => _value; object S1<long>.IUnionMembers.Value => throw null; public interface IUnionMembers { public static S1<T> Create(int x) => throw null; public static S1<T> Create(string x) => throw null; public object Value { get; } } } class Program { static void Main() { System.Console.Write(Test1(new S1<long>(10))); System.Console.Write(Test1(default)); System.Console.Write(Test1(new S1<long>(""11""))); System.Console.Write(Test1(new S1<long>(0))); } static bool Test1(S1<long> u) { return u is 10; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); CompileAndVerify(comp, expectedOutput: "TrueFalseFalseFalse").VerifyDiagnostics(); } [Theory] [CombinatorialData] public void UnionMatching_MemberProvider_Value_08_Provider_NotPublic([CombinatorialValues("", "private", "internal", "protected", "internal protected", "private protected")] string accessibility) { var src = @" [System.Runtime.CompilerServices.Union] class S1 : S1.IUnionMembers { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } public object Value => _value; object IUnionMembers.Value => throw null; " + accessibility + @" interface IUnionMembers { public static S1 Create(int x) => new S1(x); public static S1 Create(string x) => new S1(x); public object Value { get; } } } class Program { static void Main() { System.Console.Write(Test1(new S1(10))); System.Console.Write(Test1(default)); System.Console.Write(Test1(new S1(""11""))); System.Console.Write(Test1(new S1(0))); } static bool Test1(S1 u) { return u is 10; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); var verifier = CompileAndVerify(comp, expectedOutput: "TrueFalseFalseFalse").VerifyDiagnostics(); verifier.VerifyIL("Program.Test1", @" { // Code size 31 (0x1f) .maxstack 2 .locals init (object V_0) IL_0000: ldarg.0 IL_0001: brfalse.s IL_001d IL_0003: ldarg.0 IL_0004: callvirt ""object S1.Value.get"" IL_0009: stloc.0 IL_000a: ldloc.0 IL_000b: isinst ""int"" IL_0010: brfalse.s IL_001d IL_0012: ldloc.0 IL_0013: unbox.any ""int"" IL_0018: ldc.i4.s 10 IL_001a: ceq IL_001c: ret IL_001d: ldc.i4.0 IL_001e: ret } "); } [Fact] public void UnionMatching_MemberProvider_Value_09_WrongType() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 : S1.IUnionMembers { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } public System.IComparable Value => throw null; public interface IUnionMembers { public static S1 Create(int x) => new S1(x); public static S1 Create(string x) => new S1(x); public System.IComparable Value { get; } } } class Program { static bool Test1(S1 u) { #line 21 return u is 10; } } "; var comp = CreateCompilation([src, UnionAttributeSource]); comp.VerifyDiagnostics( // (3,8): error CS9386: A union member provider type must have an instance 'Value' property of type 'object?' or 'object'. The property must have a public get accessor. // struct S1 : S1.IUnionMembers Diagnostic(ErrorCode.ERR_MissingUnionValueProperty, "S1").WithLocation(3, 8), // (21,21): error CS0656: Missing compiler required member 'S1.IUnionMembers.Value' // return u is 10; Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "10").WithArguments("S1.IUnionMembers", "Value").WithLocation(21, 21) ); } [Fact] public void UnionMatching_MemberProvider_Value_10_WrongType() { var src = @" [System.Runtime.CompilerServices.Union] struct S1<T> : S1<T>.IUnionMembers { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } public object Value => throw null; T IUnionMembers.Value => throw null; public interface IUnionMembers { public static S1<T> Create(int x) => new S1<T>(x); public static S1<T> Create(string x) => new S1<T>(x); public T Value { get; } } } class Program { static bool Test1(S1<object> u) { return u is 10; } } "; var comp = CreateCompilation([src, UnionAttributeSource]); comp.VerifyDiagnostics( // (3,8): error CS9386: A union member provider type must have an instance 'Value' property of type 'object?' or 'object'. The property must have a public get accessor. // struct S1<T> : S1<T>.IUnionMembers Diagnostic(ErrorCode.ERR_MissingUnionValueProperty, "S1").WithLocation(3, 8), // (25,21): error CS0656: Missing compiler required member 'S1<T>.IUnionMembers.Value' // return u is 10; Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "10").WithArguments("S1<T>.IUnionMembers", "Value").WithLocation(25, 21) ); } [Theory] [CombinatorialData] public void UnionMatching_MemberProvider_Value_11_WrongRefKind([CombinatorialValues("ref", "ref readonly")] string refModifier) { var src = @" [System.Runtime.CompilerServices.Union] struct S1 : S1.IUnionMembers { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } public object Value => throw null; " + refModifier + @" object IUnionMembers.Value => throw null; public interface IUnionMembers { public static S1 Create(int x) => new S1(x); public static S1 Create(string x) => new S1(x); public " + refModifier + @" object Value { get; } } } class Program { static bool Test1(S1 u) { #line 21 return u is 10; } } "; var comp = CreateCompilation([src, UnionAttributeSource]); comp.VerifyDiagnostics( // (3,8): error CS9386: A union member provider type must have an instance 'Value' property of type 'object?' or 'object'. The property must have a public get accessor. // struct S1 : S1.IUnionMembers Diagnostic(ErrorCode.ERR_MissingUnionValueProperty, "S1").WithLocation(3, 8), // (21,21): error CS0656: Missing compiler required member 'S1.IUnionMembers.Value' // return u is 10; Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "10").WithArguments("S1.IUnionMembers", "Value").WithLocation(21, 21) ); } [Fact] public void UnionMatching_MemberProvider_Value_12_Static() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 : S1.IUnionMembers { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } public object Value => throw null; public interface IUnionMembers { public static S1 Create(int x) => new S1(x); public static S1 Create(string x) => new S1(x); public static object Value => throw null; } } class Program { static bool Test1(S1 u) { #line 21 return u is 10; } } "; var comp = CreateCompilation([src, UnionAttributeSource]); comp.VerifyDiagnostics( // (3,8): error CS9386: A union member provider type must have an instance 'Value' property of type 'object?' or 'object'. The property must have a public get accessor. // struct S1 : S1.IUnionMembers Diagnostic(ErrorCode.ERR_MissingUnionValueProperty, "S1").WithLocation(3, 8), // (21,21): error CS0656: Missing compiler required member 'S1.IUnionMembers.Value' // return u is 10; Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "10").WithArguments("S1.IUnionMembers", "Value").WithLocation(21, 21) ); } [Fact] public void UnionMatching_MemberProvider_Value_13_NotVirtual() { var src = @" [System.Runtime.CompilerServices.Union] class S1 : S1.IUnionMembers { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } public object Value => _value; public interface IUnionMembers { public static S1 Create(int x) => new S1(x); public static S1 Create(string x) => new S1(x); public sealed object Value => ((S1)this).Value; } } class Program { static void Main() { System.Console.Write(Test1(new S1(10))); System.Console.Write(Test1(default)); System.Console.Write(Test1(new S1(""11""))); System.Console.Write(Test1(new S1(0))); } static bool Test1(S1 u) { return u is 10; } } "; var comp = CreateCompilation([src, UnionAttributeSource], targetFramework: TargetFramework.NetCoreApp, options: TestOptions.ReleaseExe); var verifier = CompileAndVerify(comp, expectedOutput: ExecutionConditionUtil.IsMonoOrCoreClr ? "TrueFalseFalseFalse" : null, verify: Verification.FailsPEVerify).VerifyDiagnostics(); verifier.VerifyIL("Program.Test1", @" { // Code size 31 (0x1f) .maxstack 2 .locals init (object V_0) IL_0000: ldarg.0 IL_0001: brfalse.s IL_001d IL_0003: ldarg.0 IL_0004: callvirt ""object S1.IUnionMembers.Value.get"" IL_0009: stloc.0 IL_000a: ldloc.0 IL_000b: isinst ""int"" IL_0010: brfalse.s IL_001d IL_0012: ldloc.0 IL_0013: unbox.any ""int"" IL_0018: ldc.i4.s 10 IL_001a: ceq IL_001c: ret IL_001d: ldc.i4.0 IL_001e: ret } "); } [Theory] [CombinatorialData] public void UnionMatching_MemberProvider_Value_14_NotPublic([CombinatorialValues("private", "internal", "protected", "internal protected", "private protected")] string accessibility) { var src = @" [System.Runtime.CompilerServices.Union] class S1 : S1.IUnionMembers { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } public object Value => _value; " + (accessibility == "private" ? "" : "object IUnionMembers.Value => throw null;") + @" public interface IUnionMembers { public static S1 Create(int x) => new S1(x); public static S1 Create(string x) => new S1(x); " + accessibility + @" object Value { get" + (accessibility == "private" ? " => throw null" : "") + @"; } } } class Program { static bool Test1(S1 u) { #line 28 return u is 10; } } "; var comp = CreateCompilation([src, UnionAttributeSource], targetFramework: TargetFramework.NetCoreApp); comp.VerifyEmitDiagnostics( // (3,7): error CS9386: A union member provider type must have an instance 'Value' property of type 'object?' or 'object'. The property must have a public get accessor. // class S1 : S1.IUnionMembers Diagnostic(ErrorCode.ERR_MissingUnionValueProperty, "S1").WithLocation(3, 7), // (28,21): error CS0656: Missing compiler required member 'S1.IUnionMembers.Value' // return u is 10; Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "10").WithArguments("S1.IUnionMembers", "Value").WithLocation(28, 21) ); } [Theory] [CombinatorialData] public void UnionMatching_MemberProvider_Value_15_NotPublic_Get([CombinatorialValues("private", "internal", "protected", "internal protected", "private protected")] string accessibility) { var src = @" [System.Runtime.CompilerServices.Union] class S1 : S1.IUnionMembers { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } public object Value => _value; " + (accessibility == "private" ? "" : "object IUnionMembers.Value { get => throw null; set => throw null; }") + @" public interface IUnionMembers { public static S1 Create(int x) => new S1(x); public static S1 Create(string x) => new S1(x); public object Value { " + accessibility + @" get" + (accessibility == "private" ? " => throw null" : "") + @"; set" + (accessibility == "private" ? " => throw null" : "") + @"; } } } class Program { static bool Test1(S1 u) { #line 28 return u is 10; } } "; var comp = CreateCompilation([src, UnionAttributeSource], targetFramework: TargetFramework.NetCoreApp); comp.VerifyEmitDiagnostics( // (3,7): error CS9386: A union member provider type must have an instance 'Value' property of type 'object?' or 'object'. The property must have a public get accessor. // class S1 : S1.IUnionMembers Diagnostic(ErrorCode.ERR_MissingUnionValueProperty, "S1").WithLocation(3, 7), // (28,21): error CS0656: Missing compiler required member 'S1.IUnionMembers.Value' // return u is 10; Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "10").WithArguments("S1.IUnionMembers", "Value").WithLocation(28, 21) ); } [Fact] public void UnionMatching_MemberProvider_Value_Inheritance_01() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 : S1.IUnionMembers { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } public object Value => _value; public interface IUnionMembers : IUnionMembersBase { public static S1 Create(int x) => new S1(x); public static S1 Create(string x) => new S1(x); } public interface IUnionMembersBase { public object Value { get; } } } class Program { static void Main() { System.Console.Write(Test1(new S1(10))); System.Console.Write(Test1(default)); System.Console.Write(Test1(new S1(""11""))); System.Console.Write(Test1(new S1(0))); } static bool Test1(S1 u) { #line 21 return u is 10; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); var verifier = CompileAndVerify(comp, expectedOutput: "TrueFalseFalseFalse").VerifyDiagnostics(); verifier.VerifyIL("Program.Test1", @" { // Code size 35 (0x23) .maxstack 2 .locals init (object V_0) IL_0000: ldarga.s V_0 IL_0002: constrained. ""S1"" IL_0008: callvirt ""object S1.IUnionMembersBase.Value.get"" IL_000d: stloc.0 IL_000e: ldloc.0 IL_000f: isinst ""int"" IL_0014: brfalse.s IL_0021 IL_0016: ldloc.0 IL_0017: unbox.any ""int"" IL_001c: ldc.i4.s 10 IL_001e: ceq IL_0020: ret IL_0021: ldc.i4.0 IL_0022: ret } "); } [Fact] public void UnionMatching_MemberProvider_Value_Inheritance_02_Missing() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 : S1.IUnionMembers { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } public object Value => throw null; public interface IUnionMembers : IUnionMembersBase { public static S1 Create(int x) => new S1(x); public static S1 Create(string x) => new S1(x); } public interface IUnionMembersBase { } } class Program { static bool Test1(S1 u) { #line 21 return u is 10; } } "; var comp = CreateCompilation([src, UnionAttributeSource]); comp.VerifyDiagnostics( // (3,8): error CS9386: A union member provider type must have an instance 'Value' property of type 'object?' or 'object'. The property must have a public get accessor. // struct S1 : S1.IUnionMembers Diagnostic(ErrorCode.ERR_MissingUnionValueProperty, "S1").WithLocation(3, 8), // (21,21): error CS0656: Missing compiler required member 'S1.IUnionMembers.Value' // return u is 10; Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "10").WithArguments("S1.IUnionMembers", "Value").WithLocation(21, 21) ); } [Fact] public void UnionMatching_MemberProvider_Value_Inheritance_03_Ambiguous() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 : S1.IUnionMembers { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } public object Value => throw null; public interface IUnionMembers : IUnionMembersBase1, IUnionMembersBase2 { public static S1 Create(int x) => new S1(x); public static S1 Create(string x) => new S1(x); } public interface IUnionMembersBase1 { public object Value { get; } } public interface IUnionMembersBase2 { public object Value { get; } } } class Program { static bool Test1(S1 u) { #line 21 return u is 10; } } "; var comp = CreateCompilation([src, UnionAttributeSource]); comp.VerifyDiagnostics( // (3,8): error CS9386: A union member provider type must have an instance 'Value' property of type 'object?' or 'object'. The property must have a public get accessor. // struct S1 : S1.IUnionMembers Diagnostic(ErrorCode.ERR_MissingUnionValueProperty, "S1").WithLocation(3, 8), // (21,21): error CS0656: Missing compiler required member 'S1.IUnionMembers.Value' // return u is 10; Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "10").WithArguments("S1.IUnionMembers", "Value").WithLocation(21, 21) ); } [Fact] public void UnionMatching_MemberProvider_Value_Inheritance_04_Ambiguous() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 : S1.IUnionMembers { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } public object Value => throw null; public interface IUnionMembers : IUnionMembersBase1, IUnionMembersBase2 { public static S1 Create(int x) => new S1(x); public static S1 Create(string x) => new S1(x); } public interface IUnionMembersBase1 : IUnionMembersBase3 { public object Value { get; } } public interface IUnionMembersBase2 : IUnionMembersBase3 { public object Value { get; } } public interface IUnionMembersBase3 { } } class Program { static bool Test1(S1 u) { #line 21 return u is 10; } } "; var comp = CreateCompilation([src, UnionAttributeSource]); comp.VerifyDiagnostics( // (3,8): error CS9386: A union member provider type must have an instance 'Value' property of type 'object?' or 'object'. The property must have a public get accessor. // struct S1 : S1.IUnionMembers Diagnostic(ErrorCode.ERR_MissingUnionValueProperty, "S1").WithLocation(3, 8), // (21,21): error CS0656: Missing compiler required member 'S1.IUnionMembers.Value' // return u is 10; Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "10").WithArguments("S1.IUnionMembers", "Value").WithLocation(21, 21) ); } [Fact] public void UnionMatching_MemberProvider_Value_Inheritance_05_Generic() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 : S1.IUnionMembers { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } public object Value => throw null; object IUnionMembersBase<object>.Value => _value; public interface IUnionMembers : IUnionMembersBase<object> { public static S1 Create(int x) => throw null; public static S1 Create(string x) => throw null; } public interface IUnionMembersBase<T> { public T Value { get; } } } class Program { static void Main() { System.Console.Write(Test1(new S1(10))); System.Console.Write(Test1(default)); System.Console.Write(Test1(new S1(""11""))); System.Console.Write(Test1(new S1(0))); } static bool Test1(S1 u) { return u is 10; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); var verifier = CompileAndVerify(comp, expectedOutput: "TrueFalseFalseFalse").VerifyDiagnostics(); verifier.VerifyIL("Program.Test1", @" { // Code size 35 (0x23) .maxstack 2 .locals init (object V_0) IL_0000: ldarga.s V_0 IL_0002: constrained. ""S1"" IL_0008: callvirt ""object S1.IUnionMembersBase<object>.Value.get"" IL_000d: stloc.0 IL_000e: ldloc.0 IL_000f: isinst ""int"" IL_0014: brfalse.s IL_0021 IL_0016: ldloc.0 IL_0017: unbox.any ""int"" IL_001c: ldc.i4.s 10 IL_001e: ceq IL_0020: ret IL_0021: ldc.i4.0 IL_0022: ret } "); } [Fact] public void UnionMatching_MemberProvider_Value_Inheritance_06_InGenericUnion() { var src = @" [System.Runtime.CompilerServices.Union] struct S1<T> : S1<T>.IUnionMembers { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } public object Value => throw null; object IUnionMembersBase.Value => _value; public interface IUnionMembers : IUnionMembersBase { public static S1<T> Create(int x) => new S1<T>(x); public static S1<T> Create(string x) => new S1<T>(x); } public interface IUnionMembersBase { public object Value { get; } } } class Program { static void Main() { System.Console.Write(Test1(new S1<long>(10))); System.Console.Write(Test1(default)); System.Console.Write(Test1(new S1<long>(""11""))); System.Console.Write(Test1(new S1<long>(0))); } static bool Test1(S1<long> u) { return u is 10; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); CompileAndVerify(comp, expectedOutput: "TrueFalseFalseFalse").VerifyDiagnostics(); } [Fact] public void UnionMatching_MemberProvider_Value_Inheritance_07_InGenericUnion() { var src = @" [System.Runtime.CompilerServices.Union] struct S1<T> : S1<T>.IUnionMembers { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } public object Value => throw null; object IUnionMembersBase.Value => _value; public interface IUnionMembers : IUnionMembersBase { public static S1<T> Create(int x) => new S1<T>(x); public static S1<T> Create(string x) => new S1<T>(x); } } public interface IUnionMembersBase { public object Value { get; } } class Program { static void Main() { System.Console.Write(Test1(new S1<long>(10))); System.Console.Write(Test1(default)); System.Console.Write(Test1(new S1<long>(""11""))); System.Console.Write(Test1(new S1<long>(0))); } static bool Test1(S1<long> u) { return u is 10; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); CompileAndVerify(comp, expectedOutput: "TrueFalseFalseFalse").VerifyDiagnostics(); } [Fact] public void UnionMatching_MemberProvider_Value_Inheritance_08_InGenericUnion() { var src = @" [System.Runtime.CompilerServices.Union] struct S1<T> : S1<T>.IUnionMembers { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } public object Value => throw null; object IUnionMembersBase<T>.Value => _value; public interface IUnionMembers : IUnionMembersBase<T> { public static S1<T> Create(int x) => new S1<T>(x); public static S1<T> Create(string x) => new S1<T>(x); } } public interface IUnionMembersBase<T> { public object Value { get; } } class Program { static void Main() { System.Console.Write(Test1(new S1<long>(10))); System.Console.Write(Test1(default)); System.Console.Write(Test1(new S1<long>(""11""))); System.Console.Write(Test1(new S1<long>(0))); } static bool Test1(S1<long> u) { return u is 10; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); CompileAndVerify(comp, expectedOutput: "TrueFalseFalseFalse").VerifyDiagnostics(); } [Theory] [CombinatorialData] public void UnionMatching_MemberProvider_Value_Inheritance_09_Provider_NotPublic([CombinatorialValues("internal", "internal protected")] string accessibility) { var src = @" [System.Runtime.CompilerServices.Union] class S1 : S1.IUnionMembers { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } public object Value => throw null; object IUnionMembersBase.Value => _value; public interface IUnionMembers : IUnionMembersBase { public static S1 Create(int x) => new S1(x); public static S1 Create(string x) => new S1(x); } " + accessibility + @" interface IUnionMembersBase { public object Value { get; } } } class Program { static void Main() { System.Console.Write(Test1(new S1(10))); System.Console.Write(Test1(default)); System.Console.Write(Test1(new S1(""11""))); System.Console.Write(Test1(new S1(0))); } static bool Test1(S1 u) { return u is 10; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); var verifier = CompileAndVerify(comp, expectedOutput: "TrueFalseFalseFalse").VerifyDiagnostics(); verifier.VerifyIL("Program.Test1", @" { // Code size 31 (0x1f) .maxstack 2 .locals init (object V_0) IL_0000: ldarg.0 IL_0001: brfalse.s IL_001d IL_0003: ldarg.0 IL_0004: callvirt ""object S1.IUnionMembersBase.Value.get"" IL_0009: stloc.0 IL_000a: ldloc.0 IL_000b: isinst ""int"" IL_0010: brfalse.s IL_001d IL_0012: ldloc.0 IL_0013: unbox.any ""int"" IL_0018: ldc.i4.s 10 IL_001a: ceq IL_001c: ret IL_001d: ldc.i4.0 IL_001e: ret } "); } [Theory] [CombinatorialData] public void UnionMatching_MemberProvider_Value_Inheritance_10_Provider_NotPublic([CombinatorialValues("", "private", "internal", "protected", "internal protected", "private protected")] string accessibility) { var src = @" [System.Runtime.CompilerServices.Union] public class S1 : S1.IUnionMembers { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } public object Value => _value; object IUnionMembersBase.Value => throw null; public interface IUnionMembers : IUnionMembersBase { public static S1 Create(int x) => new S1(x); public static S1 Create(string x) => new S1(x); } " + accessibility + @" interface IUnionMembersBase { public object Value { get; } } } class Program { static bool Test1(S1 u) { return u is 10; } } "; var comp = CreateCompilation([src, UnionAttributeSource]); comp.VerifyEmitDiagnostics( // (12,22): error CS0061: Inconsistent accessibility: base interface 'S1.IUnionMembersBase' is less accessible than interface 'S1.IUnionMembers' // public interface IUnionMembers : IUnionMembersBase Diagnostic(ErrorCode.ERR_BadVisBaseInterface, "IUnionMembers").WithArguments("S1.IUnionMembers", "S1.IUnionMembersBase").WithLocation(12, 22) ); } [Theory] [CombinatorialData] public void UnionMatching_MemberProvider_Value_Inheritance_11_NotPublic([CombinatorialValues("private", "internal", "protected", "internal protected", "private protected")] string accessibility) { var src = @" [System.Runtime.CompilerServices.Union] class S1 : S1.IUnionMembers { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } public object Value => _value; " + (accessibility == "private" ? "" : "object IUnionMembersBase.Value => throw null;") + @" public interface IUnionMembers : IUnionMembersBase { public static S1 Create(int x) => new S1(x); public static S1 Create(string x) => new S1(x); } public interface IUnionMembersBase { " + accessibility + @" object Value { get" + (accessibility == "private" ? " => throw null" : "") + @"; } } } class Program { static bool Test1(S1 u) { #line 28 return u is 10; } } "; var comp = CreateCompilation([src, UnionAttributeSource], targetFramework: TargetFramework.NetCoreApp); comp.VerifyEmitDiagnostics( // (3,7): error CS9386: A union member provider type must have an instance 'Value' property of type 'object?' or 'object'. The property must have a public get accessor. // class S1 : S1.IUnionMembers Diagnostic(ErrorCode.ERR_MissingUnionValueProperty, "S1").WithLocation(3, 7), // (28,21): error CS0656: Missing compiler required member 'S1.IUnionMembers.Value' // return u is 10; Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "10").WithArguments("S1.IUnionMembers", "Value").WithLocation(28, 21) ); } [Theory] [CombinatorialData] public void UnionMatching_MemberProvider_Value_Inheritance_12_NotPublic_Get([CombinatorialValues("private", "internal", "protected", "internal protected", "private protected")] string accessibility) { var src = @" [System.Runtime.CompilerServices.Union] class S1 : S1.IUnionMembers { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } public object Value => _value; " + (accessibility == "private" ? "" : "object IUnionMembersBase.Value { get => throw null; set => throw null; }") + @" public interface IUnionMembers : IUnionMembersBase { public static S1 Create(int x) => new S1(x); public static S1 Create(string x) => new S1(x); } public interface IUnionMembersBase { public object Value { " + accessibility + @" get" + (accessibility == "private" ? " => throw null" : "") + @"; set" + (accessibility == "private" ? " => throw null" : "") + @"; } } } class Program { static bool Test1(S1 u) { #line 28 return u is 10; } } "; var comp = CreateCompilation([src, UnionAttributeSource], targetFramework: TargetFramework.NetCoreApp); comp.VerifyEmitDiagnostics( // (3,7): error CS9386: A union member provider type must have an instance 'Value' property of type 'object?' or 'object'. The property must have a public get accessor. // class S1 : S1.IUnionMembers Diagnostic(ErrorCode.ERR_MissingUnionValueProperty, "S1").WithLocation(3, 7), // (28,21): error CS0656: Missing compiler required member 'S1.IUnionMembers.Value' // return u is 10; Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "10").WithArguments("S1.IUnionMembers", "Value").WithLocation(28, 21) ); } [Fact] public void UnionMatching_MemberProvider_Value_Inheritance_13_WrongType() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 : S1.IUnionMembers { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } public System.IComparable Value => throw null; public interface IUnionMembers : IUnionMembersBase { public static S1 Create(int x) => new S1(x); public static S1 Create(string x) => new S1(x); } public interface IUnionMembersBase { public System.IComparable Value { get; } } } class Program { static bool Test1(S1 u) { #line 21 return u is 10; } } "; var comp = CreateCompilation([src, UnionAttributeSource]); comp.VerifyDiagnostics( // (3,8): error CS9386: A union member provider type must have an instance 'Value' property of type 'object?' or 'object'. The property must have a public get accessor. // struct S1 : S1.IUnionMembers Diagnostic(ErrorCode.ERR_MissingUnionValueProperty, "S1").WithLocation(3, 8), // (21,21): error CS0656: Missing compiler required member 'S1.IUnionMembers.Value' // return u is 10; Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "10").WithArguments("S1.IUnionMembers", "Value").WithLocation(21, 21) ); } [Fact] public void UnionMatching_MemberProvider_Value_Inheritance_14_WrongType() { var src = @" [System.Runtime.CompilerServices.Union] struct S1<T> : S1<T>.IUnionMembers { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } public object Value => throw null; T IUnionMembersBase.Value => throw null; public interface IUnionMembers : IUnionMembersBase { public static S1<T> Create(int x) => new S1<T>(x); public static S1<T> Create(string x) => new S1<T>(x); } public interface IUnionMembersBase { public T Value { get; } } } class Program { static bool Test1(S1<object> u) { #line 25 return u is 10; } } "; var comp = CreateCompilation([src, UnionAttributeSource]); comp.VerifyDiagnostics( // (3,8): error CS9386: A union member provider type must have an instance 'Value' property of type 'object?' or 'object'. The property must have a public get accessor. // struct S1<T> : S1<T>.IUnionMembers Diagnostic(ErrorCode.ERR_MissingUnionValueProperty, "S1").WithLocation(3, 8), // (25,21): error CS0656: Missing compiler required member 'S1<T>.IUnionMembers.Value' // return u is 10; Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "10").WithArguments("S1<T>.IUnionMembers", "Value").WithLocation(25, 21) ); } [Theory] [CombinatorialData] public void UnionMatching_MemberProvider_Value_Inheritance_15_WrongRefKind([CombinatorialValues("ref", "ref readonly")] string refModifier) { var src = @" [System.Runtime.CompilerServices.Union] struct S1 : S1.IUnionMembers { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } public object Value => throw null; " + refModifier + @" object IUnionMembersBase.Value => throw null; public interface IUnionMembers : IUnionMembersBase { public static S1 Create(int x) => new S1(x); public static S1 Create(string x) => new S1(x); } public interface IUnionMembersBase { public " + refModifier + @" object Value { get; } } } class Program { static bool Test1(S1 u) { #line 21 return u is 10; } } "; var comp = CreateCompilation([src, UnionAttributeSource]); comp.VerifyDiagnostics( // (3,8): error CS9386: A union member provider type must have an instance 'Value' property of type 'object?' or 'object'. The property must have a public get accessor. // struct S1 : S1.IUnionMembers Diagnostic(ErrorCode.ERR_MissingUnionValueProperty, "S1").WithLocation(3, 8), // (21,21): error CS0656: Missing compiler required member 'S1.IUnionMembers.Value' // return u is 10; Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "10").WithArguments("S1.IUnionMembers", "Value").WithLocation(21, 21) ); } [Fact] public void UnionMatching_MemberProvider_Value_Inheritance_16_Static() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 : S1.IUnionMembers { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } public object Value => throw null; public interface IUnionMembers : IUnionMembersBase { public static S1 Create(int x) => new S1(x); public static S1 Create(string x) => new S1(x); } public interface IUnionMembersBase { public static object Value => throw null; } } class Program { static bool Test1(S1 u) { #line 21 return u is 10; } } "; var comp = CreateCompilation([src, UnionAttributeSource]); comp.VerifyDiagnostics( // (3,8): error CS9386: A union member provider type must have an instance 'Value' property of type 'object?' or 'object'. The property must have a public get accessor. // struct S1 : S1.IUnionMembers Diagnostic(ErrorCode.ERR_MissingUnionValueProperty, "S1").WithLocation(3, 8), // (21,21): error CS0656: Missing compiler required member 'S1.IUnionMembers.Value' // return u is 10; Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "10").WithArguments("S1.IUnionMembers", "Value").WithLocation(21, 21) ); } [Fact] public void UnionMatching_MemberProvider_Value_Inheritance_17_NotVirtual() { var src = @" [System.Runtime.CompilerServices.Union] class S1 : S1.IUnionMembers { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } public interface IUnionMembers : IUnionMembersBase { public static S1 Create(int x) => new S1(x); public static S1 Create(string x) => new S1(x); } public interface IUnionMembersBase { public sealed object Value => ((S1)this)._value; } } class Program { static void Main() { System.Console.Write(Test1(new S1(10))); System.Console.Write(Test1(default)); System.Console.Write(Test1(new S1(""11""))); System.Console.Write(Test1(new S1(0))); } static bool Test1(S1 u) { return u is 10; } } "; var comp = CreateCompilation([src, UnionAttributeSource], targetFramework: TargetFramework.NetCoreApp, options: TestOptions.ReleaseExe); var verifier = CompileAndVerify(comp, expectedOutput: ExecutionConditionUtil.IsMonoOrCoreClr ? "TrueFalseFalseFalse" : null, verify: Verification.FailsPEVerify).VerifyDiagnostics(); verifier.VerifyIL("Program.Test1", @" { // Code size 31 (0x1f) .maxstack 2 .locals init (object V_0) IL_0000: ldarg.0 IL_0001: brfalse.s IL_001d IL_0003: ldarg.0 IL_0004: callvirt ""object S1.IUnionMembersBase.Value.get"" IL_0009: stloc.0 IL_000a: ldloc.0 IL_000b: isinst ""int"" IL_0010: brfalse.s IL_001d IL_0012: ldloc.0 IL_0013: unbox.any ""int"" IL_0018: ldc.i4.s 10 IL_001a: ceq IL_001c: ret IL_001d: ldc.i4.0 IL_001e: ret } "); } [Fact] public void UnionMatching_MemberProvider_Value_Inheritance_18_Shadowing() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 : S1.IUnionMembers { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } object IUnionMembers.Value => _value; object IUnionMembersBase.Value => throw null; public interface IUnionMembers : IUnionMembersBase { public static S1 Create(int x) => new S1(x); public static S1 Create(string x) => new S1(x); new public object Value { get; } } public interface IUnionMembersBase { public object Value { get; } } } class Program { static void Main() { System.Console.Write(Test1(new S1(10))); System.Console.Write(Test1(default)); System.Console.Write(Test1(new S1(""11""))); System.Console.Write(Test1(new S1(0))); } static bool Test1(S1 u) { #line 21 return u is 10; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); var verifier = CompileAndVerify(comp, expectedOutput: "TrueFalseFalseFalse").VerifyDiagnostics(); verifier.VerifyIL("Program.Test1", @" { // Code size 35 (0x23) .maxstack 2 .locals init (object V_0) IL_0000: ldarga.s V_0 IL_0002: constrained. ""S1"" IL_0008: callvirt ""object S1.IUnionMembers.Value.get"" IL_000d: stloc.0 IL_000e: ldloc.0 IL_000f: isinst ""int"" IL_0014: brfalse.s IL_0021 IL_0016: ldloc.0 IL_0017: unbox.any ""int"" IL_001c: ldc.i4.s 10 IL_001e: ceq IL_0020: ret IL_0021: ldc.i4.0 IL_0022: ret } "); } [Fact] public void UnionMatching_MemberProvider_Value_Inheritance_19_Shadowing() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 : S1.IUnionMembers { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } object IBase2.Value => _value; object IBase1.Value => throw null; public interface IUnionMembers : IBase1, IBase2 { public static S1 Create(int x) => new S1(x); public static S1 Create(string x) => new S1(x); } public interface IBase2 : IBase1 { new public object Value { get; } } public interface IBase1 { public object Value { get; } } } class Program { static void Main() { System.Console.Write(Test1(new S1(10))); System.Console.Write(Test1(default)); System.Console.Write(Test1(new S1(""11""))); System.Console.Write(Test1(new S1(0))); } static bool Test1(S1 u) { #line 21 return u is 10; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); var verifier = CompileAndVerify(comp, expectedOutput: "TrueFalseFalseFalse").VerifyDiagnostics(); verifier.VerifyIL("Program.Test1", @" { // Code size 35 (0x23) .maxstack 2 .locals init (object V_0) IL_0000: ldarga.s V_0 IL_0002: constrained. ""S1"" IL_0008: callvirt ""object S1.IBase2.Value.get"" IL_000d: stloc.0 IL_000e: ldloc.0 IL_000f: isinst ""int"" IL_0014: brfalse.s IL_0021 IL_0016: ldloc.0 IL_0017: unbox.any ""int"" IL_001c: ldc.i4.s 10 IL_001e: ceq IL_0020: ret IL_0021: ldc.i4.0 IL_0022: ret } "); } [Fact] public void UnionMatching_MemberProvider_Value_Inheritance_20_Shadowing() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 : S1.IUnionMembers { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } object IUnionMembers.Value => _value; object IBase<object>.Value => throw null; public interface IUnionMembers : IBase<object> { public static S1 Create(int x) => new S1(x); public static S1 Create(string x) => new S1(x); new public object Value { get; } } public interface IBase<T> { public T Value { get; } } } class Program { static void Main() { System.Console.Write(Test1(new S1(10))); System.Console.Write(Test1(default)); System.Console.Write(Test1(new S1(""11""))); System.Console.Write(Test1(new S1(0))); } static bool Test1(S1 u) { #line 21 return u is 10; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); var verifier = CompileAndVerify(comp, expectedOutput: "TrueFalseFalseFalse").VerifyDiagnostics(); verifier.VerifyIL("Program.Test1", @" { // Code size 35 (0x23) .maxstack 2 .locals init (object V_0) IL_0000: ldarga.s V_0 IL_0002: constrained. ""S1"" IL_0008: callvirt ""object S1.IUnionMembers.Value.get"" IL_000d: stloc.0 IL_000e: ldloc.0 IL_000f: isinst ""int"" IL_0014: brfalse.s IL_0021 IL_0016: ldloc.0 IL_0017: unbox.any ""int"" IL_001c: ldc.i4.s 10 IL_001e: ceq IL_0020: ret IL_0021: ldc.i4.0 IL_0022: ret } "); } [Fact] public void UnionMatching_MemberProvider_Value_Inheritance_21_Shadowing() { var src = @" [System.Runtime.CompilerServices.Union] struct S1<T> : S1<T>.IUnionMembers { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } object IUnionMembers.Value => _value; T IBase<T>.Value => throw null; public interface IUnionMembers : IBase<T> { public static S1<T> Create(int x) => new S1<T>(x); public static S1<T> Create(string x) => new S1<T>(x); new public object Value { get; } } } public interface IBase<T> { public T Value { get; } } class Program { static void Main() { System.Console.Write(Test1(new S1<object>(10))); System.Console.Write(Test1(default)); System.Console.Write(Test1(new S1<object>(""11""))); System.Console.Write(Test1(new S1<object>(0))); } static bool Test1(S1<object> u) { #line 21 return u is 10; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); var verifier = CompileAndVerify(comp, expectedOutput: "TrueFalseFalseFalse").VerifyDiagnostics(); verifier.VerifyIL("Program.Test1", @" { // Code size 35 (0x23) .maxstack 2 .locals init (object V_0) IL_0000: ldarga.s V_0 IL_0002: constrained. ""S1<object>"" IL_0008: callvirt ""object S1<object>.IUnionMembers.Value.get"" IL_000d: stloc.0 IL_000e: ldloc.0 IL_000f: isinst ""int"" IL_0014: brfalse.s IL_0021 IL_0016: ldloc.0 IL_0017: unbox.any ""int"" IL_001c: ldc.i4.s 10 IL_001e: ceq IL_0020: ret IL_0021: ldc.i4.0 IL_0022: ret } "); } [Fact] public void UnionMatching_MemberProvider_Value_Inheritance_22_Shadowing() { var src = @" [System.Runtime.CompilerServices.Union] struct S1<T> : S1<T>.IUnionMembers { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } object IUnionMembers.Value => _value; object IBase<T>.Value => throw null; public interface IUnionMembers : IBase<T> { public static S1<T> Create(int x) => new S1<T>(x); public static S1<T> Create(string x) => new S1<T>(x); new public object Value { get; } } } public interface IBase<T> { public object Value { get; } } class Program { static void Main() { System.Console.Write(Test1(new S1<object>(10))); System.Console.Write(Test1(default)); System.Console.Write(Test1(new S1<object>(""11""))); System.Console.Write(Test1(new S1<object>(0))); } static bool Test1(S1<object> u) { #line 21 return u is 10; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); var verifier = CompileAndVerify(comp, expectedOutput: "TrueFalseFalseFalse").VerifyDiagnostics(); verifier.VerifyIL("Program.Test1", @" { // Code size 35 (0x23) .maxstack 2 .locals init (object V_0) IL_0000: ldarga.s V_0 IL_0002: constrained. ""S1<object>"" IL_0008: callvirt ""object S1<object>.IUnionMembers.Value.get"" IL_000d: stloc.0 IL_000e: ldloc.0 IL_000f: isinst ""int"" IL_0014: brfalse.s IL_0021 IL_0016: ldloc.0 IL_0017: unbox.any ""int"" IL_001c: ldc.i4.s 10 IL_001e: ceq IL_0020: ret IL_0021: ldc.i4.0 IL_0022: ret } "); } [Fact] public void UnionMatching_MemberProvider_Value_Inheritance_23_Shadowing() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 : S1.IUnionMembers { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } object IBase2.Value => _value; object IBase1.Value() => throw null; object IBase0.Value => throw null; public interface IUnionMembers : IBase0, IBase1, IBase2 { public static S1 Create(int x) => new S1(x); public static S1 Create(string x) => new S1(x); } public interface IBase2 : IBase1 { new public object Value { get; } } public interface IBase1 : IBase0 { public new object Value(); } public interface IBase0 { public object Value { get; } } } class Program { static void Main() { System.Console.Write(Test1(new S1(10))); System.Console.Write(Test1(default)); System.Console.Write(Test1(new S1(""11""))); System.Console.Write(Test1(new S1(0))); } static bool Test1(S1 u) { #line 21 return u is 10; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); var verifier = CompileAndVerify(comp, expectedOutput: "TrueFalseFalseFalse").VerifyDiagnostics(); verifier.VerifyIL("Program.Test1", @" { // Code size 35 (0x23) .maxstack 2 .locals init (object V_0) IL_0000: ldarga.s V_0 IL_0002: constrained. ""S1"" IL_0008: callvirt ""object S1.IBase2.Value.get"" IL_000d: stloc.0 IL_000e: ldloc.0 IL_000f: isinst ""int"" IL_0014: brfalse.s IL_0021 IL_0016: ldloc.0 IL_0017: unbox.any ""int"" IL_001c: ldc.i4.s 10 IL_001e: ceq IL_0020: ret IL_0021: ldc.i4.0 IL_0022: ret } "); } [Fact] public void UnionMatching_MemberProvider_Value_Inheritance_24_Shadowing() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 : S1.IUnionMembers { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } object IUnionMembersBase.Value => _value; int IUnionMembers.Value => throw null; public interface IUnionMembers : IUnionMembersBase { public static S1 Create(int x) => new S1(x); public static S1 Create(string x) => new S1(x); new public int Value { get; } } public interface IUnionMembersBase { public object Value { get; } } } class Program { static void Main() { System.Console.Write(Test1(new S1(10))); System.Console.Write(Test1(default)); System.Console.Write(Test1(new S1(""11""))); System.Console.Write(Test1(new S1(0))); } static bool Test1(S1 u) { #line 21 return u is 10; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); var verifier = CompileAndVerify(comp, expectedOutput: "TrueFalseFalseFalse").VerifyDiagnostics(); verifier.VerifyIL("Program.Test1", @" { // Code size 35 (0x23) .maxstack 2 .locals init (object V_0) IL_0000: ldarga.s V_0 IL_0002: constrained. ""S1"" IL_0008: callvirt ""object S1.IUnionMembersBase.Value.get"" IL_000d: stloc.0 IL_000e: ldloc.0 IL_000f: isinst ""int"" IL_0014: brfalse.s IL_0021 IL_0016: ldloc.0 IL_0017: unbox.any ""int"" IL_001c: ldc.i4.s 10 IL_001e: ceq IL_0020: ret IL_0021: ldc.i4.0 IL_0022: ret } "); } [Fact] public void UnionMatching_MemberProvider_Value_Inheritance_25_Shadowing() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 : S1.IUnionMembers { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } object IUnionMembersBase.Value => _value; object IUnionMembers.Value() => throw null; public interface IUnionMembers : IUnionMembersBase { public static S1 Create(int x) => new S1(x); public static S1 Create(string x) => new S1(x); new public object Value(); } public interface IUnionMembersBase { public object Value { get; } } } class Program { static void Main() { System.Console.Write(Test1(new S1(10))); System.Console.Write(Test1(default)); System.Console.Write(Test1(new S1(""11""))); System.Console.Write(Test1(new S1(0))); } static bool Test1(S1 u) { #line 21 return u is 10; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); var verifier = CompileAndVerify(comp, expectedOutput: "TrueFalseFalseFalse").VerifyDiagnostics(); verifier.VerifyIL("Program.Test1", @" { // Code size 35 (0x23) .maxstack 2 .locals init (object V_0) IL_0000: ldarga.s V_0 IL_0002: constrained. ""S1"" IL_0008: callvirt ""object S1.IUnionMembersBase.Value.get"" IL_000d: stloc.0 IL_000e: ldloc.0 IL_000f: isinst ""int"" IL_0014: brfalse.s IL_0021 IL_0016: ldloc.0 IL_0017: unbox.any ""int"" IL_001c: ldc.i4.s 10 IL_001e: ceq IL_0020: ret IL_0021: ldc.i4.0 IL_0022: ret } "); } [Fact] public void UnionMatching_MemberProvider_Value_Inheritance_26_Shadowing() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 : S1.IUnionMembers { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } object IBase1.Value => _value; int IBase2.Value => throw null; public interface IUnionMembers : IBase2, IBase1 { public static S1 Create(int x) => new S1(x); public static S1 Create(string x) => new S1(x); } public interface IBase2 : IBase1 { new public int Value { get; } } public interface IBase1 { public object Value { get; } } } class Program { static void Main() { System.Console.Write(Test1(new S1(10))); System.Console.Write(Test1(default)); System.Console.Write(Test1(new S1(""11""))); System.Console.Write(Test1(new S1(0))); } static bool Test1(S1 u) { #line 21 return u is 10; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); var verifier = CompileAndVerify(comp, expectedOutput: "TrueFalseFalseFalse").VerifyDiagnostics(); verifier.VerifyIL("Program.Test1", @" { // Code size 35 (0x23) .maxstack 2 .locals init (object V_0) IL_0000: ldarga.s V_0 IL_0002: constrained. ""S1"" IL_0008: callvirt ""object S1.IBase1.Value.get"" IL_000d: stloc.0 IL_000e: ldloc.0 IL_000f: isinst ""int"" IL_0014: brfalse.s IL_0021 IL_0016: ldloc.0 IL_0017: unbox.any ""int"" IL_001c: ldc.i4.s 10 IL_001e: ceq IL_0020: ret IL_0021: ldc.i4.0 IL_0022: ret } "); } [Fact] public void UnionMatching_MemberProvider_Value_Inheritance_27_Shadowing() { var src = @" [System.Runtime.CompilerServices.Union] struct S1 : S1.IUnionMembers { private readonly object _value; public S1(int x) { _value = x; } public S1(string x) { _value = x; } object IBase1.Value => _value; object IBase2.Value() => throw null; public interface IUnionMembers : IBase2, IBase1 { public static S1 Create(int x) => new S1(x); public static S1 Create(string x) => new S1(x); } public interface IBase2 : IBase1 { new public object Value(); } public interface IBase1 { public object Value { get; } } } class Program { static void Main() { System.Console.Write(Test1(new S1(10))); System.Console.Write(Test1(default)); System.Console.Write(Test1(new S1(""11""))); System.Console.Write(Test1(new S1(0))); } static bool Test1(S1 u) { #line 21 return u is 10; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); var verifier = CompileAndVerify(comp, expectedOutput: "TrueFalseFalseFalse").VerifyDiagnostics(); verifier.VerifyIL("Program.Test1", @" { // Code size 35 (0x23) .maxstack 2 .locals init (object V_0) IL_0000: ldarga.s V_0 IL_0002: constrained. ""S1"" IL_0008: callvirt ""object S1.IBase1.Value.get"" IL_000d: stloc.0 IL_000e: ldloc.0 IL_000f: isinst ""int"" IL_0014: brfalse.s IL_0021 IL_0016: ldloc.0 IL_0017: unbox.any ""int"" IL_001c: ldc.i4.s 10 IL_001e: ceq IL_0020: ret IL_0021: ldc.i4.0 IL_0022: ret } "); } [Fact] public void NullCoalescing_CondAccess_ExplicitUserDefinedConv_01() { var source = @" [System.Runtime.CompilerServices.Union] struct S { public S(C? c) { } public object Value => throw null; } struct C { void M1(C? c1) { int x; S s = (S?)c1?.M2(x = 0) ?? c1.Value.M3(x = 0); #line 15 x.ToString(); // 1 } C M2(object obj) { return this; } S M3(object obj) { return (S)this; } } "; CreateCompilation([source, UnionAttributeSource]).VerifyDiagnostics( // (15,9): error CS0165: Use of unassigned local variable 'x' // x.ToString(); // 1 Diagnostic(ErrorCode.ERR_UseDefViolation, "x").WithArguments("x").WithLocation(15, 9)); } [Fact] public void NullCoalescing_CondAccess_ExplicitUserDefinedConv_02() { var source = @" [System.Runtime.CompilerServices.Union] class B { public B(C c) { } public object Value => throw null; } class C { void M1(C c1) { int x; B b = (B)c1?.M1(x = 0) ?? c1!.M2(x = 0); #line 11 x.ToString(); // 1 } C M1(object obj) { return this; } B M2(object obj) { return new B(null); } } "; // If the LHS of a `??` is cast using a user-defined conversion whose parameter // is not a non-nullable value type, we can't propagate out the "state when not null" // because we can't know whether the conditional access itself was non-null. CreateCompilation([source, UnionAttributeSource]).VerifyDiagnostics( // (11,9): error CS0165: Use of unassigned local variable 'x' // x.ToString(); // 1 Diagnostic(ErrorCode.ERR_UseDefViolation, "x").WithArguments("x").WithLocation(11, 9)); } [Fact] public void NullCoalescing_CondAccess_ExplicitUserDefinedConv_03() { var source = @" [System.Runtime.CompilerServices.Union] struct B { public B(C c) {} public object Value => throw null; } struct C { void M1(C? c1) { int x; #line 14 B b = (B?)c1?.M1(x = 0) ?? c1!.Value.M2(x = 0); x.ToString(); } C M1(object obj) { return this; } B M2(object obj) { return new B(); } } "; CreateCompilation([source, UnionAttributeSource]).VerifyDiagnostics( // (14,15): error CS0030: Cannot convert type 'C?' to 'B?' // B b = (B?)c1?.M1(x = 0) ?? c1!.Value.M2(x = 0); Diagnostic(ErrorCode.ERR_NoExplicitConv, "(B?)c1?.M1(x = 0)").WithArguments("C?", "B?").WithLocation(14, 15), // (15,9): error CS0165: Use of unassigned local variable 'x' // x.ToString(); Diagnostic(ErrorCode.ERR_UseDefViolation, "x").WithArguments("x").WithLocation(15, 9) ); } [Fact] public void NullCoalescing_CondAccess_ExplicitUserDefinedConv_04() { var source = @" [System.Runtime.CompilerServices.Union] struct B { public B(C c) {} public object Value => throw null; } struct C { void M1(C? c1) { int x; #line 14 B? b = (B?)c1?.M1(x = 0) ?? c1!.Value.M2(x = 0); x.ToString(); } C M1(object obj) { return this; } B? M2(object obj) { return new B(); } } "; CreateCompilation([source, UnionAttributeSource]).VerifyDiagnostics( // (14,16): error CS0030: Cannot convert type 'C?' to 'B?' // B? b = (B?)c1?.M1(x = 0) ?? c1!.Value.M2(x = 0); Diagnostic(ErrorCode.ERR_NoExplicitConv, "(B?)c1?.M1(x = 0)").WithArguments("C?", "B?").WithLocation(14, 16), // (15,9): error CS0165: Use of unassigned local variable 'x' // x.ToString(); Diagnostic(ErrorCode.ERR_UseDefViolation, "x").WithArguments("x").WithLocation(15, 9) ); } [Fact] public void NullCoalescing_CondAccess_ExplicitUserDefinedConv_05() { var source = @" [System.Runtime.CompilerServices.Union] struct B { public B(C c) {} public object Value => throw null; } class C { static void M1(C c1) { int x; B b = (B?)c1?.M1(x = 0) ?? c1.M2(x = 0); #line 13 x.ToString(); // 1 } C M1(object obj) { return this; } B M2(object obj) { return default; } } "; CreateCompilation([source, UnionAttributeSource]).VerifyDiagnostics( // (13,9): error CS0165: Use of unassigned local variable 'x' // x.ToString(); // 1 Diagnostic(ErrorCode.ERR_UseDefViolation, "x").WithArguments("x").WithLocation(13, 9)); } [Fact] public void NullCoalescingOperator_09() { var source = @"C? c = new C(); D d = c ?? new D(); d.ToString(); class C {} [System.Runtime.CompilerServices.Union] class D : D.IUnionMembers { public interface IUnionMembers { public static D? Create(C c) => default; public object Value { get; } } object IUnionMembers.Value => throw null!; } "; var comp = CreateCompilation([source, UnionAttributeSource], options: WithNullableEnable(TestOptions.ReleaseExe)); comp.VerifyDiagnostics( // (2,7): warning CS8600: Converting null literal or possible null value to non-nullable type. // D d = c ?? new D(); Diagnostic(ErrorCode.WRN_ConvertingNullableToNonNullable, "c ?? new D()").WithLocation(2, 7), // (4,1): warning CS8602: Dereference of a possibly null reference. // d.ToString(); Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "d").WithLocation(4, 1) ); } [Fact] public void ImplicitConversions_07() // This is a clone of a test from NullableReferenceTypesTests { var source = @" [System.Runtime.CompilerServices.Union] class A<T> { public A(B<T> b) => throw null!; public object Value => throw null!; } class B<T> { } class C { static B<T> F<T>(T t) => throw null!; static void G(A<object?> a) => throw null!; static void Main(object? x) { var y = F(x); G(y); if (x == null) return; var z = F(x); #line 18 G(z); // warning var z2 = F(x); G(z2!); } }"; var comp = CreateCompilation([source, UnionAttributeSource], options: WithNullableEnable()); comp.VerifyDiagnostics( // (18,11): warning CS8620: Argument of type 'B<object>' cannot be used for parameter 'b' of type 'B<object?>' in 'A<object?>.A(B<object?> b)' due to differences in the nullability of reference types. // G(z); // warning Diagnostic(ErrorCode.WRN_NullabilityMismatchInArgument, "z").WithArguments("B<object>", "B<object?>", "b", "A<object?>.A(B<object?> b)").WithLocation(18, 11) ); } [Fact] public void ImplicitConversion_Params() // This is a clone of a test from NullableReferenceTypesTests { var source = @" [System.Runtime.CompilerServices.Union] class A<T> { public A(B<T> b) => throw null!; public object Value => throw null!; } class B<T> { } class C { static B<T> F<T>(T t) => throw null!; static void G(params A<object>[] a) => throw null!; static void Main(object? x) { var y = F(x); #line 16 G(y); // 1 if (x == null) return; var z = F(x); G(z); } }"; var comp = CreateCompilation([source, UnionAttributeSource], options: WithNullableEnable()); comp.VerifyDiagnostics( // (16,11): warning CS8620: Argument of type 'B<object?>' cannot be used for parameter 'b' of type 'B<object>' in 'A<object>.A(B<object> b)' due to differences in the nullability of reference types. // G(y); // 1 Diagnostic(ErrorCode.WRN_NullabilityMismatchInArgument, "y").WithArguments("B<object?>", "B<object>", "b", "A<object>.A(B<object> b)").WithLocation(16, 11) ); } [Fact] public void NullableT_NullableStructToClass() // This is a clone of a test from NullableReferenceTypesTests { var source = @"struct S { } [System.Runtime.CompilerServices.Union] class C { public C(S? s) {} public object Value => throw null!; } class Program { // S -> C static void F1(S s) { var c1 = (C)s; _ = c1.ToString(); C c2 = s; _ = c2.ToString(); } // S? -> C? static void F2(S? ns) { if (ns.HasValue) { var c1 = (C?)ns; #line 24 _ = c1.ToString(); // 1 C? c2 = ns; _ = c2.ToString(); } else { var c3 = (C?)ns; #line 31 _ = c3.ToString(); // 2 C? c4 = ns; _ = c4.ToString(); } } }"; var comp = CreateCompilation([source, UnionAttributeSource], options: WithNullableEnable()); comp.VerifyDiagnostics( // (24,17): warning CS8602: Dereference of a possibly null reference. // _ = c1.ToString(); // 1 Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "c1").WithLocation(24, 17), // (31,17): warning CS8602: Dereference of a possibly null reference. // _ = c3.ToString(); // 2 Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "c3").WithLocation(31, 17)); } [Fact] public void TestOrder02() // This is a clone of a test from CodeGenTupleEqualityTests { var source = @" using System; public class C { public static void Main() { var result = (new B(1), new Nullable<B>(new A(2))) == (new A(3), new B(4)); Console.WriteLine(); Console.WriteLine(result); } } struct A { public readonly int N; public A(int n) { this.N = n; Console.Write($""new A({ n }); ""); } } [System.Runtime.CompilerServices.Union] #line 22 struct B { public readonly int N; public B(int n) { this.N = n; Console.Write($""new B({n}); ""); } public B(A a) { Console.Write($""A({a.N})->""); N = a.N; Console.Write($""new B({N}); ""); } public static bool operator ==(B b1, B b2) { Console.Write($""B({b1.N})==B({b2.N}); ""); return b1.N == b2.N; } public static bool operator !=(B b1, B b2) { Console.Write($""B({b1.N})!=B({b2.N}); ""); return b1.N != b2.N; } public object Value => throw null; } "; var comp = CreateCompilation([source, UnionAttributeSource], options: TestOptions.DebugExe); comp.VerifyDiagnostics( // (22,8): warning CS0660: 'B' defines operator == or operator != but does not override Object.Equals(object o) // struct B Diagnostic(ErrorCode.WRN_EqualityOpWithoutEquals, "B").WithArguments("B").WithLocation(22, 8), // (22,8): warning CS0661: 'B' defines operator == or operator != but does not override Object.GetHashCode() // struct B Diagnostic(ErrorCode.WRN_EqualityOpWithoutGetHashCode, "B").WithArguments("B").WithLocation(22, 8) ); CompileAndVerify(comp, expectedOutput: @"new B(1); new A(2); A(2)->new B(2); new A(3); new B(4); A(3)->new B(3); B(1)==B(3); False "); } [Fact] public void TypePattern_01_UnionInstance_Only_BindConstantPatternWithFallbackToTypePattern() { var src = @" class C0; [System.Runtime.CompilerServices.Union] class C1 : C0 { private readonly object _value; public C1(int x) { _value = x; } public C1(C0 x) { _value = x; } public object Value => _value; } class Program { static void Main() { System.Console.Write(Test1(new C1(10))); System.Console.Write(Test1(null)); System.Console.Write(Test1(new C1(new C1(1)))); System.Console.Write(Test1(new C1(new C0()))); } static bool Test1(C1 u) { return u switch { C1 => true, _ => false }; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); var verifier = CompileAndVerify(comp, expectedOutput: "TrueFalseTrueTrue").VerifyDiagnostics(); verifier.VerifyIL("Program.Test1", @" { // Code size 11 (0xb) .maxstack 1 .locals init (bool V_0) IL_0000: ldarg.0 IL_0001: brfalse.s IL_0007 IL_0003: ldc.i4.1 IL_0004: stloc.0 IL_0005: br.s IL_0009 IL_0007: ldc.i4.0 IL_0008: stloc.0 IL_0009: ldloc.0 IL_000a: ret } "); comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular15); CompileAndVerify(comp, expectedOutput: "TrueFalseTrueTrue").VerifyDiagnostics(); comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular14); CompileAndVerify(comp, expectedOutput: "TrueFalseTrueTrue").VerifyDiagnostics(); } [Fact] public void TypePattern_02_UnionInstance_Only_BindConstantPatternWithFallbackToTypePattern() { var src = @" [System.Runtime.CompilerServices.Union] class C1 { private readonly object _value; public C1(int x) { _value = x; } public C1(string x) { _value = x; } public object Value => _value; } class C2(string x) : C1(x); class Program { static void Main() { System.Console.Write(Test1(new C1(10))); System.Console.Write(Test1(null)); System.Console.Write(Test1(new C1(""a""))); System.Console.Write(Test1(new C1(null))); System.Console.Write(Test1(new C2(""a""))); System.Console.Write(Test1(new C2(null))); } static bool Test1(C1 u) { return u switch { C2 => true, _ => false }; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); var verifier = CompileAndVerify(comp, expectedOutput: "FalseFalseFalseFalseTrueTrue").VerifyDiagnostics(); verifier.VerifyIL("Program.Test1", @" { // Code size 16 (0x10) .maxstack 1 .locals init (bool V_0) IL_0000: ldarg.0 IL_0001: isinst ""C2"" IL_0006: brfalse.s IL_000c IL_0008: ldc.i4.1 IL_0009: stloc.0 IL_000a: br.s IL_000e IL_000c: ldc.i4.0 IL_000d: stloc.0 IL_000e: ldloc.0 IL_000f: ret } "); comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular15); CompileAndVerify(comp, expectedOutput: "FalseFalseFalseFalseTrueTrue").VerifyDiagnostics(); comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular14); CompileAndVerify(comp, expectedOutput: "FalseFalseFalseFalseTrueTrue").VerifyDiagnostics(); } [Fact] public void TypePattern_03_UnionInstance_Only_BindTypePattern() { var src = @" class C0; [System.Runtime.CompilerServices.Union] class C1 : C0 { private readonly object _value; public C1(int x) { _value = x; } public C1(C0 x) { _value = x; } public object Value => _value; } class Program { static void Main() { System.Console.Write(Test1(new C1(10))); System.Console.Write(Test1(null)); System.Console.Write(Test1(new C1(new C1(1)))); System.Console.Write(Test1(new C1(new C0()))); } static bool Test1(C1 u) { return u switch { global::C1 => true, _ => false }; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); var verifier = CompileAndVerify(comp, expectedOutput: "TrueFalseTrueTrue").VerifyDiagnostics(); verifier.VerifyIL("Program.Test1", @" { // Code size 11 (0xb) .maxstack 1 .locals init (bool V_0) IL_0000: ldarg.0 IL_0001: brfalse.s IL_0007 IL_0003: ldc.i4.1 IL_0004: stloc.0 IL_0005: br.s IL_0009 IL_0007: ldc.i4.0 IL_0008: stloc.0 IL_0009: ldloc.0 IL_000a: ret } "); comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular15); CompileAndVerify(comp, expectedOutput: "TrueFalseTrueTrue").VerifyDiagnostics(); comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular14); CompileAndVerify(comp, expectedOutput: "TrueFalseTrueTrue").VerifyDiagnostics(); } [Fact] public void TypePattern_04_UnionInstance_Only_BindTypePattern() { var src = @" [System.Runtime.CompilerServices.Union] class C1 { private readonly object _value; public C1(int x) { _value = x; } public C1(string x) { _value = x; } public object Value => _value; } class C2(string x) : C1(x); class Program { static void Main() { System.Console.Write(Test1(new C1(10))); System.Console.Write(Test1(null)); System.Console.Write(Test1(new C1(""a""))); System.Console.Write(Test1(new C1(null))); System.Console.Write(Test1(new C2(""a""))); System.Console.Write(Test1(new C2(null))); } static bool Test1(C1 u) { return u switch { global::C2 => true, _ => false }; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); var verifier = CompileAndVerify(comp, expectedOutput: "FalseFalseFalseFalseTrueTrue").VerifyDiagnostics(); verifier.VerifyIL("Program.Test1", @" { // Code size 16 (0x10) .maxstack 1 .locals init (bool V_0) IL_0000: ldarg.0 IL_0001: isinst ""C2"" IL_0006: brfalse.s IL_000c IL_0008: ldc.i4.1 IL_0009: stloc.0 IL_000a: br.s IL_000e IL_000c: ldc.i4.0 IL_000d: stloc.0 IL_000e: ldloc.0 IL_000f: ret } "); comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular15); CompileAndVerify(comp, expectedOutput: "FalseFalseFalseFalseTrueTrue").VerifyDiagnostics(); comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular14); CompileAndVerify(comp, expectedOutput: "FalseFalseFalseFalseTrueTrue").VerifyDiagnostics(); } [Fact] public void TypePattern_05_UnionInstance_Only_BindIsOperator() { var src = @" class C0 {} [System.Runtime.CompilerServices.Union] class C1 : C0 { private readonly object _value; public C1(int x) { _value = x; } public C1(C0 x) { _value = x; } public object Value => _value; } class Program { static void Main() { System.Console.Write(Test1(new C1(10))); System.Console.Write(Test1(null)); System.Console.Write(Test1(new C1(new C1(1)))); System.Console.Write(Test1(new C1(new C0()))); } static bool Test1(C1 u) { return u is C1; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); var verifier = CompileAndVerify(comp, expectedOutput: "TrueFalseTrueTrue").VerifyDiagnostics(); verifier.VerifyIL("Program.Test1", @" { // Code size 5 (0x5) .maxstack 2 IL_0000: ldarg.0 IL_0001: ldnull IL_0002: cgt.un IL_0004: ret } "); comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular15); CompileAndVerify(comp, expectedOutput: "TrueFalseTrueTrue").VerifyDiagnostics(); comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular14); CompileAndVerify(comp, expectedOutput: "TrueFalseTrueTrue").VerifyDiagnostics(); comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular6); CompileAndVerify(comp, expectedOutput: "TrueFalseTrueTrue").VerifyDiagnostics(); } [Fact] public void TypePattern_06_UnionInstance_Only_BindIsOperator() { var src = @" [System.Runtime.CompilerServices.Union] class C1 { private readonly object _value; public C1(int x) { _value = x; } public C1(string x) { _value = x; } public object Value => _value; } class C2(string x) : C1(x); class Program { static void Main() { System.Console.Write(Test1(new C1(10))); System.Console.Write(Test1(null)); System.Console.Write(Test1(new C1(""a""))); System.Console.Write(Test1(new C1(null))); System.Console.Write(Test1(new C2(""a""))); System.Console.Write(Test1(new C2(null))); } static bool Test1(C1 u) { return u is C2; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); var verifier = CompileAndVerify(comp, expectedOutput: "FalseFalseFalseFalseTrueTrue").VerifyDiagnostics(); verifier.VerifyIL("Program.Test1", @" { // Code size 10 (0xa) .maxstack 2 IL_0000: ldarg.0 IL_0001: isinst ""C2"" IL_0006: ldnull IL_0007: cgt.un IL_0009: ret } "); comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular15); CompileAndVerify(comp, expectedOutput: "FalseFalseFalseFalseTrueTrue").VerifyDiagnostics(); comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular14); CompileAndVerify(comp, expectedOutput: "FalseFalseFalseFalseTrueTrue").VerifyDiagnostics(); } [Fact] public void TypePattern_07_UnionInstance_And_Value_BindConstantPatternWithFallbackToTypePattern() { var src = @" [System.Runtime.CompilerServices.Union] class C1 { protected readonly object _value; public C1(int x) { _value = x; } public C1(C2 x) { _value = x; } protected C1(object x) { _value = x; } public object Value => _value; } class C2(object x) : I1 { public object Value1 => x; } class C3(object x) : C1(x), I1 { object I1.Value1 => _value; } interface I1 { object Value1 { get; } } class Program { static void Main() { System.Console.Write(Test1(new C1(10))); System.Console.Write(Test1(new C1(new C2(11)))); System.Console.Write(Test1(new C1(null))); System.Console.Write(Test1(null)); System.Console.Write(Test1(new C3(10))); System.Console.Write(Test1(new C3(new C2(11)))); System.Console.Write(Test1(new C3(null))); } static bool Test1(C1 u) { return u switch { I1 => true, _ => false }; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); VerifyDecisionDagDump<SwitchExpressionSyntax>(comp, @"[0]: t0 is I1 ? [4] : [1] [1]: t0 != null ? [2] : [5] [2]: t1 = t0.Value; [3] [3]: t1 is I1 ? [4] : [5] [4]: leaf <arm> `I1 => true` [5]: leaf <arm> `_ => false` ", forLowering: true); var verifier = CompileAndVerify(comp, expectedOutput: "FalseTrueFalseFalseTrueTrueTrue").VerifyDiagnostics(); comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular15); CompileAndVerify(comp, expectedOutput: "FalseTrueFalseFalseTrueTrueTrue").VerifyDiagnostics(); comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular14); comp.VerifyDiagnostics( // (42,27): error CS9327: Feature 'unions' is not available in C# 14.0. Please use language version 15.0 or greater. // return u switch { I1 => true, _ => false }; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion14, "I1").WithArguments("unions", "15.0").WithLocation(42, 27) ); } [Fact] public void TypePattern_08_UnionInstance_And_Value_Plus_Conjunction() { var src = @" [System.Runtime.CompilerServices.Union] class C1 { protected readonly object _value; public C1(int x) { _value = x; } public C1(C2 x) { _value = x; } protected C1(object x) { _value = x; } public object Value => _value; } class C2(object x) : I1 { public object Value1 => x; } class C3(object x) : C1(x), I1 { object I1.Value1 => _value; } interface I1 { object Value1 { get; } } class Program { static void Main() { System.Console.Write(Test1(new C1(10))); System.Console.Write(Test1(new C1(11))); System.Console.Write(Test1(new C1(new C2(10)))); System.Console.Write(Test1(new C1(new C2(11)))); System.Console.Write(Test1(new C1(new C2(null)))); System.Console.Write(Test1(new C1(null))); System.Console.Write(Test1(null)); System.Console.Write(Test1(new C3(10))); System.Console.Write(Test1(new C3(11))); System.Console.Write(Test1(new C3(new C2(10)))); System.Console.Write(Test1(new C3(new C2(11)))); System.Console.Write(Test1(new C3(new C2(null)))); System.Console.Write(Test1(new C3(null))); } static bool Test1(C1 u) { return u switch { I1 and { Value1: 10 } => true, _ => false }; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); VerifyDecisionDagDump<SwitchExpressionSyntax>(comp, @"[0]: t0 is I1 ? [1] : [6] [1]: t1 = (I1)t0; [2] [2]: t2 = t1.Value1; [3] [3]: t2 is int ? [4] : [15] [4]: t3 = (int)t2; [5] [5]: t3 == 10 ? [14] : [15] [6]: t0 != null ? [7] : [15] [7]: t4 = t0.Value; [8] [8]: t4 is I1 ? [9] : [15] [9]: t5 = (I1)t4; [10] [10]: t6 = t5.Value1; [11] [11]: t6 is int ? [12] : [15] [12]: t7 = (int)t6; [13] [13]: t7 == 10 ? [14] : [15] [14]: leaf <arm> `I1 and { Value1: 10 } => true` [15]: leaf <arm> `_ => false` ", forLowering: true); CompileAndVerify(comp, expectedOutput: "FalseFalseTrueFalseFalseFalseFalseTrueFalseFalseFalseFalseFalse").VerifyDiagnostics(); } [Fact] public void TypePattern_09_UnionInstance_And_Value_Plus_Conjunction() { var src = @" [System.Runtime.CompilerServices.Union] class C1 { protected readonly object _value; public C1(int x) { _value = x; } public C1(C4 x) { _value = x; } public C1(C5 x) { _value = x; } protected C1(object x) { _value = x; } public object Value => _value; } interface I2 { object Value2 { get; } } [System.Runtime.CompilerServices.Union] class C4 : C1 { public C4(int x) : base(x) {} public C4(C5 x) : base(x) {} protected C4(object x) : base(x) {} } class C5(object x) : I2 { public object Value2 => x; } class C6(object x) : C4(x), I2 { object I2.Value2 => _value; } class Program { static bool Test1(C1 u) { return u switch { C4 and I2 and { Value2: 11 } => true, _ => false }; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseDll); VerifyDecisionDagDump<SwitchExpressionSyntax>(comp, @"[0]: t0 is C4 ? [1] : [15] [1]: t1 = (C4)t0; [2] [2]: t1 is I2 ? [3] : [8] [3]: t2 = (I2)t1; [4] [4]: t3 = t2.Value2; [5] [5]: t3 is int ? [6] : [33] [6]: t4 = (int)t3; [7] [7]: t4 == 11 ? [32] : [33] [8]: t5 = t1.Value; [9] [9]: t5 is I2 ? [10] : [33] [10]: t6 = (I2)t5; [11] [11]: t7 = t6.Value2; [12] [12]: t7 is int ? [13] : [33] [13]: t8 = (int)t7; [14] [14]: t8 == 11 ? [32] : [33] [15]: t0 != null ? [16] : [33] [16]: t9 = t0.Value; [17] [17]: t9 is C4 ? [18] : [33] [18]: t10 = (C4)t9; [19] [19]: t10 is I2 ? [20] : [25] [20]: t11 = (I2)t10; [21] [21]: t12 = t11.Value2; [22] [22]: t12 is int ? [23] : [33] [23]: t13 = (int)t12; [24] [24]: t13 == 11 ? [32] : [33] [25]: t14 = t10.Value; [26] [26]: t14 is I2 ? [27] : [33] [27]: t15 = (I2)t14; [28] [28]: t16 = t15.Value2; [29] [29]: t16 is int ? [30] : [33] [30]: t17 = (int)t16; [31] [31]: t17 == 11 ? [32] : [33] [32]: leaf <arm> `C4 and I2 and { Value2: 11 } => true` [33]: leaf <arm> `_ => false` ", forLowering: true); CompileAndVerify(comp).VerifyDiagnostics(); } [Fact] public void TypePattern_10_UnionInstance_And_Value_Plus_Conjunction() { var src = @" [System.Runtime.CompilerServices.Union] class C1 { protected readonly object _value; public C1(int x) { _value = x; } public C1(C2 x) { _value = x; } public C1(C4 x) { _value = x; } public C1(C5 x) { _value = x; } protected C1(object x) { _value = x; } public object Value => _value; } class C2(object x) : I1 { public object Value1 => x; } class C3(object x) : C1(x), I1 { object I1.Value1 => _value; } interface I1 { object Value1 { get; } } interface I2 { object Value2 { get; } } [System.Runtime.CompilerServices.Union] class C4 : C1 { public C4(int x) : base(x) {} public C4(C5 x) : base(x) {} protected C4(object x) : base(x) {} } class C5(object x) : I2 { public object Value2 => x; } class C6(object x) : C4(x), I2 { object I2.Value2 => _value; } class C7(object x) : C6(x), I1 { object I1.Value1 => _value; } class Program { static bool Test1(C1 u) { return u switch { I1 and { Value1: 10 } and C4 and I2 and { Value2: 11 } => true, _ => false }; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseDll); VerifyDecisionDagDump<SwitchExpressionSyntax>(comp, @"[0]: t0 is I1 ? [1] : [21] [1]: t1 = (I1)t0; [2] [2]: t2 = t1.Value1; [3] [3]: t2 is int ? [4] : [45] [4]: t3 = (int)t2; [5] [5]: t3 == 10 ? [6] : [45] [6]: t1 is C4 ? [7] : [45] [7]: t4 = (C4)t1; [8] [8]: t4 is I2 ? [9] : [14] [9]: t5 = (I2)t4; [10] [10]: t6 = t5.Value2; [11] [11]: t6 is int ? [12] : [45] [12]: t7 = (int)t6; [13] [13]: t7 == 11 ? [44] : [45] [14]: t8 = t4.Value; [15] [15]: t8 is I2 ? [16] : [45] [16]: t9 = (I2)t8; [17] [17]: t10 = t9.Value2; [18] [18]: t10 is int ? [19] : [45] [19]: t11 = (int)t10; [20] [20]: t11 == 11 ? [44] : [45] [21]: t0 != null ? [22] : [45] [22]: t12 = t0.Value; [23] [23]: t12 is I1 ? [24] : [45] [24]: t13 = (I1)t12; [25] [25]: t14 = t13.Value1; [26] [26]: t14 is int ? [27] : [45] [27]: t15 = (int)t14; [28] [28]: t15 == 10 ? [29] : [45] [29]: t13 is C4 ? [30] : [45] [30]: t16 = (C4)t13; [31] [31]: t16 is I2 ? [32] : [37] [32]: t17 = (I2)t16; [33] [33]: t18 = t17.Value2; [34] [34]: t18 is int ? [35] : [45] [35]: t19 = (int)t18; [36] [36]: t19 == 11 ? [44] : [45] [37]: t20 = t16.Value; [38] [38]: t20 is I2 ? [39] : [45] [39]: t21 = (I2)t20; [40] [40]: t22 = t21.Value2; [41] [41]: t22 is int ? [42] : [45] [42]: t23 = (int)t22; [43] [43]: t23 == 11 ? [44] : [45] [44]: leaf <arm> `I1 and { Value1: 10 } and C4 and I2 and { Value2: 11 } => true` [45]: leaf <arm> `_ => false` ", forLowering: true); CompileAndVerify(comp).VerifyDiagnostics(); } [Fact] public void TypePattern_11_UnionInstance_And_Value_Exhaustiveness_And_Reachability() { var src0 = @" [System.Runtime.CompilerServices.Union] class C1 { protected readonly object _value; public C1(int x) { _value = x; } public C1(C2 x) { _value = x; } protected C1(object x) { _value = x; } public object Value => _value; } class C2 : I1 { public bool Value1 => throw null; } class C3(object x) : C1(x), I1 { bool I1.Value1 => throw null; } interface I1 { bool Value1 { get; } } "; var src1 = @" class Program { static int Test1(C1 u) { return u switch { I1 => 1, #line 100 I1 and { Value1: true } => 2, _ => 3 }; } } "; var comp = CreateCompilation([src1, src0, UnionAttributeSource], options: TestOptions.ReleaseDll); comp.VerifyDiagnostics( // (100,13): error CS8510: The pattern is unreachable. It has already been handled by a previous arm of the switch expression or it is impossible to match. // I1 and { Value1: true } => 2, Diagnostic(ErrorCode.ERR_SwitchArmSubsumed, "I1 and { Value1: true }").WithLocation(100, 13) ); var src2 = @" class Program { static int Test2(C1 u) { return u switch { I1 and { Value1: true } => 2, I1 => 1, _ => 3 }; } } "; comp = CreateCompilation([src2, src0, UnionAttributeSource], options: TestOptions.ReleaseDll); comp.VerifyDiagnostics(); var src3 = @" class Program { static int Test3(C1 u) { #line 300 return u switch { I1 and { Value1: true } => 2, not I1 => 3 }; } } "; comp = CreateCompilation([src3, src0, UnionAttributeSource], options: TestOptions.ReleaseDll); comp.VerifyDiagnostics( // (300,18): warning CS8509: The switch expression does not handle all possible values of its input type (it is not exhaustive). For example, the pattern 'I1{ Value1: false }' is not covered. // return u switch Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustive, "switch").WithArguments("I1{ Value1: false }").WithLocation(300, 18) ); src3 = @" class Program { static int Test3(object u) { #line 300 return u switch { C1 and I1 and { Value1: true } => 2, not C1 => 3, not I1 => 3 }; } } "; comp = CreateCompilation([src3, src0, UnionAttributeSource], options: TestOptions.ReleaseDll); comp.VerifyDiagnostics( // (300,18): warning CS8509: The switch expression does not handle all possible values of its input type (it is not exhaustive). For example, the pattern 'I1{ Value1: false }' is not covered. // return u switch Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustive, "switch").WithArguments("I1{ Value1: false }").WithLocation(300, 18) ); src3 = @" class Program { static int Test3(object u) { #line 300 return u switch { C1 { Value: I1 { Value1: false } } => 1, C1 and I1 and { Value1: true } => 2, not C1 => 3, }; } static int Test4(object u) { #line 400 return u switch { C1 { Value: I1 { Value1: false } } => 1, C1 and I1 and { Value1: true } => 2, not C1 => 3, C1 { Value: int } => 4, }; } static int Test5(object u) { #line 500 return u switch { C1 { Value: I1 { Value1: false } } => 1, C1 and I1 and { Value1: true } => 2, not C1 => 3, C1 { Value: int } => 4, C1 => 5, }; } } "; comp = CreateCompilation([src3, src0, UnionAttributeSource], options: TestOptions.ReleaseDll); comp.VerifyDiagnostics( // (300,18): warning CS8509: The switch expression does not handle all possible values of its input type (it is not exhaustive). For example, the pattern 'C1{ Value: int }' is not covered. // return u switch Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustive, "switch").WithArguments("C1{ Value: int }").WithLocation(300, 18), // (400,18): warning CS8509: The switch expression does not handle all possible values of its input type (it is not exhaustive). For example, the pattern 'C1' is not covered. // return u switch Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustive, "switch").WithArguments("C1").WithLocation(400, 18) ); var src4 = @" class Program { static int Test4(object u) { return u switch { I1 => 1, C1 { Value: I1 } => 4, #line 400 C1 and I1 and { Value1: true } => 2, _ => 3 }; } } "; comp = CreateCompilation([src4, src0, UnionAttributeSource], options: TestOptions.ReleaseDll); comp.VerifyDiagnostics( // (400,13): error CS8510: The pattern is unreachable. It has already been handled by a previous arm of the switch expression or it is impossible to match. // C1 and I1 and { Value1: true } => 2, Diagnostic(ErrorCode.ERR_SwitchArmSubsumed, "C1 and I1 and { Value1: true }").WithLocation(400, 13) ); var src5 = @" class Program { static int Test4(object u) { return u switch { I1 => 1, C1 and I1 and { Value1: true } => 2, _ => 3 }; } } "; comp = CreateCompilation([src5, src0, UnionAttributeSource], options: TestOptions.ReleaseDll); VerifyDecisionDagDump<SwitchExpressionSyntax>(comp, @"[0]: t0 is I1 ? [1] : [2] [1]: leaf <arm> `I1 => 1` [2]: t0 is C1 ? [3] : [10] [3]: t1 = (C1)t0; [4] [4]: t2 = t1.Value; [5] [5]: t2 is I1 ? [6] : [10] [6]: t3 = (I1)t2; [7] [7]: t4 = t3.Value1; [8] [8]: t4 == True ? [9] : [10] [9]: leaf <arm> `C1 and I1 and { Value1: true } => 2` [10]: leaf <arm> `_ => 3` ", forLowering: true); comp.VerifyDiagnostics( ); var src6 = @" class Program { static int Test4(object u) { return u switch { C1 { Value: I1 } => 4, C1 and I1 and { Value1: true } => 2, _ => 3 }; } } "; comp = CreateCompilation([src6, src0, UnionAttributeSource], options: TestOptions.ReleaseDll); VerifyDecisionDagDump<SwitchExpressionSyntax>(comp, @"[0]: t0 is C1 ? [1] : [10] [1]: t1 = (C1)t0; [2] [2]: t2 = t1.Value; [3] [3]: t2 is I1 ? [4] : [5] [4]: leaf <arm> `C1 { Value: I1 } => 4` [5]: t1 is I1 ? [6] : [10] [6]: t3 = (I1)t1; [7] [7]: t4 = t3.Value1; [8] [8]: t4 == True ? [9] : [10] [9]: leaf <arm> `C1 and I1 and { Value1: true } => 2` [10]: leaf <arm> `_ => 3` ", forLowering: true); comp.VerifyDiagnostics( ); var src7 = @" class Program { static int Test4(object u) { return u switch { I1 { Value1: false } => 1, C1 { Value: I1 { Value1: false } } => 4, C1 and I1 and { Value1: true } => 2, _ => 3 }; } } "; comp = CreateCompilation([src7, src0, UnionAttributeSource], options: TestOptions.ReleaseDll); VerifyDecisionDagDump<SwitchExpressionSyntax>(comp, @"[0]: t0 is I1 ? [1] : [9] [1]: t1 = (I1)t0; [2] [2]: t2 = t1.Value1; [3] [3]: t2 == False ? [4] : [5] [4]: leaf <arm> `I1 { Value1: false } => 1` [5]: t0 is C1 ? [6] : [18] [6]: t3 = (C1)t0; [7] [7]: t4 = t3.Value; [8] [8]: t4 is I1 ? [13] : [17] [9]: t0 is C1 ? [10] : [18] [10]: t3 = (C1)t0; [11] [11]: t4 = t3.Value; [12] [12]: t4 is I1 ? [13] : [18] [13]: t5 = (I1)t4; [14] [14]: t6 = t5.Value1; [15] [15]: t6 == False ? [16] : [17] [16]: leaf <arm> `C1 { Value: I1 { Value1: false } } => 4` [17]: leaf <arm> `C1 and I1 and { Value1: true } => 2` [18]: leaf <arm> `_ => 3` ", forLowering: true); comp.VerifyDiagnostics( ); var src8 = @" class Program { static int Test4(object u) { return u switch { I1 => 1, C1 { Value: I1 { Value1: false } } => 4, C1 and I1 and { Value1: true } => 2, _ => 3 }; } } "; comp = CreateCompilation([src8, src0, UnionAttributeSource], options: TestOptions.ReleaseDll); VerifyDecisionDagDump<SwitchExpressionSyntax>(comp, @"[0]: t0 is I1 ? [1] : [2] [1]: leaf <arm> `I1 => 1` [2]: t0 is C1 ? [3] : [11] [3]: t1 = (C1)t0; [4] [4]: t2 = t1.Value; [5] [5]: t2 is I1 ? [6] : [11] [6]: t3 = (I1)t2; [7] [7]: t4 = t3.Value1; [8] [8]: t4 == False ? [9] : [10] [9]: leaf <arm> `C1 { Value: I1 { Value1: false } } => 4` [10]: leaf <arm> `C1 and I1 and { Value1: true } => 2` [11]: leaf <arm> `_ => 3` ", forLowering: true); comp.VerifyDiagnostics( ); var src9 = @" class Program { static int Test4(object u) { return u switch { I1 { Value1: false } => 1, C1 { Value: I1 } => 4, C1 and I1 and { Value1: true } => 2, _ => 3 }; } } "; comp = CreateCompilation([src9, src0, UnionAttributeSource], options: TestOptions.ReleaseDll); VerifyDecisionDagDump<SwitchExpressionSyntax>(comp, @"[0]: t0 is I1 ? [1] : [10] [1]: t1 = (I1)t0; [2] [2]: t2 = t1.Value1; [3] [3]: t2 == False ? [4] : [5] [4]: leaf <arm> `I1 { Value1: false } => 1` [5]: t0 is C1 ? [6] : [15] [6]: t3 = (C1)t0; [7] [7]: t4 = t3.Value; [8] [8]: t4 is I1 ? [14] : [9] [9]: leaf <arm> `C1 and I1 and { Value1: true } => 2` [10]: t0 is C1 ? [11] : [15] [11]: t3 = (C1)t0; [12] [12]: t4 = t3.Value; [13] [13]: t4 is I1 ? [14] : [15] [14]: leaf <arm> `C1 { Value: I1 } => 4` [15]: leaf <arm> `_ => 3` ", forLowering: true); comp.VerifyDiagnostics( ); } [Fact] public void TypePattern_12_UnionInstance_And_Value_BindTypePattern() { var src = @" [System.Runtime.CompilerServices.Union] class C1 { protected readonly object _value; public C1(int x) { _value = x; } public C1(C2 x) { _value = x; } protected C1(object x) { _value = x; } public object Value => _value; } class C2(object x) : I1 { public object Value1 => x; } class C3(object x) : C1(x), I1 { object I1.Value1 => _value; } interface I1 { object Value1 { get; } } class Program { static void Main() { System.Console.Write(Test1(new C1(10))); System.Console.Write(Test1(new C1(new C2(11)))); System.Console.Write(Test1(new C1(null))); System.Console.Write(Test1(null)); System.Console.Write(Test1(new C3(10))); System.Console.Write(Test1(new C3(new C2(11)))); System.Console.Write(Test1(new C3(null))); } static bool Test1(C1 u) { return u switch { global::I1 => true, _ => false }; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); VerifyDecisionDagDump<SwitchExpressionSyntax>(comp, @"[0]: t0 is I1 ? [4] : [1] [1]: t0 != null ? [2] : [5] [2]: t1 = t0.Value; [3] [3]: t1 is I1 ? [4] : [5] [4]: leaf <arm> `global::I1 => true` [5]: leaf <arm> `_ => false` ", forLowering: true); var verifier = CompileAndVerify(comp, expectedOutput: "FalseTrueFalseFalseTrueTrueTrue").VerifyDiagnostics(); comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular15); CompileAndVerify(comp, expectedOutput: "FalseTrueFalseFalseTrueTrueTrue").VerifyDiagnostics(); comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular14); comp.VerifyDiagnostics( // (42,27): error CS9327: Feature 'unions' is not available in C# 14.0. Please use language version 15.0 or greater. // return u switch { global::I1 => true, _ => false }; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion14, "global::I1").WithArguments("unions", "15.0").WithLocation(42, 27) ); } [Fact] public void TypePattern_13_UnionInstance_And_Value_BindIsOperator() { var src = @" [System.Runtime.CompilerServices.Union] class C1 { protected readonly object _value; public C1(int x) { _value = x; } public C1(C2 x) { _value = x; } protected C1(object x) { _value = x; } public object Value => _value; } class C2 : I1 { private object _x; public C2(object x) { _x = x; } public object Value1 => _x; } class C3 : C1, I1 { public C3(object x) : base(x) { } object I1.Value1 => _value; } interface I1 { object Value1 { get; } } class Program { static void Main() { System.Console.Write(Test1(new C1(10))); System.Console.Write(Test1(new C1(new C2(11)))); System.Console.Write(Test1(new C1(null))); System.Console.Write(Test1(null)); System.Console.Write(Test1(new C3(10))); System.Console.Write(Test1(new C3(new C2(11)))); System.Console.Write(Test1(new C3(null))); } static bool Test1(C1 u) { #line 42 return u is I1; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); VerifyDecisionDagDump<BinaryExpressionSyntax>(comp, @"[0]: t0 is I1 ? [4] : [1] [1]: t0 != null ? [2] : [5] [2]: t1 = t0.Value; [3] [3]: t1 is I1 ? [4] : [5] [4]: leaf <isPatternSuccess> `u is I1` [5]: leaf <isPatternFailure> `u is I1` ", forLowering: true); var verifier = CompileAndVerify(comp, expectedOutput: "FalseTrueFalseFalseTrueTrueTrue").VerifyDiagnostics(); comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular15); CompileAndVerify(comp, expectedOutput: "FalseTrueFalseFalseTrueTrueTrue").VerifyDiagnostics(); comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular14); comp.VerifyDiagnostics( // (42,16): error CS9327: Feature 'unions' is not available in C# 14.0. Please use language version 15.0 or greater. // return u is I1; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion14, "u is I1").WithArguments("unions", "15.0").WithLocation(42, 16) ); comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular6); CompileAndVerify(comp, expectedOutput: "FalseFalseFalseFalseTrueTrueTrue").VerifyDiagnostics(); } [Fact] public void TypePattern_14_UnionInstance_And_Value_Plus_Designation() { var src = @" [System.Runtime.CompilerServices.Union] class C1 { protected readonly object _value; public C1(int x) { _value = x; } public C1(C2 x) { _value = x; } protected C1(object x) { _value = x; } public object Value => _value; } class C2(object x) : I1 { public object Value1 => x; } class C3(object x) : C1(x), I1 { object I1.Value1 => _value; } interface I1 { object Value1 { get; } } class Program { static void Main() { System.Console.Write(Test1(new C1(10))); System.Console.Write(Test1(new C1(11))); System.Console.Write(Test1(new C1(new C2(12)))); System.Console.Write(Test1(new C1(new C2(13)))); System.Console.Write(Test1(new C1(new C2(null)))); System.Console.Write(Test1(new C1(null))); System.Console.Write(Test1(null)); System.Console.Write(Test1(new C3(14))); System.Console.Write(Test1(new C3(15))); System.Console.Write(Test1(new C3(new C2(16)))); System.Console.Write(Test1(new C3(new C2(17)))); System.Console.Write(Test1(new C3(new C2(null)))); System.Console.Write(Test1(new C3(null))); } static int Test1(C1 u) { return u switch { I1 and { Value1: int i } => -i, _ => -999 }; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); comp.VerifyDiagnostics( // (48,48): error CS8780: A variable may not be declared within a 'not' or an 'or' pattern or a union matching involving matching against either the instance, or its underlying value. // return u switch { I1 and { Value1: int i } => -i, _ => -999 }; Diagnostic(ErrorCode.ERR_DesignatorBeneathPatternCombinator, "i").WithLocation(48, 48) ); } [Fact] public void TypePattern_15_UnionInstance_And_Value_Plus_Designation() { var src = @" [System.Runtime.CompilerServices.Union] class C1 { protected readonly object _value; public C1(int x) { _value = x; } public C1(C2 x) { _value = x; } protected C1(object x) { _value = x; } public object Value => _value; } class C2(object x) : I1 { public object Value1 => x; } class C3(object x) : C1(x), I1 { object I1.Value1 => _value; } interface I1 { object Value1 { get; } } class Program { static void Main() { System.Console.Write(Test1(new C1(10))); System.Console.Write(Test1(new C1(11))); System.Console.Write(Test1(new C1(new C2(12)))); System.Console.Write(Test1(new C1(new C2(13)))); System.Console.Write(Test1(new C1(new C2(null)))); System.Console.Write(Test1(new C1(null))); System.Console.Write(Test1(null)); System.Console.Write(Test1(new C3(14))); System.Console.Write(Test1(new C3(15))); System.Console.Write(Test1(new C3(new C2(16)))); System.Console.Write(Test1(new C3(new C2(17)))); System.Console.Write(Test1(new C3(new C2(null)))); System.Console.Write(Test1(new C3(null))); } static int Test1(C1 u) { if ( u is not (I1 and { Value1: int i })) return -999; return -i; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); comp.VerifyDiagnostics( // (48,45): error CS8780: A variable may not be declared within a 'not' or an 'or' pattern or a union matching involving matching against either the instance, or its underlying value. // if ( u is not (I1 and { Value1: int i })) Diagnostic(ErrorCode.ERR_DesignatorBeneathPatternCombinator, "i").WithLocation(48, 45) ); } [Fact] public void TypePattern_16_UnionInstance_And_Value_Plus_Designation() { var src = @" [System.Runtime.CompilerServices.Union] class C1 { protected readonly object _value; public C1(int x) { _value = x; } public C1(C2 x) { _value = x; } protected C1(object x) { _value = x; } public object Value => _value; } class C2(object x) : I1 { public object Value1 => x; } class C3(object x) : C1(x), I1 { object I1.Value1 => _value; } interface I1 { object Value1 { get; } } class Program { static void Main() { System.Console.Write(Test1(new C1(10))); System.Console.Write(Test1(new C1(11))); System.Console.Write(Test1(new C1(new C2(12)))); System.Console.Write(Test1(new C1(new C2(13)))); System.Console.Write(Test1(new C1(new C2(null)))); System.Console.Write(Test1(new C1(null))); System.Console.Write(Test1(null)); System.Console.Write(Test1(new C3(14))); System.Console.Write(Test1(new C3(15))); System.Console.Write(Test1(new C3(new C2(16)))); System.Console.Write(Test1(new C3(new C2(17)))); System.Console.Write(Test1(new C3(new C2(null)))); System.Console.Write(Test1(new C3(null))); } static int Test1(C1 u) { return u switch { I1 and var i1 and { Value1: int } => -(int)i1.Value1, _ => -999 }; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); comp.VerifyDiagnostics( // (48,38): error CS8780: A variable may not be declared within a 'not' or an 'or' pattern or a union matching involving matching against either the instance, or its underlying value. // return u switch { I1 and var i1 and { Value1: int } => -(int)i1.Value1, _ => -999 }; Diagnostic(ErrorCode.ERR_DesignatorBeneathPatternCombinator, "i1").WithLocation(48, 38) ); } [Fact] public void TypePattern_17_UnionInstance_And_Value_Plus_Designation() { var src = @" [System.Runtime.CompilerServices.Union] class C1 { protected readonly object _value; public C1(int x) { _value = x; } public C1(C2 x) { _value = x; } protected C1(object x) { _value = x; } public object Value => _value; } class C2(object x) : I1 { public object Value1 => x; } class C3(object x) : C1(x), I1 { object I1.Value1 => _value; } interface I1 { object Value1 { get; } } class Program { static void Main() { //System.Console.Write(Test1(new C1(10))); //System.Console.Write(Test1(new C1(11))); //System.Console.Write(Test1(new C1(new C2(12)))); //System.Console.Write(Test1(new C1(new C2(13)))); //System.Console.Write(Test1(new C1(new C2(null)))); //System.Console.Write(Test1(new C1(null))); //System.Console.Write(Test1(null)); //System.Console.Write(Test1(new C3(14))); //System.Console.Write(Test1(new C3(15))); //System.Console.Write(Test1(new C3(new C2(16)))); //System.Console.Write(Test1(new C3(new C2(17)))); //System.Console.Write(Test1(new C3(new C2(null)))); //System.Console.Write(Test1(new C3(null))); } static int Test1(C1 u) { switch (u) { #line 100 case I1 and var i1 and { Value1: int } when GetTrue(ref i1): return -(int)i1.Value1; default: return -999; } } static int Test2(object u) { switch (u) { #line 200 case C1 and I1 and var i1 and { Value1: int } when GetTrue(ref i1): return -(int)i1.Value1; default: return -999; } } static int Test3(object u) { switch (u) { #line 300 case C1 and (I1) and var i1 and { Value1: int } when GetTrue(ref i1): return -(int)i1.Value1; default: return -999; } } static int Test4(object u) { switch (u) { #line 400 case (C1 and I1) and var i1 and { Value1: int } when GetTrue(ref i1): return -(int)i1.Value1; default: return -999; } } static int Test5(object u) { switch (u) { #line 500 case C1 and (I1 and { Value1: int }) and var i1 when GetTrue(ref i1): return -(int)i1.Value1; default: return -999; } } static int Test6(object u) { switch (u) { #line 600 case (C1 and I1) and ({ Value1: int } and var i1) when GetTrue(ref i1): return -(int)i1.Value1; default: return -999; } } static int Test7(object u) { switch (u) { #line 700 case C1 and I1 and { Value1: int } i1 when GetTrue(ref i1): return -(int)i1.Value1; default: return -999; } } static int Test8(C1 u) { switch (u) { #line 800 case (I1 or int) and var i1: return 0; default: return -999; } } static int Test9(C1 u) { switch (u) { #line 900 case (int or I1) and var i1: return 0; default: return -999; } } static bool GetTrue(ref I1 i1) => true; } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); comp.VerifyDiagnostics( // (100,29): error CS8780: A variable may not be declared within a 'not' or an 'or' pattern or a union matching involving matching against either the instance, or its underlying value. // case I1 and var i1 and { Value1: int } when GetTrue(ref i1): Diagnostic(ErrorCode.ERR_DesignatorBeneathPatternCombinator, "i1").WithLocation(100, 29), // (200,36): error CS8780: A variable may not be declared within a 'not' or an 'or' pattern or a union matching involving matching against either the instance, or its underlying value. // case C1 and I1 and var i1 and { Value1: int } when GetTrue(ref i1): Diagnostic(ErrorCode.ERR_DesignatorBeneathPatternCombinator, "i1").WithLocation(200, 36), // (300,38): error CS8780: A variable may not be declared within a 'not' or an 'or' pattern or a union matching involving matching against either the instance, or its underlying value. // case C1 and (I1) and var i1 and { Value1: int } when GetTrue(ref i1): Diagnostic(ErrorCode.ERR_DesignatorBeneathPatternCombinator, "i1").WithLocation(300, 38), // (400,38): error CS8780: A variable may not be declared within a 'not' or an 'or' pattern or a union matching involving matching against either the instance, or its underlying value. // case (C1 and I1) and var i1 and { Value1: int } when GetTrue(ref i1): Diagnostic(ErrorCode.ERR_DesignatorBeneathPatternCombinator, "i1").WithLocation(400, 38), // (500,58): error CS8780: A variable may not be declared within a 'not' or an 'or' pattern or a union matching involving matching against either the instance, or its underlying value. // case C1 and (I1 and { Value1: int }) and var i1 when GetTrue(ref i1): Diagnostic(ErrorCode.ERR_DesignatorBeneathPatternCombinator, "i1").WithLocation(500, 58), // (600,59): error CS8780: A variable may not be declared within a 'not' or an 'or' pattern or a union matching involving matching against either the instance, or its underlying value. // case (C1 and I1) and ({ Value1: int } and var i1) when GetTrue(ref i1): Diagnostic(ErrorCode.ERR_DesignatorBeneathPatternCombinator, "i1").WithLocation(600, 59), // (700,48): error CS8780: A variable may not be declared within a 'not' or an 'or' pattern or a union matching involving matching against either the instance, or its underlying value. // case C1 and I1 and { Value1: int } i1 when GetTrue(ref i1): Diagnostic(ErrorCode.ERR_DesignatorBeneathPatternCombinator, "i1").WithLocation(700, 48) ); } [Fact] public void TypePattern_18_UnionInstance_And_Value_Plus_Designation() { var src = @" [System.Runtime.CompilerServices.Union] class C1 { protected readonly object _value; public C1(int x) { _value = x; } public C1(C2 x) { _value = x; } protected C1(object x) { _value = x; } public object Value => _value; public int Length => 0; public object this[int i] => null; public C1 this[System.Range i] => null; } class C2(object x) : I1 { public object Value1 => x; } class C3(object x) : C1(x), I1 { object I1.Value1 => _value; } interface I1 { object Value1 { get; } } class Program { static int Test1(C1 u) { switch (u) { #line 100 case [.. I1 and var i1, _ ]: return -(int)i1.Value1; default: return -999; } } static int Test2(C1 u) { switch (u) { #line 200 case [.. I1, var i1 ] and var u1: return -(int)i1; default: return -999; } } static int Test3(C1 u) { switch (u) { #line 300 case not [.. var i1, _ ]: return -1; default: return -999; } } } "; var comp = CreateCompilation([src, UnionAttributeSource], targetFramework: TargetFramework.NetCoreApp, options: TestOptions.ReleaseDll); comp.VerifyDiagnostics( // (100,33): error CS8780: A variable may not be declared within a 'not' or an 'or' pattern or a union matching involving matching against either the instance, or its underlying value. // case [.. I1 and var i1, _ ]: Diagnostic(ErrorCode.ERR_DesignatorBeneathPatternCombinator, "i1").WithLocation(100, 33), // (300,30): error CS8780: A variable may not be declared within a 'not' or an 'or' pattern or a union matching involving matching against either the instance, or its underlying value. // case not [.. var i1, _ ]: Diagnostic(ErrorCode.ERR_DesignatorBeneathPatternCombinator, "i1").WithLocation(300, 30) ); } [Fact] public void TypePattern_19_UnionInstance_And_Value_Plus_Designation() { var src = @" [System.Runtime.CompilerServices.Union] class C1 { protected readonly object _value; public C1(int x) { _value = x; } public C1(C2 x) { _value = x; } protected C1(object x) { _value = x; } public object Value => _value; } class C2(object x) : I1 { public object Value1 => x; } class C3(object x) : C1(x), I1 { object I1.Value1 => _value; } interface I1 { object Value1 { get; } } class Program { static int Test1(C1[] u) { switch (u) { #line 100 case [I1 and var i1, _ ]: return -(int)i1.Value1; default: return -999; } } static int Test2(C1[] u) { switch (u) { #line 200 case [I1, var i1 ] and var u1: return -1; default: return -999; } } static int Test3(C1[] u) { switch (u) { #line 300 case not [var i1, _ ]: return -1; default: return -999; } } } "; var comp = CreateCompilation([src, UnionAttributeSource], targetFramework: TargetFramework.NetCoreApp, options: TestOptions.ReleaseDll); comp.VerifyDiagnostics( // (100,30): error CS8780: A variable may not be declared within a 'not' or an 'or' pattern or a union matching involving matching against either the instance, or its underlying value. // case [I1 and var i1, _ ]: Diagnostic(ErrorCode.ERR_DesignatorBeneathPatternCombinator, "i1").WithLocation(100, 30), // (300,27): error CS8780: A variable may not be declared within a 'not' or an 'or' pattern or a union matching involving matching against either the instance, or its underlying value. // case not [var i1, _ ]: Diagnostic(ErrorCode.ERR_DesignatorBeneathPatternCombinator, "i1").WithLocation(300, 27) ); } [Fact] public void TypePattern_20_UnionInstance_And_Value_Plus_Designation() { var src = @" [System.Runtime.CompilerServices.Union] class C1 { protected readonly object _value; public C1(int x) { _value = x; } public C1(C2 x) { _value = x; } protected C1(object x) { _value = x; } public object Value => _value; } class C2(object x) : I1 { public object Value1 => x; } class C3(object x) : C1(x), I1 { object I1.Value1 => _value; } interface I1 { object Value1 { get; } } class Program { static int Test1((C1, object) u) { switch (u) { #line 100 case (I1 and var i1, _ ): return -(int)i1.Value1; default: return -999; } } static int Test2((C1, object) u) { switch (u) { #line 200 case (I1, var i1 ) and var u1: return -1; default: return -999; } } static int Test3((C1, object) u) { switch (u) { #line 300 case not (var i1, _ ): return -1; default: return -999; } } } "; var comp = CreateCompilation([src, UnionAttributeSource], targetFramework: TargetFramework.NetCoreApp, options: TestOptions.ReleaseDll); comp.VerifyDiagnostics( // (100,30): error CS8780: A variable may not be declared within a 'not' or an 'or' pattern or a union matching involving matching against either the instance, or its underlying value. // case (I1 and var i1, _ ): Diagnostic(ErrorCode.ERR_DesignatorBeneathPatternCombinator, "i1").WithLocation(100, 30), // (300,18): error CS8120: The switch case is unreachable. It has already been handled by a previous case or it is impossible to match. // case not (var i1, _ ): Diagnostic(ErrorCode.ERR_SwitchCaseSubsumed, "not (var i1, _ )").WithLocation(300, 18), // (300,27): error CS8780: A variable may not be declared within a 'not' or an 'or' pattern or a union matching involving matching against either the instance, or its underlying value. // case not (var i1, _ ): Diagnostic(ErrorCode.ERR_DesignatorBeneathPatternCombinator, "i1").WithLocation(300, 27) ); } [Fact] public void TypePattern_21_UnionInstance_And_Value_Plus_Designation() { var src = @" [System.Runtime.CompilerServices.Union] class C1 { protected readonly object _value; public C1(int x) { _value = x; } public C1(C2 x) { _value = x; } protected C1(object x) { _value = x; } public object Value => _value; } class C2(object x) : I1 { public object Value1 => x; } class C3(object x) : C1(x), I1 { object I1.Value1 => _value; } interface I1 { object Value1 { get; } } class C4 { public void Deconstruct(out C1 c, out object x) => throw null; } class Program { static int Test1(C4 u) { switch (u) { #line 100 case (I1 and var i1, _ ): return -(int)i1.Value1; default: return -999; } } static int Test2(C4 u) { switch (u) { #line 200 case (I1, var i1 ) and var u1: return -1; default: return -999; } } static int Test3(C4 u) { switch (u) { #line 300 case not (var i1, _ ): return -1; default: return -999; } } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseDll); comp.VerifyDiagnostics( // (100,30): error CS8780: A variable may not be declared within a 'not' or an 'or' pattern or a union matching involving matching against either the instance, or its underlying value. // case (I1 and var i1, _ ): Diagnostic(ErrorCode.ERR_DesignatorBeneathPatternCombinator, "i1").WithLocation(100, 30), // (300,27): error CS8780: A variable may not be declared within a 'not' or an 'or' pattern or a union matching involving matching against either the instance, or its underlying value. // case not (var i1, _ ): Diagnostic(ErrorCode.ERR_DesignatorBeneathPatternCombinator, "i1").WithLocation(300, 27) ); } [Fact] public void TypePattern_22_UnionInstance_And_Value_Plus_Designation() { var src = @" [System.Runtime.CompilerServices.Union] class C1 { protected readonly object _value; public C1(int x) { _value = x; } public C1(C2 x) { _value = x; } protected C1(object x) { _value = x; } public object Value => _value; } class C2(object x) : I1 { public object Value1 => x; } class C3(object x) : C1(x), I1 { object I1.Value1 => _value; } interface I1 { object Value1 { get; } } class Program { static int Test1(System.Runtime.CompilerServices.ITuple u) { switch (u) { #line 100 case (C1 and I1 and var i1, _ ): return -(int)i1.Value1; default: return -999; } } static int Test2(System.Runtime.CompilerServices.ITuple u) { switch (u) { #line 200 case (C1 and I1, var i1 ) and var u1: return -1; default: return -999; } } static int Test3(System.Runtime.CompilerServices.ITuple u) { switch (u) { #line 300 case not (var i1, _ ): return -1; default: return -999; } } } "; var comp = CreateCompilation([src, UnionAttributeSource], targetFramework: TargetFramework.NetCoreApp, options: TestOptions.ReleaseDll); comp.VerifyDiagnostics( // (100,37): error CS8780: A variable may not be declared within a 'not' or an 'or' pattern or a union matching involving matching against either the instance, or its underlying value. // case (C1 and I1 and var i1, _ ): Diagnostic(ErrorCode.ERR_DesignatorBeneathPatternCombinator, "i1").WithLocation(100, 37), // (300,27): error CS8780: A variable may not be declared within a 'not' or an 'or' pattern or a union matching involving matching against either the instance, or its underlying value. // case not (var i1, _ ): Diagnostic(ErrorCode.ERR_DesignatorBeneathPatternCombinator, "i1").WithLocation(300, 27) ); } [Fact] public void TypePattern_23_UnionInstance_And_Value_Plus_Designation() { var src = @" [System.Runtime.CompilerServices.Union] class C1 { protected readonly object _value; public C1(int x) { _value = x; } public C1(C2 x) { _value = x; } protected C1(object x) { _value = x; } public object Value => _value; } class C2(object x) : I1 { public object Value1 => x; } class C3(object x) : C1(x), I1 { object I1.Value1 => _value; } interface I1 { object Value1 { get; } } class C4 { public C1 C => throw null; public object O => throw null; } class Program { static int Test1(C4 u) { switch (u) { #line 100 case { C: I1 and var i1, O: _ }: return -(int)i1.Value1; default: return -999; } } static int Test2(C4 u) { switch (u) { #line 200 case { C: I1, O: var i1 } and var u1: return -1; default: return -999; } } static int Test3(C4 u) { switch (u) { #line 300 case not { C: var i1, O: _ }: return -1; default: return -999; } } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseDll); comp.VerifyDiagnostics( // (100,34): error CS8780: A variable may not be declared within a 'not' or an 'or' pattern or a union matching involving matching against either the instance, or its underlying value. // case { C: I1 and var i1, O: _ }: Diagnostic(ErrorCode.ERR_DesignatorBeneathPatternCombinator, "i1").WithLocation(100, 34), // (300,31): error CS8780: A variable may not be declared within a 'not' or an 'or' pattern or a union matching involving matching against either the instance, or its underlying value. // case not { C: var i1, O: _ }: Diagnostic(ErrorCode.ERR_DesignatorBeneathPatternCombinator, "i1").WithLocation(300, 31) ); } [Fact] public void TypePattern_24_UnionInstance_And_Value() { var source1 = @" #nullable enable public union U<T>(T); class Program { int M9<Y>(U<Y> y) { return y switch { Y => 1, }; } } "; var comp = CreateCompilation([source1, UnionAttributeSource, IUnionSource, IsClosedTypeAttributeDefinition]); VerifyDecisionDagDump<SwitchExpressionSyntax>(comp, @"[0]: t0 is Y ? [3] : [1] [1]: t1 = t0.Value; [2] [2]: t1 != null ? [3] : [4] [3]: leaf <arm> `Y => 1` [4]: leaf <default> `y switch { Y => 1, }` ", forLowering: false); comp.VerifyEmitDiagnostics( // (10,18): warning CS8655: The switch expression does not handle some null inputs (it is not exhaustive). For example, the pattern 'null' is not covered. // return y switch Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustiveForNull, "switch").WithArguments("null").WithLocation(10, 18) ); var source2 = @" #nullable enable public union U<T>(T); class Program { int M9<Y>(U<Y> y) { return y switch { Y => 1, null => 2, }; } } "; comp = CreateCompilation([source2, UnionAttributeSource, IUnionSource, IsClosedTypeAttributeDefinition]); VerifyDecisionDagDump<SwitchExpressionSyntax>(comp, @"[0]: t0 is Y ? [3] : [1] [1]: t1 = t0.Value; [2] [2]: t1 != null ? [3] : [4] [3]: leaf <arm> `Y => 1` [4]: leaf <arm> `null => 2` ", forLowering: false); comp.VerifyEmitDiagnostics( ); } [Fact] public void TypePattern_25_UnionInstance_And_Value() { var source1 = @" #nullable enable public union U<T>(T); class Program { int M9<Y>(U<Y> y) where Y : struct { return y switch { Y => 1, }; } } "; var comp = CreateCompilation([source1, UnionAttributeSource, IUnionSource, IsClosedTypeAttributeDefinition]); VerifyDecisionDagDump<SwitchExpressionSyntax>(comp, @"[0]: t0 is Y ? [3] : [1] [1]: t1 = t0.Value; [2] [2]: t1 != null ? [3] : [4] [3]: leaf <arm> `Y => 1` [4]: leaf <default> `y switch { Y => 1, }` ", forLowering: false); comp.VerifyEmitDiagnostics(); var source2 = @" #nullable enable public union U<T>(T); class Program { int M9<Y>(U<Y> y) where Y : struct { return y switch { Y => 1, null => 2, }; } } "; comp = CreateCompilation([source2, UnionAttributeSource, IUnionSource, IsClosedTypeAttributeDefinition]); VerifyDecisionDagDump<SwitchExpressionSyntax>(comp, @"[0]: t0 is Y ? [3] : [1] [1]: t1 = t0.Value; [2] [2]: t1 != null ? [3] : [4] [3]: leaf <arm> `Y => 1` [4]: leaf <arm> `null => 2` ", forLowering: false); comp.VerifyEmitDiagnostics( ); } [Fact] public void TypePattern_26_UnionInstance_And_Value() { var source1 = @" #nullable enable public union U<T>(T); class Program { int M9<Y>(U<Y> y) where Y : class? { return y switch { Y => 1, }; } } "; var comp = CreateCompilation([source1, UnionAttributeSource, IUnionSource, IsClosedTypeAttributeDefinition]); VerifyDecisionDagDump<SwitchExpressionSyntax>(comp, @"[0]: t0 is Y ? [3] : [1] [1]: t1 = t0.Value; [2] [2]: t1 != null ? [3] : [4] [3]: leaf <arm> `Y => 1` [4]: leaf <default> `y switch { Y => 1, }` ", forLowering: false); comp.VerifyEmitDiagnostics( // (10,18): warning CS8655: The switch expression does not handle some null inputs (it is not exhaustive). For example, the pattern 'null' is not covered. // return y switch Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustiveForNull, "switch").WithArguments("null").WithLocation(10, 18) ); var source2 = @" #nullable enable public union U<T>(T); class Program { int M9<Y>(U<Y> y) where Y : class? { return y switch { Y => 1, null => 2, }; } } "; comp = CreateCompilation([source2, UnionAttributeSource, IUnionSource, IsClosedTypeAttributeDefinition]); VerifyDecisionDagDump<SwitchExpressionSyntax>(comp, @"[0]: t0 is Y ? [3] : [1] [1]: t1 = t0.Value; [2] [2]: t1 != null ? [3] : [4] [3]: leaf <arm> `Y => 1` [4]: leaf <arm> `null => 2` ", forLowering: false); comp.VerifyEmitDiagnostics( ); } [Fact] public void TypePattern_27_UnionInstance_And_Value() { var source1 = @" #nullable enable public union U<T>(T); class Program { int M9<Y>(U<Y> y) where Y : notnull { return y switch { Y => 1, }; } } "; var comp = CreateCompilation([source1, UnionAttributeSource, IUnionSource, IsClosedTypeAttributeDefinition]); VerifyDecisionDagDump<SwitchExpressionSyntax>(comp, @"[0]: t0 is Y ? [3] : [1] [1]: t1 = t0.Value; [2] [2]: t1 != null ? [3] : [4] [3]: leaf <arm> `Y => 1` [4]: leaf <default> `y switch { Y => 1, }` ", forLowering: false); comp.VerifyEmitDiagnostics(); var source2 = @" #nullable enable public union U<T>(T); class Program { int M9<Y>(U<Y> y) where Y : notnull { return y switch { Y => 1, null => 2, }; } } "; comp = CreateCompilation([source2, UnionAttributeSource, IUnionSource, IsClosedTypeAttributeDefinition]); VerifyDecisionDagDump<SwitchExpressionSyntax>(comp, @"[0]: t0 is Y ? [3] : [1] [1]: t1 = t0.Value; [2] [2]: t1 != null ? [3] : [4] [3]: leaf <arm> `Y => 1` [4]: leaf <arm> `null => 2` ", forLowering: false); comp.VerifyEmitDiagnostics( ); } [Fact] public void TypePattern_28_UnionInstance_And_Value() { var source1 = @" #nullable enable public union U<T>(T); class Program { int M9<Y>(U<Y> y) where Y : class { return y switch { Y => 1, }; } } "; var comp = CreateCompilation([source1, UnionAttributeSource, IUnionSource, IsClosedTypeAttributeDefinition]); VerifyDecisionDagDump<SwitchExpressionSyntax>(comp, @"[0]: t0 is Y ? [3] : [1] [1]: t1 = t0.Value; [2] [2]: t1 != null ? [3] : [4] [3]: leaf <arm> `Y => 1` [4]: leaf <default> `y switch { Y => 1, }` ", forLowering: false); comp.VerifyEmitDiagnostics(); var source2 = @" #nullable enable public union U<T>(T); class Program { int M9<Y>(U<Y> y) where Y : class { return y switch { Y => 1, null => 2, }; } } "; comp = CreateCompilation([source2, UnionAttributeSource, IUnionSource, IsClosedTypeAttributeDefinition]); VerifyDecisionDagDump<SwitchExpressionSyntax>(comp, @"[0]: t0 is Y ? [3] : [1] [1]: t1 = t0.Value; [2] [2]: t1 != null ? [3] : [4] [3]: leaf <arm> `Y => 1` [4]: leaf <arm> `null => 2` ", forLowering: false); comp.VerifyEmitDiagnostics( ); } [Fact] public void TypePattern_29_UnionInstance_And_Value() { var source1 = @" [System.Runtime.CompilerServices.Union] class U<T> { private readonly object _value; public U(T x) { _value = x; } public object Value => _value; } "; var source2 = @" #nullable enable class Program { int M9<X, Y>(U<Y> y) where Y : X { #line 100 return y switch { Y => 1, #line 400 X => 2, }; } } "; var comp = CreateCompilation([source1 + source2, UnionAttributeSource]); VerifyDecisionDagDump<SwitchExpressionSyntax>(comp, @"[0]: t0 is Y ? [4] : [1] [1]: t0 != null ? [2] : [7] [2]: t1 = t0.Value; [3] [3]: t1 != null ? [4] : [5] [4]: leaf <arm> `Y => 1` [5]: t0 is X ? [6] : [7] [6]: leaf <arm> `X => 2` [7]: leaf <default> `y switch { Y => 1, #line 400 X => 2, }` ", forLowering: false); comp.VerifyEmitDiagnostics( // (100,18): warning CS8655: The switch expression does not handle some null inputs (it is not exhaustive). For example, the pattern 'null' is not covered. // return y switch Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustiveForNull, "switch").WithArguments("null").WithLocation(100, 18) ); var source3 = @" class U<T> { } "; comp = CreateCompilation([source3 + source2]); VerifyDecisionDagDump<SwitchExpressionSyntax>(comp, @"[0]: t0 is Y ? [1] : [2] [1]: leaf <arm> `Y => 1` [2]: t0 is X ? [3] : [4] [3]: leaf <arm> `X => 2` [4]: leaf <default> `y switch { Y => 1, #line 400 X => 2, }` ", forLowering: false); comp.VerifyEmitDiagnostics( // (100,18): warning CS8509: The switch expression does not handle all possible values of its input type (it is not exhaustive). For example, the pattern '_' is not covered. // return y switch Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustive, "switch").WithArguments("_").WithLocation(100, 18) ); } [Fact] public void DeclarationPattern_01_UnionInstance_Only() { var src = @" class C0; [System.Runtime.CompilerServices.Union] class C1 : C0 { private readonly object _value; public C1(int x) { _value = x; } public C1(C0 x) { _value = x; } public object Value => _value; } class Program { static void Main() { System.Console.Write(Test1(new C1(10))); System.Console.Write(Test1(null)); System.Console.Write(Test1(new C1(new C1(1)))); System.Console.Write(Test1(new C1(new C0()))); } static bool Test1(C1 u) { return u switch { C1 x => true, _ => false }; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); var verifier = CompileAndVerify(comp, expectedOutput: "TrueFalseTrueTrue").VerifyDiagnostics(); verifier.VerifyIL("Program.Test1", @" { // Code size 11 (0xb) .maxstack 1 .locals init (bool V_0) IL_0000: ldarg.0 IL_0001: brfalse.s IL_0007 IL_0003: ldc.i4.1 IL_0004: stloc.0 IL_0005: br.s IL_0009 IL_0007: ldc.i4.0 IL_0008: stloc.0 IL_0009: ldloc.0 IL_000a: ret } "); comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular15); CompileAndVerify(comp, expectedOutput: "TrueFalseTrueTrue").VerifyDiagnostics(); comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular14); CompileAndVerify(comp, expectedOutput: "TrueFalseTrueTrue").VerifyDiagnostics(); } [Fact] public void DeclarationPattern_02_UnionInstance_Only() { var src = @" [System.Runtime.CompilerServices.Union] class C1 { private readonly object _value; public C1(int x) { _value = x; } public C1(string x) { _value = x; } public object Value => _value; } class C2(string x) : C1(x); class Program { static void Main() { System.Console.Write(Test1(new C1(10))); System.Console.Write(Test1(null)); System.Console.Write(Test1(new C1(""a""))); System.Console.Write(Test1(new C1(null))); System.Console.Write(Test1(new C2(""a""))); System.Console.Write(Test1(new C2(null))); } static bool Test1(C1 u) { return u switch { C2 x => true, _ => false }; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); var verifier = CompileAndVerify(comp, expectedOutput: "FalseFalseFalseFalseTrueTrue").VerifyDiagnostics(); verifier.VerifyIL("Program.Test1", @" { // Code size 16 (0x10) .maxstack 1 .locals init (bool V_0) IL_0000: ldarg.0 IL_0001: isinst ""C2"" IL_0006: brfalse.s IL_000c IL_0008: ldc.i4.1 IL_0009: stloc.0 IL_000a: br.s IL_000e IL_000c: ldc.i4.0 IL_000d: stloc.0 IL_000e: ldloc.0 IL_000f: ret } "); comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular15); CompileAndVerify(comp, expectedOutput: "FalseFalseFalseFalseTrueTrue").VerifyDiagnostics(); comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular14); CompileAndVerify(comp, expectedOutput: "FalseFalseFalseFalseTrueTrue").VerifyDiagnostics(); } [Fact] public void DeclarationPattern_03_UnionInstance_And_Value() { var src = @" [System.Runtime.CompilerServices.Union] class C1 { protected readonly object _value; public C1(int x) { _value = x; } public C1(C2 x) { _value = x; } protected C1(object x) { _value = x; } public object Value => _value; } class C2(object x) : I1 { public object Value1 => x; } class C3(object x) : C1(x), I1 { object I1.Value1 => _value; } interface I1 { object Value1 { get; } } class Program { static void Main() { System.Console.Write(Test1(new C1(10))); System.Console.Write(Test1(new C1(new C2(11)))); System.Console.Write(Test1(new C1(null))); System.Console.Write(Test1(null)); System.Console.Write(Test1(new C3(10))); System.Console.Write(Test1(new C3(new C2(11)))); System.Console.Write(Test1(new C3(null))); } static bool Test1(C1 u) { return u switch { I1 x => true, _ => false }; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); VerifyDecisionDagDump<SwitchExpressionSyntax>(comp, @"[0]: t0 is I1 ? [1] : [2] [1]: t1 = (I1)t0; [7] [2]: t0 != null ? [3] : [9] [3]: t2 = t0.Value; [4] [4]: t2 != null ? [5] : [9] [5]: t2 is I1 ? [6] : [9] [6]: t3 = (I1)t2; [7] [7]: when <true> ? [8] : <unreachable> [8]: leaf <arm> `I1 x => true` [9]: leaf <arm> `_ => false` ", forLowering: false); comp.VerifyDiagnostics( // (42,30): error CS8780: A variable may not be declared within a 'not' or an 'or' pattern or a union matching involving matching against either the instance, or its underlying value. // return u switch { I1 x => true, _ => false }; Diagnostic(ErrorCode.ERR_DesignatorBeneathPatternCombinator, "x").WithLocation(42, 30) ); comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular15); comp.VerifyDiagnostics( // (42,30): error CS8780: A variable may not be declared within a 'not' or an 'or' pattern or a union matching involving matching against either the instance, or its underlying value. // return u switch { I1 x => true, _ => false }; Diagnostic(ErrorCode.ERR_DesignatorBeneathPatternCombinator, "x").WithLocation(42, 30) ); comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular14); comp.VerifyDiagnostics( // (42,27): error CS9327: Feature 'unions' is not available in C# 14.0. Please use language version 15.0 or greater. // return u switch { I1 x => true, _ => false }; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion14, "I1 x").WithArguments("unions", "15.0").WithLocation(42, 27), // (42,30): error CS8780: A variable may not be declared within a 'not' or an 'or' pattern or a union matching involving matching against either the instance, or its underlying value. // return u switch { I1 x => true, _ => false }; Diagnostic(ErrorCode.ERR_DesignatorBeneathPatternCombinator, "x").WithLocation(42, 30) ); } [Fact] public void PropertyPattern_01_UnionInstance_Only() { var src = @" [System.Runtime.CompilerServices.Union] class C1 { private readonly object _value; public C1(int x) { _value = x; } public C1(string x) { _value = x; } public object Value => _value; } class Program { static void Main() { System.Console.Write(Test1(new C1(10))); System.Console.Write(Test1(new C1(""11""))); System.Console.Write(Test1(new C1(null))); System.Console.Write(Test1(null)); } static bool Test1(C1 u) { return u switch { {} => true, _ => false }; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); var verifier = CompileAndVerify(comp, expectedOutput: "TrueTrueTrueFalse").VerifyDiagnostics(); verifier.VerifyIL("Program.Test1", @" { // Code size 11 (0xb) .maxstack 1 .locals init (bool V_0) IL_0000: ldarg.0 IL_0001: brfalse.s IL_0007 IL_0003: ldc.i4.1 IL_0004: stloc.0 IL_0005: br.s IL_0009 IL_0007: ldc.i4.0 IL_0008: stloc.0 IL_0009: ldloc.0 IL_000a: ret } "); comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular15); CompileAndVerify(comp, expectedOutput: "TrueTrueTrueFalse").VerifyDiagnostics(); comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular14); CompileAndVerify(comp, expectedOutput: "TrueTrueTrueFalse").VerifyDiagnostics(); } [Fact] public void PropertyPattern_02_UnionInstance_Only() { var src = @" class C0; [System.Runtime.CompilerServices.Union] class C1 : C0 { private readonly object _value; public C1(int x) { _value = x; } public C1(C0 x) { _value = x; } public object Value => _value; } class Program { static void Main() { System.Console.Write(Test1(new C1(10))); System.Console.Write(Test1(null)); System.Console.Write(Test1(new C1(new C1(1)))); System.Console.Write(Test1(new C1(new C0()))); } static bool Test1(C1 u) { return u switch { C0 {} => true, _ => false }; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); var verifier = CompileAndVerify(comp, expectedOutput: "TrueFalseTrueTrue").VerifyDiagnostics(); verifier.VerifyIL("Program.Test1", @" { // Code size 11 (0xb) .maxstack 1 .locals init (bool V_0) IL_0000: ldarg.0 IL_0001: brfalse.s IL_0007 IL_0003: ldc.i4.1 IL_0004: stloc.0 IL_0005: br.s IL_0009 IL_0007: ldc.i4.0 IL_0008: stloc.0 IL_0009: ldloc.0 IL_000a: ret } "); comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular15); CompileAndVerify(comp, expectedOutput: "TrueFalseTrueTrue").VerifyDiagnostics(); comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular14); CompileAndVerify(comp, expectedOutput: "TrueFalseTrueTrue").VerifyDiagnostics(); } [Fact] public void PropertyPattern_03_UnionInstance_Only() { var src = @" [System.Runtime.CompilerServices.Union] class C1 { private readonly object _value; public C1(int x) { _value = x; } public C1(string x) { _value = x; } public object Value => _value; } class C2(string x) : C1(x); class Program { static void Main() { System.Console.Write(Test1(new C1(10))); System.Console.Write(Test1(null)); System.Console.Write(Test1(new C1(""a""))); System.Console.Write(Test1(new C1(null))); System.Console.Write(Test1(new C2(""a""))); System.Console.Write(Test1(new C2(null))); } static bool Test1(C1 u) { return u switch { C2 {} => true, _ => false }; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); var verifier = CompileAndVerify(comp, expectedOutput: "FalseFalseFalseFalseTrueTrue").VerifyDiagnostics(); verifier.VerifyIL("Program.Test1", @" { // Code size 16 (0x10) .maxstack 1 .locals init (bool V_0) IL_0000: ldarg.0 IL_0001: isinst ""C2"" IL_0006: brfalse.s IL_000c IL_0008: ldc.i4.1 IL_0009: stloc.0 IL_000a: br.s IL_000e IL_000c: ldc.i4.0 IL_000d: stloc.0 IL_000e: ldloc.0 IL_000f: ret } "); comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular15); CompileAndVerify(comp, expectedOutput: "FalseFalseFalseFalseTrueTrue").VerifyDiagnostics(); comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular14); CompileAndVerify(comp, expectedOutput: "FalseFalseFalseFalseTrueTrue").VerifyDiagnostics(); } [Fact] public void PropertyPattern_04_UnionInstance_And_Value() { var src = @" [System.Runtime.CompilerServices.Union] class C1 { protected readonly object _value; public C1(int x) { _value = x; } public C1(C2 x) { _value = x; } protected C1(object x) { _value = x; } public object Value => _value; } class C2(object x) : I1 { public object Value1 => x; } class C3(object x) : C1(x), I1 { object I1.Value1 => _value; } interface I1 { object Value1 { get; } } class Program { static void Main() { System.Console.Write(Test1(new C1(10))); System.Console.Write(Test1(new C1(new C2(11)))); System.Console.Write(Test1(new C1(null))); System.Console.Write(Test1(null)); System.Console.Write(Test1(new C3(10))); System.Console.Write(Test1(new C3(new C2(11)))); System.Console.Write(Test1(new C3(null))); } static bool Test1(C1 u) { return u switch { I1 {} => true, _ => false }; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); VerifyDecisionDagDump<SwitchExpressionSyntax>(comp, @"[0]: t0 is I1 ? [4] : [1] [1]: t0 != null ? [2] : [5] [2]: t1 = t0.Value; [3] [3]: t1 is I1 ? [4] : [5] [4]: leaf <arm> `I1 {} => true` [5]: leaf <arm> `_ => false` ", forLowering: true); var verifier = CompileAndVerify(comp, expectedOutput: "FalseTrueFalseFalseTrueTrueTrue").VerifyDiagnostics(); comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular15); CompileAndVerify(comp, expectedOutput: "FalseTrueFalseFalseTrueTrueTrue").VerifyDiagnostics(); comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular14); comp.VerifyDiagnostics( // (42,27): error CS9327: Feature 'unions' is not available in C# 14.0. Please use language version 15.0 or greater. // return u switch { I1 {} => true, _ => false }; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion14, "I1 {}").WithArguments("unions", "15.0").WithLocation(42, 27) ); } [Fact] public void PropertyPattern_05_UnionInstance_And_Value() { var src = @" [System.Runtime.CompilerServices.Union] class C1 { protected readonly object _value; public C1(int x) { _value = x; } public C1(C2 x) { _value = x; } protected C1(object x) { _value = x; } public object Value => _value; } class C2(object x) : I1 { public object Value1 => x; } class C3(object x) : C1(x), I1 { object I1.Value1 => _value; } interface I1 { object Value1 { get; } } class Program { static void Main() { System.Console.Write(Test1(new C1(10))); System.Console.Write(Test1(new C1(11))); System.Console.Write(Test1(new C1(new C2(10)))); System.Console.Write(Test1(new C1(new C2(11)))); System.Console.Write(Test1(new C1(new C2(null)))); System.Console.Write(Test1(new C1(null))); System.Console.Write(Test1(null)); System.Console.Write(Test1(new C3(10))); System.Console.Write(Test1(new C3(11))); System.Console.Write(Test1(new C3(new C2(10)))); System.Console.Write(Test1(new C3(new C2(11)))); System.Console.Write(Test1(new C3(new C2(null)))); System.Console.Write(Test1(new C3(null))); } static bool Test1(C1 u) { return u switch { I1 { Value1: 10 } => true, _ => false }; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); VerifyDecisionDagDump<SwitchExpressionSyntax>(comp, @"[0]: t0 is I1 ? [1] : [6] [1]: t1 = (I1)t0; [2] [2]: t2 = t1.Value1; [3] [3]: t2 is int ? [4] : [15] [4]: t3 = (int)t2; [5] [5]: t3 == 10 ? [14] : [15] [6]: t0 != null ? [7] : [15] [7]: t4 = t0.Value; [8] [8]: t4 is I1 ? [9] : [15] [9]: t5 = (I1)t4; [10] [10]: t6 = t5.Value1; [11] [11]: t6 is int ? [12] : [15] [12]: t7 = (int)t6; [13] [13]: t7 == 10 ? [14] : [15] [14]: leaf <arm> `I1 { Value1: 10 } => true` [15]: leaf <arm> `_ => false` ", forLowering: true); CompileAndVerify(comp, expectedOutput: "FalseFalseTrueFalseFalseFalseFalseTrueFalseFalseFalseFalseFalse").VerifyDiagnostics(); } [Fact] public void PropertyPattern_06_UnionInstance_And_Value_Plus_Conjunction() { var src = @" [System.Runtime.CompilerServices.Union] class C1 { protected readonly object _value; public C1(int x) { _value = x; } public C1(C4 x) { _value = x; } public C1(C5 x) { _value = x; } protected C1(object x) { _value = x; } public object Value => _value; } interface I2 { object Value2 { get; } } [System.Runtime.CompilerServices.Union] class C4 : C1 { public C4(int x) : base(x) {} public C4(C5 x) : base(x) {} protected C4(object x) : base(x) {} } class C5(object x) : I2 { public object Value2 => x; } class C6(object x) : C4(x), I2 { object I2.Value2 => _value; } class Program { static bool Test1(C1 u) { return u switch { C4 { } and I2 and { Value2: 11 } => true, _ => false }; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseDll); VerifyDecisionDagDump<SwitchExpressionSyntax>(comp, @"[0]: t0 is C4 ? [1] : [15] [1]: t1 = (C4)t0; [2] [2]: t1 is I2 ? [3] : [8] [3]: t2 = (I2)t1; [4] [4]: t3 = t2.Value2; [5] [5]: t3 is int ? [6] : [33] [6]: t4 = (int)t3; [7] [7]: t4 == 11 ? [32] : [33] [8]: t5 = t1.Value; [9] [9]: t5 is I2 ? [10] : [33] [10]: t6 = (I2)t5; [11] [11]: t7 = t6.Value2; [12] [12]: t7 is int ? [13] : [33] [13]: t8 = (int)t7; [14] [14]: t8 == 11 ? [32] : [33] [15]: t0 != null ? [16] : [33] [16]: t9 = t0.Value; [17] [17]: t9 is C4 ? [18] : [33] [18]: t10 = (C4)t9; [19] [19]: t10 is I2 ? [20] : [25] [20]: t11 = (I2)t10; [21] [21]: t12 = t11.Value2; [22] [22]: t12 is int ? [23] : [33] [23]: t13 = (int)t12; [24] [24]: t13 == 11 ? [32] : [33] [25]: t14 = t10.Value; [26] [26]: t14 is I2 ? [27] : [33] [27]: t15 = (I2)t14; [28] [28]: t16 = t15.Value2; [29] [29]: t16 is int ? [30] : [33] [30]: t17 = (int)t16; [31] [31]: t17 == 11 ? [32] : [33] [32]: leaf <arm> `C4 { } and I2 and { Value2: 11 } => true` [33]: leaf <arm> `_ => false` ", forLowering: true); CompileAndVerify(comp).VerifyDiagnostics(); } [Fact] public void PropertyPattern_07_UnionInstance_And_Value_Plus_Conjunction() { var src = @" [System.Runtime.CompilerServices.Union] class C1 { protected readonly object _value; public C1(int x) { _value = x; } public C1(C2 x) { _value = x; } public C1(C4 x) { _value = x; } public C1(C5 x) { _value = x; } protected C1(object x) { _value = x; } public object Value => _value; } class C2(object x) : I1 { public object Value1 => x; } class C3(object x) : C1(x), I1 { object I1.Value1 => _value; } interface I1 { object Value1 { get; } } interface I2 { object Value2 { get; } } [System.Runtime.CompilerServices.Union] class C4 : C1 { public C4(int x) : base(x) {} public C4(C5 x) : base(x) {} protected C4(object x) : base(x) {} } class C5(object x) : I2 { public object Value2 => x; } class C6(object x) : C4(x), I2 { object I2.Value2 => _value; } class C7(object x) : C6(x), I1 { object I1.Value1 => _value; } class Program { static bool Test1(C1 u) { return u switch { I1 { Value1: 10 } and C4 and I2 and { Value2: 11 } => true, _ => false }; } static bool Test2(C1 u) { return u switch { I1 {} and { Value1: 10 } and C4 and I2 and { Value2: 11 } => true, _ => false }; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseDll); VerifyDecisionDagDump<SwitchExpressionSyntax>(comp, @"[0]: t0 is I1 ? [1] : [21] [1]: t1 = (I1)t0; [2] [2]: t2 = t1.Value1; [3] [3]: t2 is int ? [4] : [45] [4]: t3 = (int)t2; [5] [5]: t3 == 10 ? [6] : [45] [6]: t1 is C4 ? [7] : [45] [7]: t4 = (C4)t1; [8] [8]: t4 is I2 ? [9] : [14] [9]: t5 = (I2)t4; [10] [10]: t6 = t5.Value2; [11] [11]: t6 is int ? [12] : [45] [12]: t7 = (int)t6; [13] [13]: t7 == 11 ? [44] : [45] [14]: t8 = t4.Value; [15] [15]: t8 is I2 ? [16] : [45] [16]: t9 = (I2)t8; [17] [17]: t10 = t9.Value2; [18] [18]: t10 is int ? [19] : [45] [19]: t11 = (int)t10; [20] [20]: t11 == 11 ? [44] : [45] [21]: t0 != null ? [22] : [45] [22]: t12 = t0.Value; [23] [23]: t12 is I1 ? [24] : [45] [24]: t13 = (I1)t12; [25] [25]: t14 = t13.Value1; [26] [26]: t14 is int ? [27] : [45] [27]: t15 = (int)t14; [28] [28]: t15 == 10 ? [29] : [45] [29]: t13 is C4 ? [30] : [45] [30]: t16 = (C4)t13; [31] [31]: t16 is I2 ? [32] : [37] [32]: t17 = (I2)t16; [33] [33]: t18 = t17.Value2; [34] [34]: t18 is int ? [35] : [45] [35]: t19 = (int)t18; [36] [36]: t19 == 11 ? [44] : [45] [37]: t20 = t16.Value; [38] [38]: t20 is I2 ? [39] : [45] [39]: t21 = (I2)t20; [40] [40]: t22 = t21.Value2; [41] [41]: t22 is int ? [42] : [45] [42]: t23 = (int)t22; [43] [43]: t23 == 11 ? [44] : [45] [44]: leaf <arm> `I1 { Value1: 10 } and C4 and I2 and { Value2: 11 } => true` [45]: leaf <arm> `_ => false` ", forLowering: true); VerifyDecisionDagDump<SwitchExpressionSyntax>(comp, @"[0]: t0 is I1 ? [1] : [21] [1]: t1 = (I1)t0; [2] [2]: t2 = t1.Value1; [3] [3]: t2 is int ? [4] : [45] [4]: t3 = (int)t2; [5] [5]: t3 == 10 ? [6] : [45] [6]: t1 is C4 ? [7] : [45] [7]: t4 = (C4)t1; [8] [8]: t4 is I2 ? [9] : [14] [9]: t5 = (I2)t4; [10] [10]: t6 = t5.Value2; [11] [11]: t6 is int ? [12] : [45] [12]: t7 = (int)t6; [13] [13]: t7 == 11 ? [44] : [45] [14]: t8 = t4.Value; [15] [15]: t8 is I2 ? [16] : [45] [16]: t9 = (I2)t8; [17] [17]: t10 = t9.Value2; [18] [18]: t10 is int ? [19] : [45] [19]: t11 = (int)t10; [20] [20]: t11 == 11 ? [44] : [45] [21]: t0 != null ? [22] : [45] [22]: t12 = t0.Value; [23] [23]: t12 is I1 ? [24] : [45] [24]: t13 = (I1)t12; [25] [25]: t14 = t13.Value1; [26] [26]: t14 is int ? [27] : [45] [27]: t15 = (int)t14; [28] [28]: t15 == 10 ? [29] : [45] [29]: t13 is C4 ? [30] : [45] [30]: t16 = (C4)t13; [31] [31]: t16 is I2 ? [32] : [37] [32]: t17 = (I2)t16; [33] [33]: t18 = t17.Value2; [34] [34]: t18 is int ? [35] : [45] [35]: t19 = (int)t18; [36] [36]: t19 == 11 ? [44] : [45] [37]: t20 = t16.Value; [38] [38]: t20 is I2 ? [39] : [45] [39]: t21 = (I2)t20; [40] [40]: t22 = t21.Value2; [41] [41]: t22 is int ? [42] : [45] [42]: t23 = (int)t22; [43] [43]: t23 == 11 ? [44] : [45] [44]: leaf <arm> `I1 {} and { Value1: 10 } and C4 and I2 and { Value2: 11 } => true` [45]: leaf <arm> `_ => false` ", index: 1, forLowering: true); CompileAndVerify(comp).VerifyDiagnostics(); } [Fact] public void PropertyPattern_08_UnionInstance_And_Value_Plus_Designation() { var src = @" [System.Runtime.CompilerServices.Union] class C1 { protected readonly object _value; public C1(int x) { _value = x; } public C1(C2 x) { _value = x; } protected C1(object x) { _value = x; } public object Value => _value; } class C2(object x) : I1 { public object Value1 => x; } class C3(object x) : C1(x), I1 { object I1.Value1 => _value; } interface I1 { object Value1 { get; } } class Program { static void Main() { System.Console.Write(Test1(new C1(10))); System.Console.Write(Test1(new C1(new C2(11)))); System.Console.Write(Test1(new C1(null))); System.Console.Write(Test1(null)); System.Console.Write(Test1(new C3(10))); System.Console.Write(Test1(new C3(new C2(11)))); System.Console.Write(Test1(new C3(null))); } static bool Test1(C1 u) { return u switch { I1 {} i1 => true, _ => false }; } static bool Test2(C1 u) { return u switch { I1 { Value1: var v1 } => true, _ => false }; } static bool Test3(C1 u) { return u switch { I1 {} and var i1 => true, _ => false }; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); comp.VerifyDiagnostics( // (42,33): error CS8780: A variable may not be declared within a 'not' or an 'or' pattern or a union matching involving matching against either the instance, or its underlying value. // return u switch { I1 {} i1 => true, _ => false }; Diagnostic(ErrorCode.ERR_DesignatorBeneathPatternCombinator, "i1").WithLocation(42, 33), // (47,44): error CS8780: A variable may not be declared within a 'not' or an 'or' pattern or a union matching involving matching against either the instance, or its underlying value. // return u switch { I1 { Value1: var v1 } => true, _ => false }; Diagnostic(ErrorCode.ERR_DesignatorBeneathPatternCombinator, "v1").WithLocation(47, 44), // (52,41): error CS8780: A variable may not be declared within a 'not' or an 'or' pattern or a union matching involving matching against either the instance, or its underlying value. // return u switch { I1 {} and var i1 => true, _ => false }; Diagnostic(ErrorCode.ERR_DesignatorBeneathPatternCombinator, "i1").WithLocation(52, 41) ); } [Fact] public void PositionalPattern_01_UnionInstance_Only() { var src = @" [System.Runtime.CompilerServices.Union] class C1 { private readonly object _value; public C1(int x) { _value = x; } public C1(string x) { _value = x; } public object Value => _value; public void Deconstruct(out object x, out object y) { x = 1; y = 2; } } class Program { static void Main() { System.Console.Write(Test1(new C1(10))); System.Console.Write(Test1(new C1(""11""))); System.Console.Write(Test1(new C1(null))); System.Console.Write(Test1(null)); } static bool Test1(C1 u) { return u switch { (_, _) => true, _ => false }; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); var verifier = CompileAndVerify(comp, expectedOutput: "TrueTrueTrueFalse").VerifyDiagnostics(); verifier.VerifyIL("Program.Test1", @" { // Code size 11 (0xb) .maxstack 1 .locals init (bool V_0) IL_0000: ldarg.0 IL_0001: brfalse.s IL_0007 IL_0003: ldc.i4.1 IL_0004: stloc.0 IL_0005: br.s IL_0009 IL_0007: ldc.i4.0 IL_0008: stloc.0 IL_0009: ldloc.0 IL_000a: ret } "); comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular15); CompileAndVerify(comp, expectedOutput: "TrueTrueTrueFalse").VerifyDiagnostics(); comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular14); CompileAndVerify(comp, expectedOutput: "TrueTrueTrueFalse").VerifyDiagnostics(); } [Fact] public void PositionalPattern_02_UnionInstance_Only() { var src = @" class C0 { public void Deconstruct(out object x, out object y) { x = 1; y = 2; } } [System.Runtime.CompilerServices.Union] class C1 : C0 { private readonly object _value; public C1(int x) { _value = x; } public C1(C0 x) { _value = x; } public object Value => _value; } class Program { static void Main() { System.Console.Write(Test1(new C1(10))); System.Console.Write(Test1(null)); System.Console.Write(Test1(new C1(new C1(1)))); System.Console.Write(Test1(new C1(new C0()))); } static bool Test1(C1 u) { return u switch { C0 (_, _) => true, _ => false }; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); var verifier = CompileAndVerify(comp, expectedOutput: "TrueFalseTrueTrue").VerifyDiagnostics(); verifier.VerifyIL("Program.Test1", @" { // Code size 11 (0xb) .maxstack 1 .locals init (bool V_0) IL_0000: ldarg.0 IL_0001: brfalse.s IL_0007 IL_0003: ldc.i4.1 IL_0004: stloc.0 IL_0005: br.s IL_0009 IL_0007: ldc.i4.0 IL_0008: stloc.0 IL_0009: ldloc.0 IL_000a: ret } "); comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular15); CompileAndVerify(comp, expectedOutput: "TrueFalseTrueTrue").VerifyDiagnostics(); comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular14); CompileAndVerify(comp, expectedOutput: "TrueFalseTrueTrue").VerifyDiagnostics(); } [Fact] public void PositionalPattern_03_UnionInstance_Only() { var src = @" [System.Runtime.CompilerServices.Union] class C1 { private readonly object _value; public C1(int x) { _value = x; } public C1(string x) { _value = x; } public object Value => _value; } class C2(string x) : C1(x) { public void Deconstruct(out object x, out object y) { x = 1; y = 2; } } class Program { static void Main() { System.Console.Write(Test1(new C1(10))); System.Console.Write(Test1(null)); System.Console.Write(Test1(new C1(""a""))); System.Console.Write(Test1(new C1(null))); System.Console.Write(Test1(new C2(""a""))); System.Console.Write(Test1(new C2(null))); } static bool Test1(C1 u) { return u switch { C2 (_, _) => true, _ => false }; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); var verifier = CompileAndVerify(comp, expectedOutput: "FalseFalseFalseFalseTrueTrue").VerifyDiagnostics(); verifier.VerifyIL("Program.Test1", @" { // Code size 16 (0x10) .maxstack 1 .locals init (bool V_0) IL_0000: ldarg.0 IL_0001: isinst ""C2"" IL_0006: brfalse.s IL_000c IL_0008: ldc.i4.1 IL_0009: stloc.0 IL_000a: br.s IL_000e IL_000c: ldc.i4.0 IL_000d: stloc.0 IL_000e: ldloc.0 IL_000f: ret } "); comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular15); CompileAndVerify(comp, expectedOutput: "FalseFalseFalseFalseTrueTrue").VerifyDiagnostics(); comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular14); CompileAndVerify(comp, expectedOutput: "FalseFalseFalseFalseTrueTrue").VerifyDiagnostics(); } [Fact] public void PositionalPattern_04_UnionInstance_And_Value() { var src = @" [System.Runtime.CompilerServices.Union] class C1 { protected readonly object _value; public C1(int x) { _value = x; } public C1(C2 x) { _value = x; } protected C1(object x) { _value = x; } public object Value => _value; } class C2(object x) : I1 { public object Value1 => x; void I1.Deconstruct(out object x, out object y) => throw null; } class C3(object x) : C1(x), I1 { void I1.Deconstruct(out object x, out object y) => throw null; } interface I1 { public void Deconstruct(out object x, out object y); } class Program { static void Main() { System.Console.Write(Test1(new C1(10))); System.Console.Write(Test1(new C1(new C2(11)))); System.Console.Write(Test1(new C1(null))); System.Console.Write(Test1(null)); System.Console.Write(Test1(new C3(10))); System.Console.Write(Test1(new C3(new C2(11)))); System.Console.Write(Test1(new C3(null))); } static bool Test1(C1 u) { return u switch { I1 (_, _) => true, _ => false }; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); VerifyDecisionDagDump<SwitchExpressionSyntax>(comp, @"[0]: t0 is I1 ? [4] : [1] [1]: t0 != null ? [2] : [5] [2]: t1 = t0.Value; [3] [3]: t1 is I1 ? [4] : [5] [4]: leaf <arm> `I1 (_, _) => true` [5]: leaf <arm> `_ => false` ", forLowering: true); var verifier = CompileAndVerify(comp, expectedOutput: "FalseTrueFalseFalseTrueTrueTrue").VerifyDiagnostics(); comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular15); CompileAndVerify(comp, expectedOutput: "FalseTrueFalseFalseTrueTrueTrue").VerifyDiagnostics(); comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular14); comp.VerifyDiagnostics( // (43,27): error CS9327: Feature 'unions' is not available in C# 14.0. Please use language version 15.0 or greater. // return u switch { I1 (_, _) => true, _ => false }; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion14, "I1 (_, _)").WithArguments("unions", "15.0").WithLocation(43, 27) ); } [Fact] public void PositionalPattern_05_UnionInstance_And_Value() { var src = @" [System.Runtime.CompilerServices.Union] class C1 { protected readonly object _value; public C1(int x) { _value = x; } public C1(C2 x) { _value = x; } protected C1(object x) { _value = x; } public object Value => _value; } class C2(object x) : I1 { void I1.Deconstruct(out object x1, out object y1) { x1 = x; y1 = 2; } } class C3(object x) : C1(x), I1 { void I1.Deconstruct(out object x, out object y) { x = _value; y = 2; } } interface I1 { public void Deconstruct(out object x, out object y); } class Program { static void Main() { System.Console.Write(Test1(new C1(10))); System.Console.Write(Test1(new C1(11))); System.Console.Write(Test1(new C1(new C2(10)))); System.Console.Write(Test1(new C1(new C2(11)))); System.Console.Write(Test1(new C1(new C2(null)))); System.Console.Write(Test1(new C1(null))); System.Console.Write(Test1(null)); System.Console.Write(Test1(new C3(10))); System.Console.Write(Test1(new C3(11))); System.Console.Write(Test1(new C3(new C2(10)))); System.Console.Write(Test1(new C3(new C2(11)))); System.Console.Write(Test1(new C3(new C2(null)))); System.Console.Write(Test1(new C3(null))); } static bool Test1(C1 u) { return u switch { I1 (10, _) => true, _ => false }; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); VerifyDecisionDagDump<SwitchExpressionSyntax>(comp, @"[0]: t0 is I1 ? [1] : [6] [1]: t1 = (I1)t0; [2] [2]: (Item1, Item2) t2 = t1; [3] [3]: t2.Item1 is int ? [4] : [15] [4]: t3 = (int)t2.Item1; [5] [5]: t3 == 10 ? [14] : [15] [6]: t0 != null ? [7] : [15] [7]: t4 = t0.Value; [8] [8]: t4 is I1 ? [9] : [15] [9]: t5 = (I1)t4; [10] [10]: (Item1, Item2) t6 = t5; [11] [11]: t6.Item1 is int ? [12] : [15] [12]: t7 = (int)t6.Item1; [13] [13]: t7 == 10 ? [14] : [15] [14]: leaf <arm> `I1 (10, _) => true` [15]: leaf <arm> `_ => false` ", forLowering: true); CompileAndVerify(comp, expectedOutput: "FalseFalseTrueFalseFalseFalseFalseTrueFalseFalseFalseFalseFalse").VerifyDiagnostics(); } [Fact] public void PositionalPattern_06_UnionInstance_And_Value_Plus_Conjunction() { var src = @" [System.Runtime.CompilerServices.Union] class C1 { protected readonly object _value; public C1(int x) { _value = x; } public C1(C4 x) { _value = x; } public C1(C5 x) { _value = x; } protected C1(object x) { _value = x; } public object Value => _value; } interface I2 { public void Deconstruct(out object x1, out object y1); } [System.Runtime.CompilerServices.Union] class C4 : C1 { public C4(int x) : base(x) {} public C4(C5 x) : base(x) {} protected C4(object x) : base(x) {} public void Deconstruct(out object x1, out object y1) => throw null; } class C5(object x) : I2 { public object Value2 => x; void I2.Deconstruct(out object x1, out object y1) => throw null; } class C6(object x) : C4(x), I2 { void I2.Deconstruct(out object x1, out object y1) => throw null; } class Program { static bool Test1(C1 u) { return u switch { C4 (_, _) and I2 and (11, _) => true, _ => false }; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseDll); VerifyDecisionDagDump<SwitchExpressionSyntax>(comp, @"[0]: t0 is C4 ? [1] : [15] [1]: t1 = (C4)t0; [2] [2]: t1 is I2 ? [3] : [8] [3]: t2 = (I2)t1; [4] [4]: (Item1, Item2) t3 = t2; [5] [5]: t3.Item1 is int ? [6] : [33] [6]: t4 = (int)t3.Item1; [7] [7]: t4 == 11 ? [32] : [33] [8]: t5 = t1.Value; [9] [9]: t5 is I2 ? [10] : [33] [10]: t6 = (I2)t5; [11] [11]: (Item1, Item2) t7 = t6; [12] [12]: t7.Item1 is int ? [13] : [33] [13]: t8 = (int)t7.Item1; [14] [14]: t8 == 11 ? [32] : [33] [15]: t0 != null ? [16] : [33] [16]: t9 = t0.Value; [17] [17]: t9 is C4 ? [18] : [33] [18]: t10 = (C4)t9; [19] [19]: t10 is I2 ? [20] : [25] [20]: t11 = (I2)t10; [21] [21]: (Item1, Item2) t12 = t11; [22] [22]: t12.Item1 is int ? [23] : [33] [23]: t13 = (int)t12.Item1; [24] [24]: t13 == 11 ? [32] : [33] [25]: t14 = t10.Value; [26] [26]: t14 is I2 ? [27] : [33] [27]: t15 = (I2)t14; [28] [28]: (Item1, Item2) t16 = t15; [29] [29]: t16.Item1 is int ? [30] : [33] [30]: t17 = (int)t16.Item1; [31] [31]: t17 == 11 ? [32] : [33] [32]: leaf <arm> `C4 (_, _) and I2 and (11, _) => true` [33]: leaf <arm> `_ => false` ", forLowering: true); CompileAndVerify(comp).VerifyDiagnostics(); } [Fact] public void PositionalPattern_07_UnionInstance_And_Value_Plus_Conjunction() { var src = @" [System.Runtime.CompilerServices.Union] class C1 { protected readonly object _value; public C1(int x) { _value = x; } public C1(C2 x) { _value = x; } public C1(C4 x) { _value = x; } public C1(C5 x) { _value = x; } protected C1(object x) { _value = x; } public object Value => _value; } class C2(object x) : I1 { public object Value1 => x; void I1.Deconstruct(out object x1, out object y1) => throw null; } class C3(object x) : C1(x), I1 { void I1.Deconstruct(out object x1, out object y1) => throw null; } interface I1 { public void Deconstruct(out object x1, out object y1); } interface I2 { public void Deconstruct(out object x1, out object y1); } [System.Runtime.CompilerServices.Union] class C4 : C1 { public C4(int x) : base(x) {} public C4(C5 x) : base(x) {} protected C4(object x) : base(x) {} } class C5(object x) : I2 { public object Value2 => x; void I2.Deconstruct(out object x1, out object y1) => throw null; } class C6(object x) : C4(x), I2 { void I2.Deconstruct(out object x1, out object y1) => throw null; } class C7(object x) : C6(x), I1 { void I1.Deconstruct(out object x1, out object y1) => throw null; } class Program { static bool Test1(C1 u) { return u switch { I1 (10, _) and C4 and I2 and (_, 11) => true, _ => false }; } static bool Test2(C1 u) { return u switch { I1 (_, _) and (10, _) and C4 and I2 and (_, 11) => true, _ => false }; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseDll); VerifyDecisionDagDump<SwitchExpressionSyntax>(comp, @"[0]: t0 is I1 ? [1] : [21] [1]: t1 = (I1)t0; [2] [2]: (Item1, Item2) t2 = t1; [3] [3]: t2.Item1 is int ? [4] : [45] [4]: t3 = (int)t2.Item1; [5] [5]: t3 == 10 ? [6] : [45] [6]: t1 is C4 ? [7] : [45] [7]: t4 = (C4)t1; [8] [8]: t4 is I2 ? [9] : [14] [9]: t5 = (I2)t4; [10] [10]: (Item1, Item2) t6 = t5; [11] [11]: t6.Item2 is int ? [12] : [45] [12]: t7 = (int)t6.Item2; [13] [13]: t7 == 11 ? [44] : [45] [14]: t8 = t4.Value; [15] [15]: t8 is I2 ? [16] : [45] [16]: t9 = (I2)t8; [17] [17]: (Item1, Item2) t10 = t9; [18] [18]: t10.Item2 is int ? [19] : [45] [19]: t11 = (int)t10.Item2; [20] [20]: t11 == 11 ? [44] : [45] [21]: t0 != null ? [22] : [45] [22]: t12 = t0.Value; [23] [23]: t12 is I1 ? [24] : [45] [24]: t13 = (I1)t12; [25] [25]: (Item1, Item2) t14 = t13; [26] [26]: t14.Item1 is int ? [27] : [45] [27]: t15 = (int)t14.Item1; [28] [28]: t15 == 10 ? [29] : [45] [29]: t13 is C4 ? [30] : [45] [30]: t16 = (C4)t13; [31] [31]: t16 is I2 ? [32] : [37] [32]: t17 = (I2)t16; [33] [33]: (Item1, Item2) t18 = t17; [34] [34]: t18.Item2 is int ? [35] : [45] [35]: t19 = (int)t18.Item2; [36] [36]: t19 == 11 ? [44] : [45] [37]: t20 = t16.Value; [38] [38]: t20 is I2 ? [39] : [45] [39]: t21 = (I2)t20; [40] [40]: (Item1, Item2) t22 = t21; [41] [41]: t22.Item2 is int ? [42] : [45] [42]: t23 = (int)t22.Item2; [43] [43]: t23 == 11 ? [44] : [45] [44]: leaf <arm> `I1 (10, _) and C4 and I2 and (_, 11) => true` [45]: leaf <arm> `_ => false` ", forLowering: true); VerifyDecisionDagDump<SwitchExpressionSyntax>(comp, @"[0]: t0 is I1 ? [1] : [21] [1]: t1 = (I1)t0; [2] [2]: (Item1, Item2) t2 = t1; [3] [3]: t2.Item1 is int ? [4] : [45] [4]: t3 = (int)t2.Item1; [5] [5]: t3 == 10 ? [6] : [45] [6]: t1 is C4 ? [7] : [45] [7]: t4 = (C4)t1; [8] [8]: t4 is I2 ? [9] : [14] [9]: t5 = (I2)t4; [10] [10]: (Item1, Item2) t6 = t5; [11] [11]: t6.Item2 is int ? [12] : [45] [12]: t7 = (int)t6.Item2; [13] [13]: t7 == 11 ? [44] : [45] [14]: t8 = t4.Value; [15] [15]: t8 is I2 ? [16] : [45] [16]: t9 = (I2)t8; [17] [17]: (Item1, Item2) t10 = t9; [18] [18]: t10.Item2 is int ? [19] : [45] [19]: t11 = (int)t10.Item2; [20] [20]: t11 == 11 ? [44] : [45] [21]: t0 != null ? [22] : [45] [22]: t12 = t0.Value; [23] [23]: t12 is I1 ? [24] : [45] [24]: t13 = (I1)t12; [25] [25]: (Item1, Item2) t14 = t13; [26] [26]: t14.Item1 is int ? [27] : [45] [27]: t15 = (int)t14.Item1; [28] [28]: t15 == 10 ? [29] : [45] [29]: t13 is C4 ? [30] : [45] [30]: t16 = (C4)t13; [31] [31]: t16 is I2 ? [32] : [37] [32]: t17 = (I2)t16; [33] [33]: (Item1, Item2) t18 = t17; [34] [34]: t18.Item2 is int ? [35] : [45] [35]: t19 = (int)t18.Item2; [36] [36]: t19 == 11 ? [44] : [45] [37]: t20 = t16.Value; [38] [38]: t20 is I2 ? [39] : [45] [39]: t21 = (I2)t20; [40] [40]: (Item1, Item2) t22 = t21; [41] [41]: t22.Item2 is int ? [42] : [45] [42]: t23 = (int)t22.Item2; [43] [43]: t23 == 11 ? [44] : [45] [44]: leaf <arm> `I1 (_, _) and (10, _) and C4 and I2 and (_, 11) => true` [45]: leaf <arm> `_ => false` ", index: 1, forLowering: true); CompileAndVerify(comp).VerifyDiagnostics(); } [Fact] public void PositionalPattern_08_UnionInstance_And_Value_Plus_Designation() { var src = @" [System.Runtime.CompilerServices.Union] class C1 { protected readonly object _value; public C1(int x) { _value = x; } public C1(C2 x) { _value = x; } protected C1(object x) { _value = x; } public object Value => _value; } class C2(object x) : I1 { public object Value1 => x; void I1.Deconstruct(out object x, out object y) => throw null; } class C3(object x) : C1(x), I1 { void I1.Deconstruct(out object x, out object y) => throw null; } interface I1 { public void Deconstruct(out object x, out object y); } class Program { static void Main() { System.Console.Write(Test1(new C1(10))); System.Console.Write(Test1(new C1(new C2(11)))); System.Console.Write(Test1(new C1(null))); System.Console.Write(Test1(null)); System.Console.Write(Test1(new C3(10))); System.Console.Write(Test1(new C3(new C2(11)))); System.Console.Write(Test1(new C3(null))); } static bool Test1(C1 u) { return u switch { I1 (_, _) i1 => true, _ => false }; } static bool Test2(C1 u) { return u switch { I1 (var v1, _) => true, _ => false }; } static bool Test3(C1 u) { return u switch { I1 (_, _) and var i1 => true, _ => false }; } } "; var comp = CreateCompilation([src, UnionAttributeSource], options: TestOptions.ReleaseExe); comp.VerifyDiagnostics( // (43,37): error CS8780: A variable may not be declared within a 'not' or an 'or' pattern or a union matching involving matching against either the instance, or its underlying value. // return u switch { I1 (_, _) i1 => true, _ => false }; Diagnostic(ErrorCode.ERR_DesignatorBeneathPatternCombinator, "i1").WithLocation(43, 37), // (48,35): error CS8780: A variable may not be declared within a 'not' or an 'or' pattern or a union matching involving matching against either the instance, or its underlying value. // return u switch { I1 (var v1, _) => true, _ => false }; Diagnostic(ErrorCode.ERR_DesignatorBeneathPatternCombinator, "v1").WithLocation(48, 35), // (53,45): error CS8780: A variable may not be declared within a 'not' or an 'or' pattern or a union matching involving matching against either the instance, or its underlying value. // return u switch { I1 (_, _) and var i1 => true, _ => false }; Diagnostic(ErrorCode.ERR_DesignatorBeneathPatternCombinator, "i1").WithLocation(53, 45) ); } [Fact] [WorkItem("https://github.com/dotnet/roslyn/issues/84570")] public void AnalyzerActions_01() { var comp0 = CreateCompilation([UnionAttributeSource, IUnionSource]); var text1 = @" public union TestUnion(string, int) { private int _f; public void TestMethod(long x) { } } "; var analyzer = new AnalyzerActions_01_Analyzer(); var comp1 = CreateCompilation(text1, references: [comp0.ToMetadataReference()]); comp1.GetAnalyzerDiagnostics([analyzer], null).Verify(); Assert.Equal(1, analyzer.FireCount1); Assert.Equal(1, analyzer.FireCount2); Assert.Equal(1, analyzer.FireCount3); Assert.Equal(1, analyzer.FireCount4_1); Assert.Equal(1, analyzer.FireCount4_2); Assert.Equal(0, analyzer.FireCount4_3); Assert.Equal(1, analyzer.FireCount5_1); Assert.Equal(1, analyzer.FireCount5_2); Assert.Equal(1, analyzer.FireCount5_3); Assert.Equal(0, analyzer.FireCount5_4); Assert.Equal(1, analyzer.FireCount6); Assert.Equal(1, analyzer.FireCount7); Assert.Equal(1, analyzer.FireCount8); Assert.Equal(0, analyzer.FireCount9); Assert.Equal(1, analyzer.FireCount10); Assert.Equal(1, analyzer.FireCount11); Assert.Equal(1, analyzer.FireCount12); Assert.Equal(1, analyzer.FireCount13); Assert.Equal(1, analyzer.FireCount14); Assert.Equal(1, analyzer.FireCount15); Assert.Equal(0, analyzer.FireCount16); Assert.Equal(1, analyzer.FireCount17); Assert.Equal(1, analyzer.FireCount18); Assert.Equal(0, analyzer.FireCount19); Assert.Equal(1, analyzer.FireCount20); Assert.Equal(0, analyzer.FireCount21); Assert.Equal(1, analyzer.FireCount22); } private class AnalyzerActions_01_Analyzer : DiagnosticAnalyzer { public int FireCount1; public int FireCount2; public int FireCount3; public int FireCount4_1; public int FireCount4_2; public int FireCount4_3; public int FireCount5_1; public int FireCount5_2; public int FireCount5_3; public int FireCount5_4; public int FireCount6; public int FireCount7; public int FireCount8; public int FireCount9; public int FireCount10; public int FireCount11; public int FireCount12; public int FireCount13; public int FireCount14; public int FireCount15; public int FireCount16; public int FireCount17; public int FireCount18; public int FireCount19; public int FireCount20; public int FireCount21; public int FireCount22; private static readonly DiagnosticDescriptor Descriptor = new DiagnosticDescriptor("XY0000", "Test", "Test", "Test", DiagnosticSeverity.Warning, true, "Test", "Test"); public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics => ImmutableArray.Create(Descriptor); public override void Initialize(AnalysisContext context) { context.RegisterSyntaxNodeAction(Handle1, SyntaxKind.UnionDeclaration); context.RegisterSyntaxNodeAction(Handle2, SyntaxKind.FieldDeclaration); context.RegisterSyntaxNodeAction(Handle3, SyntaxKind.MethodDeclaration); context.RegisterSyntaxNodeAction(Handle4, SyntaxKind.ParameterList); context.RegisterSyntaxNodeAction(Handle5, SyntaxKind.Parameter); context.RegisterCodeBlockAction(Handle6); context.RegisterCodeBlockStartAction<SyntaxKind>(Handle7); context.RegisterOperationAction(Handle9, OperationKind.ConstructorBody); context.RegisterOperationBlockAction(Handle10); context.RegisterOperationBlockStartAction(Handle11); context.RegisterSymbolAction(Handle12, SymbolKind.NamedType); context.RegisterSymbolAction(Handle13, SymbolKind.Method); context.RegisterSymbolAction(Handle14, SymbolKind.Parameter); context.RegisterSymbolAction(Handle15, SymbolKind.Field); context.RegisterSymbolAction(Handle16, SymbolKind.Property); context.RegisterSymbolStartAction(Handle17, SymbolKind.NamedType); context.RegisterSymbolStartAction(Handle18, SymbolKind.Method); context.RegisterSymbolStartAction(Handle19, SymbolKind.Parameter); context.RegisterSymbolStartAction(Handle20, SymbolKind.Field); context.RegisterSymbolStartAction(Handle21, SymbolKind.Property); } protected void Handle1(SyntaxNodeAnalysisContext context) { Interlocked.Increment(ref FireCount1); Assert.IsType<UnionDeclarationSyntax>(context.Node); Assert.Equal("TestUnion", context.ContainingSymbol.ToTestDisplayString()); } protected void Handle2(SyntaxNodeAnalysisContext context) { Interlocked.Increment(ref FireCount2); Assert.IsType<FieldDeclarationSyntax>(context.Node); Assert.Equal("System.Int32 TestUnion._f", context.ContainingSymbol.ToTestDisplayString()); } protected void Handle3(SyntaxNodeAnalysisContext context) { Interlocked.Increment(ref FireCount3); Assert.IsType<MethodDeclarationSyntax>(context.Node); Assert.Equal("void TestUnion.TestMethod(System.Int64 x)", context.ContainingSymbol.ToTestDisplayString()); } protected void Handle4(SyntaxNodeAnalysisContext context) { switch (context.Node.Parent.Kind()) { case SyntaxKind.UnionDeclaration: Interlocked.Increment(ref FireCount4_1); Assert.Equal("TestUnion", context.ContainingSymbol.ToTestDisplayString()); break; case SyntaxKind.MethodDeclaration: Interlocked.Increment(ref FireCount4_2); Assert.Equal("void TestUnion.TestMethod(System.Int64 x)", context.ContainingSymbol.ToTestDisplayString()); break; default: Interlocked.Increment(ref FireCount4_3); break; } } protected void Handle5(SyntaxNodeAnalysisContext context) { switch (context.Node.ToString()) { case "string": Interlocked.Increment(ref FireCount5_1); Assert.Equal("TestUnion", context.ContainingSymbol.ToTestDisplayString()); break; case "int": Interlocked.Increment(ref FireCount5_2); Assert.Equal("TestUnion", context.ContainingSymbol.ToTestDisplayString()); break; case "long x": Interlocked.Increment(ref FireCount5_3); Assert.Equal("void TestUnion.TestMethod(System.Int64 x)", context.ContainingSymbol.ToTestDisplayString()); break; default: Interlocked.Increment(ref FireCount5_4); break; } } private void Handle6(CodeBlockAnalysisContext context) { Interlocked.Increment(ref FireCount6); Assert.IsType<MethodDeclarationSyntax>(context.CodeBlock); Assert.Equal("void TestUnion.TestMethod(System.Int64 x)", context.OwningSymbol.ToTestDisplayString()); } private void Handle7(CodeBlockStartAnalysisContext<SyntaxKind> context) { Interlocked.Increment(ref FireCount7); Assert.IsType<MethodDeclarationSyntax>(context.CodeBlock); Assert.Equal("void TestUnion.TestMethod(System.Int64 x)", context.OwningSymbol.ToTestDisplayString()); context.RegisterCodeBlockEndAction(Handle8); } private void Handle8(CodeBlockAnalysisContext context) { Interlocked.Increment(ref FireCount8); Assert.IsType<MethodDeclarationSyntax>(context.CodeBlock); Assert.Equal("void TestUnion.TestMethod(System.Int64 x)", context.OwningSymbol.ToTestDisplayString()); } protected void Handle9(OperationAnalysisContext context) { Interlocked.Increment(ref FireCount9); } private void Handle10(OperationBlockAnalysisContext context) { Interlocked.Increment(ref FireCount10); Assert.Equal("void TestUnion.TestMethod(System.Int64 x)", context.OwningSymbol.ToTestDisplayString()); } private void Handle11(OperationBlockStartAnalysisContext context) { Interlocked.Increment(ref FireCount11); Assert.Equal("void TestUnion.TestMethod(System.Int64 x)", context.OwningSymbol.ToTestDisplayString()); } private void Handle12(SymbolAnalysisContext context) { Interlocked.Increment(ref FireCount12); Assert.Equal("TestUnion", context.Symbol.ToTestDisplayString()); } private void Handle13(SymbolAnalysisContext context) { Interlocked.Increment(ref FireCount13); Assert.Equal("void TestUnion.TestMethod(System.Int64 x)", context.Symbol.ToTestDisplayString()); } private void Handle14(SymbolAnalysisContext context) { Interlocked.Increment(ref FireCount14); Assert.Equal("System.Int64 x", context.Symbol.ToTestDisplayString()); } private void Handle15(SymbolAnalysisContext context) { Interlocked.Increment(ref FireCount15); Assert.Equal("System.Int32 TestUnion._f", context.Symbol.ToTestDisplayString()); } private void Handle16(SymbolAnalysisContext context) { Interlocked.Increment(ref FireCount16); } private void Handle17(SymbolStartAnalysisContext context) { Interlocked.Increment(ref FireCount17); Assert.Equal("TestUnion", context.Symbol.ToTestDisplayString()); context.RegisterSymbolEndAction(Handle22); } private void Handle18(SymbolStartAnalysisContext context) { Interlocked.Increment(ref FireCount18); Assert.Equal("void TestUnion.TestMethod(System.Int64 x)", context.Symbol.ToTestDisplayString()); } private void Handle19(SymbolStartAnalysisContext context) { Interlocked.Increment(ref FireCount19); } private void Handle20(SymbolStartAnalysisContext context) { Interlocked.Increment(ref FireCount20); Assert.Equal("System.Int32 TestUnion._f", context.Symbol.ToTestDisplayString()); } private void Handle21(SymbolStartAnalysisContext context) { Interlocked.Increment(ref FireCount21); } private void Handle22(SymbolAnalysisContext context) { Interlocked.Increment(ref FireCount22); Assert.Equal("TestUnion", context.Symbol.ToTestDisplayString()); } } } }