File: CodeGen\CodeGenRefReturnTests.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 System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.CodeAnalysis.CSharp.Symbols;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.CSharp.Test.Utilities;
using Microsoft.CodeAnalysis.Test.Utilities;
using Roslyn.Test.Utilities;
using Xunit;
 
namespace Microsoft.CodeAnalysis.CSharp.UnitTests
{
    public class RefReturnTests : CompilingTestBase
    {
        private CompilationVerifier CompileAndVerifyRef(
            string source,
            string expectedOutput = null,
            CSharpCompilationOptions options = null,
            Verification verify = default)
        {
            return CompileAndVerify(
                source,
                expectedOutput: expectedOutput,
                options: options,
                verify: verify);
        }
 
        [Fact]
        public void RefReturnRefAssignment()
        {
            CompileAndVerify(@"
using System;
class C
{
    static readonly int _ro = 42;
    static int _rw = 42;
 
    static void Main()
    {
        Console.WriteLine(M1(ref _rw));
        Console.WriteLine(M2(in _ro));
        Console.WriteLine(M3(in _ro));;
 
        M1(ref _rw)++;
 
        Console.WriteLine(M1(ref _rw));
        Console.WriteLine(M2(in _ro));
        Console.WriteLine(M3(in _ro));;
    }
 
    static ref int M1(ref int rrw) => ref (rrw = ref _rw);
 
    static ref readonly int M2(in int rro) => ref (rro = ref _ro);
 
    static ref readonly int M3(in int rro) => ref (rro = ref _rw);
}", verify: Verification.Fails, expectedOutput: @"42
42
42
43
42
43");
        }
 
        [Fact]
        public void RefReturnArrayAccess()
        {
            var text = @"
class Program
{
    static ref int M()
    {
        return ref (new int[1])[0];
    }
}
";
 
            CompileAndVerifyRef(text).VerifyIL("Program.M()", @"
{
  // Code size       13 (0xd)
  .maxstack  2
  IL_0000:  ldc.i4.1
  IL_0001:  newarr     ""int""
  IL_0006:  ldc.i4.0
  IL_0007:  ldelema    ""int""
  IL_000c:  ret
}");
        }
 
        [Fact]
        public void RefReturnRefParameter()
        {
            var text = @"
class Program
{
    static ref int M(ref int i)
    {
        return ref i;
    }
}
";
 
            CompileAndVerifyRef(text, verify: Verification.Skipped).VerifyIL("Program.M(ref int)", @"
{
  // Code size        2 (0x2)
  .maxstack  1
  IL_0000:  ldarg.0
  IL_0001:  ret
}");
        }
 
        [Fact]
        public void RefReturnOutParameter()
        {
            var text = @"
class Program
{
    static ref int M(out int i)
    {
        i = 0;
        return ref i;
    }
}
";
 
            CompileAndVerify(text, parseOptions: TestOptions.Regular10, verify: Verification.Fails).VerifyIL("Program.M(out int)", @"
{
  // Code size        5 (0x5)
  .maxstack  2
  IL_0000:  ldarg.0
  IL_0001:  ldc.i4.0
  IL_0002:  stind.i4
  IL_0003:  ldarg.0
  IL_0004:  ret
}");
        }
 
        [Fact]
        public void RefReturnRefLocal()
        {
            var text = @"
class Program
{
    static ref int M(ref int i)
    {
        ref int local = ref i;
        local = 0;
        return ref local;
    }
}
";
 
            CompileAndVerifyRef(text, verify: Verification.Fails).VerifyIL("Program.M(ref int)", @"
{
  // Code size        5 (0x5)
  .maxstack  3
  IL_0000:  ldarg.0
  IL_0001:  dup
  IL_0002:  ldc.i4.0
  IL_0003:  stind.i4
  IL_0004:  ret
}");
        }
 
        [Fact]
        public void RefReturnStaticProperty()
        {
            var text = @"
class Program
{
    static int field = 0;
    static ref int P { get { return ref field; } }
 
    static ref int M()
    {
        return ref P;
    }
 
    public static void Main()
    {
        var local = 42;   // must be real local
        P = local;
        P = local;  // assign again, should not use stack local
        System.Console.WriteLine(P);
    }
}
";
 
            var v = CompileAndVerifyRef(text, expectedOutput: "42");
 
            v.VerifyIL("Program.M()", @"
{
  // Code size        6 (0x6)
  .maxstack  1
  IL_0000:  call       ""ref int Program.P.get""
  IL_0005:  ret
}");
 
            v.VerifyIL("Program.Main()", @"
{
  // Code size       29 (0x1d)
  .maxstack  2
  .locals init (int V_0) //local
  IL_0000:  ldc.i4.s   42
  IL_0002:  stloc.0
  IL_0003:  call       ""ref int Program.P.get""
  IL_0008:  ldloc.0
  IL_0009:  stind.i4
  IL_000a:  call       ""ref int Program.P.get""
  IL_000f:  ldloc.0
  IL_0010:  stind.i4
  IL_0011:  call       ""ref int Program.P.get""
  IL_0016:  ldind.i4
  IL_0017:  call       ""void System.Console.WriteLine(int)""
  IL_001c:  ret
}");
 
        }
 
        [Fact]
        public void RefReturnClassInstanceProperty()
        {
            var text = @"
class Program
{
    int field = 0;
    ref int P { get { return ref field; } }
 
    ref int M()
    {
        return ref P;
    }
 
    ref int M1()
    {
        return ref new Program().P;
    }
}
";
 
            var compilation = CompileAndVerifyRef(text);
            compilation.VerifyIL("Program.M()", @"
{
  // Code size        7 (0x7)
  .maxstack  1
  IL_0000:  ldarg.0
  IL_0001:  call       ""ref int Program.P.get""
  IL_0006:  ret
}");
            compilation.VerifyIL("Program.M1()", @"
{
  // Code size       11 (0xb)
  .maxstack  1
  IL_0000:  newobj     ""Program..ctor()""
  IL_0005:  call       ""ref int Program.P.get""
  IL_000a:  ret
}");
        }
 
        [Fact]
        public void RefReturnStructInstanceProperty()
        {
            var text = @"
struct Program
{
    public ref int P { get { return ref (new int[1])[0]; } }
 
    ref int M()
    {
        return ref P;
    }
 
    ref int M1(ref Program program)
    {
        return ref program.P;
    }
}
 
struct Program2
{
    Program program;
 
    Program2(Program program)
    {
        this.program = program;
    }
 
    ref int M()
    {
        return ref program.P;
    }
}
 
class Program3
{
    Program program = default(Program);
 
    ref int M()
    {
        return ref program.P;
    }
}
";
 
            var compilation = CompileAndVerifyRef(text, verify: Verification.Passes);
            compilation.VerifyIL("Program.M()", @"
{
  // Code size        7 (0x7)
  .maxstack  1
  IL_0000:  ldarg.0
  IL_0001:  call       ""ref int Program.P.get""
  IL_0006:  ret
}");
            compilation.VerifyIL("Program.M1(ref Program)", @"
{
  // Code size        7 (0x7)
  .maxstack  1
  IL_0000:  ldarg.1
  IL_0001:  call       ""ref int Program.P.get""
  IL_0006:  ret
}");
            compilation.VerifyIL("Program2.M()", @"
{
  // Code size       12 (0xc)
  .maxstack  1
  IL_0000:  ldarg.0
  IL_0001:  ldflda     ""Program Program2.program""
  IL_0006:  call       ""ref int Program.P.get""
  IL_000b:  ret
}");
            compilation.VerifyIL("Program3.M()", @"
{
  // Code size       12 (0xc)
  .maxstack  1
  IL_0000:  ldarg.0
  IL_0001:  ldflda     ""Program Program3.program""
  IL_0006:  call       ""ref int Program.P.get""
  IL_000b:  ret
}");
        }
 
        [Fact]
        public void RefReturnConstrainedInstanceProperty()
        {
            var text = @"
interface I
{
    ref int P { get; }
}
 
class Program<T>
    where T : I
{
    T t = default(T);
 
    ref int M()
    {
        return ref t.P;
    }
}
 
class Program2<T>
    where T : class, I
{
    ref int M(T t)
    {
        return ref t.P;
    }
}
 
class Program3<T>
    where T : struct, I
{
    T t = default(T);
 
    ref int M()
    {
        return ref t.P;
    }
}
";
 
            var compilation = CompileAndVerifyRef(text);
            compilation.VerifyIL("Program<T>.M()", @"
{
  // Code size       18 (0x12)
  .maxstack  1
  IL_0000:  ldarg.0
  IL_0001:  ldflda     ""T Program<T>.t""
  IL_0006:  constrained. ""T""
  IL_000c:  callvirt   ""ref int I.P.get""
  IL_0011:  ret
}");
            compilation.VerifyIL("Program2<T>.M(T)", @"
{
  // Code size       12 (0xc)
  .maxstack  1
  IL_0000:  ldarg.1
  IL_0001:  box        ""T""
  IL_0006:  callvirt   ""ref int I.P.get""
  IL_000b:  ret
}");
            compilation.VerifyIL("Program3<T>.M()", @"
{
  // Code size       18 (0x12)
  .maxstack  1
  IL_0000:  ldarg.0
  IL_0001:  ldflda     ""T Program3<T>.t""
  IL_0006:  constrained. ""T""
  IL_000c:  callvirt   ""ref int I.P.get""
  IL_0011:  ret
}");
        }
 
        [Fact]
        public void RefReturnClassInstanceIndexer()
        {
            var text = @"
class Program
{
    int field = 0;
    ref int this[int i] { get { return ref field; } }
 
    ref int M()
    {
        return ref this[0];
    }
 
    ref int M1()
    {
        return ref new Program()[0];
    }
}
";
 
            var compilation = CompileAndVerifyRef(text);
            compilation.VerifyIL("Program.M()", @"
{
  // Code size        8 (0x8)
  .maxstack  2
  IL_0000:  ldarg.0
  IL_0001:  ldc.i4.0
  IL_0002:  call       ""ref int Program.this[int].get""
  IL_0007:  ret
}");
            compilation.VerifyIL("Program.M1()", @"
{
  // Code size       12 (0xc)
  .maxstack  2
  IL_0000:  newobj     ""Program..ctor()""
  IL_0005:  ldc.i4.0
  IL_0006:  call       ""ref int Program.this[int].get""
  IL_000b:  ret
}");
        }
 
        [Fact]
        public void RefReturnStructInstanceIndexer()
        {
            var text = @"
struct Program
{
    public ref int this[int i] { get { return ref (new int[1])[0]; } }
 
    ref int M()
    {
        return ref this[0];
    }
}
 
struct Program2
{
    Program program;
 
    Program2(Program program)
    {
        this.program = program;
    }
 
    ref int M()
    {
        return ref program[0];
    }
}
 
class Program3
{
    Program program = default(Program);
 
    ref int M()
    {
        return ref program[0];
    }
}
";
 
            var compilation = CompileAndVerifyRef(text, verify: Verification.Passes);
            compilation.VerifyIL("Program.M()", @"
{
  // Code size        8 (0x8)
  .maxstack  2
  IL_0000:  ldarg.0
  IL_0001:  ldc.i4.0
  IL_0002:  call       ""ref int Program.this[int].get""
  IL_0007:  ret
}");
            compilation.VerifyIL("Program2.M()", @"
{
  // Code size       13 (0xd)
  .maxstack  2
  IL_0000:  ldarg.0
  IL_0001:  ldflda     ""Program Program2.program""
  IL_0006:  ldc.i4.0
  IL_0007:  call       ""ref int Program.this[int].get""
  IL_000c:  ret
}");
            compilation.VerifyIL("Program3.M()", @"
{
  // Code size       13 (0xd)
  .maxstack  2
  IL_0000:  ldarg.0
  IL_0001:  ldflda     ""Program Program3.program""
  IL_0006:  ldc.i4.0
  IL_0007:  call       ""ref int Program.this[int].get""
  IL_000c:  ret
}");
        }
 
        [Fact]
        public void RefReturnConstrainedInstanceIndexer()
        {
            var text = @"
interface I
{
    ref int this[int i] { get; }
}
 
class Program<T>
    where T : I
{
    T t = default(T);
 
    ref int M()
    {
        return ref t[0];
    }
}
 
class Program2<T>
    where T : class, I
{
    ref int M(T t)
    {
        return ref t[0];
    }
}
 
class Program3<T>
    where T : struct, I
{
    T t = default(T);
 
    ref int M()
    {
        return ref t[0];
    }
}
";
 
            var compilation = CompileAndVerifyRef(text);
            compilation.VerifyIL("Program<T>.M()", @"
{
  // Code size       19 (0x13)
  .maxstack  2
  IL_0000:  ldarg.0
  IL_0001:  ldflda     ""T Program<T>.t""
  IL_0006:  ldc.i4.0
  IL_0007:  constrained. ""T""
  IL_000d:  callvirt   ""ref int I.this[int].get""
  IL_0012:  ret
}");
            compilation.VerifyIL("Program2<T>.M(T)", @"
{
  // Code size       13 (0xd)
  .maxstack  2
  IL_0000:  ldarg.1
  IL_0001:  box        ""T""
  IL_0006:  ldc.i4.0
  IL_0007:  callvirt   ""ref int I.this[int].get""
  IL_000c:  ret
}");
            compilation.VerifyIL("Program3<T>.M()", @"
{
  // Code size       19 (0x13)
  .maxstack  2
  IL_0000:  ldarg.0
  IL_0001:  ldflda     ""T Program3<T>.t""
  IL_0006:  ldc.i4.0
  IL_0007:  constrained. ""T""
  IL_000d:  callvirt   ""ref int I.this[int].get""
  IL_0012:  ret
}");
        }
 
        [Fact]
        public void RefReturnStaticFieldLikeEvent()
        {
            var text = @"
delegate void D();
 
class Program
{
    static event D d;
 
    static ref D M()
    {
        return ref d;
    }
}
";
 
            CompileAndVerifyRef(text).VerifyIL("Program.M()", @"
{
  // Code size        6 (0x6)
  .maxstack  1
  IL_0000:  ldsflda    ""D Program.d""
  IL_0005:  ret
}");
        }
 
        [Fact]
        public void RefReturnClassInstanceFieldLikeEvent()
        {
            var text = @"
delegate void D();
 
class Program
{
    event D d;
 
    ref D M()
    {
        return ref d;
    }
 
    ref D M1()
    {
        return ref new Program().d;
    }
}
";
 
            var compilation = CompileAndVerifyRef(text);
            compilation.VerifyIL("Program.M()", @"
{
  // Code size        7 (0x7)
  .maxstack  1
  IL_0000:  ldarg.0
  IL_0001:  ldflda     ""D Program.d""
  IL_0006:  ret
}");
            compilation.VerifyIL("Program.M1()", @"
{
  // Code size       11 (0xb)
  .maxstack  1
  IL_0000:  newobj     ""Program..ctor()""
  IL_0005:  ldflda     ""D Program.d""
  IL_000a:  ret
}");
        }
 
        [Fact]
        public void RefReturnStaticField()
        {
            var text = @"
class Program
{
    static int i = 0;
 
    static ref int M()
    {
        return ref i;
    }
}
";
 
            CompileAndVerifyRef(text).VerifyIL("Program.M()", @"
{
  // Code size        6 (0x6)
  .maxstack  1
  IL_0000:  ldsflda    ""int Program.i""
  IL_0005:  ret
}");
        }
 
        [Fact]
        public void RefReturnClassInstanceField()
        {
            var text = @"
class Program
{
    int i = 0;
 
    ref int M()
    {
        return ref i;
    }
 
    ref int M1()
    {
        return ref new Program().i;
    }
}
";
 
            var compilation = CompileAndVerifyRef(text);
            compilation.VerifyIL("Program.M()", @"
{
  // Code size        7 (0x7)
  .maxstack  1
  IL_0000:  ldarg.0
  IL_0001:  ldflda     ""int Program.i""
  IL_0006:  ret
}");
            compilation.VerifyIL("Program.M1()", @"
{
  // Code size       11 (0xb)
  .maxstack  1
  IL_0000:  newobj     ""Program..ctor()""
  IL_0005:  ldflda     ""int Program.i""
  IL_000a:  ret
}");
        }
 
        [Fact]
        public void RefReturnStructInstanceField()
        {
            var text = @"
struct Program
{
    public int i;
}
 
class Program2
{
    Program program = default(Program);
 
    ref int M(ref Program program)
    {
        return ref program.i;
    }
 
    ref int M()
    {
        return ref program.i;
    }
}
";
 
            var compilation = CompileAndVerifyRef(text, verify: Verification.Fails);
            compilation.VerifyIL("Program2.M(ref Program)", @"
{
  // Code size        7 (0x7)
  .maxstack  1
  IL_0000:  ldarg.1
  IL_0001:  ldflda     ""int Program.i""
  IL_0006:  ret
}");
            compilation.VerifyIL("Program2.M()", @"
{
  // Code size       12 (0xc)
  .maxstack  1
  IL_0000:  ldarg.0
  IL_0001:  ldflda     ""Program Program2.program""
  IL_0006:  ldflda     ""int Program.i""
  IL_000b:  ret
}");
        }
 
        [Fact]
        public void RefReturnStaticCallWithoutArguments()
        {
            var text = @"
class Program
{
    static ref int M()
    {
        return ref M();
    }
}
";
 
            CompileAndVerifyRef(text).VerifyIL("Program.M()", @"
{
  // Code size        6 (0x6)
  .maxstack  1
  IL_0000:  call       ""ref int Program.M()""
  IL_0005:  ret
}");
        }
 
        [Fact]
        public void RefReturnClassInstanceCallWithoutArguments()
        {
            var text = @"
class Program
{
    ref int M()
    {
        return ref M();
    }
 
    ref int M1()
    {
        return ref new Program().M();
    }
}
";
 
            var compilation = CompileAndVerifyRef(text);
            compilation.VerifyIL("Program.M()", @"
{
  // Code size        7 (0x7)
  .maxstack  1
  IL_0000:  ldarg.0
  IL_0001:  call       ""ref int Program.M()""
  IL_0006:  ret
}");
            compilation.VerifyIL("Program.M1()", @"
{
  // Code size       11 (0xb)
  .maxstack  1
  IL_0000:  newobj     ""Program..ctor()""
  IL_0005:  call       ""ref int Program.M()""
  IL_000a:  ret
}");
        }
 
        [Fact]
        public void RefReturnStructInstanceCallWithoutArguments()
        {
            var text = @"
struct Program
{
    public ref int M()
    {
        return ref M();
    }
}
 
struct Program2
{
    Program program;
 
    ref int M()
    {
        return ref program.M();
    }
}
 
class Program3
{
    Program program;
 
    ref int M()
    {
        return ref program.M();
    }
}
";
 
            var compilation = CompileAndVerifyRef(text);
            compilation.VerifyIL("Program.M()", @"
{
  // Code size        7 (0x7)
  .maxstack  1
  IL_0000:  ldarg.0
  IL_0001:  call       ""ref int Program.M()""
  IL_0006:  ret
}");
            compilation.VerifyIL("Program2.M()", @"
{
  // Code size       12 (0xc)
  .maxstack  1
  IL_0000:  ldarg.0
  IL_0001:  ldflda     ""Program Program2.program""
  IL_0006:  call       ""ref int Program.M()""
  IL_000b:  ret
}");
            compilation.VerifyIL("Program3.M()", @"
{
  // Code size       12 (0xc)
  .maxstack  1
  IL_0000:  ldarg.0
  IL_0001:  ldflda     ""Program Program3.program""
  IL_0006:  call       ""ref int Program.M()""
  IL_000b:  ret
}");
        }
 
        [Fact]
        public void RefReturnConstrainedInstanceCallWithoutArguments()
        {
            var text = @"
interface I
{
    ref int M();
}
 
class Program<T>
    where T : I
{
    T t = default(T);
 
    ref int M()
    {
        return ref t.M();
    }
}
 
class Program2<T>
    where T : class, I
{
    ref int M(T t)
    {
        return ref t.M();
    }
}
 
class Program3<T>
    where T : struct, I
{
    T t = default(T);
 
    ref int M()
    {
        return ref t.M();
    }
}
";
 
            var compilation = CompileAndVerifyRef(text);
            compilation.VerifyIL("Program<T>.M()", @"
{
  // Code size       18 (0x12)
  .maxstack  1
  IL_0000:  ldarg.0
  IL_0001:  ldflda     ""T Program<T>.t""
  IL_0006:  constrained. ""T""
  IL_000c:  callvirt   ""ref int I.M()""
  IL_0011:  ret
}");
            compilation.VerifyIL("Program2<T>.M(T)", @"
{
  // Code size       12 (0xc)
  .maxstack  1
  IL_0000:  ldarg.1
  IL_0001:  box        ""T""
  IL_0006:  callvirt   ""ref int I.M()""
  IL_000b:  ret
}");
            compilation.VerifyIL("Program3<T>.M()", @"
{
  // Code size       18 (0x12)
  .maxstack  1
  IL_0000:  ldarg.0
  IL_0001:  ldflda     ""T Program3<T>.t""
  IL_0006:  constrained. ""T""
  IL_000c:  callvirt   ""ref int I.M()""
  IL_0011:  ret
}");
        }
 
        [Fact]
        public void RefReturnStaticCallWithArguments()
        {
            var text = @"
class Program
{
    static ref int M(ref int i, ref int j, object o)
    {
        return ref M(ref i, ref j, o);
    }
}
";
 
            CompileAndVerifyRef(text).VerifyIL("Program.M(ref int, ref int, object)", @"
{
  // Code size        9 (0x9)
  .maxstack  3
  IL_0000:  ldarg.0
  IL_0001:  ldarg.1
  IL_0002:  ldarg.2
  IL_0003:  call       ""ref int Program.M(ref int, ref int, object)""
  IL_0008:  ret
}");
        }
 
        [Fact]
        public void RefReturnClassInstanceCallWithArguments()
        {
            var text = @"
class Program
{
    ref int M(ref int i, ref int j, object o)
    {
        return ref M(ref i, ref j, o);
    }
 
    ref int M1(ref int i, ref int j, object o)
    {
        return ref new Program().M(ref i, ref j, o);
    }
}
";
 
            var compilation = CompileAndVerifyRef(text);
            compilation.VerifyIL("Program.M(ref int, ref int, object)", @"
{
  // Code size       10 (0xa)
  .maxstack  4
  IL_0000:  ldarg.0
  IL_0001:  ldarg.1
  IL_0002:  ldarg.2
  IL_0003:  ldarg.3
  IL_0004:  call       ""ref int Program.M(ref int, ref int, object)""
  IL_0009:  ret
}");
            compilation.VerifyIL("Program.M1(ref int, ref int, object)", @"
{
  // Code size       14 (0xe)
  .maxstack  4
  IL_0000:  newobj     ""Program..ctor()""
  IL_0005:  ldarg.1
  IL_0006:  ldarg.2
  IL_0007:  ldarg.3
  IL_0008:  call       ""ref int Program.M(ref int, ref int, object)""
  IL_000d:  ret
}");
        }
 
        [Fact]
        public void RefReturnStructInstanceCallWithArguments()
        {
            var text = @"
struct Program
{
    public ref int M(ref int i, ref int j, object o)
    {
        return ref M(ref i, ref j, o);
    }
}
 
struct Program2
{
    Program program;
 
    ref int M(ref int i, ref int j, object o)
    {
        return ref program.M(ref i, ref j, o);
    }
}
 
class Program3
{
    Program program;
 
    ref int M(ref int i, ref int j, object o)
    {
        return ref program.M(ref i, ref j, o);
    }
}
";
 
            var compilation = CompileAndVerifyRef(text);
            compilation.VerifyIL("Program.M(ref int, ref int, object)", @"
{
  // Code size       10 (0xa)
  .maxstack  4
  IL_0000:  ldarg.0
  IL_0001:  ldarg.1
  IL_0002:  ldarg.2
  IL_0003:  ldarg.3
  IL_0004:  call       ""ref int Program.M(ref int, ref int, object)""
  IL_0009:  ret
}");
            compilation.VerifyIL("Program2.M(ref int, ref int, object)", @"
{
  // Code size       15 (0xf)
  .maxstack  4
  IL_0000:  ldarg.0
  IL_0001:  ldflda     ""Program Program2.program""
  IL_0006:  ldarg.1
  IL_0007:  ldarg.2
  IL_0008:  ldarg.3
  IL_0009:  call       ""ref int Program.M(ref int, ref int, object)""
  IL_000e:  ret
}");
            compilation.VerifyIL("Program3.M(ref int, ref int, object)", @"
{
  // Code size       15 (0xf)
  .maxstack  4
  IL_0000:  ldarg.0
  IL_0001:  ldflda     ""Program Program3.program""
  IL_0006:  ldarg.1
  IL_0007:  ldarg.2
  IL_0008:  ldarg.3
  IL_0009:  call       ""ref int Program.M(ref int, ref int, object)""
  IL_000e:  ret
}");
        }
 
        [Fact]
        public void RefReturnConstrainedInstanceCallWithArguments()
        {
            var text = @"
interface I
{
    ref int M(ref int i, ref int j, object o);
}
 
class Program<T>
    where T : I
{
    T t = default(T);
 
    ref int M(ref int i, ref int j, object o)
    {
        return ref t.M(ref i, ref j, o);
    }
}
 
class Program2<T>
    where T : class, I
{
    ref int M(T t, ref int i, ref int j, object o)
    {
        return ref t.M(ref i, ref j, o);
    }
}
 
class Program3<T>
    where T : struct, I
{
    T t = default(T);
 
    ref int M(ref int i, ref int j, object o)
    {
        return ref t.M(ref i, ref j, o);
    }
}
";
 
            var compilation = CompileAndVerifyRef(text);
            compilation.VerifyIL("Program<T>.M(ref int, ref int, object)", @"
{
  // Code size       21 (0x15)
  .maxstack  4
  IL_0000:  ldarg.0
  IL_0001:  ldflda     ""T Program<T>.t""
  IL_0006:  ldarg.1
  IL_0007:  ldarg.2
  IL_0008:  ldarg.3
  IL_0009:  constrained. ""T""
  IL_000f:  callvirt   ""ref int I.M(ref int, ref int, object)""
  IL_0014:  ret
}");
            compilation.VerifyIL("Program2<T>.M(T, ref int, ref int, object)", @"
{
  // Code size       16 (0x10)
  .maxstack  4
  IL_0000:  ldarg.1
  IL_0001:  box        ""T""
  IL_0006:  ldarg.2
  IL_0007:  ldarg.3
  IL_0008:  ldarg.s    V_4
  IL_000a:  callvirt   ""ref int I.M(ref int, ref int, object)""
  IL_000f:  ret
}");
            compilation.VerifyIL("Program3<T>.M(ref int, ref int, object)", @"
{
  // Code size       21 (0x15)
  .maxstack  4
  IL_0000:  ldarg.0
  IL_0001:  ldflda     ""T Program3<T>.t""
  IL_0006:  ldarg.1
  IL_0007:  ldarg.2
  IL_0008:  ldarg.3
  IL_0009:  constrained. ""T""
  IL_000f:  callvirt   ""ref int I.M(ref int, ref int, object)""
  IL_0014:  ret
}");
        }
 
        [Fact]
        public void RefReturnDelegateInvocationWithNoArguments()
        {
            var text = @"
delegate ref int D();
 
class Program
{
    static ref int M(D d)
    {
        return ref d();
    }
}
";
 
            CompileAndVerifyRef(text).VerifyIL("Program.M(D)", @"
{
  // Code size        7 (0x7)
  .maxstack  1
  IL_0000:  ldarg.0
  IL_0001:  callvirt   ""ref int D.Invoke()""
  IL_0006:  ret
}");
        }
 
        [Fact]
        public void RefReturnDelegateInvocationWithArguments()
        {
            var text = @"
delegate ref int D(ref int i, ref int j, object o);
 
class Program
{
    static ref int M(D d, ref int i, ref int j, object o)
    {
        return ref d(ref i, ref j, o);
    }
}
";
 
            CompileAndVerifyRef(text).VerifyIL("Program.M(D, ref int, ref int, object)", @"
{
  // Code size       10 (0xa)
  .maxstack  4
  IL_0000:  ldarg.0
  IL_0001:  ldarg.1
  IL_0002:  ldarg.2
  IL_0003:  ldarg.3
  IL_0004:  callvirt   ""ref int D.Invoke(ref int, ref int, object)""
  IL_0009:  ret
}");
        }
 
        [Fact]
        public void RefReturnsAreVariables()
        {
            var text = @"
class Program
{
    int field = 0;
 
    ref int P { get { return ref field; } }
 
    ref int this[int i] { get { return ref field; } }
 
    ref int M(ref int i)
    {
        return ref i;
    }
 
    void N(out int i)
    {
        i = 0;
    }
 
    static unsafe void Main()
    {
        var program = new Program();
        program.P = 0;
        program.P += 1;
        program.P++;
        program.M(ref program.P);
        program.N(out program.P);
        fixed (int* i = &program.P) { }
        var tr = __makeref(program.P);
        program[0] = 0;
        program[0] += 1;
        program[0]++;
        program.M(ref program[0]);
        program.N(out program[0]);
        fixed (int* i = &program[0]) { }
        tr = __makeref(program[0]);
        program.M(ref program.field) = 0;
        program.M(ref program.field) += 1;
        program.M(ref program.field)++;
        program.M(ref program.M(ref program.field));
        program.N(out program.M(ref program.field));
        fixed (int* i = &program.M(ref program.field)) { }
        tr = __makeref(program.M(ref program.field));
    }
}
";
 
            CompileAndVerifyRef(text, options: TestOptions.UnsafeReleaseDll, verify: Verification.Fails).VerifyIL("Program.Main()", @"
{
  // Code size      291 (0x123)
  .maxstack  4
  .locals init (pinned int& V_0)
  IL_0000:  newobj     ""Program..ctor()""
  IL_0005:  dup
  IL_0006:  callvirt   ""ref int Program.P.get""
  IL_000b:  ldc.i4.0
  IL_000c:  stind.i4
  IL_000d:  dup
  IL_000e:  callvirt   ""ref int Program.P.get""
  IL_0013:  dup
  IL_0014:  ldind.i4
  IL_0015:  ldc.i4.1
  IL_0016:  add
  IL_0017:  stind.i4
  IL_0018:  dup
  IL_0019:  callvirt   ""ref int Program.P.get""
  IL_001e:  dup
  IL_001f:  ldind.i4
  IL_0020:  ldc.i4.1
  IL_0021:  add
  IL_0022:  stind.i4
  IL_0023:  dup
  IL_0024:  dup
  IL_0025:  callvirt   ""ref int Program.P.get""
  IL_002a:  callvirt   ""ref int Program.M(ref int)""
  IL_002f:  pop
  IL_0030:  dup
  IL_0031:  dup
  IL_0032:  callvirt   ""ref int Program.P.get""
  IL_0037:  callvirt   ""void Program.N(out int)""
  IL_003c:  dup
  IL_003d:  callvirt   ""ref int Program.P.get""
  IL_0042:  stloc.0
  IL_0043:  ldloc.0
  IL_0044:  pop
  IL_0045:  ldc.i4.0
  IL_0046:  conv.u
  IL_0047:  stloc.0
  IL_0048:  dup
  IL_0049:  callvirt   ""ref int Program.P.get""
  IL_004e:  mkrefany   ""int""
  IL_0053:  pop
  IL_0054:  dup
  IL_0055:  ldc.i4.0
  IL_0056:  callvirt   ""ref int Program.this[int].get""
  IL_005b:  ldc.i4.0
  IL_005c:  stind.i4
  IL_005d:  dup
  IL_005e:  ldc.i4.0
  IL_005f:  callvirt   ""ref int Program.this[int].get""
  IL_0064:  dup
  IL_0065:  ldind.i4
  IL_0066:  ldc.i4.1
  IL_0067:  add
  IL_0068:  stind.i4
  IL_0069:  dup
  IL_006a:  ldc.i4.0
  IL_006b:  callvirt   ""ref int Program.this[int].get""
  IL_0070:  dup
  IL_0071:  ldind.i4
  IL_0072:  ldc.i4.1
  IL_0073:  add
  IL_0074:  stind.i4
  IL_0075:  dup
  IL_0076:  dup
  IL_0077:  ldc.i4.0
  IL_0078:  callvirt   ""ref int Program.this[int].get""
  IL_007d:  callvirt   ""ref int Program.M(ref int)""
  IL_0082:  pop
  IL_0083:  dup
  IL_0084:  dup
  IL_0085:  ldc.i4.0
  IL_0086:  callvirt   ""ref int Program.this[int].get""
  IL_008b:  callvirt   ""void Program.N(out int)""
  IL_0090:  dup
  IL_0091:  ldc.i4.0
  IL_0092:  callvirt   ""ref int Program.this[int].get""
  IL_0097:  stloc.0
  IL_0098:  ldloc.0
  IL_0099:  pop
  IL_009a:  ldc.i4.0
  IL_009b:  conv.u
  IL_009c:  stloc.0
  IL_009d:  dup
  IL_009e:  ldc.i4.0
  IL_009f:  callvirt   ""ref int Program.this[int].get""
  IL_00a4:  mkrefany   ""int""
  IL_00a9:  pop
  IL_00aa:  dup
  IL_00ab:  dup
  IL_00ac:  ldflda     ""int Program.field""
  IL_00b1:  callvirt   ""ref int Program.M(ref int)""
  IL_00b6:  ldc.i4.0
  IL_00b7:  stind.i4
  IL_00b8:  dup
  IL_00b9:  dup
  IL_00ba:  ldflda     ""int Program.field""
  IL_00bf:  callvirt   ""ref int Program.M(ref int)""
  IL_00c4:  dup
  IL_00c5:  ldind.i4
  IL_00c6:  ldc.i4.1
  IL_00c7:  add
  IL_00c8:  stind.i4
  IL_00c9:  dup
  IL_00ca:  dup
  IL_00cb:  ldflda     ""int Program.field""
  IL_00d0:  callvirt   ""ref int Program.M(ref int)""
  IL_00d5:  dup
  IL_00d6:  ldind.i4
  IL_00d7:  ldc.i4.1
  IL_00d8:  add
  IL_00d9:  stind.i4
  IL_00da:  dup
  IL_00db:  dup
  IL_00dc:  dup
  IL_00dd:  ldflda     ""int Program.field""
  IL_00e2:  callvirt   ""ref int Program.M(ref int)""
  IL_00e7:  callvirt   ""ref int Program.M(ref int)""
  IL_00ec:  pop
  IL_00ed:  dup
  IL_00ee:  dup
  IL_00ef:  dup
  IL_00f0:  ldflda     ""int Program.field""
  IL_00f5:  callvirt   ""ref int Program.M(ref int)""
  IL_00fa:  callvirt   ""void Program.N(out int)""
  IL_00ff:  dup
  IL_0100:  dup
  IL_0101:  ldflda     ""int Program.field""
  IL_0106:  callvirt   ""ref int Program.M(ref int)""
  IL_010b:  stloc.0
  IL_010c:  ldloc.0
  IL_010d:  pop
  IL_010e:  ldc.i4.0
  IL_010f:  conv.u
  IL_0110:  stloc.0
  IL_0111:  dup
  IL_0112:  ldflda     ""int Program.field""
  IL_0117:  callvirt   ""ref int Program.M(ref int)""
  IL_011c:  mkrefany   ""int""
  IL_0121:  pop
  IL_0122:  ret
}");
        }
 
        [Fact]
        public void RefReturnsAreValues()
        {
            var text = @"
class Program
{
    int field = 0;
 
    ref int P { get { return ref field; } }
 
    ref int this[int i] { get { return ref field; } }
 
    ref int M(ref int i)
    {
        return ref i;
    }
 
    void N(int i)
    {
        i = 0;
    }
 
    static unsafe int Main()
    {
        var program = new Program();
        var @int = program.P + 0;
        var @string = program.P.ToString();
        var @long = (long)program.P;
        program.N(program.P);
        @int += program[0] + 0;
        @string = program[0].ToString();
        @long += (long)program[0];
        program.N(program[0]);
        @int += program.M(ref program.field) + 0;
        @string = program.M(ref program.field).ToString();
        @long += (long)program.M(ref program.field);
        program.N(program.M(ref program.field));
        return unchecked((int)((long)@int + @long));
    }
}
";
 
            CompileAndVerifyRef(text, options: TestOptions.UnsafeReleaseDll, verify: Verification.Fails).VerifyIL("Program.Main()", @"
{
  // Code size      168 (0xa8)
  .maxstack  4
  .locals init (Program V_0, //program
                long V_1) //long
  IL_0000:  newobj     ""Program..ctor()""
  IL_0005:  stloc.0
  IL_0006:  ldloc.0
  IL_0007:  callvirt   ""ref int Program.P.get""
  IL_000c:  ldind.i4
  IL_000d:  ldloc.0
  IL_000e:  callvirt   ""ref int Program.P.get""
  IL_0013:  call       ""string int.ToString()""
  IL_0018:  pop
  IL_0019:  ldloc.0
  IL_001a:  callvirt   ""ref int Program.P.get""
  IL_001f:  ldind.i4
  IL_0020:  conv.i8
  IL_0021:  stloc.1
  IL_0022:  ldloc.0
  IL_0023:  ldloc.0
  IL_0024:  callvirt   ""ref int Program.P.get""
  IL_0029:  ldind.i4
  IL_002a:  callvirt   ""void Program.N(int)""
  IL_002f:  ldloc.0
  IL_0030:  ldc.i4.0
  IL_0031:  callvirt   ""ref int Program.this[int].get""
  IL_0036:  ldind.i4
  IL_0037:  add
  IL_0038:  ldloc.0
  IL_0039:  ldc.i4.0
  IL_003a:  callvirt   ""ref int Program.this[int].get""
  IL_003f:  call       ""string int.ToString()""
  IL_0044:  pop
  IL_0045:  ldloc.1
  IL_0046:  ldloc.0
  IL_0047:  ldc.i4.0
  IL_0048:  callvirt   ""ref int Program.this[int].get""
  IL_004d:  ldind.i4
  IL_004e:  conv.i8
  IL_004f:  add
  IL_0050:  stloc.1
  IL_0051:  ldloc.0
  IL_0052:  ldloc.0
  IL_0053:  ldc.i4.0
  IL_0054:  callvirt   ""ref int Program.this[int].get""
  IL_0059:  ldind.i4
  IL_005a:  callvirt   ""void Program.N(int)""
  IL_005f:  ldloc.0
  IL_0060:  ldloc.0
  IL_0061:  ldflda     ""int Program.field""
  IL_0066:  callvirt   ""ref int Program.M(ref int)""
  IL_006b:  ldind.i4
  IL_006c:  add
  IL_006d:  ldloc.0
  IL_006e:  ldloc.0
  IL_006f:  ldflda     ""int Program.field""
  IL_0074:  callvirt   ""ref int Program.M(ref int)""
  IL_0079:  call       ""string int.ToString()""
  IL_007e:  pop
  IL_007f:  ldloc.1
  IL_0080:  ldloc.0
  IL_0081:  ldloc.0
  IL_0082:  ldflda     ""int Program.field""
  IL_0087:  callvirt   ""ref int Program.M(ref int)""
  IL_008c:  ldind.i4
  IL_008d:  conv.i8
  IL_008e:  add
  IL_008f:  stloc.1
  IL_0090:  ldloc.0
  IL_0091:  ldloc.0
  IL_0092:  ldloc.0
  IL_0093:  ldflda     ""int Program.field""
  IL_0098:  callvirt   ""ref int Program.M(ref int)""
  IL_009d:  ldind.i4
  IL_009e:  callvirt   ""void Program.N(int)""
  IL_00a3:  conv.i8
  IL_00a4:  ldloc.1
  IL_00a5:  add
  IL_00a6:  conv.i4
  IL_00a7:  ret
}");
        }
 
        [Fact]
        public void RefReturnArrayAccessNested()
        {
            var text = @"
class Program
{
    static ref int M()
    {
        ref int N()
        {
            return ref (new int[1])[0];
        }
 
        return ref N();
    }
}
";
 
            CompileAndVerify(text, parseOptions: TestOptions.Regular).VerifyIL("Program.M()", @"
{
  // Code size        6 (0x6)
  .maxstack  1
  IL_0000:  call       ""ref int Program.<M>g__N|0_0()""
  IL_0005:  ret
}").VerifyIL("Program.<M>g__N|0_0", @"
{
  // Code size       13 (0xd)
  .maxstack  2
  IL_0000:  ldc.i4.1
  IL_0001:  newarr     ""int""
  IL_0006:  ldc.i4.0
  IL_0007:  ldelema    ""int""
  IL_000c:  ret
}");
        }
 
        [Fact]
        public void RefReturnArrayAccessNested1()
        {
            var text = @"
class Program
{
    static ref int M()
    {
        var arr = new int[1]{40};
 
        ref int N()
        {
            ref int NN(ref int arg) => ref arg;
 
            ref var r = ref NN(ref arr[0]); 
            r += 2;
 
            return ref r;
        }
 
        return ref N();
    }
 
    static void Main()
    {
        System.Console.WriteLine(M());
    }
}
";
 
            CompileAndVerify(text, parseOptions: TestOptions.Regular, expectedOutput: "42", verify: Verification.Fails).VerifyIL("Program.M()", @"
{
  // Code size       26 (0x1a)
  .maxstack  5
  .locals init (Program.<>c__DisplayClass0_0 V_0) //CS$<>8__locals0
  IL_0000:  ldloca.s   V_0
  IL_0002:  ldc.i4.1
  IL_0003:  newarr     ""int""
  IL_0008:  dup
  IL_0009:  ldc.i4.0
  IL_000a:  ldc.i4.s   40
  IL_000c:  stelem.i4
  IL_000d:  stfld      ""int[] Program.<>c__DisplayClass0_0.arr""
  IL_0012:  ldloca.s   V_0
  IL_0014:  call       ""ref int Program.<M>g__N|0_0(ref Program.<>c__DisplayClass0_0)""
  IL_0019:  ret
}").VerifyIL("Program.<M>g__N|0_0", @"
{
  // Code size       24 (0x18)
  .maxstack  4
  IL_0000:  ldarg.0
  IL_0001:  ldfld      ""int[] Program.<>c__DisplayClass0_0.arr""
  IL_0006:  ldc.i4.0
  IL_0007:  ldelema    ""int""
  IL_000c:  call       ""ref int Program.<M>g__NN|0_1(ref int)""
  IL_0011:  dup
  IL_0012:  dup
  IL_0013:  ldind.i4
  IL_0014:  ldc.i4.2
  IL_0015:  add
  IL_0016:  stind.i4
  IL_0017:  ret
}").VerifyIL("Program.<M>g__NN|0_1", @"
{
  // Code size        2 (0x2)
  .maxstack  1
  IL_0000:  ldarg.0
  IL_0001:  ret
}");
        }
 
        [Fact]
        public void RefReturnArrayAccessNested2()
        {
            var text = @"
class Program
{
    delegate ref int D();    
 
    static D M()
    {
        var arr = new int[1]{40};
 
        ref int N()
        {
            ref int NN(ref int arg) => ref arg;
 
            ref var r = ref NN(ref arr[0]); 
            r += 2;
 
            return ref r;
        }
 
        return N;
    }
 
    static void Main()
    {
        System.Console.WriteLine(M()());
    }
}
";
 
            CompileAndVerify(text, parseOptions: TestOptions.Regular, expectedOutput: "42", verify: Verification.Fails).VerifyIL("Program.M()", @"
{
  // Code size       36 (0x24)
  .maxstack  5
  .locals init (Program.<>c__DisplayClass1_0 V_0) //CS$<>8__locals0
  IL_0000:  newobj     ""Program.<>c__DisplayClass1_0..ctor()""
  IL_0005:  stloc.0
  IL_0006:  ldloc.0
  IL_0007:  ldc.i4.1
  IL_0008:  newarr     ""int""
  IL_000d:  dup
  IL_000e:  ldc.i4.0
  IL_000f:  ldc.i4.s   40
  IL_0011:  stelem.i4
  IL_0012:  stfld      ""int[] Program.<>c__DisplayClass1_0.arr""
  IL_0017:  ldloc.0
  IL_0018:  ldftn      ""ref int Program.<>c__DisplayClass1_0.<M>g__N|0()""
  IL_001e:  newobj     ""Program.D..ctor(object, System.IntPtr)""
  IL_0023:  ret
}").VerifyIL("Program.<>c__DisplayClass1_0.<M>g__N|0()", @"
{
  // Code size       24 (0x18)
  .maxstack  4
  IL_0000:  ldarg.0
  IL_0001:  ldfld      ""int[] Program.<>c__DisplayClass1_0.arr""
  IL_0006:  ldc.i4.0
  IL_0007:  ldelema    ""int""
  IL_000c:  call       ""ref int Program.<M>g__NN|1_1(ref int)""
  IL_0011:  dup
  IL_0012:  dup
  IL_0013:  ldind.i4
  IL_0014:  ldc.i4.2
  IL_0015:  add
  IL_0016:  stind.i4
  IL_0017:  ret
}").VerifyIL("Program.<M>g__NN|1_1(ref int)", @"
{
  // Code size        2 (0x2)
  .maxstack  1
  IL_0000:  ldarg.0
  IL_0001:  ret
}");
        }
 
        [Fact]
        public void RefReturnConditionalAccess01()
        {
            var text = @"
    using System;
 
    class Program
    {
        class C1<T> where T : IDisposable
        {
            T inst = default(T);
 
            public ref T GetDisposable()
            {
                return ref inst;
            }
 
            public void Test()
            {
                GetDisposable().Dispose();
                System.Console.Write(inst.ToString());
 
                GetDisposable()?.Dispose();
                System.Console.Write(inst.ToString());
            }
        }
 
        static void Main(string[] args)
        {
            var v = new C1<Mutable>();
            v.Test();
        }
    }
 
    struct Mutable : IDisposable
    {
        public int disposed;
         
        public void Dispose()
        {
            disposed += 1;
        }
 
        public override string ToString()
        {
            return disposed.ToString();
        }
    }
";
 
            CompileAndVerifyRef(text, expectedOutput: "12")
                .VerifyIL("Program.C1<T>.Test()", @"
{
  // Code size      114 (0x72)
  .maxstack  2
  .locals init (T V_0)
  IL_0000:  ldarg.0
  IL_0001:  call       ""ref T Program.C1<T>.GetDisposable()""
  IL_0006:  constrained. ""T""
  IL_000c:  callvirt   ""void System.IDisposable.Dispose()""
  IL_0011:  ldarg.0
  IL_0012:  ldflda     ""T Program.C1<T>.inst""
  IL_0017:  constrained. ""T""
  IL_001d:  callvirt   ""string object.ToString()""
  IL_0022:  call       ""void System.Console.Write(string)""
  IL_0027:  ldarg.0
  IL_0028:  call       ""ref T Program.C1<T>.GetDisposable()""
  IL_002d:  ldloca.s   V_0
  IL_002f:  initobj    ""T""
  IL_0035:  ldloc.0
  IL_0036:  box        ""T""
  IL_003b:  brtrue.s   IL_0050
  IL_003d:  ldobj      ""T""
  IL_0042:  stloc.0
  IL_0043:  ldloca.s   V_0
  IL_0045:  ldloc.0
  IL_0046:  box        ""T""
  IL_004b:  brtrue.s   IL_0050
  IL_004d:  pop
  IL_004e:  br.s       IL_005b
  IL_0050:  constrained. ""T""
  IL_0056:  callvirt   ""void System.IDisposable.Dispose()""
  IL_005b:  ldarg.0
  IL_005c:  ldflda     ""T Program.C1<T>.inst""
  IL_0061:  constrained. ""T""
  IL_0067:  callvirt   ""string object.ToString()""
  IL_006c:  call       ""void System.Console.Write(string)""
  IL_0071:  ret
}");
        }
 
        [Fact]
        public void RefReturnConditionalAccess02()
        {
            var text = @"
using System;
 
class Program
{
    class C1<T> where T : IDisposable
    {
        T inst = default(T);
 
        public ref T GetDisposable(ref T arg)
        {
            return ref arg;
        }
 
        public void Test()
        {
            ref T temp = ref GetDisposable(ref inst);
            temp.Dispose();
            System.Console.Write(inst.ToString());
 
            temp?.Dispose();
            System.Console.Write(inst.ToString());
        }
    }
 
    static void Main(string[] args)
    {
        var v = new C1<Mutable>();
        v.Test();
    }
}
 
struct Mutable : IDisposable
{
    public int disposed;
 
    public void Dispose()
    {
        disposed += 1;
    }
 
    public override string ToString()
    {
        return disposed.ToString();
    }
}
";
 
            CompileAndVerifyRef(text, expectedOutput: "12", verify: Verification.Fails)
                .VerifyIL("Program.C1<T>.Test()", @"
{
  // Code size      115 (0x73)
  .maxstack  2
  .locals init (T V_0)
  IL_0000:  ldarg.0
  IL_0001:  ldarg.0
  IL_0002:  ldflda     ""T Program.C1<T>.inst""
  IL_0007:  call       ""ref T Program.C1<T>.GetDisposable(ref T)""
  IL_000c:  dup
  IL_000d:  constrained. ""T""
  IL_0013:  callvirt   ""void System.IDisposable.Dispose()""
  IL_0018:  ldarg.0
  IL_0019:  ldflda     ""T Program.C1<T>.inst""
  IL_001e:  constrained. ""T""
  IL_0024:  callvirt   ""string object.ToString()""
  IL_0029:  call       ""void System.Console.Write(string)""
  IL_002e:  ldloca.s   V_0
  IL_0030:  initobj    ""T""
  IL_0036:  ldloc.0
  IL_0037:  box        ""T""
  IL_003c:  brtrue.s   IL_0051
  IL_003e:  ldobj      ""T""
  IL_0043:  stloc.0
  IL_0044:  ldloca.s   V_0
  IL_0046:  ldloc.0
  IL_0047:  box        ""T""
  IL_004c:  brtrue.s   IL_0051
  IL_004e:  pop
  IL_004f:  br.s       IL_005c
  IL_0051:  constrained. ""T""
  IL_0057:  callvirt   ""void System.IDisposable.Dispose()""
  IL_005c:  ldarg.0
  IL_005d:  ldflda     ""T Program.C1<T>.inst""
  IL_0062:  constrained. ""T""
  IL_0068:  callvirt   ""string object.ToString()""
  IL_006d:  call       ""void System.Console.Write(string)""
  IL_0072:  ret
}");
        }
 
        [Fact]
        public void RefReturnConditionalAccess03()
        {
            var text = @"
using System;
 
class Program
{
    class C1<T> where T : IDisposable
    {
        T inst = default(T);
 
        public ref T GetDisposable(ref T arg)
        {
            return ref arg;
        }
 
        public void Test()
        {
            ref T temp = ref GetDisposable(ref inst);
 
            // prevent eliding of temp 
            for(int i = 0; i < 2; i++)
            {
                temp.Dispose();
                System.Console.Write(inst.ToString());
 
                temp?.Dispose();
                System.Console.Write(inst.ToString());
            }
        }
    }
 
    static void Main(string[] args)
    {
        var v = new C1<Mutable>();
        v.Test();
    }
}
 
struct Mutable : IDisposable
{
    public int disposed;
 
    public void Dispose()
    {
        disposed += 1;
    }
 
    public override string ToString()
    {
        return disposed.ToString();
    }
}
";
 
            CompileAndVerifyRef(text, expectedOutput: "1234", verify: Verification.Fails)
                .VerifyIL("Program.C1<T>.Test()", @"
{
  // Code size      129 (0x81)
  .maxstack  2
  .locals init (T& V_0, //temp
                int V_1, //i
                T V_2)
  IL_0000:  ldarg.0
  IL_0001:  ldarg.0
  IL_0002:  ldflda     ""T Program.C1<T>.inst""
  IL_0007:  call       ""ref T Program.C1<T>.GetDisposable(ref T)""
  IL_000c:  stloc.0
  IL_000d:  ldc.i4.0
  IL_000e:  stloc.1
  IL_000f:  br.s       IL_007c
  IL_0011:  ldloc.0
  IL_0012:  constrained. ""T""
  IL_0018:  callvirt   ""void System.IDisposable.Dispose()""
  IL_001d:  ldarg.0
  IL_001e:  ldflda     ""T Program.C1<T>.inst""
  IL_0023:  constrained. ""T""
  IL_0029:  callvirt   ""string object.ToString()""
  IL_002e:  call       ""void System.Console.Write(string)""
  IL_0033:  ldloc.0
  IL_0034:  ldloca.s   V_2
  IL_0036:  initobj    ""T""
  IL_003c:  ldloc.2
  IL_003d:  box        ""T""
  IL_0042:  brtrue.s   IL_0057
  IL_0044:  ldobj      ""T""
  IL_0049:  stloc.2
  IL_004a:  ldloca.s   V_2
  IL_004c:  ldloc.2
  IL_004d:  box        ""T""
  IL_0052:  brtrue.s   IL_0057
  IL_0054:  pop
  IL_0055:  br.s       IL_0062
  IL_0057:  constrained. ""T""
  IL_005d:  callvirt   ""void System.IDisposable.Dispose()""
  IL_0062:  ldarg.0
  IL_0063:  ldflda     ""T Program.C1<T>.inst""
  IL_0068:  constrained. ""T""
  IL_006e:  callvirt   ""string object.ToString()""
  IL_0073:  call       ""void System.Console.Write(string)""
  IL_0078:  ldloc.1
  IL_0079:  ldc.i4.1
  IL_007a:  add
  IL_007b:  stloc.1
  IL_007c:  ldloc.1
  IL_007d:  ldc.i4.2
  IL_007e:  blt.s      IL_0011
  IL_0080:  ret
}");
        }
 
        [Fact]
        public void RefReturnConditionalAccess04()
        {
            var text = @"
using System;
 
class Program
{
    class C1<T> where T : IGoo<T>, new()
    {
        T inst = new T();
 
        public ref T GetDisposable(ref T arg)
        {
            return ref arg;
        }
 
        public void Test()
        {
            GetDisposable(ref inst)?.Blah(ref inst);
            System.Console.Write(inst == null);
        }
    }
 
    static void Main(string[] args)
    {
        var v = new C1<Goo>();
        v.Test();
    }
}
 
interface IGoo<T>
{
    void Blah(ref T arg);
}
 
class Goo : IGoo<Goo>
{
    public int disposed;
 
    public void Blah(ref Goo arg)
    {
        arg = null;
        disposed++;
        System.Console.Write(disposed);
    }
}
";
 
            CompileAndVerifyRef(text, expectedOutput: "1True", verify: Verification.Fails)
                .VerifyIL("Program.C1<T>.Test()", @"
{
  // Code size       84 (0x54)
  .maxstack  2
  .locals init (T V_0)
  IL_0000:  ldarg.0
  IL_0001:  ldarg.0
  IL_0002:  ldflda     ""T Program.C1<T>.inst""
  IL_0007:  call       ""ref T Program.C1<T>.GetDisposable(ref T)""
  IL_000c:  ldloca.s   V_0
  IL_000e:  initobj    ""T""
  IL_0014:  ldloc.0
  IL_0015:  box        ""T""
  IL_001a:  brtrue.s   IL_002f
  IL_001c:  ldobj      ""T""
  IL_0021:  stloc.0
  IL_0022:  ldloca.s   V_0
  IL_0024:  ldloc.0
  IL_0025:  box        ""T""
  IL_002a:  brtrue.s   IL_002f
  IL_002c:  pop
  IL_002d:  br.s       IL_0040
  IL_002f:  ldarg.0
  IL_0030:  ldflda     ""T Program.C1<T>.inst""
  IL_0035:  constrained. ""T""
  IL_003b:  callvirt   ""void IGoo<T>.Blah(ref T)""
  IL_0040:  ldarg.0
  IL_0041:  ldfld      ""T Program.C1<T>.inst""
  IL_0046:  box        ""T""
  IL_004b:  ldnull
  IL_004c:  ceq
  IL_004e:  call       ""void System.Console.Write(bool)""
  IL_0053:  ret
}");
        }
 
        [Fact]
        public void RefReturnConditionalAccess05()
        {
            var text = @"
using System;
 
class Program
{
    class C1<T> where T : IGoo<T>, new()
    {
        T inst = new T();
 
        public ref T GetDisposable(ref T arg)
        {
            return ref arg;
        }
 
        public void Test()
        {
            ref T temp = ref GetDisposable(ref inst);
 
            // prevent eliding of temp 
            for(int i = 0; i < 2; i++)
            {
                temp?.Blah(ref temp);
                System.Console.Write(temp == null);
                System.Console.Write(inst == null);
 
                inst = new T();
                temp?.Blah(ref temp);
                System.Console.Write(temp == null);
                System.Console.Write(inst == null);
            }
        }
    }
 
    static void Main(string[] args)
    {
        var v = new C1<Goo>();
        v.Test();
    }
}
 
interface IGoo<T>
{
    void Blah(ref T arg);
}
 
class Goo : IGoo<Goo>
{
    public int disposed;
 
    public void Blah(ref Goo arg)
    {
        arg = null;
        disposed++;
        System.Console.Write(disposed);
    }
}
";
 
            CompileAndVerifyRef(text, expectedOutput: "1TrueTrue1TrueTrueTrueTrue1TrueTrue", verify: Verification.Fails)
                .VerifyIL("Program.C1<T>.Test()", @"
{
  // Code size      215 (0xd7)
  .maxstack  2
  .locals init (T& V_0, //temp
                int V_1, //i
                T V_2)
  IL_0000:  ldarg.0
  IL_0001:  ldarg.0
  IL_0002:  ldflda     ""T Program.C1<T>.inst""
  IL_0007:  call       ""ref T Program.C1<T>.GetDisposable(ref T)""
  IL_000c:  stloc.0
  IL_000d:  ldc.i4.0
  IL_000e:  stloc.1
  IL_000f:  br         IL_00cf
  IL_0014:  ldloc.0
  IL_0015:  ldloca.s   V_2
  IL_0017:  initobj    ""T""
  IL_001d:  ldloc.2
  IL_001e:  box        ""T""
  IL_0023:  brtrue.s   IL_0038
  IL_0025:  ldobj      ""T""
  IL_002a:  stloc.2
  IL_002b:  ldloca.s   V_2
  IL_002d:  ldloc.2
  IL_002e:  box        ""T""
  IL_0033:  brtrue.s   IL_0038
  IL_0035:  pop
  IL_0036:  br.s       IL_0044
  IL_0038:  ldloc.0
  IL_0039:  constrained. ""T""
  IL_003f:  callvirt   ""void IGoo<T>.Blah(ref T)""
  IL_0044:  ldloc.0
  IL_0045:  ldobj      ""T""
  IL_004a:  box        ""T""
  IL_004f:  ldnull
  IL_0050:  ceq
  IL_0052:  call       ""void System.Console.Write(bool)""
  IL_0057:  ldarg.0
  IL_0058:  ldfld      ""T Program.C1<T>.inst""
  IL_005d:  box        ""T""
  IL_0062:  ldnull
  IL_0063:  ceq
  IL_0065:  call       ""void System.Console.Write(bool)""
  IL_006a:  ldarg.0
  IL_006b:  call       ""T System.Activator.CreateInstance<T>()""
  IL_0070:  stfld      ""T Program.C1<T>.inst""
  IL_0075:  ldloc.0
  IL_0076:  ldloca.s   V_2
  IL_0078:  initobj    ""T""
  IL_007e:  ldloc.2
  IL_007f:  box        ""T""
  IL_0084:  brtrue.s   IL_0099
  IL_0086:  ldobj      ""T""
  IL_008b:  stloc.2
  IL_008c:  ldloca.s   V_2
  IL_008e:  ldloc.2
  IL_008f:  box        ""T""
  IL_0094:  brtrue.s   IL_0099
  IL_0096:  pop
  IL_0097:  br.s       IL_00a5
  IL_0099:  ldloc.0
  IL_009a:  constrained. ""T""
  IL_00a0:  callvirt   ""void IGoo<T>.Blah(ref T)""
  IL_00a5:  ldloc.0
  IL_00a6:  ldobj      ""T""
  IL_00ab:  box        ""T""
  IL_00b0:  ldnull
  IL_00b1:  ceq
  IL_00b3:  call       ""void System.Console.Write(bool)""
  IL_00b8:  ldarg.0
  IL_00b9:  ldfld      ""T Program.C1<T>.inst""
  IL_00be:  box        ""T""
  IL_00c3:  ldnull
  IL_00c4:  ceq
  IL_00c6:  call       ""void System.Console.Write(bool)""
  IL_00cb:  ldloc.1
  IL_00cc:  ldc.i4.1
  IL_00cd:  add
  IL_00ce:  stloc.1
  IL_00cf:  ldloc.1
  IL_00d0:  ldc.i4.2
  IL_00d1:  blt        IL_0014
  IL_00d6:  ret
}");
        }
 
        [Fact]
        public void RefReturn_CSharp6()
        {
            var text = @"
class Program
{
    static ref int M()
    {
        return ref (new int[1])[0];
    }
}
";
 
            var comp = CreateCompilation(text, parseOptions: TestOptions.Regular.WithLanguageVersion(LanguageVersion.CSharp6));
            comp.VerifyDiagnostics(
                // (4,12): error CS8059: Feature 'byref locals and returns' is not available in C# 6. Please use language version 7.0 or greater.
                //     static ref int M()
                Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion6, "ref").WithArguments("byref locals and returns", "7.0").WithLocation(4, 12),
                // (6,16): error CS8059: Feature 'byref locals and returns' is not available in C# 6. Please use language version 7.0 or greater.
                //         return ref (new int[1])[0];
                Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion6, "ref").WithArguments("byref locals and returns", "7.0").WithLocation(6, 16)
                );
        }
 
        [Fact]
        public void RefInLambda_CSharp6()
        {
            var text = @"
class Program
{
    static ref int M()
    {
        var arr = new int[1]{40};
 
        ref int N()
        {
            ref int NN(ref int arg) => ref arg;
 
            ref var r = ref NN(ref arr[0]);
            r += 2;
 
            return ref r;
        }
 
        return ref N();
    }
}
";
            var comp = CreateCompilation(text, parseOptions: TestOptions.Regular.WithLanguageVersion(LanguageVersion.CSharp6));
            comp.VerifyDiagnostics(
                // (4,12): error CS8059: Feature 'byref locals and returns' is not available in C# 6. Please use language version 7.0 or greater.
                //     static ref int M()
                Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion6, "ref").WithArguments("byref locals and returns", "7.0").WithLocation(4, 12),
                // (8,9): error CS8059: Feature 'byref locals and returns' is not available in C# 6. Please use language version 7.0 or greater.
                //         ref int N()
                Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion6, "ref").WithArguments("byref locals and returns", "7.0").WithLocation(8, 9),
                // (8,17): error CS8059: Feature 'local functions' is not available in C# 6. Please use language version 7.0 or greater.
                //         ref int N()
                Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion6, "N").WithArguments("local functions", "7.0").WithLocation(8, 17),
                // (10,13): error CS8059: Feature 'byref locals and returns' is not available in C# 6. Please use language version 7.0 or greater.
                //             ref int NN(ref int arg) => ref arg;
                Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion6, "ref").WithArguments("byref locals and returns", "7.0").WithLocation(10, 13),
                // (10,21): error CS8059: Feature 'local functions' is not available in C# 6. Please use language version 7.0 or greater.
                //             ref int NN(ref int arg) => ref arg;
                Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion6, "NN").WithArguments("local functions", "7.0").WithLocation(10, 21),
                // (10,40): error CS8059: Feature 'byref locals and returns' is not available in C# 6. Please use language version 7.0 or greater.
                //             ref int NN(ref int arg) => ref arg;
                Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion6, "ref").WithArguments("byref locals and returns", "7.0").WithLocation(10, 40),
                // (12,13): error CS8059: Feature 'byref locals and returns' is not available in C# 6. Please use language version 7.0 or greater.
                //             ref var r = ref NN(ref arr[0]);
                Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion6, "ref").WithArguments("byref locals and returns", "7.0").WithLocation(12, 13),
                // (12,25): error CS8059: Feature 'byref locals and returns' is not available in C# 6. Please use language version 7.0 or greater.
                //             ref var r = ref NN(ref arr[0]);
                Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion6, "ref").WithArguments("byref locals and returns", "7.0").WithLocation(12, 25),
                // (15,20): error CS8059: Feature 'byref locals and returns' is not available in C# 6. Please use language version 7.0 or greater.
                //             return ref r;
                Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion6, "ref").WithArguments("byref locals and returns", "7.0").WithLocation(15, 20),
                // (18,16): error CS8059: Feature 'byref locals and returns' is not available in C# 6. Please use language version 7.0 or greater.
                //         return ref N();
                Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion6, "ref").WithArguments("byref locals and returns", "7.0").WithLocation(18, 16)
                );
        }
 
        [Fact]
        public void RefDelegate_CSharp6()
        {
            var text = @"
delegate ref int D();
";
 
            var comp = CreateCompilation(text, parseOptions: TestOptions.Regular.WithLanguageVersion(LanguageVersion.CSharp6));
            comp.VerifyDiagnostics(
                // (2,10): error CS8059: Feature 'byref locals and returns' is not available in C# 6. Please use language version 7.0 or greater.
                // delegate ref int D();
                Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion6, "ref").WithArguments("byref locals and returns", "7.0").WithLocation(2, 10)
                );
        }
 
        [Fact]
        public void RefInForStatement_CSharp6()
        {
            var text = @"
class Program
{
    static int M(ref int d)
    {
        for (ref int a = ref d; ;) { }
    }
}
";
 
            var comp = CreateCompilation(text, parseOptions: TestOptions.Regular.WithLanguageVersion(LanguageVersion.CSharp6));
            comp.VerifyDiagnostics(
                // (6,14): error CS8059: Feature 'ref for-loop variables' is not available in C# 6. Please use language version 7.3 or greater.
                //         for (ref int a = ref d; ;) { }
                Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion6, "ref int").WithArguments("ref for-loop variables", "7.3").WithLocation(6, 14),
                // (6,26): error CS8059: Feature 'byref locals and returns' is not available in C# 6. Please use language version 7.0 or greater.
                //         for (ref int a = ref d; ;) { }
                Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion6, "ref").WithArguments("byref locals and returns", "7.0").WithLocation(6, 26));
        }
 
        [Fact]
        public void RefLambdaInferenceMethodArgument()
        {
            var text = @"
delegate ref int D(int x);
 
class C
{
    static void MD(D d) { }
 
    static int i = 0;
    static void M()
    {
        MD((x) => ref i);
        MD(x => ref i);
    }
}
";
 
            var comp = CreateCompilation(text, parseOptions: TestOptions.Regular.WithLanguageVersion(LanguageVersion.CSharp6));
            comp.VerifyDiagnostics(
                // (2,10): error CS8059: Feature 'byref locals and returns' is not available in C# 6. Please use language version 7.0 or greater.
                // delegate ref int D(int x);
                Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion6, "ref").WithArguments("byref locals and returns", "7.0").WithLocation(2, 10),
                // (11,19): error CS8059: Feature 'byref locals and returns' is not available in C# 6. Please use language version 7.0 or greater.
                //         MD((x) => ref i);
                Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion6, "ref").WithArguments("byref locals and returns", "7.0").WithLocation(11, 19),
                // (12,17): error CS8059: Feature 'byref locals and returns' is not available in C# 6. Please use language version 7.0 or greater.
                //         MD(x => ref i);
                Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion6, "ref").WithArguments("byref locals and returns", "7.0").WithLocation(12, 17)
                );
        }
 
        [Fact]
        public void Override_Metadata()
        {
            var ilSource =
@".class public abstract A
{
  .method public hidebysig specialname rtspecialname instance void .ctor() { ret }
  .method public virtual instance object F() { ldnull throw }
  .method public virtual instance object& get_P() { ldnull throw }
  .property instance object& P()
  {
    .get instance object& A::get_P()
  }
}
.class public abstract B1 extends A
{
  .method public hidebysig specialname rtspecialname instance void .ctor() { ret }
  .method public virtual instance object F() { ldnull throw }
  .method public virtual instance object get_P() { ldnull throw }
  .property instance object P()
  {
    .get instance object B1::get_P()
  }
}
.class public abstract B2 extends A
{
  .method public hidebysig specialname rtspecialname instance void .ctor() { ret }
  .method public virtual instance object& F() { ldnull throw }
  .method public virtual instance object& get_P() { ldnull throw }
  .property instance object& P()
  {
    .get instance object& B2::get_P()
  }
}";
            var ref1 = CompileIL(ilSource);
            var compilation = CreateCompilation("", options: TestOptions.DebugDll, references: new[] { ref1 });
 
            var method = compilation.GetMember<MethodSymbol>("B1.F");
            Assert.Equal("System.Object B1.F()", method.ToTestDisplayString());
            Assert.Equal("System.Object A.F()", method.OverriddenMethod.ToTestDisplayString());
 
            var property = compilation.GetMember<PropertySymbol>("B1.P");
            Assert.Equal("System.Object B1.P { get; }", property.ToTestDisplayString());
            Assert.Null(property.OverriddenProperty);
 
            method = compilation.GetMember<MethodSymbol>("B2.F");
            Assert.Equal("ref System.Object B2.F()", method.ToTestDisplayString());
            Assert.Null(method.OverriddenMethod);
 
            property = compilation.GetMember<PropertySymbol>("B2.P");
            Assert.Equal("ref System.Object B2.P { get; }", property.ToTestDisplayString());
            Assert.Equal("ref System.Object A.P { get; }", property.OverriddenProperty.ToTestDisplayString());
        }
 
        [WorkItem(12763, "https://github.com/dotnet/roslyn/issues/12763")]
        [Fact]
        public void RefReturnFieldUse001()
        {
            var text = @"
public class A<T>
{
    private T _f;
    public ref T F()
    {
        return ref _f;
    }
 
    private T _p;
    public ref T P
    {
        get { return ref _p; }
    }
}
";
 
            var comp = CreateCompilation(text, options: TestOptions.ReleaseDll);
 
            comp.VerifyDiagnostics(
                // no diagnostics expected
                );
        }
 
        [WorkItem(12763, "https://github.com/dotnet/roslyn/issues/12763")]
        [Fact]
        public void RefAssignFieldUse001()
        {
            var text = @"
public class A<T>
{
    private T _f;
    public ref T F()
    {
        ref var r = ref _f;
        return ref r;
    }
 
    private T _p;
    public ref T P
    {
        get 
        { 
            ref var r = ref _p;
            return ref r;
        }
    }
}
";
 
            var comp = CreateCompilation(text, options: TestOptions.ReleaseDll);
 
            comp.VerifyDiagnostics(
                // no diagnostics expected
                );
        }
 
        [Fact]
        public void ThrowRefReturn()
        {
            var text = @"using System;
class Program
{
    static ref int P1 { get => throw new E(1); }
    static ref int P2 => throw new E(2);
    static ref int M() => throw new E(3);
 
    public static void Main()
    {
        ref int L() => throw new E(4);
        D d = () => throw new E(5);
 
        try { ref int x = ref P1; }  catch (E e) { Console.Write(e.Value); }
        try { ref int x = ref P2; }  catch (E e) { Console.Write(e.Value); }
        try { ref int x = ref M(); } catch (E e) { Console.Write(e.Value); }
        try { ref int x = ref L(); } catch (E e) { Console.Write(e.Value); }
        try { ref int x = ref d(); } catch (E e) { Console.Write(e.Value); }
    }
}
delegate ref int D();
class E : Exception
{
    public int Value;
    public E(int value) { this.Value = value; }
}
";
            var v = CompileAndVerify(text, expectedOutput: "12345");
        }
 
        [Fact]
        public void NoRefThrow()
        {
            var text = @"using System;
class Program
{
    static ref int P1 { get => ref throw new E(1); }
    static ref int P2 => ref throw new E(2);
    static ref int M() => ref throw new E(3);
 
    public static void Main()
    {
        ref int L() => ref throw new E(4);
        D d = () => ref throw new E(5);
        L();
        d();
    }
}
delegate ref int D();
class E : Exception
{
    public int Value;
    public E(int value) { this.Value = value; }
}
";
            CreateCompilation(text).VerifyDiagnostics(
                // (4,36): error CS8115: A throw expression is not allowed in this context.
                //     static ref int P1 { get => ref throw new E(1); }
                Diagnostic(ErrorCode.ERR_ThrowMisplaced, "throw").WithLocation(4, 36),
                // (5,30): error CS8115: A throw expression is not allowed in this context.
                //     static ref int P2 => ref throw new E(2);
                Diagnostic(ErrorCode.ERR_ThrowMisplaced, "throw").WithLocation(5, 30),
                // (6,31): error CS8115: A throw expression is not allowed in this context.
                //     static ref int M() => ref throw new E(3);
                Diagnostic(ErrorCode.ERR_ThrowMisplaced, "throw").WithLocation(6, 31),
                // (10,28): error CS8115: A throw expression is not allowed in this context.
                //         ref int L() => ref throw new E(4);
                Diagnostic(ErrorCode.ERR_ThrowMisplaced, "throw").WithLocation(10, 28),
                // (11,25): error CS8115: A throw expression is not allowed in this context.
                //         D d = () => ref throw new E(5);
                Diagnostic(ErrorCode.ERR_ThrowMisplaced, "throw").WithLocation(11, 25)
                );
        }
 
        [Fact]
        [WorkItem(13206, "https://github.com/dotnet/roslyn/issues/13206")]
        public void Lambda_01()
        {
            var source =
@"public delegate ref T D<T>();
public class A<T>
{
#pragma warning disable 0649
    private T _t;
    public ref T F()
    {
        return ref _t;
    }
}
public class B
{
    public static void F<T>(D<T> d, T t)
    {
        d() = t;
    }
}
 
class Program
{
    static void Main()
    {
        var o = new A<int>();
        B.F(() => o.F(), 2);
        System.Console.WriteLine(o.F());
    }
}";
 
            CreateCompilation(source).VerifyDiagnostics(
                // (24,19): error CS8150: By-value returns may only be used in methods that return by value
                //         B.F(() => o.F(), 2);
                Diagnostic(ErrorCode.ERR_MustHaveRefReturn, "o.F()").WithLocation(24, 19)
                );
        }
 
        [Fact]
        [WorkItem(13206, "https://github.com/dotnet/roslyn/issues/13206")]
        public void Lambda_02()
        {
            var source =
@"public delegate ref T D<T>();
public class A<T>
{
#pragma warning disable 0649
    private T _t;
    public ref T F()
    {
        return ref _t;
    }
}
public class B
{
    public static void F<T>(D<T> d, T t)
    {
        d() = t;
    }
}
 
class Program
{
    static void Main()
    {
        var o = new A<int>();
        B.F(() => ref o.F(), 2);
        System.Console.WriteLine(o.F());
    }
}";
 
            var v = CompileAndVerify(source, expectedOutput: "2");
        }
 
        [Fact]
        [WorkItem(13206, "https://github.com/dotnet/roslyn/issues/13206")]
        public void Lambda_03()
        {
            var source =
@"public delegate T D<T>();
public class A<T>
{
#pragma warning disable 0649
    private T _t;
    public ref T F()
    {
        return ref _t;
    }
}
public class B
{
    public static void F<T>(D<T> d, T t)
    {
        d();
    }
}
 
class Program
{
    static void Main()
    {
        var o = new A<int>();
        B.F(() => ref o.F(), 2);
        System.Console.WriteLine(o.F());
    }
}";
 
            CreateCompilation(source).VerifyDiagnostics(
                // (24,23): error CS8149: By-reference returns may only be used in methods that return by reference
                //         B.F(() => ref o.F(), 2);
                Diagnostic(ErrorCode.ERR_MustNotHaveRefReturn, "o.F()").WithLocation(24, 23)
                );
        }
 
        [Fact]
        [WorkItem(13206, "https://github.com/dotnet/roslyn/issues/13206")]
        public void Delegate_01()
        {
            var source =
@"public delegate ref T D<T>();
public class A<T>
{
#pragma warning disable 0649
    private T _t;
    public ref T F()
    {
        return ref _t;
    }
}
public class B
{
    public static void F<T>(D<T> d, T t)
    {
        d() = t;
    }
}
 
class Program
{
    static void Main()
    {
        var o = new A<int>();
        B.F(o.F, 2);
        System.Console.Write(o.F());
        B.F(new D<int>(o.F), 3);
        System.Console.Write(o.F());
    }
}";
 
            var v = CompileAndVerify(source, expectedOutput: "23");
        }
 
        [Fact]
        [WorkItem(13206, "https://github.com/dotnet/roslyn/issues/13206")]
        public void Delegate_02()
        {
            var source =
@"public delegate T D<T>();
public class A<T>
{
#pragma warning disable 0649
    private T _t;
    public ref T F()
    {
        return ref _t;
    }
}
public class B
{
    public static void F<T>(D<T> d, T t)
    {
        d();
    }
}
 
class Program
{
    static void Main()
    {
        var o = new A<int>();
        B.F(o.F, 2);
        System.Console.Write(o.F());
        B.F(new D<int>(o.F), 3);
        System.Console.Write(o.F());
    }
}";
 
            CreateCompilation(source, parseOptions: TestOptions.WithoutImprovedOverloadCandidates).VerifyDiagnostics(
                // (24,13): error CS8189: Ref mismatch between 'A<int>.F()' and delegate 'D<int>'
                //         B.F(o.F, 2);
                Diagnostic(ErrorCode.ERR_DelegateRefMismatch, "o.F").WithArguments("A<int>.F()", "D<int>").WithLocation(24, 13),
                // (26,24): error CS8189: Ref mismatch between 'A<int>.F()' and delegate 'D<int>'
                //         B.F(new D<int>(o.F), 3);
                Diagnostic(ErrorCode.ERR_DelegateRefMismatch, "o.F").WithArguments("A<int>.F()", "D<int>").WithLocation(26, 24)
                );
            CreateCompilation(source).VerifyDiagnostics(
                // (24,13): error CS8189: Ref mismatch between 'A<int>.F()' and delegate 'D<int>'
                //         B.F(o.F, 2);
                Diagnostic(ErrorCode.ERR_DelegateRefMismatch, "o.F").WithArguments("A<int>.F()", "D<int>").WithLocation(24, 13),
                // (26,24): error CS8189: Ref mismatch between 'A<int>.F()' and delegate 'D<int>'
                //         B.F(new D<int>(o.F), 3);
                Diagnostic(ErrorCode.ERR_DelegateRefMismatch, "o.F").WithArguments("A<int>.F()", "D<int>").WithLocation(26, 24)
                );
        }
 
        [Fact]
        [WorkItem(13206, "https://github.com/dotnet/roslyn/issues/13206")]
        public void Delegate_03()
        {
            var source =
@"public delegate ref T D<T>();
public class A<T>
{
    private T _t = default(T);
    public T F()
    {
        return _t;
    }
}
public class B
{
    public static void F<T>(D<T> d, T t)
    {
        d() = t;
    }
}
 
class Program
{
    static void Main()
    {
        var o = new A<int>();
        B.F(o.F, 2);
        System.Console.Write(o.F());
        B.F(new D<int>(o.F), 3);
        System.Console.Write(o.F());
    }
}";
 
            CreateCompilation(source, parseOptions: TestOptions.WithoutImprovedOverloadCandidates).VerifyDiagnostics(
                // (23,13): error CS8189: Ref mismatch between 'A<int>.F()' and delegate 'D<int>'
                //         B.F(o.F, 2);
                Diagnostic(ErrorCode.ERR_DelegateRefMismatch, "o.F").WithArguments("A<int>.F()", "D<int>").WithLocation(23, 13),
                // (25,24): error CS8189: Ref mismatch between 'A<int>.F()' and delegate 'D<int>'
                //         B.F(new D<int>(o.F), 3);
                Diagnostic(ErrorCode.ERR_DelegateRefMismatch, "o.F").WithArguments("A<int>.F()", "D<int>").WithLocation(25, 24)
                );
            CreateCompilation(source).VerifyDiagnostics(
                // (23,13): error CS8189: Ref mismatch between 'A<int>.F()' and delegate 'D<int>'
                //         B.F(o.F, 2);
                Diagnostic(ErrorCode.ERR_DelegateRefMismatch, "o.F").WithArguments("A<int>.F()", "D<int>").WithLocation(23, 13),
                // (25,24): error CS8189: Ref mismatch between 'A<int>.F()' and delegate 'D<int>'
                //         B.F(new D<int>(o.F), 3);
                Diagnostic(ErrorCode.ERR_DelegateRefMismatch, "o.F").WithArguments("A<int>.F()", "D<int>").WithLocation(25, 24)
                );
        }
 
        [Fact]
        [WorkItem(16947, "https://github.com/dotnet/roslyn/issues/16947")]
        public void Dynamic001()
        {
            var source =
@"
 
public class C 
{
    public void M() 
    {
        dynamic d = ""qq"";
 
        F(ref d);
    }
 
    public static ref dynamic F(ref dynamic d)
    {
        // this is ok
        F1(ref d.Length);
 
        // this is an error
        return ref d.Length;
    }
 
    public static void F1(ref dynamic d)
    {
    }
}
 
";
 
            CreateCompilationWithMscorlib461AndCSharp(source).VerifyEmitDiagnostics(
                // (18,20): error CS8156: An expression cannot be used in this context because it may not be returned by reference
                //         return ref d.Length;
                Diagnostic(ErrorCode.ERR_RefReturnLvalueExpected, "d.Length").WithLocation(18, 20)
            );
        }
 
        [Fact]
        [WorkItem(16947, "https://github.com/dotnet/roslyn/issues/16947")]
        public void Dynamic001a()
        {
            var source =
@"
 
public class C
{
    public static void Main()
    {
        dynamic d = ""qq"";
 
        System.Console.WriteLine(F(ref d));
    }
 
    public static dynamic F(ref dynamic d)
    {
        ref var temp1 = ref F1(ref d.Length);
        d = ""qwerty"";
        ref var temp2 = ref F1(ref d.Length);
 
        return temp1;
    }
 
    public static ref dynamic F1(ref dynamic d)
    {
        return ref d;
    }
}
 
";
 
            var comp = CreateCompilationWithMscorlib461AndCSharp(source, options: TestOptions.ReleaseExe);
 
            var v = CompileAndVerify(comp, verify: Verification.Fails, expectedOutput: "2");
 
            v.VerifyIL("C.F(ref dynamic)", @"
{
  // Code size      180 (0xb4)
  .maxstack  8
  .locals init (object& V_0, //temp1
                object V_1,
                object V_2)
  IL_0000:  ldsfld     ""System.Runtime.CompilerServices.CallSite<System.Func<System.Runtime.CompilerServices.CallSite, dynamic, dynamic>> C.<>o__1.<>p__0""
  IL_0005:  brtrue.s   IL_0036
  IL_0007:  ldc.i4.0
  IL_0008:  ldstr      ""Length""
  IL_000d:  ldtoken    ""C""
  IL_0012:  call       ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)""
  IL_0017:  ldc.i4.1
  IL_0018:  newarr     ""Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo""
  IL_001d:  dup
  IL_001e:  ldc.i4.0
  IL_001f:  ldc.i4.0
  IL_0020:  ldnull
  IL_0021:  call       ""Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo.Create(Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfoFlags, string)""
  IL_0026:  stelem.ref
  IL_0027:  call       ""System.Runtime.CompilerServices.CallSiteBinder Microsoft.CSharp.RuntimeBinder.Binder.GetMember(Microsoft.CSharp.RuntimeBinder.CSharpBinderFlags, string, System.Type, System.Collections.Generic.IEnumerable<Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo>)""
  IL_002c:  call       ""System.Runtime.CompilerServices.CallSite<System.Func<System.Runtime.CompilerServices.CallSite, dynamic, dynamic>> System.Runtime.CompilerServices.CallSite<System.Func<System.Runtime.CompilerServices.CallSite, dynamic, dynamic>>.Create(System.Runtime.CompilerServices.CallSiteBinder)""
  IL_0031:  stsfld     ""System.Runtime.CompilerServices.CallSite<System.Func<System.Runtime.CompilerServices.CallSite, dynamic, dynamic>> C.<>o__1.<>p__0""
  IL_0036:  ldsfld     ""System.Runtime.CompilerServices.CallSite<System.Func<System.Runtime.CompilerServices.CallSite, dynamic, dynamic>> C.<>o__1.<>p__0""
  IL_003b:  ldfld      ""System.Func<System.Runtime.CompilerServices.CallSite, dynamic, dynamic> System.Runtime.CompilerServices.CallSite<System.Func<System.Runtime.CompilerServices.CallSite, dynamic, dynamic>>.Target""
  IL_0040:  ldsfld     ""System.Runtime.CompilerServices.CallSite<System.Func<System.Runtime.CompilerServices.CallSite, dynamic, dynamic>> C.<>o__1.<>p__0""
  IL_0045:  ldarg.0
  IL_0046:  ldind.ref
  IL_0047:  callvirt   ""dynamic System.Func<System.Runtime.CompilerServices.CallSite, dynamic, dynamic>.Invoke(System.Runtime.CompilerServices.CallSite, dynamic)""
  IL_004c:  stloc.1
  IL_004d:  ldloca.s   V_1
  IL_004f:  call       ""ref dynamic C.F1(ref dynamic)""
  IL_0054:  stloc.0
  IL_0055:  ldarg.0
  IL_0056:  ldstr      ""qwerty""
  IL_005b:  stind.ref
  IL_005c:  ldsfld     ""System.Runtime.CompilerServices.CallSite<System.Func<System.Runtime.CompilerServices.CallSite, dynamic, dynamic>> C.<>o__1.<>p__1""
  IL_0061:  brtrue.s   IL_0092
  IL_0063:  ldc.i4.0
  IL_0064:  ldstr      ""Length""
  IL_0069:  ldtoken    ""C""
  IL_006e:  call       ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)""
  IL_0073:  ldc.i4.1
  IL_0074:  newarr     ""Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo""
  IL_0079:  dup
  IL_007a:  ldc.i4.0
  IL_007b:  ldc.i4.0
  IL_007c:  ldnull
  IL_007d:  call       ""Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo.Create(Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfoFlags, string)""
  IL_0082:  stelem.ref
  IL_0083:  call       ""System.Runtime.CompilerServices.CallSiteBinder Microsoft.CSharp.RuntimeBinder.Binder.GetMember(Microsoft.CSharp.RuntimeBinder.CSharpBinderFlags, string, System.Type, System.Collections.Generic.IEnumerable<Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo>)""
  IL_0088:  call       ""System.Runtime.CompilerServices.CallSite<System.Func<System.Runtime.CompilerServices.CallSite, dynamic, dynamic>> System.Runtime.CompilerServices.CallSite<System.Func<System.Runtime.CompilerServices.CallSite, dynamic, dynamic>>.Create(System.Runtime.CompilerServices.CallSiteBinder)""
  IL_008d:  stsfld     ""System.Runtime.CompilerServices.CallSite<System.Func<System.Runtime.CompilerServices.CallSite, dynamic, dynamic>> C.<>o__1.<>p__1""
  IL_0092:  ldsfld     ""System.Runtime.CompilerServices.CallSite<System.Func<System.Runtime.CompilerServices.CallSite, dynamic, dynamic>> C.<>o__1.<>p__1""
  IL_0097:  ldfld      ""System.Func<System.Runtime.CompilerServices.CallSite, dynamic, dynamic> System.Runtime.CompilerServices.CallSite<System.Func<System.Runtime.CompilerServices.CallSite, dynamic, dynamic>>.Target""
  IL_009c:  ldsfld     ""System.Runtime.CompilerServices.CallSite<System.Func<System.Runtime.CompilerServices.CallSite, dynamic, dynamic>> C.<>o__1.<>p__1""
  IL_00a1:  ldarg.0
  IL_00a2:  ldind.ref
  IL_00a3:  callvirt   ""dynamic System.Func<System.Runtime.CompilerServices.CallSite, dynamic, dynamic>.Invoke(System.Runtime.CompilerServices.CallSite, dynamic)""
  IL_00a8:  stloc.2
  IL_00a9:  ldloca.s   V_2
  IL_00ab:  call       ""ref dynamic C.F1(ref dynamic)""
  IL_00b0:  pop
  IL_00b1:  ldloc.0
  IL_00b2:  ldind.ref
  IL_00b3:  ret
}");
        }
 
        [Fact]
        [WorkItem(16947, "https://github.com/dotnet/roslyn/issues/16947")]
        public void Dynamic001b()
        {
            var source =
@"
 
public class C
{
    public static void Main()
    {
        dynamic d = ""qq"";
 
        System.Console.WriteLine(F(ref d));
        }
 
        public static dynamic F(ref dynamic d)
        {
            ref var temp1 = ref Test(arg2: ref F1(42, ref d.Length, 123), arg1: ref F1(42, ref d.Length, 123));
            d = ""qwerty"";
            ref var temp2 = ref Test(arg2: ref F1(42, ref d.Length, 123), arg1: ref F1(42, ref d.Length, 123));
 
            return temp1;
        }
 
        public static ref dynamic F1(in int arg1, ref dynamic d, in int arg2)
        {
            if (arg1 == arg2) throw null;
 
            return ref d;
        }
 
        public static ref dynamic Test(ref dynamic arg1, ref dynamic arg2)
        {
            return ref arg2;
        }
    }
";
 
            var comp = CreateCompilationWithMscorlib461AndCSharp(source, options: TestOptions.ReleaseExe);
 
            var v = CompileAndVerify(comp, verify: Verification.Fails, expectedOutput: "2");
        }
 
        [Fact]
        [WorkItem(16947, "https://github.com/dotnet/roslyn/issues/16947")]
        public void Dynamic002()
        {
            var source =
@"
 
public class C 
{
    public void M() 
    {
        dynamic d = ""qq"";
 
        F(ref d);
    }
 
    public static ref dynamic F(ref dynamic d)
    {
        // this is ok
        F1(ref d[0]);
 
        return ref d[0];
    }
 
    public static void F1(ref dynamic d)
    {
    }
}
 
";
 
            CreateCompilationWithMscorlib461AndCSharp(source).VerifyEmitDiagnostics(
                // (17,20): error CS8156: An expression cannot be used in this context because it may not be returned by reference
                //         return ref d[0];
                Diagnostic(ErrorCode.ERR_RefReturnLvalueExpected, "d[0]").WithLocation(17, 20)
            );
        }
 
        [Fact]
        [WorkItem(16947, "https://github.com/dotnet/roslyn/issues/16947")]
        public void Dynamic003()
        {
            var source =
@"
 
public class C 
{
    public void M() 
    {
        dynamic d = ""qq"";
 
        F(ref d);
    }
 
    public static ref dynamic F(ref dynamic d)
    {
        return ref G(ref d.Length);
    }
 
    public static ref dynamic G(ref dynamic d)
    {
        return ref d;
    }
}
 
";
 
            CreateCompilationWithMscorlib461AndCSharp(source).VerifyEmitDiagnostics(
                // (14,26): error CS8156: An expression cannot be used in this context because it may not be returned by reference
                //         return ref G(ref d.Length);
                Diagnostic(ErrorCode.ERR_RefReturnLvalueExpected, "d.Length").WithLocation(14, 26),
                // (14,20): error CS8347: Cannot use a result of 'C.G(ref dynamic)' in this context because it may expose variables referenced by parameter 'd' outside of their declaration scope
                //         return ref G(ref d.Length);
                Diagnostic(ErrorCode.ERR_EscapeCall, "G(ref d.Length)").WithArguments("C.G(ref dynamic)", "d").WithLocation(14, 20)
            );
        }
 
        [Fact]
        public void RefReturnVarianceDelegate()
        {
            var source = @"
using System;
 
delegate ref T RefFunc1<T>();
delegate ref T RefFunc2<in T>();
delegate ref T RefFunc3<out T>();
 
delegate ref Action<T> RefFunc1a<T>();
delegate ref Action<T> RefFunc2a<in T>();
delegate ref Action<T> RefFunc3a<out T>();
         
delegate ref Func<T> RefFunc1f<T>();
delegate ref Func<T> RefFunc2f<in T>();
delegate ref Func<T> RefFunc3f<out T>();
 
";
 
            CreateCompilationWithMscorlib461AndCSharp(source).VerifyEmitDiagnostics(
                // (6,10): error CS1961: Invalid variance: The type parameter 'T' must be invariantly valid on 'RefFunc3<T>.Invoke()'. 'T' is covariant.
                // delegate ref T RefFunc3<out T>();
                Diagnostic(ErrorCode.ERR_UnexpectedVariance, "ref T").WithArguments("RefFunc3<T>.Invoke()", "T", "covariant", "invariantly").WithLocation(6, 10),
                // (5,10): error CS1961: Invalid variance: The type parameter 'T' must be invariantly valid on 'RefFunc2<T>.Invoke()'. 'T' is contravariant.
                // delegate ref T RefFunc2<in T>();
                Diagnostic(ErrorCode.ERR_UnexpectedVariance, "ref T").WithArguments("RefFunc2<T>.Invoke()", "T", "contravariant", "invariantly").WithLocation(5, 10),
                // (14,10): error CS1961: Invalid variance: The type parameter 'T' must be invariantly valid on 'RefFunc3f<T>.Invoke()'. 'T' is covariant.
                // delegate ref Func<T> RefFunc3f<out T>();
                Diagnostic(ErrorCode.ERR_UnexpectedVariance, "ref Func<T>").WithArguments("RefFunc3f<T>.Invoke()", "T", "covariant", "invariantly").WithLocation(14, 10),
                // (13,10): error CS1961: Invalid variance: The type parameter 'T' must be invariantly valid on 'RefFunc2f<T>.Invoke()'. 'T' is contravariant.
                // delegate ref Func<T> RefFunc2f<in T>();
                Diagnostic(ErrorCode.ERR_UnexpectedVariance, "ref Func<T>").WithArguments("RefFunc2f<T>.Invoke()", "T", "contravariant", "invariantly").WithLocation(13, 10),
                // (10,10): error CS1961: Invalid variance: The type parameter 'T' must be invariantly valid on 'RefFunc3a<T>.Invoke()'. 'T' is covariant.
                // delegate ref Action<T> RefFunc3a<out T>();
                Diagnostic(ErrorCode.ERR_UnexpectedVariance, "ref Action<T>").WithArguments("RefFunc3a<T>.Invoke()", "T", "covariant", "invariantly").WithLocation(10, 10),
                // (9,10): error CS1961: Invalid variance: The type parameter 'T' must be invariantly valid on 'RefFunc2a<T>.Invoke()'. 'T' is contravariant.
                // delegate ref Action<T> RefFunc2a<in T>();
                Diagnostic(ErrorCode.ERR_UnexpectedVariance, "ref Action<T>").WithArguments("RefFunc2a<T>.Invoke()", "T", "contravariant", "invariantly").WithLocation(9, 10)
 
            );
        }
 
        [Fact]
        public void RefReturnVarianceMethod()
        {
            var source = @"
using System;
 
interface IM1<T> { ref T RefMethod(); }
interface IM2<in T> { ref T RefMethod(); }
interface IM3<out T> { ref T RefMethod(); }
 
interface IM1a<T> { ref Action<T> RefMethod(); }
interface IM2a<in T> { ref Action<T> RefMethod(); }
interface IM3a<out T> { ref Action<T> RefMethod(); }
 
interface IM1f<T> { ref Func<T> RefMethod(); }
interface IM2f<in T> { ref Func<T> RefMethod(); }
interface IM3f<out T> { ref Func<T> RefMethod(); }
 
";
 
            CreateCompilationWithMscorlib461AndCSharp(source).VerifyEmitDiagnostics(
                // (6,24): error CS1961: Invalid variance: The type parameter 'T' must be invariantly valid on 'IM3<T>.RefMethod()'. 'T' is covariant.
                // interface IM3<out T> { ref T RefMethod(); }
                Diagnostic(ErrorCode.ERR_UnexpectedVariance, "ref T").WithArguments("IM3<T>.RefMethod()", "T", "covariant", "invariantly").WithLocation(6, 24),
                // (10,25): error CS1961: Invalid variance: The type parameter 'T' must be invariantly valid on 'IM3a<T>.RefMethod()'. 'T' is covariant.
                // interface IM3a<out T> { ref Action<T> RefMethod(); }
                Diagnostic(ErrorCode.ERR_UnexpectedVariance, "ref Action<T>").WithArguments("IM3a<T>.RefMethod()", "T", "covariant", "invariantly").WithLocation(10, 25),
                // (9,24): error CS1961: Invalid variance: The type parameter 'T' must be invariantly valid on 'IM2a<T>.RefMethod()'. 'T' is contravariant.
                // interface IM2a<in T> { ref Action<T> RefMethod(); }
                Diagnostic(ErrorCode.ERR_UnexpectedVariance, "ref Action<T>").WithArguments("IM2a<T>.RefMethod()", "T", "contravariant", "invariantly").WithLocation(9, 24),
                // (13,24): error CS1961: Invalid variance: The type parameter 'T' must be invariantly valid on 'IM2f<T>.RefMethod()'. 'T' is contravariant.
                // interface IM2f<in T> { ref Func<T> RefMethod(); }
                Diagnostic(ErrorCode.ERR_UnexpectedVariance, "ref Func<T>").WithArguments("IM2f<T>.RefMethod()", "T", "contravariant", "invariantly").WithLocation(13, 24),
                // (14,25): error CS1961: Invalid variance: The type parameter 'T' must be invariantly valid on 'IM3f<T>.RefMethod()'. 'T' is covariant.
                // interface IM3f<out T> { ref Func<T> RefMethod(); }
                Diagnostic(ErrorCode.ERR_UnexpectedVariance, "ref Func<T>").WithArguments("IM3f<T>.RefMethod()", "T", "covariant", "invariantly").WithLocation(14, 25),
                // (5,23): error CS1961: Invalid variance: The type parameter 'T' must be invariantly valid on 'IM2<T>.RefMethod()'. 'T' is contravariant.
                // interface IM2<in T> { ref T RefMethod(); }
                Diagnostic(ErrorCode.ERR_UnexpectedVariance, "ref T").WithArguments("IM2<T>.RefMethod()", "T", "contravariant", "invariantly").WithLocation(5, 23)
 
            );
        }
 
        [Fact]
        public void RefReturnVarianceProperty()
        {
            var source = @"
using System;
 
interface IP1<T> { ref T RefProp{get;} }
interface IP2<in T> { ref T RefProp{get;} }
interface IP3<out T> { ref T RefProp{get;} }
 
interface IP1a<T> { ref Action<T> RefProp{get;} }
interface IP2a<in T> { ref Action<T> RefProp{get;} }
interface IP3a<out T> { ref Action<T> RefProp{get;} }
 
interface IP1f<T> { ref Func<T> RefProp{get;} }
interface IP2f<in T> { ref Func<T> RefProp{get;} }
interface IP3f<out T> { ref Func<T> RefProp{get;} }
 
";
 
            CreateCompilationWithMscorlib461AndCSharp(source).VerifyEmitDiagnostics(
                // (5,23): error CS1961: Invalid variance: The type parameter 'T' must be invariantly valid on 'IP2<T>.RefProp'. 'T' is contravariant.
                // interface IP2<in T> { ref T RefProp{get;} }
                Diagnostic(ErrorCode.ERR_UnexpectedVariance, "ref T").WithArguments("IP2<T>.RefProp", "T", "contravariant", "invariantly").WithLocation(5, 23),
                // (13,24): error CS1961: Invalid variance: The type parameter 'T' must be invariantly valid on 'IP2f<T>.RefProp'. 'T' is contravariant.
                // interface IP2f<in T> { ref Func<T> RefProp{get;} }
                Diagnostic(ErrorCode.ERR_UnexpectedVariance, "ref Func<T>").WithArguments("IP2f<T>.RefProp", "T", "contravariant", "invariantly").WithLocation(13, 24),
                // (9,24): error CS1961: Invalid variance: The type parameter 'T' must be invariantly valid on 'IP2a<T>.RefProp'. 'T' is contravariant.
                // interface IP2a<in T> { ref Action<T> RefProp{get;} }
                Diagnostic(ErrorCode.ERR_UnexpectedVariance, "ref Action<T>").WithArguments("IP2a<T>.RefProp", "T", "contravariant", "invariantly").WithLocation(9, 24),
                // (10,25): error CS1961: Invalid variance: The type parameter 'T' must be invariantly valid on 'IP3a<T>.RefProp'. 'T' is covariant.
                // interface IP3a<out T> { ref Action<T> RefProp{get;} }
                Diagnostic(ErrorCode.ERR_UnexpectedVariance, "ref Action<T>").WithArguments("IP3a<T>.RefProp", "T", "covariant", "invariantly").WithLocation(10, 25),
                // (14,25): error CS1961: Invalid variance: The type parameter 'T' must be invariantly valid on 'IP3f<T>.RefProp'. 'T' is covariant.
                // interface IP3f<out T> { ref Func<T> RefProp{get;} }
                Diagnostic(ErrorCode.ERR_UnexpectedVariance, "ref Func<T>").WithArguments("IP3f<T>.RefProp", "T", "covariant", "invariantly").WithLocation(14, 25),
                // (6,24): error CS1961: Invalid variance: The type parameter 'T' must be invariantly valid on 'IP3<T>.RefProp'. 'T' is covariant.
                // interface IP3<out T> { ref T RefProp{get;} }
                Diagnostic(ErrorCode.ERR_UnexpectedVariance, "ref T").WithArguments("IP3<T>.RefProp", "T", "covariant", "invariantly").WithLocation(6, 24)
 
            );
        }
 
        [Fact]
        public void RefReturnVarianceIndexer()
        {
            var source = @"
using System;
 
interface IP1<T> { ref T this[int i]{get;} }
interface IP2<in T> { ref T this[int i]{get;} }
interface IP3<out T> { ref T this[int i]{get;} }
 
interface IP1a<T> { ref Action<T> this[int i]{get;} }
interface IP2a<in T> { ref Action<T> this[int i]{get;} }
interface IP3a<out T> { ref Action<T> this[int i]{get;} }
 
interface IP1f<T> { ref Func<T> this[int i]{get;} }
interface IP2f<in T> { ref Func<T> this[int i]{get;} }
interface IP3f<out T> { ref Func<T> this[int i]{get;} }
 
";
 
            CreateCompilationWithMscorlib461AndCSharp(source).VerifyEmitDiagnostics(
                // (6,24): error CS1961: Invalid variance: The type parameter 'T' must be invariantly valid on 'IP3<T>.this[int]'. 'T' is covariant.
                // interface IP3<out T> { ref T this[int i]{get;} }
                Diagnostic(ErrorCode.ERR_UnexpectedVariance, "ref T").WithArguments("IP3<T>.this[int]", "T", "covariant", "invariantly").WithLocation(6, 24),
                // (5,23): error CS1961: Invalid variance: The type parameter 'T' must be invariantly valid on 'IP2<T>.this[int]'. 'T' is contravariant.
                // interface IP2<in T> { ref T this[int i]{get;} }
                Diagnostic(ErrorCode.ERR_UnexpectedVariance, "ref T").WithArguments("IP2<T>.this[int]", "T", "contravariant", "invariantly").WithLocation(5, 23),
                // (9,24): error CS1961: Invalid variance: The type parameter 'T' must be invariantly valid on 'IP2a<T>.this[int]'. 'T' is contravariant.
                // interface IP2a<in T> { ref Action<T> this[int i]{get;} }
                Diagnostic(ErrorCode.ERR_UnexpectedVariance, "ref Action<T>").WithArguments("IP2a<T>.this[int]", "T", "contravariant", "invariantly").WithLocation(9, 24),
                // (10,25): error CS1961: Invalid variance: The type parameter 'T' must be invariantly valid on 'IP3a<T>.this[int]'. 'T' is covariant.
                // interface IP3a<out T> { ref Action<T> this[int i]{get;} }
                Diagnostic(ErrorCode.ERR_UnexpectedVariance, "ref Action<T>").WithArguments("IP3a<T>.this[int]", "T", "covariant", "invariantly").WithLocation(10, 25),
                // (13,24): error CS1961: Invalid variance: The type parameter 'T' must be invariantly valid on 'IP2f<T>.this[int]'. 'T' is contravariant.
                // interface IP2f<in T> { ref Func<T> this[int i]{get;} }
                Diagnostic(ErrorCode.ERR_UnexpectedVariance, "ref Func<T>").WithArguments("IP2f<T>.this[int]", "T", "contravariant", "invariantly").WithLocation(13, 24),
                // (14,25): error CS1961: Invalid variance: The type parameter 'T' must be invariantly valid on 'IP3f<T>.this[int]'. 'T' is covariant.
                // interface IP3f<out T> { ref Func<T> this[int i]{get;} }
                Diagnostic(ErrorCode.ERR_UnexpectedVariance, "ref Func<T>").WithArguments("IP3f<T>.this[int]", "T", "covariant", "invariantly").WithLocation(14, 25)
 
            );
        }
 
        [Fact]
        public void RefMethodGroupConversionError()
        {
            var source = @"
using System;
 
class Program
{
    delegate ref T RefFunc1<T>();
 
    static void Main()
    {
        RefFunc1<object> f = M1;
        f() = 1;
 
        f = new RefFunc1<object>(M1);
        f() = 1;
    }
 
    static ref string M1() => ref new string[]{""qq""}[0];
}
 
";
 
            CreateCompilationWithMscorlib461AndCSharp(source, parseOptions: TestOptions.WithoutImprovedOverloadCandidates).VerifyEmitDiagnostics(
                // (10,30): error CS0407: 'string Program.M1()' has the wrong return type
                //         RefFunc1<object> f = M1;
                Diagnostic(ErrorCode.ERR_BadRetType, "M1").WithArguments("Program.M1()", "string"),
                // (13,34): error CS0407: 'string Program.M1()' has the wrong return type
                //         f = new RefFunc1<object>(M1);
                Diagnostic(ErrorCode.ERR_BadRetType, "M1").WithArguments("Program.M1()", "string").WithLocation(13, 34)
            );
            CreateCompilationWithMscorlib461AndCSharp(source).VerifyEmitDiagnostics(
                // (10,30): error CS0407: 'string Program.M1()' has the wrong return type
                //         RefFunc1<object> f = M1;
                Diagnostic(ErrorCode.ERR_BadRetType, "M1").WithArguments("Program.M1()", "string").WithLocation(10, 30),
                // (13,34): error CS0407: 'string Program.M1()' has the wrong return type
                //         f = new RefFunc1<object>(M1);
                Diagnostic(ErrorCode.ERR_BadRetType, "M1").WithArguments("Program.M1()", "string").WithLocation(13, 34)
            );
        }
 
        [Fact]
        public void RefMethodGroupConversionError_WithResolution()
        {
            var source = @"
class Base
{
    public static Base Instance = new Base();
}
 
class Derived1: Base
{
    public static new Derived1 Instance = new Derived1();
}
 
class Derived2: Derived1
{
}
 
class Program
{
    delegate ref TResult RefFunc1<TArg, TResult>(TArg arg);
 
    static void Main()
    {
        RefFunc1<Derived2, Base> f = M1;
        System.Console.WriteLine(f(null));
    }
 
    static ref Base M1(Base arg) => ref Base.Instance;
    static ref Derived1 M1(Derived1 arg) => ref Derived1.Instance;
}
 
";
 
            CreateCompilationWithMscorlib461AndCSharp(source, parseOptions: TestOptions.WithoutImprovedOverloadCandidates).VerifyEmitDiagnostics(
                // (22,38): error CS0407: 'Derived1 Program.M1(Derived1)' has the wrong return type
                //         RefFunc1<Derived2, Base> f = M1;
                Diagnostic(ErrorCode.ERR_BadRetType, "M1").WithArguments("Program.M1(Derived1)", "Derived1").WithLocation(22, 38)
            );
            CreateCompilationWithMscorlib461AndCSharp(source).VerifyEmitDiagnostics(
            );
        }
 
        [Fact]
        public void RefMethodGroupConversionNoError_WithResolution()
        {
            var source = @"
using System;
 
class Base
{
    public static Base Instance = new Base();
}
 
class Derived1 : Base
{
    public static new Derived1 Instance = new Derived1();
}
 
class Derived2 : Derived1
{
    public static new Derived2 Instance = new Derived2();
}
 
class Program
{
    delegate ref TResult RefFunc1<TArg, TResult>(TArg arg);
 
    static void Main()
    {
        RefFunc1<Derived2, Base> f = M1;
        System.Console.WriteLine(f(null));
    }
 
    static ref Base M1(Base arg) => throw null;
    static ref Base M1(Derived1 arg) => ref Base.Instance;
}
";
 
            CompileAndVerify(source, parseOptions: TestOptions.Regular, expectedOutput: "Base", verify: Verification.Passes);
        }
 
        [Fact]
        public void RefMethodGroupOverloadResolutionErr()
        {
            var source = @"
using System;
 
class Base
{
    public static Base Instance = new Base();
}
 
class Derived1: Base
{
    public static new Derived1 Instance = new Derived1();
}
 
class Derived2: Derived1
{
    public static new Derived2 Instance = new Derived2();
}
 
class Program
{
    delegate ref TResult RefFunc1<TArg, TResult>(TArg arg);
 
    static void Main()
    {
        Test(M1);
        Test(M3);
    }
 
    static ref Base M1(Derived1 arg) => ref Base.Instance;
    static ref Base M3(Derived2 arg) => ref Base.Instance;
 
    static void Test(RefFunc1<Derived2, Base> arg) => Console.WriteLine(arg);
    static void Test(RefFunc1<Derived2, Derived1> arg) => Console.WriteLine(arg);
}
 
";
 
            CreateCompilationWithMscorlib461AndCSharp(source, parseOptions: TestOptions.WithoutImprovedOverloadCandidates).VerifyEmitDiagnostics(
                // (25,9): error CS0121: The call is ambiguous between the following methods or properties: 'Program.Test(Program.RefFunc1<Derived2, Base>)' and 'Program.Test(Program.RefFunc1<Derived2, Derived1>)'
                //         Test(M1);
                Diagnostic(ErrorCode.ERR_AmbigCall, "Test").WithArguments("Program.Test(Program.RefFunc1<Derived2, Base>)", "Program.Test(Program.RefFunc1<Derived2, Derived1>)").WithLocation(25, 9),
                // (26,9): error CS0121: The call is ambiguous between the following methods or properties: 'Program.Test(Program.RefFunc1<Derived2, Base>)' and 'Program.Test(Program.RefFunc1<Derived2, Derived1>)'
                //         Test(M3);
                Diagnostic(ErrorCode.ERR_AmbigCall, "Test").WithArguments("Program.Test(Program.RefFunc1<Derived2, Base>)", "Program.Test(Program.RefFunc1<Derived2, Derived1>)").WithLocation(26, 9)
            );
            CreateCompilationWithMscorlib461AndCSharp(source).VerifyEmitDiagnostics(
            );
        }
 
        [Fact]
        public void RefMethodGroupOverloadResolution()
        {
            var source = @"
using System;
 
class Base
{
    public static Base Instance = new Base();
}
 
class Derived1: Base
{
    public static new Derived1 Instance = new Derived1();
}
 
class Derived2: Derived1
{
    public static new Derived2 Instance = new Derived2();
}
 
class Program
{
    delegate ref TResult RefFunc1<TArg, TResult>(TArg arg);
 
    static void Main()
    {
        Test(M2);
    }
 
    static ref Derived1 M2(Base arg) => ref Derived1.Instance;
 
    static void Test(RefFunc1<Derived2, Base> arg) => Console.WriteLine(arg);
    static void Test(RefFunc1<Derived2, Derived1> arg) => Console.WriteLine(arg);
}
 
";
 
            CompileAndVerify(source, parseOptions: TestOptions.Regular, expectedOutput: "Program+RefFunc1`2[Derived2,Derived1]", verify: Verification.Passes);
        }
 
        [Fact]
        public void RefLambdaOverloadResolution()
        {
            var source = @"
using System;
 
class Base
{
    public static Base Instance = new Base();
}
 
class Derived1: Base
{
    public static new Derived1 Instance = new Derived1();
}
 
class Derived2: Derived1
{
    public static new Derived2 Instance = new Derived2();
}
 
class Program
{
    delegate ref TResult RefFunc1<TArg, TResult>(TArg arg);
 
    static void Main()
    {
        Test((t)=> Base.Instance);
        Test((t)=> ref Base.Instance);
    }
 
    static void Test(RefFunc1<Derived1, Base> arg) => Console.WriteLine(arg);
    static void Test(Func<Derived1, Base> arg) => Console.WriteLine(arg);
}
 
";
 
            CompileAndVerify(source, parseOptions: TestOptions.Regular, expectedOutput: @"System.Func`2[Derived1,Base]
Program+RefFunc1`2[Derived1,Base]", verify: Verification.Passes);
        }
 
        [WorkItem(25024, "https://github.com/dotnet/roslyn/issues/25024")]
        [Fact]
        public void RefReturnDiscardLifetime()
        {
            var text = @"
    class Program
    {
        static bool flag = true;
 
        public static void Main()
        {
            if (flag)
            {
                ref var local1 = ref M1(out var _);
                ref var local2 = ref M1(out var _);
 
                local1 = 1;
                local2 = 2;
                System.Console.Write(local1 + local2);
            }
 
            if (flag)
            {
                ref var local1 = ref M1(out var _);
                ref var local2 = ref M1(out var _);
 
                local1 = 3;
                local2 = 4;
                System.Console.Write(local1 + local2);
            }
        }
 
        public static ref int M1(out int arg)
        {
            arg = 123;
            return ref arg;
        }
       
    }
";
 
            CompileAndVerify(text, expectedOutput: "37", parseOptions: TestOptions.Regular10, verify: Verification.Fails).VerifyIL("Program.Main()", @"
{
  // Code size       75 (0x4b)
  .maxstack  3
  .locals init (int& V_0, //local2
                int V_1,
                int V_2,
                int& V_3, //local2
                int V_4,
                int V_5)
  IL_0000:  ldsfld     ""bool Program.flag""
  IL_0005:  brfalse.s  IL_0025
  IL_0007:  ldloca.s   V_1
  IL_0009:  call       ""ref int Program.M1(out int)""
  IL_000e:  ldloca.s   V_2
  IL_0010:  call       ""ref int Program.M1(out int)""
  IL_0015:  stloc.0
  IL_0016:  dup
  IL_0017:  ldc.i4.1
  IL_0018:  stind.i4
  IL_0019:  ldloc.0
  IL_001a:  ldc.i4.2
  IL_001b:  stind.i4
  IL_001c:  ldind.i4
  IL_001d:  ldloc.0
  IL_001e:  ldind.i4
  IL_001f:  add
  IL_0020:  call       ""void System.Console.Write(int)""
  IL_0025:  ldsfld     ""bool Program.flag""
  IL_002a:  brfalse.s  IL_004a
  IL_002c:  ldloca.s   V_4
  IL_002e:  call       ""ref int Program.M1(out int)""
  IL_0033:  ldloca.s   V_5
  IL_0035:  call       ""ref int Program.M1(out int)""
  IL_003a:  stloc.3
  IL_003b:  dup
  IL_003c:  ldc.i4.3
  IL_003d:  stind.i4
  IL_003e:  ldloc.3
  IL_003f:  ldc.i4.4
  IL_0040:  stind.i4
  IL_0041:  ldind.i4
  IL_0042:  ldloc.3
  IL_0043:  ldind.i4
  IL_0044:  add
  IL_0045:  call       ""void System.Console.Write(int)""
  IL_004a:  ret
}");
        }
    }
}