// 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 Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.CSharp.Test.Utilities;
using Microsoft.CodeAnalysis.Test.Utilities;
using Roslyn.Test.Utilities;
using Xunit;

namespace Microsoft.CodeAnalysis.CSharp.UnitTests
{
    [CompilerTrait(CompilerFeature.Patterns)]
    public class PatternMatchingTests5 : PatternMatchingTestBase
    {
        [Fact]
        public void ExtendedPropertyPatterns_01()
        {
            var program = @"
using System;
class C
{
    public C Prop1 { get; set; }
    public C Prop2 { get; set; }
    public C Prop3 { get; set; }

    static bool Test1(C o) => o is { Prop1.Prop2.Prop3: null };
    static bool Test2(S o) => o is { Prop1.Prop2.Prop3: null };
    static bool Test3(S? o) => o is { Prop1.Prop2.Prop3: null };
    static bool Test4(S0 o) => o is { Prop1.Prop2.Prop3: 420 };

    public static void Main()
    {
        Console.WriteLine(Test1(new() { Prop1 = new() { Prop2 = new() { Prop3 = null }}}));
        Console.WriteLine(Test2(new() { Prop1 = new() { Prop2 = new() { Prop3 = null }}}));
        Console.WriteLine(Test3(new() { Prop1 = new() { Prop2 = new() { Prop3 = null }}}));

        Console.WriteLine(Test1(new() { Prop1 = new() { Prop2 = null }}));
        Console.WriteLine(Test2(new() { Prop1 = new() { Prop2 = null }}));
        Console.WriteLine(Test3(new() { Prop1 = new() { Prop2 = null }}));

        Console.WriteLine(Test1(new() { Prop1 = null }));
        Console.WriteLine(Test2(new() { Prop1 = null }));
        Console.WriteLine(Test3(new() { Prop1 = null }));

        Console.WriteLine(Test1(default));
        Console.WriteLine(Test2(default));
        Console.WriteLine(Test3(default));

        Console.WriteLine(Test4(new() { Prop1 = new() { Prop2 = new() { Prop3 = 421 }}}));
        Console.WriteLine(Test4(new() { Prop1 = new() { Prop2 = new() { Prop3 = 420 }}}));
    }
}
struct S { public A? Prop1; }
struct A { public B? Prop2; }
struct B { public int? Prop3; }

struct S0 { public A0 Prop1; }
struct A0 { public B0 Prop2; }
struct B0 { public int Prop3; }
";
            var compilation = CreateCompilation(program, parseOptions: TestOptions.RegularWithExtendedPropertyPatterns, options: TestOptions.ReleaseExe);
            compilation.VerifyDiagnostics();
            var expectedOutput = @"
True
True
True
False
False
False
False
False
False
False
False
False
False
True
";
            var verifier = CompileAndVerify(compilation, expectedOutput: expectedOutput);
            verifier.VerifyIL("C.Test1", @"
{
  // Code size       35 (0x23)
  .maxstack  2
  .locals init (C V_0,
                C V_1)
  IL_0000:  ldarg.0
  IL_0001:  brfalse.s  IL_0021
  IL_0003:  ldarg.0
  IL_0004:  callvirt   ""C C.Prop1.get""
  IL_0009:  stloc.0
  IL_000a:  ldloc.0
  IL_000b:  brfalse.s  IL_0021
  IL_000d:  ldloc.0
  IL_000e:  callvirt   ""C C.Prop2.get""
  IL_0013:  stloc.1
  IL_0014:  ldloc.1
  IL_0015:  brfalse.s  IL_0021
  IL_0017:  ldloc.1
  IL_0018:  callvirt   ""C C.Prop3.get""
  IL_001d:  ldnull
  IL_001e:  ceq
  IL_0020:  ret
  IL_0021:  ldc.i4.0
  IL_0022:  ret
}");
            verifier.VerifyIL("C.Test2", @"
{
  // Code size       64 (0x40)
  .maxstack  2
  .locals init (A? V_0,
                B? V_1,
                int? V_2)
  IL_0000:  ldarg.0
  IL_0001:  ldfld      ""A? S.Prop1""
  IL_0006:  stloc.0
  IL_0007:  ldloca.s   V_0
  IL_0009:  call       ""bool A?.HasValue.get""
  IL_000e:  brfalse.s  IL_003e
  IL_0010:  ldloca.s   V_0
  IL_0012:  call       ""A A?.GetValueOrDefault()""
  IL_0017:  ldfld      ""B? A.Prop2""
  IL_001c:  stloc.1
  IL_001d:  ldloca.s   V_1
  IL_001f:  call       ""bool B?.HasValue.get""
  IL_0024:  brfalse.s  IL_003e
  IL_0026:  ldloca.s   V_1
  IL_0028:  call       ""B B?.GetValueOrDefault()""
  IL_002d:  ldfld      ""int? B.Prop3""
  IL_0032:  stloc.2
  IL_0033:  ldloca.s   V_2
  IL_0035:  call       ""bool int?.HasValue.get""
  IL_003a:  ldc.i4.0
  IL_003b:  ceq
  IL_003d:  ret
  IL_003e:  ldc.i4.0
  IL_003f:  ret
}");
            verifier.VerifyIL("C.Test4", @"
{
  // Code size       24 (0x18)
  .maxstack  2
  IL_0000:  ldarg.0
  IL_0001:  ldfld      ""A0 S0.Prop1""
  IL_0006:  ldfld      ""B0 A0.Prop2""
  IL_000b:  ldfld      ""int B0.Prop3""
  IL_0010:  ldc.i4     0x1a4
  IL_0015:  ceq
  IL_0017:  ret
}");
        }

        [Fact]
        public void ExtendedPropertyPatterns_02()
        {
            var program = @"
class C
{
    public C Prop1 { get; set; }
    public C Prop2 { get; set; }

    public static void Main()
    {
        _ = new C() is { Prop1: null } and { Prop1.Prop2: null };
        _ = new C() is { Prop1: null, Prop1.Prop2: null };
    }
}
";
            var compilation = CreateCompilation(program, parseOptions: TestOptions.RegularWithExtendedPropertyPatterns, options: TestOptions.ReleaseExe);
            compilation.VerifyDiagnostics(
                // (9,13): error CS8518: An expression of type 'C' can never match the provided pattern.
                //         _ = new C() is { Prop1: null } and { Prop1.Prop2: null };
                Diagnostic(ErrorCode.ERR_IsPatternImpossible, "new C() is { Prop1: null } and { Prop1.Prop2: null }").WithArguments("C").WithLocation(9, 13),
                // (10,13): error CS8518: An expression of type 'C' can never match the provided pattern.
                //         _ = new C() is { Prop1: null, Prop1.Prop2: null };
                Diagnostic(ErrorCode.ERR_IsPatternImpossible, "new C() is { Prop1: null, Prop1.Prop2: null }").WithArguments("C").WithLocation(10, 13)
                );
        }

        [Fact]
        public void ExtendedPropertyPatterns_03()
        {
            var program = @"
using System;
class C
{
    C _prop1;
    C _prop2;

    C Prop1
    {
        get { Console.WriteLine(nameof(Prop1)); return _prop1; }
        set => _prop1 = value;
    }
    C Prop2
    {
        get { Console.WriteLine(nameof(Prop2)); return _prop2; }
        set => _prop2 = value;
    }

    public static void Main()
    {
        Test(null);
        Test(new());
        Test(new() { Prop1 = new() });
        Test(new() { Prop1 = new() { Prop2 = new() } });
    }
    static void Test(C o)
    {
        Console.WriteLine(nameof(Test));
        var result = o switch
        {
            {Prop1: null} => 1,
            {Prop1.Prop2: null} => 2,
            _ => -1,
        };
        Console.WriteLine(result);
    }
}
";
            var compilation = CreateCompilation(program, parseOptions: TestOptions.RegularWithExtendedPropertyPatterns, options: TestOptions.ReleaseExe);
            compilation.VerifyDiagnostics();
            var expectedOutput = @"
Test
-1
Test
Prop1
1
Test
Prop1
Prop2
2
Test
Prop1
Prop2
-1";
            var verifier = CompileAndVerify(compilation, expectedOutput: expectedOutput);
            verifier.VerifyIL("C.Test", @"
{
  // Code size       50 (0x32)
  .maxstack  1
  .locals init (int V_0,
                C V_1)
  IL_0000:  ldstr      ""Test""
  IL_0005:  call       ""void System.Console.WriteLine(string)""
  IL_000a:  ldarg.0
  IL_000b:  brfalse.s  IL_0029
  IL_000d:  ldarg.0
  IL_000e:  callvirt   ""C C.Prop1.get""
  IL_0013:  stloc.1
  IL_0014:  ldloc.1
  IL_0015:  brfalse.s  IL_0021
  IL_0017:  ldloc.1
  IL_0018:  callvirt   ""C C.Prop2.get""
  IL_001d:  brfalse.s  IL_0025
  IL_001f:  br.s       IL_0029
  IL_0021:  ldc.i4.1
  IL_0022:  stloc.0
  IL_0023:  br.s       IL_002b
  IL_0025:  ldc.i4.2
  IL_0026:  stloc.0
  IL_0027:  br.s       IL_002b
  IL_0029:  ldc.i4.m1
  IL_002a:  stloc.0
  IL_002b:  ldloc.0
  IL_002c:  call       ""void System.Console.WriteLine(int)""
  IL_0031:  ret
}");
        }

        [Fact]
        public void ExtendedPropertyPatterns_04()
        {
            var program = @"
class C
{
    public static void Main()
    {
        _ = new C() is { Prop1<int>.Prop2: {} };
        _ = new C() is { Prop1->Prop2: {} };
        _ = new C() is { Prop1!.Prop2: {} };
        _ = new C() is { Prop1?.Prop2: {} };
        _ = new C() is { Prop1[0]: {} };
        _ = new C() is { 1: {} };
    }
}
";
            var compilation = CreateCompilation(program, parseOptions: TestOptions.RegularWithExtendedPropertyPatterns, options: TestOptions.ReleaseExe);
            compilation.VerifyDiagnostics(
                    // (6,26): error CS8918: Identifier or a simple member access expected.
                    //         _ = new C() is { Prop1<int>.Prop2: {} };
                    Diagnostic(ErrorCode.ERR_InvalidNameInSubpattern, "Prop1<int>").WithLocation(6, 26),
                    // (7,26): error CS8918: Identifier or a simple member access expected.
                    //         _ = new C() is { Prop1->Prop2: {} };
                    Diagnostic(ErrorCode.ERR_InvalidNameInSubpattern, "Prop1->Prop2").WithLocation(7, 26),
                    // (8,26): error CS8918: Identifier or a simple member access expected.
                    //         _ = new C() is { Prop1!.Prop2: {} };
                    Diagnostic(ErrorCode.ERR_InvalidNameInSubpattern, "Prop1!").WithLocation(8, 26),
                    // (9,26): error CS8918: Identifier or a simple member access expected.
                    //         _ = new C() is { Prop1?.Prop2: {} };
                    Diagnostic(ErrorCode.ERR_InvalidNameInSubpattern, "Prop1?.Prop2").WithLocation(9, 26),
                    // (10,26): error CS8503: A property subpattern requires a reference to the property or field to be matched, e.g. '{ Name: Prop1[0] }'
                    //         _ = new C() is { Prop1[0]: {} };
                    Diagnostic(ErrorCode.ERR_PropertyPatternNameMissing, "Prop1[0]").WithArguments("Prop1[0]").WithLocation(10, 26),
                    // (10,26): error CS0246: The type or namespace name 'Prop1' could not be found (are you missing a using directive or an assembly reference?)
                    //         _ = new C() is { Prop1[0]: {} };
                    Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "Prop1").WithArguments("Prop1").WithLocation(10, 26),
                    // (10,31): error CS0270: Array size cannot be specified in a variable declaration (try initializing with a 'new' expression)
                    //         _ = new C() is { Prop1[0]: {} };
                    Diagnostic(ErrorCode.ERR_ArraySizeInDeclaration, "[0]").WithLocation(10, 31),
                    // (10,34): error CS1003: Syntax error, ',' expected
                    //         _ = new C() is { Prop1[0]: {} };
                    Diagnostic(ErrorCode.ERR_SyntaxError, ":").WithArguments(",").WithLocation(10, 34),
                    // (10,36): error CS1003: Syntax error, ',' expected
                    //         _ = new C() is { Prop1[0]: {} };
                    Diagnostic(ErrorCode.ERR_SyntaxError, "{").WithArguments(",").WithLocation(10, 36),
                    // (11,26): error CS8918: Identifier or a simple member access expected.
                    //         _ = new C() is { 1: {} };
                    Diagnostic(ErrorCode.ERR_InvalidNameInSubpattern, "1").WithLocation(11, 26));
        }

        [Fact, WorkItem(52956, "https://github.com/dotnet/roslyn/issues/52956")]
        public void ExtendedPropertyPatterns_05()
        {
            var program = @"
class C
{
    C Field1, Field2, Field3, Field4;
    public void M()
    {
        _ = this is { Field1.Field2.Field3: {} };
        _ = this is { Field4: {} };
    }
}
";
            var compilation = CreateCompilation(program, parseOptions: TestOptions.RegularWithExtendedPropertyPatterns);
            compilation.VerifyEmitDiagnostics(
                // (4,7): warning CS0649: Field 'C.Field1' is never assigned to, and will always have its default value null
                //     C Field1, Field2, Field3, Field4;
                Diagnostic(ErrorCode.WRN_UnassignedInternalField, "Field1").WithArguments("C.Field1", "null").WithLocation(4, 7),
                // (4,15): warning CS0649: Field 'C.Field2' is never assigned to, and will always have its default value null
                //     C Field1, Field2, Field3, Field4;
                Diagnostic(ErrorCode.WRN_UnassignedInternalField, "Field2").WithArguments("C.Field2", "null").WithLocation(4, 15),
                // (4,23): warning CS0649: Field 'C.Field3' is never assigned to, and will always have its default value null
                //     C Field1, Field2, Field3, Field4;
                Diagnostic(ErrorCode.WRN_UnassignedInternalField, "Field3").WithArguments("C.Field3", "null").WithLocation(4, 23),
                // (4,31): warning CS0649: Field 'C.Field4' is never assigned to, and will always have its default value null
                //     C Field1, Field2, Field3, Field4;
                Diagnostic(ErrorCode.WRN_UnassignedInternalField, "Field4").WithArguments("C.Field4", "null").WithLocation(4, 31)
                );
        }

        [Fact, WorkItem(52956, "https://github.com/dotnet/roslyn/issues/52956")]
        public void ExtendedPropertyPatterns_05_NestedRecursivePattern()
        {
            var program = @"
class C
{
    C Field1, Field2, Field3, Field4;
    public void M()
    {
        _ = this is { Field1: { Field2.Field3.Field4: not null } };
    }
}
";
            var compilation = CreateCompilation(program, parseOptions: TestOptions.RegularWithExtendedPropertyPatterns);
            compilation.VerifyEmitDiagnostics(
                // (4,7): warning CS0649: Field 'C.Field1' is never assigned to, and will always have its default value null
                //     C Field1, Field2, Field3, Field4;
                Diagnostic(ErrorCode.WRN_UnassignedInternalField, "Field1").WithArguments("C.Field1", "null").WithLocation(4, 7),
                // (4,15): warning CS0649: Field 'C.Field2' is never assigned to, and will always have its default value null
                //     C Field1, Field2, Field3, Field4;
                Diagnostic(ErrorCode.WRN_UnassignedInternalField, "Field2").WithArguments("C.Field2", "null").WithLocation(4, 15),
                // (4,23): warning CS0649: Field 'C.Field3' is never assigned to, and will always have its default value null
                //     C Field1, Field2, Field3, Field4;
                Diagnostic(ErrorCode.WRN_UnassignedInternalField, "Field3").WithArguments("C.Field3", "null").WithLocation(4, 23),
                // (4,31): warning CS0649: Field 'C.Field4' is never assigned to, and will always have its default value null
                //     C Field1, Field2, Field3, Field4;
                Diagnostic(ErrorCode.WRN_UnassignedInternalField, "Field4").WithArguments("C.Field4", "null").WithLocation(4, 31)
                );
        }

        [Fact, WorkItem(52956, "https://github.com/dotnet/roslyn/issues/52956")]
        public void ExtendedPropertyPatterns_05_Properties()
        {
            var program = @"
class C
{
    C Prop1 { get; set; }
    C Prop2 { get; set; }
    C Prop3 { get; set; }
    C Prop4 { get; set; }
    public void M()
    {
        _ = this is { Prop1.Prop2.Prop3: {} };
        _ = this is { Prop4: {} };
    }
}
";
            var compilation = CreateCompilation(program, parseOptions: TestOptions.RegularWithExtendedPropertyPatterns);
            compilation.VerifyEmitDiagnostics();
        }

        [Fact]
        public void ExtendedPropertyPatterns_IOperation_Properties()
        {
            var src = @"
class Program
{
    static void M(A a)
    /*<bind>*/{
        _ = a is { Prop1.Prop2.Prop3: null };
    }/*</bind>*/
}
class A { public B Prop1 => null; }
class B { public C Prop2 => null; }
class C { public object Prop3 => null; }
";
            var comp = CreateCompilation(src, parseOptions: TestOptions.RegularWithExtendedPropertyPatterns);
            comp.VerifyDiagnostics();

            var tree = comp.SyntaxTrees.Single();
            var model = comp.GetSemanticModel(tree, ignoreAccessibility: false);
            var isPattern = tree.GetRoot().DescendantNodes().OfType<IsPatternExpressionSyntax>().Single();

            VerifyOperationTree(comp, model.GetOperation(isPattern), @"
IIsPatternOperation (OperationKind.IsPattern, Type: System.Boolean) (Syntax: 'a is { Prop ... op3: null }')
  Value:
    IParameterReferenceOperation: a (OperationKind.ParameterReference, Type: A) (Syntax: 'a')
  Pattern:
    IRecursivePatternOperation (OperationKind.RecursivePattern, Type: null) (Syntax: '{ Prop1.Pro ... op3: null }') (InputType: A, NarrowedType: A, DeclaredSymbol: null, MatchedType: A, DeconstructSymbol: null)
      DeconstructionSubpatterns (0)
      PropertySubpatterns (1):
          IPropertySubpatternOperation (OperationKind.PropertySubpattern, Type: null, IsImplicit) (Syntax: 'Prop1')
            Member:
              IPropertyReferenceOperation: B A.Prop1 { get; } (OperationKind.PropertyReference, Type: B) (Syntax: 'Prop1')
                Instance Receiver:
                  IInstanceReferenceOperation (ReferenceKind: PatternInput) (OperationKind.InstanceReference, Type: A, IsImplicit) (Syntax: 'Prop1')
            Pattern:
              IRecursivePatternOperation (OperationKind.RecursivePattern, Type: null, IsImplicit) (Syntax: 'Prop1') (InputType: B, NarrowedType: B, DeclaredSymbol: null, MatchedType: B, DeconstructSymbol: null)
                DeconstructionSubpatterns (0)
                PropertySubpatterns (1):
                    IPropertySubpatternOperation (OperationKind.PropertySubpattern, Type: null, IsImplicit) (Syntax: 'Prop1.Prop2')
                      Member:
                        IPropertyReferenceOperation: C B.Prop2 { get; } (OperationKind.PropertyReference, Type: C) (Syntax: 'Prop1.Prop2')
                          Instance Receiver:
                            IInstanceReferenceOperation (ReferenceKind: PatternInput) (OperationKind.InstanceReference, Type: B, IsImplicit) (Syntax: 'Prop1.Prop2')
                      Pattern:
                        IRecursivePatternOperation (OperationKind.RecursivePattern, Type: null, IsImplicit) (Syntax: 'Prop1.Prop2') (InputType: C, NarrowedType: C, DeclaredSymbol: null, MatchedType: C, DeconstructSymbol: null)
                          DeconstructionSubpatterns (0)
                          PropertySubpatterns (1):
                              IPropertySubpatternOperation (OperationKind.PropertySubpattern, Type: null, IsImplicit) (Syntax: 'Prop1.Prop2.Prop3')
                                Member:
                                  IPropertyReferenceOperation: System.Object C.Prop3 { get; } (OperationKind.PropertyReference, Type: System.Object) (Syntax: 'Prop1.Prop2.Prop3')
                                    Instance Receiver:
                                      IInstanceReferenceOperation (ReferenceKind: PatternInput) (OperationKind.InstanceReference, Type: C, IsImplicit) (Syntax: 'Prop1.Prop2.Prop3')
                                Pattern:
                                  IConstantPatternOperation (OperationKind.ConstantPattern, Type: null) (Syntax: 'null') (InputType: System.Object, NarrowedType: System.Object)
                                    Value:
                                      IConversionOperation (TryCast: False, Unchecked) (OperationKind.Conversion, Type: System.Object, Constant: null, IsImplicit) (Syntax: 'null')
                                        Conversion: CommonConversion (Exists: True, IsIdentity: False, IsNumeric: False, IsReference: True, IsUserDefined: False) (MethodSymbol: null)
                                        Operand:
                                          ILiteralOperation (OperationKind.Literal, Type: null, Constant: null) (Syntax: 'null')
");

            var expectedFlowGraph = @"
Block[B0] - Entry
    Statements (0)
    Next (Regular) Block[B1]
Block[B1] - Block
    Predecessors: [B0]
    Statements (1)
        IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: '_ = a is {  ... p3: null };')
          Expression:
            ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: System.Boolean) (Syntax: '_ = a is {  ... op3: null }')
              Left:
                IDiscardOperation (Symbol: System.Boolean _) (OperationKind.Discard, Type: System.Boolean) (Syntax: '_')
              Right:
                IIsPatternOperation (OperationKind.IsPattern, Type: System.Boolean) (Syntax: 'a is { Prop ... op3: null }')
                  Value:
                    IParameterReferenceOperation: a (OperationKind.ParameterReference, Type: A) (Syntax: 'a')
                  Pattern:
                    IRecursivePatternOperation (OperationKind.RecursivePattern, Type: null) (Syntax: '{ Prop1.Pro ... op3: null }') (InputType: A, NarrowedType: A, DeclaredSymbol: null, MatchedType: A, DeconstructSymbol: null)
                      DeconstructionSubpatterns (0)
                      PropertySubpatterns (1):
                          IPropertySubpatternOperation (OperationKind.PropertySubpattern, Type: null, IsImplicit) (Syntax: 'Prop1')
                            Member:
                              IPropertyReferenceOperation: B A.Prop1 { get; } (OperationKind.PropertyReference, Type: B) (Syntax: 'Prop1')
                                Instance Receiver:
                                  IInstanceReferenceOperation (ReferenceKind: PatternInput) (OperationKind.InstanceReference, Type: A, IsImplicit) (Syntax: 'Prop1')
                            Pattern:
                              IRecursivePatternOperation (OperationKind.RecursivePattern, Type: null, IsImplicit) (Syntax: 'Prop1') (InputType: B, NarrowedType: B, DeclaredSymbol: null, MatchedType: B, DeconstructSymbol: null)
                                DeconstructionSubpatterns (0)
                                PropertySubpatterns (1):
                                    IPropertySubpatternOperation (OperationKind.PropertySubpattern, Type: null, IsImplicit) (Syntax: 'Prop1.Prop2')
                                      Member:
                                        IPropertyReferenceOperation: C B.Prop2 { get; } (OperationKind.PropertyReference, Type: C) (Syntax: 'Prop1.Prop2')
                                          Instance Receiver:
                                            IInstanceReferenceOperation (ReferenceKind: PatternInput) (OperationKind.InstanceReference, Type: B, IsImplicit) (Syntax: 'Prop1.Prop2')
                                      Pattern:
                                        IRecursivePatternOperation (OperationKind.RecursivePattern, Type: null, IsImplicit) (Syntax: 'Prop1.Prop2') (InputType: C, NarrowedType: C, DeclaredSymbol: null, MatchedType: C, DeconstructSymbol: null)
                                          DeconstructionSubpatterns (0)
                                          PropertySubpatterns (1):
                                              IPropertySubpatternOperation (OperationKind.PropertySubpattern, Type: null, IsImplicit) (Syntax: 'Prop1.Prop2.Prop3')
                                                Member:
                                                  IPropertyReferenceOperation: System.Object C.Prop3 { get; } (OperationKind.PropertyReference, Type: System.Object) (Syntax: 'Prop1.Prop2.Prop3')
                                                    Instance Receiver:
                                                      IInstanceReferenceOperation (ReferenceKind: PatternInput) (OperationKind.InstanceReference, Type: C, IsImplicit) (Syntax: 'Prop1.Prop2.Prop3')
                                                Pattern:
                                                  IConstantPatternOperation (OperationKind.ConstantPattern, Type: null) (Syntax: 'null') (InputType: System.Object, NarrowedType: System.Object)
                                                    Value:
                                                      IConversionOperation (TryCast: False, Unchecked) (OperationKind.Conversion, Type: System.Object, Constant: null, IsImplicit) (Syntax: 'null')
                                                        Conversion: CommonConversion (Exists: True, IsIdentity: False, IsNumeric: False, IsReference: True, IsUserDefined: False) (MethodSymbol: null)
                                                          (ImplicitReference)
                                                        Operand:
                                                          ILiteralOperation (OperationKind.Literal, Type: null, Constant: null) (Syntax: 'null')
    Next (Regular) Block[B2]
Block[B2] - Exit
    Predecessors: [B1]
    Statements (0)
";

            VerifyFlowGraphAndDiagnosticsForTest<BlockSyntax>(src, expectedFlowGraph, DiagnosticDescription.None, parseOptions: TestOptions.Regular10);
        }

        [Fact]
        public void ExtendedPropertyPatterns_IOperation_FieldsInStructs()
        {
            var src = @"
class Program
{
    static void M(A a)
    /*<bind>*/{
        _ = a is { Field1.Field2.Field3: null, Field4: null };
    }/*</bind>*/
}
struct A { public B? Field1; public B? Field4; }
struct B { public C? Field2; }
struct C { public object Field3; }
";
            var expectedDiagnostics = new[]
            {
                // (9,22): warning CS0649: Field 'A.Field1' is never assigned to, and will always have its default value
                // struct A { public B? Field1; public B? Field4; }
                Diagnostic(ErrorCode.WRN_UnassignedInternalField, "Field1").WithArguments("A.Field1", "").WithLocation(9, 22),
                // (9,40): warning CS0649: Field 'A.Field4' is never assigned to, and will always have its default value
                // struct A { public B? Field1; public B? Field4; }
                Diagnostic(ErrorCode.WRN_UnassignedInternalField, "Field4").WithArguments("A.Field4", "").WithLocation(9, 40),
                // (10,22): warning CS0649: Field 'B.Field2' is never assigned to, and will always have its default value
                // struct B { public C? Field2; }
                Diagnostic(ErrorCode.WRN_UnassignedInternalField, "Field2").WithArguments("B.Field2", "").WithLocation(10, 22),
                // (11,26): warning CS0649: Field 'C.Field3' is never assigned to, and will always have its default value null
                // struct C { public object Field3; }
                Diagnostic(ErrorCode.WRN_UnassignedInternalField, "Field3").WithArguments("C.Field3", "null").WithLocation(11, 26)
            };
            var comp = CreateCompilation(src, parseOptions: TestOptions.RegularWithExtendedPropertyPatterns);
            comp.VerifyDiagnostics(expectedDiagnostics);

            var tree = comp.SyntaxTrees.Single();
            var model = comp.GetSemanticModel(tree, ignoreAccessibility: false);
            var isPattern = tree.GetRoot().DescendantNodes().OfType<IsPatternExpressionSyntax>().Single();

            VerifyOperationTree(comp, model.GetOperation(isPattern), @"
IIsPatternOperation (OperationKind.IsPattern, Type: System.Boolean) (Syntax: 'a is { Fiel ... ld4: null }')
  Value:
    IParameterReferenceOperation: a (OperationKind.ParameterReference, Type: A) (Syntax: 'a')
  Pattern:
    IRecursivePatternOperation (OperationKind.RecursivePattern, Type: null) (Syntax: '{ Field1.Fi ... ld4: null }') (InputType: A, NarrowedType: A, DeclaredSymbol: null, MatchedType: A, DeconstructSymbol: null)
      DeconstructionSubpatterns (0)
      PropertySubpatterns (2):
          IPropertySubpatternOperation (OperationKind.PropertySubpattern, Type: null, IsImplicit) (Syntax: 'Field1')
            Member:
              IFieldReferenceOperation: B? A.Field1 (OperationKind.FieldReference, Type: B?) (Syntax: 'Field1')
                Instance Receiver:
                  IInstanceReferenceOperation (ReferenceKind: PatternInput) (OperationKind.InstanceReference, Type: A, IsImplicit) (Syntax: 'Field1')
            Pattern:
              IRecursivePatternOperation (OperationKind.RecursivePattern, Type: null, IsImplicit) (Syntax: 'Field1') (InputType: B, NarrowedType: B, DeclaredSymbol: null, MatchedType: B, DeconstructSymbol: null)
                DeconstructionSubpatterns (0)
                PropertySubpatterns (1):
                    IPropertySubpatternOperation (OperationKind.PropertySubpattern, Type: null, IsImplicit) (Syntax: 'Field1.Field2')
                      Member:
                        IFieldReferenceOperation: C? B.Field2 (OperationKind.FieldReference, Type: C?) (Syntax: 'Field1.Field2')
                          Instance Receiver:
                            IInstanceReferenceOperation (ReferenceKind: PatternInput) (OperationKind.InstanceReference, Type: B, IsImplicit) (Syntax: 'Field1.Field2')
                      Pattern:
                        IRecursivePatternOperation (OperationKind.RecursivePattern, Type: null, IsImplicit) (Syntax: 'Field1.Field2') (InputType: C, NarrowedType: C, DeclaredSymbol: null, MatchedType: C, DeconstructSymbol: null)
                          DeconstructionSubpatterns (0)
                          PropertySubpatterns (1):
                              IPropertySubpatternOperation (OperationKind.PropertySubpattern, Type: null, IsImplicit) (Syntax: 'Field1.Field2.Field3')
                                Member:
                                  IFieldReferenceOperation: System.Object C.Field3 (OperationKind.FieldReference, Type: System.Object) (Syntax: 'Field1.Field2.Field3')
                                    Instance Receiver:
                                      IInstanceReferenceOperation (ReferenceKind: PatternInput) (OperationKind.InstanceReference, Type: C, IsImplicit) (Syntax: 'Field1.Field2.Field3')
                                Pattern:
                                  IConstantPatternOperation (OperationKind.ConstantPattern, Type: null) (Syntax: 'null') (InputType: System.Object, NarrowedType: System.Object)
                                    Value:
                                      IConversionOperation (TryCast: False, Unchecked) (OperationKind.Conversion, Type: System.Object, Constant: null, IsImplicit) (Syntax: 'null')
                                        Conversion: CommonConversion (Exists: True, IsIdentity: False, IsNumeric: False, IsReference: True, IsUserDefined: False) (MethodSymbol: null)
                                        Operand:
                                          ILiteralOperation (OperationKind.Literal, Type: null, Constant: null) (Syntax: 'null')
          IPropertySubpatternOperation (OperationKind.PropertySubpattern, Type: null) (Syntax: 'Field4: null')
            Member:
              IFieldReferenceOperation: B? A.Field4 (OperationKind.FieldReference, Type: B?) (Syntax: 'Field4')
                Instance Receiver:
                  IInstanceReferenceOperation (ReferenceKind: PatternInput) (OperationKind.InstanceReference, Type: A, IsImplicit) (Syntax: 'Field4')
            Pattern:
              IConstantPatternOperation (OperationKind.ConstantPattern, Type: null) (Syntax: 'null') (InputType: B?, NarrowedType: B?)
                Value:
                  IConversionOperation (TryCast: False, Unchecked) (OperationKind.Conversion, Type: B?, Constant: null, IsImplicit) (Syntax: 'null')
                    Conversion: CommonConversion (Exists: True, IsIdentity: False, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null)
                    Operand:
                      ILiteralOperation (OperationKind.Literal, Type: null, Constant: null) (Syntax: 'null')
");

            var expectedFlowGraph = @"
Block[B0] - Entry
    Statements (0)
    Next (Regular) Block[B1]
Block[B1] - Block
    Predecessors: [B0]
    Statements (1)
        IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: '_ = a is {  ... d4: null };')
          Expression:
            ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: System.Boolean) (Syntax: '_ = a is {  ... ld4: null }')
              Left:
                IDiscardOperation (Symbol: System.Boolean _) (OperationKind.Discard, Type: System.Boolean) (Syntax: '_')
              Right:
                IIsPatternOperation (OperationKind.IsPattern, Type: System.Boolean) (Syntax: 'a is { Fiel ... ld4: null }')
                  Value:
                    IParameterReferenceOperation: a (OperationKind.ParameterReference, Type: A) (Syntax: 'a')
                  Pattern:
                    IRecursivePatternOperation (OperationKind.RecursivePattern, Type: null) (Syntax: '{ Field1.Fi ... ld4: null }') (InputType: A, NarrowedType: A, DeclaredSymbol: null, MatchedType: A, DeconstructSymbol: null)
                      DeconstructionSubpatterns (0)
                      PropertySubpatterns (2):
                          IPropertySubpatternOperation (OperationKind.PropertySubpattern, Type: null, IsImplicit) (Syntax: 'Field1')
                            Member:
                              IFieldReferenceOperation: B? A.Field1 (OperationKind.FieldReference, Type: B?) (Syntax: 'Field1')
                                Instance Receiver:
                                  IInstanceReferenceOperation (ReferenceKind: PatternInput) (OperationKind.InstanceReference, Type: A, IsImplicit) (Syntax: 'Field1')
                            Pattern:
                              IRecursivePatternOperation (OperationKind.RecursivePattern, Type: null, IsImplicit) (Syntax: 'Field1') (InputType: B, NarrowedType: B, DeclaredSymbol: null, MatchedType: B, DeconstructSymbol: null)
                                DeconstructionSubpatterns (0)
                                PropertySubpatterns (1):
                                    IPropertySubpatternOperation (OperationKind.PropertySubpattern, Type: null, IsImplicit) (Syntax: 'Field1.Field2')
                                      Member:
                                        IFieldReferenceOperation: C? B.Field2 (OperationKind.FieldReference, Type: C?) (Syntax: 'Field1.Field2')
                                          Instance Receiver:
                                            IInstanceReferenceOperation (ReferenceKind: PatternInput) (OperationKind.InstanceReference, Type: B, IsImplicit) (Syntax: 'Field1.Field2')
                                      Pattern:
                                        IRecursivePatternOperation (OperationKind.RecursivePattern, Type: null, IsImplicit) (Syntax: 'Field1.Field2') (InputType: C, NarrowedType: C, DeclaredSymbol: null, MatchedType: C, DeconstructSymbol: null)
                                          DeconstructionSubpatterns (0)
                                          PropertySubpatterns (1):
                                              IPropertySubpatternOperation (OperationKind.PropertySubpattern, Type: null, IsImplicit) (Syntax: 'Field1.Field2.Field3')
                                                Member:
                                                  IFieldReferenceOperation: System.Object C.Field3 (OperationKind.FieldReference, Type: System.Object) (Syntax: 'Field1.Field2.Field3')
                                                    Instance Receiver:
                                                      IInstanceReferenceOperation (ReferenceKind: PatternInput) (OperationKind.InstanceReference, Type: C, IsImplicit) (Syntax: 'Field1.Field2.Field3')
                                                Pattern:
                                                  IConstantPatternOperation (OperationKind.ConstantPattern, Type: null) (Syntax: 'null') (InputType: System.Object, NarrowedType: System.Object)
                                                    Value:
                                                      IConversionOperation (TryCast: False, Unchecked) (OperationKind.Conversion, Type: System.Object, Constant: null, IsImplicit) (Syntax: 'null')
                                                        Conversion: CommonConversion (Exists: True, IsIdentity: False, IsNumeric: False, IsReference: True, IsUserDefined: False) (MethodSymbol: null)
                                                          (ImplicitReference)
                                                        Operand:
                                                          ILiteralOperation (OperationKind.Literal, Type: null, Constant: null) (Syntax: 'null')
                          IPropertySubpatternOperation (OperationKind.PropertySubpattern, Type: null) (Syntax: 'Field4: null')
                            Member:
                              IFieldReferenceOperation: B? A.Field4 (OperationKind.FieldReference, Type: B?) (Syntax: 'Field4')
                                Instance Receiver:
                                  IInstanceReferenceOperation (ReferenceKind: PatternInput) (OperationKind.InstanceReference, Type: A, IsImplicit) (Syntax: 'Field4')
                            Pattern:
                              IConstantPatternOperation (OperationKind.ConstantPattern, Type: null) (Syntax: 'null') (InputType: B?, NarrowedType: B?)
                                Value:
                                  IConversionOperation (TryCast: False, Unchecked) (OperationKind.Conversion, Type: B?, Constant: null, IsImplicit) (Syntax: 'null')
                                    Conversion: CommonConversion (Exists: True, IsIdentity: False, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null)
                                      (NullLiteral)
                                    Operand:
                                      ILiteralOperation (OperationKind.Literal, Type: null, Constant: null) (Syntax: 'null')
    Next (Regular) Block[B2]
Block[B2] - Exit
    Predecessors: [B1]
    Statements (0)
";

            VerifyFlowGraphAndDiagnosticsForTest<BlockSyntax>(src, expectedFlowGraph, expectedDiagnostics, parseOptions: TestOptions.Regular10);
        }

        [Fact]
        public void ExtendedPropertyPatterns_Explainer()
        {
            var src = @"
class Program
{
    void M(A a)
    {
        _ = a switch // 1
        {
            { BProp.BoolProp: true } => 1
        };

        _ = a switch // 2
        {
            { BProp.IntProp: <= 0 } => 1
        };
     }
}
class A { public B BProp => null; }
class B
{
    public bool BoolProp => true;
    public int IntProp => 0;
}
";
            var comp = CreateCompilation(src, parseOptions: TestOptions.RegularWithExtendedPropertyPatterns);
            comp.VerifyDiagnostics(
                // (6,15): warning CS8509: The switch expression does not handle all possible values of its input type (it is not exhaustive). For example, the pattern '{ BProp: { BoolProp: false } }' is not covered.
                //         _ = a switch // 1
                Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustive, "switch").WithArguments("{ BProp: { BoolProp: false } }").WithLocation(6, 15),
                // (11,15): warning CS8509: The switch expression does not handle all possible values of its input type (it is not exhaustive). For example, the pattern '{ BProp: { IntProp: 1 } }' is not covered.
                //         _ = a switch // 2
                Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustive, "switch").WithArguments("{ BProp: { IntProp: 1 } }").WithLocation(11, 15)
                );
        }

        [Fact, WorkItem(52956, "https://github.com/dotnet/roslyn/issues/52956")]
        public void ExtendedPropertyPatterns_BadMemberAccess()
        {
            var program = @"
class C
{
    C Field1, Field2, Field3;
    public static void Main()
    {
        _ = new C() is { Field1?.Field2: {} }; // 1
        _ = new C() is { Field1!.Field2: {} }; // 2
        _ = new C() is { Missing: null }; // 3
        _ = new C() is { Field3.Missing: {} }; // 4
        _ = new C() is { Missing1.Missing2: {} }; // 5
    }
}
";
            var compilation = CreateCompilation(program, parseOptions: TestOptions.RegularWithExtendedPropertyPatterns);
            compilation.VerifyEmitDiagnostics(
                // (4,7): warning CS0169: The field 'C.Field1' is never used
                //     C Field1, Field2, Field3;
                Diagnostic(ErrorCode.WRN_UnreferencedField, "Field1").WithArguments("C.Field1").WithLocation(4, 7),
                // (4,15): warning CS0169: The field 'C.Field2' is never used
                //     C Field1, Field2, Field3;
                Diagnostic(ErrorCode.WRN_UnreferencedField, "Field2").WithArguments("C.Field2").WithLocation(4, 15),
                // (4,23): warning CS0649: Field 'C.Field3' is never assigned to, and will always have its default value null
                //     C Field1, Field2, Field3;
                Diagnostic(ErrorCode.WRN_UnassignedInternalField, "Field3").WithArguments("C.Field3", "null").WithLocation(4, 23),
                // (7,26): error CS8918: Identifier or a simple member access expected.
                //         _ = new C() is { Field1?.Field2: {} }; // 1
                Diagnostic(ErrorCode.ERR_InvalidNameInSubpattern, "Field1?.Field2").WithLocation(7, 26),
                // (8,26): error CS8918: Identifier or a simple member access expected.
                //         _ = new C() is { Field1!.Field2: {} }; // 2
                Diagnostic(ErrorCode.ERR_InvalidNameInSubpattern, "Field1!").WithLocation(8, 26),
                // (9,26): error CS0117: 'C' does not contain a definition for 'Missing'
                //         _ = new C() is { Missing: null }; // 3
                Diagnostic(ErrorCode.ERR_NoSuchMember, "Missing").WithArguments("C", "Missing").WithLocation(9, 26),
                // (10,33): error CS0117: 'C' does not contain a definition for 'Missing'
                //         _ = new C() is { Field3.Missing: {} }; // 4
                Diagnostic(ErrorCode.ERR_NoSuchMember, "Missing").WithArguments("C", "Missing").WithLocation(10, 33),
                // (11,26): error CS0117: 'C' does not contain a definition for 'Missing1'
                //         _ = new C() is { Missing1.Missing2: {} }; // 5
                Diagnostic(ErrorCode.ERR_NoSuchMember, "Missing1").WithArguments("C", "Missing1").WithLocation(11, 26)
                );
        }

        [Fact]
        public void ExtendedPropertyPatterns_IOperationOnMissing()
        {
            var program = @"
class C
{
    public void M()
    {
        _ = this is { Missing: null };
    }
}
";
            var comp = CreateCompilation(program, parseOptions: TestOptions.RegularWithExtendedPropertyPatterns);
            comp.VerifyEmitDiagnostics(
                // (6,23): error CS0117: 'C' does not contain a definition for 'Missing'
                //         _ = this is { Missing: null };
                Diagnostic(ErrorCode.ERR_NoSuchMember, "Missing").WithArguments("C", "Missing").WithLocation(6, 23)
                );

            var tree = comp.SyntaxTrees.Single();
            var model = comp.GetSemanticModel(tree, ignoreAccessibility: false);
            var isPattern = tree.GetRoot().DescendantNodes().OfType<IsPatternExpressionSyntax>().Single();

            VerifyOperationTree(comp, model.GetOperation(isPattern), @"
IIsPatternOperation (OperationKind.IsPattern, Type: System.Boolean, IsInvalid) (Syntax: 'this is { M ... ing: null }')
  Value:
    IInstanceReferenceOperation (ReferenceKind: ContainingTypeInstance) (OperationKind.InstanceReference, Type: C) (Syntax: 'this')
  Pattern:
    IRecursivePatternOperation (OperationKind.RecursivePattern, Type: null, IsInvalid) (Syntax: '{ Missing: null }') (InputType: C, NarrowedType: C, DeclaredSymbol: null, MatchedType: C, DeconstructSymbol: null)
      DeconstructionSubpatterns (0)
      PropertySubpatterns (1):
          IPropertySubpatternOperation (OperationKind.PropertySubpattern, Type: null, IsInvalid) (Syntax: 'Missing: null')
            Member:
              IInvalidOperation (OperationKind.Invalid, Type: null, IsInvalid) (Syntax: 'Missing')
                Children(0)
            Pattern:
              IConstantPatternOperation (OperationKind.ConstantPattern, Type: null) (Syntax: 'null') (InputType: ?, NarrowedType: ?)
                Value:
                  IConversionOperation (TryCast: False, Unchecked) (OperationKind.Conversion, Type: ?, Constant: null, IsImplicit) (Syntax: 'null')
                    Conversion: CommonConversion (Exists: True, IsIdentity: False, IsNumeric: False, IsReference: True, IsUserDefined: False) (MethodSymbol: null)
                    Operand:
                      ILiteralOperation (OperationKind.Literal, Type: null, Constant: null) (Syntax: 'null')
");
        }

        [Fact]
        public void ExtendedPropertyPatterns_IOperationOnNestedMissing()
        {
            var program = @"
class C
{
    int Property { get; set; }
    public void M()
    {
        _ = this is { Property.Missing: null };
    }
}
";
            var comp = CreateCompilation(program, parseOptions: TestOptions.RegularWithExtendedPropertyPatterns);
            comp.VerifyEmitDiagnostics(
                // (7,32): error CS0117: 'int' does not contain a definition for 'Missing'
                //         _ = this is { Property.Missing: null };
                Diagnostic(ErrorCode.ERR_NoSuchMember, "Missing").WithArguments("int", "Missing").WithLocation(7, 32)
                );

            var tree = comp.SyntaxTrees.Single();
            var model = comp.GetSemanticModel(tree, ignoreAccessibility: false);
            var isPattern = tree.GetRoot().DescendantNodes().OfType<IsPatternExpressionSyntax>().Single();

            VerifyOperationTree(comp, model.GetOperation(isPattern), @"
IIsPatternOperation (OperationKind.IsPattern, Type: System.Boolean, IsInvalid) (Syntax: 'this is { P ... ing: null }')
  Value:
    IInstanceReferenceOperation (ReferenceKind: ContainingTypeInstance) (OperationKind.InstanceReference, Type: C) (Syntax: 'this')
  Pattern:
    IRecursivePatternOperation (OperationKind.RecursivePattern, Type: null, IsInvalid) (Syntax: '{ Property. ... ing: null }') (InputType: C, NarrowedType: C, DeclaredSymbol: null, MatchedType: C, DeconstructSymbol: null)
      DeconstructionSubpatterns (0)
      PropertySubpatterns (1):
          IPropertySubpatternOperation (OperationKind.PropertySubpattern, Type: null, IsImplicit) (Syntax: 'Property')
            Member:
              IPropertyReferenceOperation: System.Int32 C.Property { get; set; } (OperationKind.PropertyReference, Type: System.Int32) (Syntax: 'Property')
                Instance Receiver:
                  IInstanceReferenceOperation (ReferenceKind: PatternInput) (OperationKind.InstanceReference, Type: C, IsImplicit) (Syntax: 'Property')
            Pattern:
              IRecursivePatternOperation (OperationKind.RecursivePattern, Type: null, IsImplicit) (Syntax: 'Property') (InputType: System.Int32, NarrowedType: System.Int32, DeclaredSymbol: null, MatchedType: System.Int32, DeconstructSymbol: null)
                DeconstructionSubpatterns (0)
                PropertySubpatterns (1):
                    IPropertySubpatternOperation (OperationKind.PropertySubpattern, Type: null, IsInvalid, IsImplicit) (Syntax: 'Property.Missing')
                      Member:
                        IInvalidOperation (OperationKind.Invalid, Type: null, IsInvalid) (Syntax: 'Property.Missing')
                          Children(0)
                      Pattern:
                        IConstantPatternOperation (OperationKind.ConstantPattern, Type: null) (Syntax: 'null') (InputType: ?, NarrowedType: ?)
                          Value:
                            IConversionOperation (TryCast: False, Unchecked) (OperationKind.Conversion, Type: ?, Constant: null, IsImplicit) (Syntax: 'null')
                              Conversion: CommonConversion (Exists: True, IsIdentity: False, IsNumeric: False, IsReference: True, IsUserDefined: False) (MethodSymbol: null)
                              Operand:
                                ILiteralOperation (OperationKind.Literal, Type: null, Constant: null) (Syntax: 'null')
");
        }

        [Fact]
        public void ExtendedPropertyPatterns_IOperationOnTwoMissing()
        {
            var program = @"
class C
{
    public void M()
    {
        _ = this is { Missing1.Missing2: null };
    }
}
";
            var comp = CreateCompilation(program, parseOptions: TestOptions.RegularWithExtendedPropertyPatterns);
            comp.VerifyEmitDiagnostics(
                // (6,23): error CS0117: 'C' does not contain a definition for 'Missing1'
                //         _ = this is { Missing1.Missing2: null };
                Diagnostic(ErrorCode.ERR_NoSuchMember, "Missing1").WithArguments("C", "Missing1").WithLocation(6, 23)
                );

            var tree = comp.SyntaxTrees.Single();
            var model = comp.GetSemanticModel(tree, ignoreAccessibility: false);
            var isPattern = tree.GetRoot().DescendantNodes().OfType<IsPatternExpressionSyntax>().Single();

            VerifyOperationTree(comp, model.GetOperation(isPattern), @"
IIsPatternOperation (OperationKind.IsPattern, Type: System.Boolean, IsInvalid) (Syntax: 'this is { M ... ng2: null }')
  Value:
    IInstanceReferenceOperation (ReferenceKind: ContainingTypeInstance) (OperationKind.InstanceReference, Type: C) (Syntax: 'this')
  Pattern:
    IRecursivePatternOperation (OperationKind.RecursivePattern, Type: null, IsInvalid) (Syntax: '{ Missing1. ... ng2: null }') (InputType: C, NarrowedType: C, DeclaredSymbol: null, MatchedType: C, DeconstructSymbol: null)
      DeconstructionSubpatterns (0)
      PropertySubpatterns (1):
          IPropertySubpatternOperation (OperationKind.PropertySubpattern, Type: null, IsInvalid, IsImplicit) (Syntax: 'Missing1')
            Member:
              IInvalidOperation (OperationKind.Invalid, Type: null, IsInvalid) (Syntax: 'Missing1')
                Children(0)
            Pattern:
              IRecursivePatternOperation (OperationKind.RecursivePattern, Type: null, IsInvalid, IsImplicit) (Syntax: 'Missing1') (InputType: ?, NarrowedType: ?, DeclaredSymbol: null, MatchedType: ?, DeconstructSymbol: null)
                DeconstructionSubpatterns (0)
                PropertySubpatterns (1):
                    IPropertySubpatternOperation (OperationKind.PropertySubpattern, Type: null, IsInvalid, IsImplicit) (Syntax: 'Missing1.Missing2')
                      Member:
                        IInvalidOperation (OperationKind.Invalid, Type: null, IsInvalid) (Syntax: 'Missing1.Missing2')
                          Children(0)
                      Pattern:
                        IConstantPatternOperation (OperationKind.ConstantPattern, Type: null) (Syntax: 'null') (InputType: ?, NarrowedType: ?)
                          Value:
                            IConversionOperation (TryCast: False, Unchecked) (OperationKind.Conversion, Type: ?, Constant: null, IsImplicit) (Syntax: 'null')
                              Conversion: CommonConversion (Exists: True, IsIdentity: False, IsNumeric: False, IsReference: True, IsUserDefined: False) (MethodSymbol: null)
                              Operand:
                                ILiteralOperation (OperationKind.Literal, Type: null, Constant: null) (Syntax: 'null')
");
        }

        [Fact, WorkItem(53484, "https://github.com/dotnet/roslyn/issues/53484")]
        public void ExtendedPropertyPatterns_SuppressionOnPattern()
        {
            var program = @"
#nullable enable
public class ContainerType
{
    public class Type
    {
        public void M(object o)
        {
            const Type c = null!;
            if (o is c!) {}                      // a1
            if (o is 1!) {}                      // a2
            if (o is (c!)) {}                    // a3
            if (o is (1!)) {}                    // a4
            if (o is Type!) {}                   // a5
            if (o is ContainerType!.Type) {}     // a6
            if (o is ContainerType.Type!) {}     // a7
            if (o is < c!) {}                    // a8

            switch (o)
            {
                case c!: break;                  // b1
                case 1!: break;                  // b2
                case (c!): break;                // b3
                case (1!): break;                // b4
                case Type!: break;               // b5
                case ContainerType!.Type: break; // b6
                case ContainerType.Type!: break; // b7
                case < c!: break;                // b8
            }

            _ = o switch
            {
                c! => 0,                         // c1
                1! => 0,                         // c2
                (c!) => 0,                       // c3
                (1!) => 0,                       // c4
                Type! => 0,                      // c5
                ContainerType!.Type => 0,        // c6
                ContainerType.Type! => 0,        // c7
                < c! => 0,                       // c8
            };
        }
    }
}
";
            var compilation = CreateCompilation(program, parseOptions: TestOptions.RegularWithExtendedPropertyPatterns);
            compilation.VerifyEmitDiagnostics(
                // (10,22): error CS8598: The suppression operator is not allowed in this context
                //             if (o is c!) {}                      // a1
                Diagnostic(ErrorCode.ERR_IllegalSuppression, "c!").WithLocation(10, 22),
                // (11,22): error CS8598: The suppression operator is not allowed in this context
                //             if (o is 1!) {}                      // a2
                Diagnostic(ErrorCode.ERR_IllegalSuppression, "1!").WithLocation(11, 22),
                // (12,23): error CS8598: The suppression operator is not allowed in this context
                //             if (o is (c!)) {}                    // a3
                Diagnostic(ErrorCode.ERR_IllegalSuppression, "c!").WithLocation(12, 23),
                // (13,23): error CS8598: The suppression operator is not allowed in this context
                //             if (o is (1!)) {}                    // a4
                Diagnostic(ErrorCode.ERR_IllegalSuppression, "1!").WithLocation(13, 23),
                // (14,22): error CS8598: The suppression operator is not allowed in this context
                //             if (o is Type!) {}                   // a5
                Diagnostic(ErrorCode.ERR_IllegalSuppression, "Type!").WithLocation(14, 22),
                // (15,22): error CS8598: The suppression operator is not allowed in this context
                //             if (o is ContainerType!.Type) {}     // a6
                Diagnostic(ErrorCode.ERR_IllegalSuppression, "ContainerType").WithLocation(15, 22),
                // (16,22): error CS8598: The suppression operator is not allowed in this context
                //             if (o is ContainerType.Type!) {}     // a7
                Diagnostic(ErrorCode.ERR_IllegalSuppression, "ContainerType.Type!").WithLocation(16, 22),
                // (17,24): error CS8598: The suppression operator is not allowed in this context
                //             if (o is < c!) {}                    // a8
                Diagnostic(ErrorCode.ERR_IllegalSuppression, "c!").WithLocation(17, 24),
                // (21,22): error CS8598: The suppression operator is not allowed in this context
                //                 case c!: break;                  // b1
                Diagnostic(ErrorCode.ERR_IllegalSuppression, "c!").WithLocation(21, 22),
                // (22,22): error CS8598: The suppression operator is not allowed in this context
                //                 case 1!: break;                  // b2
                Diagnostic(ErrorCode.ERR_IllegalSuppression, "1!").WithLocation(22, 22),
                // (23,23): error CS8598: The suppression operator is not allowed in this context
                //                 case (c!): break;                // b3
                Diagnostic(ErrorCode.ERR_IllegalSuppression, "c!").WithLocation(23, 23),
                // (24,23): error CS8598: The suppression operator is not allowed in this context
                //                 case (1!): break;                // b4
                Diagnostic(ErrorCode.ERR_IllegalSuppression, "1!").WithLocation(24, 23),
                // (25,22): error CS8598: The suppression operator is not allowed in this context
                //                 case Type!: break;               // b5
                Diagnostic(ErrorCode.ERR_IllegalSuppression, "Type!").WithLocation(25, 22),
                // (26,22): error CS8598: The suppression operator is not allowed in this context
                //                 case ContainerType!.Type: break; // b6
                Diagnostic(ErrorCode.ERR_IllegalSuppression, "ContainerType").WithLocation(26, 22),
                // (27,22): error CS8598: The suppression operator is not allowed in this context
                //                 case ContainerType.Type!: break; // b7
                Diagnostic(ErrorCode.ERR_IllegalSuppression, "ContainerType.Type!").WithLocation(27, 22),
                // (28,24): error CS8598: The suppression operator is not allowed in this context
                //                 case < c!: break;                // b8
                Diagnostic(ErrorCode.ERR_IllegalSuppression, "c!").WithLocation(28, 24),
                // (33,17): error CS8598: The suppression operator is not allowed in this context
                //                 c! => 0,                         // c1
                Diagnostic(ErrorCode.ERR_IllegalSuppression, "c!").WithLocation(33, 17),
                // (34,17): error CS8598: The suppression operator is not allowed in this context
                //                 1! => 0,                         // c2
                Diagnostic(ErrorCode.ERR_IllegalSuppression, "1!").WithLocation(34, 17),
                // (35,18): error CS8598: The suppression operator is not allowed in this context
                //                 (c!) => 0,                       // c3
                Diagnostic(ErrorCode.ERR_IllegalSuppression, "c!").WithLocation(35, 18),
                // (36,18): error CS8598: The suppression operator is not allowed in this context
                //                 (1!) => 0,                       // c4
                Diagnostic(ErrorCode.ERR_IllegalSuppression, "1!").WithLocation(36, 18),
                // (37,17): error CS8598: The suppression operator is not allowed in this context
                //                 Type! => 0,                      // c5
                Diagnostic(ErrorCode.ERR_IllegalSuppression, "Type!").WithLocation(37, 17),
                // (38,17): error CS8598: The suppression operator is not allowed in this context
                //                 ContainerType!.Type => 0,        // c6
                Diagnostic(ErrorCode.ERR_IllegalSuppression, "ContainerType").WithLocation(38, 17),
                // (39,17): error CS8598: The suppression operator is not allowed in this context
                //                 ContainerType.Type! => 0,        // c7
                Diagnostic(ErrorCode.ERR_IllegalSuppression, "ContainerType.Type!").WithLocation(39, 17),
                // (40,19): error CS8598: The suppression operator is not allowed in this context
                //                 < c! => 0,                       // c8
                Diagnostic(ErrorCode.ERR_IllegalSuppression, "c!").WithLocation(40, 19)
                );
        }

        [Fact, WorkItem(53484, "https://github.com/dotnet/roslyn/issues/53484")]
        public void ExtendedPropertyPatterns_PointerAccessInPattern()
        {
            var program = @"
public class Type
{
    public unsafe void M(S* s)
    {
        if (0 is s->X) {}
    }
}

public struct S
{
    public int X;
}
";
            var compilation = CreateCompilation(program, parseOptions: TestOptions.RegularWithExtendedPropertyPatterns, options: TestOptions.UnsafeDebugDll);
            compilation.VerifyEmitDiagnostics(
                // (6,18): error CS9133: A constant value of type 'int' is expected
                //         if (0 is s->X) {}
                Diagnostic(ErrorCode.ERR_ConstantValueOfTypeExpected, "s->X").WithArguments("int").WithLocation(6, 18)
            );
        }

        [Fact]
        public void ExtendedPropertyPatterns_SymbolInfo_01()
        {
            var source =
@"
using System;
class Program
{
    public static void Main()
    {
        P p = new P();
        Console.WriteLine(p is { X.Y: {}, Y.X: {} });
    }
}
class P
{
    public P X { get; }
    public P Y;
}
";
            var compilation = CreatePatternCompilation(source);
            compilation.VerifyEmitDiagnostics(
                    // (14,14): warning CS0649: Field 'P.Y' is never assigned to, and will always have its default value null
                    //     public P Y;
                    Diagnostic(ErrorCode.WRN_UnassignedInternalField, "Y").WithArguments("P.Y", "null").WithLocation(14, 14)
                );
            var tree = compilation.SyntaxTrees[0];
            var model = compilation.GetSemanticModel(tree);

            var subpatterns = tree.GetRoot().DescendantNodes().OfType<SubpatternSyntax>().ToArray();
            Assert.Equal(2, subpatterns.Length);

            AssertEmpty(model.GetSymbolInfo(subpatterns[0]));
            AssertEmpty(model.GetSymbolInfo(subpatterns[0].ExpressionColon));
            var xy = subpatterns[0].ExpressionColon.Expression;
            var xySymbol = model.GetSymbolInfo(xy);
            Assert.Equal(CandidateReason.None, xySymbol.CandidateReason);
            Assert.Equal("P P.Y", xySymbol.Symbol.ToTestDisplayString());

            var x = ((MemberAccessExpressionSyntax)subpatterns[0].ExpressionColon.Expression).Expression;
            var xSymbol = model.GetSymbolInfo(x);
            Assert.Equal(CandidateReason.None, xSymbol.CandidateReason);
            Assert.Equal("P P.X { get; }", xSymbol.Symbol.ToTestDisplayString());

            var yName = ((MemberAccessExpressionSyntax)subpatterns[0].ExpressionColon.Expression).Name;
            var yNameSymbol = model.GetSymbolInfo(yName);
            Assert.Equal(CandidateReason.None, yNameSymbol.CandidateReason);
            Assert.Equal("P P.Y", yNameSymbol.Symbol.ToTestDisplayString());

            AssertEmpty(model.GetSymbolInfo(subpatterns[1]));
            AssertEmpty(model.GetSymbolInfo(subpatterns[1].ExpressionColon));
            var yx = subpatterns[1].ExpressionColon.Expression;
            var yxSymbol = model.GetSymbolInfo(yx);
            Assert.NotEqual(default, yxSymbol);
            Assert.Equal(CandidateReason.None, yxSymbol.CandidateReason);
            Assert.Equal("P P.X { get; }", yxSymbol.Symbol.ToTestDisplayString());

            var y = ((MemberAccessExpressionSyntax)subpatterns[1].ExpressionColon.Expression).Expression;
            var ySymbol = model.GetSymbolInfo(y);
            Assert.Equal(CandidateReason.None, ySymbol.CandidateReason);
            Assert.Equal("P P.Y", ySymbol.Symbol.ToTestDisplayString());

            var xName = ((MemberAccessExpressionSyntax)subpatterns[1].ExpressionColon.Expression).Name;
            var xNameSymbol = model.GetSymbolInfo(xName);
            Assert.Equal(CandidateReason.None, xNameSymbol.CandidateReason);
            Assert.Equal("P P.X { get; }", xNameSymbol.Symbol.ToTestDisplayString());
        }

        [Fact]
        public void ExtendedPropertyPatterns_SymbolInfo_02()
        {
            var source =
@"
using System;
class Program
{
    public static void Main()
    {
        P p = null;
        Console.WriteLine(p is { X.Y: {}, Y.X: {}, });
    }
}
interface I1
{
    P X { get; }
    P Y { get; }
}
interface I2
{
    P X { get; }
    P Y { get; }
}
interface P : I1, I2
{
    // X and Y inherited ambiguously
}
";
            var compilation = CreatePatternCompilation(source);
            compilation.VerifyEmitDiagnostics(
                    // (8,34): error CS0229: Ambiguity between 'I1.X' and 'I2.X'
                    //         Console.WriteLine(p is { X.Y: {}, Y.X: {}, });
                    Diagnostic(ErrorCode.ERR_AmbigMember, "X").WithArguments("I1.X", "I2.X").WithLocation(8, 34),
                    // (8,43): error CS0229: Ambiguity between 'I1.Y' and 'I2.Y'
                    //         Console.WriteLine(p is { X.Y: {}, Y.X: {}, });
                    Diagnostic(ErrorCode.ERR_AmbigMember, "Y").WithArguments("I1.Y", "I2.Y").WithLocation(8, 43)
                );
            var tree = compilation.SyntaxTrees[0];
            var model = compilation.GetSemanticModel(tree);

            var subpatterns = tree.GetRoot().DescendantNodes().OfType<SubpatternSyntax>().ToArray();
            Assert.Equal(2, subpatterns.Length);

            AssertEmpty(model.GetSymbolInfo(subpatterns[0]));
            AssertEmpty(model.GetSymbolInfo(subpatterns[0].ExpressionColon));
            var x = ((MemberAccessExpressionSyntax)subpatterns[0].ExpressionColon.Expression).Expression;
            var xSymbol = model.GetSymbolInfo(x);
            Assert.Equal(CandidateReason.Ambiguous, xSymbol.CandidateReason);
            Assert.Null(xSymbol.Symbol);
            Assert.Equal(2, xSymbol.CandidateSymbols.Length);
            Assert.Equal("P I1.X { get; }", xSymbol.CandidateSymbols[0].ToTestDisplayString());
            Assert.Equal("P I2.X { get; }", xSymbol.CandidateSymbols[1].ToTestDisplayString());

            AssertEmpty(model.GetSymbolInfo(subpatterns[1]));
            AssertEmpty(model.GetSymbolInfo(subpatterns[1].ExpressionColon));
            var y = ((MemberAccessExpressionSyntax)subpatterns[1].ExpressionColon.Expression).Expression;
            var ySymbol = model.GetSymbolInfo(y);
            Assert.Equal(CandidateReason.Ambiguous, ySymbol.CandidateReason);
            Assert.Null(ySymbol.Symbol);
            Assert.Equal(2, ySymbol.CandidateSymbols.Length);
            Assert.Equal("P I1.Y { get; }", ySymbol.CandidateSymbols[0].ToTestDisplayString());
            Assert.Equal("P I2.Y { get; }", ySymbol.CandidateSymbols[1].ToTestDisplayString());
        }

        [Fact]
        public void ExtendedPropertyPatterns_SymbolInfo_03()
        {
            var source =
@"
using System;
class Program
{
    public static void Main()
    {
        P p = null;
        Console.WriteLine(p is { X.Y: {}, Y.X: {}, });
    }
}
class P
{
}
";
            var compilation = CreatePatternCompilation(source);
            compilation.VerifyEmitDiagnostics(
                // (8,34): error CS0117: 'P' does not contain a definition for 'X'
                //         Console.WriteLine(p is { X: 3, Y: 4 });
                Diagnostic(ErrorCode.ERR_NoSuchMember, "X").WithArguments("P", "X").WithLocation(8, 34)
                );
            var tree = compilation.SyntaxTrees[0];
            var model = compilation.GetSemanticModel(tree);

            var subpatterns = tree.GetRoot().DescendantNodes().OfType<SubpatternSyntax>().ToArray();
            Assert.Equal(2, subpatterns.Length);

            AssertEmpty(model.GetSymbolInfo(subpatterns[0]));
            AssertEmpty(model.GetSymbolInfo(subpatterns[0].ExpressionColon));
            var x = subpatterns[0].ExpressionColon.Expression;
            var xSymbol = model.GetSymbolInfo(x);
            Assert.Equal(CandidateReason.None, xSymbol.CandidateReason);
            Assert.Null(xSymbol.Symbol);
            Assert.Empty(xSymbol.CandidateSymbols);

            AssertEmpty(model.GetSymbolInfo(subpatterns[1]));
            AssertEmpty(model.GetSymbolInfo(subpatterns[1].ExpressionColon));
            var y = subpatterns[1].ExpressionColon.Expression;
            var ySymbol = model.GetSymbolInfo(y);
            Assert.Equal(CandidateReason.None, ySymbol.CandidateReason);
            Assert.Null(ySymbol.Symbol);
            Assert.Empty(ySymbol.CandidateSymbols);
        }

        [Fact]
        public void ExtendedPropertyPatterns_SymbolInfo_04()
        {
            var source =
@"
using System;
class Program
{
    public static void Main()
    {
        Console.WriteLine(new C() is { X.Y: {} });
        Console.WriteLine(new S() is { Y.X: {} });
    }
}
class C
{
    public S? X { get; }
}
struct S
{
    public C Y;
}
";
            var compilation = CreatePatternCompilation(source);
            compilation.VerifyEmitDiagnostics(
                    // (17,14): warning CS0649: Field 'S.Y' is never assigned to, and will always have its default value null
                    //     public C Y;
                    Diagnostic(ErrorCode.WRN_UnassignedInternalField, "Y").WithArguments("S.Y", "null").WithLocation(17, 14)
                );
            var tree = compilation.SyntaxTrees[0];
            var model = compilation.GetSemanticModel(tree);

            var subpatterns = tree.GetRoot().DescendantNodes().OfType<SubpatternSyntax>().ToArray();
            Assert.Equal(2, subpatterns.Length);

            AssertEmpty(model.GetSymbolInfo(subpatterns[0]));
            AssertEmpty(model.GetSymbolInfo(subpatterns[0].ExpressionColon));
            var xy = subpatterns[0].ExpressionColon.Expression;
            var xySymbol = model.GetSymbolInfo(xy);
            Assert.Equal(CandidateReason.None, xySymbol.CandidateReason);
            Assert.Equal("C S.Y", xySymbol.Symbol.ToTestDisplayString());
            var xyType = model.GetTypeInfo(xy);
            Assert.Equal("C", xyType.Type.ToTestDisplayString());
            Assert.Equal("C", xyType.ConvertedType.ToTestDisplayString());

            var x = ((MemberAccessExpressionSyntax)subpatterns[0].ExpressionColon.Expression).Expression;
            var xSymbol = model.GetSymbolInfo(x);
            Assert.Equal(CandidateReason.None, xSymbol.CandidateReason);
            Assert.Equal("S? C.X { get; }", xSymbol.Symbol.ToTestDisplayString());
            var xType = model.GetTypeInfo(x);
            Assert.Equal("S?", xType.Type.ToTestDisplayString());
            Assert.Equal("S?", xType.ConvertedType.ToTestDisplayString());

            var yName = ((MemberAccessExpressionSyntax)subpatterns[0].ExpressionColon.Expression).Name;
            var yNameSymbol = model.GetSymbolInfo(yName);
            Assert.Equal(CandidateReason.None, yNameSymbol.CandidateReason);
            Assert.Equal("C S.Y", yNameSymbol.Symbol.ToTestDisplayString());
            var yNameType = model.GetTypeInfo(yName);
            Assert.Equal("C", yNameType.Type.ToTestDisplayString());
            Assert.Equal("C", yNameType.ConvertedType.ToTestDisplayString());

            AssertEmpty(model.GetSymbolInfo(subpatterns[1]));
            AssertEmpty(model.GetSymbolInfo(subpatterns[1].ExpressionColon));
            var yx = subpatterns[1].ExpressionColon.Expression;
            var yxSymbol = model.GetSymbolInfo(yx);
            Assert.NotEqual(default, yxSymbol);
            Assert.Equal(CandidateReason.None, yxSymbol.CandidateReason);
            Assert.Equal("S? C.X { get; }", yxSymbol.Symbol.ToTestDisplayString());
            var yxType = model.GetTypeInfo(yx);
            Assert.Equal("S?", yxType.Type.ToTestDisplayString());
            Assert.Equal("S?", yxType.ConvertedType.ToTestDisplayString());

            var y = ((MemberAccessExpressionSyntax)subpatterns[1].ExpressionColon.Expression).Expression;
            var ySymbol = model.GetSymbolInfo(y);
            Assert.Equal(CandidateReason.None, ySymbol.CandidateReason);
            Assert.Equal("C S.Y", ySymbol.Symbol.ToTestDisplayString());
            var yType = model.GetTypeInfo(y);
            Assert.Equal("C", yType.Type.ToTestDisplayString());
            Assert.Equal("C", yType.ConvertedType.ToTestDisplayString());

            var xName = ((MemberAccessExpressionSyntax)subpatterns[1].ExpressionColon.Expression).Name;
            var xNameSymbol = model.GetSymbolInfo(xName);
            Assert.Equal(CandidateReason.None, xNameSymbol.CandidateReason);
            Assert.Equal("S? C.X { get; }", xNameSymbol.Symbol.ToTestDisplayString());
            var xNameType = model.GetTypeInfo(xName);
            Assert.Equal("S?", xNameType.Type.ToTestDisplayString());
            Assert.Equal("S?", xNameType.ConvertedType.ToTestDisplayString());

            var verifier = CompileAndVerify(compilation);
            verifier.VerifyIL("Program.Main", @"
{
  // Code size       92 (0x5c)
  .maxstack  2
  .locals init (C V_0,
                S? V_1,
                S V_2)
  IL_0000:  nop
  IL_0001:  newobj     ""C..ctor()""
  IL_0006:  stloc.0
  IL_0007:  ldloc.0
  IL_0008:  brfalse.s  IL_002b
  IL_000a:  ldloc.0
  IL_000b:  callvirt   ""S? C.X.get""
  IL_0010:  stloc.1
  IL_0011:  ldloca.s   V_1
  IL_0013:  call       ""bool S?.HasValue.get""
  IL_0018:  brfalse.s  IL_002b
  IL_001a:  ldloca.s   V_1
  IL_001c:  call       ""S S?.GetValueOrDefault()""
  IL_0021:  ldfld      ""C S.Y""
  IL_0026:  ldnull
  IL_0027:  cgt.un
  IL_0029:  br.s       IL_002c
  IL_002b:  ldc.i4.0
  IL_002c:  call       ""void System.Console.WriteLine(bool)""
  IL_0031:  nop
  IL_0032:  ldloca.s   V_2
  IL_0034:  initobj    ""S""
  IL_003a:  ldloc.2
  IL_003b:  ldfld      ""C S.Y""
  IL_0040:  stloc.0
  IL_0041:  ldloc.0
  IL_0042:  brfalse.s  IL_0054
  IL_0044:  ldloc.0
  IL_0045:  callvirt   ""S? C.X.get""
  IL_004a:  stloc.1
  IL_004b:  ldloca.s   V_1
  IL_004d:  call       ""bool S?.HasValue.get""
  IL_0052:  br.s       IL_0055
  IL_0054:  ldc.i4.0
  IL_0055:  call       ""void System.Console.WriteLine(bool)""
  IL_005a:  nop
  IL_005b:  ret
}
");
        }

        [Fact]
        public void ExtendedPropertyPatterns_Nullability_Properties()
        {
            var program = @"
#nullable enable
class C {
    C? Prop { get; }
    public void M() {
        if (this is { Prop.Prop: null })
        {
            this.Prop.ToString();
            this.Prop.Prop.ToString(); // 1
        }
        if (this is { Prop.Prop: {} })
        {
            this.Prop.ToString();
            this.Prop.Prop.ToString();
        }
        if (this is { Prop: null } &&
            this is { Prop.Prop: null })
        {
            this.Prop.ToString();
            this.Prop.Prop.ToString(); // 2
        }
        if (this is { Prop: null } ||
            this is { Prop.Prop: null })
        {
            this.Prop.ToString();      // 3
            this.Prop.Prop.ToString(); // 4
        }
    }
}
";
            var compilation = CreateCompilation(program, parseOptions: TestOptions.RegularWithExtendedPropertyPatterns);
            compilation.VerifyEmitDiagnostics(
                    // (9,13): warning CS8602: Dereference of a possibly null reference.
                    //             this.Prop.Prop.ToString(); // 1
                    Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "this.Prop.Prop").WithLocation(9, 13),
                    // (20,13): warning CS8602: Dereference of a possibly null reference.
                    //             this.Prop.Prop.ToString(); // 2
                    Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "this.Prop.Prop").WithLocation(20, 13),
                    // (25,13): warning CS8602: Dereference of a possibly null reference.
                    //             this.Prop.ToString();      // 3
                    Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "this.Prop").WithLocation(25, 13),
                    // (26,13): warning CS8602: Dereference of a possibly null reference.
                    //             this.Prop.Prop.ToString(); // 4
                    Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "this.Prop.Prop").WithLocation(26, 13));
        }

        [Fact]
        public void ExtendedPropertyPatterns_Nullability_AnnotatedFields()
        {
            var program = @"
#nullable enable
class C {
    public void M(C1 c1) {
        if (c1 is { Prop1.Prop2: null })
        {
            c1.Prop1.ToString();
            c1.Prop1.Prop2.ToString(); // 1
        }
        if (c1 is { Prop1.Prop2: {} })
        {
            c1.Prop1.ToString();
            c1.Prop1.Prop2.ToString();
        }
        if (c1 is { Prop1: null } &&
            c1 is { Prop1.Prop2: null })
        {
            c1.Prop1.ToString();
            c1.Prop1.Prop2.ToString(); // 2
        }
        if (c1 is { Prop1: null } ||
            c1 is { Prop1.Prop2: null })
        {
            c1.Prop1.ToString();      // 3
            c1.Prop1.Prop2.ToString(); // 4
        }
    }
}
class C1 { public C2? Prop1 = null; }
class C2 { public object? Prop2 = null; }
";
            var compilation = CreateCompilation(program, parseOptions: TestOptions.RegularWithExtendedPropertyPatterns);
            compilation.VerifyEmitDiagnostics(
                // (8,13): warning CS8602: Dereference of a possibly null reference.
                //             c1.Prop1.Prop2.ToString(); // 1
                Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "c1.Prop1.Prop2").WithLocation(8, 13),
                // (19,13): warning CS8602: Dereference of a possibly null reference.
                //             c1.Prop1.Prop2.ToString(); // 2
                Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "c1.Prop1.Prop2").WithLocation(19, 13),
                // (24,13): warning CS8602: Dereference of a possibly null reference.
                //             c1.Prop1.ToString();      // 3
                Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "c1.Prop1").WithLocation(24, 13),
                // (25,13): warning CS8602: Dereference of a possibly null reference.
                //             c1.Prop1.Prop2.ToString(); // 4
                Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "c1.Prop1.Prop2").WithLocation(25, 13)
                );
        }

        [Fact]
        public void ExtendedPropertyPatterns_Nullability_UnannotatedFields()
        {
            var program = @"
#nullable enable
class C
{
    public void M1(C1 c1)
    {
        if (c1 is { Prop1.Prop2: null })
        {
            c1.Prop1.ToString();
            c1.Prop1.Prop2.ToString(); // 1
        }
        else
        {
            c1.Prop1.ToString();
            c1.Prop1.Prop2.ToString();
        }
    }

    public void M2(C1 c1)
    {
        if (c1 is { Prop1.Prop2: {} })
        {
            c1.Prop1.ToString();
            c1.Prop1.Prop2.ToString();
        }
    }

    public void M3(C1 c1)
    {
        if (c1 is { Prop1: null } &&
            c1 is { Prop1.Prop2: null })
        {
            c1.Prop1.ToString();
            c1.Prop1.Prop2.ToString(); // 2
        }
        else
        {
            c1.Prop1.ToString(); // 3
            c1.Prop1.Prop2.ToString();
        }
    }

    public void M4(C1 c1)
    {
        if (c1 is { Prop1: null } ||
            c1 is { Prop1.Prop2: null })
        {
            c1.Prop1.ToString();      // 4
            c1.Prop1.Prop2.ToString(); // 5
        }
        else
        {
            c1.Prop1.ToString();
            c1.Prop1.Prop2.ToString();
        }
    }
}

class C1 { public C2 Prop1 = null!; }
class C2 { public object Prop2 = null!; }
";
            var compilation = CreateCompilation(program, parseOptions: TestOptions.RegularWithExtendedPropertyPatterns);
            compilation.VerifyEmitDiagnostics(
                // (10,13): warning CS8602: Dereference of a possibly null reference.
                //             c1.Prop1.Prop2.ToString(); // 1
                Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "c1.Prop1.Prop2").WithLocation(10, 13),
                // (34,13): warning CS8602: Dereference of a possibly null reference.
                //             c1.Prop1.Prop2.ToString(); // 2
                Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "c1.Prop1.Prop2").WithLocation(34, 13),
                // (38,13): warning CS8602: Dereference of a possibly null reference.
                //             c1.Prop1.ToString(); // 3
                Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "c1.Prop1").WithLocation(38, 13),
                // (48,13): warning CS8602: Dereference of a possibly null reference.
                //             c1.Prop1.ToString();      // 4
                Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "c1.Prop1").WithLocation(48, 13),
                // (49,13): warning CS8602: Dereference of a possibly null reference.
                //             c1.Prop1.Prop2.ToString(); // 5
                Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "c1.Prop1.Prop2").WithLocation(49, 13)
                );
        }

        [Fact]
        public void ExtendedPropertyPatterns_ExpressionColonInPositionalPattern()
        {
            var source = @"
class C
{
    C Property { get; set; }

    void M()
    {
        _ = this is (Property.Property: null, Property: null);
    }

    public void Deconstruct(out C c1, out C c2)
        => throw null;
}
";
            var compilation = CreateCompilation(source, parseOptions: TestOptions.Regular9);
            compilation.VerifyEmitDiagnostics(
                // (8,22): error CS1001: Identifier expected
                //         _ = this is (Property.Property: null, Property: null);
                Diagnostic(ErrorCode.ERR_IdentifierExpected, "Property.Property").WithLocation(8, 22),
                // (8,39): error CS8773: Feature 'extended property patterns' is not available in C# 9.0. Please use language version 10.0 or greater.
                //         _ = this is (Property.Property: null, Property: null);
                Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion9, ":").WithArguments("extended property patterns", "10.0").WithLocation(8, 39),
                // (8,47): error CS8517: The name 'Property' does not match the corresponding 'Deconstruct' parameter 'c2'.
                //         _ = this is (Property.Property: null, Property: null);
                Diagnostic(ErrorCode.ERR_DeconstructParameterNameMismatch, "Property").WithArguments("Property", "c2").WithLocation(8, 47));
        }

        [Fact]
        public void ExtendedPropertyPatterns_ExpressionColonInITuplePattern()
        {
            var source = @"
class C
{
    void M()
    {
        System.Runtime.CompilerServices.ITuple t = null;
        var r = t is (X.Y: 3, Y.Z: 4);
    }
}
namespace System.Runtime.CompilerServices
{
    public interface ITuple
    {
        int Length { get; }
        object this[int index] { get; }
    }
}
";
            var compilation = CreateCompilation(source, parseOptions: TestOptions.RegularWithExtendedPropertyPatterns);
            compilation.VerifyEmitDiagnostics(
                // (7,23): error CS1001: Identifier expected
                //         var r = t is (X.Y: 3, Y.Z: 4);
                Diagnostic(ErrorCode.ERR_IdentifierExpected, "X.Y").WithLocation(7, 23),
                // (7,31): error CS1001: Identifier expected
                //         var r = t is (X.Y: 3, Y.Z: 4);
                Diagnostic(ErrorCode.ERR_IdentifierExpected, "Y.Z").WithLocation(7, 31)
                );
        }

        [Fact]
        public void ExtendedPropertyPatterns_ExpressionColonInValueTuplePattern()
        {
            var source = @"
class C
{
    void M()
    {
        _ = (1, 2) is (X.Y: 3, Y.Z: 4);
    }
}
namespace System.Runtime.CompilerServices
{
    public interface ITuple
    {
        int Length { get; }
        object this[int index] { get; }
    }
}
";
            var compilation = CreateCompilation(source, parseOptions: TestOptions.RegularWithExtendedPropertyPatterns);
            compilation.VerifyEmitDiagnostics(
                // (6,24): error CS1001: Identifier expected
                //         _ = (1, 2) is (X.Y: 3, Y.Z: 4);
                Diagnostic(ErrorCode.ERR_IdentifierExpected, "X.Y").WithLocation(6, 24),
                // (6,32): error CS1001: Identifier expected
                //         _ = (1, 2) is (X.Y: 3, Y.Z: 4);
                Diagnostic(ErrorCode.ERR_IdentifierExpected, "Y.Z").WithLocation(6, 32)
                );
        }

        [Fact]
        public void ExtendedPropertyPatterns_ObsoleteProperty()
        {
            var program = @"
using System;
class C
{
    public void M1(C1 c1)
    {
        _ = c1 is { Prop1.Prop2: null };
    }
}

class C1
{
    [ObsoleteAttribute(""error Prop1"", true)]
    public C2 Prop1 { get; set; }
}
class C2
{
    [ObsoleteAttribute(""error Prop2"", true)]
    public object Prop2 { get; set; }
}
";
            var compilation = CreateCompilation(program, parseOptions: TestOptions.RegularWithExtendedPropertyPatterns);
            compilation.VerifyEmitDiagnostics(
                // (7,21): error CS0619: 'C1.Prop1' is obsolete: 'error Prop1'
                //         _ = c1 is { Prop1.Prop2: null };
                Diagnostic(ErrorCode.ERR_DeprecatedSymbolStr, "Prop1").WithArguments("C1.Prop1", "error Prop1").WithLocation(7, 21),
                // (7,27): error CS0619: 'C2.Prop2' is obsolete: 'error Prop2'
                //         _ = c1 is { Prop1.Prop2: null };
                Diagnostic(ErrorCode.ERR_DeprecatedSymbolStr, "Prop2").WithArguments("C2.Prop2", "error Prop2").WithLocation(7, 27)
                );
        }

        [Fact]
        public void ExtendedPropertyPatterns_ObsoleteAccessor()
        {
            var program = @"
using System;
class C
{
    public void M1(C1 c1)
    {
        _ = c1 is { Prop1.Prop2: null };
    }
}

class C1
{
    public C2 Prop1
    {
        [ObsoleteAttribute(""error Prop1"", true)]
        get;
        set;
    }
}
class C2
{
    public object Prop2
    {
        get;
        [ObsoleteAttribute(""error Prop2"", true)]
        set;
    }
}
";
            var compilation = CreateCompilation(program, parseOptions: TestOptions.RegularWithExtendedPropertyPatterns);
            compilation.VerifyEmitDiagnostics(
                // (7,21): error CS0619: 'C1.Prop1.get' is obsolete: 'error Prop1'
                //         _ = c1 is { Prop1.Prop2: null };
                Diagnostic(ErrorCode.ERR_DeprecatedSymbolStr, "Prop1.Prop2").WithArguments("C1.Prop1.get", "error Prop1").WithLocation(7, 21)
                );
        }

        [Fact]
        public void ExtendedPropertyPatterns_InaccessibleProperty()
        {
            var program = @"
using System;
class C
{
    public void M1(C1 c1)
    {
        _ = c1 is { Prop1.Prop2: null };
    }
}

class C1
{
    private C2 Prop1 { get; set; }
}
class C2
{
    private object Prop2 { get; set; }
}
";
            var compilation = CreateCompilation(program, parseOptions: TestOptions.RegularWithExtendedPropertyPatterns);
            compilation.VerifyEmitDiagnostics(
                // (7,21): error CS0122: 'C1.Prop1' is inaccessible due to its protection level
                //         _ = c1 is { Prop1.Prop2: null };
                Diagnostic(ErrorCode.ERR_BadAccess, "Prop1").WithArguments("C1.Prop1").WithLocation(7, 21)
                );
        }

        [Fact]
        public void ExtendedPropertyPatterns_ExpressionTree()
        {
            var program = @"
using System;
using System.Collections.Generic;
using System.Linq.Expressions;
class C
{
    public void M1(C1 c1)
    {
        Expression<Func<C1, bool>> f = (c1) => c1 is { Prop1.Prop2: null };
    }
}

class C1
{
    public C2 Prop1 { get; set; }
}
class C2
{
    public object Prop2 { get; set; }
}
";
            var compilation = CreateCompilation(program, parseOptions: TestOptions.RegularWithExtendedPropertyPatterns);
            compilation.VerifyEmitDiagnostics(
                // (9,48): error CS8122: An expression tree may not contain an 'is' pattern-matching operator.
                //         Expression<Func<C1, bool>> f = (c1) => c1 is { Prop1.Prop2: null };
                Diagnostic(ErrorCode.ERR_ExpressionTreeContainsIsMatch, "c1 is { Prop1.Prop2: null }").WithLocation(9, 48)
                );
        }

        [Fact]
        public void ExtendedPropertyPatterns_EvaluationOrder()
        {
            var program = @"
if (new C() is { Prop1.True: true, Prop1.Prop2: not null })
{
    System.Console.WriteLine(""matched1"");
}

if (new C() is { Prop1.Prop2: not null, Prop1.True: true })
{
    System.Console.WriteLine(""matched2"");
}

if (new C() is { Prop1.Prop2: not null, Prop2.True: true })
{
    System.Console.WriteLine(""matched3"");
}

if (new C() is { Prop1.Prop2.Prop3.True: true })
{
    System.Console.WriteLine(""matched3"");
}

if (new C() is { Prop1: { Prop2.Prop3.True: true } })
{
    System.Console.WriteLine(""matched4"");
}

if (new C() is { Prop1.True: false, Prop1.Prop2: not null })
{
    throw null;
}

class C
{
    public C Prop1 { get { System.Console.Write(""Prop1 ""); return this; } }
    public C Prop2 { get { System.Console.Write(""Prop2 ""); return this; } }
    public C Prop3 { get { System.Console.Write(""Prop3 ""); return this; } }
    public bool True { get { System.Console.Write(""True ""); return true; } }
}
";
            CompileAndVerify(program, parseOptions: TestOptions.RegularWithExtendedPropertyPatterns, expectedOutput: @"
Prop1 True Prop2 matched1
Prop1 Prop2 True matched2
Prop1 Prop2 Prop2 True matched3
Prop1 Prop2 Prop3 True matched3
Prop1 Prop2 Prop3 True matched4
Prop1 True");
        }

        [Fact]
        public void ExtendedPropertyPatterns_StaticMembers()
        {
            var program = @"
_ = new C() is { Static: null }; // 1
_ = new C() is { Instance.Static: null }; // 2
_ = new C() is { Static.Instance: null }; // 3

class C
{
    public C Instance { get; set; }
    public static C Static { get; set; }
}
";
            var comp = CreateCompilation(program, parseOptions: TestOptions.RegularWithExtendedPropertyPatterns);
            comp.VerifyEmitDiagnostics(
                // (2,18): error CS0176: Member 'C.Static' cannot be accessed with an instance reference; qualify it with a type name instead
                // _ = new C() is { Static: null }; // 1
                Diagnostic(ErrorCode.ERR_ObjectProhibited, "Static").WithArguments("C.Static").WithLocation(2, 18),
                // (3,27): error CS0176: Member 'C.Static' cannot be accessed with an instance reference; qualify it with a type name instead
                // _ = new C() is { Instance.Static: null }; // 2
                Diagnostic(ErrorCode.ERR_ObjectProhibited, "Static").WithArguments("C.Static").WithLocation(3, 27),
                // (4,18): error CS0176: Member 'C.Static' cannot be accessed with an instance reference; qualify it with a type name instead
                // _ = new C() is { Static.Instance: null }; // 3
                Diagnostic(ErrorCode.ERR_ObjectProhibited, "Static").WithArguments("C.Static").WithLocation(4, 18)
                );
        }

        [Fact]
        public void ExtendedPropertyPatterns_Exhaustiveness()
        {
            var program = @"
_ = new C() switch // 1
{
    { Prop.True: true } => 0
};

_ = new C() switch
{
    { Prop.True: true } => 0,
    { Prop.True: false } => 0
};

#nullable enable
_ = new C() switch // 2
{
    { Prop.Prop: null } => 0
};

class C
{
    public C Prop { get => throw null!; }
    public bool True { get => throw null!; }
}
";
            var comp = CreateCompilation(program, parseOptions: TestOptions.RegularWithExtendedPropertyPatterns);
            comp.VerifyEmitDiagnostics(
                // (2,13): warning CS8509: The switch expression does not handle all possible values of its input type (it is not exhaustive). For example, the pattern '{ Prop: { True: false } }' is not covered.
                // _ = new C() switch // 1
                Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustive, "switch").WithArguments("{ Prop: { True: false } }").WithLocation(2, 13),
                // (14,13): warning CS8509: The switch expression does not handle all possible values of its input type (it is not exhaustive). For example, the pattern '{ Prop: { Prop: not null } }' is not covered.
                // _ = new C() switch // 2
                Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustive, "switch").WithArguments("{ Prop: { Prop: not null } }").WithLocation(14, 13)
                );
        }

        [Fact, WorkItem(55184, "https://github.com/dotnet/roslyn/issues/55184")]
        public void Repro55184()
        {
            var source = @"
var x = """";

_ = x is { Error: { Length: > 0 } };
_ = x is { Error.Length: > 0 };
_ = x is { Length: { Error: > 0 } };
_ = x is { Length.Error: > 0 };
";
            var comp = CreateCompilation(source);
            comp.VerifyDiagnostics(
                // (4,12): error CS0117: 'string' does not contain a definition for 'Error'
                // _ = x is { Error: { Length: > 0 } };
                Diagnostic(ErrorCode.ERR_NoSuchMember, "Error").WithArguments("string", "Error").WithLocation(4, 12),
                // (5,12): error CS0117: 'string' does not contain a definition for 'Error'
                // _ = x is { Error.Length: > 0 };
                Diagnostic(ErrorCode.ERR_NoSuchMember, "Error").WithArguments("string", "Error").WithLocation(5, 12),
                // (6,22): error CS0117: 'int' does not contain a definition for 'Error'
                // _ = x is { Length: { Error: > 0 } };
                Diagnostic(ErrorCode.ERR_NoSuchMember, "Error").WithArguments("int", "Error").WithLocation(6, 22),
                // (7,19): error CS0117: 'int' does not contain a definition for 'Error'
                // _ = x is { Length.Error: > 0 };
                Diagnostic(ErrorCode.ERR_NoSuchMember, "Error").WithArguments("int", "Error").WithLocation(7, 19)
                );
        }

        private const string INumberBaseDefinition = """
            namespace System.Numerics;
            public interface INumberBase<T> where T : INumberBase<T> {}
            """;

        [Fact]
        public void ForbiddenOnTypeParametersConstrainedToINumberBase_01()
        {
            var source = """
                #pragma warning disable 8321 // Unused local function
                using System.Numerics;

                void M<T>(T t) where T : INumberBase<T>
                {
                    int o = t switch
                    {
                        1 => 1, // 1
                        > 1 => 2, // 2
                        int => 3, // OK
                        [] => 4, // 3
                        (_) => 5, // OK
                        "" => 6, // OK
                        { } => 7, // OK
                        var x => 8, // OK
                        _ => 9 // Ok
                    };
                }
                """;

            var comp = CreateCompilation(new[] { source, INumberBaseDefinition });
            comp.VerifyDiagnostics(
                // (8,9): error CS9060: Cannot use a numeric constant or relational pattern on 'T' because it inherits from or extends 'INumberBase<T>'. Consider using a type pattern to narrow to a specific numeric type.
                //         1 => 1, // 1
                Diagnostic(ErrorCode.ERR_CannotMatchOnINumberBase, "1").WithArguments("T").WithLocation(8, 9),
                // (9,9): error CS9060: Cannot use a numeric constant or relational pattern on 'T' because it inherits from or extends 'INumberBase<T>'. Consider using a type pattern to narrow to a specific numeric type.
                //         > 1 => 2, // 2
                Diagnostic(ErrorCode.ERR_CannotMatchOnINumberBase, "> 1").WithArguments("T").WithLocation(9, 9),
                // (11,9): error CS8985: List patterns may not be used for a value of type 'T'. No suitable 'Length' or 'Count' property was found.
                //         [] => 4, // 3
                Diagnostic(ErrorCode.ERR_ListPatternRequiresLength, "[]").WithArguments("T").WithLocation(11, 9),
                // (11,9): error CS0518: Predefined type 'System.Index' is not defined or imported
                //         [] => 4, // 3
                Diagnostic(ErrorCode.ERR_PredefinedTypeNotFound, "[]").WithArguments("System.Index").WithLocation(11, 9),
                // (11,9): error CS0021: Cannot apply indexing with [] to an expression of type 'T'
                //         [] => 4, // 3
                Diagnostic(ErrorCode.ERR_BadIndexLHS, "[]").WithArguments("T").WithLocation(11, 9)
            );
        }

        [Fact]
        public void ForbiddenOnTypeParametersConstrainedToINumberBase_02()
        {
            var source = """
                #pragma warning disable 8321 // Unused local function
                using System.Numerics;

                void M<T>(T t) where T : struct, INumberBase<T>
                {
                    int o = t switch
                    {
                        1 => 1, // 1
                        > 1 => 2, // 2
                        int => 3, // OK
                        [] => 4, // 3
                        (_) => 5, // OK
                        "" => 6, // 4
                        { } => 7, // OK
                        var x => 8, // OK
                        _ => 9 // Ok
                    };
                }
                """;

            var comp = CreateCompilation(new[] { source, INumberBaseDefinition });
            comp.VerifyDiagnostics(
                // (8,9): error CS9060: Cannot use a numeric constant or relational pattern on 'T' because it inherits from or extends 'INumberBase<T>'. Consider using a type pattern to narrow to a specific numeric type.
                //         1 => 1, // 1
                Diagnostic(ErrorCode.ERR_CannotMatchOnINumberBase, "1").WithArguments("T").WithLocation(8, 9),
                // (9,9): error CS9060: Cannot use a numeric constant or relational pattern on 'T' because it inherits from or extends 'INumberBase<T>'. Consider using a type pattern to narrow to a specific numeric type.
                //         > 1 => 2, // 2
                Diagnostic(ErrorCode.ERR_CannotMatchOnINumberBase, "> 1").WithArguments("T").WithLocation(9, 9),
                // (11,9): error CS8985: List patterns may not be used for a value of type 'T'. No suitable 'Length' or 'Count' property was found.
                //         [] => 4, // 3
                Diagnostic(ErrorCode.ERR_ListPatternRequiresLength, "[]").WithArguments("T").WithLocation(11, 9),
                // (11,9): error CS0518: Predefined type 'System.Index' is not defined or imported
                //         [] => 4, // 3
                Diagnostic(ErrorCode.ERR_PredefinedTypeNotFound, "[]").WithArguments("System.Index").WithLocation(11, 9),
                // (11,9): error CS0021: Cannot apply indexing with [] to an expression of type 'T'
                //         [] => 4, // 3
                Diagnostic(ErrorCode.ERR_BadIndexLHS, "[]").WithArguments("T").WithLocation(11, 9),
                // (13,9): error CS8121: An expression of type 'T' cannot be handled by a pattern of type 'string'.
                //         "" => 6, // 4
                Diagnostic(ErrorCode.ERR_PatternWrongType, @"""""").WithArguments("T", "string").WithLocation(13, 9)
            );
        }

        [Fact]
        public void ForbiddenOnTypeParametersConstrainedToINumberBase_MultipleReferences_01()
        {
            var source = """
                #pragma warning disable 8321 // Unused local function
                using System.Numerics;

                void M<T>(T t) where T : struct, INumberBase<T>
                {
                    int o = t switch
                    {
                        1 => 1, // 1
                        > 1 => 2, // 2
                        int => 3, // OK
                        [] => 4, // 3
                        (_) => 5, // OK
                        "" => 6, // 4
                        { } => 7, // OK
                        var x => 8, // OK
                        _ => 9 // Ok
                    };
                }
                """;

            var ref1 = CreateCompilation(INumberBaseDefinition, assemblyName: "A").EmitToImageReference();
            var ref2 = CreateCompilation(INumberBaseDefinition, assemblyName: "B").EmitToImageReference();

            var comp = CreateCompilation(new[] { source }, references: new[] { ref1, ref2 });
            comp.VerifyDiagnostics(
                // (4,34): error CS0433: The type 'INumberBase<T>' exists in both 'A, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null' and 'B, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null'
                // void M<T>(T t) where T : struct, INumberBase<T>
                Diagnostic(ErrorCode.ERR_SameFullNameAggAgg, "INumberBase<T>").WithArguments("A, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null", "System.Numerics.INumberBase<T>", "B, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null").WithLocation(4, 34),
                // (11,9): error CS8985: List patterns may not be used for a value of type 'T'. No suitable 'Length' or 'Count' property was found.
                //         [] => 4, // 3
                Diagnostic(ErrorCode.ERR_ListPatternRequiresLength, "[]").WithArguments("T").WithLocation(11, 9),
                // (11,9): error CS0518: Predefined type 'System.Index' is not defined or imported
                //         [] => 4, // 3
                Diagnostic(ErrorCode.ERR_PredefinedTypeNotFound, "[]").WithArguments("System.Index").WithLocation(11, 9),
                // (11,9): error CS0021: Cannot apply indexing with [] to an expression of type 'T'
                //         [] => 4, // 3
                Diagnostic(ErrorCode.ERR_BadIndexLHS, "[]").WithArguments("T").WithLocation(11, 9),
                // (13,9): error CS8121: An expression of type 'T' cannot be handled by a pattern of type 'string'.
                //         "" => 6, // 4
                Diagnostic(ErrorCode.ERR_PatternWrongType, @"""""").WithArguments("T", "string").WithLocation(13, 9)
            );
        }

        [Fact]
        public void ForbiddenOnTypeParametersConstrainedToINumberBase_MultipleReferences_02()
        {
            var source = """
                extern alias A;
                #pragma warning disable 8321 // Unused local function

                void M<T>(T t) where T : struct, A::System.Numerics.INumberBase<T>
                {
                    int o = t switch
                    {
                        1 => 1, // 1
                        > 1 => 2, // 2
                        int => 3, // OK
                        [] => 4, // 3
                        (_) => 5, // OK
                        "" => 6, // 4
                        { } => 7, // OK
                        var x => 8, // OK
                        _ => 9 // Ok
                    };
                }
                """;

            var ref1 = CreateCompilation(INumberBaseDefinition, assemblyName: "A").EmitToImageReference(aliases: ImmutableArray.Create("A"));
            var ref2 = CreateCompilation(INumberBaseDefinition, assemblyName: "B").EmitToImageReference();

            var comp = CreateCompilation(new[] { source }, references: new[] { ref1, ref2 });
            comp.VerifyDiagnostics(
                // (8,9): error CS9060: Cannot use a numeric constant or relational pattern on 'T' because it inherits from or extends 'INumberBase<T>'. Consider using a type pattern to narrow to a specific numeric type.
                //         1 => 1, // 1
                Diagnostic(ErrorCode.ERR_CannotMatchOnINumberBase, "1").WithArguments("T").WithLocation(8, 9),
                // (9,9): error CS9060: Cannot use a numeric constant or relational pattern on 'T' because it inherits from or extends 'INumberBase<T>'. Consider using a type pattern to narrow to a specific numeric type.
                //         > 1 => 2, // 2
                Diagnostic(ErrorCode.ERR_CannotMatchOnINumberBase, "> 1").WithArguments("T").WithLocation(9, 9),
                // (11,9): error CS8985: List patterns may not be used for a value of type 'T'. No suitable 'Length' or 'Count' property was found.
                //         [] => 4, // 3
                Diagnostic(ErrorCode.ERR_ListPatternRequiresLength, "[]").WithArguments("T").WithLocation(11, 9),
                // (11,9): error CS0518: Predefined type 'System.Index' is not defined or imported
                //         [] => 4, // 3
                Diagnostic(ErrorCode.ERR_PredefinedTypeNotFound, "[]").WithArguments("System.Index").WithLocation(11, 9),
                // (11,9): error CS0021: Cannot apply indexing with [] to an expression of type 'T'
                //         [] => 4, // 3
                Diagnostic(ErrorCode.ERR_BadIndexLHS, "[]").WithArguments("T").WithLocation(11, 9),
                // (13,9): error CS8121: An expression of type 'T' cannot be handled by a pattern of type 'string'.
                //         "" => 6, // 4
                Diagnostic(ErrorCode.ERR_PatternWrongType, @"""""").WithArguments("T", "string").WithLocation(13, 9)
            );
        }

        [Theory]
        [InlineData("class")]
        [InlineData("struct")]
        [InlineData("interface")]
        public void ForbiddenOnTypesInheritingFromINumberBase(string type)
        {
            var source = $$"""
                #pragma warning disable 8321 // Unused local function
                using System.Numerics;

                C c = default(C);
                int o = c switch
                {
                    1 => 1, // 1
                    > 1 => 2, // 2
                    int => 3, // 3
                    [] => 4, // 4
                    (_) => 5, // OK
                    "" => 6, // 5
                    { } => 7, // OK
                    var x => 8, // OK
                    _ => 9 // Ok
                };

                {{type}} C : INumberBase<C>
                {
                }
                """;

            var comp = CreateCompilation(new[] { source, INumberBaseDefinition });
            comp.VerifyDiagnostics(
                // (7,5): error CS0029: Cannot implicitly convert type 'int' to 'C'
                //     1 => 1, // 1
                Diagnostic(ErrorCode.ERR_NoImplicitConv, "1").WithArguments("int", "C").WithLocation(7, 5),
                // (8,5): error CS8781: Relational patterns may not be used for a value of type 'C'.
                //     > 1 => 2, // 2
                Diagnostic(ErrorCode.ERR_UnsupportedTypeForRelationalPattern, "> 1").WithArguments("C").WithLocation(8, 5),
                // (8,7): error CS0029: Cannot implicitly convert type 'int' to 'C'
                //     > 1 => 2, // 2
                Diagnostic(ErrorCode.ERR_NoImplicitConv, "1").WithArguments("int", "C").WithLocation(8, 7),
                // (9,5): error CS8121: An expression of type 'C' cannot be handled by a pattern of type 'int'.
                //     int => 3, // 3
                Diagnostic(ErrorCode.ERR_PatternWrongType, "int").WithArguments("C", "int").WithLocation(9, 5),
                // (10,5): error CS8985: List patterns may not be used for a value of type 'C'. No suitable 'Length' or 'Count' property was found.
                //     [] => 4, // 4
                Diagnostic(ErrorCode.ERR_ListPatternRequiresLength, "[]").WithArguments("C").WithLocation(10, 5),
                // (10,5): error CS0518: Predefined type 'System.Index' is not defined or imported
                //     [] => 4, // 4
                Diagnostic(ErrorCode.ERR_PredefinedTypeNotFound, "[]").WithArguments("System.Index").WithLocation(10, 5),
                // (10,5): error CS0021: Cannot apply indexing with [] to an expression of type 'C'
                //     [] => 4, // 4
                Diagnostic(ErrorCode.ERR_BadIndexLHS, "[]").WithArguments("C").WithLocation(10, 5),
                // (12,5): error CS0029: Cannot implicitly convert type 'string' to 'C'
                //     "" => 6, // 5
                Diagnostic(ErrorCode.ERR_NoImplicitConv, @"""""").WithArguments("string", "C").WithLocation(12, 5)
            );
        }

        [Theory]
        [InlineData("class")]
        [InlineData("struct")]
        [InlineData("interface")]
        public void ForbiddenOnTypesInheritingFromINumberBase_MultipleReferences01(string type)
        {
            var source = $$"""
                #pragma warning disable 8321 // Unused local function
                using System.Numerics;

                C c = default(C);
                int o = c switch
                {
                    1 => 1, // 1
                    > 1 => 2, // 2
                    int => 3, // 3
                    [] => 4, // 4
                    (_) => 5, // OK
                    "" => 6, // 5
                    { } => 7, // OK
                    var x => 8, // OK
                    _ => 9 // Ok
                };

                {{type}} C :
                    INumberBase<C>
                {
                }
                """;

            var ref1 = CreateCompilation(INumberBaseDefinition, assemblyName: "A").EmitToImageReference();
            var ref2 = CreateCompilation(INumberBaseDefinition, assemblyName: "B").EmitToImageReference();

            var comp = CreateCompilation(new[] { source }, references: new[] { ref1, ref2 });
            comp.VerifyDiagnostics(
                // (7,5): error CS0029: Cannot implicitly convert type 'int' to 'C'
                //     1 => 1, // 1
                Diagnostic(ErrorCode.ERR_NoImplicitConv, "1").WithArguments("int", "C").WithLocation(7, 5),
                // (8,5): error CS8781: Relational patterns may not be used for a value of type 'C'.
                //     > 1 => 2, // 2
                Diagnostic(ErrorCode.ERR_UnsupportedTypeForRelationalPattern, "> 1").WithArguments("C").WithLocation(8, 5),
                // (8,7): error CS0029: Cannot implicitly convert type 'int' to 'C'
                //     > 1 => 2, // 2
                Diagnostic(ErrorCode.ERR_NoImplicitConv, "1").WithArguments("int", "C").WithLocation(8, 7),
                // (9,5): error CS8121: An expression of type 'C' cannot be handled by a pattern of type 'int'.
                //     int => 3, // 3
                Diagnostic(ErrorCode.ERR_PatternWrongType, "int").WithArguments("C", "int").WithLocation(9, 5),
                // (10,5): error CS8985: List patterns may not be used for a value of type 'C'. No suitable 'Length' or 'Count' property was found.
                //     [] => 4, // 4
                Diagnostic(ErrorCode.ERR_ListPatternRequiresLength, "[]").WithArguments("C").WithLocation(10, 5),
                // (10,5): error CS0518: Predefined type 'System.Index' is not defined or imported
                //     [] => 4, // 4
                Diagnostic(ErrorCode.ERR_PredefinedTypeNotFound, "[]").WithArguments("System.Index").WithLocation(10, 5),
                // (10,5): error CS0021: Cannot apply indexing with [] to an expression of type 'C'
                //     [] => 4, // 4
                Diagnostic(ErrorCode.ERR_BadIndexLHS, "[]").WithArguments("C").WithLocation(10, 5),
                // (12,5): error CS0029: Cannot implicitly convert type 'string' to 'C'
                //     "" => 6, // 5
                Diagnostic(ErrorCode.ERR_NoImplicitConv, @"""""").WithArguments("string", "C").WithLocation(12, 5),
                // (19,5): error CS0433: The type 'INumberBase<T>' exists in both 'A, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null' and 'B, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null'
                //     INumberBase<C>
                Diagnostic(ErrorCode.ERR_SameFullNameAggAgg, "INumberBase<C>").WithArguments("A, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null", "System.Numerics.INumberBase<T>", "B, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null").WithLocation(19, 5)
            );
        }

        [Theory]
        [InlineData("class")]
        [InlineData("struct")]
        [InlineData("interface")]
        public void ForbiddenOnTypeParametersInheritingFromINumberBase_MultipleReferences02(string type)
        {
            var source = $$"""
                extern alias A;
                #pragma warning disable 8321 // Unused local function

                C c = default(C);
                int o = c switch
                {
                    1 => 1, // 1
                    > 1 => 2, // 2
                    int => 3, // 3
                    [] => 4, // 4
                    (_) => 5, // OK
                    "" => 6, // 5
                    { } => 7, // OK
                    var x => 8, // OK
                    _ => 9 // Ok
                };

                {{type}} C : A::System.Numerics.INumberBase<C>
                {
                }
                """;

            var ref1 = CreateCompilation(INumberBaseDefinition).EmitToImageReference(aliases: ImmutableArray.Create("A"));
            var ref2 = CreateCompilation(INumberBaseDefinition).EmitToImageReference();

            var comp = CreateCompilation(new[] { source }, references: new[] { ref1, ref2 });
            comp.VerifyDiagnostics(
                // (7,5): error CS0029: Cannot implicitly convert type 'int' to 'C'
                //     1 => 1, // 1
                Diagnostic(ErrorCode.ERR_NoImplicitConv, "1").WithArguments("int", "C").WithLocation(7, 5),
                // (8,5): error CS8781: Relational patterns may not be used for a value of type 'C'.
                //     > 1 => 2, // 2
                Diagnostic(ErrorCode.ERR_UnsupportedTypeForRelationalPattern, "> 1").WithArguments("C").WithLocation(8, 5),
                // (8,7): error CS0029: Cannot implicitly convert type 'int' to 'C'
                //     > 1 => 2, // 2
                Diagnostic(ErrorCode.ERR_NoImplicitConv, "1").WithArguments("int", "C").WithLocation(8, 7),
                // (9,5): error CS8121: An expression of type 'C' cannot be handled by a pattern of type 'int'.
                //     int => 3, // 3
                Diagnostic(ErrorCode.ERR_PatternWrongType, "int").WithArguments("C", "int").WithLocation(9, 5),
                // (10,5): error CS8985: List patterns may not be used for a value of type 'C'. No suitable 'Length' or 'Count' property was found.
                //     [] => 4, // 4
                Diagnostic(ErrorCode.ERR_ListPatternRequiresLength, "[]").WithArguments("C").WithLocation(10, 5),
                // (10,5): error CS0518: Predefined type 'System.Index' is not defined or imported
                //     [] => 4, // 4
                Diagnostic(ErrorCode.ERR_PredefinedTypeNotFound, "[]").WithArguments("System.Index").WithLocation(10, 5),
                // (10,5): error CS0021: Cannot apply indexing with [] to an expression of type 'C'
                //     [] => 4, // 4
                Diagnostic(ErrorCode.ERR_BadIndexLHS, "[]").WithArguments("C").WithLocation(10, 5),
                // (12,5): error CS0029: Cannot implicitly convert type 'string' to 'C'
                //     "" => 6, // 5
                Diagnostic(ErrorCode.ERR_NoImplicitConv, @"""""").WithArguments("string", "C").WithLocation(12, 5)
            );
        }

        private const string INumberBaseBCL = """
            namespace System
            {
                using System.Numerics;

                public class Object {}
                public class Void {}
                public class ValueType {}
                public class String {}
                public class Enum {}
                public struct Nullable<T> where T : struct {}
                public struct Byte : INumberBase<Byte> {}
                public struct SByte : INumberBase<SByte> {}
                public struct Int16 : INumberBase<Int16> {}
                public struct Char : INumberBase<Char> {}
                public struct UInt16 : INumberBase<UInt16> {}
                public struct Int32 : INumberBase<Int32> {}
                public struct UInt32 : INumberBase<UInt32> {}
                public struct Int64 : INumberBase<Int64> {}
                public struct UInt64 : INumberBase<UInt64> {}
                public struct Single : INumberBase<Single> {}
                public struct Double : INumberBase<Double> {}
                public struct Decimal : INumberBase<Decimal> { public Decimal(int value) {} }
                public struct IntPtr : INumberBase<IntPtr> {}
                public struct UIntPtr : INumberBase<UIntPtr> {}
            }
            """;

        [Theory]
        [InlineData("byte")]
        [InlineData("sbyte")]
        [InlineData("short")]
        [InlineData("ushort")]
        [InlineData("int")]
        [InlineData("uint")]
        [InlineData("nint")]
        [InlineData("nuint")]
        [InlineData("long")]
        [InlineData("ulong")]
        [InlineData("float")]
        [InlineData("double")]
        [InlineData("decimal")]
        public void MatchingOnConstantConversionsWithINumberBaseIsAllowed(string inputType)
        {
            var source = $$"""
                {{inputType}} i = 1;
                _ = i switch
                {
                    1 => 1,
                    > 1 => 2,
                    _ => 3
                };
                """;

            var comp = CreateEmptyCompilation(new[] { source, INumberBaseBCL, INumberBaseDefinition });
            comp.VerifyDiagnostics();
        }

        [Theory]
        [InlineData("byte")]
        [InlineData("sbyte")]
        [InlineData("short")]
        [InlineData("ushort")]
        [InlineData("int")]
        [InlineData("uint")]
        [InlineData("nint")]
        [InlineData("nuint")]
        [InlineData("long")]
        [InlineData("ulong")]
        [InlineData("float")]
        [InlineData("double")]
        [InlineData("decimal")]
        public void MatchingOnConstantConversionsWithINumberBaseIsAllowed_Nullable(string inputType)
        {
            var source = $$"""
                {{inputType}}? i = 1;
                _ = i switch
                {
                    1 => 1,
                    > 1 => 2,
                    _ => 3
                };
                """;

            var comp = CreateEmptyCompilation(new[] { source, INumberBaseBCL, INumberBaseDefinition });
            comp.VerifyDiagnostics();
        }

        [Fact]
        public void MatchingOnConstantConversionsWithINumberBaseIsDisallowed_TypePatternToINumberBaseInt()
        {
            var source = """
                using System.Numerics;
                int i = 1;
                _ = ((INumberBase<int>)i) switch
                {
                    1 => 1,
                    > 1 => 2,
                    _ => 3
                };
                """;

            var comp = CreateEmptyCompilation(new[] { source, INumberBaseBCL, INumberBaseDefinition });
            comp.VerifyDiagnostics(
                // (5,5): error CS9060: Cannot use a numeric constant or relational pattern on 'INumberBase<int>' because it inherits from or extends 'INumberBase<T>'. Consider using a type pattern to narrow to a specific numeric type.
                //     1 => 1,
                Diagnostic(ErrorCode.ERR_CannotMatchOnINumberBase, "1").WithArguments("System.Numerics.INumberBase<int>").WithLocation(5, 5),
                // (6,5): error CS9060: Cannot use a numeric constant or relational pattern on 'INumberBase<int>' because it inherits from or extends 'INumberBase<T>'. Consider using a type pattern to narrow to a specific numeric type.
                //     > 1 => 2,
                Diagnostic(ErrorCode.ERR_CannotMatchOnINumberBase, "> 1").WithArguments("System.Numerics.INumberBase<int>").WithLocation(6, 5)
            );
        }

        [Theory]
        [InlineData("byte")]
        [InlineData("sbyte")]
        [InlineData("short")]
        [InlineData("ushort")]
        [InlineData("uint")]
        [InlineData("nint")]
        [InlineData("nuint")]
        [InlineData("long")]
        [InlineData("ulong")]
        [InlineData("float")]
        [InlineData("double")]
        [InlineData("decimal")]
        public void MatchingOnConstantConversionsWithINumberBaseIsAllowed_TypePatternToINumberBaseT(string inputType)
        {
            var source = $$"""
                using System.Numerics;
                {{inputType}} i = 1;
                _ = ((INumberBase<{{inputType}}>)i) switch
                {
                    1 => 1,
                    > 1 => 2,
                    _ => 3
                };
                """;

            var comp = CreateEmptyCompilation(new[] { source, INumberBaseBCL, INumberBaseDefinition });
            comp.VerifyDiagnostics(
                // (5,5): error CS0029: Cannot implicitly convert type 'int' to 'System.Numerics.INumberBase<nint>'
                //     1 => 1,
                Diagnostic(ErrorCode.ERR_NoImplicitConv, "1").WithArguments("int", $"System.Numerics.INumberBase<{inputType}>").WithLocation(5, 5),
                // (6,5): error CS8781: Relational patterns may not be used for a value of type 'System.Numerics.INumberBase<nint>'.
                //     > 1 => 2,
                Diagnostic(ErrorCode.ERR_UnsupportedTypeForRelationalPattern, "> 1").WithArguments($"System.Numerics.INumberBase<{inputType}>").WithLocation(6, 5),
                // (6,7): error CS0029: Cannot implicitly convert type 'int' to 'System.Numerics.INumberBase<nint>'
                //     > 1 => 2,
                Diagnostic(ErrorCode.ERR_NoImplicitConv, "1").WithArguments("int", $"System.Numerics.INumberBase<{inputType}>").WithLocation(6, 7)
            );
        }

        [Fact]
        public void MatchingOnINumberBaseIsAllowed_ClassNotInterface()
        {
            var source = """
                #pragma warning disable 8321 // Unused local function
                using System.Numerics;

                void M<T>(T t) where T : INumberBase<T>
                {
                    int o = t switch
                    {
                        1 => 1,
                        > 1 => 2,
                        _ => 3
                    };
                }

                namespace System.Numerics
                {
                    public class INumberBase<T> where T : INumberBase<T>
                    {
                    }
                }
                """;

            var comp = CreateCompilation(source);
            comp.VerifyDiagnostics();
        }

        [Fact]
        public void MatchingOnINumberBaseIsAllowed_WrongArity()
        {
            var source = """
                #pragma warning disable 8321 // Unused local function
                using System.Numerics;

                void M1<T1, T2>(T1 t) where T1 : INumberBase<T1, T2>
                {
                    int o = t switch
                    {
                        1 => 1,
                        > 1 => 2,
                        _ => 3
                    };
                }

                void M2<T>(T t) where T : INumberBase
                {
                    int o = t switch
                    {
                        1 => 1,
                        > 1 => 2,
                        _ => 3
                    };
                }

                namespace System.Numerics
                {
                    public interface INumberBase<T1, T2> where T1 : INumberBase<T1, T2>
                    {
                    }

                    public interface INumberBase
                    {
                    }
                }
                """;

            var comp = CreateCompilation(source);
            comp.VerifyDiagnostics();
        }

        [Fact]
        public void MatchingOnINumberBaseIsAllowed_WrongNamespace()
        {
            var source = """
                #pragma warning disable 8321 // Unused local function
                using System;

                void M<T>(T t) where T : INumberBase<T>
                {
                    int o = t switch
                    {
                        1 => 1,
                        > 1 => 2,
                        _ => 3
                    };
                }

                namespace System
                {
                    public interface INumberBase<T> where T : INumberBase<T>
                    {
                    }
                }
                """;

            var comp = CreateCompilation(source);
            comp.VerifyDiagnostics();
        }

        [Fact]
        public void MatchingOnINumberBaseIsAllowed_NestedType()
        {
            var source = """
                #pragma warning disable 8321 // Unused local function
                using static System.Numerics.Outer;

                void M<T>(T t) where T : INumberBase<T>
                {
                    int o = t switch
                    {
                        1 => 1,
                        > 1 => 2,
                        _ => 3
                    };
                }

                namespace System.Numerics
                {
                    public interface Outer
                    {
                        public interface INumberBase<T> where T : INumberBase<T>
                        {
                        }
                    }
                }
                """;

            var comp = CreateCompilation(source);
            comp.VerifyDiagnostics();
        }

        [Fact, WorkItem(64399, "https://github.com/dotnet/roslyn/issues/64399")]
        public void ShortestPathToDefaultNodeYieldsNoRemainingValues()
        {
            var source = """
public enum Enum
{
    Zero = 0,
    One = 1,
    Two = 2,
}

class N
{
    private static int M(Enum e1, Enum e2)
    {
        return (e1, e2) switch
        {
            (Enum.Two, _) => 0,
            (_, Enum.Two) => 0,
            (Enum.Zero, Enum.Zero) => 0,
            (Enum.Zero, Enum.One) => 0,
            (Enum.One, Enum.Zero) => 0,
            ( < 0 or > Enum.Two, _) => 0,
            (_, < 0 or > Enum.Two) => 0,
        };
    }
}
""";

            var comp = CreateCompilation(source);
            comp.VerifyDiagnostics(
                // (12,25): warning CS8509: The switch expression does not handle all possible values of its input type (it is not exhaustive). For example, the pattern '(Enum.One, Enum.One)' is not covered.
                //         return (e1, e2) switch
                Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustive, "switch").WithArguments("(Enum.One, Enum.One)").WithLocation(12, 25)
                );
        }

        [Fact, WorkItem(64399, "https://github.com/dotnet/roslyn/issues/64399")]
        public void ShortestPathToDefaultNodeYieldsNoRemainingValues_RequiringFalseWhenClause()
        {
            var source = """
public enum Enum
{
    Zero = 0,
    One = 1,
    Two = 2,
}

class N
{
    private static int M(Enum e1, Enum e2, bool b)
    {
        return (e1, e2) switch
        {
            (Enum.One, Enum.One) when b => 0,
            (Enum.Two, _) => 0,
            (_, Enum.Two) => 0,
            (Enum.Zero, Enum.Zero) => 0,
            (Enum.Zero, Enum.One) => 0,
            (Enum.One, Enum.Zero) => 0,
            ( < 0 or > Enum.Two, _) => 0,
            (_, < 0 or > Enum.Two) => 0,
        };
    }
}
""";

            var comp = CreateCompilation(source);
            comp.VerifyDiagnostics(
                // (12,25): warning CS8846: The switch expression does not handle all possible values of its input type (it is not exhaustive). For example, the pattern '(Enum.One, Enum.One)' is not covered. However, a pattern with a 'when' clause might successfully match this value.
                //         return (e1, e2) switch
                Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustiveWithWhen, "switch").WithArguments("(Enum.One, Enum.One)").WithLocation(12, 25)
                );
        }

        [Fact, WorkItem(64399, "https://github.com/dotnet/roslyn/issues/64399")]
        public void ShortestPathToDefaultNodeYieldsNoRemainingValues_NullBranch()
        {
            var source = """
public enum Enum
{
    Zero = 0,
    One = 1,
    Two = 2,
}

class N
{
    private static int M(Enum e1, Enum e2, object o)
    {
        return (e1, e2, o) switch
        {
            (Enum.One, Enum.One, _) => 0,
            (Enum.Two, _, _) => 0,
            (_, Enum.Two, _) => 0,
            (Enum.Zero, Enum.Zero, _) => 0,
            (Enum.Zero, Enum.One, _) => 0,
            (Enum.One, Enum.Zero, _) => 0,
            ( < 0 or > Enum.Two, _, _) => 0,
            (_, < 0 or > Enum.Two, string s) => 0,
        };
    }
}
""";

            var comp = CreateCompilation(source);

            VerifyDecisionDagDump<SwitchExpressionSyntax>(comp,
@"[0]: t1 = t0.e1; [1]
[1]: t1 == 1 ? [2] : [8]
[2]: t2 = t0.e2; [3]
[3]: t2 == 1 ? [4] : [5]
[4]: leaf <arm> `(Enum.One, Enum.One, _) => 0`
[5]: t2 == 2 ? [12] : [6]
[6]: t2 == 0 ? [7] : [18]
[7]: leaf <arm> `(Enum.One, Enum.Zero, _) => 0`
[8]: t1 == 2 ? [9] : [10]
[9]: leaf <arm> `(Enum.Two, _, _) => 0`
[10]: t2 = t0.e2; [11]
[11]: t2 == 2 ? [12] : [13]
[12]: leaf <arm> `(_, Enum.Two, _) => 0`
[13]: t1 == 0 ? [14] : [24]
[14]: t2 == 0 ? [15] : [16]
[15]: leaf <arm> `(Enum.Zero, Enum.Zero, _) => 0`
[16]: t2 == 1 ? [17] : [18]
[17]: leaf <arm> `(Enum.Zero, Enum.One, _) => 0`
[18]: t3 = t0.o; [19]
[19]: t3 is string ? [20] : [23]
[20]: t4 = (string)t3; [21]
[21]: when <true> ? [22] : <unreachable>
[22]: leaf <arm> `(_, < 0 or > Enum.Two, string s) => 0`
[23]: leaf <default> `(e1, e2, o) switch
        {
            (Enum.One, Enum.One, _) => 0,
            (Enum.Two, _, _) => 0,
            (_, Enum.Two, _) => 0,
            (Enum.Zero, Enum.Zero, _) => 0,
            (Enum.Zero, Enum.One, _) => 0,
            (Enum.One, Enum.Zero, _) => 0,
            ( < 0 or > Enum.Two, _, _) => 0,
            (_, < 0 or > Enum.Two, string s) => 0,
        }`
[24]: leaf <arm> `( < 0 or > Enum.Two, _, _) => 0`
");

            comp.VerifyDiagnostics(
                // (12,28): warning CS8524: The switch expression does not handle some values of its input type (it is not exhaustive) involving an unnamed enum value. For example, the pattern '(Enum.One, (Enum)3, _)' is not covered.
                //         return (e1, e2, o) switch
                Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustiveWithUnnamedEnumValue, "switch").WithArguments("(Enum.One, (Enum)3, _)").WithLocation(12, 28)
                );
        }

        [Fact, WorkItem(64399, "https://github.com/dotnet/roslyn/issues/64399")]
        public void ShortestPathToDefaultNodeYieldsNoRemainingValues_Nullability()
        {
            var source = """
#nullable enable

public enum Enum
{
    Zero = 0,
    One = 1,
    Two = 2,
}

class N
{
    private static int M(Enum e1, Enum e2, string s)
    {
        return (e1, e2, s) switch
        {
            (Enum.Two, _, _) => 0,
            (_, Enum.Two, _) => 0,
            (Enum.Zero, Enum.Zero, _) => 0,
            (Enum.Zero, Enum.One, _) => 0,
            (Enum.One, Enum.Zero, _) => 0,
            ( < 0 or > Enum.Two, _, _) => 0,
            (_, < 0 or > Enum.Two, _) => 0,
            (_, _, string) => 0,
        };
    }
}
""";

            var comp = CreateCompilation(source);
            comp.VerifyDiagnostics();
        }

        [Fact, WorkItem(64399, "https://github.com/dotnet/roslyn/issues/64399")]
        public void ShortestPathToDefaultNodeYieldsNoRemainingValues_Nullability_NullableString()
        {
            var source = """
#nullable enable

public enum Enum
{
    Zero = 0,
    One = 1,
    Two = 2,
}

class N
{
    private static int M1(Enum e1, Enum e2, string? s)
    {
        return (e1, e2, s) switch // 1
        {
            (Enum.Two, _, _) => 0,
            (_, Enum.Two, _) => 0,
            (Enum.Zero, Enum.Zero, _) => 0,
            (Enum.Zero, Enum.One, _) => 0,
            (Enum.One, Enum.Zero, _) => 0,
            ( < 0 or > Enum.Two, _, _) => 0,
            (_, < 0 or > Enum.Two, null) => 0,
            (_, _, null) => 1,
        };
    }

    private static int M2(Enum e1, Enum e2, string? s)
    {
        return (e1, e2, s) switch // 2
        {
            (Enum.Two, _, _) => 0,
            (_, Enum.Two, _) => 0,
            (Enum.Zero, Enum.Zero, _) => 0,
            (Enum.Zero, Enum.One, _) => 0,
            (Enum.One, Enum.Zero, _) => 0,
            ( < 0 or > Enum.Two, _, _) => 0,
            (_, < 0 or > Enum.Two, _) => 0,
            (_, _, "") => 1,
        };
    }

    private static int M3(Enum e1, Enum e2, string? s)
    {
        return (e1, e2, s) switch // 3
        {
            (Enum.Two, _, _) => 0,
            (_, Enum.Two, _) => 0,
            (Enum.Zero, Enum.Zero, _) => 0,
            (Enum.Zero, Enum.One, _) => 0,
            (Enum.One, Enum.Zero, _) => 0,
            ( < 0 or > Enum.Two, _, _) => 0,
            (_, < 0 or > Enum.Two, _) => 0,
            (_, _, string) => 1,
        };
    }

    private static int M4(Enum e1, Enum e2, string? s)
    {
        return (e1, e2, s) switch // 4
        {
            (Enum.Two, _, _) => 0,
            (_, Enum.Two, _) => 0,
            (Enum.Zero, Enum.Zero, _) => 0,
            (Enum.Zero, Enum.One, _) => 0,
            (Enum.One, Enum.Zero, _) => 0,
            ( < 0 or > Enum.Two, _, _) => 0,
            (_, < 0 or > Enum.Two, null) => 1,
        };
    }

    private static int M5(Enum e1, Enum e2, string? s)
    {
        return (e1, e2, s) switch // 5
        {
            (Enum.Two, _, _) => 0,
            (_, Enum.Two, _) => 0,
            (Enum.Zero, Enum.Zero, _) => 0,
            (Enum.Zero, Enum.One, _) => 0,
            (Enum.One, Enum.Zero, _) => 0,
            ( < 0 or > Enum.Two, _, _) => 0,
            (_, < 0 or > Enum.Two, "") => 1,
        };
    }

    private static int M6(Enum e1, Enum e2, string? s)
    {
        return (e1, e2, s) switch // 6
        {
            (Enum.Two, _, _) => 0,
            (_, Enum.Two, _) => 0,
            (Enum.Zero, Enum.Zero, _) => 0,
            (Enum.Zero, Enum.One, _) => 0,
            (Enum.One, Enum.Zero, _) => 0,
            ( < 0 or > Enum.Two, _, _) => 0,
            (_, < 0 or > Enum.Two, string) => 1,
        };
    }
}
""";

            var comp = CreateCompilation(source);
            comp.VerifyDiagnostics(
                // (14,28): warning CS8524: The switch expression does not handle some values of its input type (it is not exhaustive) involving an unnamed enum value. For example, the pattern '(Enum.Zero, (Enum)-1, not null)' is not covered.
                //         return (e1, e2, s) switch // 1
                Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustiveWithUnnamedEnumValue, "switch").WithArguments("(Enum.Zero, (Enum)-1, not null)").WithLocation(14, 28),
                // (29,28): warning CS8509: The switch expression does not handle all possible values of its input type (it is not exhaustive). For example, the pattern '(Enum.One, Enum.One, "A")' is not covered.
                //         return (e1, e2, s) switch // 2
                Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustive, "switch").WithArguments("(Enum.One, Enum.One, \"A\")").WithLocation(29, 28),
                // (44,28): warning CS8655: The switch expression does not handle some null inputs (it is not exhaustive). For example, the pattern '(Enum.One, Enum.One, null)' is not covered.
                //         return (e1, e2, s) switch // 3
                Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustiveForNull, "switch").WithArguments("(Enum.One, Enum.One, null)").WithLocation(44, 28),
                // (59,28): warning CS8524: The switch expression does not handle some values of its input type (it is not exhaustive) involving an unnamed enum value. For example, the pattern '(Enum.Zero, (Enum)-1, not null)' is not covered.
                //         return (e1, e2, s) switch // 4
                Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustiveWithUnnamedEnumValue, "switch").WithArguments("(Enum.Zero, (Enum)-1, not null)").WithLocation(59, 28),
                // (73,28): warning CS8524: The switch expression does not handle some values of its input type (it is not exhaustive) involving an unnamed enum value. For example, the pattern '(Enum.Zero, (Enum)-1, "A")' is not covered.
                //         return (e1, e2, s) switch // 5
                Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustiveWithUnnamedEnumValue, "switch").WithArguments("(Enum.Zero, (Enum)-1, \"A\")").WithLocation(73, 28),
                // (87,28): warning CS8509: The switch expression does not handle all possible values of its input type (it is not exhaustive). For example, the pattern '(Enum.One, Enum.One, _)' is not covered.
                //         return (e1, e2, s) switch // 6
                Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustive, "switch").WithArguments("(Enum.One, Enum.One, _)").WithLocation(87, 28)
                );
        }

        [Theory, CombinatorialData, WorkItem(64399, "https://github.com/dotnet/roslyn/issues/64399")]
        public void ShortestPathToDefaultNodeYieldsNoRemainingValues_Nullability_Deconstruction(bool nullableEnable)
        {
            var source = """
public enum Enum
{
    Zero = 0,
    One = 1,
    Two = 2,
}

class N
{
    private int M1()
    {
        return this switch // 1
        {
            (Enum.Two, _, _) => 0,
            (_, Enum.Two, _) => 0,
            (Enum.Zero, Enum.Zero, _) => 0,
            (Enum.Zero, Enum.One, _) => 0,
            (Enum.One, Enum.Zero, _) => 0,
            ( < 0 or > Enum.Two, _, _) => 0,
            (_, < 0 or > Enum.Two, _) => 0,
            (_, _, not null) => 1,
        };
    }

    private int M2()
    {
        return this switch // 2
        {
            (Enum.Two, _, _) => 0,
            (_, Enum.Two, _) => 0,
            (Enum.Zero, Enum.Zero, _) => 0,
            (Enum.Zero, Enum.One, _) => 0,
            (Enum.One, Enum.Zero, _) => 0,
            ( < 0 or > Enum.Two, _, _) => 0,
            (_, < 0 or > Enum.Two, _) => 0,
            (_, _, true) => 1,
            (_, _, false) => 1,
        };
    }

    private int M3()
    {
        return this switch // 3
        {
            null => 1,
            (Enum.Two, _, _) => 0,
            (_, Enum.Two, _) => 0,
            (Enum.Zero, Enum.Zero, _) => 0,
            (Enum.Zero, Enum.One, _) => 0,
            (Enum.One, Enum.Zero, _) => 0,
            ( < 0 or > Enum.Two, _, _) => 0,
            (_, < 0 or > Enum.Two, _) => 0,
            (_, _, true) => 1,
            (_, _, false) => 1,
        };
    }

    private int M4()
    {
        return this switch // 4
        {
            null => 1,
            (Enum.Two, _, _) => 0,
            (_, Enum.Two, _) => 0,
            (Enum.Zero, Enum.Zero, _) => 0,
            (Enum.Zero, Enum.One, _) => 0,
            (Enum.One, Enum.Zero, _) => 0,
            ( < 0 or > Enum.Two, _, _) => 0,
            (_, < 0 or > Enum.Two, _) => 0,
            (_, _, true) => 1,
        };
    }

    private int M5()
    {
        return this switch // 5
        {
            (Enum.Two, _, _) => 0,
            (_, Enum.Two, _) => 0,
            (Enum.Zero, Enum.Zero, _) => 0,
            (Enum.Zero, Enum.One, _) => 0,
            (Enum.One, Enum.Zero, _) => 0,
            ( < 0 or > Enum.Two, _, _) => 0,
            (_, < 0 or > Enum.Two, not null) => 1,
        };
    }

    private int M6()
    {
        return this switch // 6
        {
            (Enum.Two, _, _) => 0,
            (_, Enum.Two, _) => 0,
            (Enum.Zero, Enum.Zero, _) => 0,
            (Enum.Zero, Enum.One, _) => 0,
            (Enum.One, Enum.Zero, _) => 0,
            ( < 0 or > Enum.Two, _, _) => 0,
            (_, < 0 or > Enum.Two, true) => 1,
            (_, < 0 or > Enum.Two, false) => 1,
        };
    }

    private int M7()
    {
        return this switch // 7
        {
            null => 1,
            (Enum.Two, _, _) => 0,
            (_, Enum.Two, _) => 0,
            (Enum.Zero, Enum.Zero, _) => 0,
            (Enum.Zero, Enum.One, _) => 0,
            (Enum.One, Enum.Zero, _) => 0,
            ( < 0 or > Enum.Two, _, _) => 0,
            (_, < 0 or > Enum.Two, true) => 1,
            (_, < 0 or > Enum.Two, false) => 1,
        };
    }

    private int M8()
    {
        return this switch // 8
        {
            null => 1,
            (Enum.Two, _, _) => 0,
            (_, Enum.Two, _) => 0,
            (Enum.Zero, Enum.Zero, _) => 0,
            (Enum.Zero, Enum.One, _) => 0,
            (Enum.One, Enum.Zero, _) => 0,
            ( < 0 or > Enum.Two, _, _) => 0,
            (_, < 0 or > Enum.Two, true) => 1,
        };
    }

    void Deconstruct(out Enum e1, out Enum e2, out bool? s) => throw null!;
}
""";

            var comp = CreateCompilation(source, options: TestOptions.DebugDll.WithNullableContextOptions(nullableEnable ? NullableContextOptions.Enable : NullableContextOptions.Disable));
            if (nullableEnable)
            {
                comp.VerifyDiagnostics(
                    // (12,21): warning CS8655: The switch expression does not handle some null inputs (it is not exhaustive). For example, the pattern '(Enum.One, Enum.One, null)' is not covered.
                    //         return this switch // 1
                    Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustiveForNull, "switch").WithArguments("(Enum.One, Enum.One, null)").WithLocation(12, 21),
                    // (27,21): warning CS8655: The switch expression does not handle some null inputs (it is not exhaustive). For example, the pattern '(Enum.One, Enum.One, null)' is not covered.
                    //         return this switch // 2
                    Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustiveForNull, "switch").WithArguments("(Enum.One, Enum.One, null)").WithLocation(27, 21),
                    // (43,21): warning CS8655: The switch expression does not handle some null inputs (it is not exhaustive). For example, the pattern '(Enum.One, Enum.One, null)' is not covered.
                    //         return this switch // 3
                    Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustiveForNull, "switch").WithArguments("(Enum.One, Enum.One, null)").WithLocation(43, 21),
                    // (60,21): warning CS8509: The switch expression does not handle all possible values of its input type (it is not exhaustive). For example, the pattern '(Enum.One, Enum.One, false)' is not covered.
                    //         return this switch // 4
                    Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustive, "switch").WithArguments("(Enum.One, Enum.One, false)").WithLocation(60, 21),
                    // (76,21): warning CS8509: The switch expression does not handle all possible values of its input type (it is not exhaustive). For example, the pattern '(Enum.One, Enum.One, _)' is not covered.
                    //         return this switch // 5
                    Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustive, "switch").WithArguments("(Enum.One, Enum.One, _)").WithLocation(76, 21),
                    // (90,21): warning CS8509: The switch expression does not handle all possible values of its input type (it is not exhaustive). For example, the pattern '(Enum.One, Enum.One, _)' is not covered.
                    //         return this switch // 6
                    Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustive, "switch").WithArguments("(Enum.One, Enum.One, _)").WithLocation(90, 21),
                    // (105,21): warning CS8509: The switch expression does not handle all possible values of its input type (it is not exhaustive). For example, the pattern '(Enum.One, Enum.One, _)' is not covered.
                    //         return this switch // 7
                    Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustive, "switch").WithArguments("(Enum.One, Enum.One, _)").WithLocation(105, 21),
                    // (121,21): warning CS8524: The switch expression does not handle some values of its input type (it is not exhaustive) involving an unnamed enum value. For example, the pattern '(Enum.Zero, (Enum)-1, false)' is not covered.
                    //         return this switch // 8
                    Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustiveWithUnnamedEnumValue, "switch").WithArguments("(Enum.Zero, (Enum)-1, false)").WithLocation(121, 21)
                    );
            }
            else
            {
                comp.VerifyDiagnostics(
                    // (60,21): warning CS8509: The switch expression does not handle all possible values of its input type (it is not exhaustive). For example, the pattern '(Enum.One, Enum.One, false)' is not covered.
                    //         return this switch // 4
                    Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustive, "switch").WithArguments("(Enum.One, Enum.One, false)").WithLocation(60, 21),
                    // (76,21): warning CS8509: The switch expression does not handle all possible values of its input type (it is not exhaustive). For example, the pattern '(Enum.One, Enum.One, _)' is not covered.
                    //         return this switch // 5
                    Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustive, "switch").WithArguments("(Enum.One, Enum.One, _)").WithLocation(76, 21),
                    // (90,21): warning CS8509: The switch expression does not handle all possible values of its input type (it is not exhaustive). For example, the pattern '(Enum.One, Enum.One, _)' is not covered.
                    //         return this switch // 6
                    Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustive, "switch").WithArguments("(Enum.One, Enum.One, _)").WithLocation(90, 21),
                    // (105,21): warning CS8509: The switch expression does not handle all possible values of its input type (it is not exhaustive). For example, the pattern '(Enum.One, Enum.One, _)' is not covered.
                    //         return this switch // 7
                    Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustive, "switch").WithArguments("(Enum.One, Enum.One, _)").WithLocation(105, 21),
                    // (121,21): warning CS8524: The switch expression does not handle some values of its input type (it is not exhaustive) involving an unnamed enum value. For example, the pattern '(Enum.Zero, (Enum)-1, false)' is not covered.
                    //         return this switch // 8
                    Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustiveWithUnnamedEnumValue, "switch").WithArguments("(Enum.Zero, (Enum)-1, false)").WithLocation(121, 21)
                    );
            }
        }

        [Theory, CombinatorialData, WorkItem(64399, "https://github.com/dotnet/roslyn/issues/64399")]
        public void ShortestPathToDefaultNodeYieldsNoRemainingValues_Nullability_NullableBool(bool nullableEnable)
        {
            var source = """
public enum Enum
{
    Zero = 0,
    One = 1,
    Two = 2,
}

class N
{
    private static int M1(Enum e1, Enum e2, bool? i)
    {
        return (e1, e2, i) switch // 1
        {
            (Enum.Two, _, _) => 0,
            (_, Enum.Two, _) => 0,
            (Enum.Zero, Enum.Zero, _) => 0,
            (Enum.Zero, Enum.One, _) => 0,
            (Enum.One, Enum.Zero, _) => 0,
            ( < 0 or > Enum.Two, _, _) => 0,
            (_, < 0 or > Enum.Two, _) => 0,
            (_, _, true) => 1,
        };
    }

    private static int M2(Enum e1, Enum e2, bool? i)
    {
        return (e1, e2, i) switch // 2
        {
            (Enum.Two, _, _) => 0,
            (_, Enum.Two, _) => 0,
            (Enum.Zero, Enum.Zero, _) => 0,
            (Enum.Zero, Enum.One, _) => 0,
            (Enum.One, Enum.Zero, _) => 0,
            ( < 0 or > Enum.Two, _, _) => 0,
            (_, < 0 or > Enum.Two, _) => 0,
            (_, _, true) => 1,
            (_, _, false) => 1,
        };
    }
}
""";
            var comp = CreateCompilation(source, options: TestOptions.DebugDll.WithNullableContextOptions(nullableEnable ? NullableContextOptions.Enable : NullableContextOptions.Disable));
            if (nullableEnable)
            {
                comp.VerifyDiagnostics(
                    // (12,28): warning CS8509: The switch expression does not handle all possible values of its input type (it is not exhaustive). For example, the pattern '(Enum.One, Enum.One, false)' is not covered.
                    //         return (e1, e2, i) switch // 1
                    Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustive, "switch").WithArguments("(Enum.One, Enum.One, false)").WithLocation(12, 28),
                    // (27,28): warning CS8655: The switch expression does not handle some null inputs (it is not exhaustive). For example, the pattern '(Enum.One, Enum.One, null)' is not covered.
                    //         return (e1, e2, i) switch // 2
                    Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustiveForNull, "switch").WithArguments("(Enum.One, Enum.One, null)").WithLocation(27, 28)
                    );
            }
            else
            {
                comp.VerifyDiagnostics(
                    // (12,28): warning CS8509: The switch expression does not handle all possible values of its input type (it is not exhaustive). For example, the pattern '(Enum.One, Enum.One, false)' is not covered.
                    //         return (e1, e2, i) switch // 1
                    Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustive, "switch").WithArguments("(Enum.One, Enum.One, false)").WithLocation(12, 28)
                    );
            }
        }

        [Fact, WorkItem(45679, "https://github.com/dotnet/roslyn/issues/45679")]
        public void IsExpression_SwitchDispatch_Numeric()
        {
            var source = """
class C
{
    public static void Main()
    {
        System.Console.Write(
              Test(0) == false
            & Test(1)
            & Test(2)
            & Test(3)
            & Test(4)
            & Test(5)
            & Test(6)
            & Test(7)
            & Test(8)
        );
    }  
    public static bool Test(int a)
    {
        return (a is 1 or 2 or 3 or 4 or 5 or 6 or 7 or 8);
    }
}
""";
            var compilation = CompileAndVerify(source, expectedOutput: "True");
            compilation.VerifyIL("C.Test", """
{
  // Code size       14 (0xe)
  .maxstack  2
  .locals init (bool V_0)
  IL_0000:  ldarg.0
  IL_0001:  ldc.i4.1
  IL_0002:  sub
  IL_0003:  ldc.i4.7
  IL_0004:  bgt.un.s   IL_000a
  IL_0006:  ldc.i4.1
  IL_0007:  stloc.0
  IL_0008:  br.s       IL_000c
  IL_000a:  ldc.i4.0
  IL_000b:  stloc.0
  IL_000c:  ldloc.0
  IL_000d:  ret
}
""");
        }

        [Fact, WorkItem(45679, "https://github.com/dotnet/roslyn/issues/45679")]
        public void IsExpression_SwitchDispatch_SwitchIL()
        {
            var source = """
class C
{
    public static void Main()
    {
        System.Console.Write(
              Test(1, null) == false
            & Test(1, default(int))
            & Test(2, default(bool))
            & Test(3, default(double))
            & Test(4, default(long))
            & Test(5, default(long)) == false
        );
    }
    public static bool Test(int a, object b)
    {
        return (a, b) is 
                (1, int) or
                (2, bool) or
                (3, double) or
                (4, long);
    }
}
""";
            var compilation = CompileAndVerify(source, expectedOutput: "True");
            compilation.VerifyIL("C.Test", """
{
  // Code size       72 (0x48)
  .maxstack  2
  .locals init (bool V_0)
  IL_0000:  ldarg.0
  IL_0001:  ldc.i4.1
  IL_0002:  sub
  IL_0003:  switch    (
        IL_001a,
        IL_0024,
        IL_002e,
        IL_0038)
  IL_0018:  br.s       IL_0044
  IL_001a:  ldarg.1
  IL_001b:  isinst     "int"
  IL_0020:  brtrue.s   IL_0040
  IL_0022:  br.s       IL_0044
  IL_0024:  ldarg.1
  IL_0025:  isinst     "bool"
  IL_002a:  brtrue.s   IL_0040
  IL_002c:  br.s       IL_0044
  IL_002e:  ldarg.1
  IL_002f:  isinst     "double"
  IL_0034:  brtrue.s   IL_0040
  IL_0036:  br.s       IL_0044
  IL_0038:  ldarg.1
  IL_0039:  isinst     "long"
  IL_003e:  brfalse.s  IL_0044
  IL_0040:  ldc.i4.1
  IL_0041:  stloc.0
  IL_0042:  br.s       IL_0046
  IL_0044:  ldc.i4.0
  IL_0045:  stloc.0
  IL_0046:  ldloc.0
  IL_0047:  ret
}
""");
        }

        [Fact, WorkItem(45679, "https://github.com/dotnet/roslyn/issues/45679")]
        public void IsExpression_SwitchDispatch_String()
        {
            var source = """
class C
{
    public static void Main()
    {
        System.Console.Write(
              Test("0") == false
            & Test("1")
            & Test("2")
            & Test("3")
            & Test("4")
            & Test("5")
            & Test("6")
            & Test("7")
            & Test("8")
        );
    }  
    public static bool Test(string a)
    {
        return (a is "1" or "2" or "3" or "4" or "5" or "6" or "7" or "8");
    }
}
""";
            var compilation = CompileAndVerify(source, expectedOutput: "True");
            compilation.VerifyIL("C.Test", """
{
  // Code size       73 (0x49)
  .maxstack  2
  .locals init (bool V_0,
                int V_1,
                char V_2)
  IL_0000:  ldarg.0
  IL_0001:  brfalse.s  IL_0045
  IL_0003:  ldarg.0
  IL_0004:  call       "int string.Length.get"
  IL_0009:  stloc.1
  IL_000a:  ldloc.1
  IL_000b:  ldc.i4.1
  IL_000c:  bne.un.s   IL_0045
  IL_000e:  ldarg.0
  IL_000f:  ldc.i4.0
  IL_0010:  call       "char string.this[int].get"
  IL_0015:  stloc.2
  IL_0016:  ldloc.2
  IL_0017:  ldc.i4.s   49
  IL_0019:  sub
  IL_001a:  switch    (
        IL_0041,
        IL_0041,
        IL_0041,
        IL_0041,
        IL_0041,
        IL_0041,
        IL_0041,
        IL_0041)
  IL_003f:  br.s       IL_0045
  IL_0041:  ldc.i4.1
  IL_0042:  stloc.0
  IL_0043:  br.s       IL_0047
  IL_0045:  ldc.i4.0
  IL_0046:  stloc.0
  IL_0047:  ldloc.0
  IL_0048:  ret
}
""");
        }

        [Theory]
        [InlineData("object", "new {}")]
        [InlineData("dynamic", "new {}")]
        [InlineData("System.ValueType", "((int)x0)/2")]
        public void ConstantsExpectedInPatternExpression(string type, string expression)
        {
            var source = @$"
class Outer
{{
    bool M0({type} x0)
    {{
        return x0 is {expression};
    }}
}}
";
            CreateCompilation(source).VerifyDiagnostics(
                // (6,22): error CS0150: A constant value is expected
                //         return x0 is {expression};
                Diagnostic(ErrorCode.ERR_ConstantExpected, expression).WithLocation(6, 22)
            );
        }

        [Fact]
        [WorkItem("https://github.com/dotnet/roslyn/issues/82063")]
        public void SideeffectEvaluations_01()
        {
            var src = @"
interface I1
{
    int F {get;}
}

class C11;
class C12;
class C13(int f) : C12, I1
{
    public int F
    {
        get
        {
            System.Console.Write(""Evaluated C13.F "");
            return f;   
        }
    }
}
class C14(int f) : I1
{
    public int F
    {
        get
        {
            System.Console.Write(""Evaluated C14.F "");
            return f;   
        }
    }
}
class C15(int f) : I1
{
    public int F
    {
        get
        {
            System.Console.Write(""Evaluated C15.F "");
            return f;   
        }
    }
}

class Program
{
    static void Main()
    {
        object[] s = [null, new C11(), new C12(), new C13(1), new C14(1), new C15(1), new C13(2), new C14(2), new C15(2), new C13(3), new C14(3), new C15(3)]; 
        int[] i = [1, 2, 3];
        foreach (var s1 in s)
        {
            foreach (var j in i)
            {
                var t = Test1((s1, j));
                System.Console.WriteLine(t);
            }
        }
    }

    static bool Test1((object, int) u)
    {
        return u is (C12 and I1 and { F: 1 }, 2) or (I1 and { F: 1 or 2 }, 1);
    }   
}
";
            var comp = CreateCompilation(src, options: TestOptions.ReleaseExe);

            VerifyDecisionDagDump<IsPatternExpressionSyntax>(comp,
@"[0]: t1 = t0.Item1; [1]
[1]: t1 is C12 ? [2] : [9]
[2]: t2 = (C12)t1; [3]
[3]: t2 is I1 ? [4] : [17]
[4]: t3 = (I1)t2; [5]
[5]: t4 = t3.F; [6]
[6]: t4 == 1 ? [7] : [13]
[7]: t5 = t0.Item2; [8]
[8]: t5 == 2 ? [16] : [15]
[9]: t1 is I1 ? [10] : [17]
[10]: t3 = (I1)t1; [11]
[11]: t4 = t3.F; [12]
[12]: t4 == 1 ? [14] : [13]
[13]: t4 == 2 ? [14] : [17]
[14]: t5 = t0.Item2; [15]
[15]: t5 == 1 ? [16] : [17]
[16]: leaf <isPatternSuccess> `(C12 and I1 and { F: 1 }, 2) or (I1 and { F: 1 or 2 }, 1)`
[17]: leaf <isPatternFailure> `(C12 and I1 and { F: 1 }, 2) or (I1 and { F: 1 or 2 }, 1)`
");

            var verifier = CompileAndVerify(
                comp,
                expectedOutput: @"
False
False
False
False
False
False
False
False
False
Evaluated C13.F True
Evaluated C13.F True
Evaluated C13.F False
Evaluated C14.F True
Evaluated C14.F False
Evaluated C14.F False
Evaluated C15.F True
Evaluated C15.F False
Evaluated C15.F False
Evaluated C13.F True
Evaluated C13.F False
Evaluated C13.F False
Evaluated C14.F True
Evaluated C14.F False
Evaluated C14.F False
Evaluated C15.F True
Evaluated C15.F False
Evaluated C15.F False
Evaluated C13.F False
Evaluated C13.F False
Evaluated C13.F False
Evaluated C14.F False
Evaluated C14.F False
Evaluated C14.F False
Evaluated C15.F False
Evaluated C15.F False
Evaluated C15.F False
").VerifyDiagnostics();

            verifier.VerifyIL("Program.Test1", @"
{
  // Code size      102 (0x66)
  .maxstack  2
  .locals init (object V_0,
                C12 V_1,
                I1 V_2,
                int V_3,
                int V_4,
                bool V_5)
  IL_0000:  ldarg.0
  IL_0001:  ldfld      ""object System.ValueTuple<object, int>.Item1""
  IL_0006:  stloc.0
  IL_0007:  ldloc.0
  IL_0008:  isinst     ""C12""
  IL_000d:  stloc.1
  IL_000e:  ldloc.1
  IL_000f:  brfalse.s  IL_0035
  IL_0011:  ldloc.1
  IL_0012:  isinst     ""I1""
  IL_0017:  stloc.2
  IL_0018:  ldloc.2
  IL_0019:  brfalse.s  IL_0060
  IL_001b:  ldloc.2
  IL_001c:  callvirt   ""int I1.F.get""
  IL_0021:  stloc.3
  IL_0022:  ldloc.3
  IL_0023:  ldc.i4.1
  IL_0024:  bne.un.s   IL_004a
  IL_0026:  ldarg.0
  IL_0027:  ldfld      ""int System.ValueTuple<object, int>.Item2""
  IL_002c:  stloc.s    V_4
  IL_002e:  ldloc.s    V_4
  IL_0030:  ldc.i4.2
  IL_0031:  beq.s      IL_005b
  IL_0033:  br.s       IL_0056
  IL_0035:  ldloc.0
  IL_0036:  isinst     ""I1""
  IL_003b:  stloc.2
  IL_003c:  ldloc.2
  IL_003d:  brfalse.s  IL_0060
  IL_003f:  ldloc.2
  IL_0040:  callvirt   ""int I1.F.get""
  IL_0045:  stloc.3
  IL_0046:  ldloc.3
  IL_0047:  ldc.i4.1
  IL_0048:  beq.s      IL_004e
  IL_004a:  ldloc.3
  IL_004b:  ldc.i4.2
  IL_004c:  bne.un.s   IL_0060
  IL_004e:  ldarg.0
  IL_004f:  ldfld      ""int System.ValueTuple<object, int>.Item2""
  IL_0054:  stloc.s    V_4
  IL_0056:  ldloc.s    V_4
  IL_0058:  ldc.i4.1
  IL_0059:  bne.un.s   IL_0060
  IL_005b:  ldc.i4.1
  IL_005c:  stloc.s    V_5
  IL_005e:  br.s       IL_0063
  IL_0060:  ldc.i4.0
  IL_0061:  stloc.s    V_5
  IL_0063:  ldloc.s    V_5
  IL_0065:  ret
}
");
        }

        [Fact]
        [WorkItem("https://github.com/dotnet/roslyn/issues/82063")]
        public void SideeffectEvaluations_02()
        {
            var src = @"
interface I1
{
    int F {get;}
}

class C11;
class C12;
class C13(int f) : C12, I1
{
    public int F
    {
        get
        {
            System.Console.Write(""Evaluated C13.F "");
            return f;   
        }
    }
}
class C14(int f) : I1
{
    public int F
    {
        get
        {
            System.Console.Write(""Evaluated C14.F "");
            return f;   
        }
    }
}
class C15(int f) : I1
{
    public int F
    {
        get
        {
            System.Console.Write(""Evaluated C15.F "");
            return f;   
        }
    }
}

class Program
{
    static void Main()
    {
        object[] s = [null, new C11(), new C12(), new C13(1), new C14(1), new C15(1), new C13(2), new C14(2), new C15(2), new C13(3), new C14(3), new C15(3)]; 
        int[] i = [1, 2, 3];
        foreach (var s1 in s)
        {
            foreach (var j in i)
            {
                var t = Test1((s1, j));
                System.Console.WriteLine(t);
            }
        }
    }

    static bool Test1((object, int) u)
    {
        return u is (I1 and { F: 1 or 2 }, 1) or (C12 and I1 and { F: 1 }, 2);
    }   
}
";
            var comp = CreateCompilation(src, options: TestOptions.ReleaseExe);

            VerifyDecisionDagDump<IsPatternExpressionSyntax>(comp,
@"[0]: t1 = t0.Item1; [1]
[1]: t1 is I1 ? [2] : [13]
[2]: t2 = (I1)t1; [3]
[3]: t3 = t2.F; [4]
[4]: t3 == 1 ? [5] : [9]
[5]: t4 = t0.Item2; [6]
[6]: t4 == 1 ? [12] : [7]
[7]: t1 is C12 ? [8] : [13]
[8]: t4 == 2 ? [12] : [13]
[9]: t3 == 2 ? [10] : [13]
[10]: t4 = t0.Item2; [11]
[11]: t4 == 1 ? [12] : [13]
[12]: leaf <isPatternSuccess> `(I1 and { F: 1 or 2 }, 1) or (C12 and I1 and { F: 1 }, 2)`
[13]: leaf <isPatternFailure> `(I1 and { F: 1 or 2 }, 1) or (C12 and I1 and { F: 1 }, 2)`
");

            var verifier = CompileAndVerify(
                comp,
                expectedOutput: @"
False
False
False
False
False
False
False
False
False
Evaluated C13.F True
Evaluated C13.F True
Evaluated C13.F False
Evaluated C14.F True
Evaluated C14.F False
Evaluated C14.F False
Evaluated C15.F True
Evaluated C15.F False
Evaluated C15.F False
Evaluated C13.F True
Evaluated C13.F False
Evaluated C13.F False
Evaluated C14.F True
Evaluated C14.F False
Evaluated C14.F False
Evaluated C15.F True
Evaluated C15.F False
Evaluated C15.F False
Evaluated C13.F False
Evaluated C13.F False
Evaluated C13.F False
Evaluated C14.F False
Evaluated C14.F False
Evaluated C14.F False
Evaluated C15.F False
Evaluated C15.F False
Evaluated C15.F False
").VerifyDiagnostics();

            verifier.VerifyIL("Program.Test1", @"
{
  // Code size       81 (0x51)
  .maxstack  2
  .locals init (object V_0,
                I1 V_1,
                int V_2,
                int V_3,
                bool V_4)
  IL_0000:  ldarg.0
  IL_0001:  ldfld      ""object System.ValueTuple<object, int>.Item1""
  IL_0006:  stloc.0
  IL_0007:  ldloc.0
  IL_0008:  isinst     ""I1""
  IL_000d:  stloc.1
  IL_000e:  ldloc.1
  IL_000f:  brfalse.s  IL_004b
  IL_0011:  ldloc.1
  IL_0012:  callvirt   ""int I1.F.get""
  IL_0017:  stloc.2
  IL_0018:  ldloc.2
  IL_0019:  ldc.i4.1
  IL_001a:  beq.s      IL_0022
  IL_001c:  ldloc.2
  IL_001d:  ldc.i4.2
  IL_001e:  beq.s      IL_003b
  IL_0020:  br.s       IL_004b
  IL_0022:  ldarg.0
  IL_0023:  ldfld      ""int System.ValueTuple<object, int>.Item2""
  IL_0028:  stloc.3
  IL_0029:  ldloc.3
  IL_002a:  ldc.i4.1
  IL_002b:  beq.s      IL_0046
  IL_002d:  ldloc.0
  IL_002e:  isinst     ""C12""
  IL_0033:  brfalse.s  IL_004b
  IL_0035:  ldloc.3
  IL_0036:  ldc.i4.2
  IL_0037:  beq.s      IL_0046
  IL_0039:  br.s       IL_004b
  IL_003b:  ldarg.0
  IL_003c:  ldfld      ""int System.ValueTuple<object, int>.Item2""
  IL_0041:  stloc.3
  IL_0042:  ldloc.3
  IL_0043:  ldc.i4.1
  IL_0044:  bne.un.s   IL_004b
  IL_0046:  ldc.i4.1
  IL_0047:  stloc.s    V_4
  IL_0049:  br.s       IL_004e
  IL_004b:  ldc.i4.0
  IL_004c:  stloc.s    V_4
  IL_004e:  ldloc.s    V_4
  IL_0050:  ret
}
");
        }

        [Fact]
        [WorkItem("https://github.com/dotnet/roslyn/issues/82063")]
        public void SideeffectEvaluations_03()
        {
            var src = @"
interface I1
{
    int F {get;}
}

interface I2 : I1
{
}

class C11;
class C12;
class C13(int f) : C12, I1
{
    public int F
    {
        get
        {
            System.Console.Write(""Evaluated C13.F "");
            return f;   
        }
    }
}
class C14(int f) : I2
{
    public int F
    {
        get
        {
            System.Console.Write(""Evaluated C14.F "");
            return f;   
        }
    }
}
class C15(int f) : I1
{
    public int F
    {
        get
        {
            System.Console.Write(""Evaluated C15.F "");
            return f;   
        }
    }
}
class C16(int f) : C12, I2
{
    public int F
    {
        get
        {
            System.Console.Write(""Evaluated C15.F "");
            return f;   
        }
    }
}

class Program
{
    static void Main()
    {
        object[] s = [null, new C11(), new C12(), new C13(1), new C14(1), new C15(1), new C16(1), new C13(2), new C14(2), new C15(2), new C16(2), new C13(3), new C14(3), new C15(3), new C16(3)]; 
        int[] i = [1, 2, 3];
        foreach (var s1 in s)
        {
            foreach (var j in i)
            {
                var t = Test1((s1, j));
                System.Console.WriteLine(t);
            }
        }
    }

    static bool Test1((object, int) u)
    {
        return u is (C12 and I1 and { F: 1 }, 2) or (I2 and { F: 1 or 2 }, 1);
    }   
}
";
            var comp = CreateCompilation(src, options: TestOptions.ReleaseExe);

            VerifyDecisionDagDump<IsPatternExpressionSyntax>(comp,
@"[0]: t1 = t0.Item1; [1]
[1]: t1 is C12 ? [2] : [12]
[2]: t2 = (C12)t1; [3]
[3]: t2 is I1 ? [4] : [20]
[4]: t3 = (I1)t2; [5]
[5]: t4 = t3.F; [6]
[6]: t4 == 1 ? [7] : [10]
[7]: t5 = t0.Item2; [8]
[8]: t5 == 2 ? [19] : [9]
[9]: t1 is I2 ? [18] : [20]
[10]: t1 is I2 ? [11] : [20]
[11]: t4 == 2 ? [17] : [20]
[12]: t1 is I2 ? [13] : [20]
[13]: t6 = (I2)t1; [14]
[14]: t7 = t6.F; [15]
[15]: t7 == 1 ? [17] : [16]
[16]: t7 == 2 ? [17] : [20]
[17]: t5 = t0.Item2; [18]
[18]: t5 == 1 ? [19] : [20]
[19]: leaf <isPatternSuccess> `(C12 and I1 and { F: 1 }, 2) or (I2 and { F: 1 or 2 }, 1)`
[20]: leaf <isPatternFailure> `(C12 and I1 and { F: 1 }, 2) or (I2 and { F: 1 or 2 }, 1)`
");

            var verifier = CompileAndVerify(
                comp,
                expectedOutput: @"
False
False
False
False
False
False
False
False
False
Evaluated C13.F False
Evaluated C13.F True
Evaluated C13.F False
Evaluated C14.F True
Evaluated C14.F False
Evaluated C14.F False
False
False
False
Evaluated C15.F True
Evaluated C15.F True
Evaluated C15.F False
Evaluated C13.F False
Evaluated C13.F False
Evaluated C13.F False
Evaluated C14.F True
Evaluated C14.F False
Evaluated C14.F False
False
False
False
Evaluated C15.F True
Evaluated C15.F False
Evaluated C15.F False
Evaluated C13.F False
Evaluated C13.F False
Evaluated C13.F False
Evaluated C14.F False
Evaluated C14.F False
Evaluated C14.F False
False
False
False
Evaluated C15.F False
Evaluated C15.F False
Evaluated C15.F False
").VerifyDiagnostics();

            verifier.VerifyIL("Program.Test1", @"
{
  // Code size      127 (0x7f)
  .maxstack  2
  .locals init (object V_0,
            C12 V_1,
            I1 V_2,
            int V_3,
            int V_4,
            I2 V_5,
            int V_6,
            bool V_7)
  IL_0000:  ldarg.0
  IL_0001:  ldfld      ""object System.ValueTuple<object, int>.Item1""
  IL_0006:  stloc.0
  IL_0007:  ldloc.0
  IL_0008:  isinst     ""C12""
  IL_000d:  stloc.1
  IL_000e:  ldloc.1
  IL_000f:  brfalse.s  IL_004b
  IL_0011:  ldloc.1
  IL_0012:  isinst     ""I1""
  IL_0017:  stloc.2
  IL_0018:  ldloc.2
  IL_0019:  brfalse.s  IL_0079
  IL_001b:  ldloc.2
  IL_001c:  callvirt   ""int I1.F.get""
  IL_0021:  stloc.3
  IL_0022:  ldloc.3
  IL_0023:  ldc.i4.1
  IL_0024:  bne.un.s   IL_003d
  IL_0026:  ldarg.0
  IL_0027:  ldfld      ""int System.ValueTuple<object, int>.Item2""
  IL_002c:  stloc.s    V_4
  IL_002e:  ldloc.s    V_4
  IL_0030:  ldc.i4.2
  IL_0031:  beq.s      IL_0074
  IL_0033:  ldloc.0
  IL_0034:  isinst     ""I2""
  IL_0039:  brtrue.s   IL_006f
  IL_003b:  br.s       IL_0079
  IL_003d:  ldloc.0
  IL_003e:  isinst     ""I2""
  IL_0043:  brfalse.s  IL_0079
  IL_0045:  ldloc.3
  IL_0046:  ldc.i4.2
  IL_0047:  beq.s      IL_0067
  IL_0049:  br.s       IL_0079
  IL_004b:  ldloc.0
  IL_004c:  isinst     ""I2""
  IL_0051:  stloc.s    V_5
  IL_0053:  ldloc.s    V_5
  IL_0055:  brfalse.s  IL_0079
  IL_0057:  ldloc.s    V_5
  IL_0059:  callvirt   ""int I1.F.get""
  IL_005e:  stloc.s    V_6
  IL_0060:  ldloc.s    V_6
  IL_0062:  ldc.i4.1
  IL_0063:  sub
  IL_0064:  ldc.i4.1
  IL_0065:  bgt.un.s   IL_0079
  IL_0067:  ldarg.0
  IL_0068:  ldfld      ""int System.ValueTuple<object, int>.Item2""
  IL_006d:  stloc.s    V_4
  IL_006f:  ldloc.s    V_4
  IL_0071:  ldc.i4.1
  IL_0072:  bne.un.s   IL_0079
  IL_0074:  ldc.i4.1
  IL_0075:  stloc.s    V_7
  IL_0077:  br.s       IL_007c
  IL_0079:  ldc.i4.0
  IL_007a:  stloc.s    V_7
  IL_007c:  ldloc.s    V_7
  IL_007e:  ret
}
");
        }

        [Fact]
        [WorkItem("https://github.com/dotnet/roslyn/issues/82063")]
        public void SideeffectEvaluations_04()
        {
            var src = @"
interface I1
{
    int F {get;}
}

interface I2 : I1
{
}

class C11;
class C12;
class C13(int f) : C12, I1
{
    public int F
    {
        get
        {
            System.Console.Write(""Evaluated C13.F "");
            return f;   
        }
    }
}
class C14(int f) : I2
{
    public int F
    {
        get
        {
            System.Console.Write(""Evaluated C14.F "");
            return f;   
        }
    }
}
class C15(int f) : I1
{
    public int F
    {
        get
        {
            System.Console.Write(""Evaluated C15.F "");
            return f;   
        }
    }
}
class C16(int f) : C12, I2
{
    public int F
    {
        get
        {
            System.Console.Write(""Evaluated C15.F "");
            return f;   
        }
    }
}

class Program
{
    static void Main()
    {
        object[] s = [null, new C11(), new C12(), new C13(1), new C14(1), new C15(1), new C16(1), new C13(2), new C14(2), new C15(2), new C16(2), new C13(3), new C14(3), new C15(3), new C16(3)]; 
        int[] i = [1, 2, 3];
        foreach (var s1 in s)
        {
            foreach (var j in i)
            {
                var t = Test1((s1, j));
                System.Console.WriteLine(t);
            }
        }
    }

    static bool Test1((object, int) u)
    {
        return u is (C12 and I2 and { F: 1 }, 2) or (I1 and { F: 1 or 2 }, 1);
    }   
}
";
            var comp = CreateCompilation(src, options: TestOptions.ReleaseExe);

            VerifyDecisionDagDump<IsPatternExpressionSyntax>(comp,
@"[0]: t1 = t0.Item1; [1]
[1]: t1 is C12 ? [2] : [10]
[2]: t2 = (C12)t1; [3]
[3]: t2 is I2 ? [4] : [10]
[4]: t3 = (I2)t2; [5]
[5]: t4 = t3.F; [6]
[6]: t4 == 1 ? [7] : [9]
[7]: t5 = t0.Item2; [8]
[8]: t5 == 2 ? [17] : [16]
[9]: t4 == 2 ? [15] : [18]
[10]: t1 is I1 ? [11] : [18]
[11]: t6 = (I1)t1; [12]
[12]: t7 = t6.F; [13]
[13]: t7 == 1 ? [15] : [14]
[14]: t7 == 2 ? [15] : [18]
[15]: t5 = t0.Item2; [16]
[16]: t5 == 1 ? [17] : [18]
[17]: leaf <isPatternSuccess> `(C12 and I2 and { F: 1 }, 2) or (I1 and { F: 1 or 2 }, 1)`
[18]: leaf <isPatternFailure> `(C12 and I2 and { F: 1 }, 2) or (I1 and { F: 1 or 2 }, 1)`
");

            var verifier = CompileAndVerify(
                comp,
                expectedOutput: @"
False
False
False
False
False
False
False
False
False
Evaluated C13.F True
Evaluated C13.F False
Evaluated C13.F False
Evaluated C14.F True
Evaluated C14.F False
Evaluated C14.F False
Evaluated C15.F True
Evaluated C15.F False
Evaluated C15.F False
Evaluated C15.F True
Evaluated C15.F True
Evaluated C15.F False
Evaluated C13.F True
Evaluated C13.F False
Evaluated C13.F False
Evaluated C14.F True
Evaluated C14.F False
Evaluated C14.F False
Evaluated C15.F True
Evaluated C15.F False
Evaluated C15.F False
Evaluated C15.F True
Evaluated C15.F False
Evaluated C15.F False
Evaluated C13.F False
Evaluated C13.F False
Evaluated C13.F False
Evaluated C14.F False
Evaluated C14.F False
Evaluated C14.F False
Evaluated C15.F False
Evaluated C15.F False
Evaluated C15.F False
Evaluated C15.F False
Evaluated C15.F False
Evaluated C15.F False
").VerifyDiagnostics();

            verifier.VerifyIL("Program.Test1", @"
{
  // Code size      111 (0x6f)
  .maxstack  2
  .locals init (object V_0,
            C12 V_1,
            I2 V_2,
            int V_3,
            int V_4,
            I1 V_5,
            int V_6,
            bool V_7)
  IL_0000:  ldarg.0
  IL_0001:  ldfld      ""object System.ValueTuple<object, int>.Item1""
  IL_0006:  stloc.0
  IL_0007:  ldloc.0
  IL_0008:  isinst     ""C12""
  IL_000d:  stloc.1
  IL_000e:  ldloc.1
  IL_000f:  brfalse.s  IL_003b
  IL_0011:  ldloc.1
  IL_0012:  isinst     ""I2""
  IL_0017:  stloc.2
  IL_0018:  ldloc.2
  IL_0019:  brfalse.s  IL_003b
  IL_001b:  ldloc.2
  IL_001c:  callvirt   ""int I1.F.get""
  IL_0021:  stloc.3
  IL_0022:  ldloc.3
  IL_0023:  ldc.i4.1
  IL_0024:  beq.s      IL_002c
  IL_0026:  ldloc.3
  IL_0027:  ldc.i4.2
  IL_0028:  beq.s      IL_0057
  IL_002a:  br.s       IL_0069
  IL_002c:  ldarg.0
  IL_002d:  ldfld      ""int System.ValueTuple<object, int>.Item2""
  IL_0032:  stloc.s    V_4
  IL_0034:  ldloc.s    V_4
  IL_0036:  ldc.i4.2
  IL_0037:  beq.s      IL_0064
  IL_0039:  br.s       IL_005f
  IL_003b:  ldloc.0
  IL_003c:  isinst     ""I1""
  IL_0041:  stloc.s    V_5
  IL_0043:  ldloc.s    V_5
  IL_0045:  brfalse.s  IL_0069
  IL_0047:  ldloc.s    V_5
  IL_0049:  callvirt   ""int I1.F.get""
  IL_004e:  stloc.s    V_6
  IL_0050:  ldloc.s    V_6
  IL_0052:  ldc.i4.1
  IL_0053:  sub
  IL_0054:  ldc.i4.1
  IL_0055:  bgt.un.s   IL_0069
  IL_0057:  ldarg.0
  IL_0058:  ldfld      ""int System.ValueTuple<object, int>.Item2""
  IL_005d:  stloc.s    V_4
  IL_005f:  ldloc.s    V_4
  IL_0061:  ldc.i4.1
  IL_0062:  bne.un.s   IL_0069
  IL_0064:  ldc.i4.1
  IL_0065:  stloc.s    V_7
  IL_0067:  br.s       IL_006c
  IL_0069:  ldc.i4.0
  IL_006a:  stloc.s    V_7
  IL_006c:  ldloc.s    V_7
  IL_006e:  ret
}
");
        }

        [Fact]
        [WorkItem("https://github.com/dotnet/roslyn/issues/82063")]
        public void SideeffectEvaluations_05()
        {
            var src = @"
interface I1
{
    int F {get;}
}

interface I2 : I1
{
}

class C11;
class C12;
class C13(int f) : C12, I1
{
    public int F
    {
        get
        {
            System.Console.Write(""Evaluated C13.F "");
            return f;   
        }
    }
}
class C14(int f) : I2
{
    public int F
    {
        get
        {
            System.Console.Write(""Evaluated C14.F "");
            return f;   
        }
    }
}
class C15(int f) : I1
{
    public int F
    {
        get
        {
            System.Console.Write(""Evaluated C15.F "");
            return f;   
        }
    }
}
class C16(int f) : C12, I2
{
    public int F
    {
        get
        {
            System.Console.Write(""Evaluated C15.F "");
            return f;   
        }
    }
}

class Program
{
    static void Main()
    {
        object[] s = [null, new C11(), new C12(), new C13(1), new C14(1), new C15(1), new C16(1), new C13(2), new C14(2), new C15(2), new C16(2), new C13(3), new C14(3), new C15(3), new C16(3)]; 
        int[] i = [1, 2, 3];
        foreach (var s1 in s)
        {
            foreach (var j in i)
            {
                var t = Test1((s1, j));
                System.Console.WriteLine(t);
            }
        }
    }

    static int Test1((object, int) u)
    {
        return u switch { (C12 and I1 and { F: 1 and var x1 }, 2) => x1 ,(I2 and { F: (1 or 2) and var x2 }, 1) => x2, _ => -100 };
    }   
}
";
            var comp = CreateCompilation(src, options: TestOptions.ReleaseExe);

            VerifyDecisionDagDump<SwitchExpressionSyntax>(comp,
@"[0]: t1 = t0.Item1; [1]
[1]: t1 is C12 ? [2] : [17]
[2]: t2 = (C12)t1; [3]
[3]: t2 is I1 ? [4] : [26]
[4]: t3 = (I1)t2; [5]
[5]: t4 = t3.F; [6]
[6]: t4 == 1 ? [7] : [12]
[7]: t5 = t0.Item2; [8]
[8]: t5 == 2 ? [9] : [11]
[9]: when <true> ? [10] : <unreachable>
[10]: leaf <arm> `(C12 and I1 and { F: 1 and var x1 }, 2) => x1`
[11]: t1 is I2 ? [15] : [26]
[12]: t1 is I2 ? [13] : [26]
[13]: t4 == 2 ? [14] : [26]
[14]: t5 = t0.Item2; [15]
[15]: t5 == 1 ? [16] : [26]
[16]: t8 <-- t4; [24]
[17]: t1 is I2 ? [18] : [26]
[18]: t7 = (I2)t1; [19]
[19]: t8 = t7.F; [20]
[20]: t8 == 1 ? [22] : [21]
[21]: t8 == 2 ? [22] : [26]
[22]: t5 = t0.Item2; [23]
[23]: t5 == 1 ? [24] : [26]
[24]: when <true> ? [25] : <unreachable>
[25]: leaf <arm> `(I2 and { F: (1 or 2) and var x2 }, 1) => x2`
[26]: leaf <arm> `_ => -100`
");

            var verifier = CompileAndVerify(
                comp,
                expectedOutput: @"
-100
-100
-100
-100
-100
-100
-100
-100
-100
Evaluated C13.F -100
Evaluated C13.F 1
Evaluated C13.F -100
Evaluated C14.F 1
Evaluated C14.F -100
Evaluated C14.F -100
-100
-100
-100
Evaluated C15.F 1
Evaluated C15.F 1
Evaluated C15.F -100
Evaluated C13.F -100
Evaluated C13.F -100
Evaluated C13.F -100
Evaluated C14.F 2
Evaluated C14.F -100
Evaluated C14.F -100
-100
-100
-100
Evaluated C15.F 2
Evaluated C15.F -100
Evaluated C15.F -100
Evaluated C13.F -100
Evaluated C13.F -100
Evaluated C13.F -100
Evaluated C14.F -100
Evaluated C14.F -100
Evaluated C14.F -100
-100
-100
-100
Evaluated C15.F -100
Evaluated C15.F -100
Evaluated C15.F -100
").VerifyDiagnostics();

            verifier.VerifyIL("Program.Test1", @"
{
  // Code size      150 (0x96)
  .maxstack  2
  .locals init (int V_0, //x1
            int V_1, //x2
            int V_2,
            object V_3,
            C12 V_4,
            I1 V_5,
            int V_6,
            I2 V_7)
  IL_0000:  ldarg.0
  IL_0001:  ldfld      ""object System.ValueTuple<object, int>.Item1""
  IL_0006:  stloc.3
  IL_0007:  ldloc.3
  IL_0008:  isinst     ""C12""
  IL_000d:  stloc.s    V_4
  IL_000f:  ldloc.s    V_4
  IL_0011:  brfalse.s  IL_0060
  IL_0013:  ldloc.s    V_4
  IL_0015:  isinst     ""I1""
  IL_001a:  stloc.s    V_5
  IL_001c:  ldloc.s    V_5
  IL_001e:  brfalse.s  IL_0091
  IL_0020:  ldloc.s    V_5
  IL_0022:  callvirt   ""int I1.F.get""
  IL_0027:  stloc.0
  IL_0028:  ldloc.0
  IL_0029:  ldc.i4.1
  IL_002a:  bne.un.s   IL_0043
  IL_002c:  ldarg.0
  IL_002d:  ldfld      ""int System.ValueTuple<object, int>.Item2""
  IL_0032:  stloc.s    V_6
  IL_0034:  ldloc.s    V_6
  IL_0036:  ldc.i4.2
  IL_0037:  beq.s      IL_0089
  IL_0039:  ldloc.3
  IL_003a:  isinst     ""I2""
  IL_003f:  brtrue.s   IL_0057
  IL_0041:  br.s       IL_0091
  IL_0043:  ldloc.3
  IL_0044:  isinst     ""I2""
  IL_0049:  brfalse.s  IL_0091
  IL_004b:  ldloc.0
  IL_004c:  ldc.i4.2
  IL_004d:  bne.un.s   IL_0091
  IL_004f:  ldarg.0
  IL_0050:  ldfld      ""int System.ValueTuple<object, int>.Item2""
  IL_0055:  stloc.s    V_6
  IL_0057:  ldloc.s    V_6
  IL_0059:  ldc.i4.1
  IL_005a:  bne.un.s   IL_0091
  IL_005c:  ldloc.0
  IL_005d:  stloc.1
  IL_005e:  br.s       IL_008d
  IL_0060:  ldloc.3
  IL_0061:  isinst     ""I2""
  IL_0066:  stloc.s    V_7
  IL_0068:  ldloc.s    V_7
  IL_006a:  brfalse.s  IL_0091
  IL_006c:  ldloc.s    V_7
  IL_006e:  callvirt   ""int I1.F.get""
  IL_0073:  stloc.1
  IL_0074:  ldloc.1
  IL_0075:  ldc.i4.1
  IL_0076:  sub
  IL_0077:  ldc.i4.1
  IL_0078:  bgt.un.s   IL_0091
  IL_007a:  ldarg.0
  IL_007b:  ldfld      ""int System.ValueTuple<object, int>.Item2""
  IL_0080:  stloc.s    V_6
  IL_0082:  ldloc.s    V_6
  IL_0084:  ldc.i4.1
  IL_0085:  beq.s      IL_008d
  IL_0087:  br.s       IL_0091
  IL_0089:  ldloc.0
  IL_008a:  stloc.2
  IL_008b:  br.s       IL_0094
  IL_008d:  ldloc.1
  IL_008e:  stloc.2
  IL_008f:  br.s       IL_0094
  IL_0091:  ldc.i4.s   -100
  IL_0093:  stloc.2
  IL_0094:  ldloc.2
  IL_0095:  ret
}
");
        }

        [Fact]
        [WorkItem("https://github.com/dotnet/roslyn/issues/82063")]
        public void SideeffectEvaluations_06()
        {
            var src = @"
#nullable enable

interface I1
{
    C2? F { get; }
}

class C2
{
    public string? S = null;
}

interface I2 : I1
{
}

class C11;
class C12;
class C13 : C12, I1
{
    public C2? F => null;
}
class C14 : I2
{
    public C2? F => null;
}
class C15 : I1
{
    public C2? F => null;
}
class C16 : C12, I2
{
    public C2? F => null;
}

class Program
{
    static int Test1((object, int) u)
    {
        return u switch 
        {
            (C12 and I1 and { F: { S: ""1"" and var x1 } }, 2) => x1.Length ,
            (I2 and { F: { S: (""1"" or ""2"") and var x2 } }, 1) => x2.Length,
            _ => -100
        };
    }   

    static int Test2((object, int) u)
    {
        return u switch 
        {
            (C12 and I1 and { F: { S: ""1"" } x3 }, 2) => x3.S.Length ,
            (I2 and { F: { S: (""1"" or ""2"") } x4 }, 1) => x4.S.Length,
            _ => -100
        };
    }   
}
";
            var comp = CreateCompilation(src, options: TestOptions.ReleaseDll);
            comp.VerifyDiagnostics();
        }

        [Fact]
        [WorkItem("https://github.com/dotnet/roslyn/issues/82063")]
        public void SideeffectEvaluations_07()
        {
            var src = @"
class C0;

class C01(bool p) : C0
{
    public bool P => p;
}


class C1(bool p) : C01(p);

class C02(bool p) : C0
{
    public bool P => p;
}

class C2(bool p) : C02(p);

class C3(bool p) : C01(p);

class C4(bool p) : C01(p);

class C03(bool p) : C0
{
    public bool P => p;
}

class C5(bool p) : C03(p);

class C6(bool p) : C01(p);

static class Program
{
    static void Main()
    {
        C0[] s = [null, new C1(true), new C2(true), new C3(true), new C4(true), new C5(true), new C6(true), new C1(false), new C2(false), new C3(false), new C4(false), new C5(false), new C6(false)]; 
        foreach (var s1 in s)
        {
            var t = s1.Test1();
            System.Console.WriteLine(t);
        }
    }

    internal static bool Test1(this C0 c)
    {
        return c
            is C1 { P: true }
            or C2 { P: true }
            or C3 { P: true }
            or C4 { P: true }
            or C5 { P: true }
            or C6 { P: true };
    }
}
";
            var comp = CreateCompilation(src, options: TestOptions.ReleaseExe);

            VerifyDecisionDagDump<IsPatternExpressionSyntax>(comp,
@"[0]: t0 is C1 ? [1] : [4]
[1]: t1 = (C1)t0; [2]
[2]: t2 = t1.P; [3]
[3]: t2 == True ? [24] : [25]
[4]: t0 is C2 ? [5] : [8]
[5]: t3 = (C2)t0; [6]
[6]: t4 = t3.P; [7]
[7]: t4 == True ? [24] : [25]
[8]: t0 is C3 ? [9] : [12]
[9]: t5 = (C3)t0; [10]
[10]: t6 = t5.P; [11]
[11]: t6 == True ? [24] : [25]
[12]: t0 is C4 ? [13] : [16]
[13]: t7 = (C4)t0; [14]
[14]: t8 = t7.P; [15]
[15]: t8 == True ? [24] : [25]
[16]: t0 is C5 ? [17] : [20]
[17]: t9 = (C5)t0; [18]
[18]: t10 = t9.P; [19]
[19]: t10 == True ? [24] : [25]
[20]: t0 is C6 ? [21] : [25]
[21]: t11 = (C6)t0; [22]
[22]: t12 = t11.P; [23]
[23]: t12 == True ? [24] : [25]
[24]: leaf <isPatternSuccess> `C1 { P: true }
            or C2 { P: true }
            or C3 { P: true }
            or C4 { P: true }
            or C5 { P: true }
            or C6 { P: true }`
[25]: leaf <isPatternFailure> `C1 { P: true }
            or C2 { P: true }
            or C3 { P: true }
            or C4 { P: true }
            or C5 { P: true }
            or C6 { P: true }`
");

            var verifier = CompileAndVerify(
                comp,
                expectedOutput: @"
False
True
True
True
True
True
True
False
False
False
False
False
False
").VerifyDiagnostics();

            verifier.VerifyIL("Program.Test1", @"
{
  // Code size      135 (0x87)
  .maxstack  1
  .locals init (C1 V_0,
            C2 V_1,
            C3 V_2,
            C4 V_3,
            C5 V_4,
            C6 V_5,
            bool V_6)
  IL_0000:  ldarg.0
  IL_0001:  isinst     ""C1""
  IL_0006:  stloc.0
  IL_0007:  ldloc.0
  IL_0008:  brfalse.s  IL_0014
  IL_000a:  ldloc.0
  IL_000b:  callvirt   ""bool C01.P.get""
  IL_0010:  brtrue.s   IL_007c
  IL_0012:  br.s       IL_0081
  IL_0014:  ldarg.0
  IL_0015:  isinst     ""C2""
  IL_001a:  stloc.1
  IL_001b:  ldloc.1
  IL_001c:  brfalse.s  IL_0028
  IL_001e:  ldloc.1
  IL_001f:  callvirt   ""bool C02.P.get""
  IL_0024:  brtrue.s   IL_007c
  IL_0026:  br.s       IL_0081
  IL_0028:  ldarg.0
  IL_0029:  isinst     ""C3""
  IL_002e:  stloc.2
  IL_002f:  ldloc.2
  IL_0030:  brfalse.s  IL_003c
  IL_0032:  ldloc.2
  IL_0033:  callvirt   ""bool C01.P.get""
  IL_0038:  brtrue.s   IL_007c
  IL_003a:  br.s       IL_0081
  IL_003c:  ldarg.0
  IL_003d:  isinst     ""C4""
  IL_0042:  stloc.3
  IL_0043:  ldloc.3
  IL_0044:  brfalse.s  IL_0050
  IL_0046:  ldloc.3
  IL_0047:  callvirt   ""bool C01.P.get""
  IL_004c:  brtrue.s   IL_007c
  IL_004e:  br.s       IL_0081
  IL_0050:  ldarg.0
  IL_0051:  isinst     ""C5""
  IL_0056:  stloc.s    V_4
  IL_0058:  ldloc.s    V_4
  IL_005a:  brfalse.s  IL_0067
  IL_005c:  ldloc.s    V_4
  IL_005e:  callvirt   ""bool C03.P.get""
  IL_0063:  brtrue.s   IL_007c
  IL_0065:  br.s       IL_0081
  IL_0067:  ldarg.0
  IL_0068:  isinst     ""C6""
  IL_006d:  stloc.s    V_5
  IL_006f:  ldloc.s    V_5
  IL_0071:  brfalse.s  IL_0081
  IL_0073:  ldloc.s    V_5
  IL_0075:  callvirt   ""bool C01.P.get""
  IL_007a:  brfalse.s  IL_0081
  IL_007c:  ldc.i4.1
  IL_007d:  stloc.s    V_6
  IL_007f:  br.s       IL_0084
  IL_0081:  ldc.i4.0
  IL_0082:  stloc.s    V_6
  IL_0084:  ldloc.s    V_6
  IL_0086:  ret
}
");
        }

        [Fact]
        [WorkItem("https://github.com/dotnet/roslyn/issues/82063")]
        public void SideeffectEvaluations_08()
        {
            var src = @"
interface I1
{
    int F {get;}
}

class C12;
class C13(int f) : C12, I1
{
    public int F
    {
        get
        {
            System.Console.Write(""Evaluated C13.F "");
            return f;   
        }
    }
}
class C14(int f) : I1
{
    public int F
    {
        get
        {
            System.Console.Write(""Evaluated C14.F "");
            return f;   
        }
    }
}

class Program
{
    static void Main()
    {
        I1[] s = [null, new C13(1), new C14(1), new C13(2), new C14(2), new C13(3), new C14(3)]; 
        int[] i = [1, 2, 3];
        foreach (var s1 in s)
        {
            foreach (var j in i)
            {
                var t = Test1((s1, j));
                System.Console.WriteLine(t);
            }
        }
    }

    static bool Test1((I1, int) u)
    {
        return u is (C12 and I1 and { F: 1 }, 2) or ({ F: 1 or 2 }, 1);
    }   
}
";
            var comp = CreateCompilation(src, options: TestOptions.ReleaseExe);

            VerifyDecisionDagDump<IsPatternExpressionSyntax>(comp,
@"[0]: t1 = t0.Item1; [1]
[1]: t1 is C12 ? [2] : [8]
[2]: t2 = (C12)t1; [3]
[3]: t2 is I1 ? [4] : [9]
[4]: t3 = t1.F; [5]
[5]: t3 == 1 ? [6] : [11]
[6]: t4 = t0.Item2; [7]
[7]: t4 == 2 ? [14] : [13]
[8]: t1 != null ? [9] : [15]
[9]: t3 = t1.F; [10]
[10]: t3 == 1 ? [12] : [11]
[11]: t3 == 2 ? [12] : [15]
[12]: t4 = t0.Item2; [13]
[13]: t4 == 1 ? [14] : [15]
[14]: leaf <isPatternSuccess> `(C12 and I1 and { F: 1 }, 2) or ({ F: 1 or 2 }, 1)`
[15]: leaf <isPatternFailure> `(C12 and I1 and { F: 1 }, 2) or ({ F: 1 or 2 }, 1)`
");

            var verifier = CompileAndVerify(
                comp,
                expectedOutput: @"
False
False
False
Evaluated C13.F True
Evaluated C13.F True
Evaluated C13.F False
Evaluated C14.F True
Evaluated C14.F False
Evaluated C14.F False
Evaluated C13.F True
Evaluated C13.F False
Evaluated C13.F False
Evaluated C14.F True
Evaluated C14.F False
Evaluated C14.F False
Evaluated C13.F False
Evaluated C13.F False
Evaluated C13.F False
Evaluated C14.F False
Evaluated C14.F False
Evaluated C14.F False
").VerifyDiagnostics(
                );

            verifier.VerifyIL("Program.Test1", @"
{
  // Code size       89 (0x59)
  .maxstack  2
  .locals init (I1 V_0,
            C12 V_1,
            int V_2,
            int V_3,
            bool V_4)
  IL_0000:  ldarg.0
  IL_0001:  ldfld      ""I1 System.ValueTuple<I1, int>.Item1""
  IL_0006:  stloc.0
  IL_0007:  ldloc.0
  IL_0008:  isinst     ""C12""
  IL_000d:  stloc.1
  IL_000e:  ldloc.1
  IL_000f:  brfalse.s  IL_0031
  IL_0011:  ldloc.1
  IL_0012:  isinst     ""I1""
  IL_0017:  brfalse.s  IL_0034
  IL_0019:  ldloc.0
  IL_001a:  callvirt   ""int I1.F.get""
  IL_001f:  stloc.2
  IL_0020:  ldloc.2
  IL_0021:  ldc.i4.1
  IL_0022:  bne.un.s   IL_003f
  IL_0024:  ldarg.0
  IL_0025:  ldfld      ""int System.ValueTuple<I1, int>.Item2""
  IL_002a:  stloc.3
  IL_002b:  ldloc.3
  IL_002c:  ldc.i4.2
  IL_002d:  beq.s      IL_004e
  IL_002f:  br.s       IL_004a
  IL_0031:  ldloc.0
  IL_0032:  brfalse.s  IL_0053
  IL_0034:  ldloc.0
  IL_0035:  callvirt   ""int I1.F.get""
  IL_003a:  stloc.2
  IL_003b:  ldloc.2
  IL_003c:  ldc.i4.1
  IL_003d:  beq.s      IL_0043
  IL_003f:  ldloc.2
  IL_0040:  ldc.i4.2
  IL_0041:  bne.un.s   IL_0053
  IL_0043:  ldarg.0
  IL_0044:  ldfld      ""int System.ValueTuple<I1, int>.Item2""
  IL_0049:  stloc.3
  IL_004a:  ldloc.3
  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 SideeffectEvaluations_09()
        {
            var src = @"
using System;

class C11;

class C12;

struct S1
{

    static void Main()
    {
        object[] s = [null, (new C11()), (new C12()), (1), (""1""), (2), (""2""), (3), (""3"")]; 
        int[] i = [1, 2, 3];
        foreach (var s1 in s)
        {
            foreach (var j in i)
            {
                var t = Test1((s1, j));
                System.Console.WriteLine(t);
            }
        }
    }

    static bool Test1((object, 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 => c as int?;
    }
}
";
            var comp = CreateCompilation(src, options: TestOptions.ReleaseExe);

            VerifyDecisionDagDump<IsPatternExpressionSyntax>(comp,
@"[0]: t1 = t0.Item1; [1]
[1]: t1 is int ? [2] : [11]
[2]: t2 = (int)t1; [3]
[3]: t2 == 1 ? [4] : [12]
[4]: t3 = t0.Item2; [5]
[5]: t3 == 2 ? [19] : [6]
[6]: t4 = (System.IComparable)t1; [7]
[7]: t5 = t4.AsInt; [8]
[8]: t5 != null ? [9] : [20]
[9]: t6 = (int)t5; [10]
[10]: t6 == 3 ? [18] : [20]
[11]: t1 is System.IComparable ? [12] : [20]
[12]: t4 = (System.IComparable)t1; [13]
[13]: t5 = t4.AsInt; [14]
[14]: t5 != null ? [15] : [20]
[15]: t6 = (int)t5; [16]
[16]: t6 == 3 ? [17] : [20]
[17]: t3 = t0.Item2; [18]
[18]: t3 == 1 ? [19] : [20]
[19]: leaf <isPatternSuccess> `(int and 1, 2) or (System.IComparable and { AsInt: 3 }, 1)`
[20]: leaf <isPatternFailure> `(int and 1, 2) or (System.IComparable and { AsInt: 3 }, 1)`
",
forLowering: true);

            var verifier = CompileAndVerify(
                comp,
                expectedOutput: @"
False
False
False
False
False
False
False
False
False
False
True
False
False
False
False
False
False
False
False
False
False
True
False
False
False
False
False
").VerifyDiagnostics();

            verifier.VerifyIL("S1.Test1", @"
{
  // Code size      137 (0x89)
  .maxstack  2
  .locals init (object V_0,
                int V_1,
                System.IComparable V_2,
                int? V_3,
                bool V_4)
  IL_0000:  ldarg.0
  IL_0001:  ldfld      ""object System.ValueTuple<object, int>.Item1""
  IL_0006:  stloc.0
  IL_0007:  ldloc.0
  IL_0008:  isinst     ""int""
  IL_000d:  brfalse.s  IL_0046
  IL_000f:  ldloc.0
  IL_0010:  unbox.any  ""int""
  IL_0015:  ldc.i4.1
  IL_0016:  bne.un.s   IL_0052
  IL_0018:  ldarg.0
  IL_0019:  ldfld      ""int System.ValueTuple<object, int>.Item2""
  IL_001e:  stloc.1
  IL_001f:  ldloc.1
  IL_0020:  ldc.i4.2
  IL_0021:  beq.s      IL_007e
  IL_0023:  ldloc.0
  IL_0024:  castclass  ""System.IComparable""
  IL_0029:  stloc.2
  IL_002a:  ldloc.2
  IL_002b:  call       ""int? IComparableExtensions.get_AsInt(System.IComparable)""
  IL_0030:  stloc.3
  IL_0031:  ldloca.s   V_3
  IL_0033:  call       ""bool int?.HasValue.get""
  IL_0038:  brfalse.s  IL_0083
  IL_003a:  ldloca.s   V_3
  IL_003c:  call       ""int int?.GetValueOrDefault()""
  IL_0041:  ldc.i4.3
  IL_0042:  beq.s      IL_007a
  IL_0044:  br.s       IL_0083
  IL_0046:  ldloc.0
  IL_0047:  isinst     ""System.IComparable""
  IL_004c:  stloc.2
  IL_004d:  ldloc.2
  IL_004e:  brtrue.s   IL_0059
  IL_0050:  br.s       IL_0083
  IL_0052:  ldloc.0
  IL_0053:  castclass  ""System.IComparable""
  IL_0058:  stloc.2
  IL_0059:  ldloc.2
  IL_005a:  call       ""int? IComparableExtensions.get_AsInt(System.IComparable)""
  IL_005f:  stloc.3
  IL_0060:  ldloca.s   V_3
  IL_0062:  call       ""bool int?.HasValue.get""
  IL_0067:  brfalse.s  IL_0083
  IL_0069:  ldloca.s   V_3
  IL_006b:  call       ""int int?.GetValueOrDefault()""
  IL_0070:  ldc.i4.3
  IL_0071:  bne.un.s   IL_0083
  IL_0073:  ldarg.0
  IL_0074:  ldfld      ""int System.ValueTuple<object, int>.Item2""
  IL_0079:  stloc.1
  IL_007a:  ldloc.1
  IL_007b:  ldc.i4.1
  IL_007c:  bne.un.s   IL_0083
  IL_007e:  ldc.i4.1
  IL_007f:  stloc.s    V_4
  IL_0081:  br.s       IL_0086
  IL_0083:  ldc.i4.0
  IL_0084:  stloc.s    V_4
  IL_0086:  ldloc.s    V_4
  IL_0088:  ret
}
");
        }

        [Fact]
        public void ValueSet_WithTypePatternAndOrValues()
        {
            // Exercises ValueSet in combination with type tests on an object input.
            // The `int and (1 or 2 or 3)` pattern creates a ValueSet on the typed int temp.
            var source = """
class C
{
    public static void Main()
    {
        System.Console.Write(Test(1));
        System.Console.Write(Test(2));
        System.Console.Write(Test(3));
        System.Console.Write(Test(4));
        System.Console.Write(Test("x"));
        System.Console.Write(Test(null));
    }
    public static string Test(object o)
    {
        return o switch
        {
            int and (1 or 2 or 3) => "V",
            not null => "O",
            null => "N",
        };
    }
}
""";
            CompileAndVerify(source, expectedOutput: "VVVOON");
        }

        [Fact]
        public void ValueSet_FilterWithExplicitNullTest()
        {
            // Exercises ValueSet.Filter with BoundDagExplicitNullTest.
            // The `null` arm creates an explicit null test on the object input.
            // When filtering the ValueSet (inside the `int and (1 or 2 or 3)` arm)
            // with this null test, the ValueSet must correctly return
            // whenTrue = False (null can't match values), whenFalse = this.
            var source = """
class C
{
    public static void Main()
    {
        System.Console.Write(Test(1));
        System.Console.Write(Test(2));
        System.Console.Write(Test(3));
        System.Console.Write(Test(4));
        System.Console.Write(Test("x"));
        System.Console.Write(Test(null));
    }
    public static string Test(object o)
    {
        return o switch
        {
            null => "N",
            int and (1 or 2 or 3) => "V",
            _ => "O",
        };
    }
}
""";
            CompileAndVerify(source, expectedOutput: "VVVOON");
        }

        [Fact]
        public void ValueSet_UnionNonNullTest_Implicit()
        {
            // Captures the DAG shape for an implicit union value pattern. Unlike the
            // explicit type-pattern cases below, this form is not expected to create
            // a ValueSet on the union value input.
            var source = """
                union S1(int, string)
                {
                    static void Main()
                    {
                        System.Console.Write(Test(new S1(1)));
                        System.Console.Write(Test(new S1(3)));
                        System.Console.Write(Test(new S1(5)));
                        System.Console.Write(Test(new S1(7)));
                        System.Console.Write(Test(new S1("hello")));
                    }

                    static int Test(S1 u)
                    {
                        return u switch { string => 0, 1 or 3 or 5 => 1, _ => 2 };
                    }
                }
                """;
            var comp = CreateCompilation([source, UnionAttributeSource, IUnionSource], options: TestOptions.ReleaseExe);
            comp.VerifyDiagnostics();
            VerifyDecisionDagDump<SwitchExpressionSyntax>(comp,
@"[0]: t1 = t0.Value; [1]
[1]: t1 != null ? [2] : [9]
[2]: t1 is string ? [3] : [4]
[3]: leaf <arm> `string => 0`
[4]: t2 = (int)t1; [5]
[5]: t2 == 1 ? [8] : [6]
[6]: t2 == 3 ? [8] : [7]
[7]: t2 == 5 ? [8] : [9]
[8]: leaf <arm> `1 or 3 or 5 => 1`
[9]: leaf <arm> `_ => 2`
",
forLowering: false);
            CompileAndVerify(comp, expectedOutput: "11120");
        }

        [Fact]
        public void ValueSet_BadConstant()
        {
            verify("C.Missing or 1",
@"[0]: t0 == bad ? [2] : [1]
[1]: t0 == 1 ? [2] : [3]
[2]: leaf <isPatternSuccess> `C.Missing or 1`
[3]: leaf <isPatternFailure> `C.Missing or 1`
",
                // (3,47): error CS0117: 'C' does not contain a definition for 'Missing'
                //     static bool Test(int value) => value is C.Missing or 1;
                Diagnostic(ErrorCode.ERR_NoSuchMember, "Missing").WithArguments("C", "Missing").WithLocation(3, 47));
            verify("1 or C.Missing",
@"[0]: t0 == 1 ? [2] : [1]
[1]: t0 == bad ? [2] : [3]
[2]: leaf <isPatternSuccess> `1 or C.Missing`
[3]: leaf <isPatternFailure> `1 or C.Missing`
",
                // (3,52): error CS0117: 'C' does not contain a definition for 'Missing'
                //     static bool Test(int value) => value is 1 or C.Missing;
                Diagnostic(ErrorCode.ERR_NoSuchMember, "Missing").WithArguments("C", "Missing").WithLocation(3, 52));

            void verify(string pattern, string expectedDag, DiagnosticDescription expectedDiagnostic)
            {
                var source = $$"""
                    class C
                    {
                        static bool Test(int value) => value is {{pattern}};
                    }
                    """;
                var comp = CreateCompilation(source);

                comp.VerifyDiagnostics(expectedDiagnostic);
                VerifyDecisionDagDump<IsPatternExpressionSyntax>(comp, expectedDag, forLowering: false);
            }
        }

        [Fact]
        public void ValueSet_LoweringOrder_Numeric()
        {
            // Values are intentionally listed in descending order so the IL observes any canonicalization.
            var source = """
                enum E
                {
                    Ten = 10,
                    Fifty = 50,
                }

                class C
                {
                    public static bool SByte(sbyte value) => value is 50 or 10;
                    public static bool Byte(byte value) => value is 50 or 10;
                    public static bool Int16(short value) => value is 50 or 10;
                    public static bool UInt16(ushort value) => value is 50 or 10;
                    public static bool Int32(int value) => value is 50 or 10;
                    public static bool UInt32(uint value) => value is 50 or 10;
                    public static bool Int64(long value) => value is 50 or 10;
                    public static bool UInt64(ulong value) => value is 50 or 10;
                    public static bool Enum(E value) => value is E.Fifty or E.Ten;
                    public static bool Char(char value) => value is 'z' or 'a';
                    public static bool NInt(nint value) => value is 50 or 10;
                    public static bool NUInt(nuint value) => value is 50 or 10;
                    public static bool Decimal(decimal value) => value is 1m or 0m;
                    public static bool Single(float value) => value is 50f or 10f;
                    public static bool Double(double value) => value is 50d or 10d;
                }
                """;
            var verifier = CompileAndVerify(source, options: TestOptions.ReleaseDll);

            const string expectedInt32IL = """
                {
                  // Code size       18 (0x12)
                  .maxstack  2
                  .locals init (bool V_0)
                  IL_0000:  ldarg.0
                  IL_0001:  ldc.i4.s   10
                  IL_0003:  beq.s      IL_000a
                  IL_0005:  ldarg.0
                  IL_0006:  ldc.i4.s   50
                  IL_0008:  bne.un.s   IL_000e
                  IL_000a:  ldc.i4.1
                  IL_000b:  stloc.0
                  IL_000c:  br.s       IL_0010
                  IL_000e:  ldc.i4.0
                  IL_000f:  stloc.0
                  IL_0010:  ldloc.0
                  IL_0011:  ret
                }
                """;
            verifier.VerifyIL("C.SByte", expectedInt32IL);
            verifier.VerifyIL("C.Byte", expectedInt32IL);
            verifier.VerifyIL("C.Int16", expectedInt32IL);
            verifier.VerifyIL("C.UInt16", expectedInt32IL);
            verifier.VerifyIL("C.Int32", expectedInt32IL);
            verifier.VerifyIL("C.UInt32", expectedInt32IL);
            verifier.VerifyIL("C.Enum", expectedInt32IL);
            verifier.VerifyIL("C.Int64", """
                {
                  // Code size       20 (0x14)
                  .maxstack  2
                  .locals init (bool V_0)
                  IL_0000:  ldarg.0
                  IL_0001:  ldc.i4.s   10
                  IL_0003:  conv.i8
                  IL_0004:  beq.s      IL_000c
                  IL_0006:  ldarg.0
                  IL_0007:  ldc.i4.s   50
                  IL_0009:  conv.i8
                  IL_000a:  bne.un.s   IL_0010
                  IL_000c:  ldc.i4.1
                  IL_000d:  stloc.0
                  IL_000e:  br.s       IL_0012
                  IL_0010:  ldc.i4.0
                  IL_0011:  stloc.0
                  IL_0012:  ldloc.0
                  IL_0013:  ret
                }
                """);
            verifier.VerifyIL("C.UInt64", """
                {
                  // Code size       20 (0x14)
                  .maxstack  2
                  .locals init (bool V_0)
                  IL_0000:  ldarg.0
                  IL_0001:  ldc.i4.s   10
                  IL_0003:  conv.i8
                  IL_0004:  beq.s      IL_000c
                  IL_0006:  ldarg.0
                  IL_0007:  ldc.i4.s   50
                  IL_0009:  conv.i8
                  IL_000a:  bne.un.s   IL_0010
                  IL_000c:  ldc.i4.1
                  IL_000d:  stloc.0
                  IL_000e:  br.s       IL_0012
                  IL_0010:  ldc.i4.0
                  IL_0011:  stloc.0
                  IL_0012:  ldloc.0
                  IL_0013:  ret
                }
                """);
            verifier.VerifyIL("C.Char", """
                {
                  // Code size       18 (0x12)
                  .maxstack  2
                  .locals init (bool V_0)
                  IL_0000:  ldarg.0
                  IL_0001:  ldc.i4.s   97
                  IL_0003:  beq.s      IL_000a
                  IL_0005:  ldarg.0
                  IL_0006:  ldc.i4.s   122
                  IL_0008:  bne.un.s   IL_000e
                  IL_000a:  ldc.i4.1
                  IL_000b:  stloc.0
                  IL_000c:  br.s       IL_0010
                  IL_000e:  ldc.i4.0
                  IL_000f:  stloc.0
                  IL_0010:  ldloc.0
                  IL_0011:  ret
                }
                """);
            verifier.VerifyIL("C.NInt", """
                {
                  // Code size       23 (0x17)
                  .maxstack  2
                  .locals init (bool V_0,
                                long V_1)
                  IL_0000:  ldarg.0
                  IL_0001:  conv.i8
                  IL_0002:  stloc.1
                  IL_0003:  ldloc.1
                  IL_0004:  ldc.i4.s   10
                  IL_0006:  conv.i8
                  IL_0007:  beq.s      IL_000f
                  IL_0009:  ldloc.1
                  IL_000a:  ldc.i4.s   50
                  IL_000c:  conv.i8
                  IL_000d:  bne.un.s   IL_0013
                  IL_000f:  ldc.i4.1
                  IL_0010:  stloc.0
                  IL_0011:  br.s       IL_0015
                  IL_0013:  ldc.i4.0
                  IL_0014:  stloc.0
                  IL_0015:  ldloc.0
                  IL_0016:  ret
                }
                """);
            verifier.VerifyIL("C.NUInt", """
                {
                  // Code size       23 (0x17)
                  .maxstack  2
                  .locals init (bool V_0,
                                ulong V_1)
                  IL_0000:  ldarg.0
                  IL_0001:  conv.u8
                  IL_0002:  stloc.1
                  IL_0003:  ldloc.1
                  IL_0004:  ldc.i4.s   10
                  IL_0006:  conv.i8
                  IL_0007:  beq.s      IL_000f
                  IL_0009:  ldloc.1
                  IL_000a:  ldc.i4.s   50
                  IL_000c:  conv.i8
                  IL_000d:  bne.un.s   IL_0013
                  IL_000f:  ldc.i4.1
                  IL_0010:  stloc.0
                  IL_0011:  br.s       IL_0015
                  IL_0013:  ldc.i4.0
                  IL_0014:  stloc.0
                  IL_0015:  ldloc.0
                  IL_0016:  ret
                }
                """);
            verifier.VerifyIL("C.Decimal", """
                {
                  // Code size       58 (0x3a)
                  .maxstack  6
                  .locals init (bool V_0)
                  IL_0000:  ldarg.0
                  IL_0001:  ldc.i4.0
                  IL_0002:  ldc.i4.0
                  IL_0003:  ldc.i4.0
                  IL_0004:  ldc.i4.0
                  IL_0005:  ldc.i4.s   28
                  IL_0007:  newobj     "decimal..ctor(int, int, int, bool, byte)"
                  IL_000c:  call       "bool decimal.op_Equality(decimal, decimal)"
                  IL_0011:  brtrue.s   IL_0032
                  IL_0013:  ldarg.0
                  IL_0014:  ldc.i4     0x10000000
                  IL_0019:  ldc.i4     0x3e250261
                  IL_001e:  ldc.i4     0x204fce5e
                  IL_0023:  ldc.i4.0
                  IL_0024:  ldc.i4.s   28
                  IL_0026:  newobj     "decimal..ctor(int, int, int, bool, byte)"
                  IL_002b:  call       "bool decimal.op_Equality(decimal, decimal)"
                  IL_0030:  brfalse.s  IL_0036
                  IL_0032:  ldc.i4.1
                  IL_0033:  stloc.0
                  IL_0034:  br.s       IL_0038
                  IL_0036:  ldc.i4.0
                  IL_0037:  stloc.0
                  IL_0038:  ldloc.0
                  IL_0039:  ret
                }
                """);
            verifier.VerifyIL("C.Single", """
                {
                  // Code size       24 (0x18)
                  .maxstack  2
                  .locals init (bool V_0)
                  IL_0000:  ldarg.0
                  IL_0001:  ldc.r4     10
                  IL_0006:  beq.s      IL_0010
                  IL_0008:  ldarg.0
                  IL_0009:  ldc.r4     50
                  IL_000e:  bne.un.s   IL_0014
                  IL_0010:  ldc.i4.1
                  IL_0011:  stloc.0
                  IL_0012:  br.s       IL_0016
                  IL_0014:  ldc.i4.0
                  IL_0015:  stloc.0
                  IL_0016:  ldloc.0
                  IL_0017:  ret
                }
                """);
            verifier.VerifyIL("C.Double", """
                {
                  // Code size       32 (0x20)
                  .maxstack  2
                  .locals init (bool V_0)
                  IL_0000:  ldarg.0
                  IL_0001:  ldc.r8     10
                  IL_000a:  beq.s      IL_0018
                  IL_000c:  ldarg.0
                  IL_000d:  ldc.r8     50
                  IL_0016:  bne.un.s   IL_001c
                  IL_0018:  ldc.i4.1
                  IL_0019:  stloc.0
                  IL_001a:  br.s       IL_001e
                  IL_001c:  ldc.i4.0
                  IL_001d:  stloc.0
                  IL_001e:  ldloc.0
                  IL_001f:  ret
                }
                """);
        }

        [Fact]
        public void ValueSet_LoweringOrder_StringAndSpan()
        {
            // Values are intentionally listed in descending order so the IL observes both direct and optimized dispatch.
            var source = """
                using System;

                class C
                {
                    public static bool String(string value) => value is "z" or "a";
                    public static bool Span(Span<char> value) => value is "z" or "a";
                    public static bool ReadOnlySpan(ReadOnlySpan<char> value) => value is "z" or "a";

                    public static bool LargeString(string value) =>
                        value is "g" or "f" or "e" or "d" or "c" or "b" or "a";

                    public static bool LargeSpan(Span<char> value) =>
                        value is "g" or "f" or "e" or "d" or "c" or "b" or "a";

                    public static bool LargeReadOnlySpan(ReadOnlySpan<char> value) =>
                        value is "g" or "f" or "e" or "d" or "c" or "b" or "a";
                }
                """;
            var comp = CreateCompilationWithSpanAndMemoryExtensions(
                source,
                options: TestOptions.ReleaseDll,
                parseOptions: TestOptions.RegularPreview);
            var verifier = CompileAndVerify(comp);

            verifier.VerifyIL("C.String", """
                {
                  // Code size       34 (0x22)
                  .maxstack  2
                  .locals init (bool V_0)
                  IL_0000:  ldarg.0
                  IL_0001:  ldstr      "z"
                  IL_0006:  call       "bool string.op_Equality(string, string)"
                  IL_000b:  brtrue.s   IL_001a
                  IL_000d:  ldarg.0
                  IL_000e:  ldstr      "a"
                  IL_0013:  call       "bool string.op_Equality(string, string)"
                  IL_0018:  brfalse.s  IL_001e
                  IL_001a:  ldc.i4.1
                  IL_001b:  stloc.0
                  IL_001c:  br.s       IL_0020
                  IL_001e:  ldc.i4.0
                  IL_001f:  stloc.0
                  IL_0020:  ldloc.0
                  IL_0021:  ret
                }
                """);
            verifier.VerifyIL("C.Span", """
                {
                  // Code size       44 (0x2c)
                  .maxstack  2
                  .locals init (bool V_0)
                  IL_0000:  ldarg.0
                  IL_0001:  ldstr      "a"
                  IL_0006:  call       "System.ReadOnlySpan<char> System.MemoryExtensions.AsSpan(string)"
                  IL_000b:  call       "bool System.MemoryExtensions.SequenceEqual<char>(System.Span<char>, System.ReadOnlySpan<char>)"
                  IL_0010:  brtrue.s   IL_0024
                  IL_0012:  ldarg.0
                  IL_0013:  ldstr      "z"
                  IL_0018:  call       "System.ReadOnlySpan<char> System.MemoryExtensions.AsSpan(string)"
                  IL_001d:  call       "bool System.MemoryExtensions.SequenceEqual<char>(System.Span<char>, System.ReadOnlySpan<char>)"
                  IL_0022:  brfalse.s  IL_0028
                  IL_0024:  ldc.i4.1
                  IL_0025:  stloc.0
                  IL_0026:  br.s       IL_002a
                  IL_0028:  ldc.i4.0
                  IL_0029:  stloc.0
                  IL_002a:  ldloc.0
                  IL_002b:  ret
                }
                """);
            verifier.VerifyIL("C.ReadOnlySpan", """
                {
                  // Code size       44 (0x2c)
                  .maxstack  2
                  .locals init (bool V_0)
                  IL_0000:  ldarg.0
                  IL_0001:  ldstr      "a"
                  IL_0006:  call       "System.ReadOnlySpan<char> System.MemoryExtensions.AsSpan(string)"
                  IL_000b:  call       "bool System.MemoryExtensions.SequenceEqual<char>(System.ReadOnlySpan<char>, System.ReadOnlySpan<char>)"
                  IL_0010:  brtrue.s   IL_0024
                  IL_0012:  ldarg.0
                  IL_0013:  ldstr      "z"
                  IL_0018:  call       "System.ReadOnlySpan<char> System.MemoryExtensions.AsSpan(string)"
                  IL_001d:  call       "bool System.MemoryExtensions.SequenceEqual<char>(System.ReadOnlySpan<char>, System.ReadOnlySpan<char>)"
                  IL_0022:  brfalse.s  IL_0028
                  IL_0024:  ldc.i4.1
                  IL_0025:  stloc.0
                  IL_0026:  br.s       IL_002a
                  IL_0028:  ldc.i4.0
                  IL_0029:  stloc.0
                  IL_002a:  ldloc.0
                  IL_002b:  ret
                }
                """);
            verifier.VerifyIL("C.LargeString", """
                {
                  // Code size       69 (0x45)
                  .maxstack  2
                  .locals init (bool V_0,
                                int V_1,
                                char V_2)
                  IL_0000:  ldarg.0
                  IL_0001:  brfalse.s  IL_0041
                  IL_0003:  ldarg.0
                  IL_0004:  call       "int string.Length.get"
                  IL_0009:  stloc.1
                  IL_000a:  ldloc.1
                  IL_000b:  ldc.i4.1
                  IL_000c:  bne.un.s   IL_0041
                  IL_000e:  ldarg.0
                  IL_000f:  ldc.i4.0
                  IL_0010:  call       "char string.this[int].get"
                  IL_0015:  stloc.2
                  IL_0016:  ldloc.2
                  IL_0017:  ldc.i4.s   97
                  IL_0019:  sub
                  IL_001a:  switch    (
                        IL_003d,
                        IL_003d,
                        IL_003d,
                        IL_003d,
                        IL_003d,
                        IL_003d,
                        IL_003d)
                  IL_003b:  br.s       IL_0041
                  IL_003d:  ldc.i4.1
                  IL_003e:  stloc.0
                  IL_003f:  br.s       IL_0043
                  IL_0041:  ldc.i4.0
                  IL_0042:  stloc.0
                  IL_0043:  ldloc.0
                  IL_0044:  ret
                }
                """);
            verifier.VerifyIL("C.LargeSpan", """
                {
                  // Code size       69 (0x45)
                  .maxstack  2
                  .locals init (bool V_0,
                                int V_1,
                                char V_2)
                  IL_0000:  ldarga.s   V_0
                  IL_0002:  call       "int System.Span<char>.Length.get"
                  IL_0007:  stloc.1
                  IL_0008:  ldloc.1
                  IL_0009:  ldc.i4.1
                  IL_000a:  bne.un.s   IL_0041
                  IL_000c:  ldarga.s   V_0
                  IL_000e:  ldc.i4.0
                  IL_000f:  call       "ref char System.Span<char>.this[int].get"
                  IL_0014:  ldind.u2
                  IL_0015:  stloc.2
                  IL_0016:  ldloc.2
                  IL_0017:  ldc.i4.s   97
                  IL_0019:  sub
                  IL_001a:  switch    (
                        IL_003d,
                        IL_003d,
                        IL_003d,
                        IL_003d,
                        IL_003d,
                        IL_003d,
                        IL_003d)
                  IL_003b:  br.s       IL_0041
                  IL_003d:  ldc.i4.1
                  IL_003e:  stloc.0
                  IL_003f:  br.s       IL_0043
                  IL_0041:  ldc.i4.0
                  IL_0042:  stloc.0
                  IL_0043:  ldloc.0
                  IL_0044:  ret
                }
                """);
            verifier.VerifyIL("C.LargeReadOnlySpan", """
                {
                  // Code size       69 (0x45)
                  .maxstack  2
                  .locals init (bool V_0,
                                int V_1,
                                char V_2)
                  IL_0000:  ldarga.s   V_0
                  IL_0002:  call       "int System.ReadOnlySpan<char>.Length.get"
                  IL_0007:  stloc.1
                  IL_0008:  ldloc.1
                  IL_0009:  ldc.i4.1
                  IL_000a:  bne.un.s   IL_0041
                  IL_000c:  ldarga.s   V_0
                  IL_000e:  ldc.i4.0
                  IL_000f:  call       "ref readonly char System.ReadOnlySpan<char>.this[int].get"
                  IL_0014:  ldind.u2
                  IL_0015:  stloc.2
                  IL_0016:  ldloc.2
                  IL_0017:  ldc.i4.s   97
                  IL_0019:  sub
                  IL_001a:  switch    (
                        IL_003d,
                        IL_003d,
                        IL_003d,
                        IL_003d,
                        IL_003d,
                        IL_003d,
                        IL_003d)
                  IL_003b:  br.s       IL_0041
                  IL_003d:  ldc.i4.1
                  IL_003e:  stloc.0
                  IL_003f:  br.s       IL_0043
                  IL_0041:  ldc.i4.0
                  IL_0042:  stloc.0
                  IL_0043:  ldloc.0
                  IL_0044:  ret
                }
                """);

            comp = CreateCompilationWithSpanAndMemoryExtensions(
                source,
                options: TestOptions.ReleaseDll,
                parseOptions: TestOptions.RegularPreview.WithDisableLengthBasedSwitch());
            verifier = CompileAndVerify(comp);

            verifier.VerifyIL("C.LargeString", """
                {
                  // Code size      199 (0xc7)
                  .maxstack  2
                  .locals init (bool V_0,
                                uint V_1)
                  IL_0000:  ldarg.0
                  IL_0001:  call       "uint <PrivateImplementationDetails>.ComputeStringHash(string)"
                  IL_0006:  stloc.1
                  IL_0007:  ldloc.1
                  IL_0008:  ldc.i4     0xe20c2606
                  IL_000d:  bgt.un.s   IL_002c
                  IL_000f:  ldloc.1
                  IL_0010:  ldc.i4     0xe00c22e0
                  IL_0015:  beq.s      IL_0076
                  IL_0017:  ldloc.1
                  IL_0018:  ldc.i4     0xe10c2473
                  IL_001d:  beq.s      IL_0085
                  IL_001f:  ldloc.1
                  IL_0020:  ldc.i4     0xe20c2606
                  IL_0025:  beq.s      IL_0058
                  IL_0027:  br         IL_00c3
                  IL_002c:  ldloc.1
                  IL_002d:  ldc.i4     0xe40c292c
                  IL_0032:  bgt.un.s   IL_0046
                  IL_0034:  ldloc.1
                  IL_0035:  ldc.i4     0xe30c2799
                  IL_003a:  beq.s      IL_0067
                  IL_003c:  ldloc.1
                  IL_003d:  ldc.i4     0xe40c292c
                  IL_0042:  beq.s      IL_00b2
                  IL_0044:  br.s       IL_00c3
                  IL_0046:  ldloc.1
                  IL_0047:  ldc.i4     0xe60c2c52
                  IL_004c:  beq.s      IL_0094
                  IL_004e:  ldloc.1
                  IL_004f:  ldc.i4     0xe70c2de5
                  IL_0054:  beq.s      IL_00a3
                  IL_0056:  br.s       IL_00c3
                  IL_0058:  ldarg.0
                  IL_0059:  ldstr      "g"
                  IL_005e:  call       "bool string.op_Equality(string, string)"
                  IL_0063:  brtrue.s   IL_00bf
                  IL_0065:  br.s       IL_00c3
                  IL_0067:  ldarg.0
                  IL_0068:  ldstr      "f"
                  IL_006d:  call       "bool string.op_Equality(string, string)"
                  IL_0072:  brtrue.s   IL_00bf
                  IL_0074:  br.s       IL_00c3
                  IL_0076:  ldarg.0
                  IL_0077:  ldstr      "e"
                  IL_007c:  call       "bool string.op_Equality(string, string)"
                  IL_0081:  brtrue.s   IL_00bf
                  IL_0083:  br.s       IL_00c3
                  IL_0085:  ldarg.0
                  IL_0086:  ldstr      "d"
                  IL_008b:  call       "bool string.op_Equality(string, string)"
                  IL_0090:  brtrue.s   IL_00bf
                  IL_0092:  br.s       IL_00c3
                  IL_0094:  ldarg.0
                  IL_0095:  ldstr      "c"
                  IL_009a:  call       "bool string.op_Equality(string, string)"
                  IL_009f:  brtrue.s   IL_00bf
                  IL_00a1:  br.s       IL_00c3
                  IL_00a3:  ldarg.0
                  IL_00a4:  ldstr      "b"
                  IL_00a9:  call       "bool string.op_Equality(string, string)"
                  IL_00ae:  brtrue.s   IL_00bf
                  IL_00b0:  br.s       IL_00c3
                  IL_00b2:  ldarg.0
                  IL_00b3:  ldstr      "a"
                  IL_00b8:  call       "bool string.op_Equality(string, string)"
                  IL_00bd:  brfalse.s  IL_00c3
                  IL_00bf:  ldc.i4.1
                  IL_00c0:  stloc.0
                  IL_00c1:  br.s       IL_00c5
                  IL_00c3:  ldc.i4.0
                  IL_00c4:  stloc.0
                  IL_00c5:  ldloc.0
                  IL_00c6:  ret
                }
                """);
            verifier.VerifyIL("C.LargeSpan", """
                {
                  // Code size      252 (0xfc)
                  .maxstack  2
                  .locals init (bool V_0,
                                uint V_1)
                  IL_0000:  ldarg.0
                  IL_0001:  call       "uint <PrivateImplementationDetails>.ComputeSpanHash(System.Span<char>)"
                  IL_0006:  stloc.1
                  IL_0007:  ldloc.1
                  IL_0008:  ldc.i4     0xe20c2606
                  IL_000d:  bgt.un.s   IL_0035
                  IL_000f:  ldloc.1
                  IL_0010:  ldc.i4     0xe00c22e0
                  IL_0015:  beq        IL_00ba
                  IL_001a:  ldloc.1
                  IL_001b:  ldc.i4     0xe10c2473
                  IL_0020:  beq        IL_00a6
                  IL_0025:  ldloc.1
                  IL_0026:  ldc.i4     0xe20c2606
                  IL_002b:  beq        IL_00e2
                  IL_0030:  br         IL_00f8
                  IL_0035:  ldloc.1
                  IL_0036:  ldc.i4     0xe40c292c
                  IL_003b:  bgt.un.s   IL_0055
                  IL_003d:  ldloc.1
                  IL_003e:  ldc.i4     0xe30c2799
                  IL_0043:  beq        IL_00ce
                  IL_0048:  ldloc.1
                  IL_0049:  ldc.i4     0xe40c292c
                  IL_004e:  beq.s      IL_006a
                  IL_0050:  br         IL_00f8
                  IL_0055:  ldloc.1
                  IL_0056:  ldc.i4     0xe60c2c52
                  IL_005b:  beq.s      IL_0092
                  IL_005d:  ldloc.1
                  IL_005e:  ldc.i4     0xe70c2de5
                  IL_0063:  beq.s      IL_007e
                  IL_0065:  br         IL_00f8
                  IL_006a:  ldarg.0
                  IL_006b:  ldstr      "a"
                  IL_0070:  call       "System.ReadOnlySpan<char> System.MemoryExtensions.AsSpan(string)"
                  IL_0075:  call       "bool System.MemoryExtensions.SequenceEqual<char>(System.Span<char>, System.ReadOnlySpan<char>)"
                  IL_007a:  brtrue.s   IL_00f4
                  IL_007c:  br.s       IL_00f8
                  IL_007e:  ldarg.0
                  IL_007f:  ldstr      "b"
                  IL_0084:  call       "System.ReadOnlySpan<char> System.MemoryExtensions.AsSpan(string)"
                  IL_0089:  call       "bool System.MemoryExtensions.SequenceEqual<char>(System.Span<char>, System.ReadOnlySpan<char>)"
                  IL_008e:  brtrue.s   IL_00f4
                  IL_0090:  br.s       IL_00f8
                  IL_0092:  ldarg.0
                  IL_0093:  ldstr      "c"
                  IL_0098:  call       "System.ReadOnlySpan<char> System.MemoryExtensions.AsSpan(string)"
                  IL_009d:  call       "bool System.MemoryExtensions.SequenceEqual<char>(System.Span<char>, System.ReadOnlySpan<char>)"
                  IL_00a2:  brtrue.s   IL_00f4
                  IL_00a4:  br.s       IL_00f8
                  IL_00a6:  ldarg.0
                  IL_00a7:  ldstr      "d"
                  IL_00ac:  call       "System.ReadOnlySpan<char> System.MemoryExtensions.AsSpan(string)"
                  IL_00b1:  call       "bool System.MemoryExtensions.SequenceEqual<char>(System.Span<char>, System.ReadOnlySpan<char>)"
                  IL_00b6:  brtrue.s   IL_00f4
                  IL_00b8:  br.s       IL_00f8
                  IL_00ba:  ldarg.0
                  IL_00bb:  ldstr      "e"
                  IL_00c0:  call       "System.ReadOnlySpan<char> System.MemoryExtensions.AsSpan(string)"
                  IL_00c5:  call       "bool System.MemoryExtensions.SequenceEqual<char>(System.Span<char>, System.ReadOnlySpan<char>)"
                  IL_00ca:  brtrue.s   IL_00f4
                  IL_00cc:  br.s       IL_00f8
                  IL_00ce:  ldarg.0
                  IL_00cf:  ldstr      "f"
                  IL_00d4:  call       "System.ReadOnlySpan<char> System.MemoryExtensions.AsSpan(string)"
                  IL_00d9:  call       "bool System.MemoryExtensions.SequenceEqual<char>(System.Span<char>, System.ReadOnlySpan<char>)"
                  IL_00de:  brtrue.s   IL_00f4
                  IL_00e0:  br.s       IL_00f8
                  IL_00e2:  ldarg.0
                  IL_00e3:  ldstr      "g"
                  IL_00e8:  call       "System.ReadOnlySpan<char> System.MemoryExtensions.AsSpan(string)"
                  IL_00ed:  call       "bool System.MemoryExtensions.SequenceEqual<char>(System.Span<char>, System.ReadOnlySpan<char>)"
                  IL_00f2:  brfalse.s  IL_00f8
                  IL_00f4:  ldc.i4.1
                  IL_00f5:  stloc.0
                  IL_00f6:  br.s       IL_00fa
                  IL_00f8:  ldc.i4.0
                  IL_00f9:  stloc.0
                  IL_00fa:  ldloc.0
                  IL_00fb:  ret
                }
                """);
            verifier.VerifyIL("C.LargeReadOnlySpan", """
                {
                  // Code size      134 (0x86)
                  .maxstack  2
                  .locals init (bool V_0)
                  IL_0000:  ldarg.0
                  IL_0001:  ldstr      "a"
                  IL_0006:  call       "System.ReadOnlySpan<char> System.MemoryExtensions.AsSpan(string)"
                  IL_000b:  call       "bool System.MemoryExtensions.SequenceEqual<char>(System.ReadOnlySpan<char>, System.ReadOnlySpan<char>)"
                  IL_0010:  brtrue.s   IL_007e
                  IL_0012:  ldarg.0
                  IL_0013:  ldstr      "b"
                  IL_0018:  call       "System.ReadOnlySpan<char> System.MemoryExtensions.AsSpan(string)"
                  IL_001d:  call       "bool System.MemoryExtensions.SequenceEqual<char>(System.ReadOnlySpan<char>, System.ReadOnlySpan<char>)"
                  IL_0022:  brtrue.s   IL_007e
                  IL_0024:  ldarg.0
                  IL_0025:  ldstr      "c"
                  IL_002a:  call       "System.ReadOnlySpan<char> System.MemoryExtensions.AsSpan(string)"
                  IL_002f:  call       "bool System.MemoryExtensions.SequenceEqual<char>(System.ReadOnlySpan<char>, System.ReadOnlySpan<char>)"
                  IL_0034:  brtrue.s   IL_007e
                  IL_0036:  ldarg.0
                  IL_0037:  ldstr      "d"
                  IL_003c:  call       "System.ReadOnlySpan<char> System.MemoryExtensions.AsSpan(string)"
                  IL_0041:  call       "bool System.MemoryExtensions.SequenceEqual<char>(System.ReadOnlySpan<char>, System.ReadOnlySpan<char>)"
                  IL_0046:  brtrue.s   IL_007e
                  IL_0048:  ldarg.0
                  IL_0049:  ldstr      "e"
                  IL_004e:  call       "System.ReadOnlySpan<char> System.MemoryExtensions.AsSpan(string)"
                  IL_0053:  call       "bool System.MemoryExtensions.SequenceEqual<char>(System.ReadOnlySpan<char>, System.ReadOnlySpan<char>)"
                  IL_0058:  brtrue.s   IL_007e
                  IL_005a:  ldarg.0
                  IL_005b:  ldstr      "f"
                  IL_0060:  call       "System.ReadOnlySpan<char> System.MemoryExtensions.AsSpan(string)"
                  IL_0065:  call       "bool System.MemoryExtensions.SequenceEqual<char>(System.ReadOnlySpan<char>, System.ReadOnlySpan<char>)"
                  IL_006a:  brtrue.s   IL_007e
                  IL_006c:  ldarg.0
                  IL_006d:  ldstr      "g"
                  IL_0072:  call       "System.ReadOnlySpan<char> System.MemoryExtensions.AsSpan(string)"
                  IL_0077:  call       "bool System.MemoryExtensions.SequenceEqual<char>(System.ReadOnlySpan<char>, System.ReadOnlySpan<char>)"
                  IL_007c:  brfalse.s  IL_0082
                  IL_007e:  ldc.i4.1
                  IL_007f:  stloc.0
                  IL_0080:  br.s       IL_0084
                  IL_0082:  ldc.i4.0
                  IL_0083:  stloc.0
                  IL_0084:  ldloc.0
                  IL_0085:  ret
                }
                """);
        }

        [Fact]
        public void ValueSet_UnionNonNullTest_ExplicitType()
        {
            // Exercises ValueSet.Filter with BoundDagNonNullTest from unions.
            // The `int and (1 or 3 or 5)` pattern forces an explicit type test which
            // generates a non-null test on the union Value temp, before the ValueSet
            // on the extracted int temp.
            var source = """
                union S1(int, string)
                {
                    static void Main()
                    {
                        System.Console.Write(Test(new S1(1)));
                        System.Console.Write(Test(new S1(3)));
                        System.Console.Write(Test(new S1(5)));
                        System.Console.Write(Test(new S1(7)));
                        System.Console.Write(Test(new S1("hello")));
                    }

                    static int Test(S1 u)
                    {
                        return u switch { string => 0, int and (1 or 3 or 5) => 1, _ => 2 };
                    }
                }
                """;
            var comp = CreateCompilation([source, UnionAttributeSource, IUnionSource], options: TestOptions.ReleaseExe);
            comp.VerifyDiagnostics();
            VerifyDecisionDagDump<SwitchExpressionSyntax>(comp,
@"[0]: t1 = t0.Value; [1]
[1]: t1 != null ? [2] : [9]
[2]: t1 is string ? [3] : [4]
[3]: leaf <arm> `string => 0`
[4]: t2 = (int)t1; [5]
[5]: t2 == 1 ? [8] : [6]
[6]: t2 == 3 ? [8] : [7]
[7]: t2 == 5 ? [8] : [9]
[8]: leaf <arm> `int and (1 or 3 or 5) => 1`
[9]: leaf <arm> `_ => 2`
",
forLowering: false);
            CompileAndVerify(comp, expectedOutput: "11120");
        }

        [Fact]
        public void ValueSet_UnionNonNullTest_LargeOrPattern()
        {
            // Exercises ValueSet with a larger set of or'd values on a union.
            // Ensures the ValueSet coalescing works correctly with union non-null tests.
            var source = """
                union S1(int, string)
                {
                    static void Main()
                    {
                        System.Console.Write(Test(new S1(1)));
                        System.Console.Write(Test(new S1(5)));
                        System.Console.Write(Test(new S1(10)));
                        System.Console.Write(Test(new S1(99)));
                        System.Console.Write(Test(new S1("x")));
                    }

                    static int Test(S1 u)
                    {
                        return u switch
                        {
                            string => 0,
                            int and (1 or 2 or 3 or 4 or 5 or 6 or 7 or 8 or 9 or 10) => 1,
                            _ => 2,
                        };
                    }
                }
                """;
            var comp = CreateCompilation([source, UnionAttributeSource, IUnionSource], options: TestOptions.ReleaseExe);
            comp.VerifyDiagnostics();
            CompileAndVerify(comp, expectedOutput: "11120");
        }

        [Fact]
        public void ValueSet_UnionNonNullTest_NullableUnion()
        {
            // Exercises ValueSet with a nullable union type.
            // The nullable adds an extra layer of null testing.
            var source = """
                union S1(int, string)
                {
                    static void Main()
                    {
                        System.Console.Write(Test(new S1(1)));
                        System.Console.Write(Test(new S1(3)));
                        System.Console.Write(Test(new S1(7)));
                        System.Console.Write(Test(new S1("x")));
                        System.Console.Write(Test(null));
                    }

                    static int Test(S1? u)
                    {
                        return u switch
                        {
                            null => 9,
                            int and (1 or 3 or 5) => 1,
                            string => 0,
                            _ => 2,
                        };
                    }
                }
                """;
            var comp = CreateCompilation([source, UnionAttributeSource, IUnionSource], options: TestOptions.ReleaseExe);
            comp.VerifyDiagnostics();
            VerifyDecisionDagDump<SwitchExpressionSyntax>(comp,
@"[0]: t0 == null ? [4] : [1]
[1]: t1 = (S1)t0; [2]
[2]: t2 = t1.Value; [3]
[3]: t2 == null ? [4] : [5]
[4]: leaf <arm> `null => 9`
[5]: t2 is int ? [6] : [12]
[6]: t3 = (int)t2; [7]
[7]: t3 == 1 ? [10] : [8]
[8]: t3 == 3 ? [10] : [9]
[9]: t3 == 5 ? [10] : [11]
[10]: leaf <arm> `int and (1 or 3 or 5) => 1`
[11]: leaf <arm> `_ => 2`
[12]: leaf <arm> `string => 0`
",
forLowering: false);
            CompileAndVerify(comp, expectedOutput: "11209");
        }

        [Fact]
        public void ValueSet_UnionNonNullTest_WithNullArm()
        {
            // Exercises an explicit null arm together with a union value arm that can
            // form a ValueSet behind an explicit type pattern.
            var source = """
                union S1(int, string)
                {
                    static void Main()
                    {
                        System.Console.Write(Test(new S1(1)));
                        System.Console.Write(Test(new S1(5)));
                        System.Console.Write(Test(new S1(7)));
                        System.Console.Write(Test(new S1("x")));
                    }

                    static int Test(S1 u)
                    {
                        return u switch
                        {
                            null => 9,
                            int and (1 or 3 or 5) => 1,
                            string => 0,
                            _ => 2,
                        };
                    }
                }
                """;
            var comp = CreateCompilation([source, UnionAttributeSource, IUnionSource], options: TestOptions.ReleaseExe);
            comp.VerifyDiagnostics();
            VerifyDecisionDagDump<SwitchExpressionSyntax>(comp,
@"[0]: t1 = t0.Value; [1]
[1]: t1 == null ? [2] : [3]
[2]: leaf <arm> `null => 9`
[3]: t1 is int ? [4] : [10]
[4]: t2 = (int)t1; [5]
[5]: t2 == 1 ? [8] : [6]
[6]: t2 == 3 ? [8] : [7]
[7]: t2 == 5 ? [8] : [9]
[8]: leaf <arm> `int and (1 or 3 or 5) => 1`
[9]: leaf <arm> `_ => 2`
[10]: leaf <arm> `string => 0`
",
forLowering: false);
            CompileAndVerify(comp, expectedOutput: "1120");
        }

        [Fact]
        public void ValueSet_UnionNonNullTest_NotPattern()
        {
            // Exercises ValueSet with negated or-patterns on unions.
            // `not (1 or 3 or 5)` creates a complement ValueSet.
            var source = """
                union S1(int, string)
                {
                    static void Main()
                    {
                        System.Console.Write(Test(new S1(1)));
                        System.Console.Write(Test(new S1(7)));
                        System.Console.Write(Test(new S1("x")));
                    }

                    static int Test(S1 u)
                    {
                        return u switch
                        {
                            string => 0,
                            int and not (1 or 3 or 5) => 2,
                            _ => 1,
                        };
                    }
                }
                """;
            var comp = CreateCompilation([source, UnionAttributeSource, IUnionSource], options: TestOptions.ReleaseExe);
            comp.VerifyDiagnostics();
            VerifyDecisionDagDump<SwitchExpressionSyntax>(comp,
@"[0]: t1 = t0.Value; [1]
[1]: t1 != null ? [2] : [8]
[2]: t1 is string ? [3] : [4]
[3]: leaf <arm> `string => 0`
[4]: t2 = (int)t1; [5]
[5]: t2 == 1 ? [8] : [6]
[6]: t2 == 3 ? [8] : [7]
[7]: t2 == 5 ? [8] : [9]
[8]: leaf <arm> `_ => 1`
[9]: leaf <arm> `int and not (1 or 3 or 5) => 2`
",
forLowering: false);
            CompileAndVerify(comp, expectedOutput: "120");
        }

        [Fact]
        public void ValueSet_UnionNonNullTest_MultipleArmsWithValues()
        {
            // Multiple arms with different value sets on the same union type.
            var source = """
                union S1(int, string)
                {
                    static void Main()
                    {
                        System.Console.Write(Test(new S1(1)));
                        System.Console.Write(Test(new S1(4)));
                        System.Console.Write(Test(new S1(7)));
                        System.Console.Write(Test(new S1("x")));
                    }

                    static int Test(S1 u)
                    {
                        return u switch
                        {
                            string => 0,
                            int and (1 or 2 or 3) => 1,
                            int and (4 or 5 or 6) => 2,
                            _ => 3,
                        };
                    }
                }
                """;
            var comp = CreateCompilation([source, UnionAttributeSource, IUnionSource], options: TestOptions.ReleaseExe);
            comp.VerifyDiagnostics();
            VerifyDecisionDagDump<SwitchExpressionSyntax>(comp,
@"[0]: t1 = t0.Value; [1]
[1]: t1 != null ? [2] : [13]
[2]: t1 is string ? [3] : [4]
[3]: leaf <arm> `string => 0`
[4]: t2 = (int)t1; [5]
[5]: t2 == 1 ? [8] : [6]
[6]: t2 == 2 ? [8] : [7]
[7]: t2 == 3 ? [8] : [9]
[8]: leaf <arm> `int and (1 or 2 or 3) => 1`
[9]: t2 == 4 ? [12] : [10]
[10]: t2 == 5 ? [12] : [11]
[11]: t2 == 6 ? [12] : [13]
[12]: leaf <arm> `int and (4 or 5 or 6) => 2`
[13]: leaf <arm> `_ => 3`
",
forLowering: false);
            CompileAndVerify(comp, expectedOutput: "1230");
        }

    }
}
