File: CodeGen\CodeGenConditionalOperatorTests.cs
Web Access
Project: src\src\Compilers\CSharp\Test\Emit\Microsoft.CodeAnalysis.CSharp.Emit.UnitTests.csproj (Microsoft.CodeAnalysis.CSharp.Emit.UnitTests)
// 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 Microsoft.CodeAnalysis.CSharp.Test.Utilities;
using Microsoft.CodeAnalysis.Test.Utilities;
using Roslyn.Test.Utilities;
using Xunit;
 
namespace Microsoft.CodeAnalysis.CSharp.UnitTests.CodeGen
{
    public class CodeGenConditionalOperatorTests : CSharpTestBase
    {
        [Fact, WorkItem(61483, "https://github.com/dotnet/roslyn/issues/61483")]
        public void Branchless_Compare()
        {
            var source = """
                using static System.Console;
                WriteLine(C.Compare(1, 2));
                WriteLine(C.Compare(3, 3));
                WriteLine(C.Compare(5, 4));
 
                class C
                {
                    public static int Compare(int x, int y)
                    {
                        int tmp1 = (x > y) ? 1 : 0;
                        int tmp2 = (x < y) ? 1 : 0;
                        return tmp1 - tmp2;
                    }
                }
                """;
            var expectedOutput = """
                -1
                0
                1
                """;
 
            var verifier = CompileAndVerify(source, options: TestOptions.ReleaseExe, expectedOutput: expectedOutput);
            verifier.VerifyDiagnostics();
            verifier.VerifyMethodBody("C.Compare", """
                {
                  // Code size       12 (0xc)
                  .maxstack  3
                  .locals init (int V_0) //tmp2
                  // sequence point: int tmp1 = (x > y) ? 1 : 0;
                  IL_0000:  ldarg.0
                  IL_0001:  ldarg.1
                  IL_0002:  cgt
                  // sequence point: int tmp2 = (x < y) ? 1 : 0;
                  IL_0004:  ldarg.0
                  IL_0005:  ldarg.1
                  IL_0006:  clt
                  IL_0008:  stloc.0
                  // sequence point: return tmp1 - tmp2;
                  IL_0009:  ldloc.0
                  IL_000a:  sub
                  IL_000b:  ret
                }
                """);
 
            verifier = CompileAndVerify(source, options: TestOptions.ReleaseExe.WithDebugPlusMode(true), expectedOutput: expectedOutput);
            verifier.VerifyDiagnostics();
            verifier.VerifyMethodBody("C.Compare", """
                {
                  // Code size       14 (0xe)
                  .maxstack  2
                  .locals init (int V_0, //tmp1
                                int V_1) //tmp2
                  // sequence point: int tmp1 = (x > y) ? 1 : 0;
                  IL_0000:  ldarg.0
                  IL_0001:  ldarg.1
                  IL_0002:  cgt
                  IL_0004:  stloc.0
                  // sequence point: int tmp2 = (x < y) ? 1 : 0;
                  IL_0005:  ldarg.0
                  IL_0006:  ldarg.1
                  IL_0007:  clt
                  IL_0009:  stloc.1
                  // sequence point: return tmp1 - tmp2;
                  IL_000a:  ldloc.0
                  IL_000b:  ldloc.1
                  IL_000c:  sub
                  IL_000d:  ret
                }
                """);
 
            verifier = CompileAndVerify(source, options: TestOptions.DebugExe, expectedOutput: expectedOutput);
            verifier.VerifyDiagnostics();
            verifier.VerifyMethodBody("C.Compare", """
            {
                // Code size       27 (0x1b)
                .maxstack  2
                .locals init (int V_0, //tmp1
                            int V_1, //tmp2
                            int V_2)
                // sequence point: {
                IL_0000:  nop
                // sequence point: int tmp1 = (x > y) ? 1 : 0;
                IL_0001:  ldarg.0
                IL_0002:  ldarg.1
                IL_0003:  bgt.s      IL_0008
                IL_0005:  ldc.i4.0
                IL_0006:  br.s       IL_0009
                IL_0008:  ldc.i4.1
                IL_0009:  stloc.0
                // sequence point: int tmp2 = (x < y) ? 1 : 0;
                IL_000a:  ldarg.0
                IL_000b:  ldarg.1
                IL_000c:  blt.s      IL_0011
                IL_000e:  ldc.i4.0
                IL_000f:  br.s       IL_0012
                IL_0011:  ldc.i4.1
                IL_0012:  stloc.1
                // sequence point: return tmp1 - tmp2;
                IL_0013:  ldloc.0
                IL_0014:  ldloc.1
                IL_0015:  sub
                IL_0016:  stloc.2
                IL_0017:  br.s       IL_0019
                // sequence point: }
                IL_0019:  ldloc.2
                IL_001a:  ret
            }
            """);
        }
 
        [Fact, WorkItem(61483, "https://github.com/dotnet/roslyn/issues/61483")]
        public void Branchless_Operations()
        {
            var source = """
                using static System.Console;
 
                class C
                {
                    static void Main() => M(1, 0, null!, true);
                    static void M(int x, int y, object a, bool b)
                    {
                        Write(x == y ? 1 : 0);
                        Write(x == y ? 0 : 1);
                        Write(x < y ? 1 : 0);
                        Write(x < y ? 0 : 1);
                        Write(x > y ? 1 : 0);
                        Write(x > y ? 0 : 1);
                        Write(a is string ? 0 : 1);
                        Write(a is not string ? 0 : 1);
                        Write(b ? 0 : 1);
                        Write(!b ? 0 : 1);
                        Write(x <= y ? true : false);
                        Write(x <= y ? false : true);
                        Write(x != y ? (byte)1 : (byte)0);
                        Write(x != y ? 1 : (sbyte)0);
                        Write(x != y ? (short)1 : (short)0);
                        Write(x != y ? (ushort)1 : 0);
                        Write(x != y ? 1U : 0);
                        Write(x != y ? 1L : 0);
                        Write(x != y ? 1UL : 0);
                        Write(x != y ? (nint)1 : 0);
                        Write(x != y ? 1 : (nuint)0);
                        Write(x < y ? (char)0 : (char)1);
                        Write(x < y ? '\x1' : '\x0');
                        Write(true ? 1 : 0);
                        Write(false ? 0 : 1);
                        const bool B = true;
                        Write(B ? 1 : 0);
                    }
                }
                """;
            var verifier = CompileAndVerify(source,
                options: TestOptions.ReleaseExe,
                expectedOutput: "0101101001FalseTrue111111111" + (char)1 + (char)0 + "111");
            verifier.VerifyDiagnostics();
            verifier.VerifyMethodBody("C.M", """
                {
                  // Code size      288 (0x120)
                  .maxstack  2
                  // sequence point: Write(x == y ? 1 : 0);
                  IL_0000:  ldarg.0
                  IL_0001:  ldarg.1
                  IL_0002:  ceq
                  IL_0004:  call       "void System.Console.Write(int)"
                  // sequence point: Write(x == y ? 0 : 1);
                  IL_0009:  ldarg.0
                  IL_000a:  ldarg.1
                  IL_000b:  ceq
                  IL_000d:  ldc.i4.0
                  IL_000e:  ceq
                  IL_0010:  call       "void System.Console.Write(int)"
                  // sequence point: Write(x < y ? 1 : 0);
                  IL_0015:  ldarg.0
                  IL_0016:  ldarg.1
                  IL_0017:  clt
                  IL_0019:  call       "void System.Console.Write(int)"
                  // sequence point: Write(x < y ? 0 : 1);
                  IL_001e:  ldarg.0
                  IL_001f:  ldarg.1
                  IL_0020:  clt
                  IL_0022:  ldc.i4.0
                  IL_0023:  ceq
                  IL_0025:  call       "void System.Console.Write(int)"
                  // sequence point: Write(x > y ? 1 : 0);
                  IL_002a:  ldarg.0
                  IL_002b:  ldarg.1
                  IL_002c:  cgt
                  IL_002e:  call       "void System.Console.Write(int)"
                  // sequence point: Write(x > y ? 0 : 1);
                  IL_0033:  ldarg.0
                  IL_0034:  ldarg.1
                  IL_0035:  cgt
                  IL_0037:  ldc.i4.0
                  IL_0038:  ceq
                  IL_003a:  call       "void System.Console.Write(int)"
                  // sequence point: Write(a is string ? 0 : 1);
                  IL_003f:  ldarg.2
                  IL_0040:  isinst     "string"
                  IL_0045:  ldnull
                  IL_0046:  ceq
                  IL_0048:  call       "void System.Console.Write(int)"
                  // sequence point: Write(a is not string ? 0 : 1);
                  IL_004d:  ldarg.2
                  IL_004e:  isinst     "string"
                  IL_0053:  ldnull
                  IL_0054:  cgt.un
                  IL_0056:  call       "void System.Console.Write(int)"
                  // sequence point: Write(b ? 0 : 1);
                  IL_005b:  ldarg.3
                  IL_005c:  ldc.i4.0
                  IL_005d:  ceq
                  IL_005f:  call       "void System.Console.Write(int)"
                  // sequence point: Write(!b ? 0 : 1);
                  IL_0064:  ldarg.3
                  IL_0065:  ldc.i4.0
                  IL_0066:  cgt.un
                  IL_0068:  call       "void System.Console.Write(int)"
                  // sequence point: Write(x <= y ? true : false);
                  IL_006d:  ldarg.0
                  IL_006e:  ldarg.1
                  IL_006f:  cgt
                  IL_0071:  ldc.i4.0
                  IL_0072:  ceq
                  IL_0074:  call       "void System.Console.Write(bool)"
                  // sequence point: Write(x <= y ? false : true);
                  IL_0079:  ldarg.0
                  IL_007a:  ldarg.1
                  IL_007b:  cgt
                  IL_007d:  call       "void System.Console.Write(bool)"
                  // sequence point: Write(x != y ? (byte)1 : (byte)0);
                  IL_0082:  ldarg.0
                  IL_0083:  ldarg.1
                  IL_0084:  ceq
                  IL_0086:  ldc.i4.0
                  IL_0087:  ceq
                  IL_0089:  conv.u1
                  IL_008a:  call       "void System.Console.Write(int)"
                  // sequence point: Write(x != y ? 1 : (sbyte)0);
                  IL_008f:  ldarg.0
                  IL_0090:  ldarg.1
                  IL_0091:  ceq
                  IL_0093:  ldc.i4.0
                  IL_0094:  ceq
                  IL_0096:  call       "void System.Console.Write(int)"
                  // sequence point: Write(x != y ? (short)1 : (short)0);
                  IL_009b:  ldarg.0
                  IL_009c:  ldarg.1
                  IL_009d:  ceq
                  IL_009f:  ldc.i4.0
                  IL_00a0:  ceq
                  IL_00a2:  conv.i2
                  IL_00a3:  call       "void System.Console.Write(int)"
                  // sequence point: Write(x != y ? (ushort)1 : 0);
                  IL_00a8:  ldarg.0
                  IL_00a9:  ldarg.1
                  IL_00aa:  ceq
                  IL_00ac:  ldc.i4.0
                  IL_00ad:  ceq
                  IL_00af:  call       "void System.Console.Write(int)"
                  // sequence point: Write(x != y ? 1U : 0);
                  IL_00b4:  ldarg.0
                  IL_00b5:  ldarg.1
                  IL_00b6:  ceq
                  IL_00b8:  ldc.i4.0
                  IL_00b9:  ceq
                  IL_00bb:  call       "void System.Console.Write(uint)"
                  // sequence point: Write(x != y ? 1L : 0);
                  IL_00c0:  ldarg.0
                  IL_00c1:  ldarg.1
                  IL_00c2:  ceq
                  IL_00c4:  ldc.i4.0
                  IL_00c5:  ceq
                  IL_00c7:  conv.i8
                  IL_00c8:  call       "void System.Console.Write(long)"
                  // sequence point: Write(x != y ? 1UL : 0);
                  IL_00cd:  ldarg.0
                  IL_00ce:  ldarg.1
                  IL_00cf:  ceq
                  IL_00d1:  ldc.i4.0
                  IL_00d2:  ceq
                  IL_00d4:  conv.i8
                  IL_00d5:  call       "void System.Console.Write(ulong)"
                  // sequence point: Write(x != y ? (nint)1 : 0);
                  IL_00da:  ldarg.0
                  IL_00db:  ldarg.1
                  IL_00dc:  ceq
                  IL_00de:  ldc.i4.0
                  IL_00df:  ceq
                  IL_00e1:  conv.i
                  IL_00e2:  conv.i8
                  IL_00e3:  call       "void System.Console.Write(long)"
                  // sequence point: Write(x != y ? 1 : (nuint)0);
                  IL_00e8:  ldarg.0
                  IL_00e9:  ldarg.1
                  IL_00ea:  ceq
                  IL_00ec:  ldc.i4.0
                  IL_00ed:  ceq
                  IL_00ef:  conv.i
                  IL_00f0:  conv.u8
                  IL_00f1:  call       "void System.Console.Write(ulong)"
                  // sequence point: Write(x < y ? (char)0 : (char)1);
                  IL_00f6:  ldarg.0
                  IL_00f7:  ldarg.1
                  IL_00f8:  clt
                  IL_00fa:  ldc.i4.0
                  IL_00fb:  ceq
                  IL_00fd:  conv.u2
                  IL_00fe:  call       "void System.Console.Write(char)"
                  // sequence point: Write(x < y ? '\x1' : '\x0');
                  IL_0103:  ldarg.0
                  IL_0104:  ldarg.1
                  IL_0105:  clt
                  IL_0107:  conv.u2
                  IL_0108:  call       "void System.Console.Write(char)"
                  // sequence point: Write(true ? 1 : 0);
                  IL_010d:  ldc.i4.1
                  IL_010e:  call       "void System.Console.Write(int)"
                  // sequence point: Write(false ? 0 : 1);
                  IL_0113:  ldc.i4.1
                  IL_0114:  call       "void System.Console.Write(int)"
                  // sequence point: Write(B ? 1 : 0);
                  IL_0119:  ldc.i4.1
                  IL_011a:  call       "void System.Console.Write(int)"
                  // sequence point: }
                  IL_011f:  ret
                }
                """);
        }
 
        [Fact, WorkItem(61483, "https://github.com/dotnet/roslyn/issues/61483")]
        public void Branchless_Negations()
        {
            var source = """
                using static System.Console;
 
                class C
                {
                    static void Main() => M(1, 0, true);
                    static void M(int x, int y, bool b)
                    {
                        Write(!(x < y) ? 0 : 1);
                        Write(!!(x < y) ? 0 : 1);
                        Write(!!!(x < y) ? 0 : 1);
                        Write(!(x == y) ? 0 : 1);
                        Write(!b ? 0 : 1);
                        Write(!!b ? 0 : 1);
                        Write(!!!b ? 0 : 1);
                        Write(!false ? 0 : 1);
                        Write(!!false ? 0 : 1);
                        Write(!!!false ? 0 : 1);
                    }
                }
                """;
            var verifier = CompileAndVerify(source,
                options: TestOptions.ReleaseExe,
                expectedOutput: "0100101010");
            verifier.VerifyDiagnostics();
            verifier.VerifyMethodBody("C.M", """
                {
                  // Code size       85 (0x55)
                  .maxstack  2
                  // sequence point: Write(!(x < y) ? 0 : 1);
                  IL_0000:  ldarg.0
                  IL_0001:  ldarg.1
                  IL_0002:  clt
                  IL_0004:  call       "void System.Console.Write(int)"
                  // sequence point: Write(!!(x < y) ? 0 : 1);
                  IL_0009:  ldarg.0
                  IL_000a:  ldarg.1
                  IL_000b:  clt
                  IL_000d:  ldc.i4.0
                  IL_000e:  ceq
                  IL_0010:  call       "void System.Console.Write(int)"
                  // sequence point: Write(!!!(x < y) ? 0 : 1);
                  IL_0015:  ldarg.0
                  IL_0016:  ldarg.1
                  IL_0017:  clt
                  IL_0019:  call       "void System.Console.Write(int)"
                  // sequence point: Write(!(x == y) ? 0 : 1);
                  IL_001e:  ldarg.0
                  IL_001f:  ldarg.1
                  IL_0020:  ceq
                  IL_0022:  call       "void System.Console.Write(int)"
                  // sequence point: Write(!b ? 0 : 1);
                  IL_0027:  ldarg.2
                  IL_0028:  ldc.i4.0
                  IL_0029:  cgt.un
                  IL_002b:  call       "void System.Console.Write(int)"
                  // sequence point: Write(!!b ? 0 : 1);
                  IL_0030:  ldarg.2
                  IL_0031:  ldc.i4.0
                  IL_0032:  ceq
                  IL_0034:  call       "void System.Console.Write(int)"
                  // sequence point: Write(!!!b ? 0 : 1);
                  IL_0039:  ldarg.2
                  IL_003a:  ldc.i4.0
                  IL_003b:  cgt.un
                  IL_003d:  call       "void System.Console.Write(int)"
                  // sequence point: Write(!false ? 0 : 1);
                  IL_0042:  ldc.i4.0
                  IL_0043:  call       "void System.Console.Write(int)"
                  // sequence point: Write(!!false ? 0 : 1);
                  IL_0048:  ldc.i4.1
                  IL_0049:  call       "void System.Console.Write(int)"
                  // sequence point: Write(!!!false ? 0 : 1);
                  IL_004e:  ldc.i4.0
                  IL_004f:  call       "void System.Console.Write(int)"
                  // sequence point: }
                  IL_0054:  ret
                }
                """);
        }
 
        [Fact, WorkItem(61483, "https://github.com/dotnet/roslyn/issues/61483")]
        public void Branchless_NonBinaryArms()
        {
            var source = """
                using static System.Console;
 
                class C
                {
                    static void Main() => M(1, 0);
                    static void M(int x, int y)
                    {
                        Write(x == y ? 1 : 1);
                        Write(x != y ? 0 : 0);
                        Write(x <= y ? 0 : 2);
                        Write(x >= y ? 2 : 1);
                        Write(x < y ? 0 : -1);
                        Write(x < y ? 0d : 1d);
                        Write(x < y ? 0f : 1f);
                        Write(x < y ? 0m : 1m);
                        Write(x < y ? '\x0' : 'a');
                    }
                }
                """;
            var verifier = CompileAndVerify(source,
                options: TestOptions.ReleaseExe,
                expectedOutput: "1022-1111a");
            verifier.VerifyDiagnostics();
            verifier.VerifyMethodBody("C.M", """
                {
                  // Code size      151 (0x97)
                  .maxstack  2
                  // sequence point: Write(x == y ? 1 : 1);
                  IL_0000:  ldarg.0
                  IL_0001:  ldarg.1
                  IL_0002:  beq.s      IL_0007
                  IL_0004:  ldc.i4.1
                  IL_0005:  br.s       IL_0008
                  IL_0007:  ldc.i4.1
                  IL_0008:  call       "void System.Console.Write(int)"
                  // sequence point: Write(x != y ? 0 : 0);
                  IL_000d:  ldarg.0
                  IL_000e:  ldarg.1
                  IL_000f:  bne.un.s   IL_0014
                  IL_0011:  ldc.i4.0
                  IL_0012:  br.s       IL_0015
                  IL_0014:  ldc.i4.0
                  IL_0015:  call       "void System.Console.Write(int)"
                  // sequence point: Write(x <= y ? 0 : 2);
                  IL_001a:  ldarg.0
                  IL_001b:  ldarg.1
                  IL_001c:  ble.s      IL_0021
                  IL_001e:  ldc.i4.2
                  IL_001f:  br.s       IL_0022
                  IL_0021:  ldc.i4.0
                  IL_0022:  call       "void System.Console.Write(int)"
                  // sequence point: Write(x >= y ? 2 : 1);
                  IL_0027:  ldarg.0
                  IL_0028:  ldarg.1
                  IL_0029:  bge.s      IL_002e
                  IL_002b:  ldc.i4.1
                  IL_002c:  br.s       IL_002f
                  IL_002e:  ldc.i4.2
                  IL_002f:  call       "void System.Console.Write(int)"
                  // sequence point: Write(x < y ? 0 : -1);
                  IL_0034:  ldarg.0
                  IL_0035:  ldarg.1
                  IL_0036:  blt.s      IL_003b
                  IL_0038:  ldc.i4.m1
                  IL_0039:  br.s       IL_003c
                  IL_003b:  ldc.i4.0
                  IL_003c:  call       "void System.Console.Write(int)"
                  // sequence point: Write(x < y ? 0d : 1d);
                  IL_0041:  ldarg.0
                  IL_0042:  ldarg.1
                  IL_0043:  blt.s      IL_0050
                  IL_0045:  ldc.r8     1
                  IL_004e:  br.s       IL_0059
                  IL_0050:  ldc.r8     0
                  IL_0059:  call       "void System.Console.Write(double)"
                  // sequence point: Write(x < y ? 0f : 1f);
                  IL_005e:  ldarg.0
                  IL_005f:  ldarg.1
                  IL_0060:  blt.s      IL_0069
                  IL_0062:  ldc.r4     1
                  IL_0067:  br.s       IL_006e
                  IL_0069:  ldc.r4     0
                  IL_006e:  call       "void System.Console.Write(float)"
                  // sequence point: Write(x < y ? 0m : 1m);
                  IL_0073:  ldarg.0
                  IL_0074:  ldarg.1
                  IL_0075:  blt.s      IL_007e
                  IL_0077:  ldsfld     "decimal decimal.One"
                  IL_007c:  br.s       IL_0083
                  IL_007e:  ldsfld     "decimal decimal.Zero"
                  IL_0083:  call       "void System.Console.Write(decimal)"
                  // sequence point: Write(x < y ? '\x0' : 'a');
                  IL_0088:  ldarg.0
                  IL_0089:  ldarg.1
                  IL_008a:  blt.s      IL_0090
                  IL_008c:  ldc.i4.s   97
                  IL_008e:  br.s       IL_0091
                  IL_0090:  ldc.i4.0
                  IL_0091:  call       "void System.Console.Write(char)"
                  // sequence point: }
                  IL_0096:  ret
                }
                """);
        }
 
        [Fact, WorkItem(61483, "https://github.com/dotnet/roslyn/issues/61483")]
        public void Branchless_NonBinaryCondition()
        {
            // public static class C { public static bool M() => -1; }
            var source1 = """
                .class public auto ansi abstract sealed beforefieldinit C
                    extends System.Object
                {
                    .method public hidebysig static bool M () cil managed
                    {
                        .maxstack 8
                        ldc.i4.m1
                        ret
                    }
                }
                """;
            var source2 = """
                System.Console.WriteLine(D.M1());
                System.Console.WriteLine(D.M2());
 
                class D
                {
                    public static int M1() => C.M() ? 1 : 0;
                    public static int M2() => C.M() ? 0 : 1;
                }
                """;
            var comp = CreateCompilationWithIL(source2, source1, options: TestOptions.ReleaseExe);
            var verifier = CompileAndVerify(comp, expectedOutput: """
                1
                0
                """);
            verifier.VerifyDiagnostics();
            verifier.VerifyMethodBody("D.M1", """
                {
                  // Code size        9 (0x9)
                  .maxstack  2
                  // sequence point: C.M() ? 1 : 0
                  IL_0000:  call       "bool C.M()"
                  IL_0005:  ldc.i4.0
                  IL_0006:  cgt.un
                  IL_0008:  ret
                }
                """);
            verifier.VerifyMethodBody("D.M2", """
                {
                  // Code size        9 (0x9)
                  .maxstack  2
                  // sequence point: C.M() ? 0 : 1
                  IL_0000:  call       "bool C.M()"
                  IL_0005:  ldc.i4.0
                  IL_0006:  ceq
                  IL_0008:  ret
                }
                """);
        }
 
        [Fact, WorkItem(638289, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/638289")]
        public void ConditionalDelegateInterfaceUnification1()
        {
            var src =
@"using System;
using System.Security;
 
[assembly: SecurityTransparent()]
 
interface I {}
 
class A : I {}
 
class C : I
{
    static Func<I> Tester(bool a)
    {
        return a 
            ? (Func<I>)(() => new A())
            : () => new C();
    }
    static void Main()
    {
        System.Console.Write(Tester(false)().GetType());
    }
}";
            var verify = CompileAndVerify(src,
                options: TestOptions.DebugExe,
                expectedOutput: "C");
            verify.VerifyIL("C.Tester", @"
{
  // Code size       73 (0x49)
  .maxstack  2
  .locals init (System.Func<I> V_0)
  IL_0000:  nop
  IL_0001:  ldarg.0
  IL_0002:  brtrue.s   IL_0025
  IL_0004:  ldsfld     ""System.Func<I> C.<>c.<>9__0_1""
  IL_0009:  dup
  IL_000a:  brtrue.s   IL_0023
  IL_000c:  pop
  IL_000d:  ldsfld     ""C.<>c C.<>c.<>9""
  IL_0012:  ldftn      ""I C.<>c.<Tester>b__0_1()""
  IL_0018:  newobj     ""System.Func<I>..ctor(object, System.IntPtr)""
  IL_001d:  dup
  IL_001e:  stsfld     ""System.Func<I> C.<>c.<>9__0_1""
  IL_0023:  br.s       IL_0044
  IL_0025:  ldsfld     ""System.Func<I> C.<>c.<>9__0_0""
  IL_002a:  dup
  IL_002b:  brtrue.s   IL_0044
  IL_002d:  pop
  IL_002e:  ldsfld     ""C.<>c C.<>c.<>9""
  IL_0033:  ldftn      ""I C.<>c.<Tester>b__0_0()""
  IL_0039:  newobj     ""System.Func<I>..ctor(object, System.IntPtr)""
  IL_003e:  dup
  IL_003f:  stsfld     ""System.Func<I> C.<>c.<>9__0_0""
  IL_0044:  stloc.0
  IL_0045:  br.s       IL_0047
  IL_0047:  ldloc.0
  IL_0048:  ret
}
");
 
            verify = CompileAndVerify(src,
                expectedOutput: "C");
            verify.VerifyIL("C.Tester", @"
{
  // Code size       67 (0x43)
  .maxstack  2
  IL_0000:  ldarg.0
  IL_0001:  brtrue.s   IL_0023
  IL_0003:  ldsfld     ""System.Func<I> C.<>c.<>9__0_1""
  IL_0008:  dup
  IL_0009:  brtrue.s   IL_0042
  IL_000b:  pop
  IL_000c:  ldsfld     ""C.<>c C.<>c.<>9""
  IL_0011:  ldftn      ""I C.<>c.<Tester>b__0_1()""
  IL_0017:  newobj     ""System.Func<I>..ctor(object, System.IntPtr)""
  IL_001c:  dup
  IL_001d:  stsfld     ""System.Func<I> C.<>c.<>9__0_1""
  IL_0022:  ret
  IL_0023:  ldsfld     ""System.Func<I> C.<>c.<>9__0_0""
  IL_0028:  dup
  IL_0029:  brtrue.s   IL_0042
  IL_002b:  pop
  IL_002c:  ldsfld     ""C.<>c C.<>c.<>9""
  IL_0031:  ldftn      ""I C.<>c.<Tester>b__0_0()""
  IL_0037:  newobj     ""System.Func<I>..ctor(object, System.IntPtr)""
  IL_003c:  dup
  IL_003d:  stsfld     ""System.Func<I> C.<>c.<>9__0_0""
  IL_0042:  ret
}
");
        }
 
        [Fact, WorkItem(20266, "https://github.com/dotnet/roslyn/issues/20266")]
        public void ConditionalAccessInMethodGroupConversion()
        {
            var source = @"
class C
{
    void M(object o)
    {
        System.Func<int, string> filter = new C(o?.ToString()).Method;
        filter(0);
    }
    string Method(int x)
    {
        throw null;
    }
    C(string x)
    {
    }
}
";
            var comp = CreateCompilation(source);
            comp.VerifyDiagnostics();
            CompileAndVerify(comp);
        }
 
        [Fact, WorkItem(638289, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/638289")]
        public void ConditionalDelegateInterfaceUnification2()
        {
            var src =
@"using System;
using System.Security;
 
[assembly: SecurityTransparent()]
 
interface I {}
 
class A : I {}
 
class B : I {}
 
class C : I
{
    static Func<I> Tester(int a)
    {
        return a > 0 
              ? a == 1 
                ? (Func<I>)(() => new A())
                : () => new B()
              : (() => new C());
    }
    static void Main()
    {
        System.Console.Write(Tester(1)().GetType());
    }
}";
            var verify = CompileAndVerify(src,
                options: TestOptions.DebugExe,
                expectedOutput: "A");
            verify.VerifyIL("C.Tester", @"
{
  // Code size      111 (0x6f)
  .maxstack  2
  .locals init (System.Func<I> V_0)
  IL_0000:  nop
  IL_0001:  ldarg.0
  IL_0002:  ldc.i4.0
  IL_0003:  bgt.s      IL_0026
  IL_0005:  ldsfld     ""System.Func<I> C.<>c.<>9__0_2""
  IL_000a:  dup
  IL_000b:  brtrue.s   IL_0024
  IL_000d:  pop
  IL_000e:  ldsfld     ""C.<>c C.<>c.<>9""
  IL_0013:  ldftn      ""I C.<>c.<Tester>b__0_2()""
  IL_0019:  newobj     ""System.Func<I>..ctor(object, System.IntPtr)""
  IL_001e:  dup
  IL_001f:  stsfld     ""System.Func<I> C.<>c.<>9__0_2""
  IL_0024:  br.s       IL_006a
  IL_0026:  ldarg.0
  IL_0027:  ldc.i4.1
  IL_0028:  beq.s      IL_004b
  IL_002a:  ldsfld     ""System.Func<I> C.<>c.<>9__0_1""
  IL_002f:  dup
  IL_0030:  brtrue.s   IL_0049
  IL_0032:  pop
  IL_0033:  ldsfld     ""C.<>c C.<>c.<>9""
  IL_0038:  ldftn      ""I C.<>c.<Tester>b__0_1()""
  IL_003e:  newobj     ""System.Func<I>..ctor(object, System.IntPtr)""
  IL_0043:  dup
  IL_0044:  stsfld     ""System.Func<I> C.<>c.<>9__0_1""
  IL_0049:  br.s       IL_006a
  IL_004b:  ldsfld     ""System.Func<I> C.<>c.<>9__0_0""
  IL_0050:  dup
  IL_0051:  brtrue.s   IL_006a
  IL_0053:  pop
  IL_0054:  ldsfld     ""C.<>c C.<>c.<>9""
  IL_0059:  ldftn      ""I C.<>c.<Tester>b__0_0()""
  IL_005f:  newobj     ""System.Func<I>..ctor(object, System.IntPtr)""
  IL_0064:  dup
  IL_0065:  stsfld     ""System.Func<I> C.<>c.<>9__0_0""
  IL_006a:  stloc.0
  IL_006b:  br.s       IL_006d
  IL_006d:  ldloc.0
  IL_006e:  ret
}
");
            verify = CompileAndVerify(src,
                expectedOutput: "A");
            verify.VerifyIL("C.Tester", @"
{
  // Code size      104 (0x68)
  .maxstack  2
  IL_0000:  ldarg.0
  IL_0001:  ldc.i4.0
  IL_0002:  bgt.s      IL_0024
  IL_0004:  ldsfld     ""System.Func<I> C.<>c.<>9__0_2""
  IL_0009:  dup
  IL_000a:  brtrue.s   IL_0067
  IL_000c:  pop
  IL_000d:  ldsfld     ""C.<>c C.<>c.<>9""
  IL_0012:  ldftn      ""I C.<>c.<Tester>b__0_2()""
  IL_0018:  newobj     ""System.Func<I>..ctor(object, System.IntPtr)""
  IL_001d:  dup
  IL_001e:  stsfld     ""System.Func<I> C.<>c.<>9__0_2""
  IL_0023:  ret
  IL_0024:  ldarg.0
  IL_0025:  ldc.i4.1
  IL_0026:  beq.s      IL_0048
  IL_0028:  ldsfld     ""System.Func<I> C.<>c.<>9__0_1""
  IL_002d:  dup
  IL_002e:  brtrue.s   IL_0067
  IL_0030:  pop
  IL_0031:  ldsfld     ""C.<>c C.<>c.<>9""
  IL_0036:  ldftn      ""I C.<>c.<Tester>b__0_1()""
  IL_003c:  newobj     ""System.Func<I>..ctor(object, System.IntPtr)""
  IL_0041:  dup
  IL_0042:  stsfld     ""System.Func<I> C.<>c.<>9__0_1""
  IL_0047:  ret
  IL_0048:  ldsfld     ""System.Func<I> C.<>c.<>9__0_0""
  IL_004d:  dup
  IL_004e:  brtrue.s   IL_0067
  IL_0050:  pop
  IL_0051:  ldsfld     ""C.<>c C.<>c.<>9""
  IL_0056:  ldftn      ""I C.<>c.<Tester>b__0_0()""
  IL_005c:  newobj     ""System.Func<I>..ctor(object, System.IntPtr)""
  IL_0061:  dup
  IL_0062:  stsfld     ""System.Func<I> C.<>c.<>9__0_0""
  IL_0067:  ret
}
");
        }
 
        [Fact, WorkItem(638289, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/638289")]
        public void ConditionalDelegateInterfaceUnification3()
        {
            var src =
                @"using System;
using System.Security;
 
[assembly: SecurityTransparent()]
 
interface I {}
 
class A : I {}
 
class B : I {}
 
class C : I
{
    static Func<I> Tester(int a)
    {
        return a > 0 
                ? (() => new A())
                : a == -1 
                    ? (Func<I>)(() => new B())
                    : (() => new C());
    }
    static void Main()
    {
        System.Console.Write(Tester(-1)().GetType());
    }
}";
            var verify = CompileAndVerify(src,
                options: TestOptions.DebugExe,
                expectedOutput: "B");
            verify.VerifyIL("C.Tester", @"
{
  // Code size      111 (0x6f)
  .maxstack  2
  .locals init (System.Func<I> V_0)
  IL_0000:  nop
  IL_0001:  ldarg.0
  IL_0002:  ldc.i4.0
  IL_0003:  bgt.s      IL_004b
  IL_0005:  ldarg.0
  IL_0006:  ldc.i4.m1
  IL_0007:  beq.s      IL_002a
  IL_0009:  ldsfld     ""System.Func<I> C.<>c.<>9__0_2""
  IL_000e:  dup
  IL_000f:  brtrue.s   IL_0028
  IL_0011:  pop
  IL_0012:  ldsfld     ""C.<>c C.<>c.<>9""
  IL_0017:  ldftn      ""I C.<>c.<Tester>b__0_2()""
  IL_001d:  newobj     ""System.Func<I>..ctor(object, System.IntPtr)""
  IL_0022:  dup
  IL_0023:  stsfld     ""System.Func<I> C.<>c.<>9__0_2""
  IL_0028:  br.s       IL_0049
  IL_002a:  ldsfld     ""System.Func<I> C.<>c.<>9__0_1""
  IL_002f:  dup
  IL_0030:  brtrue.s   IL_0049
  IL_0032:  pop
  IL_0033:  ldsfld     ""C.<>c C.<>c.<>9""
  IL_0038:  ldftn      ""I C.<>c.<Tester>b__0_1()""
  IL_003e:  newobj     ""System.Func<I>..ctor(object, System.IntPtr)""
  IL_0043:  dup
  IL_0044:  stsfld     ""System.Func<I> C.<>c.<>9__0_1""
  IL_0049:  br.s       IL_006a
  IL_004b:  ldsfld     ""System.Func<I> C.<>c.<>9__0_0""
  IL_0050:  dup
  IL_0051:  brtrue.s   IL_006a
  IL_0053:  pop
  IL_0054:  ldsfld     ""C.<>c C.<>c.<>9""
  IL_0059:  ldftn      ""I C.<>c.<Tester>b__0_0()""
  IL_005f:  newobj     ""System.Func<I>..ctor(object, System.IntPtr)""
  IL_0064:  dup
  IL_0065:  stsfld     ""System.Func<I> C.<>c.<>9__0_0""
  IL_006a:  stloc.0
  IL_006b:  br.s       IL_006d
  IL_006d:  ldloc.0
  IL_006e:  ret
}
");
            verify = CompileAndVerify(src,
                expectedOutput: "B");
            verify.VerifyIL("C.Tester", @"
{
  // Code size      104 (0x68)
  .maxstack  2
  IL_0000:  ldarg.0
  IL_0001:  ldc.i4.0
  IL_0002:  bgt.s      IL_0048
  IL_0004:  ldarg.0
  IL_0005:  ldc.i4.m1
  IL_0006:  beq.s      IL_0028
  IL_0008:  ldsfld     ""System.Func<I> C.<>c.<>9__0_2""
  IL_000d:  dup
  IL_000e:  brtrue.s   IL_0067
  IL_0010:  pop
  IL_0011:  ldsfld     ""C.<>c C.<>c.<>9""
  IL_0016:  ldftn      ""I C.<>c.<Tester>b__0_2()""
  IL_001c:  newobj     ""System.Func<I>..ctor(object, System.IntPtr)""
  IL_0021:  dup
  IL_0022:  stsfld     ""System.Func<I> C.<>c.<>9__0_2""
  IL_0027:  ret
  IL_0028:  ldsfld     ""System.Func<I> C.<>c.<>9__0_1""
  IL_002d:  dup
  IL_002e:  brtrue.s   IL_0067
  IL_0030:  pop
  IL_0031:  ldsfld     ""C.<>c C.<>c.<>9""
  IL_0036:  ldftn      ""I C.<>c.<Tester>b__0_1()""
  IL_003c:  newobj     ""System.Func<I>..ctor(object, System.IntPtr)""
  IL_0041:  dup
  IL_0042:  stsfld     ""System.Func<I> C.<>c.<>9__0_1""
  IL_0047:  ret
  IL_0048:  ldsfld     ""System.Func<I> C.<>c.<>9__0_0""
  IL_004d:  dup
  IL_004e:  brtrue.s   IL_0067
  IL_0050:  pop
  IL_0051:  ldsfld     ""C.<>c C.<>c.<>9""
  IL_0056:  ldftn      ""I C.<>c.<Tester>b__0_0()""
  IL_005c:  newobj     ""System.Func<I>..ctor(object, System.IntPtr)""
  IL_0061:  dup
  IL_0062:  stsfld     ""System.Func<I> C.<>c.<>9__0_0""
  IL_0067:  ret
}");
        }
 
        [Fact, WorkItem(638289, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/638289")]
        public void ConditionalDelegateInterfaceUnification4()
        {
            var src =
                @"using System;
using System.Security;
 
[assembly: SecurityTransparent()]
 
interface I {}
 
class A : I {}
 
class B : I {}
 
class D : I {}
 
class C : I
{
    static Func<I> Tester(int a)
    {
        return a > 0 
                ? a == 1 
                    ? (Func<I>)(() => new A())
                    : () => new B()
                : a == -1 
                    ? () => new C()
                    : (Func<I>)(() => new D());
    }
    static void Main()
    {
        System.Console.Write(Tester(-2)().GetType());
    }
}";
            var verify = CompileAndVerify(src,
                options: TestOptions.DebugExe,
                expectedOutput: "D");
            verify.VerifyIL("C.Tester", @"
{
  // Code size      148 (0x94)
  .maxstack  2
  .locals init (System.Func<I> V_0)
  IL_0000:  nop
  IL_0001:  ldarg.0
  IL_0002:  ldc.i4.0
  IL_0003:  bgt.s      IL_004b
  IL_0005:  ldarg.0
  IL_0006:  ldc.i4.m1
  IL_0007:  beq.s      IL_002a
  IL_0009:  ldsfld     ""System.Func<I> C.<>c.<>9__0_3""
  IL_000e:  dup
  IL_000f:  brtrue.s   IL_0028
  IL_0011:  pop
  IL_0012:  ldsfld     ""C.<>c C.<>c.<>9""
  IL_0017:  ldftn      ""I C.<>c.<Tester>b__0_3()""
  IL_001d:  newobj     ""System.Func<I>..ctor(object, System.IntPtr)""
  IL_0022:  dup
  IL_0023:  stsfld     ""System.Func<I> C.<>c.<>9__0_3""
  IL_0028:  br.s       IL_0049
  IL_002a:  ldsfld     ""System.Func<I> C.<>c.<>9__0_2""
  IL_002f:  dup
  IL_0030:  brtrue.s   IL_0049
  IL_0032:  pop
  IL_0033:  ldsfld     ""C.<>c C.<>c.<>9""
  IL_0038:  ldftn      ""I C.<>c.<Tester>b__0_2()""
  IL_003e:  newobj     ""System.Func<I>..ctor(object, System.IntPtr)""
  IL_0043:  dup
  IL_0044:  stsfld     ""System.Func<I> C.<>c.<>9__0_2""
  IL_0049:  br.s       IL_008f
  IL_004b:  ldarg.0
  IL_004c:  ldc.i4.1
  IL_004d:  beq.s      IL_0070
  IL_004f:  ldsfld     ""System.Func<I> C.<>c.<>9__0_1""
  IL_0054:  dup
  IL_0055:  brtrue.s   IL_006e
  IL_0057:  pop
  IL_0058:  ldsfld     ""C.<>c C.<>c.<>9""
  IL_005d:  ldftn      ""I C.<>c.<Tester>b__0_1()""
  IL_0063:  newobj     ""System.Func<I>..ctor(object, System.IntPtr)""
  IL_0068:  dup
  IL_0069:  stsfld     ""System.Func<I> C.<>c.<>9__0_1""
  IL_006e:  br.s       IL_008f
  IL_0070:  ldsfld     ""System.Func<I> C.<>c.<>9__0_0""
  IL_0075:  dup
  IL_0076:  brtrue.s   IL_008f
  IL_0078:  pop
  IL_0079:  ldsfld     ""C.<>c C.<>c.<>9""
  IL_007e:  ldftn      ""I C.<>c.<Tester>b__0_0()""
  IL_0084:  newobj     ""System.Func<I>..ctor(object, System.IntPtr)""
  IL_0089:  dup
  IL_008a:  stsfld     ""System.Func<I> C.<>c.<>9__0_0""
  IL_008f:  stloc.0
  IL_0090:  br.s       IL_0092
  IL_0092:  ldloc.0
  IL_0093:  ret
}
");
            verify = CompileAndVerify(src,
                expectedOutput: "D");
            verify.VerifyIL("C.Tester", @"
{
  // Code size      140 (0x8c)
  .maxstack  2
  IL_0000:  ldarg.0
  IL_0001:  ldc.i4.0
  IL_0002:  bgt.s      IL_0048
  IL_0004:  ldarg.0
  IL_0005:  ldc.i4.m1
  IL_0006:  beq.s      IL_0028
  IL_0008:  ldsfld     ""System.Func<I> C.<>c.<>9__0_3""
  IL_000d:  dup
  IL_000e:  brtrue.s   IL_008b
  IL_0010:  pop
  IL_0011:  ldsfld     ""C.<>c C.<>c.<>9""
  IL_0016:  ldftn      ""I C.<>c.<Tester>b__0_3()""
  IL_001c:  newobj     ""System.Func<I>..ctor(object, System.IntPtr)""
  IL_0021:  dup
  IL_0022:  stsfld     ""System.Func<I> C.<>c.<>9__0_3""
  IL_0027:  ret
  IL_0028:  ldsfld     ""System.Func<I> C.<>c.<>9__0_2""
  IL_002d:  dup
  IL_002e:  brtrue.s   IL_008b
  IL_0030:  pop
  IL_0031:  ldsfld     ""C.<>c C.<>c.<>9""
  IL_0036:  ldftn      ""I C.<>c.<Tester>b__0_2()""
  IL_003c:  newobj     ""System.Func<I>..ctor(object, System.IntPtr)""
  IL_0041:  dup
  IL_0042:  stsfld     ""System.Func<I> C.<>c.<>9__0_2""
  IL_0047:  ret
  IL_0048:  ldarg.0
  IL_0049:  ldc.i4.1
  IL_004a:  beq.s      IL_006c
  IL_004c:  ldsfld     ""System.Func<I> C.<>c.<>9__0_1""
  IL_0051:  dup
  IL_0052:  brtrue.s   IL_008b
  IL_0054:  pop
  IL_0055:  ldsfld     ""C.<>c C.<>c.<>9""
  IL_005a:  ldftn      ""I C.<>c.<Tester>b__0_1()""
  IL_0060:  newobj     ""System.Func<I>..ctor(object, System.IntPtr)""
  IL_0065:  dup
  IL_0066:  stsfld     ""System.Func<I> C.<>c.<>9__0_1""
  IL_006b:  ret
  IL_006c:  ldsfld     ""System.Func<I> C.<>c.<>9__0_0""
  IL_0071:  dup
  IL_0072:  brtrue.s   IL_008b
  IL_0074:  pop
  IL_0075:  ldsfld     ""C.<>c C.<>c.<>9""
  IL_007a:  ldftn      ""I C.<>c.<Tester>b__0_0()""
  IL_0080:  newobj     ""System.Func<I>..ctor(object, System.IntPtr)""
  IL_0085:  dup
  IL_0086:  stsfld     ""System.Func<I> C.<>c.<>9__0_0""
  IL_008b:  ret
}
");
        }
 
        [Fact(), WorkItem(638289, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/638289")]
        public void NestedConditional1()
        {
            var src =
@"using System.Security;
 
[assembly: SecurityTransparent()]
 
public interface I {}
 
class A : I {}
 
class B : I {}
 
public class C : I
{
    static I Tester(int x, int y)
    {
        return x == 0 
            ? (y == 0 ? (I)new A() : new B())
            : new C();
    }
    static void Main()
    {
        System.Console.Write(Tester(1, 0).GetType());
    }
}";
            var verify = CompileAndVerify(src,
                options: TestOptions.DebugExe,
                expectedOutput: "C");
            verify.VerifyIL("C.Tester", @"
{
  // Code size       37 (0x25)
  .maxstack  1
  .locals init (I V_0,
                I V_1)
  IL_0000:  nop
  IL_0001:  ldarg.0
  IL_0002:  brfalse.s  IL_000d
  IL_0004:  newobj     ""C..ctor()""
  IL_0009:  stloc.0
  IL_000a:  ldloc.0
  IL_000b:  br.s       IL_0020
  IL_000d:  ldarg.1
  IL_000e:  brfalse.s  IL_0019
  IL_0010:  newobj     ""B..ctor()""
  IL_0015:  stloc.0
  IL_0016:  ldloc.0
  IL_0017:  br.s       IL_0020
  IL_0019:  newobj     ""A..ctor()""
  IL_001e:  stloc.0
  IL_001f:  ldloc.0
  IL_0020:  stloc.1
  IL_0021:  br.s       IL_0023
  IL_0023:  ldloc.1
  IL_0024:  ret
}");
            // Optimized
            verify = CompileAndVerify(src,
                expectedOutput: "C");
            verify.VerifyIL("C.Tester", @"
{
  // Code size       30 (0x1e)
  .maxstack  1
  .locals init (I V_0)
  IL_0000:  ldarg.0
  IL_0001:  brfalse.s  IL_000b
  IL_0003:  newobj     ""C..ctor()""
  IL_0008:  stloc.0
  IL_0009:  ldloc.0
  IL_000a:  ret
  IL_000b:  ldarg.1
  IL_000c:  brfalse.s  IL_0016
  IL_000e:  newobj     ""B..ctor()""
  IL_0013:  stloc.0
  IL_0014:  ldloc.0
  IL_0015:  ret
  IL_0016:  newobj     ""A..ctor()""
  IL_001b:  stloc.0
  IL_001c:  ldloc.0
  IL_001d:  ret
}");
        }
 
        [Fact(), WorkItem(638289, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/638289")]
        public void NestedConditional2()
        {
            var src =
@"using System.Security;
 
[assembly: SecurityTransparent()]
 
public interface I {}
 
class A : I {}
 
class B : I {}
 
public class C : I
{
    static I Tester(int x)
    {
        return x > 0 
            ? new C()
            : (x < 0 ? (I)new A() : new B());
    }
    static void Main()
    {
        System.Console.Write(Tester(0).GetType());
    }
}";
            var verify = CompileAndVerify(src,
                options: TestOptions.DebugExe,
                expectedOutput: "B");
            verify.VerifyIL("C.Tester", @"
{
  // Code size       39 (0x27)
  .maxstack  2
  .locals init (I V_0,
                I V_1)
  IL_0000:  nop
  IL_0001:  ldarg.0
  IL_0002:  ldc.i4.0
  IL_0003:  bgt.s      IL_001b
  IL_0005:  ldarg.0
  IL_0006:  ldc.i4.0
  IL_0007:  blt.s      IL_0012
  IL_0009:  newobj     ""B..ctor()""
  IL_000e:  stloc.0
  IL_000f:  ldloc.0
  IL_0010:  br.s       IL_0019
  IL_0012:  newobj     ""A..ctor()""
  IL_0017:  stloc.0
  IL_0018:  ldloc.0
  IL_0019:  br.s       IL_0022
  IL_001b:  newobj     ""C..ctor()""
  IL_0020:  stloc.0
  IL_0021:  ldloc.0
  IL_0022:  stloc.1
  IL_0023:  br.s       IL_0025
  IL_0025:  ldloc.1
  IL_0026:  ret
}");
            // Optimized
            verify = CompileAndVerify(src,
                expectedOutput: "B");
            verify.VerifyIL("C.Tester", @"
{
  // Code size       32 (0x20)
  .maxstack  2
  .locals init (I V_0)
  IL_0000:  ldarg.0
  IL_0001:  ldc.i4.0
  IL_0002:  bgt.s      IL_0018
  IL_0004:  ldarg.0
  IL_0005:  ldc.i4.0
  IL_0006:  blt.s      IL_0010
  IL_0008:  newobj     ""B..ctor()""
  IL_000d:  stloc.0
  IL_000e:  ldloc.0
  IL_000f:  ret
  IL_0010:  newobj     ""A..ctor()""
  IL_0015:  stloc.0
  IL_0016:  ldloc.0
  IL_0017:  ret
  IL_0018:  newobj     ""C..ctor()""
  IL_001d:  stloc.0
  IL_001e:  ldloc.0
  IL_001f:  ret
}");
        }
 
        [Fact(), WorkItem(638289, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/638289")]
        public void NestedConditional3()
        {
            var src =
@"using System.Security;
 
[assembly: SecurityTransparent()]
 
public interface I {}
 
class A : I {}
 
class B : I {}
 
class D : I {}
 
public class C : I
{
    static I Tester(int x)
    {
        return x > 0 
            ? x == 1 ? (I)new A() : new B()
            : x == 0 ? (I)new C() : new D();
    }
    static void Main()
    {
        System.Console.Write(Tester(1).GetType());
    }
}";
            var verify = CompileAndVerify(src,
                options: TestOptions.DebugExe,
                expectedOutput: "A");
            verify.VerifyIL("C.Tester", @"
{
  // Code size       51 (0x33)
  .maxstack  2
  .locals init (I V_0,
                I V_1)
  IL_0000:  nop
  IL_0001:  ldarg.0
  IL_0002:  ldc.i4.0
  IL_0003:  bgt.s      IL_001a
  IL_0005:  ldarg.0
  IL_0006:  brfalse.s  IL_0011
  IL_0008:  newobj     ""D..ctor()""
  IL_000d:  stloc.0
  IL_000e:  ldloc.0
  IL_000f:  br.s       IL_0018
  IL_0011:  newobj     ""C..ctor()""
  IL_0016:  stloc.0
  IL_0017:  ldloc.0
  IL_0018:  br.s       IL_002e
  IL_001a:  ldarg.0
  IL_001b:  ldc.i4.1
  IL_001c:  beq.s      IL_0027
  IL_001e:  newobj     ""B..ctor()""
  IL_0023:  stloc.0
  IL_0024:  ldloc.0
  IL_0025:  br.s       IL_002e
  IL_0027:  newobj     ""A..ctor()""
  IL_002c:  stloc.0
  IL_002d:  ldloc.0
  IL_002e:  stloc.1
  IL_002f:  br.s       IL_0031
  IL_0031:  ldloc.1
  IL_0032:  ret
}");
            // Optimized
            verify = CompileAndVerify(src,
                expectedOutput: "A");
            verify.VerifyIL("C.Tester", @"
{
  // Code size       43 (0x2b)
  .maxstack  2
  .locals init (I V_0)
  IL_0000:  ldarg.0
  IL_0001:  ldc.i4.0
  IL_0002:  bgt.s      IL_0017
  IL_0004:  ldarg.0
  IL_0005:  brfalse.s  IL_000f
  IL_0007:  newobj     ""D..ctor()""
  IL_000c:  stloc.0
  IL_000d:  ldloc.0
  IL_000e:  ret
  IL_000f:  newobj     ""C..ctor()""
  IL_0014:  stloc.0
  IL_0015:  ldloc.0
  IL_0016:  ret
  IL_0017:  ldarg.0
  IL_0018:  ldc.i4.1
  IL_0019:  beq.s      IL_0023
  IL_001b:  newobj     ""B..ctor()""
  IL_0020:  stloc.0
  IL_0021:  ldloc.0
  IL_0022:  ret
  IL_0023:  newobj     ""A..ctor()""
  IL_0028:  stloc.0
  IL_0029:  ldloc.0
  IL_002a:  ret
}");
        }
 
        [Fact(), WorkItem(638289, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/638289")]
        public void NestedConditional4()
        {
            var src =
@"using System.Security;
 
[assembly: SecurityTransparent()]
 
public interface I {}
 
class A : I {}
 
class B : I {}
 
class D : I {}
 
public class C : I
{
    static I Tester(int x)
    {
        return x > 0 
            ? x > 1
                ? x > 2 
                    ? (I)new A() 
                    : new B() 
                : new C()
            : new D();
    }
    static void Main()
    {
        System.Console.Write(Tester(0).GetType());
    }
}";
            var verify = CompileAndVerify(src,
                options: TestOptions.DebugExe,
                expectedOutput: "D");
            verify.VerifyIL("C.Tester", @"
{
  // Code size       52 (0x34)
  .maxstack  2
  .locals init (I V_0,
                I V_1)
  IL_0000:  nop
  IL_0001:  ldarg.0
  IL_0002:  ldc.i4.0
  IL_0003:  bgt.s      IL_000e
  IL_0005:  newobj     ""D..ctor()""
  IL_000a:  stloc.0
  IL_000b:  ldloc.0
  IL_000c:  br.s       IL_002f
  IL_000e:  ldarg.0
  IL_000f:  ldc.i4.1
  IL_0010:  bgt.s      IL_001b
  IL_0012:  newobj     ""C..ctor()""
  IL_0017:  stloc.0
  IL_0018:  ldloc.0
  IL_0019:  br.s       IL_002f
  IL_001b:  ldarg.0
  IL_001c:  ldc.i4.2
  IL_001d:  bgt.s      IL_0028
  IL_001f:  newobj     ""B..ctor()""
  IL_0024:  stloc.0
  IL_0025:  ldloc.0
  IL_0026:  br.s       IL_002f
  IL_0028:  newobj     ""A..ctor()""
  IL_002d:  stloc.0
  IL_002e:  ldloc.0
  IL_002f:  stloc.1
  IL_0030:  br.s       IL_0032
  IL_0032:  ldloc.1
  IL_0033:  ret
}");
            // Optimized
            verify = CompileAndVerify(src,
                expectedOutput: "D");
            verify.VerifyIL("C.Tester", @"
{
  // Code size       44 (0x2c)
  .maxstack  2
  .locals init (I V_0)
  IL_0000:  ldarg.0
  IL_0001:  ldc.i4.0
  IL_0002:  bgt.s      IL_000c
  IL_0004:  newobj     ""D..ctor()""
  IL_0009:  stloc.0
  IL_000a:  ldloc.0
  IL_000b:  ret
  IL_000c:  ldarg.0
  IL_000d:  ldc.i4.1
  IL_000e:  bgt.s      IL_0018
  IL_0010:  newobj     ""C..ctor()""
  IL_0015:  stloc.0
  IL_0016:  ldloc.0
  IL_0017:  ret
  IL_0018:  ldarg.0
  IL_0019:  ldc.i4.2
  IL_001a:  bgt.s      IL_0024
  IL_001c:  newobj     ""B..ctor()""
  IL_0021:  stloc.0
  IL_0022:  ldloc.0
  IL_0023:  ret
  IL_0024:  newobj     ""A..ctor()""
  IL_0029:  stloc.0
  IL_002a:  ldloc.0
  IL_002b:  ret
}");
        }
 
        [Fact]
        public void TestConditionalOperatorSimple()
        {
            var source = @"
class C
{
    static void Main()
    {
        bool b = true;
        System.Console.WriteLine(b ? 1 : 2);
    }
}";
            var comp = CompileAndVerify(source, expectedOutput: "1");
            comp.VerifyDiagnostics();
            comp.VerifyIL("C.Main", @"{
  // Code size       13 (0xd)
  .maxstack  1
  IL_0000:  ldc.i4.1
  IL_0001:  brtrue.s   IL_0006
  IL_0003:  ldc.i4.2
  IL_0004:  br.s       IL_0007
  IL_0006:  ldc.i4.1
  IL_0007:  call       ""void System.Console.WriteLine(int)""
  IL_000c:  ret
}");
        }
 
        [Fact]
        public void TestConditionalOperatorConstantCondition()
        {
            var source = @"
class C
{
    static void Main()
    {
        int x = 1;
        int y = 2;
        System.Console.WriteLine(true ? x : y);
        System.Console.WriteLine(false ? x : y);
    }
}";
            var comp = CompileAndVerify(source, expectedOutput: @"
1
2");
            comp.VerifyDiagnostics();
            comp.VerifyIL("C.Main", @"{
  // Code size       15 (0xf)
  .maxstack  2
  .locals init (int V_0) //y
  IL_0000:  ldc.i4.1
  IL_0001:  ldc.i4.2
  IL_0002:  stloc.0
  IL_0003:  call       ""void System.Console.WriteLine(int)""
  IL_0008:  ldloc.0
  IL_0009:  call       ""void System.Console.WriteLine(int)""
  IL_000e:  ret
}");
        }
 
        [Fact]
        public void TestConditionalOperatorNullLiteral()
        {
            var source = @"
class C
{
    static void Main()
    {
        bool b = true;
        string s1 = b ? ""hello"" : null;
        System.Console.WriteLine(s1);
        string s2 = b ? null : ""goodbye"";
        System.Console.WriteLine(s2);
    }
}";
            var comp = CompileAndVerify(source);
            comp.VerifyDiagnostics();
            comp.VerifyIL("C.Main", @"
{
  // Code size       33 (0x21)
  .maxstack  2
  IL_0000:  ldc.i4.1
  IL_0001:  dup
  IL_0002:  brtrue.s   IL_0007
  IL_0004:  ldnull
  IL_0005:  br.s       IL_000c
  IL_0007:  ldstr      ""hello""
  IL_000c:  call       ""void System.Console.WriteLine(string)""
  IL_0011:  brtrue.s   IL_001a
  IL_0013:  ldstr      ""goodbye""
  IL_0018:  br.s       IL_001b
  IL_001a:  ldnull
  IL_001b:  call       ""void System.Console.WriteLine(string)""
  IL_0020:  ret
}");
        }
 
        [Fact]
        public void TestConditionalOperatorLambda()
        {
            var source = @"
class C
{
    static void Main()
    {
        bool b = true;
        System.Func<int, int> f = null;
        System.Console.WriteLine(f);
        System.Func<int, int> g1 = b ? f : x => x;
        System.Console.WriteLine(g1);
        System.Func<int, int> g2 = b ? x => x : f;
        System.Console.WriteLine(g2);
    }
}";
            // NOTE: this is slightly different from the Dev10 IL, which caches the lambdas in static fields
            var comp = CompileAndVerify(source);
            comp.VerifyDiagnostics();
            comp.VerifyIL("C.Main", @"
{
  // Code size       93 (0x5d)
  .maxstack  3
  .locals init (System.Func<int, int> V_0) //f
  IL_0000:  ldc.i4.1
  IL_0001:  ldnull
  IL_0002:  stloc.0
  IL_0003:  ldloc.0
  IL_0004:  call       ""void System.Console.WriteLine(object)""
  IL_0009:  dup
  IL_000a:  brtrue.s   IL_002d
  IL_000c:  ldsfld     ""System.Func<int, int> C.<>c.<>9__0_0""
  IL_0011:  dup
  IL_0012:  brtrue.s   IL_002e
  IL_0014:  pop
  IL_0015:  ldsfld     ""C.<>c C.<>c.<>9""
  IL_001a:  ldftn      ""int C.<>c.<Main>b__0_0(int)""
  IL_0020:  newobj     ""System.Func<int, int>..ctor(object, System.IntPtr)""
  IL_0025:  dup
  IL_0026:  stsfld     ""System.Func<int, int> C.<>c.<>9__0_0""
  IL_002b:  br.s       IL_002e
  IL_002d:  ldloc.0
  IL_002e:  call       ""void System.Console.WriteLine(object)""
  IL_0033:  brtrue.s   IL_0038
  IL_0035:  ldloc.0
  IL_0036:  br.s       IL_0057
  IL_0038:  ldsfld     ""System.Func<int, int> C.<>c.<>9__0_1""
  IL_003d:  dup
  IL_003e:  brtrue.s   IL_0057
  IL_0040:  pop
  IL_0041:  ldsfld     ""C.<>c C.<>c.<>9""
  IL_0046:  ldftn      ""int C.<>c.<Main>b__0_1(int)""
  IL_004c:  newobj     ""System.Func<int, int>..ctor(object, System.IntPtr)""
  IL_0051:  dup
  IL_0052:  stsfld     ""System.Func<int, int> C.<>c.<>9__0_1""
  IL_0057:  call       ""void System.Console.WriteLine(object)""
  IL_005c:  ret
}
");
        }
 
        [Fact]
        public void TestConditionalOperatorMethodGroup()
        {
            var source = @"
class C
{
    static void Main()
    {
        bool b = true;
        System.Func<int> f = null;
        System.Console.WriteLine(f);
        System.Func<int> g1 = b ? f : M;
        System.Console.WriteLine(g1);
        System.Func<int> g2 = b ? M : f;
        System.Console.WriteLine(g2);
    }
 
    static int M()
    {
        return 0;
    }
}";
            var comp = CompileAndVerify(source, parseOptions: TestOptions.Regular10);
            comp.VerifyDiagnostics();
            comp.VerifyIL("C.Main", @"
{
  // Code size       55 (0x37)
  .maxstack  3
  .locals init (System.Func<int> V_0) //f
  IL_0000:  ldc.i4.1
  IL_0001:  ldnull
  IL_0002:  stloc.0
  IL_0003:  ldloc.0
  IL_0004:  call       ""void System.Console.WriteLine(object)""
  IL_0009:  dup
  IL_000a:  brtrue.s   IL_001a
  IL_000c:  ldnull
  IL_000d:  ldftn      ""int C.M()""
  IL_0013:  newobj     ""System.Func<int>..ctor(object, System.IntPtr)""
  IL_0018:  br.s       IL_001b
  IL_001a:  ldloc.0
  IL_001b:  call       ""void System.Console.WriteLine(object)""
  IL_0020:  brtrue.s   IL_0025
  IL_0022:  ldloc.0
  IL_0023:  br.s       IL_0031
  IL_0025:  ldnull
  IL_0026:  ldftn      ""int C.M()""
  IL_002c:  newobj     ""System.Func<int>..ctor(object, System.IntPtr)""
  IL_0031:  call       ""void System.Console.WriteLine(object)""
  IL_0036:  ret
}
");
        }
 
        [Fact]
        public void TestConditionalOperatorPreferWider()
        {
            var source = @"
class C
{
    static void Main()
    {
        bool b = true;
        System.Console.Write(b ? 0 : (short)1);
        System.Console.Write(b ? 0 : 1u);
    }
}";
            // NOTE: second call is to Write(uint)
            var comp = CompileAndVerify(source, expectedOutput: "00");
            comp.VerifyDiagnostics();
            comp.VerifyIL("C.Main", @"
{
  // Code size       19 (0x13)
  .maxstack  3
  IL_0000:  ldc.i4.1
  IL_0001:  dup
  IL_0002:  ldc.i4.0
  IL_0003:  ceq
  IL_0005:  call       ""void System.Console.Write(int)""
  IL_000a:  ldc.i4.0
  IL_000b:  ceq
  IL_000d:  call       ""void System.Console.Write(uint)""
  IL_0012:  ret
}");
        }
 
        /// <summary>
        /// This specific code has caused problems in the past.
        /// System.Security.VerificationException on the second attempt.
        /// </summary>
        /// <remarks>
        /// No special handling seems to have been required to make this work
        /// in Roslyn.
        /// </remarks>
        [Fact]
        public void TestConditionalOperatorInterfaceRegression1()
        {
            var source = @"
using System;
using System.Collections.Generic;
 
public class Test
{
    static void Main()
    {
        IList<Type> knownTypeList = null;
 
        Console.Write(""first attempt: "");
        object o1 = (IList<Type>)(knownTypeList == null ? new Type[0] : knownTypeList);
        Console.WriteLine(o1);
 
        Console.Write(""second attempt: "");
        IList<Type> o2 = (IList<Type>)(knownTypeList == null ? new Type[0] : knownTypeList);
        Console.WriteLine(o2);
    }
}";
            // NOTE: second call is to Write(uint)
            var comp = CompileAndVerify(source, expectedOutput: @"
first attempt: System.Type[]
second attempt: System.Type[]");
            comp.VerifyDiagnostics();
            comp.VerifyIL("Test.Main", @"
{
  // Code size       61 (0x3d)
  .maxstack  1
  .locals init (System.Collections.Generic.IList<System.Type> V_0, //knownTypeList
  System.Collections.Generic.IList<System.Type> V_1)
  IL_0000:  ldnull
  IL_0001:  stloc.0
  IL_0002:  ldstr      ""first attempt: ""
  IL_0007:  call       ""void System.Console.Write(string)""
  IL_000c:  ldloc.0
  IL_000d:  brfalse.s  IL_0012
  IL_000f:  ldloc.0
  IL_0010:  br.s       IL_001a
  IL_0012:  ldc.i4.0
  IL_0013:  newarr     ""System.Type""
  IL_0018:  stloc.1
  IL_0019:  ldloc.1
  IL_001a:  call       ""void System.Console.WriteLine(object)""
  IL_001f:  ldstr      ""second attempt: ""
  IL_0024:  call       ""void System.Console.Write(string)""
  IL_0029:  ldloc.0
  IL_002a:  brfalse.s  IL_002f
  IL_002c:  ldloc.0
  IL_002d:  br.s       IL_0037
  IL_002f:  ldc.i4.0
  IL_0030:  newarr     ""System.Type""
  IL_0035:  stloc.1
  IL_0036:  ldloc.1
  IL_0037:  call       ""void System.Console.WriteLine(object)""
  IL_003c:  ret
}");
        }
 
        /// <summary>
        /// From orcas bug #42645.  PEVerify fails.
        /// </summary>
        [Fact]
        public void TestConditionalOperatorInterfaceRegression2()
        {
            var source = @"
using System.Collections.Generic;
 
public class Test
{
    static void Main()
    {
        int[] a = new int[] { };
        List<int> b = new List<int>();
 
        IEnumerable<int> c = a != null ? a : (IEnumerable<int>)b;
        System.Console.WriteLine(c);
    }
}";
            // Note the explicit casts, even though the conversions are
            // implicit reference conversions.
            var comp = CompileAndVerify(source);
            comp.VerifyDiagnostics();
            comp.VerifyIL("Test.Main", @"
{
  // Code size       30 (0x1e)
  .maxstack  1
  .locals init (int[] V_0, //a
  System.Collections.Generic.List<int> V_1, //b
  System.Collections.Generic.IEnumerable<int> V_2)
  IL_0000:  ldc.i4.0
  IL_0001:  newarr     ""int""
  IL_0006:  stloc.0
  IL_0007:  newobj     ""System.Collections.Generic.List<int>..ctor()""
  IL_000c:  stloc.1
  IL_000d:  ldloc.0
  IL_000e:  brtrue.s   IL_0015
  IL_0010:  ldloc.1
  IL_0011:  stloc.2
  IL_0012:  ldloc.2
  IL_0013:  br.s       IL_0018
  IL_0015:  ldloc.0
  IL_0016:  stloc.2
  IL_0017:  ldloc.2
  IL_0018:  call       ""void System.Console.WriteLine(object)""
  IL_001d:  ret
}");
        }
 
        [Fact]
        public void TestConditionalOperatorInterfaceRegression2a()
        {
            var source = @"
using System.Collections.Generic;
 
public class Test
{
    static void Main()
    {
        int[] a = new int[] { };
        List<int> b = new List<int>();
 
        IEnumerable<int> c = a != null ? a : (IEnumerable<int>)b;
    }
}";
            // Note the explicit casts, even though the conversions are
            // implicit reference conversions.
            var comp = CompileAndVerify(source);
            comp.VerifyDiagnostics();
            comp.VerifyIL("Test.Main", @"
{
  // Code size       16 (0x10)
  .maxstack  1
  .locals init (int[] V_0, //a
  System.Collections.Generic.List<int> V_1) //b
  IL_0000:  ldc.i4.0
  IL_0001:  newarr     ""int""
  IL_0006:  stloc.0
  IL_0007:  newobj     ""System.Collections.Generic.List<int>..ctor()""
  IL_000c:  stloc.1
  IL_000d:  ldloc.0
  IL_000e:  pop
  IL_000f:  ret
}
");
        }
        /// <summary>
        /// From whidbey bug #108643.  Extraneous class casts in Test1.m2 (vs Test1.m1).
        /// </summary>
        [Fact]
        public void TestConditionalOperatorInterfaceRegression3()
        {
            var source = @"
interface Base { Base m1();}
class Driver { public static int mask = 1;}
class Test1 : Base
{
    Base next;
    Base same;
    int cnt = 0;
    public Test1(Base link)
    {
        same = this;
        next = link;
        if (next == null) next = this;
    }
    public Base m1() { return ((++cnt) & Driver.mask) != 0 ? same : next; } //version1 (explicit impl in original repro)
    public Base m2() { return ((++cnt) & Driver.mask) != 0 ? this : next; } //version2 
}";
            var comp = CompileAndVerify(source);
            comp.VerifyDiagnostics();
            comp.VerifyIL("Test1.m1", @"
{
  // Code size       39 (0x27)
  .maxstack  3
  .locals init (int V_0)
  IL_0000:  ldarg.0
  IL_0001:  ldarg.0
  IL_0002:  ldfld      ""int Test1.cnt""
  IL_0007:  ldc.i4.1
  IL_0008:  add
  IL_0009:  stloc.0
  IL_000a:  ldloc.0
  IL_000b:  stfld      ""int Test1.cnt""
  IL_0010:  ldloc.0
  IL_0011:  ldsfld     ""int Driver.mask""
  IL_0016:  and
  IL_0017:  brtrue.s   IL_0020
  IL_0019:  ldarg.0
  IL_001a:  ldfld      ""Base Test1.next""
  IL_001f:  ret
  IL_0020:  ldarg.0
  IL_0021:  ldfld      ""Base Test1.same""
  IL_0026:  ret
}");
            // NOTE: no castclass
            comp.VerifyIL("Test1.m2", @"
{
  // Code size       36 (0x24)
  .maxstack  3
  .locals init (int V_0,
  Base V_1)
  IL_0000:  ldarg.0
  IL_0001:  ldarg.0
  IL_0002:  ldfld      ""int Test1.cnt""
  IL_0007:  ldc.i4.1
  IL_0008:  add
  IL_0009:  stloc.0
  IL_000a:  ldloc.0
  IL_000b:  stfld      ""int Test1.cnt""
  IL_0010:  ldloc.0
  IL_0011:  ldsfld     ""int Driver.mask""
  IL_0016:  and
  IL_0017:  brtrue.s   IL_0020
  IL_0019:  ldarg.0
  IL_001a:  ldfld      ""Base Test1.next""
  IL_001f:  ret
  IL_0020:  ldarg.0
  IL_0021:  stloc.1
  IL_0022:  ldloc.1
  IL_0023:  ret
}");
        }
 
        /// <summary>
        /// From whidbey bug #49619.  PEVerify fails.
        /// </summary>
        [Fact]
        public void TestConditionalOperatorInterfaceRegression4()
        {
            var source = @"
public interface IA { }
public interface IB { int f(); }
public class AB1 : IA, IB { public int f() { return 42; } }
public class AB2 : IA, IB { public int f() { return 1; } }
 
class MainClass
{
    public static void g(bool p)
    {
        (p ? (IB)new AB1() : (IB)new AB2()).f();
    }
}";
            // Note the explicit casts, even though the conversions are
            // implicit reference conversions.
            // CONSIDER: dev10 writes to/reads from a temp to simulate
            // a static cast (instead of using castclass).
            var comp = CompileAndVerify(source);
            comp.VerifyDiagnostics();
            comp.VerifyIL("MainClass.g", @"
{
  // Code size       26 (0x1a)
  .maxstack  1
  .locals init (IB V_0)
  IL_0000:  ldarg.0
  IL_0001:  brtrue.s   IL_000c
  IL_0003:  newobj     ""AB2..ctor()""
  IL_0008:  stloc.0
  IL_0009:  ldloc.0
  IL_000a:  br.s       IL_0013
  IL_000c:  newobj     ""AB1..ctor()""
  IL_0011:  stloc.0
  IL_0012:  ldloc.0
  IL_0013:  callvirt   ""int IB.f()""
  IL_0018:  pop
  IL_0019:  ret
}");
        }
 
        [WorkItem(9229, "DevDiv_Projects/Roslyn")]
        [Fact]
        public void TestConditionalOperatorForExpression()
        {
            var source = @"
using System.Linq;
using System.Collections.Generic;
class Program
{
    static void Main(string[] args)
    {
        string[] arr = new string[] { ""aaa"", ""bbb"", ""ccc"" };
        int[] arr_int = new int[] { 111, 222, 333 };
        IEnumerable<string> s = true ? from x in arr select x : from x in arr_int select x.ToString();
        foreach (var item in s)
        {
            System.Console.WriteLine(item);
        }
    }
}";
            string expectedOutput = @"aaa
bbb
ccc";
            CompileAndVerify(source, expectedOutput: expectedOutput);
        }
 
        [Fact]
        public void TestConditionalOperatorForObjInit()
        {
            var source = @"
using System;
class Program
{
    static void Main(string[] args)
    {
        Goo f1 = new Goo(), f2 = new Goo(), f3 = new Goo();
        bool b = true;
        f3 = b ? f1 = new Goo { i = 1 } : f2 = new Goo { i = 2 };
        Console.WriteLine(f1.i);
        Console.WriteLine(f2.i);
        Console.WriteLine(f3.i);
        b = false;
        f3 = b ? f1 = new Goo { i = 3 } : f2 = new Goo { i = 4 };
        Console.WriteLine(f1.i);
        Console.WriteLine(f2.i);
        Console.WriteLine(f3.i);
    }
}
class Goo
{
    public int i;
}
";
            string expectedOutput = @"1
0
1
1
4
4";
            CompileAndVerify(source, expectedOutput: expectedOutput);
        }
 
        [Fact]
        public void TestConditionalOperatorForObjInit_2()
        {
            var source = @"
using System;
class Program
{
    static void Main(string[] args)
    {
        bool b1 = true;
        bool b2 = false;
        Goo f = new Goo
        {
            i = b1 ? 10 : -10
        };
        Console.WriteLine(f.i);
        f = new Goo
        {
            i = b2 ? 10 : -10
        };
        Console.WriteLine(f.i);
    }
}
class Goo
{
    public int i;
}
";
            string expectedOutput = @"10
-10";
            CompileAndVerify(source, expectedOutput: expectedOutput);
        }
 
        [Fact]
        public void TestConditionalOperatorForExpressionTree()
        {
            var source = @"
using System;
using System.Linq.Expressions;
class Program
{
    static void Main(string[] args)
    {
        Expression<Func<bool, long, int, long>> testExpr = (x, y, z) => x ? y : z;
        var testFunc = testExpr.Compile();
        Console.WriteLine(testFunc(false, (long)3, 100)); //100
    }
}
";
            string expectedOutput = @"100";
            CompileAndVerify(source, expectedOutput: expectedOutput);
        }
 
        [Fact]
        public void TestConditionalOperatorForCustomOperator()
        {
            var source = @"
using System;
using System.Linq.Expressions;
class Program
{
    static void Main(string[] args)
    {
        Expression<Func<TestStruct, int?, int, int?>> testExpr = (x, y, z) => x ? y : z;
        var testFunc = testExpr.Compile();
        Console.WriteLine(testFunc(new TestStruct(), (int?)null, 10)); //10
    }
}
public struct TestStruct
{
    public static bool operator true(TestStruct ts)
    {
        return false;
    }
    public static bool operator false(TestStruct ts)
    {
        return true;
    }
}
";
            string expectedOutput = @"10";
            CompileAndVerify(source, expectedOutput: expectedOutput);
        }
 
        [Fact]
        public void TestConditionalOperatorForMultiCondition()
        {
            var source = @"
class Program
{
    static void Main(string[] args)
    {
        System.Console.WriteLine(false ? 1 : true ? 2 : 3);
    }
}
";
            string expectedOutput = @"2";
            string expectedIL = @"{
  // Code size        7 (0x7)
  .maxstack  1
  IL_0000:  ldc.i4.2  
  IL_0001:  call       ""void System.Console.WriteLine(int)""
  IL_0006:  ret       
}";
            CompileAndVerify(source, expectedOutput: expectedOutput).VerifyIL("Program.Main", expectedIL);
        }
 
        [WorkItem(528275, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/528275")]
        [Fact]
        public void TestConditionalOperatorForImplicitConv()
        {
            var source = @"
using System.Linq;
class Program
{
    static void Main(string[] args)
    {
        System.Console.WriteLine(false ? Enumerable.Empty<int>() : new int[] { 1 });
    }
}
";
            string expectedOutput = @"System.Int32[]";
            string expectedIL = @"{
  // Code size       16 (0x10)
  .maxstack  4
  IL_0000:  ldc.i4.1  
  IL_0001:  newarr     ""int""
  IL_0006:  dup       
  IL_0007:  ldc.i4.0  
  IL_0008:  ldc.i4.1  
  IL_0009:  stelem.i4 
  IL_000a:  call       ""void System.Console.WriteLine(object)""
  IL_000f:  ret       
}";
            // Dev11 compiler reports WRN_UnreachableExpr, but reachability is defined for statements not for expressions.
            // We don't report the warning.
            CompileAndVerify(source, expectedOutput: expectedOutput).VerifyIL("Program.Main", expectedIL).VerifyDiagnostics();
        }
 
        [Fact]
        public void TestConditionalOperatorForConversion()
        {
            var source = @"
using System;
class Program
{
    static void Main(string[] args)
    {
        object valueFromDatabase;
        decimal result;
        valueFromDatabase = DBNull.Value;
        result = (valueFromDatabase != DBNull.Value ? (decimal)valueFromDatabase : (decimal)0);
        System.Console.WriteLine(result);
        result = (decimal)(valueFromDatabase != DBNull.Value ? valueFromDatabase : 0); //Runtime exception
        System.Console.WriteLine(result);
    }
}
";
            string expectedIL = @"
{
  // Code size       60 (0x3c)
  .maxstack  2
  .locals init (object V_0) //valueFromDatabase
  IL_0000:  ldsfld     ""System.DBNull System.DBNull.Value""
  IL_0005:  stloc.0
  IL_0006:  ldloc.0
  IL_0007:  ldsfld     ""System.DBNull System.DBNull.Value""
  IL_000c:  bne.un.s   IL_0015
  IL_000e:  ldsfld     ""decimal decimal.Zero""
  IL_0013:  br.s       IL_001b
  IL_0015:  ldloc.0
  IL_0016:  unbox.any  ""decimal""
  IL_001b:  call       ""void System.Console.WriteLine(decimal)""
  IL_0020:  ldloc.0
  IL_0021:  ldsfld     ""System.DBNull System.DBNull.Value""
  IL_0026:  bne.un.s   IL_0030
  IL_0028:  ldc.i4.0
  IL_0029:  box        ""int""
  IL_002e:  br.s       IL_0031
  IL_0030:  ldloc.0
  IL_0031:  unbox.any  ""decimal""
  IL_0036:  call       ""void System.Console.WriteLine(decimal)""
  IL_003b:  ret
}";
            CompileAndVerify(source).VerifyIL("Program.Main", expectedIL);
        }
 
        [Fact, WorkItem(530071, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/530071")]
        public void TestConditionalOperatorForImplicitlyTypedArrays()
        {
            var source = @"
using System;
class Program
{
    static void Main(string[] args)
    {
        int[] a, a1, a2;
        a = a1 = a2 = null;
        a = true ? a1 = new[] { 1, 2, 3 } : a2 = new[] { 4, 5, 6 };
        foreach (int item in a1)
        { Console.WriteLine(item); }
    }
}
";
            string expectedOutput = @"1
2
3";
            // Dev11 compiler reports WRN_UnreachableExpr, but reachability is defined for statements not for expressions.
            // We don't report the warning.
            CompileAndVerify(source, expectedOutput: expectedOutput).
                VerifyDiagnostics();
        }
 
        [Fact]
        public void TestConditionalOperatorForConst()
        {
            var source = @"
class Program
{
    const bool con = true;
    static int Main(string[] args)
    {
        int s1 = con != true ? 1 : 2;
        return s1;
    }
}
";
            string expectedIL = @"{
  // Code size        2 (0x2)
  .maxstack  1
  IL_0000:  ldc.i4.2
  IL_0001:  ret
}";
            CompileAndVerify(source).VerifyIL("Program.Main", expectedIL);
        }
 
        [Fact]
        public void TestConditionalOperatorForStatic()
        {
            var source = @"
class Program
{
    static bool con = true;
    static int Main(string[] args)
    {
        int s1 = con != true ? 1 : 2;
        return s1;
    }
}
";
            string expectedIL = @"{
  // Code size       11 (0xb)
  .maxstack  1
  IL_0000:  ldsfld     ""bool Program.con""
  IL_0005:  brfalse.s  IL_0009
  IL_0007:  ldc.i4.2
  IL_0008:  ret
  IL_0009:  ldc.i4.1
  IL_000a:  ret
}";
            CompileAndVerify(source).VerifyIL("Program.Main", expectedIL);
        }
 
        [Fact]
        public void TestConditionalOperatorForGenericMethod()
        {
            var source = @"
class Program
{
    static void Main(string[] args)
    {
        int x = 1;
        object y = 0;
        System.Console.WriteLine(true ? fun(x) : fun(y));
    }
    private static T fun<T>(T t)
    {
        return t;
    }
}
";
            string expectedOutput = @"1";
            string expectedIL = @"{
  // Code size       17 (0x11)
  .maxstack  1
  IL_0000:  ldc.i4.1
  IL_0001:  call       ""int Program.fun<int>(int)""
  IL_0006:  box        ""int""
  IL_000b:  call       ""void System.Console.WriteLine(object)""
  IL_0010:  ret
}";
            CompileAndVerify(source, expectedOutput: expectedOutput).VerifyIL("Program.Main", expectedIL);
        }
 
        [Fact]
        public void TestConditionalOperatorForGenericMethod2()
        {
            var source = @"
class Program
{
    static void Main(string[] args)
    {
        int x = 1;
        object y = 0;
        System.Console.WriteLine(y != null ? fun(x) : fun(y));
    }
    private static T fun<T>(T t)
    {
        return t;
    }
}
";
            string expectedOutput = @"1";
            string expectedIL = @"
{
  // Code size       37 (0x25)
  .maxstack  1
  .locals init (int V_0, //x
  object V_1) //y
  IL_0000:  ldc.i4.1
  IL_0001:  stloc.0
  IL_0002:  ldc.i4.0
  IL_0003:  box        ""int""
  IL_0008:  stloc.1
  IL_0009:  ldloc.1
  IL_000a:  brtrue.s   IL_0014
  IL_000c:  ldloc.1
  IL_000d:  call       ""object Program.fun<object>(object)""
  IL_0012:  br.s       IL_001f
  IL_0014:  ldloc.0
  IL_0015:  call       ""int Program.fun<int>(int)""
  IL_001a:  box        ""int""
  IL_001f:  call       ""void System.Console.WriteLine(object)""
  IL_0024:  ret
}
";
            CompileAndVerify(source, expectedOutput: expectedOutput).VerifyIL("Program.Main", expectedIL);
        }
 
        [Fact]
        public void TestConditionalOperatorForParenthesizedExpression()
        {
            var source = @"
class Program
{
    static void Main(string[] args)
    {
        int x = 1;
        int y = 1;
        System.Console.WriteLine(((x == y)) ? (++x) : ((((++y))))); 	// OK
    }
}
";
            string expectedOutput = @"2";
            CompileAndVerify(source, expectedOutput: expectedOutput);
        }
 
        [Fact]
        public void TestConditionalOperatorForParameter()
        {
            var source = @"
class Program
{
    static bool b = true;
    static void Main(string[] args)
    {
        fun(b);
    }
    static void fun(bool b)
    {
        System.Console.WriteLine(b ? ""true"" : ""false"");
    }
}
";
            string expectedOutput = @"true";
            string expectedIL = @"{
  // Code size       21 (0x15)
  .maxstack  1
  IL_0000:  ldarg.0   
  IL_0001:  brtrue.s   IL_000a
  IL_0003:  ldstr      ""false""
  IL_0008:  br.s       IL_000f
  IL_000a:  ldstr      ""true""
  IL_000f:  call       ""void System.Console.WriteLine(string)""
  IL_0014:  ret       
}";
            CompileAndVerify(source, expectedOutput: expectedOutput).VerifyIL("Program.fun", expectedIL);
        }
 
        [Fact]
        public void TestConditionalOperatorForParameterRef()
        {
            var source = @"
class Program
{
    static bool b = true;
    static void Main(string[] args)
    {
        fun(ref b);
    }
    static void fun(ref bool b)
    {
        System.Console.WriteLine(b != true ? b = true : b = false);
    }
}
";
            string expectedOutput = @"False";
            string expectedIL = @"
{
  // Code size       24 (0x18)
  .maxstack  3
  .locals init (bool V_0)
  IL_0000:  ldarg.0
  IL_0001:  ldind.u1
  IL_0002:  brfalse.s  IL_000c
  IL_0004:  ldarg.0
  IL_0005:  ldc.i4.0
  IL_0006:  dup
  IL_0007:  stloc.0
  IL_0008:  stind.i1
  IL_0009:  ldloc.0
  IL_000a:  br.s       IL_0012
  IL_000c:  ldarg.0
  IL_000d:  ldc.i4.1
  IL_000e:  dup
  IL_000f:  stloc.0
  IL_0010:  stind.i1
  IL_0011:  ldloc.0
  IL_0012:  call       ""void System.Console.WriteLine(bool)""
  IL_0017:  ret
}";
            CompileAndVerify(source, expectedOutput: expectedOutput).VerifyIL("Program.fun", expectedIL);
        }
 
        [Fact]
        public void TestConditionalOperatorForParameterOut()
        {
            var source = @"
class Program
{
    static bool b = true;
    static void Main(string[] args)
    {
        fun(out b);
    }
    static void fun(out bool b)
    {
        System.Console.WriteLine(string.IsNullOrEmpty(""s"")  ? b = true : b = false);
    }
}
";
            string expectedOutput = @"False";
            string expectedIL = @"{
  // Code size       32 (0x20)
  .maxstack  3
  .locals init (bool V_0)
  IL_0000:  ldstr      ""s""
  IL_0005:  call       ""bool string.IsNullOrEmpty(string)""
  IL_000a:  brtrue.s   IL_0014
  IL_000c:  ldarg.0   
  IL_000d:  ldc.i4.0  
  IL_000e:  dup       
  IL_000f:  stloc.0   
  IL_0010:  stind.i1  
  IL_0011:  ldloc.0   
  IL_0012:  br.s       IL_001a
  IL_0014:  ldarg.0   
  IL_0015:  ldc.i4.1  
  IL_0016:  dup       
  IL_0017:  stloc.0   
  IL_0018:  stind.i1  
  IL_0019:  ldloc.0   
  IL_001a:  call       ""void System.Console.WriteLine(bool)""
  IL_001f:  ret       
}";
            CompileAndVerify(source, expectedOutput: expectedOutput).VerifyIL("Program.fun", expectedIL);
        }
 
        [Fact]
        public void TestConditionalRequiringBox()
        {
            var source = @"
public static class Program
{
    public static void Main()
    {
        int a = 1;
        IGoo<string> i = null;
        GooVal e = new GooVal();
 
        i = a > 1 ? i : e;
        System.Console.Write(i.Goo());
    }
 
    interface IGoo<T> { T Goo(); }
 
    struct GooVal : IGoo<string>
    {
        public string Goo() { return ""Val ""; }
    }
}";
            string expectedOutput = @"Val ";
            string expectedIL = @"
{
  // Code size       38 (0x26)
  .maxstack  2
  .locals init (Program.IGoo<string> V_0, //i
  Program.GooVal V_1, //e
  Program.IGoo<string> V_2)
  IL_0000:  ldc.i4.1
  IL_0001:  ldnull
  IL_0002:  stloc.0
  IL_0003:  ldloca.s   V_1
  IL_0005:  initobj    ""Program.GooVal""
  IL_000b:  ldc.i4.1
  IL_000c:  bgt.s      IL_0018
  IL_000e:  ldloc.1
  IL_000f:  box        ""Program.GooVal""
  IL_0014:  stloc.2
  IL_0015:  ldloc.2
  IL_0016:  br.s       IL_0019
  IL_0018:  ldloc.0
  IL_0019:  stloc.0
  IL_001a:  ldloc.0
  IL_001b:  callvirt   ""string Program.IGoo<string>.Goo()""
  IL_0020:  call       ""void System.Console.Write(string)""
  IL_0025:  ret
}";
            CompileAndVerify(source, expectedOutput: expectedOutput).VerifyIL("Program.Main", expectedIL);
        }
 
        [Fact]
        public void TestCoalesceRequiringBox()
        {
            var source = @"
public static class Program
{
    public static void Main()
    {
        IGoo<string> i = null;
        GooVal e = new GooVal();
        GooVal? n = e;
 
        i = i ?? e;
        System.Console.Write(i.Goo());
 
        i = null;
        i = n ?? i;
        System.Console.Write(i.Goo());
    }
 
    interface IGoo<T> { T Goo(); }
 
    struct GooVal : IGoo<string>
    {
        public string Goo() { return ""Val ""; }
    }
}";
            string expectedOutput = @"Val Val ";
            string expectedIL = @"
{
  // Code size       81 (0x51)
  .maxstack  3
  .locals init (Program.IGoo<string> V_0, //i
  Program.GooVal V_1, //e
  Program.GooVal? V_2,
  Program.IGoo<string> V_3)
  IL_0000:  ldnull
  IL_0001:  stloc.0
  IL_0002:  ldloca.s   V_1
  IL_0004:  initobj    ""Program.GooVal""
  IL_000a:  ldloc.1
  IL_000b:  newobj     ""Program.GooVal?..ctor(Program.GooVal)""
  IL_0010:  ldloc.0
  IL_0011:  dup
  IL_0012:  brtrue.s   IL_001b
  IL_0014:  pop
  IL_0015:  ldloc.1
  IL_0016:  box        ""Program.GooVal""
  IL_001b:  stloc.0
  IL_001c:  ldloc.0
  IL_001d:  callvirt   ""string Program.IGoo<string>.Goo()""
  IL_0022:  call       ""void System.Console.Write(string)""
  IL_0027:  ldnull
  IL_0028:  stloc.0
  IL_0029:  stloc.2
  IL_002a:  ldloca.s   V_2
  IL_002c:  call       ""bool Program.GooVal?.HasValue.get""
  IL_0031:  brtrue.s   IL_0036
  IL_0033:  ldloc.0
  IL_0034:  br.s       IL_0044
  IL_0036:  ldloca.s   V_2
  IL_0038:  call       ""Program.GooVal Program.GooVal?.GetValueOrDefault()""
  IL_003d:  box        ""Program.GooVal""
  IL_0042:  stloc.3
  IL_0043:  ldloc.3
  IL_0044:  stloc.0
  IL_0045:  ldloc.0
  IL_0046:  callvirt   ""string Program.IGoo<string>.Goo()""
  IL_004b:  call       ""void System.Console.Write(string)""
  IL_0050:  ret
}";
            CompileAndVerify(source, expectedOutput: expectedOutput).VerifyIL("Program.Main", expectedIL);
        }
 
        [Fact(), WorkItem(543609, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/543609")]
        public void SeveralAdjacentIfsWithConditionalExpressions()
        {
            var source = @"
class Class1
{
    static void Main()
    {
        int x=0;
        int y=0;
        bool local_bool=true;
        if(true?true:local_bool) x++; else y++;
        if(true?false:local_bool) x++; else y++;
        if(true?local_bool:true) x++; else y++;
    }
}
";
 
            string expectedOutput = @"";
            string expectedIL = @"
{
  // Code size       25 (0x19)
  .maxstack  3
  .locals init (int V_0, //x
  int V_1) //y
  IL_0000:  ldc.i4.0
  IL_0001:  stloc.0
  IL_0002:  ldc.i4.0
  IL_0003:  stloc.1
  IL_0004:  ldc.i4.1
  IL_0005:  ldloc.0
  IL_0006:  ldc.i4.1
  IL_0007:  add
  IL_0008:  stloc.0
  IL_0009:  ldloc.1
  IL_000a:  ldc.i4.1
  IL_000b:  add
  IL_000c:  stloc.1
  IL_000d:  brfalse.s  IL_0014
  IL_000f:  ldloc.0
  IL_0010:  ldc.i4.1
  IL_0011:  add
  IL_0012:  stloc.0
  IL_0013:  ret
  IL_0014:  ldloc.1
  IL_0015:  ldc.i4.1
  IL_0016:  add
  IL_0017:  stloc.1
  IL_0018:  ret
}";
            CompileAndVerify(source, expectedOutput: expectedOutput).VerifyIL("Class1.Main", expectedIL);
        }
 
        [Fact(), WorkItem(638289, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/638289")]
        public void TestNestedConditionalAndNullOperators()
        {
            var src =
@"using System.Security;
 
[assembly: SecurityTransparent()]
 
public interface I {}
 
class A : I {}
 
class B : I {}
 
class D : I {}
 
public class C : I
{
    static I Tester(A a)
    {
        return a ?? (a != null ? (I)new B() : new C());
    }    
    static void Main()
    {
        System.Console.Write(Tester(null).GetType());
    }
}";
            var verify = CompileAndVerify(src,
                options: TestOptions.DebugExe,
                expectedOutput: "C");
            verify.VerifyIL("C.Tester", @"
{
  // Code size       32 (0x20)
  .maxstack  2
  .locals init (I V_0,
                I V_1)
  IL_0000:  nop
  IL_0001:  ldarg.0
  IL_0002:  stloc.0
  IL_0003:  ldloc.0
  IL_0004:  dup
  IL_0005:  brtrue.s   IL_001b
  IL_0007:  pop
  IL_0008:  ldarg.0
  IL_0009:  brtrue.s   IL_0014
  IL_000b:  newobj     ""C..ctor()""
  IL_0010:  stloc.0
  IL_0011:  ldloc.0
  IL_0012:  br.s       IL_001b
  IL_0014:  newobj     ""B..ctor()""
  IL_0019:  stloc.0
  IL_001a:  ldloc.0
  IL_001b:  stloc.1
  IL_001c:  br.s       IL_001e
  IL_001e:  ldloc.1
  IL_001f:  ret
}");
            // Optimized
            verify = CompileAndVerify(src,
                expectedOutput: "C");
            verify.VerifyIL("C.Tester",
@"
{
  // Code size       26 (0x1a)
  .maxstack  2
  .locals init (I V_0)
  IL_0000:  ldarg.0
  IL_0001:  stloc.0
  IL_0002:  ldloc.0
  IL_0003:  dup
  IL_0004:  brtrue.s   IL_0019
  IL_0006:  pop
  IL_0007:  ldarg.0
  IL_0008:  brtrue.s   IL_0012
  IL_000a:  newobj     ""C..ctor()""
  IL_000f:  stloc.0
  IL_0010:  ldloc.0
  IL_0011:  ret
  IL_0012:  newobj     ""B..ctor()""
  IL_0017:  stloc.0
  IL_0018:  ldloc.0
  IL_0019:  ret
}");
        }
 
        [Fact(), WorkItem(543609, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/543609")]
        public void UnreachableLabelInUnreachableCode()
        {
            var source = @"
class Class1
{
    static void Main()
    {
        var local = ""hi"";
 
        if (true)
        {       
        } 
        else
        {        
            goto unreachable;    // this is not emitted
        }
 
        goto reachable;
 
        // stack for this block == 1 because of stacklocal
        System.Console.WriteLine(""unreachable"");
 
        // label to which we have not seen branches yet
        unreachable:    
 
            System.Console.WriteLine(""hello"");
 
        reachable:
        System.Console.WriteLine(local);
    }
}
    ";
 
            string expectedOutput = @"hi";
            string expectedIL = @"
{
  // Code size       11 (0xb)
  .maxstack  2
  IL_0000:  ldstr      ""hi""
  IL_0005:  call       ""void System.Console.WriteLine(string)""
  IL_000a:  ret
}
";
            CompileAndVerify(source, expectedOutput: expectedOutput).VerifyIL("Class1.Main", expectedIL);
        }
 
        [Fact, WorkItem(12439, "https://github.com/dotnet/roslyn/issues/12439")]
        public void GenericStructInLambda()
        {
            var source = @"
using System;
 
static class LiveList
{
    struct WhereInfo<TSource>
    {
        public int Key { get; set; }
    }
 
    static void Where<TSource>()
    {
        Action subscribe = () =>
        {
            WhereInfo<TSource>? previous = null;
 
            var previousKey = previous?.Key;
        };
    }
}";
 
            CompileAndVerify(source);
        }
 
        [Fact, WorkItem(12439, "https://github.com/dotnet/roslyn/issues/12439")]
        public void GenericStructInIterator()
        {
            var source = @"
using System;
using System.Collections.Generic;
 
static class LiveList
{
    struct WhereInfo<TSource>
    {
        public int Key { get; set; }
    }
 
    static IEnumerable<int> Where<TSource>()
    {
        WhereInfo<TSource>? previous = null;
 
        var previousKey = previous?.Key;
 
        yield break;
    }
}";
 
            CompileAndVerify(source);
        }
 
        [Fact, WorkItem(17756, "https://github.com/dotnet/roslyn/issues/17756")]
        public void TestConditionalOperatorNotLvalue()
        {
            var source = @"
    class Program
    {
 
        interface IIncrementable
        {
            int Increment();
        }
 
        struct S1: IIncrementable
        {
            public int field;
            public int Increment() => field++;
        }
 
        static void Main()
        {
            S1 v = default(S1);
            v.Increment();
 
            (true ? v : default(S1)).Increment();
 
            System.Console.WriteLine(v.field);
 
            System.Console.WriteLine((false ? default(S1): v).Increment());
 
            System.Console.WriteLine(v.field);
 
            Test(ref v);
            System.Console.WriteLine(v.field);
        }
 
        static void Test<T>(ref T arg) where T:IIncrementable
        {
            (true ? arg : default(T)).Increment();
        }
    }
";
            string expectedOutput = @"1
1
1
1";
            CompileAndVerify(source, expectedOutput: expectedOutput);
        }
 
        [Fact, WorkItem(17756, "https://github.com/dotnet/roslyn/issues/17756")]
        public void TestConditionalOperatorNotLvaluePointerElementAccess()
        {
            var source = @"
class Program
{
 
    struct S1 
    {
        public int field;
        public int Increment() => field++;
 
    }
 
    unsafe static void Main()
    {
        S1 v = default(S1);
        v.Increment();
 
        System.Console.WriteLine(v.field);
 
        S1* pv = &v;
 
        (true ? pv[0] : default(S1)).Increment();
 
        System.Console.WriteLine(v.field);
    }
}
";
            string expectedOutput = @"1
1";
            CompileAndVerify(source, expectedOutput: expectedOutput, options: TestOptions.UnsafeReleaseExe, verify: Verification.Fails);
        }
 
        [Fact, WorkItem(17756, "https://github.com/dotnet/roslyn/issues/17756")]
        public void TestConditionalOperatorNotLvalueRefCall()
        {
            var source = @"
class Program
{
 
    struct S1 
    {
        public int field;
        public int Increment() => field++;
    }
 
    private static S1 sv;
 
    private static ref S1 M1()
    {
        return ref sv;
    }
 
    static void Main()
    {
        sv.Increment();
 
        System.Console.WriteLine(sv.field);
 
        (true ? M1() : default(S1)).Increment();
 
        System.Console.WriteLine(sv.field);
    }
}
";
            string expectedOutput = @"1
1";
            CompileAndVerify(source, expectedOutput: expectedOutput);
        }
 
        [Fact]
        public void RefReadonlyConditional()
        {
            var comp = CompileAndVerify(@"
using System;
 
struct S
{
    public int X;
    public S(int x) => X = x;
 
    public void Mutate() => X++;
}
 
class C
{
    static void Main()
    {
        S local1 = new S(0);
        S local2 = new S(0);
        Console.WriteLine(local1.X);
        Console.WriteLine(local2.X);
 
        bool condition = false;
 
        (condition ? ref local1 : ref local2).Mutate();
        Console.WriteLine(local1.X);
        Console.WriteLine(local2.X);
 
        (condition ? ref local1 : ref local2).X = 0;
        Console.WriteLine(local1.X);
        Console.WriteLine(local2.X);
 
        ref readonly S ro1 = ref local1;
        ref readonly S ro2 = ref local2;
 
        (condition ? ref local1 : ref ro2).Mutate();
        Console.WriteLine(local1.X);
        Console.WriteLine(local2.X);
 
        (condition ? ref ro1 : ref local2).Mutate();
        Console.WriteLine(local1.X);
        Console.WriteLine(local2.X);
 
        (!condition ? ref local1 : ref ro2).Mutate();
        Console.WriteLine(local1.X);
        Console.WriteLine(local2.X);
 
        (!condition ? ref ro1 : ref local2).Mutate();
        Console.WriteLine(local1.X);
        Console.WriteLine(local2.X);
    }
}", expectedOutput: @"0
0
0
1
0
0
0
0
0
0
0
0
0
0");
            comp.VerifyIL("C.Main", @"
{
  // Code size      290 (0x122)
  .maxstack  3
  .locals init (S V_0, //local1
                S V_1, //local2
                S& V_2, //ro1
                S& V_3, //ro2
                S V_4)
  IL_0000:  ldloca.s   V_0
  IL_0002:  ldc.i4.0
  IL_0003:  call       ""S..ctor(int)""
  IL_0008:  ldloca.s   V_1
  IL_000a:  ldc.i4.0
  IL_000b:  call       ""S..ctor(int)""
  IL_0010:  ldloc.0
  IL_0011:  ldfld      ""int S.X""
  IL_0016:  call       ""void System.Console.WriteLine(int)""
  IL_001b:  ldloc.1
  IL_001c:  ldfld      ""int S.X""
  IL_0021:  call       ""void System.Console.WriteLine(int)""
  IL_0026:  ldc.i4.0
  IL_0027:  dup
  IL_0028:  brtrue.s   IL_002e
  IL_002a:  ldloca.s   V_1
  IL_002c:  br.s       IL_0030
  IL_002e:  ldloca.s   V_0
  IL_0030:  call       ""void S.Mutate()""
  IL_0035:  ldloc.0
  IL_0036:  ldfld      ""int S.X""
  IL_003b:  call       ""void System.Console.WriteLine(int)""
  IL_0040:  ldloc.1
  IL_0041:  ldfld      ""int S.X""
  IL_0046:  call       ""void System.Console.WriteLine(int)""
  IL_004b:  dup
  IL_004c:  brtrue.s   IL_0052
  IL_004e:  ldloca.s   V_1
  IL_0050:  br.s       IL_0054
  IL_0052:  ldloca.s   V_0
  IL_0054:  ldc.i4.0
  IL_0055:  stfld      ""int S.X""
  IL_005a:  ldloc.0
  IL_005b:  ldfld      ""int S.X""
  IL_0060:  call       ""void System.Console.WriteLine(int)""
  IL_0065:  ldloc.1
  IL_0066:  ldfld      ""int S.X""
  IL_006b:  call       ""void System.Console.WriteLine(int)""
  IL_0070:  ldloca.s   V_0
  IL_0072:  stloc.2
  IL_0073:  ldloca.s   V_1
  IL_0075:  stloc.3
  IL_0076:  dup
  IL_0077:  brtrue.s   IL_0081
  IL_0079:  ldloc.3
  IL_007a:  ldobj      ""S""
  IL_007f:  br.s       IL_0082
  IL_0081:  ldloc.0
  IL_0082:  stloc.s    V_4
  IL_0084:  ldloca.s   V_4
  IL_0086:  call       ""void S.Mutate()""
  IL_008b:  ldloc.0
  IL_008c:  ldfld      ""int S.X""
  IL_0091:  call       ""void System.Console.WriteLine(int)""
  IL_0096:  ldloc.1
  IL_0097:  ldfld      ""int S.X""
  IL_009c:  call       ""void System.Console.WriteLine(int)""
  IL_00a1:  dup
  IL_00a2:  brtrue.s   IL_00a7
  IL_00a4:  ldloc.1
  IL_00a5:  br.s       IL_00ad
  IL_00a7:  ldloc.2
  IL_00a8:  ldobj      ""S""
  IL_00ad:  stloc.s    V_4
  IL_00af:  ldloca.s   V_4
  IL_00b1:  call       ""void S.Mutate()""
  IL_00b6:  ldloc.0
  IL_00b7:  ldfld      ""int S.X""
  IL_00bc:  call       ""void System.Console.WriteLine(int)""
  IL_00c1:  ldloc.1
  IL_00c2:  ldfld      ""int S.X""
  IL_00c7:  call       ""void System.Console.WriteLine(int)""
  IL_00cc:  dup
  IL_00cd:  brfalse.s  IL_00d7
  IL_00cf:  ldloc.3
  IL_00d0:  ldobj      ""S""
  IL_00d5:  br.s       IL_00d8
  IL_00d7:  ldloc.0
  IL_00d8:  stloc.s    V_4
  IL_00da:  ldloca.s   V_4
  IL_00dc:  call       ""void S.Mutate()""
  IL_00e1:  ldloc.0
  IL_00e2:  ldfld      ""int S.X""
  IL_00e7:  call       ""void System.Console.WriteLine(int)""
  IL_00ec:  ldloc.1
  IL_00ed:  ldfld      ""int S.X""
  IL_00f2:  call       ""void System.Console.WriteLine(int)""
  IL_00f7:  brfalse.s  IL_00fc
  IL_00f9:  ldloc.1
  IL_00fa:  br.s       IL_0102
  IL_00fc:  ldloc.2
  IL_00fd:  ldobj      ""S""
  IL_0102:  stloc.s    V_4
  IL_0104:  ldloca.s   V_4
  IL_0106:  call       ""void S.Mutate()""
  IL_010b:  ldloc.0
  IL_010c:  ldfld      ""int S.X""
  IL_0111:  call       ""void System.Console.WriteLine(int)""
  IL_0116:  ldloc.1
  IL_0117:  ldfld      ""int S.X""
  IL_011c:  call       ""void System.Console.WriteLine(int)""
  IL_0121:  ret
}");
        }
 
        [Fact]
        public void RefConditionalOperatorInValConditional()
        {
            var source = @"
using System;
 
class Program
{
    static void Main()
    {
        S1 local1 = 1;
        S1 local2 = 2;
 
        bool condition = false;
 
        (condition ? 
            condition ? ref local1 : ref local2 : 
            condition ? ref local1 : ref local2).Mutate();
 
        // must print '2', the above mutation is applied to an rvalue.
        System.Console.WriteLine(local2.field);
 
        (false ? 
            condition ? ref local1 : ref local2 : 
            condition ? ref local1 : ref local2).Mutate();
 
        // must print '2', the above mutation is applied to an rvalue.
        System.Console.WriteLine(local2.field);
 
        (false ? 
            false ? ref local1 : ref local2 : 
            false ? ref local1 : ref local2).Mutate();
 
        // must print '2', the above mutation is applied to an rvalue.
        System.Console.WriteLine(local2.field);
    }
 
    struct S1
    {
        public int field;
 
        public static implicit operator S1(int arg) => new S1 {field = arg };
 
        public void Mutate()
        {
            field = 42;
        }
    }
 
}
";
            string expectedOutput = @"2
2
2";
            var verify = CompileAndVerify(source, expectedOutput: expectedOutput);
 
            verify.VerifyIL("Program.Main",
@"
{
  // Code size      101 (0x65)
  .maxstack  1
  .locals init (Program.S1 V_0, //local1
                Program.S1 V_1, //local2
                bool V_2, //condition
                Program.S1 V_3)
  IL_0000:  ldc.i4.1
  IL_0001:  call       ""Program.S1 Program.S1.op_Implicit(int)""
  IL_0006:  stloc.0
  IL_0007:  ldc.i4.2
  IL_0008:  call       ""Program.S1 Program.S1.op_Implicit(int)""
  IL_000d:  stloc.1
  IL_000e:  ldc.i4.0
  IL_000f:  stloc.2
  IL_0010:  ldloc.2
  IL_0011:  brtrue.s   IL_001c
  IL_0013:  ldloc.2
  IL_0014:  brtrue.s   IL_0019
  IL_0016:  ldloc.1
  IL_0017:  br.s       IL_0023
  IL_0019:  ldloc.0
  IL_001a:  br.s       IL_0023
  IL_001c:  ldloc.2
  IL_001d:  brtrue.s   IL_0022
  IL_001f:  ldloc.1
  IL_0020:  br.s       IL_0023
  IL_0022:  ldloc.0
  IL_0023:  stloc.3
  IL_0024:  ldloca.s   V_3
  IL_0026:  call       ""void Program.S1.Mutate()""
  IL_002b:  ldloc.1
  IL_002c:  ldfld      ""int Program.S1.field""
  IL_0031:  call       ""void System.Console.WriteLine(int)""
  IL_0036:  ldloc.2
  IL_0037:  brtrue.s   IL_003c
  IL_0039:  ldloc.1
  IL_003a:  br.s       IL_003d
  IL_003c:  ldloc.0
  IL_003d:  stloc.3
  IL_003e:  ldloca.s   V_3
  IL_0040:  call       ""void Program.S1.Mutate()""
  IL_0045:  ldloc.1
  IL_0046:  ldfld      ""int Program.S1.field""
  IL_004b:  call       ""void System.Console.WriteLine(int)""
  IL_0050:  ldloc.1
  IL_0051:  stloc.3
  IL_0052:  ldloca.s   V_3
  IL_0054:  call       ""void Program.S1.Mutate()""
  IL_0059:  ldloc.1
  IL_005a:  ldfld      ""int Program.S1.field""
  IL_005f:  call       ""void System.Console.WriteLine(int)""
  IL_0064:  ret
}");
        }
 
        [Fact]
        [WorkItem(3519, "https://github.com/dotnet/roslyn/issues/35319")]
        public void ConditionalAccessUnconstrainedTField()
        {
            var source = @"using System;
public class C<T>
{
    public C(T t) => this.t = t;
    public C(){}
 
    private T t;
 
    public void Print()
    {
        Console.WriteLine(t?.ToString());
        Console.WriteLine(t);
    }
 
}
 
public struct S
{
    int a;
    public override string ToString() => a++.ToString();
}
 
public static class Program
{
    public static void Main()
    {
        new C<S>().Print();
        new C<S?>().Print();
        new C<S?>(new S()).Print();
        new C<string>(""hello"").Print();
        new C<string>().Print();
    }
}";
            var verify = CompileAndVerify(source, expectedOutput: @"0
1
 
 
0
0
hello
hello");
 
            verify.VerifyIL("C<T>.Print()", @"
{
  // Code size       75 (0x4b)
  .maxstack  2
  .locals init (T V_0)
  IL_0000:  ldarg.0
  IL_0001:  ldflda     ""T C<T>.t""
  IL_0006:  ldloca.s   V_0
  IL_0008:  initobj    ""T""
  IL_000e:  ldloc.0
  IL_000f:  box        ""T""
  IL_0014:  brtrue.s   IL_002a
  IL_0016:  ldobj      ""T""
  IL_001b:  stloc.0
  IL_001c:  ldloca.s   V_0
  IL_001e:  ldloc.0
  IL_001f:  box        ""T""
  IL_0024:  brtrue.s   IL_002a
  IL_0026:  pop
  IL_0027:  ldnull
  IL_0028:  br.s       IL_0035
  IL_002a:  constrained. ""T""
  IL_0030:  callvirt   ""string object.ToString()""
  IL_0035:  call       ""void System.Console.WriteLine(string)""
  IL_003a:  ldarg.0
  IL_003b:  ldfld      ""T C<T>.t""
  IL_0040:  box        ""T""
  IL_0045:  call       ""void System.Console.WriteLine(object)""
  IL_004a:  ret
}");
 
        }
 
        [Fact]
        [WorkItem(3519, "https://github.com/dotnet/roslyn/issues/35319")]
        public void ConditionalAccessReadonlyUnconstrainedTField()
        {
            var source = @"using System;
public class C<T>
{
    public C(T t) => this.t = t;
    public C(){}
 
    readonly T t;
 
    public void Print()
    {
        Console.WriteLine(t?.ToString());
        Console.WriteLine(t);
    }
}
 
public struct S
{
    int a;
    public override string ToString() => a++.ToString();
}
 
public static class Program
{
    public static void Main()
    {
        new C<S>().Print();
        new C<S?>().Print();
        new C<S?>(new S()).Print();
        new C<string>(""hello"").Print();
        new C<string>().Print();
    }
}
";
            var verify = CompileAndVerify(source, expectedOutput: @"0
0
 
 
0
0
hello
hello");
 
            verify.VerifyIL("C<T>.Print()", @"
{
  // Code size       59 (0x3b)
  .maxstack  2
  .locals init (T V_0)
  IL_0000:  ldarg.0
  IL_0001:  ldfld      ""T C<T>.t""
  IL_0006:  stloc.0
  IL_0007:  ldloca.s   V_0
  IL_0009:  dup
  IL_000a:  ldobj      ""T""
  IL_000f:  box        ""T""
  IL_0014:  brtrue.s   IL_001a
  IL_0016:  pop
  IL_0017:  ldnull
  IL_0018:  br.s       IL_0025
  IL_001a:  constrained. ""T""
  IL_0020:  callvirt   ""string object.ToString()""
  IL_0025:  call       ""void System.Console.WriteLine(string)""
  IL_002a:  ldarg.0
  IL_002b:  ldfld      ""T C<T>.t""
  IL_0030:  box        ""T""
  IL_0035:  call       ""void System.Console.WriteLine(object)""
  IL_003a:  ret
}");
 
        }
 
        [Fact]
        [WorkItem(3519, "https://github.com/dotnet/roslyn/issues/35319")]
        public void ConditionalAccessUnconstrainedTLocal()
        {
            var source = @"using System;
public class C<T>
{
    public C(T t) => this.t = t;
    public C(){}
 
    private T t;
 
    public void Print()
    {
        var temp = t;
        Console.WriteLine(temp?.ToString());
        Console.WriteLine(temp);
    }
 
}
 
public struct S
{
    int a;
    public override string ToString() => a++.ToString();
}
 
public static class Program
{
    public static void Main()
    {
        new C<S>().Print();
        new C<S?>().Print();
        new C<S?>(new S()).Print();
        new C<string>(""hello"").Print();
        new C<string>().Print();
    }
}";
            var verify = CompileAndVerify(source, expectedOutput: @"0
1
 
 
0
0
hello
hello");
 
            verify.VerifyIL("C<T>.Print()", @"
{
  // Code size       73 (0x49)
  .maxstack  2
  .locals init (T V_0, //temp
                T V_1)
  IL_0000:  ldarg.0
  IL_0001:  ldfld      ""T C<T>.t""
  IL_0006:  stloc.0
  IL_0007:  ldloca.s   V_0
  IL_0009:  ldloca.s   V_1
  IL_000b:  initobj    ""T""
  IL_0011:  ldloc.1
  IL_0012:  box        ""T""
  IL_0017:  brtrue.s   IL_002d
  IL_0019:  ldobj      ""T""
  IL_001e:  stloc.1
  IL_001f:  ldloca.s   V_1
  IL_0021:  ldloc.1
  IL_0022:  box        ""T""
  IL_0027:  brtrue.s   IL_002d
  IL_0029:  pop
  IL_002a:  ldnull
  IL_002b:  br.s       IL_0038
  IL_002d:  constrained. ""T""
  IL_0033:  callvirt   ""string object.ToString()""
  IL_0038:  call       ""void System.Console.WriteLine(string)""
  IL_003d:  ldloc.0
  IL_003e:  box        ""T""
  IL_0043:  call       ""void System.Console.WriteLine(object)""
  IL_0048:  ret
}");
 
        }
 
        [Fact]
        [WorkItem(3519, "https://github.com/dotnet/roslyn/issues/35319")]
        public void ConditionalAccessUnconstrainedTTemp()
        {
            var source = @"using System;
public class C<T>
{
    public C(T t) => this.t = t;
    public C(){}
 
    T t;
 
    T M() => t;
 
    public void Print() => Console.WriteLine(M()?.ToString());
}
 
public static class Program
{
    public static void Main()
    {
        new C<int>().Print();
        new C<int?>().Print();
        new C<int?>(0).Print();
        new C<string>(""hello"").Print();
        new C<string>().Print();
    }
}
";
            var verify = CompileAndVerify(source, expectedOutput: @"0
 
0
hello
");
 
            verify.VerifyIL("C<T>.Print()", @"
{
  // Code size       43 (0x2b)
  .maxstack  2
  .locals init (T V_0)
  IL_0000:  ldarg.0
  IL_0001:  call       ""T C<T>.M()""
  IL_0006:  stloc.0
  IL_0007:  ldloca.s   V_0
  IL_0009:  dup
  IL_000a:  ldobj      ""T""
  IL_000f:  box        ""T""
  IL_0014:  brtrue.s   IL_001a
  IL_0016:  pop
  IL_0017:  ldnull
  IL_0018:  br.s       IL_0025
  IL_001a:  constrained. ""T""
  IL_0020:  callvirt   ""string object.ToString()""
  IL_0025:  call       ""void System.Console.WriteLine(string)""
  IL_002a:  ret
}");
 
        }
 
        [Fact, WorkItem(40690, "https://github.com/dotnet/roslyn/issues/40690")]
        public void ConditionalAccess_GenericExtension_ValueTuple()
        {
            var source = @"
using System;
 
public static class Extension
{
    public static string GetValue(this object value) => value?.ToString();
}
public class Class<T>
{
    public (long, T) Data { get; }
    public Class((long, T) data)
    {
        Data = data;
    }
    internal string Value
    {
        get
        {
            var q2 = Data.Item2?.GetValue();
            return q2;
        }
    }
}
class Program
{
    static void Main(string[] args)
    {
        Console.WriteLine(new Class<string>((0, ""abc"")).Value);
        Console.WriteLine(new Class<string>((0, null)).Value);
        Console.WriteLine(new Class<int>((0, 0)).Value);
        Console.WriteLine(new Class<int?>((0, 0)).Value);
        Console.WriteLine(new Class<int?>((0, null)).Value);
    }
}";
            var verifier = CompileAndVerify(source, expectedOutput: @"abc
 
0
0
");
            verifier.VerifyIL("Class<T>.Value.get", @"
{
  // Code size       46 (0x2e)
  .maxstack  2
  .locals init (System.ValueTuple<long, T> V_0)
  IL_0000:  ldarg.0
  IL_0001:  call       ""System.ValueTuple<long, T> Class<T>.Data.get""
  IL_0006:  stloc.0
  IL_0007:  ldloca.s   V_0
  IL_0009:  ldflda     ""T System.ValueTuple<long, T>.Item2""
  IL_000e:  dup
  IL_000f:  ldobj      ""T""
  IL_0014:  box        ""T""
  IL_0019:  brtrue.s   IL_001e
  IL_001b:  pop
  IL_001c:  ldnull
  IL_001d:  ret
  IL_001e:  ldobj      ""T""
  IL_0023:  box        ""T""
  IL_0028:  call       ""string Extension.GetValue(object)""
  IL_002d:  ret
}");
        }
 
        [Fact, WorkItem(40690, "https://github.com/dotnet/roslyn/issues/40690")]
        public void ConditionalAccess_InstanceMethod_ValueTuple()
        {
            var source = @"
using System;
 
public class Class<T>
{
    public (long, T) Data { get; }
    public Class((long, T) data)
    {
        Data = data;
    }
    internal string Value
    {
        get
        {
            var q2 = Data.Item2?.ToString();
            return q2;
        }
    }
}
class Program
{
    static void Main(string[] args)
    {
        Console.WriteLine(new Class<string>((0, ""abc"")).Value);
        Console.WriteLine(new Class<string>((0, null)).Value);
        Console.WriteLine(new Class<int>((0, 0)).Value);
        Console.WriteLine(new Class<int?>((0, 0)).Value);
        Console.WriteLine(new Class<int?>((0, null)).Value);
    }
}";
            var verifier = CompileAndVerify(source, expectedOutput: @"abc
 
0
0
");
            verifier.VerifyIL("Class<T>.Value.get", @"
{
  // Code size       42 (0x2a)
  .maxstack  2
  .locals init (System.ValueTuple<long, T> V_0)
  IL_0000:  ldarg.0
  IL_0001:  call       ""System.ValueTuple<long, T> Class<T>.Data.get""
  IL_0006:  stloc.0
  IL_0007:  ldloca.s   V_0
  IL_0009:  ldflda     ""T System.ValueTuple<long, T>.Item2""
  IL_000e:  dup
  IL_000f:  ldobj      ""T""
  IL_0014:  box        ""T""
  IL_0019:  brtrue.s   IL_001e
  IL_001b:  pop
  IL_001c:  ldnull
  IL_001d:  ret
  IL_001e:  constrained. ""T""
  IL_0024:  callvirt   ""string object.ToString()""
  IL_0029:  ret
}");
        }
 
        [Fact, WorkItem(66152, "https://github.com/dotnet/roslyn/issues/66152")]
        public void NullableSideEffects_01()
        {
            var source = @"
struct S1
{
    private int count;
    public override string ToString()
    {
        return (++count).ToString();
    }
}
 
class Program
{
    static void Main()
    {
        var x1 = new S1?(new S1());
        System.Console.Write(Test1(ref x1));
        System.Console.Write(x1.ToString());
        x1 = null;
        System.Console.Write(Test1(ref x1) is null);
    }
 
    static string Test1<T>(ref T x)
    {
        return x?.ToString(); 
    }
}
";
            var verifier = CompileAndVerify(source, expectedOutput: "11True").VerifyDiagnostics();
            verifier.VerifyIL("Program.Test1<T>(ref T)", @"
{
  // Code size       48 (0x30)
  .maxstack  2
  .locals init (T V_0)
  IL_0000:  ldarg.0
  IL_0001:  ldloca.s   V_0
  IL_0003:  initobj    ""T""
  IL_0009:  ldloc.0
  IL_000a:  box        ""T""
  IL_000f:  brtrue.s   IL_0024
  IL_0011:  ldobj      ""T""
  IL_0016:  stloc.0
  IL_0017:  ldloca.s   V_0
  IL_0019:  ldloc.0
  IL_001a:  box        ""T""
  IL_001f:  brtrue.s   IL_0024
  IL_0021:  pop
  IL_0022:  ldnull
  IL_0023:  ret
  IL_0024:  constrained. ""T""
  IL_002a:  callvirt   ""string object.ToString()""
  IL_002f:  ret
}
");
        }
 
        [Fact, WorkItem(66152, "https://github.com/dotnet/roslyn/issues/66152")]
        public void NullableSideEffects_02()
        {
            var source = @"
struct S1
{
    private int count;
    public override string ToString()
    {
        return (++count).ToString();
    }
}
 
class Program
{
    static void Main()
    {
        var x1 = new S1?(new S1());
        System.Console.Write(Test1(ref x1));
        System.Console.Write(x1.ToString());
        x1 = null;
        System.Console.Write(Test1(ref x1) is null);
    }
 
    static string Test1<T>(ref T x)
    {
        var y = x;
        var result = y?.ToString(); 
        x = y;
        return result;
    }
}
";
            var verifier = CompileAndVerify(source, expectedOutput: "11True").VerifyDiagnostics();
            verifier.VerifyIL("Program.Test1<T>(ref T)", @"
{
  // Code size       64 (0x40)
  .maxstack  3
  .locals init (T V_0, //y
                T V_1)
  IL_0000:  ldarg.0
  IL_0001:  ldobj      ""T""
  IL_0006:  stloc.0
  IL_0007:  ldloca.s   V_0
  IL_0009:  ldloca.s   V_1
  IL_000b:  initobj    ""T""
  IL_0011:  ldloc.1
  IL_0012:  box        ""T""
  IL_0017:  brtrue.s   IL_002d
  IL_0019:  ldobj      ""T""
  IL_001e:  stloc.1
  IL_001f:  ldloca.s   V_1
  IL_0021:  ldloc.1
  IL_0022:  box        ""T""
  IL_0027:  brtrue.s   IL_002d
  IL_0029:  pop
  IL_002a:  ldnull
  IL_002b:  br.s       IL_0038
  IL_002d:  constrained. ""T""
  IL_0033:  callvirt   ""string object.ToString()""
  IL_0038:  ldarg.0
  IL_0039:  ldloc.0
  IL_003a:  stobj      ""T""
  IL_003f:  ret
}
");
        }
 
        [Fact, WorkItem(66152, "https://github.com/dotnet/roslyn/issues/66152")]
        public void NullableSideEffects_03()
        {
            var source = @"
struct S1
{
}
 
abstract class C0<U>
{
    public abstract string Test1<T>(ref T x) where T : U;
}
 
class C1 : C0<S1?>
{
    public override string Test1<T>(ref T x)
    {
        var y = x;
        var result = y?.ToString(); 
        x = y;
        return result;
    }
}
";
            var comp = CreateCompilation(source);
            comp.VerifyEmitDiagnostics(
                // (16,23): error CS0023: Operator '?' cannot be applied to operand of type 'T'
                //         var result = y?.ToString(); 
                Diagnostic(ErrorCode.ERR_BadUnaryOp, "?").WithArguments("?", "T").WithLocation(16, 23)
                );
        }
    }
}