File: CodeGen\CodeGenRefLocalTests.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.Linq;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.CSharp.Test.Utilities;
using Microsoft.CodeAnalysis.Test.Utilities;
using Roslyn.Test.Utilities;
using Xunit;
 
namespace Microsoft.CodeAnalysis.CSharp.UnitTests
{
    [CompilerTrait(CompilerFeature.RefLocalsReturns)]
    public class CodeGenRefLocalTests : CompilingTestBase
    {
        [Fact]
        public void RefReassignInArrayElement()
        {
            const string src = @"
using System;
class C
{
    void M()
    {
        object o = string.Empty;
        M2(o);
    }
    void M2(in object o)
    {
        o = ref (new object[1])[0];
        Console.WriteLine(o?.GetHashCode() ?? 5);
    }
}";
            var verifier = CompileAndVerify(src, verify: Verification.Fails);
            const string expectedIL = @"
{
  // Code size       36 (0x24)
  .maxstack  2
  IL_0000:  ldc.i4.1
  IL_0001:  newarr     ""object""
  IL_0006:  ldc.i4.0
  IL_0007:  readonly.
  IL_0009:  ldelema    ""object""
  IL_000e:  starg.s    V_1
  IL_0010:  ldarg.1
  IL_0011:  ldind.ref
  IL_0012:  dup
  IL_0013:  brtrue.s   IL_0019
  IL_0015:  pop
  IL_0016:  ldc.i4.5
  IL_0017:  br.s       IL_001e
  IL_0019:  callvirt   ""int object.GetHashCode()""
  IL_001e:  call       ""void System.Console.WriteLine(int)""
  IL_0023:  ret
}";
            verifier.VerifyIL("C.M2", expectedIL);
 
            // N.B. Even with PEVerify compat this generates unverifiable code.
            // Compat mode has no effect because it would generate a temp variable
            // which, if we assign to the in parameter, violates safety by allowing
            // a local to be returned outside of the method scope.
            verifier = CompileAndVerify(src,
                parseOptions: TestOptions.Regular.WithPEVerifyCompatFeature(),
                verify: Verification.Fails);
            verifier.VerifyIL("C.M2", expectedIL);
        }
 
        [Fact]
        public void ReassignmentFixed()
        {
            var verifier = CompileAndVerify(@"
using System;
class C
{
    unsafe static void Main()
    {
        int x = 5, y = 11;
        ref int rx = ref x;
        fixed (int* ptr = &(rx = ref y))
        {
            Console.WriteLine(*ptr);
            rx = ref *ptr;
            Console.WriteLine(rx);
            rx = ref ptr[0];
            Console.WriteLine(rx);
        }
    }
}", options: TestOptions.UnsafeReleaseExe,
verify: Verification.Fails,
expectedOutput: @"11
11
11");
            verifier.VerifyIL("C.Main", @"
{
  // Code size       34 (0x22)
  .maxstack  2
  .locals init (int V_0, //x
                int V_1, //y
                pinned int& V_2)
  IL_0000:  ldc.i4.5
  IL_0001:  stloc.0
  IL_0002:  ldc.i4.s   11
  IL_0004:  stloc.1
  IL_0005:  ldloca.s   V_1
  IL_0007:  stloc.2
  IL_0008:  ldloc.2
  IL_0009:  conv.u
  IL_000a:  dup
  IL_000b:  ldind.i4
  IL_000c:  call       ""void System.Console.WriteLine(int)""
  IL_0011:  dup
  IL_0012:  ldind.i4
  IL_0013:  call       ""void System.Console.WriteLine(int)""
  IL_0018:  ldind.i4
  IL_0019:  call       ""void System.Console.WriteLine(int)""
  IL_001e:  ldc.i4.0
  IL_001f:  conv.u
  IL_0020:  stloc.2
  IL_0021:  ret
}");
        }
 
        [Fact]
        public void ReassignmentInOut()
        {
            var verifier = CompileAndVerify(@"
using System;
class C
{
    static void Main()
    {
        int x = 1, y = 2;
        ref int rx = ref x;
        M(out (rx = ref y));
        Console.WriteLine(rx);
        Console.WriteLine(x);
        Console.WriteLine(y);
    }
    static void M(out int rx)
    {
        rx = 5;
    }
}", expectedOutput: @" 5
1
5");
        }
 
        [Fact]
        public void ReassignmentWithReorderParameters()
        {
            var verifier = CompileAndVerify(@"
using System;
class C
{
    static void Main()
    {
        int x1 = 5, x2 = 7;
        ref int rx1 = ref x2, rx2 = ref x2;
        M2(p2: (rx1 = ref x2), p1: (rx1 = ref x1));
    }
 
    static void M2(int p1, int p2)
    {
        Console.WriteLine(p1);
        Console.WriteLine(p2);
    }
}", expectedOutput: @"5
7");
            verifier.VerifyIL("C.Main", @"
{
  // Code size       14 (0xe)
  .maxstack  2
  .locals init (int V_0, //x1
                int V_1, //x2
                int V_2)
  IL_0000:  ldc.i4.5
  IL_0001:  stloc.0
  IL_0002:  ldc.i4.7
  IL_0003:  stloc.1
  IL_0004:  ldloc.1
  IL_0005:  stloc.2
  IL_0006:  ldloc.0
  IL_0007:  ldloc.2
  IL_0008:  call       ""void C.M2(int, int)""
  IL_000d:  ret
}");
        }
 
        [Fact]
        public void ReassignmentWithReorderRefParameters()
        {
            var verifier = CompileAndVerify(@"
using System;
class C
{
    static void Main()
    {
        int x1 = 5, x2 = 7;
        ref int rx1 = ref x2, rx2 = ref x2;
        M2(p2: ref (rx1 = ref x2), p1: ref (rx1 = ref x1));
    }
 
    static void M2(ref int p1, ref int p2)
    {
        Console.WriteLine(p1);
        Console.WriteLine(p2);
    }
}", expectedOutput: @"5
7");
            verifier.VerifyIL("C.Main", @"
{
  // Code size       16 (0x10)
  .maxstack  2
  .locals init (int V_0, //x1
                int V_1, //x2
                int& V_2)
  IL_0000:  ldc.i4.5
  IL_0001:  stloc.0
  IL_0002:  ldc.i4.7
  IL_0003:  stloc.1
  IL_0004:  ldloca.s   V_1
  IL_0006:  stloc.2
  IL_0007:  ldloca.s   V_0
  IL_0009:  ldloc.2
  IL_000a:  call       ""void C.M2(ref int, ref int)""
  IL_000f:  ret
}");
        }
 
        [Fact]
        public void InReassignmentWithConversion()
        {
            var verifier = CompileAndVerify(@"
class C
{
    void M(string s)
    {
        ref string rs = ref s;
        M2((rs = ref s));
    }
    void M2(in object o) {}
}");
            verifier.VerifyIL("C.M(string)", @"
{
  // Code size       18 (0x12)
  .maxstack  3
  .locals init (string& V_0, //rs
                object V_1)
  IL_0000:  ldarga.s   V_1
  IL_0002:  stloc.0
  IL_0003:  ldarg.0
  IL_0004:  ldarga.s   V_1
  IL_0006:  dup
  IL_0007:  stloc.0
  IL_0008:  ldind.ref
  IL_0009:  stloc.1
  IL_000a:  ldloca.s   V_1
  IL_000c:  call       ""void C.M2(in object)""
  IL_0011:  ret
}");
        }
 
        [Fact]
        public void RefExprNullPropagation()
        {
            var verifier = CompileAndVerify(@"
using System;
struct S : IDisposable
{
    public int F;
    public S(int f) => F = f;
    public void Dispose()
    {
        this.F++;
        Console.WriteLine(""Dispose"");
    }
}
 
class C
{
    public static void Main()
    {
        S s1 = new S(10);
        S s2 = new S(5);
        ref S rs = ref s1;
        (rs = ref s2).Dispose();
        Console.WriteLine(s1.F);
        Console.WriteLine(s2.F);
        M(ref s1, ref s2);
        Console.WriteLine(s1.F);
        Console.WriteLine(s2.F);
    }
 
    private static void M<T>(ref T t1, ref T t2) where T : IDisposable
    {
        (t2 = ref t1)?.Dispose();
    }
}", expectedOutput: @"
Dispose
10
6
Dispose
11
6");
            verifier.VerifyIL("C.Main", @"
{
  // Code size       78 (0x4e)
  .maxstack  2
  .locals init (S V_0, //s1
                S V_1) //s2
  IL_0000:  ldloca.s   V_0
  IL_0002:  ldc.i4.s   10
  IL_0004:  call       ""S..ctor(int)""
  IL_0009:  ldloca.s   V_1
  IL_000b:  ldc.i4.5
  IL_000c:  call       ""S..ctor(int)""
  IL_0011:  ldloca.s   V_1
  IL_0013:  call       ""void S.Dispose()""
  IL_0018:  ldloc.0
  IL_0019:  ldfld      ""int S.F""
  IL_001e:  call       ""void System.Console.WriteLine(int)""
  IL_0023:  ldloc.1
  IL_0024:  ldfld      ""int S.F""
  IL_0029:  call       ""void System.Console.WriteLine(int)""
  IL_002e:  ldloca.s   V_0
  IL_0030:  ldloca.s   V_1
  IL_0032:  call       ""void C.M<S>(ref S, ref S)""
  IL_0037:  ldloc.0
  IL_0038:  ldfld      ""int S.F""
  IL_003d:  call       ""void System.Console.WriteLine(int)""
  IL_0042:  ldloc.1
  IL_0043:  ldfld      ""int S.F""
  IL_0048:  call       ""void System.Console.WriteLine(int)""
  IL_004d:  ret
}");
            verifier.VerifyIL("C.M<T>", @"
{
  // Code size       50 (0x32)
  .maxstack  2
  .locals init (T V_0)
  IL_0000:  ldarg.0
  IL_0001:  dup
  IL_0002:  starg.s    V_1
  IL_0004:  ldloca.s   V_0
  IL_0006:  initobj    ""T""
  IL_000c:  ldloc.0
  IL_000d:  box        ""T""
  IL_0012:  brtrue.s   IL_0026
  IL_0014:  ldobj      ""T""
  IL_0019:  stloc.0
  IL_001a:  ldloca.s   V_0
  IL_001c:  ldloc.0
  IL_001d:  box        ""T""
  IL_0022:  brtrue.s   IL_0026
  IL_0024:  pop
  IL_0025:  ret
  IL_0026:  constrained. ""T""
  IL_002c:  callvirt   ""void System.IDisposable.Dispose()""
  IL_0031:  ret
}");
        }
 
        [Fact]
        public void RefExprUnaryPlus()
        {
            var verifier = CompileAndVerify(@"
using System;
class C
{
    public static void Main()
    {
        int x = 10;
        int y = 5;
        ref int rx = ref x;
        Console.WriteLine((rx = ref y)++);
        Console.WriteLine(rx);
        Console.WriteLine(x);
        Console.WriteLine(y);
    }
}", expectedOutput: @"5
6
10
6");
            verifier.VerifyIL("C.Main", @"
{
  // Code size       40 (0x28)
  .maxstack  4
  .locals init (int V_0, //x
                int V_1, //y
                int V_2)
  IL_0000:  ldc.i4.s   10
  IL_0002:  stloc.0
  IL_0003:  ldc.i4.5
  IL_0004:  stloc.1
  IL_0005:  ldloca.s   V_1
  IL_0007:  dup
  IL_0008:  dup
  IL_0009:  ldind.i4
  IL_000a:  stloc.2
  IL_000b:  ldloc.2
  IL_000c:  ldc.i4.1
  IL_000d:  add
  IL_000e:  stind.i4
  IL_000f:  ldloc.2
  IL_0010:  call       ""void System.Console.WriteLine(int)""
  IL_0015:  ldind.i4
  IL_0016:  call       ""void System.Console.WriteLine(int)""
  IL_001b:  ldloc.0
  IL_001c:  call       ""void System.Console.WriteLine(int)""
  IL_0021:  ldloc.1
  IL_0022:  call       ""void System.Console.WriteLine(int)""
  IL_0027:  ret
}");
        }
 
        [Fact]
        public void RefLocalFor()
        {
            CompileAndVerify(@"
using System;
class C
{
    class LinkedList
    {
        public int Value;
        public LinkedList Next;
    }
    public static void Main()
    {
        var list = new LinkedList() { Value = 0,
            Next = new LinkedList() { Value = 0,
                Next = new LinkedList() { Value = 0, Next = null } } };
 
        for (ref var cur = ref list; cur != null; cur = ref cur.Next)
        {
            Console.WriteLine(cur.Value);
        }
        for (ref var cur = ref list; cur != null; cur = ref cur.Next)
        {
            cur.Value++;
        }
        for (ref readonly var cur = ref list; cur != null; cur = ref cur.Next)
        {
            Console.WriteLine(cur.Value);
        }
    }
}", expectedOutput: @"0
0
0
1
1
1");
        }
 
        [Fact]
        public void RefLocalForeach()
        {
            CompileAndVerify(@"
using System;
class C
{
    public static void Main()
    {
        var re = new RefEnumerable();
        foreach (ref var x in re)
        {
            Console.WriteLine(x);
        }
        foreach (ref var x in re)
        {
            x++;
        }
        foreach (ref readonly var x in re)
        {
            Console.WriteLine(x);
        }
    }
}
 
class RefEnumerable
{
    private readonly int[] _arr = new int[5];
    public StructEnum GetEnumerator() => new StructEnum(_arr);
 
    public struct StructEnum
    {
        private readonly int[] _arr;
        private int _current;
        public StructEnum(int[] arr)
        {
            _arr = arr;
            _current = -1;
        }
        public ref int Current => ref _arr[_current];
        public bool MoveNext() => ++_current != _arr.Length;
    }
}", expectedOutput: @"0
0
0
0
0
1
1
1
1
1");
        }
 
        [Fact]
        public void RefReassignDifferentTupleNames()
        {
            var comp = CreateCompilation(@"
using System;
class C
{
    public static void Main()
    {
        var t = (x: 0, y: 0);
        ref (int x, int y) rt = ref t;
 
        var t2 = (a: 2, b: 2);
        rt = ref t2;
 
        Console.Write(rt.x);
        Console.Write(rt.y);
    }
}", options: TestOptions.ReleaseExe);
 
            CompileAndVerify(comp, expectedOutput: "22");
        }
 
        [Fact]
        public void RefReassignRefExpressions()
        {
            var comp = CompileAndVerify(@"
using System;
class C
{
    static readonly int _ro = 42;
    static int _rw = 42;
 
    static void Main()
    {
        ref readonly var rro = ref _ro;
        ref var rrw = ref _rw;
 
        Console.WriteLine(rro);
        Console.WriteLine(rrw);
 
        rrw++;
        rro = ref (rro = ref rrw);
        rrw = ref (rrw = ref rrw);
 
        Console.WriteLine(rro);
        Console.WriteLine(rrw);
        Console.WriteLine(_ro);
    }
}", verify: Verification.Fails, expectedOutput: @"42
42
43
43
42");
        }
 
        [Fact]
        public void RefReassignParamByVal()
        {
            var comp = CompileAndVerify(@"
using System;
class C
{
    static void Main()
    {
        int x = 0;
        ref int rx = ref x;
        int y = 5;
        Console.WriteLine(rx);
        M(rx = ref y);
        Console.WriteLine(rx);
    }
 
    static void M(int p)
    {
        Console.WriteLine(p);
        p++;
        Console.WriteLine(p);
    }
}", expectedOutput: @"0
5
6
5
");
        }
 
        [Fact]
        public void RefReassignParamIn()
        {
            var comp = CompileAndVerify(@"
using System;
class C
{
    static void Main()
    {
        int x = 0;
        ref int rx = ref x;
        int y = 5;
        Console.WriteLine(rx);
        M(rx = ref y);
        Console.WriteLine(rx);
    }
    static void M(in int p)
    {
        Console.WriteLine(p);
    }
}", expectedOutput: @"0
5
5");
            comp.VerifyIL("C.Main", @"
{
  // Code size       27 (0x1b)
  .maxstack  2
  .locals init (int V_0, //x
                int V_1) //y
  IL_0000:  ldc.i4.0
  IL_0001:  stloc.0
  IL_0002:  ldloca.s   V_0
  IL_0004:  ldc.i4.5
  IL_0005:  stloc.1
  IL_0006:  ldind.i4
  IL_0007:  call       ""void System.Console.WriteLine(int)""
  IL_000c:  ldloca.s   V_1
  IL_000e:  dup
  IL_000f:  call       ""void C.M(in int)""
  IL_0014:  ldind.i4
  IL_0015:  call       ""void System.Console.WriteLine(int)""
  IL_001a:  ret
}");
        }
 
        [Fact]
        public void RefReassignParamInConversion()
        {
            var comp = CompileAndVerify(@"
using System;
class C
{
    static void Main()
    {
        int x = 0;
        ref int rx = ref x;
        int y = 5;
        Console.WriteLine(rx);
        M(rx = ref y);
        Console.WriteLine(rx);
    }
    static void M(in long p)
    {
        Console.WriteLine(p);
    }
}", expectedOutput: @"0
5
5");
            comp.VerifyIL("C.Main", @"
{
  // Code size       32 (0x20)
  .maxstack  2
  .locals init (int V_0, //x
                int V_1, //y
                long V_2)
  IL_0000:  ldc.i4.0
  IL_0001:  stloc.0
  IL_0002:  ldloca.s   V_0
  IL_0004:  ldc.i4.5
  IL_0005:  stloc.1
  IL_0006:  ldind.i4
  IL_0007:  call       ""void System.Console.WriteLine(int)""
  IL_000c:  ldloca.s   V_1
  IL_000e:  dup
  IL_000f:  ldind.i4
  IL_0010:  conv.i8
  IL_0011:  stloc.2
  IL_0012:  ldloca.s   V_2
  IL_0014:  call       ""void C.M(in long)""
  IL_0019:  ldind.i4
  IL_001a:  call       ""void System.Console.WriteLine(int)""
  IL_001f:  ret
}");
        }
 
        [Fact]
        public void RefReassignField()
        {
            var comp = CompileAndVerify(@"
using System;
struct S
{
    public int X;
    public S(int x) => X = x;
}
class C
{
    static void Main()
    {
        S s1 = new S(0);
        S s2 = new S(5);
        ref S rs = ref s1;
        Console.WriteLine(rs.X);
        rs.X++;
        Console.WriteLine(rs.X);
        Console.WriteLine((rs = ref s2).X++);
        rs.X++;
        Console.WriteLine(rs.X);
        Console.WriteLine(s1.X);
        Console.WriteLine(s2.X);
    }
}", expectedOutput: @"0
1
5
7
1
7");
            comp.VerifyIL("C.Main", @"
{
  // Code size      115 (0x73)
  .maxstack  4
  .locals init (S V_0, //s1
                S V_1, //s2
                int V_2)
  IL_0000:  ldloca.s   V_0
  IL_0002:  ldc.i4.0
  IL_0003:  call       ""S..ctor(int)""
  IL_0008:  ldloca.s   V_1
  IL_000a:  ldc.i4.5
  IL_000b:  call       ""S..ctor(int)""
  IL_0010:  ldloca.s   V_0
  IL_0012:  dup
  IL_0013:  ldfld      ""int S.X""
  IL_0018:  call       ""void System.Console.WriteLine(int)""
  IL_001d:  dup
  IL_001e:  ldflda     ""int S.X""
  IL_0023:  dup
  IL_0024:  ldind.i4
  IL_0025:  ldc.i4.1
  IL_0026:  add
  IL_0027:  stind.i4
  IL_0028:  ldfld      ""int S.X""
  IL_002d:  call       ""void System.Console.WriteLine(int)""
  IL_0032:  ldloca.s   V_1
  IL_0034:  dup
  IL_0035:  ldflda     ""int S.X""
  IL_003a:  dup
  IL_003b:  ldind.i4
  IL_003c:  stloc.2
  IL_003d:  ldloc.2
  IL_003e:  ldc.i4.1
  IL_003f:  add
  IL_0040:  stind.i4
  IL_0041:  ldloc.2
  IL_0042:  call       ""void System.Console.WriteLine(int)""
  IL_0047:  dup
  IL_0048:  ldflda     ""int S.X""
  IL_004d:  dup
  IL_004e:  ldind.i4
  IL_004f:  ldc.i4.1
  IL_0050:  add
  IL_0051:  stind.i4
  IL_0052:  ldfld      ""int S.X""
  IL_0057:  call       ""void System.Console.WriteLine(int)""
  IL_005c:  ldloc.0
  IL_005d:  ldfld      ""int S.X""
  IL_0062:  call       ""void System.Console.WriteLine(int)""
  IL_0067:  ldloc.1
  IL_0068:  ldfld      ""int S.X""
  IL_006d:  call       ""void System.Console.WriteLine(int)""
  IL_0072:  ret
}");
        }
 
        [Fact]
        public void RefReassignFieldReadonly()
        {
            var comp = CompileAndVerify(@"
using System;
struct S
{
    public readonly int X;
    public S(int x) => X = x;
}
class C
{
    static void Main()
    {
        S s1 = new S(0);
        S s2 = new S(5);
        ref S rs = ref s1;
        Console.WriteLine(rs.X);
        rs = new S(rs.X + 1);
        Console.WriteLine(rs.X);
        Console.WriteLine((rs = ref s2).X);
        rs = new S(rs.X + 1);
        Console.WriteLine(rs.X);
        Console.WriteLine(s1.X);
        Console.WriteLine(s2.X);
    }
}", expectedOutput: @"0
1
5
6
1
6");
            comp.VerifyIL("C.Main", @"
{
  // Code size      127 (0x7f)
  .maxstack  3
  .locals init (S V_0, //s1
                S V_1, //s2
                S& V_2) //rs
  IL_0000:  ldloca.s   V_0
  IL_0002:  ldc.i4.0
  IL_0003:  call       ""S..ctor(int)""
  IL_0008:  ldloca.s   V_1
  IL_000a:  ldc.i4.5
  IL_000b:  call       ""S..ctor(int)""
  IL_0010:  ldloca.s   V_0
  IL_0012:  stloc.2
  IL_0013:  ldloc.2
  IL_0014:  ldfld      ""int S.X""
  IL_0019:  call       ""void System.Console.WriteLine(int)""
  IL_001e:  ldloc.2
  IL_001f:  ldloc.2
  IL_0020:  ldfld      ""int S.X""
  IL_0025:  ldc.i4.1
  IL_0026:  add
  IL_0027:  newobj     ""S..ctor(int)""
  IL_002c:  stobj      ""S""
  IL_0031:  ldloc.2
  IL_0032:  ldfld      ""int S.X""
  IL_0037:  call       ""void System.Console.WriteLine(int)""
  IL_003c:  ldloca.s   V_1
  IL_003e:  dup
  IL_003f:  stloc.2
  IL_0040:  ldfld      ""int S.X""
  IL_0045:  call       ""void System.Console.WriteLine(int)""
  IL_004a:  ldloc.2
  IL_004b:  ldloc.2
  IL_004c:  ldfld      ""int S.X""
  IL_0051:  ldc.i4.1
  IL_0052:  add
  IL_0053:  newobj     ""S..ctor(int)""
  IL_0058:  stobj      ""S""
  IL_005d:  ldloc.2
  IL_005e:  ldfld      ""int S.X""
  IL_0063:  call       ""void System.Console.WriteLine(int)""
  IL_0068:  ldloc.0
  IL_0069:  ldfld      ""int S.X""
  IL_006e:  call       ""void System.Console.WriteLine(int)""
  IL_0073:  ldloc.1
  IL_0074:  ldfld      ""int S.X""
  IL_0079:  call       ""void System.Console.WriteLine(int)""
  IL_007e:  ret
}");
        }
 
        [Fact]
        public void RefReassignFieldRefReadonly()
        {
            var comp = CompileAndVerify(@"
using System;
struct S
{
    public int X;
    public S(int x) => X = x;
}
class C
{
    static void Main()
    {
        S s1 = new S(0);
        S s2 = new S(5);
        ref readonly S rs = ref s1;
        Console.WriteLine(rs.X);
        Console.WriteLine((rs = ref s2).X);
        Console.WriteLine(rs.X);
    }
}", expectedOutput: @"0
5
5");
            comp.VerifyIL("C.Main", @"
{
  // Code size       56 (0x38)
  .maxstack  2
  .locals init (S V_0, //s1
                S V_1, //s2
                S& V_2) //rs
  IL_0000:  ldloca.s   V_0
  IL_0002:  ldc.i4.0
  IL_0003:  call       ""S..ctor(int)""
  IL_0008:  ldloca.s   V_1
  IL_000a:  ldc.i4.5
  IL_000b:  call       ""S..ctor(int)""
  IL_0010:  ldloca.s   V_0
  IL_0012:  stloc.2
  IL_0013:  ldloc.2
  IL_0014:  ldfld      ""int S.X""
  IL_0019:  call       ""void System.Console.WriteLine(int)""
  IL_001e:  ldloca.s   V_1
  IL_0020:  dup
  IL_0021:  stloc.2
  IL_0022:  ldfld      ""int S.X""
  IL_0027:  call       ""void System.Console.WriteLine(int)""
  IL_002c:  ldloc.2
  IL_002d:  ldfld      ""int S.X""
  IL_0032:  call       ""void System.Console.WriteLine(int)""
  IL_0037:  ret
}");
        }
 
        [Fact]
        public void RefReadonlyStackSchedule()
        {
            var comp = CompileAndVerify(@"
using System;
struct S
{
    public int X;
    public S(int x) => X = x;
    public void AddOne() => X++;
}
class C
{
    static void Main()
    {
        S s1 = new S(5);
        ref readonly S rs = ref s1;
        rs.AddOne();
        Console.WriteLine(s1.X);
    }
}", expectedOutput: "5");
        }
 
        [Fact]
        public void RefReassignCall()
        {
            var comp = CompileAndVerify(@"
using System;
struct S
{
    public int X;
    public S(int x) => X = x;
    public void AddOne() => X++;
}
class C
{
    static void Main()
    {
        S s1 = new S(0);
        S s2 = new S(5);
        ref S rs = ref s1;
        (rs = ref s2).AddOne();
        Console.WriteLine(rs.X);
        Console.WriteLine(s1.X);
        Console.WriteLine(s2.X);
 
        ref readonly S rs2 = ref s1;
        (rs2 = ref s2).AddOne();
        Console.WriteLine(rs.X);
        Console.WriteLine(s1.X);
        Console.WriteLine(s2.X);
    }
}"
, expectedOutput: @"6
0
6
6
0
6"
);
            comp.VerifyIL("C.Main", @"
{
  // Code size      110 (0x6e)
  .maxstack  3
  .locals init (S V_0, //s1
                S V_1, //s2
                S& V_2, //rs2
                S V_3)
  IL_0000:  ldloca.s   V_0
  IL_0002:  ldc.i4.0
  IL_0003:  call       ""S..ctor(int)""
  IL_0008:  ldloca.s   V_1
  IL_000a:  ldc.i4.5
  IL_000b:  call       ""S..ctor(int)""
  IL_0010:  ldloca.s   V_1
  IL_0012:  dup
  IL_0013:  call       ""void S.AddOne()""
  IL_0018:  dup
  IL_0019:  ldfld      ""int S.X""
  IL_001e:  call       ""void System.Console.WriteLine(int)""
  IL_0023:  ldloc.0
  IL_0024:  ldfld      ""int S.X""
  IL_0029:  call       ""void System.Console.WriteLine(int)""
  IL_002e:  ldloc.1
  IL_002f:  ldfld      ""int S.X""
  IL_0034:  call       ""void System.Console.WriteLine(int)""
  IL_0039:  ldloca.s   V_0
  IL_003b:  stloc.2
  IL_003c:  ldloca.s   V_1
  IL_003e:  dup
  IL_003f:  stloc.2
  IL_0040:  ldobj      ""S""
  IL_0045:  stloc.3
  IL_0046:  ldloca.s   V_3
  IL_0048:  call       ""void S.AddOne()""
  IL_004d:  ldfld      ""int S.X""
  IL_0052:  call       ""void System.Console.WriteLine(int)""
  IL_0057:  ldloc.0
  IL_0058:  ldfld      ""int S.X""
  IL_005d:  call       ""void System.Console.WriteLine(int)""
  IL_0062:  ldloc.1
  IL_0063:  ldfld      ""int S.X""
  IL_0068:  call       ""void System.Console.WriteLine(int)""
  IL_006d:  ret
}");
        }
 
        [Fact]
        public void RefReassignTernary()
        {
            var comp = CompileAndVerify(@"
using System;
class C
{
    static void Main()
    {
        int x = 0;
        ref int r1 = ref x;
        Console.WriteLine(r1);
        int y = 2;
        int z = 3;
        (r1 = ref string.Empty.Length == 0
            ? ref y
            : ref z) = 4;
        Console.WriteLine(x);
        Console.WriteLine(r1);
        Console.WriteLine(y);
        Console.WriteLine(z);
    }
}", expectedOutput: @"0
0
4
4
3");
        }
 
        [Fact]
        public void RefReassignTernaryParam()
        {
            var comp = CompileAndVerify(@"
using System;
class C
{
    static void Main()
    {
        int x = 1, y = 2;
        ref int rx = ref x;
        M(ref (rx = ref (x == 0 ? ref x : ref y)));
        Console.WriteLine(rx);
        Console.WriteLine(x);
        Console.WriteLine(y);
    }
 
    static void M(ref int p)
    {
        Console.WriteLine(p++);
    }
}", expectedOutput: @"2
3
1
3");
            comp.VerifyIL("C.Main", @"
{
  // Code size       38 (0x26)
  .maxstack  2
  .locals init (int V_0, //x
                int V_1) //y
  IL_0000:  ldc.i4.1
  IL_0001:  stloc.0
  IL_0002:  ldc.i4.2
  IL_0003:  stloc.1
  IL_0004:  ldloc.0
  IL_0005:  brfalse.s  IL_000b
  IL_0007:  ldloca.s   V_1
  IL_0009:  br.s       IL_000d
  IL_000b:  ldloca.s   V_0
  IL_000d:  dup
  IL_000e:  call       ""void C.M(ref int)""
  IL_0013:  ldind.i4
  IL_0014:  call       ""void System.Console.WriteLine(int)""
  IL_0019:  ldloc.0
  IL_001a:  call       ""void System.Console.WriteLine(int)""
  IL_001f:  ldloc.1
  IL_0020:  call       ""void System.Console.WriteLine(int)""
  IL_0025:  ret
}");
        }
 
        [Fact]
        public void RefReassignFor()
        {
            var comp = CompileAndVerify(@"
using System;
class C
{
    static void Main()
    {
        int[] arr = new int[] { 1, 2, 3, 4, 5 };
        int i = 0;
        ref int r = ref arr[i]; 
        for (;i < 4; r = ref arr[++i])
        {
            Console.WriteLine(i);
            Console.WriteLine(r);
        }
    }
}", expectedOutput: @"0
1
1
2
2
3
3
4");
        }
 
        [Fact]
        public void AssignInMethodCall()
        {
            var comp = CompileAndVerify(@"
using System;
class C
{
    static void Main()
    {
        int a = 0;
        int b = 2;
 
        ref int r1 = ref a;
        ref int r2 = ref a;
        ref int r3 = ref a;
 
        M(ref r1 = ref r2 = ref r3 = ref b);
        Console.WriteLine(b);
        Console.WriteLine(r1);
        Console.WriteLine(r2);
        Console.WriteLine(r3);
    }
 
    static void M(ref int p)
    {
        Console.WriteLine(p);
        p++;
        Console.WriteLine(p);
    }
}", expectedOutput: @"2
3
3
3
3
3");
        }
 
        [Fact]
        public void CompoundRefAssignIsLValue()
        {
            var comp = CompileAndVerify(@"
using System;
class C
{
    static void Main()
    {
        int a = 0;
        ref int r1 = ref a;
        ref int r2 = ref a;
        ref int r3 = ref a;
        Console.WriteLine(r1);
        Console.WriteLine(r2);
        Console.WriteLine(r3);
 
        int b = 2;
        (r1 = ref r2 = ref r3 = ref b) = 3;
        Console.WriteLine(r1);
        Console.WriteLine(r2);
        Console.WriteLine(r3);
    }
}", expectedOutput: @"0
0
0
3
3
3");
            comp.VerifyIL(@"C.Main", @"
{
  // Code size       62 (0x3e)
  .maxstack  3
  .locals init (int V_0, //a
                int& V_1, //r2
                int& V_2, //r3
                int V_3) //b
  IL_0000:  ldc.i4.0
  IL_0001:  stloc.0
  IL_0002:  ldloca.s   V_0
  IL_0004:  ldloca.s   V_0
  IL_0006:  stloc.1
  IL_0007:  ldloca.s   V_0
  IL_0009:  stloc.2
  IL_000a:  ldind.i4
  IL_000b:  call       ""void System.Console.WriteLine(int)""
  IL_0010:  ldloc.1
  IL_0011:  ldind.i4
  IL_0012:  call       ""void System.Console.WriteLine(int)""
  IL_0017:  ldloc.2
  IL_0018:  ldind.i4
  IL_0019:  call       ""void System.Console.WriteLine(int)""
  IL_001e:  ldc.i4.2
  IL_001f:  stloc.3
  IL_0020:  ldloca.s   V_3
  IL_0022:  dup
  IL_0023:  stloc.2
  IL_0024:  dup
  IL_0025:  stloc.1
  IL_0026:  dup
  IL_0027:  ldc.i4.3
  IL_0028:  stind.i4
  IL_0029:  ldind.i4
  IL_002a:  call       ""void System.Console.WriteLine(int)""
  IL_002f:  ldloc.1
  IL_0030:  ldind.i4
  IL_0031:  call       ""void System.Console.WriteLine(int)""
  IL_0036:  ldloc.2
  IL_0037:  ldind.i4
  IL_0038:  call       ""void System.Console.WriteLine(int)""
  IL_003d:  ret
}");
        }
 
        [Fact]
        public void CompoundRefAssign()
        {
            var comp = CompileAndVerify(@"
using System;
class C
{
    static void Main()
    {
        int a = 0;
        ref int r1 = ref a;
        ref int r2 = ref a;
        ref int r3 = ref a;
        Console.WriteLine(r1);
        Console.WriteLine(r2);
        Console.WriteLine(r3);
 
        int b = 2;
        r1 = ref r2 = ref r3 = ref b;
        Console.WriteLine(r1);
        Console.WriteLine(r2);
        Console.WriteLine(r3);
    }
}", expectedOutput: @"0
0
0
2
2
2");
            comp.VerifyIL("C.Main", @"
{
  // Code size       59 (0x3b)
  .maxstack  2
  .locals init (int V_0, //a
                int& V_1, //r2
                int& V_2, //r3
                int V_3) //b
  IL_0000:  ldc.i4.0
  IL_0001:  stloc.0
  IL_0002:  ldloca.s   V_0
  IL_0004:  ldloca.s   V_0
  IL_0006:  stloc.1
  IL_0007:  ldloca.s   V_0
  IL_0009:  stloc.2
  IL_000a:  ldind.i4
  IL_000b:  call       ""void System.Console.WriteLine(int)""
  IL_0010:  ldloc.1
  IL_0011:  ldind.i4
  IL_0012:  call       ""void System.Console.WriteLine(int)""
  IL_0017:  ldloc.2
  IL_0018:  ldind.i4
  IL_0019:  call       ""void System.Console.WriteLine(int)""
  IL_001e:  ldc.i4.2
  IL_001f:  stloc.3
  IL_0020:  ldloca.s   V_3
  IL_0022:  dup
  IL_0023:  stloc.2
  IL_0024:  dup
  IL_0025:  stloc.1
  IL_0026:  ldind.i4
  IL_0027:  call       ""void System.Console.WriteLine(int)""
  IL_002c:  ldloc.1
  IL_002d:  ldind.i4
  IL_002e:  call       ""void System.Console.WriteLine(int)""
  IL_0033:  ldloc.2
  IL_0034:  ldind.i4
  IL_0035:  call       ""void System.Console.WriteLine(int)""
  IL_003a:  ret
}");
        }
 
        [Fact]
        public void RefReassignIn()
        {
            var comp = CompileAndVerify(@"
using System;
 
class C
{
    static int x = 0;
    static int y = 0;
 
    static void Main()
    {
        M(in x);
    }
 
    static void M(in int rx)
    {
        Console.WriteLine(x);
        Console.WriteLine(rx);
        x++;
        Console.WriteLine(x);
        Console.WriteLine(rx);
 
        rx = ref y;
        Console.WriteLine(x);
        Console.WriteLine(y);
        Console.WriteLine(rx);
        y++;
        Console.WriteLine(x);
        Console.WriteLine(y);
        Console.WriteLine(rx);
    }
}", expectedOutput: @"0
0
1
1
1
0
0
1
1
1");
        }
 
        [Fact]
        public void RefReassignOut()
        {
            var comp = CompileAndVerify(@"
using System;
 
class C
{
    static int x = 0;
    static int y = 0;
 
    static void Main()
    {
        int z;
        M(out z);
        Console.WriteLine(z);
    }
 
    static void M(out int rx)
    {
        rx = 0;
        rx = ref x;
        Console.WriteLine(x);
        rx++;
        Console.WriteLine(x);
        Console.WriteLine(rx);
        x++;
        Console.WriteLine(x);
        Console.WriteLine(rx);
 
        rx = ref y;
        Console.WriteLine(x);
        Console.WriteLine(y);
        Console.WriteLine(rx);
        y++;
        Console.WriteLine(x);
        Console.WriteLine(y);
        Console.WriteLine(rx);
    }
}", expectedOutput: @"0
1
1
2
2
2
0
0
2
1
1
0");
        }
 
        [Fact]
        public void RefReassignRefParam()
        {
            var comp = CompileAndVerify(@"
using System;
 
class C
{
    static int x = 0;
    static int y = 0;
 
    static void Main()
    {
        M(ref x);
    }
 
    static void M(ref int rx)
    {
        Console.WriteLine(x);
        rx++;
        Console.WriteLine(x);
        Console.WriteLine(rx);
        x++;
        Console.WriteLine(x);
        Console.WriteLine(rx);
 
        rx = ref y;
        Console.WriteLine(x);
        Console.WriteLine(y);
        Console.WriteLine(rx);
        y++;
        Console.WriteLine(x);
        Console.WriteLine(y);
        Console.WriteLine(rx);
    }
}", expectedOutput: @"0
1
1
2
2
2
0
0
2
1
1");
 
        }
 
        [Fact]
        public void RefReassignRefReadonlyLocal()
        {
            var comp = CompileAndVerify(@"
using System;
 
class C
{
    static void Main()
    {
        int x = 0;
        ref readonly int rx = ref x;
        Console.WriteLine(x);
        Console.WriteLine(rx);
        x++;
        Console.WriteLine(x);
        Console.WriteLine(rx);
 
        int y = 0;
        rx = ref y;
        Console.WriteLine(x);
        Console.WriteLine(y);
        Console.WriteLine(rx);
        y++;
        Console.WriteLine(x);
        Console.WriteLine(y);
        Console.WriteLine(rx);
    }
}", expectedOutput: @"0
0
1
1
1
0
0
1
1
1
");
        }
 
        [Fact]
        public void RefReassignLocal()
        {
            var comp = CompileAndVerify(@"
using System;
 
class C
{
    static void Main()
    {
        int x = 0;
        ref int rx = ref x;
        Console.WriteLine(x);
        rx++;
        Console.WriteLine(x);
        Console.WriteLine(rx);
        x++;
        Console.WriteLine(x);
        Console.WriteLine(rx);
 
        int y = 0;
        rx = ref y;
        Console.WriteLine(x);
        Console.WriteLine(y);
        Console.WriteLine(rx);
        y++;
        Console.WriteLine(x);
        Console.WriteLine(y);
        Console.WriteLine(rx);
    }
}", expectedOutput: @"0
1
1
2
2
2
0
0
2
1
1");
            comp.VerifyIL("C.Main", @"
{
  // Code size       91 (0x5b)
  .maxstack  4
  .locals init (int V_0, //x
                int V_1) //y
  IL_0000:  ldc.i4.0
  IL_0001:  stloc.0
  IL_0002:  ldloca.s   V_0
  IL_0004:  ldloc.0
  IL_0005:  call       ""void System.Console.WriteLine(int)""
  IL_000a:  dup
  IL_000b:  dup
  IL_000c:  ldind.i4
  IL_000d:  ldc.i4.1
  IL_000e:  add
  IL_000f:  stind.i4
  IL_0010:  ldloc.0
  IL_0011:  call       ""void System.Console.WriteLine(int)""
  IL_0016:  dup
  IL_0017:  ldind.i4
  IL_0018:  call       ""void System.Console.WriteLine(int)""
  IL_001d:  ldloc.0
  IL_001e:  ldc.i4.1
  IL_001f:  add
  IL_0020:  stloc.0
  IL_0021:  ldloc.0
  IL_0022:  call       ""void System.Console.WriteLine(int)""
  IL_0027:  ldind.i4
  IL_0028:  call       ""void System.Console.WriteLine(int)""
  IL_002d:  ldc.i4.0
  IL_002e:  stloc.1
  IL_002f:  ldloca.s   V_1
  IL_0031:  ldloc.0
  IL_0032:  call       ""void System.Console.WriteLine(int)""
  IL_0037:  ldloc.1
  IL_0038:  call       ""void System.Console.WriteLine(int)""
  IL_003d:  dup
  IL_003e:  ldind.i4
  IL_003f:  call       ""void System.Console.WriteLine(int)""
  IL_0044:  ldloc.1
  IL_0045:  ldc.i4.1
  IL_0046:  add
  IL_0047:  stloc.1
  IL_0048:  ldloc.0
  IL_0049:  call       ""void System.Console.WriteLine(int)""
  IL_004e:  ldloc.1
  IL_004f:  call       ""void System.Console.WriteLine(int)""
  IL_0054:  ldind.i4
  IL_0055:  call       ""void System.Console.WriteLine(int)""
  IL_005a:  ret
}");
        }
 
        [Fact]
        public void RefReadonlyReassign()
        {
            var comp = CompileAndVerify(@"
using System;
 
class C
{
    static void Main()
    {
        int x = 0;
        ref int rx = ref x;
        ref readonly int rrx = ref x;
        Console.WriteLine(x);
        Console.WriteLine(rx);
        Console.WriteLine(rrx);
 
        int y = 1;
        rx = ref y;
        Console.WriteLine(x);
        Console.WriteLine(y);
        Console.WriteLine(rx);
        Console.WriteLine(rrx);
 
        rrx = ref rx;
        y++;
        Console.WriteLine(x);
        Console.WriteLine(y);
        Console.WriteLine(rx);
        Console.WriteLine(rrx);
    }
}", expectedOutput: @"0
0
0
0
1
1
0
0
2
2
2");
        }
 
        [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/73215")]
        public void RefAssignArrayAccess_Struct()
        {
            var text = @"
class Program
{
    static void M()
    {
        ref int rl = ref (new int[1])[0];
    }
}
";
 
            CompileAndVerify(text, options: TestOptions.DebugDll).VerifyIL("Program.M()", @"
{
  // Code size       15 (0xf)
  .maxstack  2
  .locals init (int& V_0) //rl
  IL_0000:  nop
  IL_0001:  ldc.i4.1
  IL_0002:  newarr     ""int""
  IL_0007:  ldc.i4.0
  IL_0008:  ldelema    ""int""
  IL_000d:  stloc.0
  IL_000e:  ret
}");
 
            CompileAndVerify(text, options: TestOptions.ReleaseDll).VerifyIL("Program.M()", @"
{
  // Code size       10 (0xa)
  .maxstack  2
  IL_0000:  ldc.i4.1
  IL_0001:  newarr     ""int""
  IL_0006:  ldc.i4.0
  IL_0007:  ldelem.i4
  IL_0008:  pop
  IL_0009:  ret
}");
        }
 
        [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/73215")]
        public void RefAssignArrayAccess_Struct_Readonly()
        {
            var text = @"
class Program
{
    static void M(int[] a)
    {
        ref readonly int rl = ref a[0];
    }
}
";
 
            CompileAndVerify(text, options: TestOptions.DebugDll).VerifyIL("Program.M", @"
{
  // Code size       10 (0xa)
  .maxstack  2
  .locals init (int& V_0) //rl
  IL_0000:  nop
  IL_0001:  ldarg.0
  IL_0002:  ldc.i4.0
  IL_0003:  ldelema    ""int""
  IL_0008:  stloc.0
  IL_0009:  ret
}");
 
            CompileAndVerify(text, options: TestOptions.ReleaseDll).VerifyIL("Program.M", @"
{
  // Code size        5 (0x5)
  .maxstack  2
  IL_0000:  ldarg.0
  IL_0001:  ldc.i4.0
  IL_0002:  ldelem.i4
  IL_0003:  pop
  IL_0004:  ret
}");
        }
 
        [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/73215")]
        public void RefAssignArrayAccess_Class()
        {
            var text = @"
class Program
{
    static void M(object[] a)
    {
        ref object rl = ref a[0];
    }
}
";
 
            CompileAndVerify(text, options: TestOptions.DebugDll).VerifyIL("Program.M", @"
{
  // Code size       10 (0xa)
  .maxstack  2
  .locals init (object& V_0) //rl
  IL_0000:  nop
  IL_0001:  ldarg.0
  IL_0002:  ldc.i4.0
  IL_0003:  ldelema    ""object""
  IL_0008:  stloc.0
  IL_0009:  ret
}");
 
            CompileAndVerify(text, options: TestOptions.ReleaseDll).VerifyIL("Program.M", @"
{
  // Code size        9 (0x9)
  .maxstack  2
  IL_0000:  ldarg.0
  IL_0001:  ldc.i4.0
  IL_0002:  ldelema    ""object""
  IL_0007:  pop
  IL_0008:  ret
}");
        }
 
        [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/73215")]
        public void RefAssignArrayAccess_Class_Readonly()
        {
            var text = @"
class Program
{
    static void M(object[] a)
    {
        ref readonly object rl = ref a[0];
    }
}
";
 
            CompileAndVerify(text, options: TestOptions.DebugDll, verify: Verification.Fails).VerifyIL("Program.M", @"
{
  // Code size       12 (0xc)
  .maxstack  2
  .locals init (object& V_0) //rl
  IL_0000:  nop
  IL_0001:  ldarg.0
  IL_0002:  ldc.i4.0
  IL_0003:  readonly.
  IL_0005:  ldelema    ""object""
  IL_000a:  stloc.0
  IL_000b:  ret
}");
 
            CompileAndVerify(text, options: TestOptions.ReleaseDll).VerifyIL("Program.M", @"
{
  // Code size        5 (0x5)
  .maxstack  2
  IL_0000:  ldarg.0
  IL_0001:  ldc.i4.0
  IL_0002:  ldelem.ref
  IL_0003:  pop
  IL_0004:  ret
}");
        }
 
        [Theory, CombinatorialData, WorkItem("https://github.com/dotnet/roslyn/issues/73215")]
        public void RefAssignArrayAccess_Generic(
            [CombinatorialValues("", "where T : class")] string constraints)
        {
            var text = $$"""
class Program
{
    static void M<T>(T[] a) {{constraints}}
    {
        ref T rl = ref a[0];
    }
}
""";
 
            CompileAndVerify(text, options: TestOptions.DebugDll).VerifyIL("Program.M<T>", @"
{
  // Code size       10 (0xa)
  .maxstack  2
  .locals init (T& V_0) //rl
  IL_0000:  nop
  IL_0001:  ldarg.0
  IL_0002:  ldc.i4.0
  IL_0003:  ldelema    ""T""
  IL_0008:  stloc.0
  IL_0009:  ret
}");
 
            CompileAndVerify(text, options: TestOptions.ReleaseDll).VerifyIL("Program.M<T>", @"
{
  // Code size        9 (0x9)
  .maxstack  2
  IL_0000:  ldarg.0
  IL_0001:  ldc.i4.0
  IL_0002:  ldelema    ""T""
  IL_0007:  pop
  IL_0008:  ret
}");
        }
 
        [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/73215")]
        public void RefAssignArrayAccess_Generic_Struct()
        {
            var text = """
class Program
{
    static void M<T>(T[] a) where T : struct
    {
        ref T rl = ref a[0];
    }
}
""";
 
            CompileAndVerify(text, options: TestOptions.DebugDll).VerifyIL("Program.M<T>", @"
{
  // Code size       10 (0xa)
  .maxstack  2
  .locals init (T& V_0) //rl
  IL_0000:  nop
  IL_0001:  ldarg.0
  IL_0002:  ldc.i4.0
  IL_0003:  ldelema    ""T""
  IL_0008:  stloc.0
  IL_0009:  ret
}");
 
            CompileAndVerify(text, options: TestOptions.ReleaseDll).VerifyIL("Program.M<T>", @"
{
  // Code size       11 (0xb)
  .maxstack  2
  IL_0000:  ldarg.0
  IL_0001:  ldc.i4.0
  IL_0002:  readonly.
  IL_0004:  ldelema    ""T""
  IL_0009:  pop
  IL_000a:  ret
}");
        }
 
        [Theory, CombinatorialData, WorkItem("https://github.com/dotnet/roslyn/issues/73215")]
        public void RefAssignArrayAccess_Generic_Readonly(
            [CombinatorialValues("", "where T : class")] string constraints)
        {
            var text = $$"""
class Program
{
    static void M<T>(T[] a) {{constraints}}
    {
        ref readonly T rl = ref a[0];
    }
}
""";
 
            CompileAndVerify(text, options: TestOptions.DebugDll, verify: Verification.Fails).VerifyIL("Program.M<T>", @"
{
  // Code size       12 (0xc)
  .maxstack  2
  .locals init (T& V_0) //rl
  IL_0000:  nop
  IL_0001:  ldarg.0
  IL_0002:  ldc.i4.0
  IL_0003:  readonly.
  IL_0005:  ldelema    ""T""
  IL_000a:  stloc.0
  IL_000b:  ret
}");
 
            CompileAndVerify(text, options: TestOptions.ReleaseDll).VerifyIL("Program.M<T>", @"
{
  // Code size       11 (0xb)
  .maxstack  2
  IL_0000:  ldarg.0
  IL_0001:  ldc.i4.0
  IL_0002:  readonly.
  IL_0004:  ldelema    ""T""
  IL_0009:  pop
  IL_000a:  ret
}");
        }
 
        [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/73215")]
        public void RefAssignArrayAccess_Generic_Readonly_Struct()
        {
            var text = @"
class Program
{
    static void M<T>(T[] a) where T : struct
    {
        ref readonly T rl = ref a[0];
    }
}
";
 
            CompileAndVerify(text, options: TestOptions.DebugDll).VerifyIL("Program.M<T>", @"
{
  // Code size       10 (0xa)
  .maxstack  2
  .locals init (T& V_0) //rl
  IL_0000:  nop
  IL_0001:  ldarg.0
  IL_0002:  ldc.i4.0
  IL_0003:  ldelema    ""T""
  IL_0008:  stloc.0
  IL_0009:  ret
}");
 
            CompileAndVerify(text, options: TestOptions.ReleaseDll).VerifyIL("Program.M<T>", @"
{
  // Code size       11 (0xb)
  .maxstack  2
  IL_0000:  ldarg.0
  IL_0001:  ldc.i4.0
  IL_0002:  readonly.
  IL_0004:  ldelema    ""T""
  IL_0009:  pop
  IL_000a:  ret
}");
        }
 
        [Fact]
        public void RefAssignArrayAccess_Discard_Struct()
        {
            var text = @"
class Program
{
    static void M(int[] a)
    {
        _ = ref a[0];
    }
}
";
 
            CompileAndVerify(text, options: TestOptions.DebugDll).VerifyIL("Program.M", @"
{
  // Code size        6 (0x6)
  .maxstack  2
  IL_0000:  nop
  IL_0001:  ldarg.0
  IL_0002:  ldc.i4.0
  IL_0003:  ldelem.i4
  IL_0004:  pop
  IL_0005:  ret
}");
 
            CompileAndVerify(text, options: TestOptions.ReleaseDll).VerifyIL("Program.M", @"
{
  // Code size        5 (0x5)
  .maxstack  2
  IL_0000:  ldarg.0
  IL_0001:  ldc.i4.0
  IL_0002:  ldelem.i4
  IL_0003:  pop
  IL_0004:  ret
}");
        }
 
        [Fact]
        public void RefAssignArrayAccess_Discard_Class()
        {
            var text = @"
class Program
{
    static void M(object[] a)
    {
        _ = ref a[0];
    }
}
";
 
            CompileAndVerify(text, options: TestOptions.DebugDll).VerifyIL("Program.M", @"
{
  // Code size        6 (0x6)
  .maxstack  2
  IL_0000:  nop
  IL_0001:  ldarg.0
  IL_0002:  ldc.i4.0
  IL_0003:  ldelem.ref
  IL_0004:  pop
  IL_0005:  ret
}");
 
            CompileAndVerify(text, options: TestOptions.ReleaseDll).VerifyIL("Program.M", @"
{
  // Code size        5 (0x5)
  .maxstack  2
  IL_0000:  ldarg.0
  IL_0001:  ldc.i4.0
  IL_0002:  ldelem.ref
  IL_0003:  pop
  IL_0004:  ret
}");
        }
 
        [Theory, CombinatorialData]
        public void RefAssignArrayAccess_Discard_Generic(
            [CombinatorialValues("", "where T : class", "where T : struct")] string constraints)
        {
            var text = $$"""
class Program
{
    static void M<T>(T[] a) {{constraints}}
    {
        _ = ref a[0];
    }
}
""";
 
            CompileAndVerify(text, options: TestOptions.DebugDll).VerifyIL("Program.M<T>", @"
{
  // Code size       12 (0xc)
  .maxstack  2
  IL_0000:  nop
  IL_0001:  ldarg.0
  IL_0002:  ldc.i4.0
  IL_0003:  readonly.
  IL_0005:  ldelema    ""T""
  IL_000a:  pop
  IL_000b:  ret
}");
 
            CompileAndVerify(text, options: TestOptions.ReleaseDll).VerifyIL("Program.M<T>", @"
{
  // Code size       11 (0xb)
  .maxstack  2
  IL_0000:  ldarg.0
  IL_0001:  ldc.i4.0
  IL_0002:  readonly.
  IL_0004:  ldelema    ""T""
  IL_0009:  pop
  IL_000a:  ret
}");
        }
 
        [Fact]
        public void RefAssignRefParameter()
        {
            var text = @"
class Program
{
    static void M(ref int i)
    {
        ref int rl = ref i;
    }
}
";
 
            CompileAndVerify(text, options: TestOptions.DebugDll).VerifyIL("Program.M(ref int)", @"
{
  // Code size        4 (0x4)
  .maxstack  1
  .locals init (int& V_0) //rl
  IL_0000:  nop
  IL_0001:  ldarg.0
  IL_0002:  stloc.0
  IL_0003:  ret
}");
        }
 
        [Fact]
        public void RefAssignOutParameter()
        {
            var text = @"
class Program
{
    static void M(out int i)
    {
        i = 0;
        ref int rl = ref i;
    }
}
";
 
            CompileAndVerify(text, options: TestOptions.DebugDll).VerifyIL("Program.M(out int)", @"
{
  // Code size        7 (0x7)
  .maxstack  2
  .locals init (int& V_0) //rl
  IL_0000:  nop
  IL_0001:  ldarg.0
  IL_0002:  ldc.i4.0
  IL_0003:  stind.i4
  IL_0004:  ldarg.0
  IL_0005:  stloc.0
  IL_0006:  ret
}");
        }
 
        [Fact]
        public void RefAssignRefLocal()
        {
            var text = @"
class Program
{
    static void M(ref int i)
    {
        ref int local = ref i;
        ref int rl = ref local;
    }
}
";
 
            CompileAndVerify(text, options: TestOptions.DebugDll).VerifyIL("Program.M(ref int)", @"
{
  // Code size        6 (0x6)
  .maxstack  1
  .locals init (int& V_0, //local
                int& V_1) //rl
  IL_0000:  nop
  IL_0001:  ldarg.0
  IL_0002:  stloc.0
  IL_0003:  ldloc.0
  IL_0004:  stloc.1
  IL_0005:  ret
}");
        }
 
        [Fact]
        public void RefAssignStaticProperty()
        {
            var text = @"
class Program
{
    static int field = 0;
    static ref int P { get { return ref @field; } }
 
    static void M()
    {
        ref int rl = ref P;
    }
}
";
 
            CompileAndVerify(text, options: TestOptions.DebugDll, verify: Verification.Fails).VerifyIL("Program.M()", @"
{
  // Code size        8 (0x8)
  .maxstack  1
  .locals init (int& V_0) //rl
  IL_0000:  nop
  IL_0001:  call       ""ref int Program.P.get""
  IL_0006:  stloc.0
  IL_0007:  ret
}");
        }
 
        [Fact]
        public void RefAssignClassInstanceProperty()
        {
            var text = @"
class Program
{
    int field = 0;
    ref int P { get { return ref @field; } }
 
    void M()
    {
        ref int rl = ref P;
    }
 
    void M1()
    {
        ref int rl = ref new Program().P;
    }
}
";
 
            var comp = CompileAndVerify(text, options: TestOptions.DebugDll, verify: Verification.Fails);
            comp.VerifyIL("Program.M()", @"
{
  // Code size        9 (0x9)
  .maxstack  1
  .locals init (int& V_0) //rl
  IL_0000:  nop
  IL_0001:  ldarg.0
  IL_0002:  call       ""ref int Program.P.get""
  IL_0007:  stloc.0
  IL_0008:  ret
}");
            comp.VerifyIL("Program.M1()", @"
{
  // Code size       13 (0xd)
  .maxstack  1
  .locals init (int& V_0) //rl
  IL_0000:  nop
  IL_0001:  newobj     ""Program..ctor()""
  IL_0006:  call       ""ref int Program.P.get""
  IL_000b:  stloc.0
  IL_000c:  ret
}");
        }
 
        [Fact]
        public void RefAssignStructInstanceProperty()
        {
            var text = @"
struct Program
{
    public ref int P { get { return ref (new int[1])[0]; } }
 
    void M()
    {
        ref int rl = ref P;
    }
 
    void M1(ref Program program)
    {
        ref int rl = ref program.P;
    }
}
 
struct Program2
{
    Program program;
 
 
    Program2(Program program)
    {
        this.program = program;
    }
 
    void M()
    {
        ref int rl = ref program.P;
    }
}
 
class Program3
{
    Program program = default(Program);
 
    void M()
    {
        ref int rl = ref program.P;
    }
}
";
 
            var comp = CompileAndVerify(text, options: TestOptions.DebugDll, verify: Verification.Fails);
            comp.VerifyIL("Program.M()", @"
{
  // Code size        9 (0x9)
  .maxstack  1
  .locals init (int& V_0) //rl
  IL_0000:  nop
  IL_0001:  ldarg.0
  IL_0002:  call       ""ref int Program.P.get""
  IL_0007:  stloc.0
  IL_0008:  ret
}");
            comp.VerifyIL("Program.M1(ref Program)", @"
{
  // Code size        9 (0x9)
  .maxstack  1
  .locals init (int& V_0) //rl
  IL_0000:  nop
  IL_0001:  ldarg.1
  IL_0002:  call       ""ref int Program.P.get""
  IL_0007:  stloc.0
  IL_0008:  ret
}");
            comp.VerifyIL("Program2.M()", @"
{
  // Code size       14 (0xe)
  .maxstack  1
  .locals init (int& V_0) //rl
  IL_0000:  nop
  IL_0001:  ldarg.0
  IL_0002:  ldflda     ""Program Program2.program""
  IL_0007:  call       ""ref int Program.P.get""
  IL_000c:  stloc.0
  IL_000d:  ret
}");
            comp.VerifyIL("Program3.M()", @"
{
  // Code size       14 (0xe)
  .maxstack  1
  .locals init (int& V_0) //rl
  IL_0000:  nop
  IL_0001:  ldarg.0
  IL_0002:  ldflda     ""Program Program3.program""
  IL_0007:  call       ""ref int Program.P.get""
  IL_000c:  stloc.0
  IL_000d:  ret
}");
        }
 
        [Fact]
        public void RefAssignConstrainedInstanceProperty()
        {
            var text = @"
interface I
{
    ref int P { get; }
}
 
class Program<T>
    where T : I
{
    T t = default(T);
 
    void M()
    {
        ref int rl = ref t.P;
    }
}
 
class Program2<T>
    where T : class, I
{
    void M(T t)
    {
        ref int rl = ref t.P;
    }
}
 
class Program3<T>
    where T : struct, I
{
    T t = default(T);
 
    void M()
    {
        ref int rl = ref t.P;
    }
}
";
 
            var comp = CompileAndVerify(text, options: TestOptions.DebugDll);
            comp.VerifyIL("Program<T>.M()", @"
{
  // Code size       20 (0x14)
  .maxstack  1
  .locals init (int& V_0) //rl
  IL_0000:  nop
  IL_0001:  ldarg.0
  IL_0002:  ldflda     ""T Program<T>.t""
  IL_0007:  constrained. ""T""
  IL_000d:  callvirt   ""ref int I.P.get""
  IL_0012:  stloc.0
  IL_0013:  ret
}");
            comp.VerifyIL("Program2<T>.M(T)", @"
{
  // Code size       14 (0xe)
  .maxstack  1
  .locals init (int& V_0) //rl
  IL_0000:  nop
  IL_0001:  ldarg.1
  IL_0002:  box        ""T""
  IL_0007:  callvirt   ""ref int I.P.get""
  IL_000c:  stloc.0
  IL_000d:  ret
}");
            comp.VerifyIL("Program3<T>.M()", @"
{
  // Code size       20 (0x14)
  .maxstack  1
  .locals init (int& V_0) //rl
  IL_0000:  nop
  IL_0001:  ldarg.0
  IL_0002:  ldflda     ""T Program3<T>.t""
  IL_0007:  constrained. ""T""
  IL_000d:  callvirt   ""ref int I.P.get""
  IL_0012:  stloc.0
  IL_0013:  ret
}");
        }
 
        [Fact]
        public void RefAssignClassInstanceIndexer()
        {
            var text = @"
class Program
{
    int field = 0;
    ref int this[int i] { get { return ref field; } }
 
    void M()
    {
        ref int rl = ref this[0];
    }
 
    void M1()
    {
        ref int rl = ref new Program()[0];
    }
}
";
 
            var comp = CompileAndVerify(text, options: TestOptions.DebugDll, verify: Verification.Fails);
            comp.VerifyIL("Program.M()", @"
{
  // Code size       10 (0xa)
  .maxstack  2
  .locals init (int& V_0) //rl
  IL_0000:  nop
  IL_0001:  ldarg.0
  IL_0002:  ldc.i4.0
  IL_0003:  call       ""ref int Program.this[int].get""
  IL_0008:  stloc.0
  IL_0009:  ret
}");
            comp.VerifyIL("Program.M1()", @"
{
  // Code size       14 (0xe)
  .maxstack  2
  .locals init (int& V_0) //rl
  IL_0000:  nop
  IL_0001:  newobj     ""Program..ctor()""
  IL_0006:  ldc.i4.0
  IL_0007:  call       ""ref int Program.this[int].get""
  IL_000c:  stloc.0
  IL_000d:  ret
}");
        }
 
        [Fact]
        public void RefAssignStructInstanceIndexer()
        {
            var text = @"
struct Program
{
    public ref int this[int i] { get { return ref (new int[1])[0]; } }
 
    void M()
    {
        ref int rl = ref this[0];
    }
}
 
struct Program2
{
    Program program;
 
    Program2(Program program)
    {
        this.program = program;
    }
 
    void M()
    {
        ref int rl = ref program[0];
    }
}
 
class Program3
{
    Program program = default(Program);
 
    void M()
    {
        ref int rl = ref program[0];
    }
}
";
 
            var comp = CompileAndVerify(text, options: TestOptions.DebugDll, verify: Verification.Fails);
            comp.VerifyIL("Program.M()", @"
{
  // Code size       10 (0xa)
  .maxstack  2
  .locals init (int& V_0) //rl
  IL_0000:  nop
  IL_0001:  ldarg.0
  IL_0002:  ldc.i4.0
  IL_0003:  call       ""ref int Program.this[int].get""
  IL_0008:  stloc.0
  IL_0009:  ret
}");
            comp.VerifyIL("Program2.M()", @"
{
  // Code size       15 (0xf)
  .maxstack  2
  .locals init (int& V_0) //rl
  IL_0000:  nop
  IL_0001:  ldarg.0
  IL_0002:  ldflda     ""Program Program2.program""
  IL_0007:  ldc.i4.0
  IL_0008:  call       ""ref int Program.this[int].get""
  IL_000d:  stloc.0
  IL_000e:  ret
}");
            comp.VerifyIL("Program3.M()", @"
{
  // Code size       15 (0xf)
  .maxstack  2
  .locals init (int& V_0) //rl
  IL_0000:  nop
  IL_0001:  ldarg.0
  IL_0002:  ldflda     ""Program Program3.program""
  IL_0007:  ldc.i4.0
  IL_0008:  call       ""ref int Program.this[int].get""
  IL_000d:  stloc.0
  IL_000e:  ret
}");
        }
 
        [Fact]
        public void RefAssignConstrainedInstanceIndexer()
        {
            var text = @"
interface I
{
    ref int this[int i] { get; }
}
 
class Program<T>
    where T : I
{
    T t = default(T);
 
    void M()
    {
        ref int rl = ref t[0];
    }
}
 
class Program2<T>
    where T : class, I
{
    void M(T t)
    {
        ref int rl = ref t[0];
    }
}
 
class Program3<T>
    where T : struct, I
{
    T t = default(T);
 
    void M()
    {
        ref int rl = ref t[0];
    }
}
";
 
            var comp = CompileAndVerify(text, options: TestOptions.DebugDll);
            comp.VerifyIL("Program<T>.M()", @"
{
  // Code size       21 (0x15)
  .maxstack  2
  .locals init (int& V_0) //rl
  IL_0000:  nop
  IL_0001:  ldarg.0
  IL_0002:  ldflda     ""T Program<T>.t""
  IL_0007:  ldc.i4.0
  IL_0008:  constrained. ""T""
  IL_000e:  callvirt   ""ref int I.this[int].get""
  IL_0013:  stloc.0
  IL_0014:  ret
}");
            comp.VerifyIL("Program2<T>.M(T)", @"
{
  // Code size       15 (0xf)
  .maxstack  2
  .locals init (int& V_0) //rl
  IL_0000:  nop
  IL_0001:  ldarg.1
  IL_0002:  box        ""T""
  IL_0007:  ldc.i4.0
  IL_0008:  callvirt   ""ref int I.this[int].get""
  IL_000d:  stloc.0
  IL_000e:  ret
}");
            comp.VerifyIL("Program3<T>.M()", @"
{
  // Code size       21 (0x15)
  .maxstack  2
  .locals init (int& V_0) //rl
  IL_0000:  nop
  IL_0001:  ldarg.0
  IL_0002:  ldflda     ""T Program3<T>.t""
  IL_0007:  ldc.i4.0
  IL_0008:  constrained. ""T""
  IL_000e:  callvirt   ""ref int I.this[int].get""
  IL_0013:  stloc.0
  IL_0014:  ret
}");
        }
 
        [Fact]
        public void RefAssignStaticFieldLikeEvent()
        {
            var text = @"
delegate void D();
 
class Program
{
    static event D d;
 
    static void M()
    {
        ref D rl = ref d;
    }
}
";
 
            CompileAndVerify(text, options: TestOptions.DebugDll).VerifyIL("Program.M()", @"
{
  // Code size        8 (0x8)
  .maxstack  1
  .locals init (D& V_0) //rl
  IL_0000:  nop
  IL_0001:  ldsflda    ""D Program.d""
  IL_0006:  stloc.0
  IL_0007:  ret
}");
        }
 
        [Fact]
        public void RefAssignClassInstanceFieldLikeEvent()
        {
            var text = @"
delegate void D();
 
class Program
{
    event D d;
 
    void M()
    {
        ref D rl = ref d;
    }
 
    void M1()
    {
        ref D rl = ref new Program().d;
    }
}
";
 
            var comp = CompileAndVerify(text, options: TestOptions.DebugDll);
            comp.VerifyIL("Program.M()", @"
{
  // Code size        9 (0x9)
  .maxstack  1
  .locals init (D& V_0) //rl
  IL_0000:  nop
  IL_0001:  ldarg.0
  IL_0002:  ldflda     ""D Program.d""
  IL_0007:  stloc.0
  IL_0008:  ret
}");
            comp.VerifyIL("Program.M1()", @"
{
  // Code size       13 (0xd)
  .maxstack  1
  .locals init (D& V_0) //rl
  IL_0000:  nop
  IL_0001:  newobj     ""Program..ctor()""
  IL_0006:  ldflda     ""D Program.d""
  IL_000b:  stloc.0
  IL_000c:  ret
}");
        }
 
        [Fact]
        public void RefAssignStaticField()
        {
            var text = @"
class Program
{
    static int i = 0;
 
    static void M()
    {
        ref int rl = ref i;
        rl = i;
    }
}
";
 
            CompileAndVerify(text, options: TestOptions.DebugDll).VerifyIL("Program.M()", @"
{
  // Code size       15 (0xf)
  .maxstack  2
  .locals init (int& V_0) //rl
  IL_0000:  nop
  IL_0001:  ldsflda    ""int Program.i""
  IL_0006:  stloc.0
  IL_0007:  ldloc.0
  IL_0008:  ldsfld     ""int Program.i""
  IL_000d:  stind.i4
  IL_000e:  ret
}");
        }
 
        [Fact]
        public void RefAssignClassInstanceField()
        {
            var text = @"
class Program
{
    int i = 0;
 
    void M()
    {
        ref int rl = ref i;
    }
 
    void M1()
    {
        ref int rl = ref new Program().i;
    }
}
";
 
            var comp = CompileAndVerify(text, options: TestOptions.DebugDll);
            comp.VerifyIL("Program.M()", @"
{
  // Code size        9 (0x9)
  .maxstack  1
  .locals init (int& V_0) //rl
  IL_0000:  nop
  IL_0001:  ldarg.0
  IL_0002:  ldflda     ""int Program.i""
  IL_0007:  stloc.0
  IL_0008:  ret
}");
            comp.VerifyIL("Program.M1()", @"
{
  // Code size       13 (0xd)
  .maxstack  1
  .locals init (int& V_0) //rl
  IL_0000:  nop
  IL_0001:  newobj     ""Program..ctor()""
  IL_0006:  ldflda     ""int Program.i""
  IL_000b:  stloc.0
  IL_000c:  ret
}");
        }
 
        [Fact]
        public void RefAssignStructInstanceField()
        {
            var text = @"
struct Program
{
    public int i;
}
 
class Program2
{
    Program program = default(Program);
 
    void M(ref Program program)
    {
        ref int rl = ref program.i;
        rl = program.i;
    }
 
    void M()
    {
        ref int rl = ref program.i;
    }
}
";
 
            var comp = CompileAndVerify(text, options: TestOptions.DebugDll);
            comp.VerifyIL("Program2.M(ref Program)", @"
{
  // Code size       17 (0x11)
  .maxstack  2
  .locals init (int& V_0) //rl
  IL_0000:  nop
  IL_0001:  ldarg.1
  IL_0002:  ldflda     ""int Program.i""
  IL_0007:  stloc.0
  IL_0008:  ldloc.0
  IL_0009:  ldarg.1
  IL_000a:  ldfld      ""int Program.i""
  IL_000f:  stind.i4
  IL_0010:  ret
}");
            comp.VerifyIL("Program2.M()", @"
{
  // Code size       14 (0xe)
  .maxstack  1
  .locals init (int& V_0) //rl
  IL_0000:  nop
  IL_0001:  ldarg.0
  IL_0002:  ldflda     ""Program Program2.program""
  IL_0007:  ldflda     ""int Program.i""
  IL_000c:  stloc.0
  IL_000d:  ret
}");
        }
 
        [Fact]
        public void RefAssignStaticCallWithoutArguments()
        {
            var text = @"
class Program
{
    static ref int M()
    {
        ref int rl = ref M();
        return ref rl;
    }
}
";
 
            CompileAndVerify(text, options: TestOptions.DebugDll, verify: Verification.Fails).VerifyIL("Program.M()", @"
{
  // Code size       13 (0xd)
  .maxstack  1
  .locals init (int& V_0, //rl
                int& V_1)
  IL_0000:  nop
  IL_0001:  call       ""ref int Program.M()""
  IL_0006:  stloc.0
  IL_0007:  ldloc.0
  IL_0008:  stloc.1
  IL_0009:  br.s       IL_000b
  IL_000b:  ldloc.1
  IL_000c:  ret
}");
        }
 
        [Fact]
        public void RefAssignClassInstanceCallWithoutArguments()
        {
            var text = @"
class Program
{
    ref int M()
    {
        ref int rl = ref M();
        return ref rl;
    }
 
    ref int M1()
    {
        ref int rl = ref new Program().M();
        return ref rl;
    }
}
";
 
            var comp = CompileAndVerify(text, options: TestOptions.DebugDll, verify: Verification.Fails);
            comp.VerifyIL("Program.M()", @"
{
  // Code size       14 (0xe)
  .maxstack  1
  .locals init (int& V_0, //rl
                int& V_1)
  IL_0000:  nop
  IL_0001:  ldarg.0
  IL_0002:  call       ""ref int Program.M()""
  IL_0007:  stloc.0
  IL_0008:  ldloc.0
  IL_0009:  stloc.1
  IL_000a:  br.s       IL_000c
  IL_000c:  ldloc.1
  IL_000d:  ret
}");
            comp.VerifyIL("Program.M1()", @"
{
  // Code size       18 (0x12)
  .maxstack  1
  .locals init (int& V_0, //rl
                int& V_1)
  IL_0000:  nop
  IL_0001:  newobj     ""Program..ctor()""
  IL_0006:  call       ""ref int Program.M()""
  IL_000b:  stloc.0
  IL_000c:  ldloc.0
  IL_000d:  stloc.1
  IL_000e:  br.s       IL_0010
  IL_0010:  ldloc.1
  IL_0011:  ret
}");
        }
 
        [Fact]
        public void RefAssignStructInstanceCallWithoutArguments()
        {
            var text = @"
struct Program
{
    public ref int M()
    {
        ref int rl = ref M();
        return ref rl;
    }
}
 
struct Program2
{
    Program program;
 
    ref int M()
    {
        ref int rl = ref program.M();
        return ref rl;
    }
}
 
class Program3
{
    Program program;
 
    ref int M()
    {
        ref int rl = ref program.M();
        return ref rl;
    }
}
";
 
            var comp = CompileAndVerify(text, options: TestOptions.DebugDll, verify: Verification.Fails);
            comp.VerifyIL("Program.M()", @"
{
  // Code size       14 (0xe)
  .maxstack  1
  .locals init (int& V_0, //rl
                int& V_1)
  IL_0000:  nop
  IL_0001:  ldarg.0
  IL_0002:  call       ""ref int Program.M()""
  IL_0007:  stloc.0
  IL_0008:  ldloc.0
  IL_0009:  stloc.1
  IL_000a:  br.s       IL_000c
  IL_000c:  ldloc.1
  IL_000d:  ret
}");
            comp.VerifyIL("Program2.M()", @"
{
  // Code size       19 (0x13)
  .maxstack  1
  .locals init (int& V_0, //rl
                int& V_1)
  IL_0000:  nop
  IL_0001:  ldarg.0
  IL_0002:  ldflda     ""Program Program2.program""
  IL_0007:  call       ""ref int Program.M()""
  IL_000c:  stloc.0
  IL_000d:  ldloc.0
  IL_000e:  stloc.1
  IL_000f:  br.s       IL_0011
  IL_0011:  ldloc.1
  IL_0012:  ret
}");
            comp.VerifyIL("Program3.M()", @"
{
  // Code size       19 (0x13)
  .maxstack  1
  .locals init (int& V_0, //rl
                int& V_1)
  IL_0000:  nop
  IL_0001:  ldarg.0
  IL_0002:  ldflda     ""Program Program3.program""
  IL_0007:  call       ""ref int Program.M()""
  IL_000c:  stloc.0
  IL_000d:  ldloc.0
  IL_000e:  stloc.1
  IL_000f:  br.s       IL_0011
  IL_0011:  ldloc.1
  IL_0012:  ret
}");
        }
 
        [Fact]
        public void RefAssignConstrainedInstanceCallWithoutArguments()
        {
            var text = @"
interface I
{
    ref int M();
}
 
class Program<T>
    where T : I
{
    T t = default(T);
 
    ref int M()
    {
        ref int rl = ref t.M();
        return ref rl;
    }
}
 
class Program2<T>
    where T : class, I
{
    ref int M(T t)
    {
        ref int rl = ref t.M();
        return ref rl;
    }
}
 
class Program3<T>
    where T : struct, I
{
    T t = default(T);
 
    ref int M()
    {
        ref int rl = ref t.M();
        return ref rl;
    }
}
";
 
            var comp = CompileAndVerify(text, options: TestOptions.DebugDll, verify: Verification.Fails);
            comp.VerifyIL("Program<T>.M()", @"
{
  // Code size       25 (0x19)
  .maxstack  1
  .locals init (int& V_0, //rl
                int& V_1)
  IL_0000:  nop
  IL_0001:  ldarg.0
  IL_0002:  ldflda     ""T Program<T>.t""
  IL_0007:  constrained. ""T""
  IL_000d:  callvirt   ""ref int I.M()""
  IL_0012:  stloc.0
  IL_0013:  ldloc.0
  IL_0014:  stloc.1
  IL_0015:  br.s       IL_0017
  IL_0017:  ldloc.1
  IL_0018:  ret
}");
            comp.VerifyIL("Program2<T>.M(T)", @"
{
  // Code size       19 (0x13)
  .maxstack  1
  .locals init (int& V_0, //rl
                int& V_1)
  IL_0000:  nop
  IL_0001:  ldarg.1
  IL_0002:  box        ""T""
  IL_0007:  callvirt   ""ref int I.M()""
  IL_000c:  stloc.0
  IL_000d:  ldloc.0
  IL_000e:  stloc.1
  IL_000f:  br.s       IL_0011
  IL_0011:  ldloc.1
  IL_0012:  ret
}");
            comp.VerifyIL("Program3<T>.M()", @"
{
  // Code size       25 (0x19)
  .maxstack  1
  .locals init (int& V_0, //rl
                int& V_1)
  IL_0000:  nop
  IL_0001:  ldarg.0
  IL_0002:  ldflda     ""T Program3<T>.t""
  IL_0007:  constrained. ""T""
  IL_000d:  callvirt   ""ref int I.M()""
  IL_0012:  stloc.0
  IL_0013:  ldloc.0
  IL_0014:  stloc.1
  IL_0015:  br.s       IL_0017
  IL_0017:  ldloc.1
  IL_0018:  ret
}");
        }
 
        [Fact]
        public void RefAssignStaticCallWithArguments()
        {
            var text = @"
class Program
{
    static ref int M(ref int i, ref int j, object o)
    {
        ref int rl = ref M(ref i, ref j, o);
        return ref rl;
    }
}
";
 
            CompileAndVerify(text, options: TestOptions.DebugDll, verify: Verification.Fails).VerifyIL("Program.M(ref int, ref int, object)", @"
{
  // Code size       16 (0x10)
  .maxstack  3
  .locals init (int& V_0, //rl
                int& V_1)
  IL_0000:  nop
  IL_0001:  ldarg.0
  IL_0002:  ldarg.1
  IL_0003:  ldarg.2
  IL_0004:  call       ""ref int Program.M(ref int, ref int, object)""
  IL_0009:  stloc.0
  IL_000a:  ldloc.0
  IL_000b:  stloc.1
  IL_000c:  br.s       IL_000e
  IL_000e:  ldloc.1
  IL_000f:  ret
}");
        }
 
        [Fact]
        public void RefAssignClassInstanceCallWithArguments()
        {
            var text = @"
class Program
{
    ref int M(ref int i, ref int j, object o)
    {
        ref int rl = ref M(ref i, ref j, o);
        return ref rl;
    }
 
    ref int M1(ref int i, ref int j, object o)
    {
        ref int rl = ref new Program().M(ref i, ref j, o);
        return ref rl;
    }
}
";
 
            var comp = CompileAndVerify(text, options: TestOptions.DebugDll, verify: Verification.Fails);
            comp.VerifyIL("Program.M(ref int, ref int, object)", @"
{
  // Code size       17 (0x11)
  .maxstack  4
  .locals init (int& V_0, //rl
                int& V_1)
  IL_0000:  nop
  IL_0001:  ldarg.0
  IL_0002:  ldarg.1
  IL_0003:  ldarg.2
  IL_0004:  ldarg.3
  IL_0005:  call       ""ref int Program.M(ref int, ref int, object)""
  IL_000a:  stloc.0
  IL_000b:  ldloc.0
  IL_000c:  stloc.1
  IL_000d:  br.s       IL_000f
  IL_000f:  ldloc.1
  IL_0010:  ret
}");
            comp.VerifyIL("Program.M1(ref int, ref int, object)", @"
{
  // Code size       21 (0x15)
  .maxstack  4
  .locals init (int& V_0, //rl
                int& V_1)
  IL_0000:  nop
  IL_0001:  newobj     ""Program..ctor()""
  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:  stloc.0
  IL_000f:  ldloc.0
  IL_0010:  stloc.1
  IL_0011:  br.s       IL_0013
  IL_0013:  ldloc.1
  IL_0014:  ret
}");
        }
 
        [Fact]
        public void RefAssignStructInstanceCallWithArguments()
        {
            var text = @"
struct Program
{
    public ref int M(ref int i, ref int j, object o)
    {
        ref int rl = ref M(ref i, ref j, o);
        return ref rl;
    }
}
 
struct Program2
{
    Program program;
 
    ref int M(ref int i, ref int j, object o)
    {
        ref int rl = ref program.M(ref i, ref j, o);
        return ref rl;
    }
}
 
class Program3
{
    Program program;
 
    ref int M(ref int i, ref int j, object o)
    {
        ref int rl = ref program.M(ref i, ref j, o);
        return ref rl;
    }
}
";
 
            var comp = CompileAndVerify(text, options: TestOptions.DebugDll, verify: Verification.Fails);
            comp.VerifyIL("Program.M(ref int, ref int, object)", @"
{
  // Code size       17 (0x11)
  .maxstack  4
  .locals init (int& V_0, //rl
                int& V_1)
  IL_0000:  nop
  IL_0001:  ldarg.0
  IL_0002:  ldarg.1
  IL_0003:  ldarg.2
  IL_0004:  ldarg.3
  IL_0005:  call       ""ref int Program.M(ref int, ref int, object)""
  IL_000a:  stloc.0
  IL_000b:  ldloc.0
  IL_000c:  stloc.1
  IL_000d:  br.s       IL_000f
  IL_000f:  ldloc.1
  IL_0010:  ret
}");
            comp.VerifyIL("Program2.M(ref int, ref int, object)", @"
{
  // Code size       22 (0x16)
  .maxstack  4
  .locals init (int& V_0, //rl
                int& V_1)
  IL_0000:  nop
  IL_0001:  ldarg.0
  IL_0002:  ldflda     ""Program Program2.program""
  IL_0007:  ldarg.1
  IL_0008:  ldarg.2
  IL_0009:  ldarg.3
  IL_000a:  call       ""ref int Program.M(ref int, ref int, object)""
  IL_000f:  stloc.0
  IL_0010:  ldloc.0
  IL_0011:  stloc.1
  IL_0012:  br.s       IL_0014
  IL_0014:  ldloc.1
  IL_0015:  ret
}");
            comp.VerifyIL("Program3.M(ref int, ref int, object)", @"
{
  // Code size       22 (0x16)
  .maxstack  4
  .locals init (int& V_0, //rl
                int& V_1)
  IL_0000:  nop
  IL_0001:  ldarg.0
  IL_0002:  ldflda     ""Program Program3.program""
  IL_0007:  ldarg.1
  IL_0008:  ldarg.2
  IL_0009:  ldarg.3
  IL_000a:  call       ""ref int Program.M(ref int, ref int, object)""
  IL_000f:  stloc.0
  IL_0010:  ldloc.0
  IL_0011:  stloc.1
  IL_0012:  br.s       IL_0014
  IL_0014:  ldloc.1
  IL_0015:  ret
}");
        }
 
        [Fact]
        public void RefAssignConstrainedInstanceCallWithArguments()
        {
            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)
    {
        ref int rl = ref t.M(ref i, ref j, o);
        return ref rl;
    }
}
 
class Program2<T>
    where T : class, I
{
    ref int M(T t, ref int i, ref int j, object o)
    {
        ref int rl = ref t.M(ref i, ref j, o);
        return ref rl;
    }
}
 
class Program3<T>
    where T : struct, I
{
    T t = default(T);
 
    ref int M(ref int i, ref int j, object o)
    {
        ref int rl = ref t.M(ref i, ref j, o);
        return ref rl;
    }
}
";
 
            var comp = CompileAndVerify(text, options: TestOptions.DebugDll, verify: Verification.Fails);
            comp.VerifyIL("Program<T>.M(ref int, ref int, object)", @"
{
  // Code size       28 (0x1c)
  .maxstack  4
  .locals init (int& V_0, //rl
                int& V_1)
  IL_0000:  nop
  IL_0001:  ldarg.0
  IL_0002:  ldflda     ""T Program<T>.t""
  IL_0007:  ldarg.1
  IL_0008:  ldarg.2
  IL_0009:  ldarg.3
  IL_000a:  constrained. ""T""
  IL_0010:  callvirt   ""ref int I.M(ref int, ref int, object)""
  IL_0015:  stloc.0
  IL_0016:  ldloc.0
  IL_0017:  stloc.1
  IL_0018:  br.s       IL_001a
  IL_001a:  ldloc.1
  IL_001b:  ret
}");
            comp.VerifyIL("Program2<T>.M(T, ref int, ref int, object)", @"
{
  // Code size       23 (0x17)
  .maxstack  4
  .locals init (int& V_0, //rl
                int& V_1)
  IL_0000:  nop
  IL_0001:  ldarg.1
  IL_0002:  box        ""T""
  IL_0007:  ldarg.2
  IL_0008:  ldarg.3
  IL_0009:  ldarg.s    V_4
  IL_000b:  callvirt   ""ref int I.M(ref int, ref int, object)""
  IL_0010:  stloc.0
  IL_0011:  ldloc.0
  IL_0012:  stloc.1
  IL_0013:  br.s       IL_0015
  IL_0015:  ldloc.1
  IL_0016:  ret
}");
            comp.VerifyIL("Program3<T>.M(ref int, ref int, object)", @"
{
  // Code size       28 (0x1c)
  .maxstack  4
  .locals init (int& V_0, //rl
                int& V_1)
  IL_0000:  nop
  IL_0001:  ldarg.0
  IL_0002:  ldflda     ""T Program3<T>.t""
  IL_0007:  ldarg.1
  IL_0008:  ldarg.2
  IL_0009:  ldarg.3
  IL_000a:  constrained. ""T""
  IL_0010:  callvirt   ""ref int I.M(ref int, ref int, object)""
  IL_0015:  stloc.0
  IL_0016:  ldloc.0
  IL_0017:  stloc.1
  IL_0018:  br.s       IL_001a
  IL_001a:  ldloc.1
  IL_001b:  ret
}");
        }
 
        [Fact]
        public void RefAssignDelegateInvocationWithNoArguments()
        {
            var text = @"
delegate ref int D();
 
class Program
{
    static void M(D d)
    {
        ref int rl = ref d();
    }
}
";
 
            CompileAndVerify(text, options: TestOptions.DebugDll).VerifyIL("Program.M(D)", @"
{
  // Code size        9 (0x9)
  .maxstack  1
  .locals init (int& V_0) //rl
  IL_0000:  nop
  IL_0001:  ldarg.0
  IL_0002:  callvirt   ""ref int D.Invoke()""
  IL_0007:  stloc.0
  IL_0008:  ret
}");
        }
 
        [Fact]
        public void RefAssignDelegateInvocationWithArguments()
        {
            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)
    {
        ref int rl = ref d(ref i, ref j, o);
        return ref rl;
    }
}
";
 
            CompileAndVerify(text, options: TestOptions.DebugDll, verify: Verification.Fails).VerifyIL("Program.M(D, ref int, ref int, object)", @"
{
  // Code size       17 (0x11)
  .maxstack  4
  .locals init (int& V_0, //rl
                int& V_1)
  IL_0000:  nop
  IL_0001:  ldarg.0
  IL_0002:  ldarg.1
  IL_0003:  ldarg.2
  IL_0004:  ldarg.3
  IL_0005:  callvirt   ""ref int D.Invoke(ref int, ref int, object)""
  IL_000a:  stloc.0
  IL_000b:  ldloc.0
  IL_000c:  stloc.1
  IL_000d:  br.s       IL_000f
  IL_000f:  ldloc.1
  IL_0010:  ret
}");
        }
 
        [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/71369")]
        public void AssignmentValue_RefField()
        {
            var source = """
                int n = 0;
                System.Console.Write(new S(ref n).GetI());
                System.Console.Write(n);
 
                ref struct S
                {
                    ref int i;
                    public S(ref int n) => i = ref n;
                    public int GetI() => i = 2;
                }
                """;
            var verifier = CompileAndVerify(source, expectedOutput: ExecutionConditionUtil.IsMonoOrCoreClr ? "22" : null,
                verify: Verification.FailsPEVerify, targetFramework: TargetFramework.Net70);
            verifier.VerifyDiagnostics();
            verifier.VerifyIL("S.GetI", """
                {
                  // Code size       12 (0xc)
                  .maxstack  3
                  .locals init (int V_0)
                  IL_0000:  ldarg.0
                  IL_0001:  ldfld      "ref int S.i"
                  IL_0006:  ldc.i4.2
                  IL_0007:  dup
                  IL_0008:  stloc.0
                  IL_0009:  stind.i4
                  IL_000a:  ldloc.0
                  IL_000b:  ret
                }
                """);
        }
 
        [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/71369")]
        public void AssignmentValue_RefField_Temp()
        {
            var source = """
                int n = 0;
                System.Console.Write(new S(ref n).GetI());
                System.Console.Write(n);
 
                ref struct S
                {
                    ref int i;
                    public S(ref int n) => i = ref n;
                    public int GetI()
                    {
                        int x = i = 2;
                        x++;
                        return x;
                    }
                }
                """;
            var verifier = CompileAndVerify(source, expectedOutput: ExecutionConditionUtil.IsMonoOrCoreClr ? "32" : null,
                verify: Verification.FailsPEVerify, targetFramework: TargetFramework.Net70);
            verifier.VerifyDiagnostics();
            verifier.VerifyIL("S.GetI", """
                {
                  // Code size       14 (0xe)
                  .maxstack  3
                  .locals init (int V_0)
                  IL_0000:  ldarg.0
                  IL_0001:  ldfld      "ref int S.i"
                  IL_0006:  ldc.i4.2
                  IL_0007:  dup
                  IL_0008:  stloc.0
                  IL_0009:  stind.i4
                  IL_000a:  ldloc.0
                  IL_000b:  ldc.i4.1
                  IL_000c:  add
                  IL_000d:  ret
                }
                """);
        }
 
        [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/71369")]
        public void AssignmentValue_RefField_Discarded()
        {
            var source = """
                int n = 0;
                new S(ref n).SetI();
                System.Console.Write(n);
 
                ref struct S
                {
                    ref int i;
                    public S(ref int n) => i = ref n;
                    public void SetI() => i = 2;
                }
                """;
            var verifier = CompileAndVerify(source, expectedOutput: ExecutionConditionUtil.IsMonoOrCoreClr ? "2" : null,
                verify: Verification.FailsPEVerify, targetFramework: TargetFramework.Net70);
            verifier.VerifyDiagnostics();
            verifier.VerifyIL("S.SetI", """
                {
                  // Code size        9 (0x9)
                  .maxstack  2
                  IL_0000:  ldarg.0
                  IL_0001:  ldfld      "ref int S.i"
                  IL_0006:  ldc.i4.2
                  IL_0007:  stind.i4
                  IL_0008:  ret
                }
                """);
        }
 
        [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/71369")]
        public void AssignmentValue_RefField_SideEffects()
        {
            var source = """
                int n = 0;
                System.Console.Write(new S(ref n).GetI());
                System.Console.Write(n);
 
                ref struct S
                {
                    ref int i;
                    public S(ref int n) => i = ref n;
                    public int GetI() => M1(ref this).i = M2();
 
                    static ref S M1(ref S s)
                    {
                        System.Console.WriteLine("M1");
                        return ref s;
                    }
 
                    static int M2()
                    {
                        System.Console.WriteLine("M2");
                        return 2;
                    }
                }
                """;
            var expectedOutput = """
                M1
                M2
                22
                """;
            var verifier = CompileAndVerify(source, expectedOutput: ExecutionConditionUtil.IsMonoOrCoreClr ? expectedOutput : null,
                verify: Verification.Fails, targetFramework: TargetFramework.Net70);
            verifier.VerifyDiagnostics();
            verifier.VerifyIL("S.GetI", """
                {
                  // Code size       21 (0x15)
                  .maxstack  3
                  .locals init (int V_0)
                  IL_0000:  ldarg.0
                  IL_0001:  call       "ref S S.M1(ref S)"
                  IL_0006:  ldfld      "ref int S.i"
                  IL_000b:  call       "int S.M2()"
                  IL_0010:  dup
                  IL_0011:  stloc.0
                  IL_0012:  stind.i4
                  IL_0013:  ldloc.0
                  IL_0014:  ret
                }
                """);
        }
 
        [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/71369")]
        public void AssignmentValue_RefField_SideEffects_Compound()
        {
            var source = """
                int n = 1;
                System.Console.Write(new S(ref n).GetI());
                System.Console.Write(n);
 
                ref struct S
                {
                    ref int i;
                    public S(ref int n) => i = ref n;
                    public int GetI() => M1(ref this).i += M2();
 
                    static ref S M1(ref S s)
                    {
                        System.Console.WriteLine("M1");
                        return ref s;
                    }
 
                    static int M2()
                    {
                        System.Console.WriteLine("M2");
                        return 2;
                    }
                }
                """;
            var expectedOutput = """
                M1
                M2
                33
                """;
            var verifier = CompileAndVerify(source, expectedOutput: ExecutionConditionUtil.IsMonoOrCoreClr ? expectedOutput : null,
                verify: Verification.Fails, targetFramework: TargetFramework.Net70);
            verifier.VerifyDiagnostics();
            verifier.VerifyIL("S.GetI", """
                {
                  // Code size       24 (0x18)
                  .maxstack  3
                  .locals init (int V_0)
                  IL_0000:  ldarg.0
                  IL_0001:  call       "ref S S.M1(ref S)"
                  IL_0006:  ldfld      "ref int S.i"
                  IL_000b:  dup
                  IL_000c:  ldind.i4
                  IL_000d:  call       "int S.M2()"
                  IL_0012:  add
                  IL_0013:  dup
                  IL_0014:  stloc.0
                  IL_0015:  stind.i4
                  IL_0016:  ldloc.0
                  IL_0017:  ret
                }
                """);
        }
 
        [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/71369")]
        public void AssignmentValue_RefParameter()
        {
            var source = """
                int n = 0;
                System.Console.Write(C.GetI(ref n));
                System.Console.Write(n);
 
                static class C
                {
                    public static int GetI(ref int n) => n = 2;
                }
                """;
            var verifier = CompileAndVerify(source, expectedOutput: "22");
            verifier.VerifyDiagnostics();
            verifier.VerifyIL("C.GetI", """
                {
                  // Code size        7 (0x7)
                  .maxstack  3
                  .locals init (int V_0)
                  IL_0000:  ldarg.0
                  IL_0001:  ldc.i4.2
                  IL_0002:  dup
                  IL_0003:  stloc.0
                  IL_0004:  stind.i4
                  IL_0005:  ldloc.0
                  IL_0006:  ret
                }
                """);
        }
 
        [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/71369")]
        public void AssignmentValue_RefParameter_Temp()
        {
            var source = """
                int n = 0;
                System.Console.Write(C.GetI(ref n));
                System.Console.Write(n);
 
                
                static class C
                {
                    public static int GetI(ref int n)
                    {
                        int x = n = 2;
                        x++;
                        return x;
                    }
                }
                """;
            var verifier = CompileAndVerify(source, expectedOutput: "32");
            verifier.VerifyDiagnostics();
            verifier.VerifyIL("C.GetI", """
                {
                  // Code size        9 (0x9)
                  .maxstack  3
                  .locals init (int V_0)
                  IL_0000:  ldarg.0
                  IL_0001:  ldc.i4.2
                  IL_0002:  dup
                  IL_0003:  stloc.0
                  IL_0004:  stind.i4
                  IL_0005:  ldloc.0
                  IL_0006:  ldc.i4.1
                  IL_0007:  add
                  IL_0008:  ret
                }
                """);
        }
 
        [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/71369")]
        public void AssignmentValue_RefLocal()
        {
            var source = """
                int n = 0;
                System.Console.Write(C.GetI(false, ref n, ref n));
                System.Console.Write(n);
 
                static class C
                {
                    public static int GetI(bool b, ref int n, ref int m)
                    {
                        ref int i = ref n;
                        if (b) { i = ref m; }
                        return i = 2;
                    }
                }
                """;
            var verifier = CompileAndVerify(source, expectedOutput: "22");
            verifier.VerifyDiagnostics();
            verifier.VerifyIL("C.GetI", """
                {
                  // Code size       14 (0xe)
                  .maxstack  3
                  .locals init (int& V_0, //i
                                int V_1)
                  IL_0000:  ldarg.1
                  IL_0001:  stloc.0
                  IL_0002:  ldarg.0
                  IL_0003:  brfalse.s  IL_0007
                  IL_0005:  ldarg.2
                  IL_0006:  stloc.0
                  IL_0007:  ldloc.0
                  IL_0008:  ldc.i4.2
                  IL_0009:  dup
                  IL_000a:  stloc.1
                  IL_000b:  stind.i4
                  IL_000c:  ldloc.1
                  IL_000d:  ret
                }
                """);
        }
 
        [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/71369")]
        public void AssignmentValue_RefLocal_Temp()
        {
            var source = """
                int n = 0;
                System.Console.Write(C.GetI(false, ref n, ref n));
                System.Console.Write(n);
 
                static class C
                {
                    public static int GetI(bool b, ref int n, ref int m)
                    {
                        ref int i = ref n;
                        if (b) { i = ref m; }
                        int x = i = 2;
                        x++;
                        return x;
                    }
                }
                """;
            var verifier = CompileAndVerify(source, expectedOutput: "32");
            verifier.VerifyDiagnostics();
            verifier.VerifyIL("C.GetI", """
                {
                  // Code size       16 (0x10)
                  .maxstack  3
                  .locals init (int& V_0, //i
                                int V_1)
                  IL_0000:  ldarg.1
                  IL_0001:  stloc.0
                  IL_0002:  ldarg.0
                  IL_0003:  brfalse.s  IL_0007
                  IL_0005:  ldarg.2
                  IL_0006:  stloc.0
                  IL_0007:  ldloc.0
                  IL_0008:  ldc.i4.2
                  IL_0009:  dup
                  IL_000a:  stloc.1
                  IL_000b:  stind.i4
                  IL_000c:  ldloc.1
                  IL_000d:  ldc.i4.1
                  IL_000e:  add
                  IL_000f:  ret
                }
                """);
        }
 
        [Fact]
        public void RefLocalsAreVariables()
        {
            var text = @"
class Program
{
    static int field = 0;
 
    static void M(ref int i)
    {
    }
 
    static void N(out int i)
    {
        i = 0;
    }
 
    static unsafe void Main()
    {
        ref int rl = ref field;
        rl = 0;
        rl += 1;
        rl++;
        M(ref rl);
        N(out rl);
        fixed (int* i = &rl) { }
        var tr = __makeref(rl);
    }
}
";
 
            CompileAndVerify(text, options: TestOptions.UnsafeDebugDll, verify: Verification.Fails).VerifyIL("Program.Main()", @"
{
  // Code size       54 (0x36)
  .maxstack  3
  .locals init (int& V_0, //rl
                System.TypedReference V_1, //tr
                int* V_2, //i
                pinned int& V_3)
  IL_0000:  nop
  IL_0001:  ldsflda    ""int Program.field""
  IL_0006:  stloc.0
  IL_0007:  ldloc.0
  IL_0008:  ldc.i4.0
  IL_0009:  stind.i4
  IL_000a:  ldloc.0
  IL_000b:  ldloc.0
  IL_000c:  ldind.i4
  IL_000d:  ldc.i4.1
  IL_000e:  add
  IL_000f:  stind.i4
  IL_0010:  ldloc.0
  IL_0011:  ldloc.0
  IL_0012:  ldind.i4
  IL_0013:  ldc.i4.1
  IL_0014:  add
  IL_0015:  stind.i4
  IL_0016:  ldloc.0
  IL_0017:  call       ""void Program.M(ref int)""
  IL_001c:  nop
  IL_001d:  ldloc.0
  IL_001e:  call       ""void Program.N(out int)""
  IL_0023:  nop
  IL_0024:  ldloc.0
  IL_0025:  stloc.3
  IL_0026:  ldloc.3
  IL_0027:  conv.u
  IL_0028:  stloc.2
  IL_0029:  nop
  IL_002a:  nop
  IL_002b:  ldc.i4.0
  IL_002c:  conv.u
  IL_002d:  stloc.3
  IL_002e:  ldloc.0
  IL_002f:  mkrefany   ""int""
  IL_0034:  stloc.1
  IL_0035:  ret
}");
        }
 
        [Fact]
        public void RefLocalsAreValues()
        {
            var text = @"
class Program
{
    static int field = 0;
 
    static void N(int i)
    {
    }
 
    static unsafe int Main()
    {
        ref int rl = ref field;
        var @int = rl + 0;
        var @string = rl.ToString();
        var @long = (long)rl;
        N(rl);
        return unchecked((int)((long)@int + @long));
    }
}
";
 
            CompileAndVerify(text, options: TestOptions.UnsafeDebugDll, verify: Verification.Passes).VerifyIL("Program.Main()", @"
{
  // Code size       41 (0x29)
  .maxstack  2
  .locals init (int& V_0, //rl
                int V_1, //int
                string V_2, //string
                long V_3, //long
                int V_4)
  IL_0000:  nop
  IL_0001:  ldsflda    ""int Program.field""
  IL_0006:  stloc.0
  IL_0007:  ldloc.0
  IL_0008:  ldind.i4
  IL_0009:  stloc.1
  IL_000a:  ldloc.0
  IL_000b:  call       ""string int.ToString()""
  IL_0010:  stloc.2
  IL_0011:  ldloc.0
  IL_0012:  ldind.i4
  IL_0013:  conv.i8
  IL_0014:  stloc.3
  IL_0015:  ldloc.0
  IL_0016:  ldind.i4
  IL_0017:  call       ""void Program.N(int)""
  IL_001c:  nop
  IL_001d:  ldloc.1
  IL_001e:  conv.i8
  IL_001f:  ldloc.3
  IL_0020:  add
  IL_0021:  conv.i4
  IL_0022:  stloc.s    V_4
  IL_0024:  br.s       IL_0026
  IL_0026:  ldloc.s    V_4
  IL_0028:  ret
}
");
        }
 
        [Fact]
        public void RefLocal_CSharp6()
        {
            var text = @"
class Program
{
    static void M()
    {
        ref int rl = ref (new int[1])[0];
    }
}
";
            var comp = CreateCompilation(text, parseOptions: TestOptions.Regular.WithLanguageVersion(LanguageVersion.CSharp6));
            comp.VerifyDiagnostics(
                // (6,9): error CS8059: Feature 'byref locals and returns' is not available in C# 6. Please use language version 7.0 or greater.
                //         ref int rl = ref (new int[1])[0];
                Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion6, "ref").WithArguments("byref locals and returns", "7.0").WithLocation(6, 9),
                // (6,22): error CS8059: Feature 'byref locals and returns' is not available in C# 6. Please use language version 7.0 or greater.
                //         ref int rl = ref (new int[1])[0];
                Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion6, "ref").WithArguments("byref locals and returns", "7.0").WithLocation(6, 22)
                );
        }
 
        [Fact]
        public void RefVarSemanticModel()
        {
            var text = @"
class Program
{
    static void M()
    {
        int i = 0;
        ref var x = ref i;
    }
}
";
            var comp = CreateCompilation(text);
            comp.VerifyDiagnostics();
 
            var tree = comp.SyntaxTrees.Single();
            var model = comp.GetSemanticModel(tree);
 
            var xDecl = tree.GetRoot().DescendantNodes().OfType<VariableDeclaratorSyntax>().ElementAt(1);
            Assert.Equal("System.Int32 x", model.GetDeclaredSymbol(xDecl).ToTestDisplayString());
 
            var refVar = tree.GetRoot().DescendantNodes().OfType<RefTypeSyntax>().Single();
            var type = refVar.Type;
            Assert.Equal("System.Int32", model.GetTypeInfo(type).Type.ToTestDisplayString());
            Assert.Equal("System.Int32", model.GetSymbolInfo(type).Symbol.ToTestDisplayString());
            Assert.Null(model.GetAliasInfo(type));
 
            Assert.Null(model.GetSymbolInfo(refVar).Symbol);
            Assert.Null(model.GetTypeInfo(refVar).Type);
        }
 
        [Fact]
        public void RefAliasVarSemanticModel()
        {
            var text = @"
using var = C;
class C
{
    static void M()
    {
        C i = null;
        ref var x = ref i;
    }
}
";
            var comp = CreateCompilation(text);
            comp.VerifyDiagnostics(
                // (2,7): warning CS8981: The type name 'var' only contains lower-cased ascii characters. Such names may become reserved for the language.
                // using var = C;
                Diagnostic(ErrorCode.WRN_LowerCaseTypeName, "var").WithArguments("var").WithLocation(2, 7)
                );
 
            var tree = comp.SyntaxTrees.Single();
            var model = comp.GetSemanticModel(tree);
 
            var xDecl = tree.GetRoot().DescendantNodes().OfType<VariableDeclaratorSyntax>().ElementAt(1);
            Assert.Equal("C x", model.GetDeclaredSymbol(xDecl).ToTestDisplayString());
 
            var refVar = tree.GetRoot().DescendantNodes().OfType<RefTypeSyntax>().Single();
            var type = refVar.Type;
            Assert.Equal("C", model.GetTypeInfo(type).Type.ToTestDisplayString());
            Assert.Equal("C", model.GetSymbolInfo(type).Symbol.ToTestDisplayString());
            var alias = model.GetAliasInfo(type);
            Assert.Equal(SymbolKind.NamedType, alias.Target.Kind);
            Assert.Equal("C", alias.Target.ToDisplayString());
 
            Assert.Null(model.GetSymbolInfo(refVar).Symbol);
            Assert.Null(model.GetTypeInfo(refVar).Type);
        }
 
        [Fact]
        public void RefIntSemanticModel()
        {
            var text = @"
class Program
{
    static void M()
    {
        int i = 0;
        ref System.Int32 x = ref i;
    }
}
";
            var comp = CreateCompilation(text);
            comp.VerifyDiagnostics();
 
            var tree = comp.SyntaxTrees.Single();
            var model = comp.GetSemanticModel(tree);
 
            var xDecl = tree.GetRoot().DescendantNodes().OfType<VariableDeclaratorSyntax>().ElementAt(1);
            Assert.Equal("System.Int32 x", model.GetDeclaredSymbol(xDecl).ToTestDisplayString());
 
            var refInt = tree.GetRoot().DescendantNodes().OfType<RefTypeSyntax>().Single();
            var type = refInt.Type;
            Assert.Equal("System.Int32", model.GetTypeInfo(type).Type.ToTestDisplayString());
            Assert.Equal("System.Int32", model.GetSymbolInfo(type).Symbol.ToTestDisplayString());
            Assert.Null(model.GetAliasInfo(type));
 
            Assert.Null(model.GetSymbolInfo(refInt).Symbol);
            Assert.Null(model.GetTypeInfo(refInt).Type);
        }
 
        [WorkItem(17395, "https://github.com/dotnet/roslyn/issues/17453")]
        [Fact]
        public void Regression17395()
        {
            var source = @"
using System;
 
public class C 
{            
    public void F()
    {
        ref int[] a = ref {1,2,3};
        Console.WriteLine(a[0]);
 
        ref var b = ref {4, 5, 6};
        Console.WriteLine(b[0]);
 
        ref object c = ref {7,8,9};
        Console.WriteLine(c);
    }        
}
";
 
            var c = CreateCompilation(source);
 
            c.VerifyDiagnostics(
                // (8,27): error CS1510: A ref or out value must be an assignable variable
                //         ref int[] a = ref {1,2,3};
                Diagnostic(ErrorCode.ERR_RefLvalueExpected, "{1,2,3}"),
                // (11,17): error CS0820: Cannot initialize an implicitly-typed variable with an array initializer
                //         ref var b = ref {4, 5, 6};
                Diagnostic(ErrorCode.ERR_ImplicitlyTypedVariableAssignedArrayInitializer, "b = ref {4, 5, 6}").WithLocation(11, 17),
                // (14,28): error CS0622: Can only use array initializer expressions to assign to array types. Try using a new expression instead.
                //         ref object c = ref {7,8,9};
                Diagnostic(ErrorCode.ERR_ArrayInitToNonArrayType, "{7,8,9}").WithLocation(14, 28)
            );
        }
 
        [Fact, WorkItem(25264, "https://github.com/dotnet/roslyn/issues/25264"), CompilerTrait(CompilerFeature.IOperation)]
        public void TestNewRefArray()
        {
            var text = @"
public class C
{
    public static void Main()
    {
        _ = /*<bind>*/ new ref[] { 1 } /*</bind>*/ ;
    }
}
";
 
            string expectedOperationTree = @"
IInvalidOperation (OperationKind.Invalid, Type: ?, IsInvalid) (Syntax: 'new ref[] { 1 }')
  Children(1):
      IObjectOrCollectionInitializerOperation (OperationKind.ObjectOrCollectionInitializer, Type: ?[]) (Syntax: '{ 1 }')
        Initializers(1):
            IInvalidOperation (OperationKind.Invalid, Type: ?, IsImplicit) (Syntax: '1')
              Children(2):
                  IOperation:  (OperationKind.None, Type: null, IsImplicit) (Syntax: '1')
                    Children(1):
                        IInstanceReferenceOperation (ReferenceKind: ImplicitReceiver) (OperationKind.InstanceReference, Type: ?[], IsInvalid, IsImplicit) (Syntax: 'ref[]')
                  ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 1) (Syntax: '1')
";
 
            var expectedDiagnostics = new[]
            {
                // file.cs(6,28): error CS8386: Invalid object creation
                //         _ = /*<bind>*/ new ref[] { 1 } /*</bind>*/ ;
                Diagnostic(ErrorCode.ERR_InvalidObjectCreation, "ref[]").WithLocation(6, 28),
                // file.cs(6,31): error CS1031: Type expected
                //         _ = /*<bind>*/ new ref[] { 1 } /*</bind>*/ ;
                Diagnostic(ErrorCode.ERR_TypeExpected, "[").WithLocation(6, 31)
            };
 
            VerifyOperationTreeAndDiagnosticsForTest<ObjectCreationExpressionSyntax>(text, expectedOperationTree, expectedDiagnostics);
        }
 
        [Fact, WorkItem(53113, "https://github.com/dotnet/roslyn/issues/53113")]
        public void TestRefOnPointerIndirection_01()
        {
            var code = @"
using System;
 
unsafe
{
    ref int x = ref *(int*)0;
    Console.WriteLine(""run"");
}
";
 
            verify(TestOptions.UnsafeReleaseExe, Verification.Passes, @"
{
  // Code size       14 (0xe)
  .maxstack  1
  IL_0000:  ldc.i4.0
  IL_0001:  conv.i
  IL_0002:  pop
  IL_0003:  ldstr      ""run""
  IL_0008:  call       ""void System.Console.WriteLine(string)""
  IL_000d:  ret
}
");
 
            // The stloc.0 is putting a native int into an int32& local. This is terribly unsafe
            // but it is what was asked for, so oh well.
            verify(TestOptions.UnsafeDebugExe, Verification.Fails, @"
{
  // Code size       17 (0x11)
  .maxstack  1
  .locals init (int& V_0) //x
  IL_0000:  nop
  IL_0001:  ldc.i4.0
  IL_0002:  conv.i
  IL_0003:  stloc.0
  IL_0004:  ldstr      ""run""
  IL_0009:  call       ""void System.Console.WriteLine(string)""
  IL_000e:  nop
  IL_000f:  nop
  IL_0010:  ret
}
");
 
            void verify(CSharpCompilationOptions options, Verification verify, string expectedIL)
            {
                var comp = CreateCompilation(code, options: options);
                var verifier = CompileAndVerify(comp, expectedOutput: "run", verify: verify);
                verifier.VerifyDiagnostics();
                verifier.VerifyIL("<top-level-statements-entry-point>", expectedIL);
            }
        }
 
        [Fact, WorkItem(53113, "https://github.com/dotnet/roslyn/issues/53113")]
        public void TestRefOnPointerIndirection_02()
        {
            var unsafeAsPointerIl = @"
 
.class public auto ansi beforefieldinit Unsafe
    extends [mscorlib]System.Object
{
  .method public hidebysig static void* AsPointer<T>(!!T& 'value') cil managed
  {
        .maxstack 1
        ldarg.0
        conv.u
        ret
  } // end of method Unsafe::AsPointer
}
";
 
            var code = @"
using System;
 
unsafe
{
    ref int x = ref *(int*)0;
    Console.WriteLine((int)Unsafe.AsPointer(ref x));
}
";
 
            verify(TestOptions.UnsafeReleaseExe, @"
{
  // Code size       14 (0xe)
  .maxstack  1
  IL_0000:  ldc.i4.0
  IL_0001:  conv.i
  IL_0002:  call       ""void* Unsafe.AsPointer<int>(ref int)""
  IL_0007:  conv.i4
  IL_0008:  call       ""void System.Console.WriteLine(int)""
  IL_000d:  ret
}
");
 
            verify(TestOptions.UnsafeDebugExe, @"
{
  // Code size       19 (0x13)
  .maxstack  1
  .locals init (int& V_0) //x
  IL_0000:  nop
  IL_0001:  ldc.i4.0
  IL_0002:  conv.i
  IL_0003:  stloc.0
  IL_0004:  ldloc.0
  IL_0005:  call       ""void* Unsafe.AsPointer<int>(ref int)""
  IL_000a:  conv.i4
  IL_000b:  call       ""void System.Console.WriteLine(int)""
  IL_0010:  nop
  IL_0011:  nop
  IL_0012:  ret
}
");
 
            void verify(CSharpCompilationOptions options, string expectedIL)
            {
                var comp = CreateCompilationWithIL(code, unsafeAsPointerIl, options: options);
                var verifier = CompileAndVerify(comp, expectedOutput: "0", verify: Verification.Fails);
                verifier.VerifyDiagnostics();
                verifier.VerifyIL("<top-level-statements-entry-point>", expectedIL);
            }
        }
 
        [Fact, WorkItem(53113, "https://github.com/dotnet/roslyn/issues/53113")]
        public void TestRefOnPointerIndirection_03()
        {
            var code = @"
using System;
 
unsafe
{
    int i1 = 0;
    ref int i2 = ref i1;
    ref int i3 = ref i2 = ref *(int*)0;
    Console.WriteLine(""run"");
}
";
 
            verify(TestOptions.UnsafeReleaseExe, Verification.Passes, @"
{
  // Code size       16 (0x10)
  .maxstack  1
  .locals init (int V_0) //i1
  IL_0000:  ldc.i4.0
  IL_0001:  stloc.0
  IL_0002:  ldc.i4.0
  IL_0003:  conv.i
  IL_0004:  pop
  IL_0005:  ldstr      ""run""
  IL_000a:  call       ""void System.Console.WriteLine(string)""
  IL_000f:  ret
}
");
 
            verify(TestOptions.UnsafeDebugExe, Verification.Fails, @"
{
  // Code size       24 (0x18)
  .maxstack  2
  .locals init (int V_0, //i1
                int& V_1, //i2
                int& V_2) //i3
  IL_0000:  nop
  IL_0001:  ldc.i4.0
  IL_0002:  stloc.0
  IL_0003:  ldloca.s   V_0
  IL_0005:  stloc.1
  IL_0006:  ldc.i4.0
  IL_0007:  conv.i
  IL_0008:  dup
  IL_0009:  stloc.1
  IL_000a:  stloc.2
  IL_000b:  ldstr      ""run""
  IL_0010:  call       ""void System.Console.WriteLine(string)""
  IL_0015:  nop
  IL_0016:  nop
  IL_0017:  ret
}
");
 
            void verify(CSharpCompilationOptions options, Verification verify, string expectedIL)
            {
                var comp = CreateCompilation(code, options: options);
                var verifier = CompileAndVerify(comp, expectedOutput: "run", verify: verify);
                verifier.VerifyDiagnostics();
                verifier.VerifyIL("<top-level-statements-entry-point>", expectedIL);
            }
        }
 
        [Fact, WorkItem(53113, "https://github.com/dotnet/roslyn/issues/53113")]
        public void TestRefOnPointerArrayAccess_01()
        {
            var code = @"
using System;
 
unsafe
{
    ref int x = ref ((int*)0)[0];
    Console.WriteLine(""run"");
}
";
 
            verify(TestOptions.UnsafeReleaseExe, Verification.Passes, @"
{
  // Code size       14 (0xe)
  .maxstack  1
  IL_0000:  ldc.i4.0
  IL_0001:  conv.i
  IL_0002:  pop
  IL_0003:  ldstr      ""run""
  IL_0008:  call       ""void System.Console.WriteLine(string)""
  IL_000d:  ret
}
");
 
            verify(TestOptions.UnsafeDebugExe, Verification.Fails, @"
{
  // Code size       17 (0x11)
  .maxstack  1
  .locals init (int& V_0) //x
  IL_0000:  nop
  IL_0001:  ldc.i4.0
  IL_0002:  conv.i
  IL_0003:  stloc.0
  IL_0004:  ldstr      ""run""
  IL_0009:  call       ""void System.Console.WriteLine(string)""
  IL_000e:  nop
  IL_000f:  nop
  IL_0010:  ret
}
");
 
            void verify(CSharpCompilationOptions options, Verification verify, string expectedIL)
            {
                var comp = CreateCompilation(code, options: options);
                var verifier = CompileAndVerify(comp, expectedOutput: "run", verify: verify);
                verifier.VerifyDiagnostics();
                verifier.VerifyIL("<top-level-statements-entry-point>", expectedIL);
            }
        }
 
        [Fact, WorkItem(53113, "https://github.com/dotnet/roslyn/issues/53113")]
        public void TestRefOnPointerArrayAccess_02()
        {
            var code = @"
using System;
 
unsafe
{
    ref int x = ref ((int*)0)[1];
    Console.WriteLine(""run"");
}
";
 
            verify(TestOptions.UnsafeReleaseExe, Verification.Passes, @"
{
  // Code size       16 (0x10)
  .maxstack  2
  IL_0000:  ldc.i4.0
  IL_0001:  conv.i
  IL_0002:  ldc.i4.4
  IL_0003:  add
  IL_0004:  pop
  IL_0005:  ldstr      ""run""
  IL_000a:  call       ""void System.Console.WriteLine(string)""
  IL_000f:  ret
}
");
 
            verify(TestOptions.UnsafeDebugExe, Verification.Fails, @"
{
  // Code size       19 (0x13)
  .maxstack  2
  .locals init (int& V_0) //x
  IL_0000:  nop
  IL_0001:  ldc.i4.0
  IL_0002:  conv.i
  IL_0003:  ldc.i4.4
  IL_0004:  add
  IL_0005:  stloc.0
  IL_0006:  ldstr      ""run""
  IL_000b:  call       ""void System.Console.WriteLine(string)""
  IL_0010:  nop
  IL_0011:  nop
  IL_0012:  ret
}
");
 
            void verify(CSharpCompilationOptions options, Verification verify, string expectedIL)
            {
                var comp = CreateCompilation(code, options: options);
                var verifier = CompileAndVerify(comp, expectedOutput: "run", verify: verify);
                verifier.VerifyDiagnostics();
                verifier.VerifyIL("<top-level-statements-entry-point>", expectedIL);
            }
        }
 
        [Fact]
        [WorkItem(60905, "https://github.com/dotnet/roslyn/issues/60905")]
        public void ReadValueAndDiscard_01()
        {
            var source =
@"struct S { }
class Program
{
    static void Main()
    {
        F(new S[1]);
    }
    static void F(S[] a)
    {
        ref var b = ref a[0];
        _ = b;
    }
}";
            var verifier = CompileAndVerify(source, options: TestOptions.DebugExe, expectedOutput: "");
            verifier.VerifyIL("Program.F", """
{
  // Code size       17 (0x11)
  .maxstack  2
  .locals init (S& V_0) //b
  IL_0000:  nop
  IL_0001:  ldarg.0
  IL_0002:  ldc.i4.0
  IL_0003:  ldelema    "S"
  IL_0008:  stloc.0
  IL_0009:  ldloc.0
  IL_000a:  ldobj      "S"
  IL_000f:  pop
  IL_0010:  ret
}
""");
            verifier = CompileAndVerify(source, options: TestOptions.ReleaseExe, expectedOutput: "");
            verifier.VerifyIL("Program.F", """
{
  // Code size       14 (0xe)
  .maxstack  2
  IL_0000:  ldarg.0
  IL_0001:  ldc.i4.0
  IL_0002:  ldelema    "S"
  IL_0007:  ldobj      "S"
  IL_000c:  pop
  IL_000d:  ret
}
""");
        }
 
        [Fact]
        [WorkItem(60905, "https://github.com/dotnet/roslyn/issues/60905")]
        public void ReadValueAndDiscard_02()
        {
            var source =
@"struct S<T>
{
    public T F;
}
class Program
{
    static void Main()
    {
        F(new S<int>());
    }
    static void F<T>(S<T> s)
    {
        ref T t = ref s.F;
        _ = t;
    }
}";
            var verifier = CompileAndVerify(source, options: TestOptions.DebugExe, expectedOutput: "");
            verifier.VerifyIL("Program.F<T>", """
{
  // Code size       17 (0x11)
  .maxstack  1
  .locals init (T& V_0) //t
  IL_0000:  nop
  IL_0001:  ldarga.s   V_0
  IL_0003:  ldflda     "T S<T>.F"
  IL_0008:  stloc.0
  IL_0009:  ldloc.0
  IL_000a:  ldobj      "T"
  IL_000f:  pop
  IL_0010:  ret
}
""");
            verifier = CompileAndVerify(source, options: TestOptions.ReleaseExe, expectedOutput: "");
            verifier.VerifyIL("Program.F<T>", """
{
  // Code size       14 (0xe)
  .maxstack  1
  IL_0000:  ldarga.s   V_0
  IL_0002:  ldflda     "T S<T>.F"
  IL_0007:  ldobj      "T"
  IL_000c:  pop
  IL_000d:  ret
}
""");
        }
 
        [Fact]
        [WorkItem(60905, "https://github.com/dotnet/roslyn/issues/60905")]
        public void ReadValueAndDiscard_03()
        {
            var source =
@"struct S<T>
{
    public T F;
}
class Program
{
    static void Main()
    {
        var s = new S<int>();
        F(ref s);
    }
    static void F<T>(ref S<T> s)
    {
        ref T t = ref s.F;
        _ = t;
    }
}";
            var verifier = CompileAndVerify(source, options: TestOptions.DebugExe, expectedOutput: "");
            verifier.VerifyIL("Program.F<T>", """
{
  // Code size       16 (0x10)
  .maxstack  1
  .locals init (T& V_0) //t
  IL_0000:  nop
  IL_0001:  ldarg.0
  IL_0002:  ldflda     "T S<T>.F"
  IL_0007:  stloc.0
  IL_0008:  ldloc.0
  IL_0009:  ldobj      "T"
  IL_000e:  pop
  IL_000f:  ret
}
""");
            verifier = CompileAndVerify(source, options: TestOptions.ReleaseExe, expectedOutput: "");
            verifier.VerifyIL("Program.F<T>", """
{
  // Code size       13 (0xd)
  .maxstack  1
  IL_0000:  ldarg.0
  IL_0001:  ldflda     "T S<T>.F"
  IL_0006:  ldobj      "T"
  IL_000b:  pop
  IL_000c:  ret
}
""");
        }
 
        [Fact]
        [WorkItem(60905, "https://github.com/dotnet/roslyn/issues/60905")]
        public void ReadValueAndDiscard_04()
        {
            var source =
@"struct S<T>
{
    public T F;
}
class Program
{
    static void Main()
    {
        F(new S<int>());
    }
    static void F<T>(in S<T> s)
    {
        ref readonly T t = ref s.F;
        _ = t;
    }
}";
            var verifier = CompileAndVerify(source, options: TestOptions.DebugExe, expectedOutput: "");
            verifier.VerifyIL("Program.F<T>", """
{
  // Code size       16 (0x10)
  .maxstack  1
  .locals init (T& V_0) //t
  IL_0000:  nop
  IL_0001:  ldarg.0
  IL_0002:  ldflda     "T S<T>.F"
  IL_0007:  stloc.0
  IL_0008:  ldloc.0
  IL_0009:  ldobj      "T"
  IL_000e:  pop
  IL_000f:  ret
}
""");
            verifier = CompileAndVerify(source, options: TestOptions.ReleaseExe, expectedOutput: "");
            verifier.VerifyIL("Program.F<T>", """
{
  // Code size       13 (0xd)
  .maxstack  1
  IL_0000:  ldarg.0
  IL_0001:  ldflda     "T S<T>.F"
  IL_0006:  ldobj      "T"
  IL_000b:  pop
  IL_000c:  ret
}
""");
        }
 
        [Fact]
        public void ReadValueAndDiscard_05()
        {
            var source =
@"struct S<T>
{
}
class Program
{
    static void Main()
    {
        var s = new S<int>();
        F(ref s);
    }
    static void F<T>(ref S<T> s)
    {
        _ = s;
    }
}";
            var verifier = CompileAndVerify(source, options: TestOptions.DebugExe, expectedOutput: "");
            verifier.VerifyIL("Program.F<T>",
@"{
  // Code size        3 (0x3)
  .maxstack  0
  IL_0000:  nop
  IL_0001:  nop
  IL_0002:  ret
}");
            verifier = CompileAndVerify(source, options: TestOptions.ReleaseExe, expectedOutput: "");
            verifier.VerifyIL("Program.F<T>",
@"{
  // Code size        1 (0x1)
  .maxstack  0
  IL_0000:  ret
}");
        }
 
        [Fact]
        public void ReadValueAndDiscard_06()
        {
            var source =
@"struct S<T>
{
}
class Program
{
    static void Main()
    {
        F(new S<int>());
    }
    static void F<T>(in S<T> s)
    {
        _ = s;
    }
}";
            var verifier = CompileAndVerify(source, options: TestOptions.DebugExe, expectedOutput: "");
            verifier.VerifyIL("Program.F<T>",
@"{
  // Code size        3 (0x3)
  .maxstack  0
  IL_0000:  nop
  IL_0001:  nop
  IL_0002:  ret
}");
            verifier = CompileAndVerify(source, options: TestOptions.ReleaseExe, expectedOutput: "");
            verifier.VerifyIL("Program.F<T>",
@"{
  // Code size        1 (0x1)
  .maxstack  0
  IL_0000:  ret
}");
        }
    }
}