File: CodeGen\CodeGenAwaitForeachTests.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.CodeGen
{
    [CompilerTrait(CompilerFeature.AsyncStreams)]
    public class CodeGenAwaitForeachTests : EmitMetadataTestBase
    {
        [Fact]
        public void TestWithCSharp7_3()
        {
            string source = @"
using System.Collections.Generic;
class C : IAsyncEnumerable<int>
{
    public static async System.Threading.Tasks.Task Main()
    {
        await foreach (int i in new C())
        {
        }
    }
    IAsyncEnumerator<int> IAsyncEnumerable<int>.GetAsyncEnumerator(System.Threading.CancellationToken token)
        => throw null;
}";
            var expected = new[]
            {
                // (7,9): error CS8652: The feature 'async streams' is not available in C# 7.3. Please use language version 8.0 or greater.
                //         await foreach (int i in new C())
                Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7_3, "await").WithArguments("async streams", "8.0").WithLocation(7, 9)
            };
 
            var comp = CreateCompilationWithTasksExtensions(new[] { source, s_IAsyncEnumerable }, parseOptions: TestOptions.Regular7_3);
            comp.VerifyDiagnostics(expected);
 
            comp = CreateCompilationWithTasksExtensions(new[] { source, s_IAsyncEnumerable }, parseOptions: TestOptions.Regular8);
            comp.VerifyDiagnostics();
        }
 
        [Fact]
        public void TestDeconstructionWithCSharp7_3()
        {
            string source = @"
using System.Collections.Generic;
class C : IAsyncEnumerable<(int, int)>
{
    public static async System.Threading.Tasks.Task Main()
    {
        await foreach (var (i, j) in new C())
        {
        }
    }
    IAsyncEnumerator<(int, int)> IAsyncEnumerable<(int, int)>.GetAsyncEnumerator(System.Threading.CancellationToken token)
        => throw null;
}";
            var expected = new[]
            {
                // (7,9): error CS8652: The feature 'async streams' is not available in C# 7.3. Please use language version 8.0 or greater.
                //         await foreach (int i in new C())
                Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7_3, "await").WithArguments("async streams", "8.0").WithLocation(7, 9)
            };
 
            var comp = CreateCompilationWithTasksExtensions(new[] { source, s_IAsyncEnumerable }, parseOptions: TestOptions.Regular7_3);
            comp.VerifyDiagnostics(expected);
 
            comp = CreateCompilationWithTasksExtensions(new[] { source, s_IAsyncEnumerable }, parseOptions: TestOptions.Regular8);
            comp.VerifyDiagnostics();
        }
 
        [Fact]
        public void TestWithMissingValueTask()
        {
            string lib_cs = @"
using System.Collections.Generic;
public class C : IAsyncEnumerable<int>
{
    IAsyncEnumerator<int> IAsyncEnumerable<int>.GetAsyncEnumerator(System.Threading.CancellationToken token)
        => throw null;
}";
 
            var lib = CreateCompilationWithTasksExtensions(new[] { lib_cs, s_IAsyncEnumerable });
            lib.VerifyDiagnostics();
 
            string source = @"
class D
{
    public static async System.Threading.Tasks.Task Main()
    {
        await foreach (int i in new C()) { }
    }
}
";
            var comp = CreateCompilationWithTasksExtensions(source, references: new[] { lib.EmitToImageReference() });
            comp.MakeTypeMissing(WellKnownType.System_Threading_Tasks_ValueTask);
            comp.VerifyDiagnostics(
                // (6,9): error CS0518: Predefined type 'System.Threading.Tasks.ValueTask' is not defined or imported
                //         await foreach (int i in new C()) { }
                Diagnostic(ErrorCode.ERR_PredefinedTypeNotFound, "await foreach (int i in new C()) { }").WithArguments("System.Threading.Tasks.ValueTask").WithLocation(6, 9)
                );
        }
 
        [Fact]
        public void TestWithIAsyncEnumerator()
        {
            string source = @"
using System.Collections.Generic;
using System.Threading.Tasks;
public class C
{
    async Task M(IAsyncEnumerator<int> enumerator)
    {
        await foreach (int i in enumerator) { }
    }
}
";
            var comp_checked = CreateCompilationWithTasksExtensions(new[] { source, s_IAsyncEnumerable });
            comp_checked.VerifyDiagnostics(
                // (8,33): error CS8411: Async foreach statement cannot operate on variables of type 'IAsyncEnumerator<int>' because 'IAsyncEnumerator<int>' does not contain a suitable public instance or extension definition for 'GetAsyncEnumerator'
                //         await foreach (int i in enumerator) { }
                Diagnostic(ErrorCode.ERR_AwaitForEachMissingMember, "enumerator").WithArguments("System.Collections.Generic.IAsyncEnumerator<int>", "GetAsyncEnumerator").WithLocation(8, 33)
                );
        }
 
        [Fact]
        public void TestWithUIntToIntConversion()
        {
            string source = @"
using System.Collections.Generic;
using System.Threading.Tasks;
public class C : IAsyncEnumerable<uint>
{
    public static async Task Main()
    {
        try
        {
            REPLACE
            {
                await foreach (int i in new C()) { System.Console.Write($""0x{i:X8}""); }
            }
        }
        catch (System.OverflowException)
        {
            System.Console.Write(""overflow"");
        }
    }
 
    public IAsyncEnumerator<uint> GetAsyncEnumerator(System.Threading.CancellationToken token)
        => new AsyncEnumerator();
    public sealed class AsyncEnumerator : IAsyncEnumerator<uint>
    {
        bool firstValue = true;
        public uint Current => 0xFFFFFFFF;
        public async ValueTask<bool> MoveNextAsync()
        {
            await Task.Yield();
            bool result = firstValue;
            firstValue = false;
            return result;
        }
        public async ValueTask DisposeAsync()
        {
            await Task.Yield();
        }
    }
}
";
            var checkedSource = source.Replace("REPLACE", "checked");
            var comp_checked = CreateCompilationWithTasksExtensions(new[] { checkedSource, s_IAsyncEnumerable }, options: TestOptions.DebugExe);
            comp_checked.VerifyDiagnostics();
            CompileAndVerify(comp_checked, expectedOutput: "overflow");
 
            var uncheckedSource = source.Replace("REPLACE", "unchecked");
            var comp_unchecked = CreateCompilationWithTasksExtensions(new[] { uncheckedSource, s_IAsyncEnumerable }, options: TestOptions.DebugExe);
            comp_unchecked.VerifyDiagnostics();
            CompileAndVerify(comp_unchecked, expectedOutput: "0xFFFFFFFF");
 
            var runtimeAsyncCompChecked = CreateRuntimeAsyncCompilation(checkedSource);
            var verifierChecked = CompileAndVerify(runtimeAsyncCompChecked, expectedOutput: CodeGenAsyncTests.ExpectedOutput("overflow", isRuntimeAsync: true), verify: Verification.Fails with
            {
                ILVerifyMessage = """
                    [Main]: Return value missing on the stack. { Offset = 0x95 }
                    [MoveNextAsync]: Unexpected type on the stack. { Offset = 0x31, Found = Int32, Expected = value '[System.Runtime]System.Threading.Tasks.ValueTask`1<bool>' }
                    [DisposeAsync]: Return value missing on the stack. { Offset = 0x24 }
                    """
            });
            verifierChecked.VerifyIL("C.Main()", """
                {
                  // Code size      150 (0x96)
                  .maxstack  3
                  .locals init (System.Collections.Generic.IAsyncEnumerator<uint> V_0,
                                System.Threading.CancellationToken V_1,
                                object V_2,
                                int V_3, //i
                                System.Runtime.CompilerServices.DefaultInterpolatedStringHandler V_4)
                  .try
                  {
                    IL_0000:  newobj     "C..ctor()"
                    IL_0005:  ldloca.s   V_1
                    IL_0007:  initobj    "System.Threading.CancellationToken"
                    IL_000d:  ldloc.1
                    IL_000e:  callvirt   "System.Collections.Generic.IAsyncEnumerator<uint> System.Collections.Generic.IAsyncEnumerable<uint>.GetAsyncEnumerator(System.Threading.CancellationToken)"
                    IL_0013:  stloc.0
                    IL_0014:  ldnull
                    IL_0015:  stloc.2
                    .try
                    {
                      IL_0016:  br.s       IL_004e
                      IL_0018:  ldloc.0
                      IL_0019:  callvirt   "uint System.Collections.Generic.IAsyncEnumerator<uint>.Current.get"
                      IL_001e:  conv.ovf.i4.un
                      IL_001f:  stloc.3
                      IL_0020:  ldc.i4.2
                      IL_0021:  ldc.i4.1
                      IL_0022:  newobj     "System.Runtime.CompilerServices.DefaultInterpolatedStringHandler..ctor(int, int)"
                      IL_0027:  stloc.s    V_4
                      IL_0029:  ldloca.s   V_4
                      IL_002b:  ldstr      "0x"
                      IL_0030:  call       "void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendLiteral(string)"
                      IL_0035:  ldloca.s   V_4
                      IL_0037:  ldloc.3
                      IL_0038:  ldstr      "X8"
                      IL_003d:  call       "void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted<int>(int, string)"
                      IL_0042:  ldloca.s   V_4
                      IL_0044:  call       "string System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.ToStringAndClear()"
                      IL_0049:  call       "void System.Console.Write(string)"
                      IL_004e:  ldloc.0
                      IL_004f:  callvirt   "System.Threading.Tasks.ValueTask<bool> System.Collections.Generic.IAsyncEnumerator<uint>.MoveNextAsync()"
                      IL_0054:  call       "bool System.Runtime.CompilerServices.AsyncHelpers.Await<bool>(System.Threading.Tasks.ValueTask<bool>)"
                      IL_0059:  brtrue.s   IL_0018
                      IL_005b:  leave.s    IL_0060
                    }
                    catch object
                    {
                      IL_005d:  stloc.2
                      IL_005e:  leave.s    IL_0060
                    }
                    IL_0060:  ldloc.0
                    IL_0061:  brfalse.s  IL_006e
                    IL_0063:  ldloc.0
                    IL_0064:  callvirt   "System.Threading.Tasks.ValueTask System.IAsyncDisposable.DisposeAsync()"
                    IL_0069:  call       "void System.Runtime.CompilerServices.AsyncHelpers.Await(System.Threading.Tasks.ValueTask)"
                    IL_006e:  ldloc.2
                    IL_006f:  brfalse.s  IL_0086
                    IL_0071:  ldloc.2
                    IL_0072:  isinst     "System.Exception"
                    IL_0077:  dup
                    IL_0078:  brtrue.s   IL_007c
                    IL_007a:  ldloc.2
                    IL_007b:  throw
                    IL_007c:  call       "System.Runtime.ExceptionServices.ExceptionDispatchInfo System.Runtime.ExceptionServices.ExceptionDispatchInfo.Capture(System.Exception)"
                    IL_0081:  callvirt   "void System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()"
                    IL_0086:  leave.s    IL_0095
                  }
                  catch System.OverflowException
                  {
                    IL_0088:  pop
                    IL_0089:  ldstr      "overflow"
                    IL_008e:  call       "void System.Console.Write(string)"
                    IL_0093:  leave.s    IL_0095
                  }
                  IL_0095:  ret
                }
                """);
 
            var runtimeAsyncCompUnchecked = CreateRuntimeAsyncCompilation(uncheckedSource);
            var verifierUnchecked = CompileAndVerify(runtimeAsyncCompUnchecked, expectedOutput: CodeGenAsyncTests.ExpectedOutput("0xFFFFFFFF", isRuntimeAsync: true), verify: Verification.Fails with
            {
                ILVerifyMessage = """
                    [Main]: Return value missing on the stack. { Offset = 0x94 }
                    [MoveNextAsync]: Unexpected type on the stack. { Offset = 0x31, Found = Int32, Expected = value '[System.Runtime]System.Threading.Tasks.ValueTask`1<bool>' }
                    [DisposeAsync]: Return value missing on the stack. { Offset = 0x24 }
                    """
            });
            verifierUnchecked.VerifyIL("C.Main()", """
                {
                  // Code size      149 (0x95)
                  .maxstack  3
                  .locals init (System.Collections.Generic.IAsyncEnumerator<uint> V_0,
                                System.Threading.CancellationToken V_1,
                                object V_2,
                                int V_3, //i
                                System.Runtime.CompilerServices.DefaultInterpolatedStringHandler V_4)
                  .try
                  {
                    IL_0000:  newobj     "C..ctor()"
                    IL_0005:  ldloca.s   V_1
                    IL_0007:  initobj    "System.Threading.CancellationToken"
                    IL_000d:  ldloc.1
                    IL_000e:  callvirt   "System.Collections.Generic.IAsyncEnumerator<uint> System.Collections.Generic.IAsyncEnumerable<uint>.GetAsyncEnumerator(System.Threading.CancellationToken)"
                    IL_0013:  stloc.0
                    IL_0014:  ldnull
                    IL_0015:  stloc.2
                    .try
                    {
                      IL_0016:  br.s       IL_004d
                      IL_0018:  ldloc.0
                      IL_0019:  callvirt   "uint System.Collections.Generic.IAsyncEnumerator<uint>.Current.get"
                      IL_001e:  stloc.3
                      IL_001f:  ldc.i4.2
                      IL_0020:  ldc.i4.1
                      IL_0021:  newobj     "System.Runtime.CompilerServices.DefaultInterpolatedStringHandler..ctor(int, int)"
                      IL_0026:  stloc.s    V_4
                      IL_0028:  ldloca.s   V_4
                      IL_002a:  ldstr      "0x"
                      IL_002f:  call       "void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendLiteral(string)"
                      IL_0034:  ldloca.s   V_4
                      IL_0036:  ldloc.3
                      IL_0037:  ldstr      "X8"
                      IL_003c:  call       "void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted<int>(int, string)"
                      IL_0041:  ldloca.s   V_4
                      IL_0043:  call       "string System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.ToStringAndClear()"
                      IL_0048:  call       "void System.Console.Write(string)"
                      IL_004d:  ldloc.0
                      IL_004e:  callvirt   "System.Threading.Tasks.ValueTask<bool> System.Collections.Generic.IAsyncEnumerator<uint>.MoveNextAsync()"
                      IL_0053:  call       "bool System.Runtime.CompilerServices.AsyncHelpers.Await<bool>(System.Threading.Tasks.ValueTask<bool>)"
                      IL_0058:  brtrue.s   IL_0018
                      IL_005a:  leave.s    IL_005f
                    }
                    catch object
                    {
                      IL_005c:  stloc.2
                      IL_005d:  leave.s    IL_005f
                    }
                    IL_005f:  ldloc.0
                    IL_0060:  brfalse.s  IL_006d
                    IL_0062:  ldloc.0
                    IL_0063:  callvirt   "System.Threading.Tasks.ValueTask System.IAsyncDisposable.DisposeAsync()"
                    IL_0068:  call       "void System.Runtime.CompilerServices.AsyncHelpers.Await(System.Threading.Tasks.ValueTask)"
                    IL_006d:  ldloc.2
                    IL_006e:  brfalse.s  IL_0085
                    IL_0070:  ldloc.2
                    IL_0071:  isinst     "System.Exception"
                    IL_0076:  dup
                    IL_0077:  brtrue.s   IL_007b
                    IL_0079:  ldloc.2
                    IL_007a:  throw
                    IL_007b:  call       "System.Runtime.ExceptionServices.ExceptionDispatchInfo System.Runtime.ExceptionServices.ExceptionDispatchInfo.Capture(System.Exception)"
                    IL_0080:  callvirt   "void System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()"
                    IL_0085:  leave.s    IL_0094
                  }
                  catch System.OverflowException
                  {
                    IL_0087:  pop
                    IL_0088:  ldstr      "overflow"
                    IL_008d:  call       "void System.Console.Write(string)"
                    IL_0092:  leave.s    IL_0094
                  }
                  IL_0094:  ret
                }
                """);
        }
 
        [Fact]
        public void TestWithTwoIAsyncEnumerableImplementations()
        {
            string source = @"
using System.Collections.Generic;
class C : IAsyncEnumerable<int>, IAsyncEnumerable<string>
{
    public static async System.Threading.Tasks.Task Main()
    {
        await foreach (int i in new C())
        {
        }
    }
    IAsyncEnumerator<int> IAsyncEnumerable<int>.GetAsyncEnumerator(System.Threading.CancellationToken token)
        => throw null;
    IAsyncEnumerator<string> IAsyncEnumerable<string>.GetAsyncEnumerator(System.Threading.CancellationToken token)
        => throw null;
}";
            var comp = CreateCompilationWithTasksExtensions(new[] { source, s_IAsyncEnumerable });
            comp.VerifyDiagnostics(
                // (7,33): error CS8413: Async foreach statement cannot operate on variables of type 'C' because it implements multiple instantiations of 'IAsyncEnumerable<T>'; try casting to a specific interface instantiation
                //         await foreach (int i in new C())
                Diagnostic(ErrorCode.ERR_MultipleIAsyncEnumOfT, "new C()").WithArguments("C", "System.Collections.Generic.IAsyncEnumerable<T>").WithLocation(7, 33)
                );
        }
 
        [Fact]
        public void TestWithMissingPattern()
        {
            string source = @"
class C
{
    async System.Threading.Tasks.Task M()
    {
        await foreach (var i in new C())
        {
        }
    }
}";
            var comp = CreateCompilationWithMscorlib46(source);
            comp.VerifyDiagnostics(
                // (6,33): error CS8411: Async foreach statement cannot operate on variables of type 'C' because 'C' does not contain a suitable public instance or extension definition for 'GetAsyncEnumerator'
                //         await foreach (var i in new C())
                Diagnostic(ErrorCode.ERR_AwaitForEachMissingMember, "new C()").WithArguments("C", "GetAsyncEnumerator").WithLocation(6, 33)
                );
        }
 
        [Fact]
        public void TestWithStaticGetEnumerator()
        {
            string source = @"
class C
{
    async System.Threading.Tasks.Task M()
    {
        await foreach (var i in new C())
        {
        }
    }
    public static Enumerator GetAsyncEnumerator(System.Threading.CancellationToken token)
    {
        throw null;
    }
    public sealed class Enumerator
    {
    }
}";
            var comp = CreateCompilationWithMscorlib46(source);
            comp.VerifyDiagnostics(
                // (6,33): error CS8411: Async foreach statement cannot operate on variables of type 'C' because 'C' does not contain a suitable public instance or extension definition for 'GetAsyncEnumerator'
                //         await foreach (var i in new C())
                Diagnostic(ErrorCode.ERR_AwaitForEachMissingMember, "new C()").WithArguments("C", "GetAsyncEnumerator").WithLocation(6, 33)
                );
        }
 
        [Fact]
        public void TestWithInaccessibleGetEnumerator()
        {
            string source = @"
class C
{
    async System.Threading.Tasks.Task M()
    {
        await foreach (var i in new C())
        {
        }
    }
    internal Enumerator GetAsyncEnumerator(System.Threading.CancellationToken token = default)
    {
        throw null;
    }
    public sealed class Enumerator
    {
    }
}";
            var comp = CreateCompilationWithMscorlib46(source);
            comp.VerifyDiagnostics(
                // (6,33): warning CS0279: 'C' does not implement the 'async streams' pattern. 'C.GetAsyncEnumerator(System.Threading.CancellationToken)' is not a public instance or extension method.
                //         await foreach (var i in new C())
                Diagnostic(ErrorCode.WRN_PatternNotPublicOrNotInstance, "new C()").WithArguments("C", "async streams", "C.GetAsyncEnumerator(System.Threading.CancellationToken)").WithLocation(6, 33),
                // (6,33): error CS8411: Async foreach statement cannot operate on variables of type 'C' because 'C' does not contain a public definition for 'GetAsyncEnumerator'
                //         await foreach (var i in new C())
                Diagnostic(ErrorCode.ERR_AwaitForEachMissingMember, "new C()").WithArguments("C", "GetAsyncEnumerator").WithLocation(6, 33)
                );
        }
 
        [Fact]
        public void TestWithObsoletePatternMethods()
        {
            string source = @"
class C
{
    async System.Threading.Tasks.Task M()
    {
        await foreach (var i in new C())
        {
        }
    }
    [System.Obsolete]
    public Enumerator GetAsyncEnumerator(System.Threading.CancellationToken token = default)
    {
        throw null;
    }
    public sealed class Enumerator
    {
        [System.Obsolete]
        public System.Threading.Tasks.Task<bool> MoveNextAsync()
        {
            throw null;
        }
        [System.Obsolete]
        public int Current
        {
            get => throw null;
        }
     }
}";
            var comp = CreateCompilationWithMscorlib46(source);
            comp.VerifyDiagnostics(
                // (6,15): warning CS0612: 'C.GetAsyncEnumerator(CancellationToken)' is obsolete
                //         await foreach (var i in new C())
                Diagnostic(ErrorCode.WRN_DeprecatedSymbol, "foreach").WithArguments("C.GetAsyncEnumerator(System.Threading.CancellationToken)").WithLocation(6, 15),
                // (6,15): warning CS0612: 'C.Enumerator.MoveNextAsync()' is obsolete
                //         await foreach (var i in new C())
                Diagnostic(ErrorCode.WRN_DeprecatedSymbol, "foreach").WithArguments("C.Enumerator.MoveNextAsync()").WithLocation(6, 15),
                // (6,15): warning CS0612: 'C.Enumerator.Current' is obsolete
                //         await foreach (var i in new C())
                Diagnostic(ErrorCode.WRN_DeprecatedSymbol, "foreach").WithArguments("C.Enumerator.Current").WithLocation(6, 15)
                );
        }
 
        [Fact]
        public void TestWithMoveNextAsync_ReturnsValueTaskOfObject()
        {
            string source = @"
class C
{
    async System.Threading.Tasks.Task M()
    {
        await foreach (var i in new C()) { }
    }
    public Enumerator GetAsyncEnumerator() => throw null;
    public sealed class Enumerator
    {
        public System.Threading.Tasks.Task<object> MoveNextAsync() => throw null;
        public int Current => throw null;
    }
}";
            var comp = CreateCompilationWithMscorlib46(source);
            comp.VerifyDiagnostics(
                // (6,33): error CS8412: Asynchronous foreach requires that the return type 'C.Enumerator' of 'C.GetAsyncEnumerator()' must have a suitable public 'MoveNextAsync' method and public 'Current' property
                //         await foreach (var i in new C()) { }
                Diagnostic(ErrorCode.ERR_BadGetAsyncEnumerator, "new C()").WithArguments("C.Enumerator", "C.GetAsyncEnumerator()").WithLocation(6, 33)
                );
        }
 
        [Theory, CombinatorialData, WorkItem(65363, "https://github.com/dotnet/roslyn/issues/65363")]
        public void TestWithMoveNextAsync_ReturnsValueTaskOfObject_Extension(bool useCsharp8)
        {
            string source = @"
class C
{
    async System.Threading.Tasks.Task M()
    {
        await foreach (var i in new C()) { }
    }
}
static class Extension
{
    public static Enumerator GetAsyncEnumerator(this C c) => throw null;
}
public sealed class Enumerator
{
    public System.Threading.Tasks.Task<object> MoveNextAsync() => throw null;
    public int Current => throw null;
}
";
            var comp = CreateCompilationWithMscorlib46(source, parseOptions: useCsharp8 ? TestOptions.Regular8 : TestOptions.Regular9);
            if (useCsharp8)
            {
                comp.VerifyDiagnostics(
                    // (6,33): error CS8400: Feature 'extension GetAsyncEnumerator' is not available in C# 8.0. Please use language version 9.0 or greater.
                    //         await foreach (var i in new C()) { }
                    Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion8, "new C()").WithArguments("extension GetAsyncEnumerator", "9.0").WithLocation(6, 33),
                    // (6,33): error CS8412: Asynchronous foreach requires that the return type 'Enumerator' of 'Extension.GetAsyncEnumerator(C)' must have a suitable public 'MoveNextAsync' method and public 'Current' property
                    //         await foreach (var i in new C()) { }
                    Diagnostic(ErrorCode.ERR_BadGetAsyncEnumerator, "new C()").WithArguments("Enumerator", "Extension.GetAsyncEnumerator(C)").WithLocation(6, 33)
                    );
            }
            else
            {
                comp.VerifyDiagnostics(
                    // (6,33): error CS8412: Asynchronous foreach requires that the return type 'Enumerator' of 'Extension.GetAsyncEnumerator(C)' must have a suitable public 'MoveNextAsync' method and public 'Current' property
                    //         await foreach (var i in new C()) { }
                    Diagnostic(ErrorCode.ERR_BadGetAsyncEnumerator, "new C()").WithArguments("Enumerator", "Extension.GetAsyncEnumerator(C)").WithLocation(6, 33)
                    );
            }
        }
 
        [Fact]
        public void TestWithMoveNextAsync_ReturnsObject()
        {
            string source = @"
class C
{
    async System.Threading.Tasks.Task M()
    {
        await foreach (var i in new C())
        {
        }
    }
    public Enumerator GetAsyncEnumerator() => throw null;
    public sealed class Enumerator
    {
        public System.Threading.Tasks.Task<object> MoveNextAsync() => throw null; // returns Task<object>
        public int Current { get => throw null; }
    }
}";
            var comp = CreateCompilationWithMscorlib46(source);
            comp.VerifyDiagnostics(
                // (6,33): error CS8412: Asynchronous foreach requires that the return type 'C.Enumerator' of 'C.GetAsyncEnumerator()' must have a suitable public 'MoveNextAsync' method and public 'Current' property
                //         await foreach (var i in new C())
                Diagnostic(ErrorCode.ERR_BadGetAsyncEnumerator, "new C()").WithArguments("C.Enumerator", "C.GetAsyncEnumerator()").WithLocation(6, 33)
                );
        }
 
        [Fact]
        public void TestWithMoveNextAsync_Static()
        {
            string source = @"
class C
{
    async System.Threading.Tasks.Task M()
    {
        await foreach (var i in new C())
        {
        }
    }
    public Enumerator GetAsyncEnumerator(System.Threading.CancellationToken token = default)
    {
        throw null;
    }
    public sealed class Enumerator
    {
        public static System.Threading.Tasks.Task<bool> MoveNextAsync()
        {
            throw null;
        }
        public int Current
        {
            get => throw null;
        }
    }
}";
            var comp = CreateCompilationWithMscorlib46(source);
            comp.VerifyDiagnostics(
                // (6,33): error CS8412: Asynchronous foreach requires that the return type 'C.Enumerator' of 'C.GetAsyncEnumerator(CancellationToken)' must have a suitable public 'MoveNextAsync' method and public 'Current' property
                //         await foreach (var i in new C())
                Diagnostic(ErrorCode.ERR_BadGetAsyncEnumerator, "new C()").WithArguments("C.Enumerator", "C.GetAsyncEnumerator(System.Threading.CancellationToken)").WithLocation(6, 33)
                );
        }
 
        [Fact]
        public void TestWithCurrent_Static()
        {
            string source = @"
class C
{
    async System.Threading.Tasks.Task M()
    {
        await foreach (var i in new C()) { }
    }
    public Enumerator GetAsyncEnumerator()
        => throw null;
    public sealed class Enumerator
    {
        public System.Threading.Tasks.Task<bool> MoveNextAsync()
            => throw null;
        public static int Current
        {
            get => throw null;
        }
    }
}";
            var comp = CreateCompilationWithMscorlib46(source);
            comp.VerifyDiagnostics(
                // (6,33): error CS8412: Asynchronous foreach requires that the return type 'C.Enumerator' of 'C.GetAsyncEnumerator()' must have a suitable public 'MoveNextAsync' method and public 'Current' property
                //         await foreach (var i in new C()) { }
                Diagnostic(ErrorCode.ERR_BadGetAsyncEnumerator, "new C()").WithArguments("C.Enumerator", "C.GetAsyncEnumerator()").WithLocation(6, 33)
                );
        }
 
        [Fact]
        public void TestWithMoveNextAsync_NonPublic()
        {
            string source = @"
class C
{
    async System.Threading.Tasks.Task M()
    {
        await foreach (var i in new C()) { }
    }
    public Enumerator GetAsyncEnumerator()
        => throw null;
    public sealed class Enumerator
    {
        internal System.Threading.Tasks.Task<bool> MoveNextAsync()
            => throw null;
        public int Current
            => throw null;
    }
}";
            var comp = CreateCompilationWithMscorlib46(source);
            comp.VerifyDiagnostics(
                // (6,33): error CS8412: Asynchronous foreach requires that the return type 'C.Enumerator' of 'C.GetAsyncEnumerator()' must have a suitable public 'MoveNextAsync' method and public 'Current' property
                //         await foreach (var i in new C()) { }
                Diagnostic(ErrorCode.ERR_BadGetAsyncEnumerator, "new C()").WithArguments("C.Enumerator", "C.GetAsyncEnumerator()").WithLocation(6, 33)
                );
        }
 
        [Fact]
        public void TestWithCurrent_NonPublicProperty()
        {
            string source = @"
class C
{
    async System.Threading.Tasks.Task M()
    {
        await foreach (var i in new C()) { }
    }
    public Enumerator GetAsyncEnumerator(System.Threading.CancellationToken token = default)
        => throw null;
    public sealed class Enumerator
    {
        public System.Threading.Tasks.Task<bool> MoveNextAsync()
            => throw null;
        private int Current
        {
            get => throw null;
        }
    }
}";
            var comp = CreateCompilationWithMscorlib46(source);
            comp.VerifyDiagnostics(
                // (6,33): error CS0122: 'C.Enumerator.Current' is inaccessible due to its protection level
                //         await foreach (var i in new C()) { }
                Diagnostic(ErrorCode.ERR_BadAccess, "new C()").WithArguments("C.Enumerator.Current").WithLocation(6, 33),
                // (6,33): error CS8412: Asynchronous foreach requires that the return type 'C.Enumerator' of 'C.GetAsyncEnumerator(CancellationToken)' must have a suitable public 'MoveNextAsync' method and public 'Current' property
                //         await foreach (var i in new C()) { }
                Diagnostic(ErrorCode.ERR_BadGetAsyncEnumerator, "new C()").WithArguments("C.Enumerator", "C.GetAsyncEnumerator(System.Threading.CancellationToken)").WithLocation(6, 33)
                );
        }
 
        [Fact]
        public void TestWithCurrent_NonPublicGetter()
        {
            string source = @"
class C
{
    async System.Threading.Tasks.Task M()
    {
        await foreach (var i in new C()) { }
    }
    public Enumerator GetAsyncEnumerator()
        => throw null;
    public sealed class Enumerator
    {
        public System.Threading.Tasks.Task<bool> MoveNextAsync()
            => throw null;
        public int Current
        {
            private get => throw null;
            set => throw null;
        }
    }
}";
            var comp = CreateCompilationWithMscorlib46(source);
            comp.VerifyDiagnostics(
                // (6,33): error CS8412: Asynchronous foreach requires that the return type 'C.Enumerator' of 'C.GetAsyncEnumerator()' must have a suitable public 'MoveNextAsync' method and public 'Current' property
                //         await foreach (var i in new C()) { }
                Diagnostic(ErrorCode.ERR_BadGetAsyncEnumerator, "new C()").WithArguments("C.Enumerator", "C.GetAsyncEnumerator()").WithLocation(6, 33)
                );
        }
 
        [Fact]
        public void TestWithCurrent_MissingGetter()
        {
            string source = @"
class C
{
    async System.Threading.Tasks.Task M()
    {
        await foreach (var i in new C()) { }
    }
    public Enumerator GetAsyncEnumerator(System.Threading.CancellationToken token = default)
        => throw null;
    public sealed class Enumerator
    {
        public System.Threading.Tasks.Task<bool> MoveNextAsync()
            => throw null;
        public int Current
        {
            set => throw null;
        }
    }
}";
            var comp = CreateCompilationWithMscorlib46(source);
            comp.VerifyDiagnostics(
                // (6,33): error CS8412: Asynchronous foreach requires that the return type 'C.Enumerator' of 'C.GetAsyncEnumerator(CancellationToken)' must have a suitable public 'MoveNextAsync' method and public 'Current' property
                //         await foreach (var i in new C()) { }
                Diagnostic(ErrorCode.ERR_BadGetAsyncEnumerator, "new C()").WithArguments("C.Enumerator", "C.GetAsyncEnumerator(System.Threading.CancellationToken)").WithLocation(6, 33)
                );
        }
 
        [Fact]
        public void TestWithCurrent_MissingGetterOnInterface()
        {
            string source = @"
using System.Collections.Generic;
using System.Threading.Tasks;
class C : IAsyncEnumerable<int>
{
    public static async Task M(C c)
    {
        await foreach (var i in c)
        {
        }
    }
    public IAsyncEnumerator<int> GetAsyncEnumerator(System.Threading.CancellationToken token = default) => throw null;
}
namespace System.Collections.Generic
{
    public interface IAsyncEnumerable<out T>
    {
        IAsyncEnumerator<T> GetAsyncEnumerator(System.Threading.CancellationToken token = default);
    }
 
    public interface IAsyncEnumerator<out T> : System.IAsyncDisposable
    {
        System.Threading.Tasks.Task<bool> MoveNextAsync();
        T Current { set; }
    }
}
namespace System
{
    public interface IAsyncDisposable
    {
        System.Threading.Tasks.ValueTask DisposeAsync();
    }
}
";
            var comp = CreateCompilationWithTasksExtensions(source);
            comp.VerifyEmitDiagnostics(
                // (8,33): error CS8412: Asynchronous foreach requires that the return type 'IAsyncEnumerator<int>' of 'C.GetAsyncEnumerator(CancellationToken)' must have a suitable public 'MoveNextAsync' method and public 'Current' property
                //         await foreach (var i in c)
                Diagnostic(ErrorCode.ERR_BadGetAsyncEnumerator, "c").WithArguments("System.Collections.Generic.IAsyncEnumerator<int>", "C.GetAsyncEnumerator(System.Threading.CancellationToken)").WithLocation(8, 33),
                // (24,9): error CS1961: Invalid variance: The type parameter 'T' must be contravariantly valid on 'IAsyncEnumerator<T>.Current'. 'T' is covariant.
                //         T Current { set; }
                Diagnostic(ErrorCode.ERR_UnexpectedVariance, "T").WithArguments("System.Collections.Generic.IAsyncEnumerator<T>.Current", "T", "covariant", "contravariantly").WithLocation(24, 9)
                );
        }
 
        [Fact]
        public void TestWithCurrent_MissingPropertyOnInterface()
        {
            string source = @"
using System.Collections.Generic;
using System.Threading.Tasks;
class C : IAsyncEnumerable<int>
{
    public static async Task M(C c)
    {
        await foreach (var i in c)
        {
        }
    }
    public IAsyncEnumerator<int> GetAsyncEnumerator(System.Threading.CancellationToken token = default) => throw null;
}
namespace System.Collections.Generic
{
    public interface IAsyncEnumerable<out T>
    {
        IAsyncEnumerator<T> GetAsyncEnumerator(System.Threading.CancellationToken token = default);
    }
 
    public interface IAsyncEnumerator<out T> : System.IAsyncDisposable
    {
        System.Threading.Tasks.Task<bool> MoveNextAsync();
    }
}
namespace System
{
    public interface IAsyncDisposable
    {
        System.Threading.Tasks.ValueTask DisposeAsync();
    }
}
";
            var comp = CreateCompilationWithTasksExtensions(source);
            comp.VerifyEmitDiagnostics(
                // (8,33): error CS0117: 'IAsyncEnumerator<int>' does not contain a definition for 'Current'
                //         await foreach (var i in c)
                Diagnostic(ErrorCode.ERR_NoSuchMember, "c").WithArguments("System.Collections.Generic.IAsyncEnumerator<int>", "Current").WithLocation(8, 33),
                // (8,33): error CS8412: Asynchronous foreach requires that the return type 'IAsyncEnumerator<int>' of 'C.GetAsyncEnumerator(CancellationToken)' must have a suitable public 'MoveNextAsync' method and public 'Current' property
                //         await foreach (var i in c)
                Diagnostic(ErrorCode.ERR_BadGetAsyncEnumerator, "c").WithArguments("System.Collections.Generic.IAsyncEnumerator<int>", "C.GetAsyncEnumerator(System.Threading.CancellationToken)").WithLocation(8, 33)
                );
        }
 
        [Fact]
        public void TestMoveNextAsync_ReturnsTask()
        {
            string source = @"
class C
{
    async System.Threading.Tasks.Task M()
    {
        await foreach (var i in new C())
        {
        }
    }
    public Enumerator GetAsyncEnumerator(System.Threading.CancellationToken token = default)
    {
        throw null;
    }
    public sealed class Enumerator
    {
        public System.Threading.Tasks.Task MoveNextAsync()
        {
            throw null;
        }
        public int Current
        {
            get => throw null;
        }
    }
}";
            var comp = CreateCompilationWithMscorlib46(source);
            comp.VerifyDiagnostics(
                // (6,33): error CS8412: Asynchronous foreach requires that the return type 'C.Enumerator' of 'C.GetAsyncEnumerator(CancellationToken)' must have a suitable public 'MoveNextAsync' method and public 'Current' property
                //         await foreach (var i in new C())
                Diagnostic(ErrorCode.ERR_BadGetAsyncEnumerator, "new C()").WithArguments("C.Enumerator", "C.GetAsyncEnumerator(System.Threading.CancellationToken)").WithLocation(6, 33)
                );
        }
 
        [Fact]
        public void TestMoveNextAsync_ReturnsTaskOfInt()
        {
            string source = @"
class C
{
    async System.Threading.Tasks.Task M()
    {
        await foreach (var i in new C())
        {
        }
    }
    public Enumerator GetAsyncEnumerator(System.Threading.CancellationToken token = default)
    {
        throw null;
    }
    public sealed class Enumerator
    {
        public System.Threading.Tasks.Task<int> MoveNextAsync()
        {
            throw null;
        }
        public int Current
        {
            get => throw null;
        }
    }
}";
            var comp = CreateCompilationWithMscorlib46(source);
            comp.VerifyDiagnostics(
                // (6,33): error CS8412: Asynchronous foreach requires that the return type 'C.Enumerator' of 'C.GetAsyncEnumerator(CancellationToken)' must have a suitable public 'MoveNextAsync' method and public 'Current' property
                //         await foreach (var i in new C())
                Diagnostic(ErrorCode.ERR_BadGetAsyncEnumerator, "new C()").WithArguments("C.Enumerator", "C.GetAsyncEnumerator(System.Threading.CancellationToken)").WithLocation(6, 33)
                );
        }
 
        [Fact]
        public void TestMoveNextAsync_WithOptionalParameter()
        {
            string source = @"
public class C
{
    public static async System.Threading.Tasks.Task Main()
    {
        await foreach (var i in new C())
        {
        }
    }
    public Enumerator GetAsyncEnumerator(System.Threading.CancellationToken token = default)
    {
        return new Enumerator();
    }
    public sealed class Enumerator
    {
        public async System.Threading.Tasks.Task<bool> MoveNextAsync(int ok = 1)
        {
            System.Console.Write($""MoveNextAsync {ok}"");
            await System.Threading.Tasks.Task.Yield();
            return false;
        }
        public int Current
        {
            get => throw null;
        }
    }
}";
            var comp = CreateCompilationWithMscorlib46(source, options: TestOptions.DebugExe);
            comp.VerifyDiagnostics();
            CompileAndVerify(comp, expectedOutput: "MoveNextAsync 1");
 
            var runtimeAsyncComp = CreateRuntimeAsyncCompilation(source);
            var verifier = CompileAndVerify(runtimeAsyncComp, expectedOutput: CodeGenAsyncTests.ExpectedOutput("MoveNextAsync 1", isRuntimeAsync: true), verify: Verification.Fails with
            {
                ILVerifyMessage = """
                    [Main]: Return value missing on the stack. { Offset = 0x2b }
                    [MoveNextAsync]: Unexpected type on the stack. { Offset = 0x4f, Found = Int32, Expected = ref '[System.Runtime]System.Threading.Tasks.Task`1<bool>' }
                    """
            });
            verifier.VerifyIL("C.Main()", """
                {
                  // Code size       44 (0x2c)
                  .maxstack  2
                  .locals init (C.Enumerator V_0,
                                System.Threading.CancellationToken V_1)
                  IL_0000:  newobj     "C..ctor()"
                  IL_0005:  ldloca.s   V_1
                  IL_0007:  initobj    "System.Threading.CancellationToken"
                  IL_000d:  ldloc.1
                  IL_000e:  call       "C.Enumerator C.GetAsyncEnumerator(System.Threading.CancellationToken)"
                  IL_0013:  stloc.0
                  IL_0014:  br.s       IL_001d
                  IL_0016:  ldloc.0
                  IL_0017:  callvirt   "int C.Enumerator.Current.get"
                  IL_001c:  pop
                  IL_001d:  ldloc.0
                  IL_001e:  ldc.i4.1
                  IL_001f:  callvirt   "System.Threading.Tasks.Task<bool> C.Enumerator.MoveNextAsync(int)"
                  IL_0024:  call       "bool System.Runtime.CompilerServices.AsyncHelpers.Await<bool>(System.Threading.Tasks.Task<bool>)"
                  IL_0029:  brtrue.s   IL_0016
                  IL_002b:  ret
                }
                """);
        }
 
        [Fact]
        public void TestMoveNextAsync_WithParamsParameter()
        {
            string source = @"
public class C
{
    public static async System.Threading.Tasks.Task Main()
    {
        await foreach (var i in new C())
        {
        }
    }
    public Enumerator GetAsyncEnumerator(System.Threading.CancellationToken token = default)
    {
        return new Enumerator();
    }
    public sealed class Enumerator
    {
        public async System.Threading.Tasks.Task<bool> MoveNextAsync(params int[] ok)
        {
            System.Console.Write($""MoveNextAsync {ok.Length}"");
            await System.Threading.Tasks.Task.Yield();
            return false;
        }
        public int Current
        {
            get => throw null;
        }
    }
}";
            var comp = CreateCompilationWithMscorlib46(source, options: TestOptions.DebugExe);
            comp.VerifyDiagnostics();
            CompileAndVerify(comp, expectedOutput: "MoveNextAsync 0");
 
            var runtimeAsyncComp = CreateRuntimeAsyncCompilation(source);
            var verifier = CompileAndVerify(runtimeAsyncComp, expectedOutput: CodeGenAsyncTests.ExpectedOutput("MoveNextAsync 0", isRuntimeAsync: true), verify: Verification.Fails with
            {
                ILVerifyMessage = """
                    [Main]: Return value missing on the stack. { Offset = 0x2f }
                    [MoveNextAsync]: Unexpected type on the stack. { Offset = 0x51, Found = Int32, Expected = ref '[System.Runtime]System.Threading.Tasks.Task`1<bool>' }
                    """
            });
            verifier.VerifyIL("C.Main()", """
                {
                  // Code size       48 (0x30)
                  .maxstack  2
                  .locals init (C.Enumerator V_0,
                                System.Threading.CancellationToken V_1)
                  IL_0000:  newobj     "C..ctor()"
                  IL_0005:  ldloca.s   V_1
                  IL_0007:  initobj    "System.Threading.CancellationToken"
                  IL_000d:  ldloc.1
                  IL_000e:  call       "C.Enumerator C.GetAsyncEnumerator(System.Threading.CancellationToken)"
                  IL_0013:  stloc.0
                  IL_0014:  br.s       IL_001d
                  IL_0016:  ldloc.0
                  IL_0017:  callvirt   "int C.Enumerator.Current.get"
                  IL_001c:  pop
                  IL_001d:  ldloc.0
                  IL_001e:  call       "int[] System.Array.Empty<int>()"
                  IL_0023:  callvirt   "System.Threading.Tasks.Task<bool> C.Enumerator.MoveNextAsync(params int[])"
                  IL_0028:  call       "bool System.Runtime.CompilerServices.AsyncHelpers.Await<bool>(System.Threading.Tasks.Task<bool>)"
                  IL_002d:  brtrue.s   IL_0016
                  IL_002f:  ret
                }
                """);
        }
 
        [Fact]
        public void TestMoveNextAsync_Missing()
        {
            string source = @"
using System.Collections.Generic;
using System.Threading.Tasks;
class C : IAsyncEnumerable<int>
{
    public static async Task M(C c)
    {
        await foreach (var i in c)
        {
        }
    }
    public IAsyncEnumerator<int> GetAsyncEnumerator(System.Threading.CancellationToken token = default) => throw null;
}
namespace System.Collections.Generic
{
    public interface IAsyncEnumerable<out T>
    {
        IAsyncEnumerator<T> GetAsyncEnumerator(System.Threading.CancellationToken token = default);
    }
 
    public interface IAsyncEnumerator<out T> : System.IAsyncDisposable
    {
        T Current { get; }
    }
}
namespace System
{
    public interface IAsyncDisposable
    {
        System.Threading.Tasks.ValueTask DisposeAsync();
    }
}
";
            var comp = CreateCompilationWithTasksExtensions(source);
            comp.VerifyEmitDiagnostics(
                // (8,33): error CS0117: 'IAsyncEnumerator<int>' does not contain a definition for 'MoveNextAsync'
                //         await foreach (var i in c)
                Diagnostic(ErrorCode.ERR_NoSuchMember, "c").WithArguments("System.Collections.Generic.IAsyncEnumerator<int>", "MoveNextAsync").WithLocation(8, 33),
                // (8,33): error CS8412: Asynchronous foreach requires that the return type 'IAsyncEnumerator<int>' of 'C.GetAsyncEnumerator(CancellationToken)' must have a suitable public 'MoveNextAsync' method and public 'Current' property
                //         await foreach (var i in c)
                Diagnostic(ErrorCode.ERR_BadGetAsyncEnumerator, "c").WithArguments("System.Collections.Generic.IAsyncEnumerator<int>", "C.GetAsyncEnumerator(System.Threading.CancellationToken)").WithLocation(8, 33)
                );
        }
 
        [Fact]
        public void TestWithNonConvertibleElementType()
        {
            string source = @"
class C
{
    async System.Threading.Tasks.Task M()
    {
        await foreach (string i in new C())
        {
        }
    }
    public Enumerator GetAsyncEnumerator()
        => throw null;
    public sealed class Enumerator
    {
        public System.Threading.Tasks.Task<bool> MoveNextAsync()
            => throw null;
        public int Current
        {
            get => throw null;
        }
    }
}";
            var comp = CreateCompilationWithTasksExtensions(source + s_IAsyncEnumerable);
            comp.VerifyDiagnostics(
                // (6,15): error CS0030: Cannot convert type 'int' to 'string'
                //         await foreach (string i in new C())
                Diagnostic(ErrorCode.ERR_NoExplicitConv, "foreach").WithArguments("int", "string").WithLocation(6, 15)
                );
 
            var tree = comp.SyntaxTrees.Single();
            var model = comp.GetSemanticModel(tree, ignoreAccessibility: false);
            var foreachSyntax = tree.GetRoot().DescendantNodes().OfType<ForEachStatementSyntax>().Single();
            var info = model.GetForEachStatementInfo(foreachSyntax);
 
            Assert.True(info.IsAsynchronous);
            Assert.Equal("C.Enumerator C.GetAsyncEnumerator()", info.GetEnumeratorMethod.ToTestDisplayString());
            Assert.Equal("System.Threading.Tasks.Task<System.Boolean> C.Enumerator.MoveNextAsync()", info.MoveNextMethod.ToTestDisplayString());
            Assert.Equal("System.Int32 C.Enumerator.Current { get; }", info.CurrentProperty.ToTestDisplayString());
            Assert.Null(info.DisposeMethod);
            Assert.Equal("System.Int32", info.ElementType.ToTestDisplayString());
            Assert.Equal(ConversionKind.NoConversion, info.ElementConversion.Kind);
            Assert.Equal(ConversionKind.Identity, info.CurrentConversion.Kind);
        }
 
        [Fact]
        public void TestWithNonConvertibleElementType2()
        {
            string source = @"
using System.Threading.Tasks;
class C
{
    async Task M()
    {
        await foreach (Element i in new C())
        {
        }
    }
    public AsyncEnumerator GetAsyncEnumerator(System.Threading.CancellationToken token = default)
            => throw null;
    public sealed class AsyncEnumerator
    {
        public int Current
        {
            get => throw null;
        }
        public Task<bool> MoveNextAsync()
            => throw null;
        public ValueTask DisposeAsync()
            => throw null;
    }
}
class Element
{
}";
            var comp = CreateCompilationWithTasksExtensions(source);
            comp.VerifyDiagnostics(
                // (7,15): error CS0030: Cannot convert type 'int' to 'Element'
                //         await foreach (Element i in new C())
                Diagnostic(ErrorCode.ERR_NoExplicitConv, "foreach").WithArguments("int", "Element").WithLocation(7, 15)
                );
        }
 
        [Fact]
        public void TestWithExplicitlyConvertibleElementType()
        {
            string source = @"
using static System.Console;
using System.Threading.Tasks;
class C
{
    public static async System.Threading.Tasks.Task Main()
    {
        await foreach (Element i in new C())
        {
            Write($""Got({i}) "");
        }
    }
    public AsyncEnumerator GetAsyncEnumerator(System.Threading.CancellationToken token = default)
    {
        return new AsyncEnumerator();
    }
    public sealed class AsyncEnumerator : System.IAsyncDisposable
    {
        int i = 0;
        public int Current
        {
            get
            {
                Write($""Current({i}) "");
                return i;
            }
        }
        public async Task<bool> MoveNextAsync()
        {
            Write($""NextAsync({i}) "");
            i++;
            bool more = await Task.FromResult(i < 4);
            return more;
        }
        public async ValueTask DisposeAsync()
        {
            Write($""Dispose({i}) "");
            await Task.Yield();
        }
    }
}
class Element
{
    int i;
    public static explicit operator Element(int value) { Write($""Convert({value}) ""); return new Element(value); }
    private Element(int value) { i = value; }
    public override string ToString() => i.ToString();
}";
            var comp = CreateCompilationWithTasksExtensions(new[] { source, s_IAsyncEnumerable }, options: TestOptions.DebugExe);
            comp.VerifyDiagnostics();
 
            string expectedOutput = "NextAsync(0) Current(1) Convert(1) Got(1) NextAsync(1) Current(2) Convert(2) Got(2) NextAsync(2) Current(3) Convert(3) Got(3) NextAsync(3) Dispose(4)";
            CompileAndVerify(comp,
                expectedOutput: expectedOutput);
 
            var runtimeAsyncComp = CreateRuntimeAsyncCompilation(source);
            var verifier = CompileAndVerify(runtimeAsyncComp, expectedOutput: CodeGenAsyncTests.ExpectedOutput(expectedOutput, isRuntimeAsync: true), verify: Verification.Fails with
            {
                ILVerifyMessage = """
                    [Main]: Return value missing on the stack. { Offset = 0x91 }
                    [MoveNextAsync]: Unexpected type on the stack. { Offset = 0x5c, Found = Int32, Expected = ref '[System.Runtime]System.Threading.Tasks.Task`1<bool>' }
                    [DisposeAsync]: Return value missing on the stack. { Offset = 0x5f }
                    """
            });
            verifier.VerifyIL("C.Main()", """
                {
                  // Code size      146 (0x92)
                  .maxstack  2
                  .locals init (C.AsyncEnumerator V_0,
                                System.Threading.CancellationToken V_1,
                                object V_2,
                                Element V_3, //i
                                System.Runtime.CompilerServices.DefaultInterpolatedStringHandler V_4)
                  IL_0000:  newobj     "C..ctor()"
                  IL_0005:  ldloca.s   V_1
                  IL_0007:  initobj    "System.Threading.CancellationToken"
                  IL_000d:  ldloc.1
                  IL_000e:  call       "C.AsyncEnumerator C.GetAsyncEnumerator(System.Threading.CancellationToken)"
                  IL_0013:  stloc.0
                  IL_0014:  ldnull
                  IL_0015:  stloc.2
                  .try
                  {
                    IL_0016:  br.s       IL_0059
                    IL_0018:  ldloc.0
                    IL_0019:  callvirt   "int C.AsyncEnumerator.Current.get"
                    IL_001e:  call       "Element Element.op_Explicit(int)"
                    IL_0023:  stloc.3
                    IL_0024:  ldc.i4.6
                    IL_0025:  ldc.i4.1
                    IL_0026:  newobj     "System.Runtime.CompilerServices.DefaultInterpolatedStringHandler..ctor(int, int)"
                    IL_002b:  stloc.s    V_4
                    IL_002d:  ldloca.s   V_4
                    IL_002f:  ldstr      "Got("
                    IL_0034:  call       "void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendLiteral(string)"
                    IL_0039:  ldloca.s   V_4
                    IL_003b:  ldloc.3
                    IL_003c:  call       "void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted<Element>(Element)"
                    IL_0041:  ldloca.s   V_4
                    IL_0043:  ldstr      ") "
                    IL_0048:  call       "void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendLiteral(string)"
                    IL_004d:  ldloca.s   V_4
                    IL_004f:  call       "string System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.ToStringAndClear()"
                    IL_0054:  call       "void System.Console.Write(string)"
                    IL_0059:  ldloc.0
                    IL_005a:  callvirt   "System.Threading.Tasks.Task<bool> C.AsyncEnumerator.MoveNextAsync()"
                    IL_005f:  call       "bool System.Runtime.CompilerServices.AsyncHelpers.Await<bool>(System.Threading.Tasks.Task<bool>)"
                    IL_0064:  brtrue.s   IL_0018
                    IL_0066:  leave.s    IL_006b
                  }
                  catch object
                  {
                    IL_0068:  stloc.2
                    IL_0069:  leave.s    IL_006b
                  }
                  IL_006b:  ldloc.0
                  IL_006c:  brfalse.s  IL_0079
                  IL_006e:  ldloc.0
                  IL_006f:  callvirt   "System.Threading.Tasks.ValueTask C.AsyncEnumerator.DisposeAsync()"
                  IL_0074:  call       "void System.Runtime.CompilerServices.AsyncHelpers.Await(System.Threading.Tasks.ValueTask)"
                  IL_0079:  ldloc.2
                  IL_007a:  brfalse.s  IL_0091
                  IL_007c:  ldloc.2
                  IL_007d:  isinst     "System.Exception"
                  IL_0082:  dup
                  IL_0083:  brtrue.s   IL_0087
                  IL_0085:  ldloc.2
                  IL_0086:  throw
                  IL_0087:  call       "System.Runtime.ExceptionServices.ExceptionDispatchInfo System.Runtime.ExceptionServices.ExceptionDispatchInfo.Capture(System.Exception)"
                  IL_008c:  callvirt   "void System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()"
                  IL_0091:  ret
                }
                """);
        }
 
        [Fact]
        public void TestWithCaptureOfIterationVariable()
        {
            string source = @"
using static System.Console;
using System.Threading.Tasks;
public class C
{
    public static async System.Threading.Tasks.Task Main()
    {
        System.Action f = null;
        await foreach (var i in new C())
        {
            Write($""Got({i}) "");
            if (f == null) f = () => Write($""Captured({i})"");
        }
        f();
    }
    public AsyncEnumerator GetAsyncEnumerator(System.Threading.CancellationToken token = default)
    {
        return new AsyncEnumerator();
    }
    public sealed class AsyncEnumerator : System.IAsyncDisposable
    {
        int i = 0;
        public int Current => i;
        public async Task<bool> MoveNextAsync()
        {
            i++;
            return await Task.FromResult(i < 3);
        }
        public async ValueTask DisposeAsync()
        {
            await Task.Yield();
        }
    }
}";
            var comp = CreateCompilationWithTasksExtensions(new[] { source, s_IAsyncEnumerable }, options: TestOptions.DebugExe);
            comp.VerifyDiagnostics();
            CompileAndVerify(comp, expectedOutput: "Got(1) Got(2) Captured(1)");
 
            var runtimeAsyncComp = CreateRuntimeAsyncCompilation(source);
            var verifier = CompileAndVerify(runtimeAsyncComp, expectedOutput: CodeGenAsyncTests.ExpectedOutput("Got(1) Got(2) Captured(1)", isRuntimeAsync: true), verify: Verification.Fails with
            {
                ILVerifyMessage = """
                    [Main]: Return value missing on the stack. { Offset = 0xb8 }
                    [MoveNextAsync]: Unexpected type on the stack. { Offset = 0x21, Found = Int32, Expected = ref '[System.Runtime]System.Threading.Tasks.Task`1<bool>' }
                    [DisposeAsync]: Return value missing on the stack. { Offset = 0x24 }
                    """
            });
            verifier.VerifyIL("C.Main()", """
                {
                  // Code size      185 (0xb9)
                  .maxstack  2
                  .locals init (System.Action V_0, //f
                                C.AsyncEnumerator V_1,
                                System.Threading.CancellationToken V_2,
                                object V_3,
                                C.<>c__DisplayClass0_0 V_4, //CS$<>8__locals0
                                System.Runtime.CompilerServices.DefaultInterpolatedStringHandler V_5)
                  IL_0000:  ldnull
                  IL_0001:  stloc.0
                  IL_0002:  newobj     "C..ctor()"
                  IL_0007:  ldloca.s   V_2
                  IL_0009:  initobj    "System.Threading.CancellationToken"
                  IL_000f:  ldloc.2
                  IL_0010:  call       "C.AsyncEnumerator C.GetAsyncEnumerator(System.Threading.CancellationToken)"
                  IL_0015:  stloc.1
                  IL_0016:  ldnull
                  IL_0017:  stloc.3
                  .try
                  {
                    IL_0018:  br.s       IL_007a
                    IL_001a:  newobj     "C.<>c__DisplayClass0_0..ctor()"
                    IL_001f:  stloc.s    V_4
                    IL_0021:  ldloc.s    V_4
                    IL_0023:  ldloc.1
                    IL_0024:  callvirt   "int C.AsyncEnumerator.Current.get"
                    IL_0029:  stfld      "int C.<>c__DisplayClass0_0.i"
                    IL_002e:  ldc.i4.6
                    IL_002f:  ldc.i4.1
                    IL_0030:  newobj     "System.Runtime.CompilerServices.DefaultInterpolatedStringHandler..ctor(int, int)"
                    IL_0035:  stloc.s    V_5
                    IL_0037:  ldloca.s   V_5
                    IL_0039:  ldstr      "Got("
                    IL_003e:  call       "void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendLiteral(string)"
                    IL_0043:  ldloca.s   V_5
                    IL_0045:  ldloc.s    V_4
                    IL_0047:  ldfld      "int C.<>c__DisplayClass0_0.i"
                    IL_004c:  call       "void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted<int>(int)"
                    IL_0051:  ldloca.s   V_5
                    IL_0053:  ldstr      ") "
                    IL_0058:  call       "void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendLiteral(string)"
                    IL_005d:  ldloca.s   V_5
                    IL_005f:  call       "string System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.ToStringAndClear()"
                    IL_0064:  call       "void System.Console.Write(string)"
                    IL_0069:  ldloc.0
                    IL_006a:  brtrue.s   IL_007a
                    IL_006c:  ldloc.s    V_4
                    IL_006e:  ldftn      "void C.<>c__DisplayClass0_0.<Main>b__0()"
                    IL_0074:  newobj     "System.Action..ctor(object, System.IntPtr)"
                    IL_0079:  stloc.0
                    IL_007a:  ldloc.1
                    IL_007b:  callvirt   "System.Threading.Tasks.Task<bool> C.AsyncEnumerator.MoveNextAsync()"
                    IL_0080:  call       "bool System.Runtime.CompilerServices.AsyncHelpers.Await<bool>(System.Threading.Tasks.Task<bool>)"
                    IL_0085:  brtrue.s   IL_001a
                    IL_0087:  leave.s    IL_008c
                  }
                  catch object
                  {
                    IL_0089:  stloc.3
                    IL_008a:  leave.s    IL_008c
                  }
                  IL_008c:  ldloc.1
                  IL_008d:  brfalse.s  IL_009a
                  IL_008f:  ldloc.1
                  IL_0090:  callvirt   "System.Threading.Tasks.ValueTask C.AsyncEnumerator.DisposeAsync()"
                  IL_0095:  call       "void System.Runtime.CompilerServices.AsyncHelpers.Await(System.Threading.Tasks.ValueTask)"
                  IL_009a:  ldloc.3
                  IL_009b:  brfalse.s  IL_00b2
                  IL_009d:  ldloc.3
                  IL_009e:  isinst     "System.Exception"
                  IL_00a3:  dup
                  IL_00a4:  brtrue.s   IL_00a8
                  IL_00a6:  ldloc.3
                  IL_00a7:  throw
                  IL_00a8:  call       "System.Runtime.ExceptionServices.ExceptionDispatchInfo System.Runtime.ExceptionServices.ExceptionDispatchInfo.Capture(System.Exception)"
                  IL_00ad:  callvirt   "void System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()"
                  IL_00b2:  ldloc.0
                  IL_00b3:  callvirt   "void System.Action.Invoke()"
                  IL_00b8:  ret
                }
                """);
        }
 
        [Fact]
        public void TestWithGenericIterationVariable()
        {
            string source = @"
using static System.Console;
using System.Threading.Tasks;
class IntContainer
{
    public int Value { get; set; }
}
public class Program
{
    public static async System.Threading.Tasks.Task Main()
    {
        await foreach (var i in new C<IntContainer>())
        {
            Write($""Got({i.Value}) "");
        }
    }
}
class C<T> where T : IntContainer, new()
{
    public AsyncEnumerator GetAsyncEnumerator(System.Threading.CancellationToken token = default)
    {
        return new AsyncEnumerator();
    }
    public sealed class AsyncEnumerator : System.IAsyncDisposable
    {
        int i = 0;
        public T Current
        {
            get
            {
                Write($""Current({i}) "");
                var result = new T();
                ((IntContainer)result).Value = i;
                return result;
            }
        }
        public async Task<bool> MoveNextAsync()
        {
            i++;
            Write($""NextAsync({i}) "");
            return await Task.FromResult(i < 4);
        }
        public async ValueTask DisposeAsync()
        {
            Write($""Dispose({i}) "");
            await Task.Yield();
        }
    }
}";
            var comp = CreateCompilationWithTasksExtensions(new[] { source, s_IAsyncEnumerable }, options: TestOptions.DebugExe);
            comp.VerifyDiagnostics();
            var expectedOutput = "NextAsync(1) Current(1) Got(1) NextAsync(2) Current(2) Got(2) NextAsync(3) Current(3) Got(3) NextAsync(4) Dispose(4)";
            CompileAndVerify(comp, expectedOutput: expectedOutput);
 
            var runtimeAsyncComp = CreateRuntimeAsyncCompilation(source);
            var verifier = CompileAndVerify(runtimeAsyncComp, expectedOutput: CodeGenAsyncTests.ExpectedOutput(expectedOutput, isRuntimeAsync: true), verify: Verification.Fails with
            {
                ILVerifyMessage = """
                    [Main]: Return value missing on the stack. { Offset = 0x91 }
                    [MoveNextAsync]: Unexpected type on the stack. { Offset = 0x5c, Found = Int32, Expected = ref '[System.Runtime]System.Threading.Tasks.Task`1<bool>' }
                    [DisposeAsync]: Return value missing on the stack. { Offset = 0x5f }
                    """
            });
            verifier.VerifyIL("Program.Main()", """
                {
                  // Code size      146 (0x92)
                  .maxstack  2
                  .locals init (C<IntContainer>.AsyncEnumerator V_0,
                                System.Threading.CancellationToken V_1,
                                object V_2,
                                IntContainer V_3, //i
                                System.Runtime.CompilerServices.DefaultInterpolatedStringHandler V_4)
                  IL_0000:  newobj     "C<IntContainer>..ctor()"
                  IL_0005:  ldloca.s   V_1
                  IL_0007:  initobj    "System.Threading.CancellationToken"
                  IL_000d:  ldloc.1
                  IL_000e:  call       "C<IntContainer>.AsyncEnumerator C<IntContainer>.GetAsyncEnumerator(System.Threading.CancellationToken)"
                  IL_0013:  stloc.0
                  IL_0014:  ldnull
                  IL_0015:  stloc.2
                  .try
                  {
                    IL_0016:  br.s       IL_0059
                    IL_0018:  ldloc.0
                    IL_0019:  callvirt   "IntContainer C<IntContainer>.AsyncEnumerator.Current.get"
                    IL_001e:  stloc.3
                    IL_001f:  ldc.i4.6
                    IL_0020:  ldc.i4.1
                    IL_0021:  newobj     "System.Runtime.CompilerServices.DefaultInterpolatedStringHandler..ctor(int, int)"
                    IL_0026:  stloc.s    V_4
                    IL_0028:  ldloca.s   V_4
                    IL_002a:  ldstr      "Got("
                    IL_002f:  call       "void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendLiteral(string)"
                    IL_0034:  ldloca.s   V_4
                    IL_0036:  ldloc.3
                    IL_0037:  callvirt   "int IntContainer.Value.get"
                    IL_003c:  call       "void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted<int>(int)"
                    IL_0041:  ldloca.s   V_4
                    IL_0043:  ldstr      ") "
                    IL_0048:  call       "void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendLiteral(string)"
                    IL_004d:  ldloca.s   V_4
                    IL_004f:  call       "string System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.ToStringAndClear()"
                    IL_0054:  call       "void System.Console.Write(string)"
                    IL_0059:  ldloc.0
                    IL_005a:  callvirt   "System.Threading.Tasks.Task<bool> C<IntContainer>.AsyncEnumerator.MoveNextAsync()"
                    IL_005f:  call       "bool System.Runtime.CompilerServices.AsyncHelpers.Await<bool>(System.Threading.Tasks.Task<bool>)"
                    IL_0064:  brtrue.s   IL_0018
                    IL_0066:  leave.s    IL_006b
                  }
                  catch object
                  {
                    IL_0068:  stloc.2
                    IL_0069:  leave.s    IL_006b
                  }
                  IL_006b:  ldloc.0
                  IL_006c:  brfalse.s  IL_0079
                  IL_006e:  ldloc.0
                  IL_006f:  callvirt   "System.Threading.Tasks.ValueTask C<IntContainer>.AsyncEnumerator.DisposeAsync()"
                  IL_0074:  call       "void System.Runtime.CompilerServices.AsyncHelpers.Await(System.Threading.Tasks.ValueTask)"
                  IL_0079:  ldloc.2
                  IL_007a:  brfalse.s  IL_0091
                  IL_007c:  ldloc.2
                  IL_007d:  isinst     "System.Exception"
                  IL_0082:  dup
                  IL_0083:  brtrue.s   IL_0087
                  IL_0085:  ldloc.2
                  IL_0086:  throw
                  IL_0087:  call       "System.Runtime.ExceptionServices.ExceptionDispatchInfo System.Runtime.ExceptionServices.ExceptionDispatchInfo.Capture(System.Exception)"
                  IL_008c:  callvirt   "void System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()"
                  IL_0091:  ret
                }
                """);
        }
 
        [Fact]
        public void TestWithThrowingGetAsyncEnumerator()
        {
            string source = @"
using static System.Console;
using System.Threading.Tasks;
public class C
{
    public static async Task Main()
    {
        try
        {
            await foreach (var i in new C())
            {
                throw null;
            }
            throw null;
        }
        catch (System.ArgumentException e)
        {
            Write(e.Message);
        }
    }
    public AsyncEnumerator GetAsyncEnumerator(System.Threading.CancellationToken token = default)
        => throw new System.ArgumentException(""exception"");
    public sealed class AsyncEnumerator : System.IAsyncDisposable
    {
        public int Current
            => throw null;
        public Task<bool> MoveNextAsync()
            => throw null;
        public ValueTask DisposeAsync()
            => throw null;
    }
}";
            var comp = CreateCompilationWithTasksExtensions(new[] { source, s_IAsyncEnumerable }, options: TestOptions.DebugExe);
            comp.VerifyDiagnostics();
            CompileAndVerify(comp, expectedOutput: "exception");
 
            var runtimeAsyncComp = CreateRuntimeAsyncCompilation(source);
            var verifier = CompileAndVerify(runtimeAsyncComp, expectedOutput: CodeGenAsyncTests.ExpectedOutput("exception", isRuntimeAsync: true), verify: Verification.Fails with
            {
                ILVerifyMessage = """
                    [Main]: Return value missing on the stack. { Offset = 0x67 }
                    """
            });
            verifier.VerifyIL("C.Main()", """
                {
                  // Code size      104 (0x68)
                  .maxstack  2
                  .locals init (C.AsyncEnumerator V_0,
                                System.Threading.CancellationToken V_1,
                                object V_2)
                  .try
                  {
                    IL_0000:  newobj     "C..ctor()"
                    IL_0005:  ldloca.s   V_1
                    IL_0007:  initobj    "System.Threading.CancellationToken"
                    IL_000d:  ldloc.1
                    IL_000e:  call       "C.AsyncEnumerator C.GetAsyncEnumerator(System.Threading.CancellationToken)"
                    IL_0013:  stloc.0
                    IL_0014:  ldnull
                    IL_0015:  stloc.2
                    .try
                    {
                      IL_0016:  br.s       IL_0021
                      IL_0018:  ldloc.0
                      IL_0019:  callvirt   "int C.AsyncEnumerator.Current.get"
                      IL_001e:  pop
                      IL_001f:  ldnull
                      IL_0020:  throw
                      IL_0021:  ldloc.0
                      IL_0022:  callvirt   "System.Threading.Tasks.Task<bool> C.AsyncEnumerator.MoveNextAsync()"
                      IL_0027:  call       "bool System.Runtime.CompilerServices.AsyncHelpers.Await<bool>(System.Threading.Tasks.Task<bool>)"
                      IL_002c:  brtrue.s   IL_0018
                      IL_002e:  leave.s    IL_0033
                    }
                    catch object
                    {
                      IL_0030:  stloc.2
                      IL_0031:  leave.s    IL_0033
                    }
                    IL_0033:  ldloc.0
                    IL_0034:  brfalse.s  IL_0041
                    IL_0036:  ldloc.0
                    IL_0037:  callvirt   "System.Threading.Tasks.ValueTask C.AsyncEnumerator.DisposeAsync()"
                    IL_003c:  call       "void System.Runtime.CompilerServices.AsyncHelpers.Await(System.Threading.Tasks.ValueTask)"
                    IL_0041:  ldloc.2
                    IL_0042:  brfalse.s  IL_0059
                    IL_0044:  ldloc.2
                    IL_0045:  isinst     "System.Exception"
                    IL_004a:  dup
                    IL_004b:  brtrue.s   IL_004f
                    IL_004d:  ldloc.2
                    IL_004e:  throw
                    IL_004f:  call       "System.Runtime.ExceptionServices.ExceptionDispatchInfo System.Runtime.ExceptionServices.ExceptionDispatchInfo.Capture(System.Exception)"
                    IL_0054:  callvirt   "void System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()"
                    IL_0059:  ldnull
                    IL_005a:  throw
                  }
                  catch System.ArgumentException
                  {
                    IL_005b:  callvirt   "string System.Exception.Message.get"
                    IL_0060:  call       "void System.Console.Write(string)"
                    IL_0065:  leave.s    IL_0067
                  }
                  IL_0067:  ret
                }
                """);
        }
 
        [Fact]
        public void TestWithThrowingMoveNextAsync()
        {
            string source = @"
using static System.Console;
using System.Threading.Tasks;
public class C
{
    public static async Task Main()
    {
        try
        {
            await foreach (var i in new C())
            {
                throw null;
            }
            throw null;
        }
        catch (System.ArgumentException e)
        {
            Write(e.Message);
        }
    }
    public AsyncEnumerator GetAsyncEnumerator(System.Threading.CancellationToken token = default)
        => new AsyncEnumerator();
    public sealed class AsyncEnumerator : System.IAsyncDisposable
    {
        public int Current
            => throw null;
        public Task<bool> MoveNextAsync()
            => throw new System.ArgumentException(""exception"");
        public async ValueTask DisposeAsync()
        {
            Write(""dispose "");
            await Task.Yield();
        }
    }
}";
            var comp = CreateCompilationWithTasksExtensions(new[] { source, s_IAsyncEnumerable }, options: TestOptions.DebugExe);
            comp.VerifyDiagnostics();
            CompileAndVerify(comp, expectedOutput: "dispose exception");
 
            var runtimeAsyncComp = CreateRuntimeAsyncCompilation(source);
            var verifier = CompileAndVerify(runtimeAsyncComp, expectedOutput: CodeGenAsyncTests.ExpectedOutput("dispose exception", isRuntimeAsync: true), verify: Verification.Fails with
            {
                ILVerifyMessage = """
                    [Main]: Return value missing on the stack. { Offset = 0x67 }
                    [DisposeAsync]: Return value missing on the stack. { Offset = 0x2e }
                    """
            });
            verifier.VerifyIL("C.Main()", """
                {
                  // Code size      104 (0x68)
                  .maxstack  2
                  .locals init (C.AsyncEnumerator V_0,
                                System.Threading.CancellationToken V_1,
                                object V_2)
                  .try
                  {
                    IL_0000:  newobj     "C..ctor()"
                    IL_0005:  ldloca.s   V_1
                    IL_0007:  initobj    "System.Threading.CancellationToken"
                    IL_000d:  ldloc.1
                    IL_000e:  call       "C.AsyncEnumerator C.GetAsyncEnumerator(System.Threading.CancellationToken)"
                    IL_0013:  stloc.0
                    IL_0014:  ldnull
                    IL_0015:  stloc.2
                    .try
                    {
                      IL_0016:  br.s       IL_0021
                      IL_0018:  ldloc.0
                      IL_0019:  callvirt   "int C.AsyncEnumerator.Current.get"
                      IL_001e:  pop
                      IL_001f:  ldnull
                      IL_0020:  throw
                      IL_0021:  ldloc.0
                      IL_0022:  callvirt   "System.Threading.Tasks.Task<bool> C.AsyncEnumerator.MoveNextAsync()"
                      IL_0027:  call       "bool System.Runtime.CompilerServices.AsyncHelpers.Await<bool>(System.Threading.Tasks.Task<bool>)"
                      IL_002c:  brtrue.s   IL_0018
                      IL_002e:  leave.s    IL_0033
                    }
                    catch object
                    {
                      IL_0030:  stloc.2
                      IL_0031:  leave.s    IL_0033
                    }
                    IL_0033:  ldloc.0
                    IL_0034:  brfalse.s  IL_0041
                    IL_0036:  ldloc.0
                    IL_0037:  callvirt   "System.Threading.Tasks.ValueTask C.AsyncEnumerator.DisposeAsync()"
                    IL_003c:  call       "void System.Runtime.CompilerServices.AsyncHelpers.Await(System.Threading.Tasks.ValueTask)"
                    IL_0041:  ldloc.2
                    IL_0042:  brfalse.s  IL_0059
                    IL_0044:  ldloc.2
                    IL_0045:  isinst     "System.Exception"
                    IL_004a:  dup
                    IL_004b:  brtrue.s   IL_004f
                    IL_004d:  ldloc.2
                    IL_004e:  throw
                    IL_004f:  call       "System.Runtime.ExceptionServices.ExceptionDispatchInfo System.Runtime.ExceptionServices.ExceptionDispatchInfo.Capture(System.Exception)"
                    IL_0054:  callvirt   "void System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()"
                    IL_0059:  ldnull
                    IL_005a:  throw
                  }
                  catch System.ArgumentException
                  {
                    IL_005b:  callvirt   "string System.Exception.Message.get"
                    IL_0060:  call       "void System.Console.Write(string)"
                    IL_0065:  leave.s    IL_0067
                  }
                  IL_0067:  ret
                }
                """);
        }
 
        [Fact]
        public void TestWithThrowingCurrent()
        {
            string source = @"
using static System.Console;
using System.Threading.Tasks;
public class C
{
    public static async Task Main()
    {
        try
        {
            await foreach (var i in new C())
            {
                throw null;
            }
            throw null;
        }
        catch (System.ArgumentException e)
        {
            Write(e.Message);
        }
    }
    public AsyncEnumerator GetAsyncEnumerator()
        => new AsyncEnumerator();
    public sealed class AsyncEnumerator : System.IAsyncDisposable
    {
        public int Current
            => throw new System.ArgumentException(""exception"");
        public async Task<bool> MoveNextAsync()
        {
            Write(""wait "");
            await Task.Yield();
            return true;
        }
        public async ValueTask DisposeAsync()
        {
            Write(""dispose "");
            await Task.Yield();
        }
    }
}";
            var comp = CreateCompilationWithTasksExtensions(new[] { source, s_IAsyncEnumerable }, options: TestOptions.DebugExe);
            comp.VerifyDiagnostics();
            CompileAndVerify(comp, expectedOutput: "wait dispose exception");
 
            var runtimeAsyncComp = CreateRuntimeAsyncCompilation(source);
            var verifier = CompileAndVerify(runtimeAsyncComp, expectedOutput: CodeGenAsyncTests.ExpectedOutput("wait dispose exception", isRuntimeAsync: true), verify: Verification.Fails with
            {
                ILVerifyMessage = """
                    [Main]: Return value missing on the stack. { Offset = 0x5e }
                    [MoveNextAsync]: Unexpected type on the stack. { Offset = 0x2f, Found = Int32, Expected = ref '[System.Runtime]System.Threading.Tasks.Task`1<bool>' }
                    [DisposeAsync]: Return value missing on the stack. { Offset = 0x2e }
                    """
            });
            verifier.VerifyIL("C.Main()", """
                {
                  // Code size       95 (0x5f)
                  .maxstack  2
                  .locals init (C.AsyncEnumerator V_0,
                                object V_1)
                  .try
                  {
                    IL_0000:  newobj     "C..ctor()"
                    IL_0005:  call       "C.AsyncEnumerator C.GetAsyncEnumerator()"
                    IL_000a:  stloc.0
                    IL_000b:  ldnull
                    IL_000c:  stloc.1
                    .try
                    {
                      IL_000d:  br.s       IL_0018
                      IL_000f:  ldloc.0
                      IL_0010:  callvirt   "int C.AsyncEnumerator.Current.get"
                      IL_0015:  pop
                      IL_0016:  ldnull
                      IL_0017:  throw
                      IL_0018:  ldloc.0
                      IL_0019:  callvirt   "System.Threading.Tasks.Task<bool> C.AsyncEnumerator.MoveNextAsync()"
                      IL_001e:  call       "bool System.Runtime.CompilerServices.AsyncHelpers.Await<bool>(System.Threading.Tasks.Task<bool>)"
                      IL_0023:  brtrue.s   IL_000f
                      IL_0025:  leave.s    IL_002a
                    }
                    catch object
                    {
                      IL_0027:  stloc.1
                      IL_0028:  leave.s    IL_002a
                    }
                    IL_002a:  ldloc.0
                    IL_002b:  brfalse.s  IL_0038
                    IL_002d:  ldloc.0
                    IL_002e:  callvirt   "System.Threading.Tasks.ValueTask C.AsyncEnumerator.DisposeAsync()"
                    IL_0033:  call       "void System.Runtime.CompilerServices.AsyncHelpers.Await(System.Threading.Tasks.ValueTask)"
                    IL_0038:  ldloc.1
                    IL_0039:  brfalse.s  IL_0050
                    IL_003b:  ldloc.1
                    IL_003c:  isinst     "System.Exception"
                    IL_0041:  dup
                    IL_0042:  brtrue.s   IL_0046
                    IL_0044:  ldloc.1
                    IL_0045:  throw
                    IL_0046:  call       "System.Runtime.ExceptionServices.ExceptionDispatchInfo System.Runtime.ExceptionServices.ExceptionDispatchInfo.Capture(System.Exception)"
                    IL_004b:  callvirt   "void System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()"
                    IL_0050:  ldnull
                    IL_0051:  throw
                  }
                  catch System.ArgumentException
                  {
                    IL_0052:  callvirt   "string System.Exception.Message.get"
                    IL_0057:  call       "void System.Console.Write(string)"
                    IL_005c:  leave.s    IL_005e
                  }
                  IL_005e:  ret
                }
                """);
        }
 
        [Fact]
        public void TestWithThrowingDisposeAsync()
        {
            string source = @"
using static System.Console;
using System.Threading.Tasks;
public class C
{
    public static async Task Main()
    {
        try
        {
            await foreach (var i in new C())
            {
                throw null;
            }
            throw null;
        }
        catch (System.ArgumentException e)
        {
            Write(e.Message);
        }
    }
    public AsyncEnumerator GetAsyncEnumerator()
        => new AsyncEnumerator();
    public sealed class AsyncEnumerator : System.IAsyncDisposable
    {
        public int Current => throw null;
        public async Task<bool> MoveNextAsync()
        {
            Write(""wait "");
            await Task.Yield();
            return false;
        }
        public ValueTask DisposeAsync()
            => throw new System.ArgumentException(""exception"");
    }
}";
            var comp = CreateCompilationWithTasksExtensions(new[] { source, s_IAsyncEnumerable }, options: TestOptions.DebugExe);
            comp.VerifyDiagnostics();
            CompileAndVerify(comp, expectedOutput: "wait exception");
 
            var runtimeAsyncComp = CreateRuntimeAsyncCompilation(source);
            var verifier = CompileAndVerify(runtimeAsyncComp, expectedOutput: CodeGenAsyncTests.ExpectedOutput("wait exception", isRuntimeAsync: true), verify: Verification.Fails with
            {
                ILVerifyMessage = """
                    [Main]: Return value missing on the stack. { Offset = 0x5e }
                    [MoveNextAsync]: Unexpected type on the stack. { Offset = 0x2f, Found = Int32, Expected = ref '[System.Runtime]System.Threading.Tasks.Task`1<bool>' }
                    """
            });
            verifier.VerifyIL("C.Main()", """
                {
                  // Code size       95 (0x5f)
                  .maxstack  2
                  .locals init (C.AsyncEnumerator V_0,
                                object V_1)
                  .try
                  {
                    IL_0000:  newobj     "C..ctor()"
                    IL_0005:  call       "C.AsyncEnumerator C.GetAsyncEnumerator()"
                    IL_000a:  stloc.0
                    IL_000b:  ldnull
                    IL_000c:  stloc.1
                    .try
                    {
                      IL_000d:  br.s       IL_0018
                      IL_000f:  ldloc.0
                      IL_0010:  callvirt   "int C.AsyncEnumerator.Current.get"
                      IL_0015:  pop
                      IL_0016:  ldnull
                      IL_0017:  throw
                      IL_0018:  ldloc.0
                      IL_0019:  callvirt   "System.Threading.Tasks.Task<bool> C.AsyncEnumerator.MoveNextAsync()"
                      IL_001e:  call       "bool System.Runtime.CompilerServices.AsyncHelpers.Await<bool>(System.Threading.Tasks.Task<bool>)"
                      IL_0023:  brtrue.s   IL_000f
                      IL_0025:  leave.s    IL_002a
                    }
                    catch object
                    {
                      IL_0027:  stloc.1
                      IL_0028:  leave.s    IL_002a
                    }
                    IL_002a:  ldloc.0
                    IL_002b:  brfalse.s  IL_0038
                    IL_002d:  ldloc.0
                    IL_002e:  callvirt   "System.Threading.Tasks.ValueTask C.AsyncEnumerator.DisposeAsync()"
                    IL_0033:  call       "void System.Runtime.CompilerServices.AsyncHelpers.Await(System.Threading.Tasks.ValueTask)"
                    IL_0038:  ldloc.1
                    IL_0039:  brfalse.s  IL_0050
                    IL_003b:  ldloc.1
                    IL_003c:  isinst     "System.Exception"
                    IL_0041:  dup
                    IL_0042:  brtrue.s   IL_0046
                    IL_0044:  ldloc.1
                    IL_0045:  throw
                    IL_0046:  call       "System.Runtime.ExceptionServices.ExceptionDispatchInfo System.Runtime.ExceptionServices.ExceptionDispatchInfo.Capture(System.Exception)"
                    IL_004b:  callvirt   "void System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()"
                    IL_0050:  ldnull
                    IL_0051:  throw
                  }
                  catch System.ArgumentException
                  {
                    IL_0052:  callvirt   "string System.Exception.Message.get"
                    IL_0057:  call       "void System.Console.Write(string)"
                    IL_005c:  leave.s    IL_005e
                  }
                  IL_005e:  ret
                }
                """);
        }
 
        [Fact]
        public void TestWithDynamicCollection()
        {
            string source = @"
class C
{
    public static async System.Threading.Tasks.Task Main()
    {
        await foreach (var i in (dynamic)new C())
        {
        }
    }
}";
            var comp = CreateCompilationWithTasksExtensions(new[] { source, s_IAsyncEnumerable });
            // (6,33): error CS8416: Cannot use a collection of dynamic type in an asynchronous foreach
            //         await foreach (var i in (dynamic)new C())
            DiagnosticDescription expected = Diagnostic(ErrorCode.ERR_BadDynamicAwaitForEach, "(dynamic)new C()").WithLocation(6, 33);
            comp.VerifyDiagnostics(expected);
 
            comp = CreateRuntimeAsyncCompilation(source);
            comp.VerifyEmitDiagnostics(expected);
        }
 
        [Fact]
        public void TestWithIncompleteInterface()
        {
            string source = @"
namespace System.Collections.Generic
{
    public interface IAsyncEnumerable<out T>
    {
    }
}
class C
{
    async System.Threading.Tasks.Task M(System.Collections.Generic.IAsyncEnumerable<int> collection)
    {
        await foreach (var i in collection)
        {
        }
    }
}";
            var comp = CreateCompilationWithMscorlib46(source);
            comp.VerifyDiagnostics(
                // (12,33): error CS8411: Async foreach statement cannot operate on variables of type 'IAsyncEnumerable<int>' because 'IAsyncEnumerable<int>' does not contain a suitable public instance or extension definition for 'GetAsyncEnumerator'
                //         await foreach (var i in collection)
                Diagnostic(ErrorCode.ERR_AwaitForEachMissingMember, "collection").WithArguments("System.Collections.Generic.IAsyncEnumerable<int>", "GetAsyncEnumerator").WithLocation(12, 33)
                );
        }
 
        [Fact]
        public void TestWithIncompleteInterface2()
        {
            string source = @"
namespace System.Collections.Generic
{
    public interface IAsyncEnumerable<out T>
    {
        IAsyncEnumerator<T> GetAsyncEnumerator(System.Threading.CancellationToken token = default);
    }
 
    public interface IAsyncEnumerator<out T>
    {
        System.Threading.Tasks.Task<bool> MoveNextAsync();
    }
}
class C
{
    async System.Threading.Tasks.Task M(System.Collections.Generic.IAsyncEnumerable<int> collection)
    {
        await foreach (var i in collection)
        {
        }
    }
}";
            var comp = CreateCompilationWithMscorlib46(source);
            comp.VerifyDiagnostics(
                // (18,33): error CS0117: 'IAsyncEnumerator<int>' does not contain a definition for 'Current'
                //         await foreach (var i in collection)
                Diagnostic(ErrorCode.ERR_NoSuchMember, "collection").WithArguments("System.Collections.Generic.IAsyncEnumerator<int>", "Current").WithLocation(18, 33),
                // (18,33): error CS8412: Async foreach requires that the return type 'IAsyncEnumerator<int>' of 'IAsyncEnumerable<int>.GetAsyncEnumerator(System.Threading.CancellationToken)' must have a suitable public MoveNextAsync method and public Current property
                //         await foreach (var i in collection)
                Diagnostic(ErrorCode.ERR_BadGetAsyncEnumerator, "collection").WithArguments("System.Collections.Generic.IAsyncEnumerator<int>", "System.Collections.Generic.IAsyncEnumerable<int>.GetAsyncEnumerator(System.Threading.CancellationToken)").WithLocation(18, 33)
                );
        }
 
        [Fact]
        public void TestWithIncompleteInterface3()
        {
            string source = @"
namespace System.Collections.Generic
{
    public interface IAsyncEnumerable<out T>
    {
        IAsyncEnumerator<T> GetAsyncEnumerator(System.Threading.CancellationToken token = default);
    }
 
    public interface IAsyncEnumerator<out T>
    {
        T Current { get; }
    }
}
class C
{
    async System.Threading.Tasks.Task M(System.Collections.Generic.IAsyncEnumerable<int> collection)
    {
        await foreach (var i in collection)
        {
        }
    }
}";
            var comp = CreateCompilationWithMscorlib46(source);
            comp.VerifyDiagnostics(
                // (18,33): error CS0117: 'IAsyncEnumerator<int>' does not contain a definition for 'MoveNextAsync'
                //         await foreach (var i in collection)
                Diagnostic(ErrorCode.ERR_NoSuchMember, "collection").WithArguments("System.Collections.Generic.IAsyncEnumerator<int>", "MoveNextAsync").WithLocation(18, 33),
                // (18,33): error CS8412: Async foreach requires that the return type 'IAsyncEnumerator<int>' of 'IAsyncEnumerable<int>.GetAsyncEnumerator(System.Threading.CancellationToken)' must have a suitable public MoveNextAsync method and public Current property
                //         await foreach (var i in collection)
                Diagnostic(ErrorCode.ERR_BadGetAsyncEnumerator, "collection").WithArguments("System.Collections.Generic.IAsyncEnumerator<int>", "System.Collections.Generic.IAsyncEnumerable<int>.GetAsyncEnumerator(System.Threading.CancellationToken)").WithLocation(18, 33)
                );
        }
 
        [Fact]
        public void TestWithSyncPattern()
        {
            string source = @"
class C
{
    async System.Threading.Tasks.Task M()
    {
        await foreach (var i in new C())
        {
        }
    }
    public Enumerator GetEnumerator()
    {
        throw null;
    }
    public sealed class Enumerator
    {
        bool MoveNext() => throw null;
        int Current => throw null;
    }
}";
            var comp = CreateCompilationWithMscorlib46(source);
            comp.VerifyDiagnostics(
                // (6,33): error CS8411: Async foreach statement cannot operate on variables of type 'C' because 'C' does not contain a public definition for 'GetAsyncEnumerator'
                //         await foreach (var i in new C())
                Diagnostic(ErrorCode.ERR_AwaitForEachMissingMember, "new C()").WithArguments("C", "GetAsyncEnumerator").WithLocation(6, 33)
                );
        }
 
        [Fact]
        public void TestRegularForeachWithAsyncPattern()
        {
            string source = @"
class C
{
    void M()
    {
        foreach (var i in new C())
        {
        }
    }
    public Enumerator GetAsyncEnumerator(System.Threading.CancellationToken token = default) => throw null;
    public sealed class Enumerator
    {
        public System.Threading.Tasks.Task<bool> MoveNextAsync() => throw null;
        public int Current { get => throw null; }
    }
}";
            var comp = CreateCompilationWithMscorlib46(source);
            comp.VerifyDiagnostics(
                // (6,27): error CS8414: foreach statement cannot operate on variables of type 'C' because 'C' does not contain a public instance or extension definition for 'GetEnumerator'. Did you mean 'await foreach' rather than 'foreach'?
                //         foreach (var i in new C())
                Diagnostic(ErrorCode.ERR_ForEachMissingMemberWrongAsync, "new C()").WithArguments("C", "GetEnumerator").WithLocation(6, 27)
                );
        }
 
        [Fact]
        public void TestRegularForeachWithAsyncInterface()
        {
            string source = @"
using System.Collections.Generic;
class C
{
    void M(IAsyncEnumerable<int> collection)
    {
        foreach (var i in collection)
        {
        }
    }
}";
            var comp = CreateCompilationWithTasksExtensions(source + s_IAsyncEnumerable);
            comp.VerifyDiagnostics(
                // (7,27): error CS8414: foreach statement cannot operate on variables of type 'IAsyncEnumerable<int>' because 'IAsyncEnumerable<int>' does not contain a public instance or extension definition for 'GetEnumerator'. Did you mean 'await foreach'?
                //         foreach (var i in collection)
                Diagnostic(ErrorCode.ERR_ForEachMissingMemberWrongAsync, "collection").WithArguments("System.Collections.Generic.IAsyncEnumerable<int>", "GetEnumerator").WithLocation(7, 27)
                );
        }
 
        [Fact]
        public void TestWithSyncInterfaceInRegularMethod()
        {
            string source = @"
using System.Collections.Generic;
class C
{
    void M(IEnumerable<int> collection)
    {
        await foreach (var i in collection)
        {
        }
    }
}";
            var comp = CreateCompilationWithTasksExtensions(source + s_IAsyncEnumerable);
            comp.VerifyDiagnostics(
                // (7,9): error CS4033: The 'await' operator can only be used within an async method. Consider marking this method with the 'async' modifier and changing its return type to 'Task'.
                //         await foreach (var i in collection)
                Diagnostic(ErrorCode.ERR_BadAwaitWithoutVoidAsyncMethod, "await").WithLocation(7, 9),
                // (7,33): error CS8415: Asynchronous foreach statement cannot operate on variables of type 'IEnumerable<int>' because 'IEnumerable<int>' does not contain a public instance or extension definition for 'GetAsyncEnumerator'. Did you mean 'foreach' rather than 'await foreach'?
                //         await foreach (var i in collection)
                Diagnostic(ErrorCode.ERR_AwaitForEachMissingMemberWrongAsync, "collection").WithArguments("System.Collections.Generic.IEnumerable<int>", "GetAsyncEnumerator").WithLocation(7, 33)
                );
        }
 
        [Fact]
        public void TestPatternBasedAsyncEnumerableWithRegularForeach()
        {
            string source = @"
class C
{
    void M()
    {
        foreach (var i in new C())
        {
        }
    }
    public Enumerator GetAsyncEnumerator(System.Threading.CancellationToken token = default)
        => throw null;
    public sealed class Enumerator
    {
        public System.Threading.Tasks.Task<bool> MoveNextAsync()
            => throw null;
        public int Current { get => throw null; }
    }
}";
            var comp = CreateCompilationWithTasksExtensions(source + s_IAsyncEnumerable);
            comp.VerifyDiagnostics(
                // (6,27): error CS8414: foreach statement cannot operate on variables of type 'C' because 'C' does not contain a public instance or extension definition for 'GetEnumerator'. Did you mean 'await foreach'?
                //         foreach (var i in new C())
                Diagnostic(ErrorCode.ERR_ForEachMissingMemberWrongAsync, "new C()").WithArguments("C", "GetEnumerator").WithLocation(6, 27)
                );
        }
 
        [Fact]
        public void TestPatternBased_GetEnumeratorWithoutCancellationToken()
        {
            string source = @"
public class C
{
    public static async System.Threading.Tasks.Task Main()
    {
        await foreach (var i in new C())
        {
        }
    }
    public Enumerator GetAsyncEnumerator() // no parameter
        => new Enumerator(); 
    public sealed class Enumerator
    {
        public async System.Threading.Tasks.Task<bool> MoveNextAsync()
        {
            System.Console.Write(""MoveNextAsync"");
            await System.Threading.Tasks.Task.Yield();
            return false;
        }
        public int Current => throw null;
    }
}";
            var comp = CreateCompilationWithTasksExtensions(new[] { source, s_IAsyncEnumerable }, options: TestOptions.DebugExe);
            comp.VerifyDiagnostics();
            CompileAndVerify(comp, expectedOutput: "MoveNextAsync");
 
            var runtimeAsyncComp = CreateRuntimeAsyncCompilation(source);
            var verifier = CompileAndVerify(runtimeAsyncComp, expectedOutput: CodeGenAsyncTests.ExpectedOutput("MoveNextAsync", isRuntimeAsync: true), verify: Verification.Fails with
            {
                ILVerifyMessage = """
                    [Main]: Return value missing on the stack. { Offset = 0x21 }
                    [MoveNextAsync]: Unexpected type on the stack. { Offset = 0x2f, Found = Int32, Expected = ref '[System.Runtime]System.Threading.Tasks.Task`1<bool>' }
                    """
            });
            verifier.VerifyIL("C.Main()", """
                {
                  // Code size       34 (0x22)
                  .maxstack  1
                  .locals init (C.Enumerator V_0)
                  IL_0000:  newobj     "C..ctor()"
                  IL_0005:  call       "C.Enumerator C.GetAsyncEnumerator()"
                  IL_000a:  stloc.0
                  IL_000b:  br.s       IL_0014
                  IL_000d:  ldloc.0
                  IL_000e:  callvirt   "int C.Enumerator.Current.get"
                  IL_0013:  pop
                  IL_0014:  ldloc.0
                  IL_0015:  callvirt   "System.Threading.Tasks.Task<bool> C.Enumerator.MoveNextAsync()"
                  IL_001a:  call       "bool System.Runtime.CompilerServices.AsyncHelpers.Await<bool>(System.Threading.Tasks.Task<bool>)"
                  IL_001f:  brtrue.s   IL_000d
                  IL_0021:  ret
                }
                """);
        }
 
        [Fact]
        public void TestPatternBasedEnumerableWithAwaitForeach()
        {
            string source = @"
class C
{
    async System.Threading.Tasks.Task M()
    {
        await foreach (var i in new C())
        {
        }
    }
    public Enumerator<int> GetEnumerator()
        => throw null;
    public class Enumerator<T>
    {
        public T Current { get; }
        public bool MoveNext()
            => throw null;
    }
}";
            var comp = CreateCompilationWithTasksExtensions(source + s_IAsyncEnumerable);
            comp.VerifyDiagnostics(
                // (6,33): error CS8415: Asynchronous foreach statement cannot operate on variables of type 'C' because 'C' does not contain a public instance or extension definition for 'GetAsyncEnumerator'. Did you mean 'foreach' rather than 'await foreach'?
                //         await foreach (var i in new C())
                Diagnostic(ErrorCode.ERR_AwaitForEachMissingMemberWrongAsync, "new C()").WithArguments("C", "GetAsyncEnumerator").WithLocation(6, 33)
                );
        }
 
        [Fact]
        public void TestWithPattern()
        {
            string source = @"
class C
{
    async System.Threading.Tasks.Task M()
    {
        await foreach (var i in new C())
        {
        }
    }
    public Enumerator GetAsyncEnumerator(System.Threading.CancellationToken token = default)
    {
        throw null;
    }
    public sealed class Enumerator
    {
        public System.Threading.Tasks.Task<bool> MoveNextAsync()
        {
            throw null;
        }
        public int Current
        {
            get => throw null;
        }
    }
}";
            var comp = CreateCompilationWithTasksExtensions(source + s_IAsyncEnumerable);
            comp.VerifyDiagnostics();
 
            var tree = comp.SyntaxTrees.Single();
            var model = (SyntaxTreeSemanticModel)comp.GetSemanticModel(tree, ignoreAccessibility: false);
            var foreachSyntax = tree.GetRoot().DescendantNodes().OfType<ForEachStatementSyntax>().Single();
            var info = model.GetForEachStatementInfo(foreachSyntax);
 
            Assert.Equal("C.Enumerator C.GetAsyncEnumerator([System.Threading.CancellationToken token = default(System.Threading.CancellationToken)])", info.GetEnumeratorMethod.ToTestDisplayString());
            Assert.Equal("System.Threading.Tasks.Task<System.Boolean> C.Enumerator.MoveNextAsync()", info.MoveNextMethod.ToTestDisplayString());
            Assert.Equal("System.Int32 C.Enumerator.Current { get; }", info.CurrentProperty.ToTestDisplayString());
            Assert.Null(info.DisposeMethod);
            Assert.Equal("System.Int32", info.ElementType.ToTestDisplayString());
            Assert.Equal(ConversionKind.Identity, info.ElementConversion.Kind);
            Assert.Equal(ConversionKind.Identity, info.CurrentConversion.Kind);
 
            var memberModel = model.GetMemberModel(foreachSyntax);
            BoundForEachStatement boundNode = (BoundForEachStatement)memberModel.GetUpperBoundNode(foreachSyntax);
            ForEachEnumeratorInfo internalInfo = boundNode.EnumeratorInfoOpt;
            Assert.False(internalInfo.NeedsDisposal);
        }
 
        [Fact]
        public void TestWithPattern_Ref()
        {
            string source = @"
class C
{
    async System.Threading.Tasks.Task M()
    {
        await foreach (ref var i in new C())
        {
        }
    }
    public Enumerator GetAsyncEnumerator(System.Threading.CancellationToken token = default)
            => throw null;
    public sealed class Enumerator
    {
        public System.Threading.Tasks.Task<bool> MoveNextAsync()
            => throw null;
        public int Current { get => throw null; }
    }
}" + s_IAsyncEnumerable;
 
            var comp = CreateCompilationWithTasksExtensions(source, parseOptions: TestOptions.Regular12);
            comp.VerifyDiagnostics(
                // (6,32): error CS9202: Feature 'ref and unsafe in async and iterator methods' is not available in C# 12.0. Please use language version 13.0 or greater.
                //         await foreach (ref var i in new C())
                Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion12, "i").WithArguments("ref and unsafe in async and iterator methods", "13.0").WithLocation(6, 32));
 
            var expectedDiagnostics = new[]
            {
                // (6,37): error CS1510: A ref or out value must be an assignable variable
                //         await foreach (ref var i in new C())
                Diagnostic(ErrorCode.ERR_RefLvalueExpected, "new C()").WithLocation(6, 37)
            };
 
            comp = CreateCompilationWithTasksExtensions(source, parseOptions: TestOptions.Regular13);
            comp.VerifyDiagnostics(expectedDiagnostics);
 
            comp = CreateCompilationWithTasksExtensions(source);
            comp.VerifyDiagnostics(expectedDiagnostics);
 
            var tree = comp.SyntaxTrees.Single();
            var model = (SyntaxTreeSemanticModel)comp.GetSemanticModel(tree, ignoreAccessibility: false);
            var foreachSyntax = tree.GetRoot().DescendantNodes().OfType<ForEachStatementSyntax>().Single();
            Assert.Equal(default, model.GetForEachStatementInfo(foreachSyntax));
        }
 
        [Theory, CombinatorialData]
        public void TestWithPattern_Ref_Iterator([CombinatorialValues("        ", "readonly")] string modifier)
        {
            var source = $$"""
                using System;
                using System.Collections.Generic;
                using System.Threading.Tasks;
 
                class C
                {
                    static async Task Main()
                    {
                        await foreach (int i in F())
                        {
                            Console.Write(i);
                        }
                    }
 
                    static async IAsyncEnumerable<int> F()
                    {
                        await foreach (ref {{modifier}} var i in new C())
                        {
                            yield return i;
                        }
                    }
 
                    public Enumerator GetAsyncEnumerator(System.Threading.CancellationToken token = default) => new();
 
                    public sealed class Enumerator
                    {
                        private readonly int[] _array = [1, 2, 3];
                        private int _index = -1;
                        public Task<bool> MoveNextAsync()
                        {
                            if (_index < _array.Length) _index++;
                            return Task.FromResult(_index < _array.Length);
                        }       
                        public ref int Current => ref _array[_index];
                    }
                }
                """;
 
            CSharpTestSource sources = [source, AsyncStreamsTypes];
            var comp = CreateCompilationWithTasksExtensions(sources, parseOptions: TestOptions.Regular12);
            comp.VerifyDiagnostics(
                // (17,41): error CS9202: Feature 'ref and unsafe in async and iterator methods' is not available in C# 12.0. Please use language version 13.0 or greater.
                //         await foreach (ref readonly var i in new C())
                Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion12, "i").WithArguments("ref and unsafe in async and iterator methods", "13.0").WithLocation(17, 41));
 
            var expectedOutput = "123";
 
            comp = CreateCompilationWithTasksExtensions(sources, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular13);
            CompileAndVerify(comp, expectedOutput: expectedOutput).VerifyDiagnostics();
 
            comp = CreateCompilationWithTasksExtensions(sources, options: TestOptions.ReleaseExe);
            CompileAndVerify(comp, expectedOutput: expectedOutput).VerifyDiagnostics();
 
            var runtimeAsyncComp = CreateRuntimeAsyncCompilation(source);
            var verifier = CompileAndVerify(runtimeAsyncComp, expectedOutput: CodeGenAsyncTests.ExpectedOutput(expectedOutput, isRuntimeAsync: true), verify: Verification.Fails with
            {
                ILVerifyMessage = """
                    [Main]: Return value missing on the stack. { Offset = 0x5b }
                    """
            });
            verifier.VerifyIL("C.Main()", """
                {
                  // Code size       92 (0x5c)
                  .maxstack  2
                  .locals init (System.Collections.Generic.IAsyncEnumerator<int> V_0,
                                System.Threading.CancellationToken V_1,
                                object V_2)
                  IL_0000:  call       "System.Collections.Generic.IAsyncEnumerable<int> C.F()"
                  IL_0005:  ldloca.s   V_1
                  IL_0007:  initobj    "System.Threading.CancellationToken"
                  IL_000d:  ldloc.1
                  IL_000e:  callvirt   "System.Collections.Generic.IAsyncEnumerator<int> System.Collections.Generic.IAsyncEnumerable<int>.GetAsyncEnumerator(System.Threading.CancellationToken)"
                  IL_0013:  stloc.0
                  IL_0014:  ldnull
                  IL_0015:  stloc.2
                  .try
                  {
                    IL_0016:  br.s       IL_0023
                    IL_0018:  ldloc.0
                    IL_0019:  callvirt   "int System.Collections.Generic.IAsyncEnumerator<int>.Current.get"
                    IL_001e:  call       "void System.Console.Write(int)"
                    IL_0023:  ldloc.0
                    IL_0024:  callvirt   "System.Threading.Tasks.ValueTask<bool> System.Collections.Generic.IAsyncEnumerator<int>.MoveNextAsync()"
                    IL_0029:  call       "bool System.Runtime.CompilerServices.AsyncHelpers.Await<bool>(System.Threading.Tasks.ValueTask<bool>)"
                    IL_002e:  brtrue.s   IL_0018
                    IL_0030:  leave.s    IL_0035
                  }
                  catch object
                  {
                    IL_0032:  stloc.2
                    IL_0033:  leave.s    IL_0035
                  }
                  IL_0035:  ldloc.0
                  IL_0036:  brfalse.s  IL_0043
                  IL_0038:  ldloc.0
                  IL_0039:  callvirt   "System.Threading.Tasks.ValueTask System.IAsyncDisposable.DisposeAsync()"
                  IL_003e:  call       "void System.Runtime.CompilerServices.AsyncHelpers.Await(System.Threading.Tasks.ValueTask)"
                  IL_0043:  ldloc.2
                  IL_0044:  brfalse.s  IL_005b
                  IL_0046:  ldloc.2
                  IL_0047:  isinst     "System.Exception"
                  IL_004c:  dup
                  IL_004d:  brtrue.s   IL_0051
                  IL_004f:  ldloc.2
                  IL_0050:  throw
                  IL_0051:  call       "System.Runtime.ExceptionServices.ExceptionDispatchInfo System.Runtime.ExceptionServices.ExceptionDispatchInfo.Capture(System.Exception)"
                  IL_0056:  callvirt   "void System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()"
                  IL_005b:  ret
                }
                """);
        }
 
        [Fact]
        public void TestWithPattern_Ref_Iterator_Used()
        {
            var source = """
                using System.Collections.Generic;
                using System.Threading.Tasks;
 
                class C
                {
                    static async IAsyncEnumerable<int> F()
                    {
                        await foreach (ref var i in new C())
                        {
                            yield return i;
                            M(ref i);
                        }
                    }
 
                    static void M(ref int i) { }
 
                    public Enumerator GetAsyncEnumerator(System.Threading.CancellationToken token = default) => new();
 
                    public sealed class Enumerator
                    {
                        private readonly int[] _array = [1, 2, 3];
                        private int _index = -1;
                        public Task<bool> MoveNextAsync()
                        {
                            if (_index < _array.Length) _index++;
                            return Task.FromResult(_index < _array.Length);
                        }       
                        public ref int Current => ref _array[_index];
                    }
                }
                """ + AsyncStreamsTypes;
 
            var comp = CreateCompilationWithTasksExtensions(source, parseOptions: TestOptions.Regular12);
            comp.VerifyDiagnostics(
                // (8,32): error CS9202: Feature 'ref and unsafe in async and iterator methods' is not available in C# 12.0. Please use language version 13.0 or greater.
                //         await foreach (ref var i in new C())
                Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion12, "i").WithArguments("ref and unsafe in async and iterator methods", "13.0").WithLocation(8, 32));
 
            var expectedDiagnostics = new[]
            {
                // (11,19): error CS9217: A 'ref' local cannot be preserved across 'await' or 'yield' boundary.
                //             M(ref i);
                Diagnostic(ErrorCode.ERR_RefLocalAcrossAwait, "i").WithLocation(11, 19)
            };
 
            comp = CreateCompilationWithTasksExtensions(source, parseOptions: TestOptions.Regular13);
            comp.VerifyEmitDiagnostics(expectedDiagnostics);
 
            comp = CreateCompilationWithTasksExtensions(source);
            comp.VerifyEmitDiagnostics(expectedDiagnostics);
        }
 
        [Fact]
        public void TestWithPattern_PointerType()
        {
            string source = @"
unsafe class C
{
    async System.Threading.Tasks.Task M()
    {
        await foreach (var i in new C())
        {
        }
    }
    public Enumerator GetAsyncEnumerator(System.Threading.CancellationToken token = default) => throw null;
    public sealed class Enumerator
    {
        public System.Threading.Tasks.Task<bool> MoveNextAsync() => throw null;
        public int* Current { get => throw null; }
    }
}";
            var comp = CreateCompilationWithTasksExtensions(source + s_IAsyncEnumerable, options: TestOptions.UnsafeDebugDll);
            comp.VerifyDiagnostics(
                // (6,9): error CS4004: Cannot await in an unsafe context
                //         await foreach (var i in new C())
                Diagnostic(ErrorCode.ERR_AwaitInUnsafeContext, "await").WithLocation(6, 9));
 
            var tree = comp.SyntaxTrees.Single();
            var model = (SyntaxTreeSemanticModel)comp.GetSemanticModel(tree, ignoreAccessibility: false);
            var foreachSyntax = tree.GetRoot().DescendantNodes().OfType<ForEachStatementSyntax>().Single();
            Assert.Equal(default, model.GetForEachStatementInfo(foreachSyntax));
        }
 
        [Fact]
        public void TestWithPattern_InaccessibleGetAsyncEnumerator()
        {
            string source = @"
class C
{
    async System.Threading.Tasks.Task M()
    {
        await foreach (var i in new D())
        {
        }
    }
}
class D
{
    private Enumerator GetAsyncEnumerator(System.Threading.CancellationToken token)
            => throw null;
    public sealed class Enumerator
    {
        public System.Threading.Tasks.Task<bool> MoveNextAsync()
            => throw null;
        public int Current { get => throw null; }
    }
}";
            var comp = CreateCompilationWithTasksExtensions(source + s_IAsyncEnumerable);
            comp.VerifyDiagnostics(
                // (6,33): error CS8411: Async foreach statement cannot operate on variables of type 'D' because 'D' does not contain a public definition for 'GetAsyncEnumerator'
                //         await foreach (var i in new D())
                Diagnostic(ErrorCode.ERR_AwaitForEachMissingMember, "new D()").WithArguments("D", "GetAsyncEnumerator").WithLocation(6, 33)
                );
 
            var tree = comp.SyntaxTrees.Single();
            var model = (SyntaxTreeSemanticModel)comp.GetSemanticModel(tree, ignoreAccessibility: false);
            var foreachSyntax = tree.GetRoot().DescendantNodes().OfType<ForEachStatementSyntax>().Single();
            Assert.Equal(default, model.GetForEachStatementInfo(foreachSyntax));
        }
 
        [Fact]
        public void TestWithPattern_InaccessibleMoveNextAsync()
        {
            string source = @"
class C
{
    async System.Threading.Tasks.Task M()
    {
        await foreach (var i in new D())
        {
        }
    }
}
class D
{
    public Enumerator GetAsyncEnumerator(System.Threading.CancellationToken token = default)
            => throw null;
    public sealed class Enumerator
    {
        private System.Threading.Tasks.Task<bool> MoveNextAsync()
            => throw null;
        public int Current { get => throw null; }
    }
}";
            var comp = CreateCompilationWithTasksExtensions(source + s_IAsyncEnumerable);
            comp.VerifyDiagnostics(
                // (6,33): error CS0122: 'D.Enumerator.MoveNextAsync()' is inaccessible due to its protection level
                //         await foreach (var i in new D())
                Diagnostic(ErrorCode.ERR_BadAccess, "new D()").WithArguments("D.Enumerator.MoveNextAsync()").WithLocation(6, 33),
                // (6,33): error CS8412: Async foreach requires that the return type 'D.Enumerator' of 'D.GetAsyncEnumerator(System.Threading.CancellationToken)' must have a suitable public MoveNextAsync method and public Current property
                //         await foreach (var i in new D())
                Diagnostic(ErrorCode.ERR_BadGetAsyncEnumerator, "new D()").WithArguments("D.Enumerator", "D.GetAsyncEnumerator(System.Threading.CancellationToken)").WithLocation(6, 33)
                );
 
            var tree = comp.SyntaxTrees.Single();
            var model = (SyntaxTreeSemanticModel)comp.GetSemanticModel(tree, ignoreAccessibility: false);
            var foreachSyntax = tree.GetRoot().DescendantNodes().OfType<ForEachStatementSyntax>().Single();
            Assert.Equal(default, model.GetForEachStatementInfo(foreachSyntax));
        }
 
        [Fact]
        public void TestWithPattern_InaccessibleCurrent()
        {
            string source = @"
class C
{
    async System.Threading.Tasks.Task M()
    {
        await foreach (var i in new D()) { }
    }
}
class D
{
    public Enumerator GetAsyncEnumerator(System.Threading.CancellationToken token = default)
            => throw null;
    public sealed class Enumerator
    {
        public System.Threading.Tasks.Task<bool> MoveNextAsync() => throw null;
        private int Current { get => throw null; }
    }
}";
            var comp = CreateCompilationWithTasksExtensions(source + s_IAsyncEnumerable);
            comp.VerifyDiagnostics(
                // (6,33): error CS0122: 'D.Enumerator.Current' is inaccessible due to its protection level
                //         await foreach (var i in new D()) { }
                Diagnostic(ErrorCode.ERR_BadAccess, "new D()").WithArguments("D.Enumerator.Current").WithLocation(6, 33),
                // (6,33): error CS8412: Async foreach requires that the return type 'D.Enumerator' of 'D.GetAsyncEnumerator(System.Threading.CancellationToken)' must have a suitable public MoveNextAsync method and public Current property
                //         await foreach (var i in new D()) { }
                Diagnostic(ErrorCode.ERR_BadGetAsyncEnumerator, "new D()").WithArguments("D.Enumerator", "D.GetAsyncEnumerator(System.Threading.CancellationToken)").WithLocation(6, 33)
                );
 
            var tree = comp.SyntaxTrees.Single();
            var model = (SyntaxTreeSemanticModel)comp.GetSemanticModel(tree, ignoreAccessibility: false);
            var foreachSyntax = tree.GetRoot().DescendantNodes().OfType<ForEachStatementSyntax>().Single();
            Assert.Equal(default, model.GetForEachStatementInfo(foreachSyntax));
        }
 
        [Fact]
        public void TestWithPattern_InaccessibleCurrentGetter()
        {
            string source = @"
class C
{
    async System.Threading.Tasks.Task M()
    {
        await foreach (var i in new D()) { }
    }
}
class D
{
    public Enumerator GetAsyncEnumerator()
            => throw null;
    public sealed class Enumerator
    {
        public System.Threading.Tasks.Task<bool> MoveNextAsync() => throw null;
        public int Current { private get => throw null; set => throw null; }
    }
}";
            var comp = CreateCompilationWithTasksExtensions(source + s_IAsyncEnumerable);
            comp.VerifyDiagnostics(
                // (6,33): error CS8412: Async foreach requires that the return type 'D.Enumerator' of 'D.GetAsyncEnumerator()' must have a suitable public MoveNextAsync method and public Current property
                //         await foreach (var i in new D()) { }
                Diagnostic(ErrorCode.ERR_BadGetAsyncEnumerator, "new D()").WithArguments("D.Enumerator", "D.GetAsyncEnumerator()").WithLocation(6, 33)
                );
 
            var tree = comp.SyntaxTrees.Single();
            var model = (SyntaxTreeSemanticModel)comp.GetSemanticModel(tree, ignoreAccessibility: false);
            var foreachSyntax = tree.GetRoot().DescendantNodes().OfType<ForEachStatementSyntax>().Single();
            Assert.Equal(default, model.GetForEachStatementInfo(foreachSyntax));
        }
 
        [Fact]
        public void TestWithPattern_RefStruct()
        {
            string source = @"
using static System.Console;
using System.Threading.Tasks;
public class C
{
    public static async System.Threading.Tasks.Task Main()
    {
        await foreach (var s in new C())
        {
            Write($""{s.ToString()} "");
        }
        Write(""Done"");
    }
    public Enumerator GetAsyncEnumerator() => new Enumerator();
    public sealed class Enumerator : System.IAsyncDisposable
    {
        int i = 0;
        public int Current => i;
        public async Task<bool> MoveNextAsync()
        {
            i++;
            return await Task.FromResult(i < 3);
        }
        public async ValueTask DisposeAsync()
        {
            await Task.Yield();
        }
    }
}
public ref struct S
{
    int i;
    public S(int i)
    {
        this.i = i;
    }
    public override string ToString() => i.ToString();
}
";
            var comp = CreateCompilationWithTasksExtensions(source + s_IAsyncEnumerable, options: TestOptions.DebugExe);
            comp.VerifyDiagnostics();
            CompileAndVerify(comp, expectedOutput: "1 2 Done");
 
            var runtimeAsyncComp = CreateRuntimeAsyncCompilation(source);
            var verifier = CompileAndVerify(runtimeAsyncComp, expectedOutput: CodeGenAsyncTests.ExpectedOutput("1 2 Done", isRuntimeAsync: true), verify: Verification.Fails with
            {
                ILVerifyMessage = """
                    [Main]: Return value missing on the stack. { Offset = 0x6e }
                    [MoveNextAsync]: Unexpected type on the stack. { Offset = 0x21, Found = Int32, Expected = ref '[System.Runtime]System.Threading.Tasks.Task`1<bool>' }
                    [DisposeAsync]: Return value missing on the stack. { Offset = 0x24 }
                    """
            });
            verifier.VerifyIL("C.Main()", """
                {
                  // Code size      111 (0x6f)
                  .maxstack  2
                  .locals init (C.Enumerator V_0,
                                object V_1,
                                int V_2) //s
                  IL_0000:  newobj     "C..ctor()"
                  IL_0005:  call       "C.Enumerator C.GetAsyncEnumerator()"
                  IL_000a:  stloc.0
                  IL_000b:  ldnull
                  IL_000c:  stloc.1
                  .try
                  {
                    IL_000d:  br.s       IL_002c
                    IL_000f:  ldloc.0
                    IL_0010:  callvirt   "int C.Enumerator.Current.get"
                    IL_0015:  stloc.2
                    IL_0016:  ldloca.s   V_2
                    IL_0018:  call       "string int.ToString()"
                    IL_001d:  ldstr      " "
                    IL_0022:  call       "string string.Concat(string, string)"
                    IL_0027:  call       "void System.Console.Write(string)"
                    IL_002c:  ldloc.0
                    IL_002d:  callvirt   "System.Threading.Tasks.Task<bool> C.Enumerator.MoveNextAsync()"
                    IL_0032:  call       "bool System.Runtime.CompilerServices.AsyncHelpers.Await<bool>(System.Threading.Tasks.Task<bool>)"
                    IL_0037:  brtrue.s   IL_000f
                    IL_0039:  leave.s    IL_003e
                  }
                  catch object
                  {
                    IL_003b:  stloc.1
                    IL_003c:  leave.s    IL_003e
                  }
                  IL_003e:  ldloc.0
                  IL_003f:  brfalse.s  IL_004c
                  IL_0041:  ldloc.0
                  IL_0042:  callvirt   "System.Threading.Tasks.ValueTask C.Enumerator.DisposeAsync()"
                  IL_0047:  call       "void System.Runtime.CompilerServices.AsyncHelpers.Await(System.Threading.Tasks.ValueTask)"
                  IL_004c:  ldloc.1
                  IL_004d:  brfalse.s  IL_0064
                  IL_004f:  ldloc.1
                  IL_0050:  isinst     "System.Exception"
                  IL_0055:  dup
                  IL_0056:  brtrue.s   IL_005a
                  IL_0058:  ldloc.1
                  IL_0059:  throw
                  IL_005a:  call       "System.Runtime.ExceptionServices.ExceptionDispatchInfo System.Runtime.ExceptionServices.ExceptionDispatchInfo.Capture(System.Exception)"
                  IL_005f:  callvirt   "void System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()"
                  IL_0064:  ldstr      "Done"
                  IL_0069:  call       "void System.Console.Write(string)"
                  IL_006e:  ret
                }
                """);
        }
 
        [Theory]
        [InlineData("")]
        [InlineData("await Task.Yield();")]
        public void TestWithPattern_RefStructEnumerator_Async(string body)
        {
            var source = $$"""
                using System.Threading.Tasks;
                public class C
                {
                    public static async Task Main()
                    {
                        await foreach (var s in new C())
                        {
                            {{body}}
                        }
                    }
                    public Enumerator GetAsyncEnumerator() => new Enumerator();
                    public ref struct Enumerator
                    {
                        public int Current => 0;
                        public Task<bool> MoveNextAsync() => throw null;
                    }
                }
                """;
 
            CreateCompilation(source, parseOptions: TestOptions.Regular12).VerifyDiagnostics(
                // (6,15): error CS9202: Feature 'ref and unsafe in async and iterator methods' is not available in C# 12.0. Please use language version 13.0 or greater.
                //         await foreach (var s in new C())
                Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion12, "foreach").WithArguments("ref and unsafe in async and iterator methods", "13.0").WithLocation(6, 15));
 
            var expectedDiagnostics = new[]
            {
                // (6,9): error CS4007: Instance of type 'C.Enumerator' cannot be preserved across 'await' or 'yield' boundary.
                //         await foreach (var s in new C())
                Diagnostic(ErrorCode.ERR_ByRefTypeAndAwait, @"await foreach (var s in new C())
        {
            " + body + @"
        }").WithArguments("C.Enumerator").WithLocation(6, 9)
            };
 
            CreateCompilation(source, parseOptions: TestOptions.Regular13).VerifyEmitDiagnostics(expectedDiagnostics);
            CreateCompilation(source).VerifyEmitDiagnostics(expectedDiagnostics);
        }
 
        [Theory]
        [InlineData("")]
        [InlineData("await Task.Yield();")]
        [InlineData("yield return x;")]
        [InlineData("yield return x; await Task.Yield();")]
        [InlineData("await Task.Yield(); yield return x;")]
        public void TestWithPattern_RefStructEnumerator_AsyncIterator(string body)
        {
            var source = $$"""
                using System.Collections.Generic;
                using System.Threading.Tasks;
                public class C
                {
                    public static async IAsyncEnumerable<int> M()
                    {
                        await foreach (var x in new C())
                        {
                            {{body}}
                        }
                        yield return -1;
                    }
                    public Enumerator GetAsyncEnumerator() => new Enumerator();
                    public ref struct Enumerator
                    {
                        public int Current => 0;
                        public Task<bool> MoveNextAsync() => throw null;
                    }
                }
                """ + AsyncStreamsTypes;
 
            CreateCompilationWithTasksExtensions(source, parseOptions: TestOptions.Regular12).VerifyDiagnostics(
                // (7,15): error CS9202: Feature 'ref and unsafe in async and iterator methods' is not available in C# 12.0. Please use language version 13.0 or greater.
                //         await foreach (var x in new C())
                Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion12, "foreach").WithArguments("ref and unsafe in async and iterator methods", "13.0").WithLocation(7, 15));
 
            var expectedDiagnostics = new[]
            {
                // (7,9): error CS4007: Instance of type 'C.Enumerator' cannot be preserved across 'await' or 'yield' boundary.
                //         await foreach (var x in new C())
                Diagnostic(ErrorCode.ERR_ByRefTypeAndAwait, @"await foreach (var x in new C())
        {
            " + body + @"
        }").WithArguments("C.Enumerator").WithLocation(7, 9)
            };
 
            CreateCompilationWithTasksExtensions(source, parseOptions: TestOptions.Regular13).VerifyEmitDiagnostics(expectedDiagnostics);
            CreateCompilationWithTasksExtensions(source).VerifyEmitDiagnostics(expectedDiagnostics);
        }
 
        [Fact]
        public void TestWithPattern_RefStructEnumerator_Iterator()
        {
            var source = """
                using System.Collections.Generic;
                public class C
                {
                    public static IEnumerable<int> M()
                    {
                        foreach (var x in new C())
                        {
                            yield return x;
                        }
                    }
                    public Enumerator GetEnumerator() => new Enumerator();
                    public ref struct Enumerator
                    {
                        public int Current => 0;
                        public bool MoveNext() => throw null;
                    }
                }
                """;
 
            CreateCompilation(source, parseOptions: TestOptions.Regular12).VerifyDiagnostics(
                // (6,9): error CS9202: Feature 'ref and unsafe in async and iterator methods' is not available in C# 12.0. Please use language version 13.0 or greater.
                //         foreach (var x in new C())
                Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion12, "foreach").WithArguments("ref and unsafe in async and iterator methods", "13.0").WithLocation(6, 9));
 
            var expectedDiagnostics = new[]
            {
                // (6,9): error CS4007: Instance of type 'C.Enumerator' cannot be preserved across 'await' or 'yield' boundary.
                //         foreach (var x in new C())
                Diagnostic(ErrorCode.ERR_ByRefTypeAndAwait, @"foreach (var x in new C())
        {
            yield return x;
        }").WithArguments("C.Enumerator").WithLocation(6, 9)
            };
 
            CreateCompilation(source, parseOptions: TestOptions.Regular13).VerifyEmitDiagnostics(expectedDiagnostics);
            CreateCompilation(source).VerifyEmitDiagnostics(expectedDiagnostics);
        }
 
        [Fact]
        public void TestWithPattern_RefStructEnumerable_Async()
        {
            var source = """
                using System;
                using System.Threading.Tasks;
                public class C
                {
                    public static async Task Main()
                    {
                        await foreach (var x in new Enumerable())
                        {
                            await Task.Yield();
                            Console.Write($"{x} ");
                        }
                        Console.Write("Done");
                    }
                    public ref struct Enumerable
                    {
                        public Enumerator GetAsyncEnumerator() => new();
                    }
                    public class Enumerator
                    {
                        int i = 0;
                        public int Current => i;
                        public async Task<bool> MoveNextAsync()
                        {
                            i++;
                            await Task.Yield();
                            return i < 3;
                        }
                    }
                }
                """ + s_IAsyncEnumerable;
            var comp = CreateCompilationWithTasksExtensions(source, options: TestOptions.ReleaseExe);
            CompileAndVerify(comp, expectedOutput: "1 2 Done").VerifyDiagnostics();
 
            var runtimeAsyncComp = CreateRuntimeAsyncCompilation(source);
            var verifier = CompileAndVerify(runtimeAsyncComp, expectedOutput: CodeGenAsyncTests.ExpectedOutput("1 2 Done", isRuntimeAsync: true), verify: Verification.Fails with
            {
                ILVerifyMessage = """
                    [Main]: Return value missing on the stack. { Offset = 0x7d }
                    [MoveNextAsync]: Unexpected type on the stack. { Offset = 0x3b, Found = Int32, Expected = ref '[System.Runtime]System.Threading.Tasks.Task`1<bool>' }
                    """
            });
            verifier.VerifyIL("C.Main()", """
                {
                  // Code size      126 (0x7e)
                  .maxstack  3
                  .locals init (C.Enumerator V_0,
                                C.Enumerable V_1,
                                int V_2, //x
                                System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter V_3,
                                System.Runtime.CompilerServices.YieldAwaitable V_4,
                                System.Runtime.CompilerServices.DefaultInterpolatedStringHandler V_5)
                  IL_0000:  ldloca.s   V_1
                  IL_0002:  dup
                  IL_0003:  initobj    "C.Enumerable"
                  IL_0009:  call       "C.Enumerator C.Enumerable.GetAsyncEnumerator()"
                  IL_000e:  stloc.0
                  IL_000f:  br.s       IL_0066
                  IL_0011:  ldloc.0
                  IL_0012:  callvirt   "int C.Enumerator.Current.get"
                  IL_0017:  stloc.2
                  IL_0018:  call       "System.Runtime.CompilerServices.YieldAwaitable System.Threading.Tasks.Task.Yield()"
                  IL_001d:  stloc.s    V_4
                  IL_001f:  ldloca.s   V_4
                  IL_0021:  call       "System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter System.Runtime.CompilerServices.YieldAwaitable.GetAwaiter()"
                  IL_0026:  stloc.3
                  IL_0027:  ldloca.s   V_3
                  IL_0029:  call       "bool System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter.IsCompleted.get"
                  IL_002e:  brtrue.s   IL_0036
                  IL_0030:  ldloc.3
                  IL_0031:  call       "void System.Runtime.CompilerServices.AsyncHelpers.UnsafeAwaitAwaiter<System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter>(System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter)"
                  IL_0036:  ldloca.s   V_3
                  IL_0038:  call       "void System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter.GetResult()"
                  IL_003d:  ldloca.s   V_5
                  IL_003f:  ldc.i4.1
                  IL_0040:  ldc.i4.1
                  IL_0041:  call       "System.Runtime.CompilerServices.DefaultInterpolatedStringHandler..ctor(int, int)"
                  IL_0046:  ldloca.s   V_5
                  IL_0048:  ldloc.2
                  IL_0049:  call       "void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted<int>(int)"
                  IL_004e:  ldloca.s   V_5
                  IL_0050:  ldstr      " "
                  IL_0055:  call       "void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendLiteral(string)"
                  IL_005a:  ldloca.s   V_5
                  IL_005c:  call       "string System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.ToStringAndClear()"
                  IL_0061:  call       "void System.Console.Write(string)"
                  IL_0066:  ldloc.0
                  IL_0067:  callvirt   "System.Threading.Tasks.Task<bool> C.Enumerator.MoveNextAsync()"
                  IL_006c:  call       "bool System.Runtime.CompilerServices.AsyncHelpers.Await<bool>(System.Threading.Tasks.Task<bool>)"
                  IL_0071:  brtrue.s   IL_0011
                  IL_0073:  ldstr      "Done"
                  IL_0078:  call       "void System.Console.Write(string)"
                  IL_007d:  ret
                }
                """);
        }
 
        [Fact]
        public void TestWithPattern_RefStructEnumerable_AsyncIterator()
        {
            var source = """
                using System;
                using System.Collections.Generic;
                using System.Threading.Tasks;
                public class C
                {
                    public static async Task Main()
                    {
                        await foreach (var i in M())
                        {
                            Console.Write($"{i} ");
                        }
                        Console.Write("Done");
                    }
                    public static async IAsyncEnumerable<int> M()
                    {
                        await foreach (var x in new Enumerable())
                        {
                            await Task.Yield();
                            yield return x * 2;
                        }
                        yield return -1;
                    }
                    public ref struct Enumerable
                    {
                        public Enumerator GetAsyncEnumerator() => new();
                    }
                    public class Enumerator
                    {
                        int i = 0;
                        public int Current => i;
                        public async Task<bool> MoveNextAsync()
                        {
                            i++;
                            await Task.Yield();
                            return i < 3;
                        }
                    }
                }
                """;
            var comp = CreateCompilationWithTasksExtensions([source, AsyncStreamsTypes], options: TestOptions.ReleaseExe);
            CompileAndVerify(comp, expectedOutput: "2 4 -1 Done").VerifyDiagnostics();
 
            var runtimeAsyncComp = CreateRuntimeAsyncCompilation(source);
            var verifier = CompileAndVerify(runtimeAsyncComp, expectedOutput: CodeGenAsyncTests.ExpectedOutput("2 4 -1 Done", isRuntimeAsync: true), verify: Verification.Fails with
            {
                ILVerifyMessage = """
                    [Main]: Return value missing on the stack. { Offset = 0x8a }
                    [MoveNextAsync]: Unexpected type on the stack. { Offset = 0x3b, Found = Int32, Expected = ref '[System.Runtime]System.Threading.Tasks.Task`1<bool>' }
                    """
            });
            verifier.VerifyIL("C.Main()", """
                {
                  // Code size      139 (0x8b)
                  .maxstack  2
                  .locals init (System.Collections.Generic.IAsyncEnumerator<int> V_0,
                                System.Threading.CancellationToken V_1,
                                object V_2,
                                int V_3, //i
                                System.Runtime.CompilerServices.DefaultInterpolatedStringHandler V_4)
                  IL_0000:  call       "System.Collections.Generic.IAsyncEnumerable<int> C.M()"
                  IL_0005:  ldloca.s   V_1
                  IL_0007:  initobj    "System.Threading.CancellationToken"
                  IL_000d:  ldloc.1
                  IL_000e:  callvirt   "System.Collections.Generic.IAsyncEnumerator<int> System.Collections.Generic.IAsyncEnumerable<int>.GetAsyncEnumerator(System.Threading.CancellationToken)"
                  IL_0013:  stloc.0
                  IL_0014:  ldnull
                  IL_0015:  stloc.2
                  .try
                  {
                    IL_0016:  br.s       IL_0048
                    IL_0018:  ldloc.0
                    IL_0019:  callvirt   "int System.Collections.Generic.IAsyncEnumerator<int>.Current.get"
                    IL_001e:  stloc.3
                    IL_001f:  ldc.i4.1
                    IL_0020:  ldc.i4.1
                    IL_0021:  newobj     "System.Runtime.CompilerServices.DefaultInterpolatedStringHandler..ctor(int, int)"
                    IL_0026:  stloc.s    V_4
                    IL_0028:  ldloca.s   V_4
                    IL_002a:  ldloc.3
                    IL_002b:  call       "void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted<int>(int)"
                    IL_0030:  ldloca.s   V_4
                    IL_0032:  ldstr      " "
                    IL_0037:  call       "void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendLiteral(string)"
                    IL_003c:  ldloca.s   V_4
                    IL_003e:  call       "string System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.ToStringAndClear()"
                    IL_0043:  call       "void System.Console.Write(string)"
                    IL_0048:  ldloc.0
                    IL_0049:  callvirt   "System.Threading.Tasks.ValueTask<bool> System.Collections.Generic.IAsyncEnumerator<int>.MoveNextAsync()"
                    IL_004e:  call       "bool System.Runtime.CompilerServices.AsyncHelpers.Await<bool>(System.Threading.Tasks.ValueTask<bool>)"
                    IL_0053:  brtrue.s   IL_0018
                    IL_0055:  leave.s    IL_005a
                  }
                  catch object
                  {
                    IL_0057:  stloc.2
                    IL_0058:  leave.s    IL_005a
                  }
                  IL_005a:  ldloc.0
                  IL_005b:  brfalse.s  IL_0068
                  IL_005d:  ldloc.0
                  IL_005e:  callvirt   "System.Threading.Tasks.ValueTask System.IAsyncDisposable.DisposeAsync()"
                  IL_0063:  call       "void System.Runtime.CompilerServices.AsyncHelpers.Await(System.Threading.Tasks.ValueTask)"
                  IL_0068:  ldloc.2
                  IL_0069:  brfalse.s  IL_0080
                  IL_006b:  ldloc.2
                  IL_006c:  isinst     "System.Exception"
                  IL_0071:  dup
                  IL_0072:  brtrue.s   IL_0076
                  IL_0074:  ldloc.2
                  IL_0075:  throw
                  IL_0076:  call       "System.Runtime.ExceptionServices.ExceptionDispatchInfo System.Runtime.ExceptionServices.ExceptionDispatchInfo.Capture(System.Exception)"
                  IL_007b:  callvirt   "void System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()"
                  IL_0080:  ldstr      "Done"
                  IL_0085:  call       "void System.Console.Write(string)"
                  IL_008a:  ret
                }
                """);
        }
 
        [Fact]
        public void TestWithPattern_RefStructEnumerable_Iterator()
        {
            var source = """
                using System;
                using System.Collections.Generic;
                public class C
                {
                    public static void Main()
                    {
                        foreach (var i in M())
                        {
                            Console.Write($"{i} ");
                        }
                        Console.Write("Done");
                    }
                    public static IEnumerable<int> M()
                    {
                        foreach (var x in new Enumerable())
                        {
                            yield return x * 2;
                        }
                        yield return -1;
                    }
                    public ref struct Enumerable
                    {
                        public Enumerator GetEnumerator() => new();
                    }
                    public class Enumerator
                    {
                        int i = 0;
                        public int Current => i;
                        public bool MoveNext()
                        {
                            i++;
                            return i < 3;
                        }
                    }
                }
                """;
            CompileAndVerify(source, expectedOutput: "2 4 -1 Done").VerifyDiagnostics();
        }
 
        [Fact]
        public void TestWithPattern_RefStructCurrent_Async()
        {
            var source = """
                using System;
                using System.Threading.Tasks;
                public class C
                {
                    public static async Task Main()
                    {
                        await foreach (var s in new C())
                        {
                            Console.Write($"{s.ToString()} ");
                        }
                        Console.Write("Done");
                    }
                    public Enumerator GetAsyncEnumerator() => new Enumerator();
                    public sealed class Enumerator : IAsyncDisposable
                    {
                        int i = 0;
                        public S Current => new S(i);
                        public async Task<bool> MoveNextAsync()
                        {
                            i++;
                            await Task.Yield();
                            return i < 3;
                        }
                        public async ValueTask DisposeAsync()
                        {
                            await Task.Yield();
                        }
                    }
                }
                public ref struct S
                {
                    int i;
                    public S(int i)
                    {
                        this.i = i;
                    }
                    public override string ToString() => i.ToString();
                }
                """ + s_IAsyncEnumerable;
 
            var expectedDiagnostics = new[]
            {
                // (7,24): error CS9202: Feature 'ref and unsafe in async and iterator methods' is not available in C# 12.0. Please use language version 13.0 or greater.
                //         await foreach (var s in new C())
                Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion12, "var").WithArguments("ref and unsafe in async and iterator methods", "13.0").WithLocation(7, 24)
            };
 
            CreateCompilationWithTasksExtensions(source, parseOptions: TestOptions.Regular12).VerifyDiagnostics(expectedDiagnostics);
 
            var expectedOutput = "1 2 Done";
 
            var comp = CreateCompilationWithTasksExtensions(source, parseOptions: TestOptions.Regular13, options: TestOptions.ReleaseExe);
            CompileAndVerify(comp, expectedOutput: expectedOutput, verify: Verification.FailsILVerify).VerifyDiagnostics();
 
            comp = CreateCompilationWithTasksExtensions(source, options: TestOptions.ReleaseExe);
            CompileAndVerify(comp, expectedOutput: expectedOutput, verify: Verification.FailsILVerify).VerifyDiagnostics();
 
            var runtimeAsyncComp = CreateRuntimeAsyncCompilation(source);
            var verifier = CompileAndVerify(runtimeAsyncComp, expectedOutput: CodeGenAsyncTests.ExpectedOutput(expectedOutput, isRuntimeAsync: true), verify: Verification.Fails with
            {
                ILVerifyMessage = """
                    [Main]: Return value missing on the stack. { Offset = 0x74 }
                    [get_Current]: Return type is ByRef, TypedReference, ArgHandle, or ArgIterator. { Offset = 0xb }
                    [MoveNextAsync]: Unexpected type on the stack. { Offset = 0x3b, Found = Int32, Expected = ref '[System.Runtime]System.Threading.Tasks.Task`1<bool>' }
                    [DisposeAsync]: Return value missing on the stack. { Offset = 0x24 }
                    """
            });
            verifier.VerifyIL("C.Main()", """
                {
                  // Code size      117 (0x75)
                  .maxstack  2
                  .locals init (C.Enumerator V_0,
                                object V_1,
                                S V_2) //s
                  IL_0000:  newobj     "C..ctor()"
                  IL_0005:  call       "C.Enumerator C.GetAsyncEnumerator()"
                  IL_000a:  stloc.0
                  IL_000b:  ldnull
                  IL_000c:  stloc.1
                  .try
                  {
                    IL_000d:  br.s       IL_0032
                    IL_000f:  ldloc.0
                    IL_0010:  callvirt   "S C.Enumerator.Current.get"
                    IL_0015:  stloc.2
                    IL_0016:  ldloca.s   V_2
                    IL_0018:  constrained. "S"
                    IL_001e:  callvirt   "string object.ToString()"
                    IL_0023:  ldstr      " "
                    IL_0028:  call       "string string.Concat(string, string)"
                    IL_002d:  call       "void System.Console.Write(string)"
                    IL_0032:  ldloc.0
                    IL_0033:  callvirt   "System.Threading.Tasks.Task<bool> C.Enumerator.MoveNextAsync()"
                    IL_0038:  call       "bool System.Runtime.CompilerServices.AsyncHelpers.Await<bool>(System.Threading.Tasks.Task<bool>)"
                    IL_003d:  brtrue.s   IL_000f
                    IL_003f:  leave.s    IL_0044
                  }
                  catch object
                  {
                    IL_0041:  stloc.1
                    IL_0042:  leave.s    IL_0044
                  }
                  IL_0044:  ldloc.0
                  IL_0045:  brfalse.s  IL_0052
                  IL_0047:  ldloc.0
                  IL_0048:  callvirt   "System.Threading.Tasks.ValueTask C.Enumerator.DisposeAsync()"
                  IL_004d:  call       "void System.Runtime.CompilerServices.AsyncHelpers.Await(System.Threading.Tasks.ValueTask)"
                  IL_0052:  ldloc.1
                  IL_0053:  brfalse.s  IL_006a
                  IL_0055:  ldloc.1
                  IL_0056:  isinst     "System.Exception"
                  IL_005b:  dup
                  IL_005c:  brtrue.s   IL_0060
                  IL_005e:  ldloc.1
                  IL_005f:  throw
                  IL_0060:  call       "System.Runtime.ExceptionServices.ExceptionDispatchInfo System.Runtime.ExceptionServices.ExceptionDispatchInfo.Capture(System.Exception)"
                  IL_0065:  callvirt   "void System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()"
                  IL_006a:  ldstr      "Done"
                  IL_006f:  call       "void System.Console.Write(string)"
                  IL_0074:  ret
                }
                """);
        }
 
        [Fact]
        public void TestWithPattern_RefStructCurrent_AsyncIterator()
        {
            var source = """
                using System;
                using System.Collections.Generic;
                using System.Threading.Tasks;
                public class C
                {
                    public static async Task Main()
                    {
                        await foreach (var s in M())
                        {
                            Console.Write($"M:{s} ");
                        }
                        Console.Write("MainDone");
                    }
                    public static async IAsyncEnumerable<string> M()
                    {
                        await foreach (var s in new C())
                        {
                            yield return s.ToString();
                        }
                        yield return "Done";
                    }
                    public Enumerator GetAsyncEnumerator() => new Enumerator();
                    public sealed class Enumerator : IAsyncDisposable
                    {
                        int i = 0;
                        public S Current => new S(i);
                        public async Task<bool> MoveNextAsync()
                        {
                            i++;
                            await Task.Yield();
                            return i < 3;
                        }
                        public async ValueTask DisposeAsync()
                        {
                            await Task.Yield();
                        }
                    }
                }
                public ref struct S
                {
                    int i;
                    public S(int i)
                    {
                        this.i = i;
                    }
                    public override string ToString() => i.ToString();
                }
                """;
 
            var expectedDiagnostics = new[]
            {
                // (16,24): error CS9202: Feature 'ref and unsafe in async and iterator methods' is not available in C# 12.0. Please use language version 13.0 or greater.
                //         await foreach (var s in new C())
                Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion12, "var").WithArguments("ref and unsafe in async and iterator methods", "13.0").WithLocation(16, 24)
            };
 
            CSharpTestSource sources = [source, AsyncStreamsTypes];
            CreateCompilationWithTasksExtensions(sources, parseOptions: TestOptions.Regular12).VerifyDiagnostics(expectedDiagnostics);
 
            var expectedOutput = "M:1 M:2 M:Done MainDone";
 
            var comp = CreateCompilationWithTasksExtensions(sources, parseOptions: TestOptions.Regular13, options: TestOptions.ReleaseExe);
            CompileAndVerify(comp, expectedOutput: expectedOutput, verify: Verification.FailsILVerify).VerifyDiagnostics();
 
            comp = CreateCompilationWithTasksExtensions(sources, options: TestOptions.ReleaseExe);
            CompileAndVerify(comp, expectedOutput: expectedOutput, verify: Verification.FailsILVerify).VerifyDiagnostics();
 
            var runtimeAsyncComp = CreateRuntimeAsyncCompilation(source);
            var verifier = CompileAndVerify(runtimeAsyncComp, expectedOutput: CodeGenAsyncTests.ExpectedOutput(expectedOutput, isRuntimeAsync: true), verify: Verification.Fails with
            {
                ILVerifyMessage = """
                    [Main]: Return value missing on the stack. { Offset = 0x76 }
                    [get_Current]: Return type is ByRef, TypedReference, ArgHandle, or ArgIterator. { Offset = 0xb }
                    [MoveNextAsync]: Unexpected type on the stack. { Offset = 0x3b, Found = Int32, Expected = ref '[System.Runtime]System.Threading.Tasks.Task`1<bool>' }
                    [DisposeAsync]: Return value missing on the stack. { Offset = 0x24 }
                    """
            });
            verifier.VerifyIL("C.Main()", """
                {
                  // Code size      119 (0x77)
                  .maxstack  3
                  .locals init (System.Collections.Generic.IAsyncEnumerator<string> V_0,
                                System.Threading.CancellationToken V_1,
                                object V_2,
                                string V_3) //s
                  IL_0000:  call       "System.Collections.Generic.IAsyncEnumerable<string> C.M()"
                  IL_0005:  ldloca.s   V_1
                  IL_0007:  initobj    "System.Threading.CancellationToken"
                  IL_000d:  ldloc.1
                  IL_000e:  callvirt   "System.Collections.Generic.IAsyncEnumerator<string> System.Collections.Generic.IAsyncEnumerable<string>.GetAsyncEnumerator(System.Threading.CancellationToken)"
                  IL_0013:  stloc.0
                  IL_0014:  ldnull
                  IL_0015:  stloc.2
                  .try
                  {
                    IL_0016:  br.s       IL_0034
                    IL_0018:  ldloc.0
                    IL_0019:  callvirt   "string System.Collections.Generic.IAsyncEnumerator<string>.Current.get"
                    IL_001e:  stloc.3
                    IL_001f:  ldstr      "M:"
                    IL_0024:  ldloc.3
                    IL_0025:  ldstr      " "
                    IL_002a:  call       "string string.Concat(string, string, string)"
                    IL_002f:  call       "void System.Console.Write(string)"
                    IL_0034:  ldloc.0
                    IL_0035:  callvirt   "System.Threading.Tasks.ValueTask<bool> System.Collections.Generic.IAsyncEnumerator<string>.MoveNextAsync()"
                    IL_003a:  call       "bool System.Runtime.CompilerServices.AsyncHelpers.Await<bool>(System.Threading.Tasks.ValueTask<bool>)"
                    IL_003f:  brtrue.s   IL_0018
                    IL_0041:  leave.s    IL_0046
                  }
                  catch object
                  {
                    IL_0043:  stloc.2
                    IL_0044:  leave.s    IL_0046
                  }
                  IL_0046:  ldloc.0
                  IL_0047:  brfalse.s  IL_0054
                  IL_0049:  ldloc.0
                  IL_004a:  callvirt   "System.Threading.Tasks.ValueTask System.IAsyncDisposable.DisposeAsync()"
                  IL_004f:  call       "void System.Runtime.CompilerServices.AsyncHelpers.Await(System.Threading.Tasks.ValueTask)"
                  IL_0054:  ldloc.2
                  IL_0055:  brfalse.s  IL_006c
                  IL_0057:  ldloc.2
                  IL_0058:  isinst     "System.Exception"
                  IL_005d:  dup
                  IL_005e:  brtrue.s   IL_0062
                  IL_0060:  ldloc.2
                  IL_0061:  throw
                  IL_0062:  call       "System.Runtime.ExceptionServices.ExceptionDispatchInfo System.Runtime.ExceptionServices.ExceptionDispatchInfo.Capture(System.Exception)"
                  IL_0067:  callvirt   "void System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()"
                  IL_006c:  ldstr      "MainDone"
                  IL_0071:  call       "void System.Console.Write(string)"
                  IL_0076:  ret
                }
                """);
        }
 
        [Fact]
        public void TestWithPattern_RefStructCurrent_Iterator()
        {
            var source = """
                using System;
                using System.Collections.Generic;
                public class C
                {
                    public static void Main()
                    {
                        foreach (var s in M())
                        {
                            Console.Write($"M:{s} ");
                        }
                        Console.Write("MainDone");
                    }
                    public static IEnumerable<string> M()
                    {
                        foreach (var s in new C())
                        {
                            yield return s.ToString();
                        }
                        yield return "Done";
                    }
                    public Enumerator GetEnumerator() => new Enumerator();
                    public sealed class Enumerator
                    {
                        int i = 0;
                        public S Current => new S(i);
                        public bool MoveNext()
                        {
                            i++;
                            return i < 3;
                        }
                    }
                }
                public ref struct S
                {
                    int i;
                    public S(int i)
                    {
                        this.i = i;
                    }
                    public override string ToString() => i.ToString();
                }
                """;
 
            var expectedOutput = "M:1 M:2 M:Done MainDone";
 
            CompileAndVerify(source, parseOptions: TestOptions.Regular12, expectedOutput: expectedOutput, verify: Verification.FailsILVerify).VerifyDiagnostics();
            CompileAndVerify(source, parseOptions: TestOptions.Regular13, expectedOutput: expectedOutput, verify: Verification.FailsILVerify).VerifyDiagnostics();
            CompileAndVerify(source, expectedOutput: expectedOutput, verify: Verification.FailsILVerify).VerifyDiagnostics();
        }
 
        [Fact]
        public void TestWithPattern_RefReturningCurrent_Async()
        {
            string source = @"
using static System.Console;
using System.Threading.Tasks;
public class C
{
    public static async System.Threading.Tasks.Task Main()
    {
        await foreach (var s in new C())
        {
            Write($""{s.ToString()} "");
        }
        Write(""Done"");
    }
    public Enumerator GetAsyncEnumerator() => new Enumerator();
    public sealed class Enumerator
    {
        int i = 0;
        S current;
        public ref S Current
        {
            get
            {
                current = new S(i);
                return ref current;
            }
        }
        public async Task<bool> MoveNextAsync()
        {
            i++;
            return await Task.FromResult(i < 4);
        }
    }
}
public struct S
{
    int i;
    public S(int i)
    {
        this.i = i;
    }
    public override string ToString()
        => i.ToString();
}
";
            var comp = CreateCompilationWithTasksExtensions(new[] { source, s_IAsyncEnumerable }, options: TestOptions.DebugExe);
            comp.VerifyDiagnostics();
            CompileAndVerify(comp, expectedOutput: "1 2 3 Done", verify: Verification.Fails);
 
            var runtimeAsyncComp = CreateRuntimeAsyncCompilation(source);
            var verifier = CompileAndVerify(runtimeAsyncComp, expectedOutput: CodeGenAsyncTests.ExpectedOutput("1 2 3 Done", isRuntimeAsync: true), verify: Verification.Fails);
            verifier.VerifyIL("C.Main()", """
                {
                  // Code size       77 (0x4d)
                  .maxstack  2
                  .locals init (C.Enumerator V_0,
                                S V_1) //s
                  IL_0000:  newobj     "C..ctor()"
                  IL_0005:  call       "C.Enumerator C.GetAsyncEnumerator()"
                  IL_000a:  stloc.0
                  IL_000b:  br.s       IL_0035
                  IL_000d:  ldloc.0
                  IL_000e:  callvirt   "ref S C.Enumerator.Current.get"
                  IL_0013:  ldobj      "S"
                  IL_0018:  stloc.1
                  IL_0019:  ldloca.s   V_1
                  IL_001b:  constrained. "S"
                  IL_0021:  callvirt   "string object.ToString()"
                  IL_0026:  ldstr      " "
                  IL_002b:  call       "string string.Concat(string, string)"
                  IL_0030:  call       "void System.Console.Write(string)"
                  IL_0035:  ldloc.0
                  IL_0036:  callvirt   "System.Threading.Tasks.Task<bool> C.Enumerator.MoveNextAsync()"
                  IL_003b:  call       "bool System.Runtime.CompilerServices.AsyncHelpers.Await<bool>(System.Threading.Tasks.Task<bool>)"
                  IL_0040:  brtrue.s   IL_000d
                  IL_0042:  ldstr      "Done"
                  IL_0047:  call       "void System.Console.Write(string)"
                  IL_004c:  ret
                }
                """);
        }
 
        [Fact]
        public void TestWithPattern_RefReturningCurrent_Async_RefVariable()
        {
            string source = """
                using System;
                using System.Threading.Tasks;
                public class C
                {
                    public static async Task Main()
                    {
                        await foreach (ref var s in new C())
                        {
                            Console.Write($"{s} ");
                            s.F++;
                        }
                        Console.Write("Done");
                    }
                    public Enumerator GetAsyncEnumerator() => new Enumerator();
                    public sealed class Enumerator
                    {
                        S _current;
                        public ref S Current => ref _current;
                        public async Task<bool> MoveNextAsync()
                        {
                            Current = new S(Current.F + 1);
                            await Task.Yield();
                            return Current.F < 4;
                        }
                    }
                }
                public struct S
                {
                    public int F;
                    public S(int i)
                    {
                        this.F = i;
                    }
                    public override string ToString() => F.ToString();
                }
                """ + s_IAsyncEnumerable;
 
            CreateCompilationWithTasksExtensions(source, parseOptions: TestOptions.Regular12).VerifyDiagnostics(
                // (7,32): error CS9202: Feature 'ref and unsafe in async and iterator methods' is not available in C# 12.0. Please use language version 13.0 or greater.
                //         await foreach (ref var s in new C())
                Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion12, "s").WithArguments("ref and unsafe in async and iterator methods", "13.0").WithLocation(7, 32));
 
            var expectedOutput = "1 3 Done";
 
            var comp = CreateCompilationWithTasksExtensions(source, parseOptions: TestOptions.Regular13, options: TestOptions.ReleaseExe);
            CompileAndVerify(comp, expectedOutput: expectedOutput).VerifyDiagnostics();
 
            comp = CreateCompilationWithTasksExtensions(source, options: TestOptions.ReleaseExe);
            CompileAndVerify(comp, expectedOutput: expectedOutput).VerifyDiagnostics();
 
            var runtimeAsyncComp = CreateRuntimeAsyncCompilation(source);
            var verifier = CompileAndVerify(runtimeAsyncComp, expectedOutput: CodeGenAsyncTests.ExpectedOutput(expectedOutput, isRuntimeAsync: true), verify: Verification.Fails with
            {
                ILVerifyMessage = """
                    [Main]: Return value missing on the stack. { Offset = 0x64 }
                    [MoveNextAsync]: Unexpected type on the stack. { Offset = 0x4f, Found = Int32, Expected = ref '[System.Runtime]System.Threading.Tasks.Task`1<bool>' }
                    """
            });
            verifier.VerifyIL("C.Main()", """
                {
                  // Code size      101 (0x65)
                  .maxstack  3
                  .locals init (C.Enumerator V_0,
                                S& V_1, //s
                                System.Runtime.CompilerServices.DefaultInterpolatedStringHandler V_2)
                  IL_0000:  newobj     "C..ctor()"
                  IL_0005:  call       "C.Enumerator C.GetAsyncEnumerator()"
                  IL_000a:  stloc.0
                  IL_000b:  br.s       IL_004d
                  IL_000d:  ldloc.0
                  IL_000e:  callvirt   "ref S C.Enumerator.Current.get"
                  IL_0013:  stloc.1
                  IL_0014:  ldloca.s   V_2
                  IL_0016:  ldc.i4.1
                  IL_0017:  ldc.i4.1
                  IL_0018:  call       "System.Runtime.CompilerServices.DefaultInterpolatedStringHandler..ctor(int, int)"
                  IL_001d:  ldloca.s   V_2
                  IL_001f:  ldloc.1
                  IL_0020:  ldobj      "S"
                  IL_0025:  call       "void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted<S>(S)"
                  IL_002a:  ldloca.s   V_2
                  IL_002c:  ldstr      " "
                  IL_0031:  call       "void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendLiteral(string)"
                  IL_0036:  ldloca.s   V_2
                  IL_0038:  call       "string System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.ToStringAndClear()"
                  IL_003d:  call       "void System.Console.Write(string)"
                  IL_0042:  ldloc.1
                  IL_0043:  ldflda     "int S.F"
                  IL_0048:  dup
                  IL_0049:  ldind.i4
                  IL_004a:  ldc.i4.1
                  IL_004b:  add
                  IL_004c:  stind.i4
                  IL_004d:  ldloc.0
                  IL_004e:  callvirt   "System.Threading.Tasks.Task<bool> C.Enumerator.MoveNextAsync()"
                  IL_0053:  call       "bool System.Runtime.CompilerServices.AsyncHelpers.Await<bool>(System.Threading.Tasks.Task<bool>)"
                  IL_0058:  brtrue.s   IL_000d
                  IL_005a:  ldstr      "Done"
                  IL_005f:  call       "void System.Console.Write(string)"
                  IL_0064:  ret
                }
                """);
        }
 
        [Fact]
        public void TestWithPattern_RefReturningCurrent_AsyncIterator_RefVariable_01()
        {
            string source = """
                using System;
                using System.Collections.Generic;
                using System.Threading.Tasks;
                public class C
                {
                    public static async Task Main()
                    {
                        await foreach (var s in M())
                        {
                            Console.Write($"M:{s} ");
                        }
                        Console.Write("MainDone");
                    }
                    public static async IAsyncEnumerable<string> M()
                    {
                        await foreach (ref var s in new C())
                        {
                            s.F++;
                            yield return s.ToString();
                        }
                        yield return "Done";
                    }
                    public Enumerator GetAsyncEnumerator() => new Enumerator();
                    public sealed class Enumerator
                    {
                        S _current;
                        public ref S Current => ref _current;
                        public async Task<bool> MoveNextAsync()
                        {
                            Current = new S(Current.F + 1);
                            await Task.Yield();
                            return Current.F < 4;
                        }
                    }
                }
                public struct S
                {
                    public int F;
                    public S(int i)
                    {
                        this.F = i;
                    }
                    public override string ToString() => F.ToString();
                }
                """;
 
            CSharpTestSource sources = [source, AsyncStreamsTypes];
            CreateCompilationWithTasksExtensions(sources, parseOptions: TestOptions.Regular12).VerifyDiagnostics(
                // (16,32): error CS9202: Feature 'ref and unsafe in async and iterator methods' is not available in C# 12.0. Please use language version 13.0 or greater.
                //         await foreach (ref var s in new C())
                Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion12, "s").WithArguments("ref and unsafe in async and iterator methods", "13.0").WithLocation(16, 32));
 
            var expectedOutput = "M:2 M:4 M:Done MainDone";
 
            var comp = CreateCompilationWithTasksExtensions(sources, parseOptions: TestOptions.Regular13, options: TestOptions.ReleaseExe);
            CompileAndVerify(comp, expectedOutput: expectedOutput).VerifyDiagnostics();
 
            comp = CreateCompilationWithTasksExtensions(sources, options: TestOptions.ReleaseExe);
            CompileAndVerify(comp, expectedOutput: expectedOutput).VerifyDiagnostics();
 
            var runtimeAsyncComp = CreateRuntimeAsyncCompilation(source);
            var verifier = CompileAndVerify(runtimeAsyncComp, expectedOutput: CodeGenAsyncTests.ExpectedOutput(expectedOutput, isRuntimeAsync: true), verify: Verification.Fails with
            {
                ILVerifyMessage = """
                    [Main]: Return value missing on the stack. { Offset = 0x76 }
                    [MoveNextAsync]: Unexpected type on the stack. { Offset = 0x4f, Found = Int32, Expected = ref '[System.Runtime]System.Threading.Tasks.Task`1<bool>' }
                    """
            });
            verifier.VerifyIL("C.Main()", """
                {
                  // Code size      119 (0x77)
                  .maxstack  3
                  .locals init (System.Collections.Generic.IAsyncEnumerator<string> V_0,
                                System.Threading.CancellationToken V_1,
                                object V_2,
                                string V_3) //s
                  IL_0000:  call       "System.Collections.Generic.IAsyncEnumerable<string> C.M()"
                  IL_0005:  ldloca.s   V_1
                  IL_0007:  initobj    "System.Threading.CancellationToken"
                  IL_000d:  ldloc.1
                  IL_000e:  callvirt   "System.Collections.Generic.IAsyncEnumerator<string> System.Collections.Generic.IAsyncEnumerable<string>.GetAsyncEnumerator(System.Threading.CancellationToken)"
                  IL_0013:  stloc.0
                  IL_0014:  ldnull
                  IL_0015:  stloc.2
                  .try
                  {
                    IL_0016:  br.s       IL_0034
                    IL_0018:  ldloc.0
                    IL_0019:  callvirt   "string System.Collections.Generic.IAsyncEnumerator<string>.Current.get"
                    IL_001e:  stloc.3
                    IL_001f:  ldstr      "M:"
                    IL_0024:  ldloc.3
                    IL_0025:  ldstr      " "
                    IL_002a:  call       "string string.Concat(string, string, string)"
                    IL_002f:  call       "void System.Console.Write(string)"
                    IL_0034:  ldloc.0
                    IL_0035:  callvirt   "System.Threading.Tasks.ValueTask<bool> System.Collections.Generic.IAsyncEnumerator<string>.MoveNextAsync()"
                    IL_003a:  call       "bool System.Runtime.CompilerServices.AsyncHelpers.Await<bool>(System.Threading.Tasks.ValueTask<bool>)"
                    IL_003f:  brtrue.s   IL_0018
                    IL_0041:  leave.s    IL_0046
                  }
                  catch object
                  {
                    IL_0043:  stloc.2
                    IL_0044:  leave.s    IL_0046
                  }
                  IL_0046:  ldloc.0
                  IL_0047:  brfalse.s  IL_0054
                  IL_0049:  ldloc.0
                  IL_004a:  callvirt   "System.Threading.Tasks.ValueTask System.IAsyncDisposable.DisposeAsync()"
                  IL_004f:  call       "void System.Runtime.CompilerServices.AsyncHelpers.Await(System.Threading.Tasks.ValueTask)"
                  IL_0054:  ldloc.2
                  IL_0055:  brfalse.s  IL_006c
                  IL_0057:  ldloc.2
                  IL_0058:  isinst     "System.Exception"
                  IL_005d:  dup
                  IL_005e:  brtrue.s   IL_0062
                  IL_0060:  ldloc.2
                  IL_0061:  throw
                  IL_0062:  call       "System.Runtime.ExceptionServices.ExceptionDispatchInfo System.Runtime.ExceptionServices.ExceptionDispatchInfo.Capture(System.Exception)"
                  IL_0067:  callvirt   "void System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()"
                  IL_006c:  ldstr      "MainDone"
                  IL_0071:  call       "void System.Console.Write(string)"
                  IL_0076:  ret
                }
                """);
        }
 
        [Fact]
        public void TestWithPattern_RefReturningCurrent_AsyncIterator_RefVariable_02()
        {
            string source = """
                using System.Collections.Generic;
                using System.Threading.Tasks;
                public class C
                {
                    public static async IAsyncEnumerable<string> M()
                    {
                        await foreach (ref var s in new C())
                        {
                            yield return s.ToString();
                            s.F++;
                        }
                        yield return "Done";
                    }
                    public Enumerator GetAsyncEnumerator() => new Enumerator();
                    public sealed class Enumerator
                    {
                        public ref S Current => throw null;
                        public Task<bool> MoveNextAsync() => throw null;
                    }
                }
                public struct S
                {
                    public int F;
                }
                """ + AsyncStreamsTypes;
 
            CreateCompilationWithTasksExtensions(source, parseOptions: TestOptions.Regular12).VerifyDiagnostics(
                // (7,32): error CS9202: Feature 'ref and unsafe in async and iterator methods' is not available in C# 12.0. Please use language version 13.0 or greater.
                //         await foreach (ref var s in new C())
                Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion12, "s").WithArguments("ref and unsafe in async and iterator methods", "13.0").WithLocation(7, 32));
 
            var expectedDiagnostics = new[]
            {
                // (10,13): error CS9217: A 'ref' local cannot be preserved across 'await' or 'yield' boundary.
                //             s.F++;
                Diagnostic(ErrorCode.ERR_RefLocalAcrossAwait, "s.F").WithLocation(10, 13)
            };
 
            CreateCompilationWithTasksExtensions(source, parseOptions: TestOptions.Regular13).VerifyEmitDiagnostics(expectedDiagnostics);
            CreateCompilationWithTasksExtensions(source).VerifyEmitDiagnostics(expectedDiagnostics);
        }
 
        [Fact]
        public void TestWithPattern_RefReturningCurrent_Iterator_RefVariable_01()
        {
            string source = """
                using System;
                using System.Collections.Generic;
                public class C
                {
                    public static void Main()
                    {
                        foreach (var s in M())
                        {
                            Console.Write($"M:{s} ");
                        }
                        Console.Write("MainDone");
                    }
                    public static IEnumerable<string> M()
                    {
                        foreach (ref var s in new C())
                        {
                            s.F++;
                            yield return s.ToString();
                        }
                        yield return "Done";
                    }
                    public Enumerator GetEnumerator() => new Enumerator();
                    public sealed class Enumerator
                    {
                        S _current;
                        public ref S Current => ref _current;
                        public bool MoveNext()
                        {
                            Current = new S(Current.F + 1);
                            return Current.F < 4;
                        }
                    }
                }
                public struct S
                {
                    public int F;
                    public S(int i)
                    {
                        this.F = i;
                    }
                    public override string ToString() => F.ToString();
                }
                """;
 
            CreateCompilation(source, parseOptions: TestOptions.Regular12).VerifyDiagnostics(
                // (15,26): error CS9202: Feature 'ref and unsafe in async and iterator methods' is not available in C# 12.0. Please use language version 13.0 or greater.
                //         foreach (ref var s in new C())
                Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion12, "s").WithArguments("ref and unsafe in async and iterator methods", "13.0").WithLocation(15, 26));
 
            var expectedOutput = "M:2 M:4 M:Done MainDone";
 
            CompileAndVerify(source, parseOptions: TestOptions.Regular13, expectedOutput: expectedOutput).VerifyDiagnostics();
            CompileAndVerify(source, expectedOutput: expectedOutput).VerifyDiagnostics();
        }
 
        [Fact]
        public void TestWithPattern_RefReturningCurrent_Iterator_RefVariable_02()
        {
            string source = """
                using System.Collections.Generic;
                public class C
                {
                    public static IEnumerable<string> M()
                    {
                        foreach (ref var s in new C())
                        {
                            yield return s.ToString();
                            s.F++;
                        }
                        yield return "Done";
                    }
                    public Enumerator GetEnumerator() => new Enumerator();
                    public sealed class Enumerator
                    {
                        public ref S Current => throw null;
                        public bool MoveNext() => throw null;
                    }
                }
                public struct S
                {
                    public int F;
                }
                """;
 
            CreateCompilation(source, parseOptions: TestOptions.Regular12).VerifyDiagnostics(
                // (6,26): error CS9202: Feature 'ref and unsafe in async and iterator methods' is not available in C# 12.0. Please use language version 13.0 or greater.
                //         foreach (ref var s in new C())
                Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion12, "s").WithArguments("ref and unsafe in async and iterator methods", "13.0").WithLocation(6, 26));
 
            var expectedDiagnostics = new[]
            {
                // (9,13): error CS9217: A 'ref' local cannot be preserved across 'await' or 'yield' boundary.
                //             s.F++;
                Diagnostic(ErrorCode.ERR_RefLocalAcrossAwait, "s.F").WithLocation(9, 13)
            };
 
            CreateCompilation(source, parseOptions: TestOptions.Regular13).VerifyEmitDiagnostics(expectedDiagnostics);
            CreateCompilation(source).VerifyEmitDiagnostics(expectedDiagnostics);
        }
 
        [Fact]
        public void TestWithPattern_IterationVariableIsReadOnly()
        {
            string source = @"
class C
{
    async System.Threading.Tasks.Task M()
    {
        await foreach (var i in new C())
        {
            i = 1;
        }
    }
    public Enumerator GetAsyncEnumerator(System.Threading.CancellationToken token = default)
        => throw null;
    public sealed class Enumerator
    {
        public System.Threading.Tasks.Task<bool> MoveNextAsync()
            => throw null;
        public int Current { get => throw null; }
    }
}";
            var comp = CreateCompilationWithTasksExtensions(new[] { source, s_IAsyncEnumerable });
            comp.VerifyDiagnostics(
                // (8,13): error CS1656: Cannot assign to 'i' because it is a 'foreach iteration variable'
                //             i = 1;
                Diagnostic(ErrorCode.ERR_AssgReadonlyLocalCause, "i").WithArguments("i", "foreach iteration variable").WithLocation(8, 13)
                );
        }
 
        [Fact]
        public void TestWithPattern_WithStruct_MoveNextAsyncReturnsTask()
        {
            string source = @"
using static System.Console;
using System.Threading.Tasks;
class C
{
    static async Task Main()
    {
        await foreach (var i in new C())
        {
            Write($""Got({i}) "");
        }
        Write($""Done"");
    }
    public AsyncEnumerator GetAsyncEnumerator()
    {
        return new AsyncEnumerator(0);
    }
    public struct AsyncEnumerator
    {
        int i;
        internal AsyncEnumerator(int start) { i = start; }
        public int Current
        {
            get
            {
                Write($""Current({i}) "");
                i++;
                return i;
            }
        }
        public async Task<bool> MoveNextAsync()
        {
            Write($""NextAsync({i}) "");
            bool more = await Task.FromResult(i < 4);
            i = i + 100; // Note: side-effects of async methods in structs are lost
            return more;
        }
        public async ValueTask DisposeAsync()
        {
            Write($""DisposeAsync "");
            await Task.Yield();
        }
    }
}";
            var comp = CreateCompilationWithTasksExtensions(source + s_IAsyncEnumerable, options: TestOptions.DebugExe);
            comp.VerifyDiagnostics();
            var expectedOutput = "NextAsync(0) Current(0) Got(1) NextAsync(1) Current(1) Got(2) NextAsync(2) Current(2) Got(3) NextAsync(3) Current(3) Got(4) NextAsync(4) DisposeAsync Done";
            CompileAndVerify(comp, expectedOutput: expectedOutput);
 
            var runtimeAsyncComp = CreateRuntimeAsyncCompilation(source);
            runtimeAsyncComp.VerifyEmitDiagnostics(
                // (31,33): error CS9328: Method 'C.AsyncEnumerator.MoveNextAsync()' uses a feature that is not supported by runtime async currently. Opt the method out of runtime async by attributing it with 'System.Runtime.CompilerServices.RuntimeAsyncMethodGenerationAttribute(false)'.
                //         public async Task<bool> MoveNextAsync()
                Diagnostic(ErrorCode.ERR_UnsupportedFeatureInRuntimeAsync, "MoveNextAsync").WithArguments("C.AsyncEnumerator.MoveNextAsync()").WithLocation(31, 33)
            );
            // https://github.com/dotnet/roslyn/issues/79763
            // var verifier = CompileAndVerify(runtimeAsyncComp, expectedOutput: CodeGenAsyncTests.ExpectedOutput(expectedOutput, isRuntimeAsync: true), verify: Verification.Fails with
            // {
            //     ILVerifyMessage = """
            //         [Main]: Return value missing on the stack. { Offset = 0x8c }
            //         [MoveNextAsync]: Unexpected type on the stack. { Offset = 0x5d, Found = Int32, Expected = ref '[System.Runtime]System.Threading.Tasks.Task`1<bool>' }
            //         [DisposeAsync]: Return value missing on the stack. { Offset = 0x2e }
            //         """
            // });
            // verifier.VerifyIL("C.Main()", """
            //     {
            //       // Code size      141 (0x8d)
            //       .maxstack  2
            //       .locals init (C.AsyncEnumerator V_0,
            //                     object V_1,
            //                     int V_2, //i
            //                     System.Runtime.CompilerServices.DefaultInterpolatedStringHandler V_3)
            //       IL_0000:  newobj     "C..ctor()"
            //       IL_0005:  call       "C.AsyncEnumerator C.GetAsyncEnumerator()"
            //       IL_000a:  stloc.0
            //       IL_000b:  ldnull
            //       IL_000c:  stloc.1
            //       .try
            //       {
            //         IL_000d:  br.s       IL_004b
            //         IL_000f:  ldloca.s   V_0
            //         IL_0011:  call       "int C.AsyncEnumerator.Current.get"
            //         IL_0016:  stloc.2
            //         IL_0017:  ldc.i4.6
            //         IL_0018:  ldc.i4.1
            //         IL_0019:  newobj     "System.Runtime.CompilerServices.DefaultInterpolatedStringHandler..ctor(int, int)"
            //         IL_001e:  stloc.3
            //         IL_001f:  ldloca.s   V_3
            //         IL_0021:  ldstr      "Got("
            //         IL_0026:  call       "void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendLiteral(string)"
            //         IL_002b:  ldloca.s   V_3
            //         IL_002d:  ldloc.2
            //         IL_002e:  call       "void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted<int>(int)"
            //         IL_0033:  ldloca.s   V_3
            //         IL_0035:  ldstr      ") "
            //         IL_003a:  call       "void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendLiteral(string)"
            //         IL_003f:  ldloca.s   V_3
            //         IL_0041:  call       "string System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.ToStringAndClear()"
            //         IL_0046:  call       "void System.Console.Write(string)"
            //         IL_004b:  ldloca.s   V_0
            //         IL_004d:  call       "System.Threading.Tasks.Task<bool> C.AsyncEnumerator.MoveNextAsync()"
            //         IL_0052:  call       "bool System.Runtime.CompilerServices.AsyncHelpers.Await<bool>(System.Threading.Tasks.Task<bool>)"
            //         IL_0057:  brtrue.s   IL_000f
            //         IL_0059:  leave.s    IL_005e
            //       }
            //       catch object
            //       {
            //         IL_005b:  stloc.1
            //         IL_005c:  leave.s    IL_005e
            //       }
            //       IL_005e:  ldloca.s   V_0
            //       IL_0060:  call       "System.Threading.Tasks.ValueTask C.AsyncEnumerator.DisposeAsync()"
            //       IL_0065:  call       "void System.Runtime.CompilerServices.AsyncHelpers.Await(System.Threading.Tasks.ValueTask)"
            //       IL_006a:  ldloc.1
            //       IL_006b:  brfalse.s  IL_0082
            //       IL_006d:  ldloc.1
            //       IL_006e:  isinst     "System.Exception"
            //       IL_0073:  dup
            //       IL_0074:  brtrue.s   IL_0078
            //       IL_0076:  ldloc.1
            //       IL_0077:  throw
            //       IL_0078:  call       "System.Runtime.ExceptionServices.ExceptionDispatchInfo System.Runtime.ExceptionServices.ExceptionDispatchInfo.Capture(System.Exception)"
            //       IL_007d:  callvirt   "void System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()"
            //       IL_0082:  ldstr      "Done"
            //       IL_0087:  call       "void System.Console.Write(string)"
            //       IL_008c:  ret
            //     }
            //     """);
        }
 
        [Fact]
        public void TestWithPattern_MoveNextAsyncReturnsValueTask()
        {
            string source = @"
using static System.Console;
using System.Threading.Tasks;
class C
{
    static async Task Main()
    {
        await foreach (var i in new C())
        {
            Write($""Got({i}) "");
        }
        Write($""Done"");
    }
    public AsyncEnumerator GetAsyncEnumerator(System.Threading.CancellationToken token = default)
    {
        return new AsyncEnumerator(0);
    }
    public class AsyncEnumerator : System.IAsyncDisposable
    {
        int i;
        internal AsyncEnumerator(int start) { i = start; }
        public int Current
        {
            get
            {
                Write($""Current({i}) "");
                return i;
            }
        }
        public async ValueTask<bool> MoveNextAsync()
        {
            Write($""NextAsync({i}) "");
            i++;
            return await Task.FromResult(i < 4);
        }
        public async ValueTask DisposeAsync()
        {
            Write($""Dispose({i}) "");
            await Task.Yield();
        }
    }
}";
            var comp = CreateCompilationWithTasksExtensions(source + s_IAsyncEnumerable, options: TestOptions.DebugExe);
            comp.VerifyDiagnostics();
            var expectedOutput = "NextAsync(0) Current(1) Got(1) NextAsync(1) Current(2) Got(2) NextAsync(2) Current(3) Got(3) NextAsync(3) Dispose(4) Done";
            CompileAndVerify(comp, expectedOutput: expectedOutput);
 
            var tree = comp.SyntaxTrees.Single();
            var model = (SyntaxTreeSemanticModel)comp.GetSemanticModel(tree, ignoreAccessibility: false);
            var foreachSyntax = tree.GetRoot().DescendantNodes().OfType<ForEachStatementSyntax>().Single();
            var info = model.GetForEachStatementInfo(foreachSyntax);
 
            Assert.Equal("System.Threading.Tasks.ValueTask<System.Boolean> C.AsyncEnumerator.MoveNextAsync()", info.MoveNextMethod.ToTestDisplayString());
            Assert.Equal("System.Int32", info.ElementType.ToTestDisplayString());
 
            var memberModel = model.GetMemberModel(foreachSyntax);
            var boundNode = (BoundForEachStatement)memberModel.GetUpperBoundNode(foreachSyntax);
            ForEachEnumeratorInfo internalInfo = boundNode.EnumeratorInfoOpt;
            Assert.True(internalInfo.NeedsDisposal);
 
            var runtimeAsyncComp = CreateRuntimeAsyncCompilation(source);
            var verifier = CompileAndVerify(runtimeAsyncComp, expectedOutput: CodeGenAsyncTests.ExpectedOutput(expectedOutput, isRuntimeAsync: true), verify: Verification.Fails with
            {
                ILVerifyMessage = """
                    [Main]: Return value missing on the stack. { Offset = 0x96 }
                    [MoveNextAsync]: Unexpected type on the stack. { Offset = 0x5c, Found = Int32, Expected = value '[System.Runtime]System.Threading.Tasks.ValueTask`1<bool>' }
                    [DisposeAsync]: Return value missing on the stack. { Offset = 0x5f }
                    """
            });
            verifier.VerifyIL("C.Main()", """
                {
                  // Code size      151 (0x97)
                  .maxstack  2
                  .locals init (C.AsyncEnumerator V_0,
                                System.Threading.CancellationToken V_1,
                                object V_2,
                                int V_3, //i
                                System.Runtime.CompilerServices.DefaultInterpolatedStringHandler V_4)
                  IL_0000:  newobj     "C..ctor()"
                  IL_0005:  ldloca.s   V_1
                  IL_0007:  initobj    "System.Threading.CancellationToken"
                  IL_000d:  ldloc.1
                  IL_000e:  call       "C.AsyncEnumerator C.GetAsyncEnumerator(System.Threading.CancellationToken)"
                  IL_0013:  stloc.0
                  IL_0014:  ldnull
                  IL_0015:  stloc.2
                  .try
                  {
                    IL_0016:  br.s       IL_0054
                    IL_0018:  ldloc.0
                    IL_0019:  callvirt   "int C.AsyncEnumerator.Current.get"
                    IL_001e:  stloc.3
                    IL_001f:  ldc.i4.6
                    IL_0020:  ldc.i4.1
                    IL_0021:  newobj     "System.Runtime.CompilerServices.DefaultInterpolatedStringHandler..ctor(int, int)"
                    IL_0026:  stloc.s    V_4
                    IL_0028:  ldloca.s   V_4
                    IL_002a:  ldstr      "Got("
                    IL_002f:  call       "void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendLiteral(string)"
                    IL_0034:  ldloca.s   V_4
                    IL_0036:  ldloc.3
                    IL_0037:  call       "void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted<int>(int)"
                    IL_003c:  ldloca.s   V_4
                    IL_003e:  ldstr      ") "
                    IL_0043:  call       "void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendLiteral(string)"
                    IL_0048:  ldloca.s   V_4
                    IL_004a:  call       "string System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.ToStringAndClear()"
                    IL_004f:  call       "void System.Console.Write(string)"
                    IL_0054:  ldloc.0
                    IL_0055:  callvirt   "System.Threading.Tasks.ValueTask<bool> C.AsyncEnumerator.MoveNextAsync()"
                    IL_005a:  call       "bool System.Runtime.CompilerServices.AsyncHelpers.Await<bool>(System.Threading.Tasks.ValueTask<bool>)"
                    IL_005f:  brtrue.s   IL_0018
                    IL_0061:  leave.s    IL_0066
                  }
                  catch object
                  {
                    IL_0063:  stloc.2
                    IL_0064:  leave.s    IL_0066
                  }
                  IL_0066:  ldloc.0
                  IL_0067:  brfalse.s  IL_0074
                  IL_0069:  ldloc.0
                  IL_006a:  callvirt   "System.Threading.Tasks.ValueTask C.AsyncEnumerator.DisposeAsync()"
                  IL_006f:  call       "void System.Runtime.CompilerServices.AsyncHelpers.Await(System.Threading.Tasks.ValueTask)"
                  IL_0074:  ldloc.2
                  IL_0075:  brfalse.s  IL_008c
                  IL_0077:  ldloc.2
                  IL_0078:  isinst     "System.Exception"
                  IL_007d:  dup
                  IL_007e:  brtrue.s   IL_0082
                  IL_0080:  ldloc.2
                  IL_0081:  throw
                  IL_0082:  call       "System.Runtime.ExceptionServices.ExceptionDispatchInfo System.Runtime.ExceptionServices.ExceptionDispatchInfo.Capture(System.Exception)"
                  IL_0087:  callvirt   "void System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()"
                  IL_008c:  ldstr      "Done"
                  IL_0091:  call       "void System.Console.Write(string)"
                  IL_0096:  ret
                }
                """);
        }
 
        [Fact]
        [WorkItem(31609, "https://github.com/dotnet/roslyn/issues/31609")]
        public void TestWithPattern_MoveNextAsyncReturnsAwaitable()
        {
            string source = @"
using static System.Console;
using System.Threading.Tasks;
class C
{
    static async Task Main()
    {
        await foreach (var i in new C())
        {
            Write($""Item({i}) "");
            break;
        }
        Write($""Done"");
    }
    public AsyncEnumerator GetAsyncEnumerator()
    {
        return new AsyncEnumerator();
    }
    public class AsyncEnumerator : System.IAsyncDisposable
    {
        public int Current => 1;
        public Awaitable MoveNextAsync()
        {
            return new Awaitable();
        }
        public async ValueTask DisposeAsync()
        {
            Write(""Dispose "");
            await Task.Yield();
        }
    }
 
    public class Awaitable
    {
        public Awaiter GetAwaiter() { return new Awaiter(); }
    }
    public class Awaiter : System.Runtime.CompilerServices.INotifyCompletion
    {
        public bool IsCompleted { get { return true; } }
        public bool GetResult() { return true; }
        public void OnCompleted(System.Action continuation) { }
    }
}";
            var comp = CreateCompilationWithTasksExtensions(new[] { source, s_IAsyncEnumerable }, options: TestOptions.DebugExe);
            comp.VerifyDiagnostics();
            CompileAndVerify(comp, expectedOutput: "Item(1) Dispose Done");
 
            var tree = comp.SyntaxTrees.First();
            var model = (SyntaxTreeSemanticModel)comp.GetSemanticModel(tree, ignoreAccessibility: false);
            var foreachSyntax = tree.GetRoot().DescendantNodes().OfType<ForEachStatementSyntax>().Single();
            var info = model.GetForEachStatementInfo(foreachSyntax);
 
            Assert.Equal("C.Awaitable C.AsyncEnumerator.MoveNextAsync()", info.MoveNextMethod.ToTestDisplayString());
            Assert.Equal("System.Int32", info.ElementType.ToTestDisplayString());
 
            var runtimeAsyncComp = CreateRuntimeAsyncCompilation(source);
            var verifier = CompileAndVerify(runtimeAsyncComp, expectedOutput: CodeGenAsyncTests.ExpectedOutput("Item(1) Dispose Done", isRuntimeAsync: true), verify: Verification.Fails with
            {
                ILVerifyMessage = """
                    [Main]: Return value missing on the stack. { Offset = 0xa7 }
                    [DisposeAsync]: Return value missing on the stack. { Offset = 0x2e }
                    """
            });
            verifier.VerifyIL("C.Main()", """
                {
                  // Code size      168 (0xa8)
                  .maxstack  2
                  .locals init (C.AsyncEnumerator V_0,
                                object V_1,
                                int V_2, //i
                                System.Runtime.CompilerServices.DefaultInterpolatedStringHandler V_3,
                                C.Awaiter V_4)
                  IL_0000:  newobj     "C..ctor()"
                  IL_0005:  call       "C.AsyncEnumerator C.GetAsyncEnumerator()"
                  IL_000a:  stloc.0
                  IL_000b:  ldnull
                  IL_000c:  stloc.1
                  .try
                  {
                    IL_000d:  br.s       IL_004c
                    IL_000f:  ldloc.0
                    IL_0010:  callvirt   "int C.AsyncEnumerator.Current.get"
                    IL_0015:  stloc.2
                    IL_0016:  ldc.i4.7
                    IL_0017:  ldc.i4.1
                    IL_0018:  newobj     "System.Runtime.CompilerServices.DefaultInterpolatedStringHandler..ctor(int, int)"
                    IL_001d:  stloc.3
                    IL_001e:  ldloca.s   V_3
                    IL_0020:  ldstr      "Item("
                    IL_0025:  call       "void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendLiteral(string)"
                    IL_002a:  ldloca.s   V_3
                    IL_002c:  ldloc.2
                    IL_002d:  call       "void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted<int>(int)"
                    IL_0032:  ldloca.s   V_3
                    IL_0034:  ldstr      ") "
                    IL_0039:  call       "void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendLiteral(string)"
                    IL_003e:  ldloca.s   V_3
                    IL_0040:  call       "string System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.ToStringAndClear()"
                    IL_0045:  call       "void System.Console.Write(string)"
                    IL_004a:  br.s       IL_0072
                    IL_004c:  ldloc.0
                    IL_004d:  callvirt   "C.Awaitable C.AsyncEnumerator.MoveNextAsync()"
                    IL_0052:  callvirt   "C.Awaiter C.Awaitable.GetAwaiter()"
                    IL_0057:  stloc.s    V_4
                    IL_0059:  ldloc.s    V_4
                    IL_005b:  callvirt   "bool C.Awaiter.IsCompleted.get"
                    IL_0060:  brtrue.s   IL_0069
                    IL_0062:  ldloc.s    V_4
                    IL_0064:  call       "void System.Runtime.CompilerServices.AsyncHelpers.AwaitAwaiter<C.Awaiter>(C.Awaiter)"
                    IL_0069:  ldloc.s    V_4
                    IL_006b:  callvirt   "bool C.Awaiter.GetResult()"
                    IL_0070:  brtrue.s   IL_000f
                    IL_0072:  leave.s    IL_0077
                  }
                  catch object
                  {
                    IL_0074:  stloc.1
                    IL_0075:  leave.s    IL_0077
                  }
                  IL_0077:  ldloc.0
                  IL_0078:  brfalse.s  IL_0085
                  IL_007a:  ldloc.0
                  IL_007b:  callvirt   "System.Threading.Tasks.ValueTask C.AsyncEnumerator.DisposeAsync()"
                  IL_0080:  call       "void System.Runtime.CompilerServices.AsyncHelpers.Await(System.Threading.Tasks.ValueTask)"
                  IL_0085:  ldloc.1
                  IL_0086:  brfalse.s  IL_009d
                  IL_0088:  ldloc.1
                  IL_0089:  isinst     "System.Exception"
                  IL_008e:  dup
                  IL_008f:  brtrue.s   IL_0093
                  IL_0091:  ldloc.1
                  IL_0092:  throw
                  IL_0093:  call       "System.Runtime.ExceptionServices.ExceptionDispatchInfo System.Runtime.ExceptionServices.ExceptionDispatchInfo.Capture(System.Exception)"
                  IL_0098:  callvirt   "void System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()"
                  IL_009d:  ldstr      "Done"
                  IL_00a2:  call       "void System.Console.Write(string)"
                  IL_00a7:  ret
                }
                """);
        }
 
        [Fact]
        [WorkItem(31609, "https://github.com/dotnet/roslyn/issues/31609")]
        public void TestWithPattern_MoveNextAsyncReturnsAwaitable_WithoutGetAwaiter()
        {
            string source = @"
using System.Threading.Tasks;
class C
{
    static async Task Main()
    {
        await foreach (var i in new C())
        {
        }
    }
    public AsyncEnumerator GetAsyncEnumerator(System.Threading.CancellationToken token = default) => throw null;
    public class AsyncEnumerator : System.IAsyncDisposable
    {
        public int Current => 1;
        public Awaitable MoveNextAsync() => throw null;
        public ValueTask DisposeAsync() => throw null;
    }
    public class Awaitable
    {
    }
}";
            var comp = CreateCompilationWithTasksExtensions(new[] { source, s_IAsyncEnumerable }, options: TestOptions.DebugExe);
            comp.VerifyDiagnostics(
                // (7,33): error CS1061: 'C.Awaitable' does not contain a definition for 'GetAwaiter' and no accessible extension method 'GetAwaiter' accepting a first argument of type 'C.Awaitable' could be found (are you missing a using directive or an assembly reference?)
                //         await foreach (var i in new C())
                Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "new C()").WithArguments("C.Awaitable", "GetAwaiter").WithLocation(7, 33)
                );
            VerifyEmptyForEachStatementInfo(comp);
        }
 
        [Fact]
        [WorkItem(31609, "https://github.com/dotnet/roslyn/issues/31609")]
        public void TestWithPattern_MoveNextAsyncReturnsAwaitable_WithoutIsCompleted()
        {
            string source = @"
using System.Threading.Tasks;
class C
{
    static async Task Main()
    {
        await foreach (var i in new C())
        {
        }
    }
    public AsyncEnumerator GetAsyncEnumerator() => throw null;
    public class AsyncEnumerator : System.IAsyncDisposable
    {
        public int Current => 1;
        public Awaitable MoveNextAsync() => throw null;
        public ValueTask DisposeAsync() => throw null;
    }
    public class Awaitable
    {
        public Awaiter GetAwaiter() => throw null;
    }
    public class Awaiter : System.Runtime.CompilerServices.INotifyCompletion
    {
        public bool GetResult() { return true; }
        public void OnCompleted(System.Action continuation) { }
    }
}";
            var comp = CreateCompilationWithTasksExtensions(new[] { source, s_IAsyncEnumerable }, options: TestOptions.DebugExe);
            comp.VerifyDiagnostics(
                // (7,33): error CS0117: 'C.Awaiter' does not contain a definition for 'IsCompleted'
                //         await foreach (var i in new C())
                Diagnostic(ErrorCode.ERR_NoSuchMember, "new C()").WithArguments("C.Awaiter", "IsCompleted").WithLocation(7, 33)
                );
            VerifyEmptyForEachStatementInfo(comp);
        }
 
        private static void VerifyEmptyForEachStatementInfo(CSharpCompilation comp)
        {
            var tree = comp.SyntaxTrees.First();
            var model = (SyntaxTreeSemanticModel)comp.GetSemanticModel(tree, ignoreAccessibility: false);
            var foreachSyntax = tree.GetRoot().DescendantNodes().OfType<ForEachStatementSyntax>().Single();
            var info = model.GetForEachStatementInfo(foreachSyntax);
 
            Assert.Null(info.MoveNextMethod);
            Assert.Null(info.ElementType);
        }
 
        [Fact]
        [WorkItem(31609, "https://github.com/dotnet/roslyn/issues/31609")]
        public void TestWithPattern_MoveNextAsyncReturnsAwaitable_WithoutGetResult()
        {
            string source = @"
using System.Threading.Tasks;
class C
{
    static async Task Main()
    {
        await foreach (var i in new C())
        {
        }
    }
    public AsyncEnumerator GetAsyncEnumerator() => throw null;
    public class AsyncEnumerator : System.IAsyncDisposable
    {
        public int Current => 1;
        public Awaitable MoveNextAsync() => throw null;
        public ValueTask DisposeAsync() => throw null;
    }
    public class Awaitable
    {
        public Awaiter GetAwaiter() => throw null;
    }
    public class Awaiter : System.Runtime.CompilerServices.INotifyCompletion
    {
        public bool IsCompleted { get { return true; } }
        public void OnCompleted(System.Action continuation) { }
    }
}";
            var comp = CreateCompilationWithTasksExtensions(new[] { source, s_IAsyncEnumerable }, options: TestOptions.DebugExe);
            comp.VerifyDiagnostics(
                // (7,33): error CS1061: 'C.Awaiter' does not contain a definition for 'GetResult' and no accessible extension method 'GetResult' accepting a first argument of type 'C.Awaiter' could be found (are you missing a using directive or an assembly reference?)
                //         await foreach (var i in new C())
                Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "new C()").WithArguments("C.Awaiter", "GetResult").WithLocation(7, 33)
                );
            VerifyEmptyForEachStatementInfo(comp);
        }
 
        [Fact]
        [WorkItem(31609, "https://github.com/dotnet/roslyn/issues/31609")]
        public void TestWithPattern_MoveNextAsyncReturnsAwaitable_WithoutOnCompleted()
        {
            string source = @"
using System.Threading.Tasks;
class C
{
    static async Task Main()
    {
        await foreach (var i in new C())
        {
        }
    }
    public AsyncEnumerator GetAsyncEnumerator(System.Threading.CancellationToken token = default) => throw null;
    public class AsyncEnumerator : System.IAsyncDisposable
    {
        public int Current => 1;
        public Awaitable MoveNextAsync() => throw null;
        public ValueTask DisposeAsync() => throw null;
    }
 
    public class Awaitable
    {
        public Awaiter GetAwaiter() => throw null;
    }
    public class Awaiter
    {
        public bool IsCompleted { get { return true; } }
        public bool GetResult() { return true; }
    }
}";
            var comp = CreateCompilationWithTasksExtensions(new[] { source, s_IAsyncEnumerable }, options: TestOptions.DebugExe);
            comp.VerifyDiagnostics(
                // (7,33): error CS4027: 'C.Awaiter' does not implement 'INotifyCompletion'
                //         await foreach (var i in new C())
                Diagnostic(ErrorCode.ERR_DoesntImplementAwaitInterface, "new C()").WithArguments("C.Awaiter", "System.Runtime.CompilerServices.INotifyCompletion").WithLocation(7, 33)
                );
            VerifyEmptyForEachStatementInfo(comp);
        }
 
        [Fact]
        public void TestWithPattern_MoveNextAsyncReturnsBadType()
        {
            string source = @"
using System.Threading.Tasks;
class C
{
    static async Task Main()
    {
        await foreach (var i in new C())
        {
        }
    }
    public AsyncEnumerator GetAsyncEnumerator() => throw null;
    public class AsyncEnumerator
    {
        public int Current => throw null;
        public int MoveNextAsync() => throw null;
        public ValueTask DisposeAsync() => throw null;
    }
}";
            var comp = CreateCompilationWithTasksExtensions(new[] { source, s_IAsyncEnumerable });
            comp.VerifyDiagnostics(
                // (7,33): error CS1061: 'int' does not contain a definition for 'GetAwaiter' and no accessible extension method 'GetAwaiter' accepting a first argument of type 'int' could be found (are you missing a using directive or an assembly reference?)
                //         await foreach (var i in new C())
                Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "new C()").WithArguments("int", "GetAwaiter").WithLocation(7, 33)
                );
 
            var tree = comp.SyntaxTrees.First();
            var model = (SyntaxTreeSemanticModel)comp.GetSemanticModel(tree, ignoreAccessibility: false);
            var foreachSyntax = tree.GetRoot().DescendantNodes().OfType<ForEachStatementSyntax>().Single();
            var info = model.GetForEachStatementInfo(foreachSyntax);
            Assert.Null(info.MoveNextMethod);
            Assert.Null(info.ElementType);
        }
 
        [Fact]
        public void TestWithPattern_WithUnsealed()
        {
            string source = @"
using static System.Console;
using System.Threading.Tasks;
public class C
{
    public static async Task Main()
    {
        await foreach (var i in new C())
        {
            Write($""Got({i}) "");
        }
    }
    public Enumerator GetAsyncEnumerator()
    {
        return new Enumerator();
    }
    public class Enumerator
    {
        int i = 0;
        public int Current
        {
            get
            {
                Write($""Current({i}) "");
                return i;
            }
        }
        public async Task<bool> MoveNextAsync()
        {
            Write($""NextAsync({i}) "");
            i++;
            return await Task.FromResult(i < 4);
        }
        public async ValueTask DisposeAsync()
        {
            Write($""Disp"");
            await Task.Yield();
            Write($""ose({i}) "");
        }
    }
}";
            var comp = CreateCompilationWithTasksExtensions(source + s_IAsyncEnumerable, options: TestOptions.DebugExe);
            comp.VerifyDiagnostics();
 
            var tree = comp.SyntaxTrees.Single();
            var model = (SyntaxTreeSemanticModel)comp.GetSemanticModel(tree, ignoreAccessibility: false);
            var foreachSyntax = tree.GetRoot().DescendantNodes().OfType<ForEachStatementSyntax>().Single();
 
            var memberModel = model.GetMemberModel(foreachSyntax);
            BoundForEachStatement boundNode = (BoundForEachStatement)memberModel.GetUpperBoundNode(foreachSyntax);
            ForEachEnumeratorInfo internalInfo = boundNode.EnumeratorInfoOpt;
            Assert.True(internalInfo.NeedsDisposal);
 
            string expectedOutput = "NextAsync(0) Current(1) Got(1) NextAsync(1) Current(2) Got(2) NextAsync(2) Current(3) Got(3) NextAsync(3) Dispose(4)";
            CompileAndVerify(comp,
                expectedOutput: expectedOutput);
 
            var runtimeAsyncComp = CreateRuntimeAsyncCompilation(source);
            var verifier = CompileAndVerify(runtimeAsyncComp, expectedOutput: CodeGenAsyncTests.ExpectedOutput(expectedOutput, isRuntimeAsync: true), verify: Verification.Fails with
            {
                ILVerifyMessage = """
                    [Main]: Return value missing on the stack. { Offset = 0x82 }
                    [MoveNextAsync]: Unexpected type on the stack. { Offset = 0x5c, Found = Int32, Expected = ref '[System.Runtime]System.Threading.Tasks.Task`1<bool>' }
                    [DisposeAsync]: Return value missing on the stack. { Offset = 0x68 }
                    """
            });
            verifier.VerifyIL("C.Main()", """
                {
                  // Code size      131 (0x83)
                  .maxstack  2
                  .locals init (C.Enumerator V_0,
                                object V_1,
                                int V_2, //i
                                System.Runtime.CompilerServices.DefaultInterpolatedStringHandler V_3)
                  IL_0000:  newobj     "C..ctor()"
                  IL_0005:  call       "C.Enumerator C.GetAsyncEnumerator()"
                  IL_000a:  stloc.0
                  IL_000b:  ldnull
                  IL_000c:  stloc.1
                  .try
                  {
                    IL_000d:  br.s       IL_004a
                    IL_000f:  ldloc.0
                    IL_0010:  callvirt   "int C.Enumerator.Current.get"
                    IL_0015:  stloc.2
                    IL_0016:  ldc.i4.6
                    IL_0017:  ldc.i4.1
                    IL_0018:  newobj     "System.Runtime.CompilerServices.DefaultInterpolatedStringHandler..ctor(int, int)"
                    IL_001d:  stloc.3
                    IL_001e:  ldloca.s   V_3
                    IL_0020:  ldstr      "Got("
                    IL_0025:  call       "void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendLiteral(string)"
                    IL_002a:  ldloca.s   V_3
                    IL_002c:  ldloc.2
                    IL_002d:  call       "void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted<int>(int)"
                    IL_0032:  ldloca.s   V_3
                    IL_0034:  ldstr      ") "
                    IL_0039:  call       "void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendLiteral(string)"
                    IL_003e:  ldloca.s   V_3
                    IL_0040:  call       "string System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.ToStringAndClear()"
                    IL_0045:  call       "void System.Console.Write(string)"
                    IL_004a:  ldloc.0
                    IL_004b:  callvirt   "System.Threading.Tasks.Task<bool> C.Enumerator.MoveNextAsync()"
                    IL_0050:  call       "bool System.Runtime.CompilerServices.AsyncHelpers.Await<bool>(System.Threading.Tasks.Task<bool>)"
                    IL_0055:  brtrue.s   IL_000f
                    IL_0057:  leave.s    IL_005c
                  }
                  catch object
                  {
                    IL_0059:  stloc.1
                    IL_005a:  leave.s    IL_005c
                  }
                  IL_005c:  ldloc.0
                  IL_005d:  brfalse.s  IL_006a
                  IL_005f:  ldloc.0
                  IL_0060:  callvirt   "System.Threading.Tasks.ValueTask C.Enumerator.DisposeAsync()"
                  IL_0065:  call       "void System.Runtime.CompilerServices.AsyncHelpers.Await(System.Threading.Tasks.ValueTask)"
                  IL_006a:  ldloc.1
                  IL_006b:  brfalse.s  IL_0082
                  IL_006d:  ldloc.1
                  IL_006e:  isinst     "System.Exception"
                  IL_0073:  dup
                  IL_0074:  brtrue.s   IL_0078
                  IL_0076:  ldloc.1
                  IL_0077:  throw
                  IL_0078:  call       "System.Runtime.ExceptionServices.ExceptionDispatchInfo System.Runtime.ExceptionServices.ExceptionDispatchInfo.Capture(System.Exception)"
                  IL_007d:  callvirt   "void System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()"
                  IL_0082:  ret
                }
                """);
        }
 
        [Fact]
        public void TestWithPattern_WithUnsealed_WithIAsyncDisposable()
        {
            string source = @"
using static System.Console;
using System.Threading.Tasks;
public class C
{
    public static async Task Main()
    {
        await foreach (var i in new C())
        {
            Write($""Got({i}) "");
        }
    }
    public Enumerator GetAsyncEnumerator(System.Threading.CancellationToken token = default)
    {
        return new DerivedEnumerator();
    }
    public class Enumerator
    {
        protected int i = 0;
        public int Current
        {
            get
            {
                Write($""Current({i}) "");
                return i;
            }
        }
        public async Task<bool> MoveNextAsync()
        {
            Write($""NextAsync({i}) "");
            i++;
            return await Task.FromResult(i < 4);
        }
    }
    public class DerivedEnumerator : Enumerator, System.IAsyncDisposable
    {
        public ValueTask DisposeAsync() => throw null;
    }
}";
            var comp = CreateCompilationWithTasksExtensions(source + s_IAsyncEnumerable, options: TestOptions.DebugExe);
            comp.VerifyDiagnostics();
 
            var tree = comp.SyntaxTrees.Single();
            var model = (SyntaxTreeSemanticModel)comp.GetSemanticModel(tree, ignoreAccessibility: false);
            var foreachSyntax = tree.GetRoot().DescendantNodes().OfType<ForEachStatementSyntax>().Single();
 
            var memberModel = model.GetMemberModel(foreachSyntax);
            var boundNode = (BoundForEachStatement)memberModel.GetUpperBoundNode(foreachSyntax);
            ForEachEnumeratorInfo internalInfo = boundNode.EnumeratorInfoOpt;
            Assert.False(internalInfo.NeedsDisposal);
 
            var verifier = CompileAndVerify(comp,
                expectedOutput: "NextAsync(0) Current(1) Got(1) NextAsync(1) Current(2) Got(2) NextAsync(2) Current(3) Got(3) NextAsync(3)");
 
            verifier.VerifyIL("C.<Main>d__0.System.Runtime.CompilerServices.IAsyncStateMachine.MoveNext()", @"
{
  // Code size      273 (0x111)
  .maxstack  3
  .locals init (int V_0,
                System.Threading.CancellationToken V_1,
                System.Runtime.CompilerServices.TaskAwaiter<bool> V_2,
                C.<Main>d__0 V_3,
                System.Exception V_4)
  // sequence point: <hidden>
  IL_0000:  ldarg.0
  IL_0001:  ldfld      ""int C.<Main>d__0.<>1__state""
  IL_0006:  stloc.0
  .try
  {
    // sequence point: <hidden>
    IL_0007:  ldloc.0
    IL_0008:  brfalse.s  IL_0012
    IL_000a:  br.s       IL_000c
    IL_000c:  ldloc.0
    IL_000d:  ldc.i4.1
    IL_000e:  beq.s      IL_0017
    IL_0010:  br.s       IL_001c
    IL_0012:  br         IL_00a5
    IL_0017:  br         IL_00a5
    // sequence point: {
    IL_001c:  nop
    // sequence point: await foreach
    IL_001d:  nop
    // sequence point: new C()
    IL_001e:  ldarg.0
    IL_001f:  newobj     ""C..ctor()""
    IL_0024:  ldloca.s   V_1
    IL_0026:  initobj    ""System.Threading.CancellationToken""
    IL_002c:  ldloc.1
    IL_002d:  call       ""C.Enumerator C.GetAsyncEnumerator(System.Threading.CancellationToken)""
    IL_0032:  stfld      ""C.Enumerator C.<Main>d__0.<>s__1""
    // sequence point: <hidden>
    IL_0037:  br.s       IL_0067
    // sequence point: var i
    IL_0039:  ldarg.0
    IL_003a:  ldarg.0
    IL_003b:  ldfld      ""C.Enumerator C.<Main>d__0.<>s__1""
    IL_0040:  callvirt   ""int C.Enumerator.Current.get""
    IL_0045:  stfld      ""int C.<Main>d__0.<i>5__2""
    // sequence point: {
    IL_004a:  nop
    // sequence point: Write($""Got({i}) "");
    IL_004b:  ldstr      ""Got({0}) ""
    IL_0050:  ldarg.0
    IL_0051:  ldfld      ""int C.<Main>d__0.<i>5__2""
    IL_0056:  box        ""int""
    IL_005b:  call       ""string string.Format(string, object)""
    IL_0060:  call       ""void System.Console.Write(string)""
    IL_0065:  nop
    // sequence point: }
    IL_0066:  nop
    // sequence point: in
    IL_0067:  ldarg.0
    IL_0068:  ldfld      ""C.Enumerator C.<Main>d__0.<>s__1""
    IL_006d:  callvirt   ""System.Threading.Tasks.Task<bool> C.Enumerator.MoveNextAsync()""
    IL_0072:  callvirt   ""System.Runtime.CompilerServices.TaskAwaiter<bool> System.Threading.Tasks.Task<bool>.GetAwaiter()""
    IL_0077:  stloc.2
    // sequence point: <hidden>
    IL_0078:  ldloca.s   V_2
    IL_007a:  call       ""bool System.Runtime.CompilerServices.TaskAwaiter<bool>.IsCompleted.get""
    IL_007f:  brtrue.s   IL_00c1
    IL_0081:  ldarg.0
    IL_0082:  ldc.i4.0
    IL_0083:  dup
    IL_0084:  stloc.0
    IL_0085:  stfld      ""int C.<Main>d__0.<>1__state""
    // async: yield
    IL_008a:  ldarg.0
    IL_008b:  ldloc.2
    IL_008c:  stfld      ""System.Runtime.CompilerServices.TaskAwaiter<bool> C.<Main>d__0.<>u__1""
    IL_0091:  ldarg.0
    IL_0092:  stloc.3
    IL_0093:  ldarg.0
    IL_0094:  ldflda     ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder C.<Main>d__0.<>t__builder""
    IL_0099:  ldloca.s   V_2
    IL_009b:  ldloca.s   V_3
    IL_009d:  call       ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.AwaitUnsafeOnCompleted<System.Runtime.CompilerServices.TaskAwaiter<bool>, C.<Main>d__0>(ref System.Runtime.CompilerServices.TaskAwaiter<bool>, ref C.<Main>d__0)""
    IL_00a2:  nop
    IL_00a3:  leave.s    IL_0110
    // async: resume
    IL_00a5:  ldarg.0
    IL_00a6:  ldfld      ""System.Runtime.CompilerServices.TaskAwaiter<bool> C.<Main>d__0.<>u__1""
    IL_00ab:  stloc.2
    IL_00ac:  ldarg.0
    IL_00ad:  ldflda     ""System.Runtime.CompilerServices.TaskAwaiter<bool> C.<Main>d__0.<>u__1""
    IL_00b2:  initobj    ""System.Runtime.CompilerServices.TaskAwaiter<bool>""
    IL_00b8:  ldarg.0
    IL_00b9:  ldc.i4.m1
    IL_00ba:  dup
    IL_00bb:  stloc.0
    IL_00bc:  stfld      ""int C.<Main>d__0.<>1__state""
    IL_00c1:  ldarg.0
    IL_00c2:  ldloca.s   V_2
    IL_00c4:  call       ""bool System.Runtime.CompilerServices.TaskAwaiter<bool>.GetResult()""
    IL_00c9:  stfld      ""bool C.<Main>d__0.<>s__3""
    IL_00ce:  ldarg.0
    IL_00cf:  ldfld      ""bool C.<Main>d__0.<>s__3""
    IL_00d4:  brtrue     IL_0039
    IL_00d9:  ldarg.0
    IL_00da:  ldnull
    IL_00db:  stfld      ""C.Enumerator C.<Main>d__0.<>s__1""
    IL_00e0:  leave.s    IL_00fc
  }
  catch System.Exception
  {
    // async: catch handler, sequence point: <hidden>
    IL_00e2:  stloc.s    V_4
    IL_00e4:  ldarg.0
    IL_00e5:  ldc.i4.s   -2
    IL_00e7:  stfld      ""int C.<Main>d__0.<>1__state""
    IL_00ec:  ldarg.0
    IL_00ed:  ldflda     ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder C.<Main>d__0.<>t__builder""
    IL_00f2:  ldloc.s    V_4
    IL_00f4:  call       ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetException(System.Exception)""
    IL_00f9:  nop
    IL_00fa:  leave.s    IL_0110
  }
  // sequence point: }
  IL_00fc:  ldarg.0
  IL_00fd:  ldc.i4.s   -2
  IL_00ff:  stfld      ""int C.<Main>d__0.<>1__state""
  // sequence point: <hidden>
  IL_0104:  ldarg.0
  IL_0105:  ldflda     ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder C.<Main>d__0.<>t__builder""
  IL_010a:  call       ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetResult()""
  IL_010f:  nop
  IL_0110:  ret
}
", sequencePoints: "C+<Main>d__0.MoveNext", source: source + s_IAsyncEnumerable);
        }
 
        [Fact]
        public void TestWithPattern_WithIAsyncDisposable()
        {
            string source = @"
using static System.Console;
using System.Threading.Tasks;
class C
{
    public static async Task Main()
    {
        await foreach (var i in new C())
        {
            Write($""Got({i}) "");
        }
    }
    public Enumerator GetAsyncEnumerator()
    {
        return new Enumerator();
    }
    public sealed class Enumerator : System.IAsyncDisposable
    {
        int i = 0;
        public int Current
        {
            get
            {
                Write($""Current({i}) "");
                return i;
            }
        }
        public async Task<bool> MoveNextAsync()
        {
            Write($""NextAsync({i}) "");
            i++;
            return await Task.FromResult(i < 4);
        }
        public async ValueTask DisposeAsync()
        {
            Write($""Disp"");
            await Task.Yield();
            Write($""ose({i}) "");
        }
    }
}";
            var comp = CreateCompilationWithTasksExtensions(source + s_IAsyncEnumerable, options: TestOptions.DebugExe);
            comp.VerifyDiagnostics();
 
            var tree = comp.SyntaxTrees.Single();
            var model = (SyntaxTreeSemanticModel)comp.GetSemanticModel(tree, ignoreAccessibility: false);
            var foreachSyntax = tree.GetRoot().DescendantNodes().OfType<ForEachStatementSyntax>().Single();
 
            var memberModel = model.GetMemberModel(foreachSyntax);
            BoundForEachStatement boundNode = (BoundForEachStatement)memberModel.GetUpperBoundNode(foreachSyntax);
            ForEachEnumeratorInfo internalInfo = boundNode.EnumeratorInfoOpt;
            Assert.True(internalInfo.NeedsDisposal);
 
            var expectedOutput = "NextAsync(0) Current(1) Got(1) NextAsync(1) Current(2) Got(2) NextAsync(2) Current(3) Got(3) NextAsync(3) Dispose(4)";
            CompileAndVerify(comp, expectedOutput: expectedOutput);
 
            var runtimeAsyncComp = CreateRuntimeAsyncCompilation(source);
            var verifier = CompileAndVerify(runtimeAsyncComp, expectedOutput: CodeGenAsyncTests.ExpectedOutput(expectedOutput, isRuntimeAsync: true), verify: Verification.Fails with
            {
                ILVerifyMessage = """
                    [Main]: Return value missing on the stack. { Offset = 0x82 }
                    [MoveNextAsync]: Unexpected type on the stack. { Offset = 0x5c, Found = Int32, Expected = ref '[System.Runtime]System.Threading.Tasks.Task`1<bool>' }
                    [DisposeAsync]: Return value missing on the stack. { Offset = 0x68 }
                    """
            });
            verifier.VerifyIL("C.Main()", """
                {
                  // Code size      131 (0x83)
                  .maxstack  2
                  .locals init (C.Enumerator V_0,
                                object V_1,
                                int V_2, //i
                                System.Runtime.CompilerServices.DefaultInterpolatedStringHandler V_3)
                  IL_0000:  newobj     "C..ctor()"
                  IL_0005:  call       "C.Enumerator C.GetAsyncEnumerator()"
                  IL_000a:  stloc.0
                  IL_000b:  ldnull
                  IL_000c:  stloc.1
                  .try
                  {
                    IL_000d:  br.s       IL_004a
                    IL_000f:  ldloc.0
                    IL_0010:  callvirt   "int C.Enumerator.Current.get"
                    IL_0015:  stloc.2
                    IL_0016:  ldc.i4.6
                    IL_0017:  ldc.i4.1
                    IL_0018:  newobj     "System.Runtime.CompilerServices.DefaultInterpolatedStringHandler..ctor(int, int)"
                    IL_001d:  stloc.3
                    IL_001e:  ldloca.s   V_3
                    IL_0020:  ldstr      "Got("
                    IL_0025:  call       "void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendLiteral(string)"
                    IL_002a:  ldloca.s   V_3
                    IL_002c:  ldloc.2
                    IL_002d:  call       "void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted<int>(int)"
                    IL_0032:  ldloca.s   V_3
                    IL_0034:  ldstr      ") "
                    IL_0039:  call       "void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendLiteral(string)"
                    IL_003e:  ldloca.s   V_3
                    IL_0040:  call       "string System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.ToStringAndClear()"
                    IL_0045:  call       "void System.Console.Write(string)"
                    IL_004a:  ldloc.0
                    IL_004b:  callvirt   "System.Threading.Tasks.Task<bool> C.Enumerator.MoveNextAsync()"
                    IL_0050:  call       "bool System.Runtime.CompilerServices.AsyncHelpers.Await<bool>(System.Threading.Tasks.Task<bool>)"
                    IL_0055:  brtrue.s   IL_000f
                    IL_0057:  leave.s    IL_005c
                  }
                  catch object
                  {
                    IL_0059:  stloc.1
                    IL_005a:  leave.s    IL_005c
                  }
                  IL_005c:  ldloc.0
                  IL_005d:  brfalse.s  IL_006a
                  IL_005f:  ldloc.0
                  IL_0060:  callvirt   "System.Threading.Tasks.ValueTask C.Enumerator.DisposeAsync()"
                  IL_0065:  call       "void System.Runtime.CompilerServices.AsyncHelpers.Await(System.Threading.Tasks.ValueTask)"
                  IL_006a:  ldloc.1
                  IL_006b:  brfalse.s  IL_0082
                  IL_006d:  ldloc.1
                  IL_006e:  isinst     "System.Exception"
                  IL_0073:  dup
                  IL_0074:  brtrue.s   IL_0078
                  IL_0076:  ldloc.1
                  IL_0077:  throw
                  IL_0078:  call       "System.Runtime.ExceptionServices.ExceptionDispatchInfo System.Runtime.ExceptionServices.ExceptionDispatchInfo.Capture(System.Exception)"
                  IL_007d:  callvirt   "void System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()"
                  IL_0082:  ret
                }
                """);
        }
 
        [Fact]
        public void TestWithPattern_WithIAsyncDisposableUseSiteError()
        {
            string enumerator = @"
using System.Threading.Tasks;
public class C
{
    public Enumerator GetAsyncEnumerator() => throw null;
    public sealed class Enumerator : System.IAsyncDisposable
    {
        public int Current { get => throw null; }
        public Task<bool> MoveNextAsync() => throw null;
        public async ValueTask DisposeAsync()
        {
            await Task.Yield();
        }
    }
}";
            string source = @"
using System.Threading.Tasks;
class Client
{
    async Task M()
    {
        await foreach (var i in new C())
        {
        }
    }
}";
            var lib = CreateCompilationWithTasksExtensions(enumerator + s_IAsyncEnumerable);
            lib.VerifyDiagnostics();
 
            var comp = CreateCompilationWithTasksExtensions(source, references: new[] { lib.EmitToImageReference() });
            comp.MakeTypeMissing(WellKnownType.System_IAsyncDisposable);
            comp.VerifyDiagnostics();
 
            var tree = comp.SyntaxTrees.Single();
            var model = (SyntaxTreeSemanticModel)comp.GetSemanticModel(tree, ignoreAccessibility: false);
            var foreachSyntax = tree.GetRoot().DescendantNodes().OfType<ForEachStatementSyntax>().Single();
 
            var memberModel = model.GetMemberModel(foreachSyntax);
            var boundNode = (BoundForEachStatement)memberModel.GetUpperBoundNode(foreachSyntax);
            ForEachEnumeratorInfo internalInfo = boundNode.EnumeratorInfoOpt;
            Assert.True(internalInfo.NeedsDisposal);
        }
 
        [Fact]
        public void TestWithMultipleInterface()
        {
            string source = @"
using System.Collections.Generic;
class C : IAsyncEnumerable<int>, IAsyncEnumerable<string>
{
    async System.Threading.Tasks.Task M()
    {
        await foreach (var i in new C())
        {
        }
    }
    IAsyncEnumerator<int> IAsyncEnumerable<int>.GetAsyncEnumerator(System.Threading.CancellationToken token)
    {
        throw null;
    }
    IAsyncEnumerator<string> IAsyncEnumerable<string>.GetAsyncEnumerator(System.Threading.CancellationToken token)
    {
        throw null;
    }
}";
            var comp = CreateCompilationWithTasksExtensions(source + s_IAsyncEnumerable);
            comp.VerifyDiagnostics(
                // (7,33): error CS8413: Async foreach statement cannot operate on variables of type 'C' because it implements multiple instantiations of 'IAsyncEnumerable<T>'; try casting to a specific interface instantiation
                //         await foreach (var i in new C())
                Diagnostic(ErrorCode.ERR_MultipleIAsyncEnumOfT, "new C()").WithArguments("C", "System.Collections.Generic.IAsyncEnumerable<T>").WithLocation(7, 33)
                );
        }
 
        [Fact]
        public void TestWithMultipleImplementations()
        {
            string source = @"
using System.Collections.Generic;
using System.Threading.Tasks;
class Base : IAsyncEnumerable<string>
{
    IAsyncEnumerator<string> IAsyncEnumerable<string>.GetAsyncEnumerator(System.Threading.CancellationToken token)
        => throw null;
}
class C : Base, IAsyncEnumerable<int>
{
    async Task M()
    {
        await foreach (var i in new C())
        {
        }
    }
    IAsyncEnumerator<int> IAsyncEnumerable<int>.GetAsyncEnumerator(System.Threading.CancellationToken token)
        => throw null;
}";
            var comp = CreateCompilationWithTasksExtensions(source + s_IAsyncEnumerable);
            comp.VerifyDiagnostics(
                // (13,33): error CS8413: Async foreach statement cannot operate on variables of type 'C' because it implements multiple instantiations of 'IAsyncEnumerable<T>'; try casting to a specific interface instantiation
                //         await foreach (var i in new C())
                Diagnostic(ErrorCode.ERR_MultipleIAsyncEnumOfT, "new C()").WithArguments("C", "System.Collections.Generic.IAsyncEnumerable<T>").WithLocation(13, 33)
                );
        }
 
        [Fact]
        public void TestWithInterface()
        {
            string source = @"
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using static System.Console;
class C : IAsyncEnumerable<int>
{
    static async Task Main()
    {
        await foreach (var i in new C())
        {
            Write($""Got({i}) "");
        }
    }
    IAsyncEnumerator<int> IAsyncEnumerable<int>.GetAsyncEnumerator(System.Threading.CancellationToken token)
    {
        return new AsyncEnumerator();
    }
    sealed class AsyncEnumerator : IAsyncEnumerator<int>
    {
        int i = 0;
        int IAsyncEnumerator<int>.Current
        {
            get
            {
                Write($""Current({i}) "");
                return i;
            }
        }
        async ValueTask<bool> IAsyncEnumerator<int>.MoveNextAsync()
        {
            Write($""NextAsync({i}) "");
            i++;
            return await Task.FromResult(i < 4);
        }
        async ValueTask IAsyncDisposable.DisposeAsync()
        {
            Write($""Disp"");
            await Task.Yield();
            Write($""ose({i}) "");
        }
    }
}";
            var comp = CreateCompilationWithTasksExtensions(new[] { source, s_IAsyncEnumerable }, options: TestOptions.DebugExe);
            comp.VerifyDiagnostics();
 
            var expectedOutput = "NextAsync(0) Current(1) Got(1) NextAsync(1) Current(2) Got(2) NextAsync(2) Current(3) Got(3) NextAsync(3) Dispose(4)";
            CompileAndVerify(comp, expectedOutput: expectedOutput);
 
            var tree = comp.SyntaxTrees.First();
            var model = (SyntaxTreeSemanticModel)comp.GetSemanticModel(tree, ignoreAccessibility: false);
            var foreachSyntax = tree.GetRoot().DescendantNodes().OfType<ForEachStatementSyntax>().Single();
            var info = model.GetForEachStatementInfo(foreachSyntax);
 
            Assert.Equal("System.Collections.Generic.IAsyncEnumerator<System.Int32> System.Collections.Generic.IAsyncEnumerable<System.Int32>.GetAsyncEnumerator([System.Threading.CancellationToken token = default(System.Threading.CancellationToken)])",
                info.GetEnumeratorMethod.ToTestDisplayString());
            Assert.Equal("System.Threading.Tasks.ValueTask<System.Boolean> System.Collections.Generic.IAsyncEnumerator<System.Int32>.MoveNextAsync()",
                info.MoveNextMethod.ToTestDisplayString());
            Assert.Equal("System.Int32 System.Collections.Generic.IAsyncEnumerator<System.Int32>.Current { get; }",
                info.CurrentProperty.ToTestDisplayString());
            Assert.Equal("System.Threading.Tasks.ValueTask System.IAsyncDisposable.DisposeAsync()", info.DisposeMethod.ToTestDisplayString());
            Assert.Equal("System.Int32", info.ElementType.ToTestDisplayString());
            Assert.Equal(ConversionKind.Identity, info.ElementConversion.Kind);
            Assert.Equal(ConversionKind.Identity, info.CurrentConversion.Kind);
 
            var memberModel = model.GetMemberModel(foreachSyntax);
            var boundNode = (BoundForEachStatement)memberModel.GetUpperBoundNode(foreachSyntax);
            ForEachEnumeratorInfo internalInfo = boundNode.EnumeratorInfoOpt;
            Assert.True(internalInfo.NeedsDisposal);
 
            var runtimeAsyncComp = CreateRuntimeAsyncCompilation(source);
            var verifier = CompileAndVerify(runtimeAsyncComp, expectedOutput: CodeGenAsyncTests.ExpectedOutput(expectedOutput, isRuntimeAsync: true), verify: Verification.Fails with
            {
                ILVerifyMessage = """
                    [Main]: Return value missing on the stack. { Offset = 0x8c }
                    [System.Collections.Generic.IAsyncEnumerator<System.Int32>.MoveNextAsync]: Unexpected type on the stack. { Offset = 0x5c, Found = Int32, Expected = value '[System.Runtime]System.Threading.Tasks.ValueTask`1<bool>' }
                    [System.IAsyncDisposable.DisposeAsync]: Return value missing on the stack. { Offset = 0x68 }
                    """
            });
            verifier.VerifyIL("C.Main()", """
                {
                  // Code size      141 (0x8d)
                  .maxstack  2
                  .locals init (System.Collections.Generic.IAsyncEnumerator<int> V_0,
                                System.Threading.CancellationToken V_1,
                                object V_2,
                                int V_3, //i
                                System.Runtime.CompilerServices.DefaultInterpolatedStringHandler V_4)
                  IL_0000:  newobj     "C..ctor()"
                  IL_0005:  ldloca.s   V_1
                  IL_0007:  initobj    "System.Threading.CancellationToken"
                  IL_000d:  ldloc.1
                  IL_000e:  callvirt   "System.Collections.Generic.IAsyncEnumerator<int> System.Collections.Generic.IAsyncEnumerable<int>.GetAsyncEnumerator(System.Threading.CancellationToken)"
                  IL_0013:  stloc.0
                  IL_0014:  ldnull
                  IL_0015:  stloc.2
                  .try
                  {
                    IL_0016:  br.s       IL_0054
                    IL_0018:  ldloc.0
                    IL_0019:  callvirt   "int System.Collections.Generic.IAsyncEnumerator<int>.Current.get"
                    IL_001e:  stloc.3
                    IL_001f:  ldc.i4.6
                    IL_0020:  ldc.i4.1
                    IL_0021:  newobj     "System.Runtime.CompilerServices.DefaultInterpolatedStringHandler..ctor(int, int)"
                    IL_0026:  stloc.s    V_4
                    IL_0028:  ldloca.s   V_4
                    IL_002a:  ldstr      "Got("
                    IL_002f:  call       "void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendLiteral(string)"
                    IL_0034:  ldloca.s   V_4
                    IL_0036:  ldloc.3
                    IL_0037:  call       "void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted<int>(int)"
                    IL_003c:  ldloca.s   V_4
                    IL_003e:  ldstr      ") "
                    IL_0043:  call       "void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendLiteral(string)"
                    IL_0048:  ldloca.s   V_4
                    IL_004a:  call       "string System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.ToStringAndClear()"
                    IL_004f:  call       "void System.Console.Write(string)"
                    IL_0054:  ldloc.0
                    IL_0055:  callvirt   "System.Threading.Tasks.ValueTask<bool> System.Collections.Generic.IAsyncEnumerator<int>.MoveNextAsync()"
                    IL_005a:  call       "bool System.Runtime.CompilerServices.AsyncHelpers.Await<bool>(System.Threading.Tasks.ValueTask<bool>)"
                    IL_005f:  brtrue.s   IL_0018
                    IL_0061:  leave.s    IL_0066
                  }
                  catch object
                  {
                    IL_0063:  stloc.2
                    IL_0064:  leave.s    IL_0066
                  }
                  IL_0066:  ldloc.0
                  IL_0067:  brfalse.s  IL_0074
                  IL_0069:  ldloc.0
                  IL_006a:  callvirt   "System.Threading.Tasks.ValueTask System.IAsyncDisposable.DisposeAsync()"
                  IL_006f:  call       "void System.Runtime.CompilerServices.AsyncHelpers.Await(System.Threading.Tasks.ValueTask)"
                  IL_0074:  ldloc.2
                  IL_0075:  brfalse.s  IL_008c
                  IL_0077:  ldloc.2
                  IL_0078:  isinst     "System.Exception"
                  IL_007d:  dup
                  IL_007e:  brtrue.s   IL_0082
                  IL_0080:  ldloc.2
                  IL_0081:  throw
                  IL_0082:  call       "System.Runtime.ExceptionServices.ExceptionDispatchInfo System.Runtime.ExceptionServices.ExceptionDispatchInfo.Capture(System.Exception)"
                  IL_0087:  callvirt   "void System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()"
                  IL_008c:  ret
                }
                """);
        }
 
        [Fact]
        public void TestWithInterface_OnStruct_ImplicitInterfaceImplementation()
        {
            string source = @"
using static System.Console;
using System.Collections.Generic;
using System.Threading.Tasks;
struct C : IAsyncEnumerable<int>
{
    static async System.Threading.Tasks.Task Main()
    {
        await foreach (var i in new C())
        {
            Write($""Got({i}) "");
        }
    }
    public IAsyncEnumerator<int> GetAsyncEnumerator(System.Threading.CancellationToken token)
    {
        return new AsyncEnumerator();
    }
    class AsyncEnumerator : IAsyncEnumerator<int>
    {
        public int i;
        public int Current
        {
            get
            {
                Write($""Current({i}) "");
                return i;
            }
        }
        public async ValueTask<bool> MoveNextAsync()
        {
            Write($""NextAsync({i}) "");
            i++;
            return await Task.FromResult(i < 4);
        }
        public async ValueTask DisposeAsync()
        {
            Write($""Disp"");
            await Task.Yield();
            Write($""ose({i}) "");
        }
    }
}";
            // Note: the enumerator type should not be a struct, otherwise you will loop forever
            var comp = CreateCompilationWithTasksExtensions(new[] { source, s_IAsyncEnumerable }, options: TestOptions.DebugExe);
            comp.VerifyDiagnostics();
 
            var expectedOutput = "NextAsync(0) Current(1) Got(1) NextAsync(1) Current(2) Got(2) NextAsync(2) Current(3) Got(3) NextAsync(3) Dispose(4)";
            var verifier = CompileAndVerify(comp, expectedOutput: expectedOutput);
 
            // The thing to notice here is that the call to GetAsyncEnumerator is a constrained call (we're not boxing to `IAsyncEnumerable<int>`)
            verifier.VerifyIL("C.<Main>d__0.System.Runtime.CompilerServices.IAsyncStateMachine.MoveNext()", @"
{
  // Code size      496 (0x1f0)
  .maxstack  3
  .locals init (int V_0,
                C V_1,
                System.Threading.CancellationToken V_2,
                System.Runtime.CompilerServices.ValueTaskAwaiter<bool> V_3,
                System.Threading.Tasks.ValueTask<bool> V_4,
                C.<Main>d__0 V_5,
                object V_6,
                System.Runtime.CompilerServices.ValueTaskAwaiter V_7,
                System.Threading.Tasks.ValueTask V_8,
                System.Exception V_9)
  IL_0000:  ldarg.0
  IL_0001:  ldfld      ""int C.<Main>d__0.<>1__state""
  IL_0006:  stloc.0
  .try
  {
    IL_0007:  ldloc.0
    IL_0008:  brfalse.s  IL_0012
    IL_000a:  br.s       IL_000c
    IL_000c:  ldloc.0
    IL_000d:  ldc.i4.1
    IL_000e:  beq.s      IL_0014
    IL_0010:  br.s       IL_0019
    IL_0012:  br.s       IL_004c
    IL_0014:  br         IL_015c
    IL_0019:  nop
    IL_001a:  nop
    IL_001b:  ldarg.0
    IL_001c:  ldloca.s   V_1
    IL_001e:  dup
    IL_001f:  initobj    ""C""
    IL_0025:  ldloca.s   V_2
    IL_0027:  initobj    ""System.Threading.CancellationToken""
    IL_002d:  ldloc.2
    IL_002e:  constrained. ""C""
    IL_0034:  callvirt   ""System.Collections.Generic.IAsyncEnumerator<int> System.Collections.Generic.IAsyncEnumerable<int>.GetAsyncEnumerator(System.Threading.CancellationToken)""
    IL_0039:  stfld      ""System.Collections.Generic.IAsyncEnumerator<int> C.<Main>d__0.<>s__1""
    IL_003e:  ldarg.0
    IL_003f:  ldnull
    IL_0040:  stfld      ""object C.<Main>d__0.<>s__2""
    IL_0045:  ldarg.0
    IL_0046:  ldc.i4.0
    IL_0047:  stfld      ""int C.<Main>d__0.<>s__3""
    IL_004c:  nop
    .try
    {
      IL_004d:  ldloc.0
      IL_004e:  brfalse.s  IL_0052
      IL_0050:  br.s       IL_0054
      IL_0052:  br.s       IL_00ca
      IL_0054:  br.s       IL_0084
      IL_0056:  ldarg.0
      IL_0057:  ldarg.0
      IL_0058:  ldfld      ""System.Collections.Generic.IAsyncEnumerator<int> C.<Main>d__0.<>s__1""
      IL_005d:  callvirt   ""int System.Collections.Generic.IAsyncEnumerator<int>.Current.get""
      IL_0062:  stfld      ""int C.<Main>d__0.<i>5__4""
      IL_0067:  nop
      IL_0068:  ldstr      ""Got({0}) ""
      IL_006d:  ldarg.0
      IL_006e:  ldfld      ""int C.<Main>d__0.<i>5__4""
      IL_0073:  box        ""int""
      IL_0078:  call       ""string string.Format(string, object)""
      IL_007d:  call       ""void System.Console.Write(string)""
      IL_0082:  nop
      IL_0083:  nop
      IL_0084:  ldarg.0
      IL_0085:  ldfld      ""System.Collections.Generic.IAsyncEnumerator<int> C.<Main>d__0.<>s__1""
      IL_008a:  callvirt   ""System.Threading.Tasks.ValueTask<bool> System.Collections.Generic.IAsyncEnumerator<int>.MoveNextAsync()""
      IL_008f:  stloc.s    V_4
      IL_0091:  ldloca.s   V_4
      IL_0093:  call       ""System.Runtime.CompilerServices.ValueTaskAwaiter<bool> System.Threading.Tasks.ValueTask<bool>.GetAwaiter()""
      IL_0098:  stloc.3
      IL_0099:  ldloca.s   V_3
      IL_009b:  call       ""bool System.Runtime.CompilerServices.ValueTaskAwaiter<bool>.IsCompleted.get""
      IL_00a0:  brtrue.s   IL_00e6
      IL_00a2:  ldarg.0
      IL_00a3:  ldc.i4.0
      IL_00a4:  dup
      IL_00a5:  stloc.0
      IL_00a6:  stfld      ""int C.<Main>d__0.<>1__state""
      IL_00ab:  ldarg.0
      IL_00ac:  ldloc.3
      IL_00ad:  stfld      ""System.Runtime.CompilerServices.ValueTaskAwaiter<bool> C.<Main>d__0.<>u__1""
      IL_00b2:  ldarg.0
      IL_00b3:  stloc.s    V_5
      IL_00b5:  ldarg.0
      IL_00b6:  ldflda     ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder C.<Main>d__0.<>t__builder""
      IL_00bb:  ldloca.s   V_3
      IL_00bd:  ldloca.s   V_5
      IL_00bf:  call       ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.AwaitUnsafeOnCompleted<System.Runtime.CompilerServices.ValueTaskAwaiter<bool>, C.<Main>d__0>(ref System.Runtime.CompilerServices.ValueTaskAwaiter<bool>, ref C.<Main>d__0)""
      IL_00c4:  nop
      IL_00c5:  leave      IL_01ef
      IL_00ca:  ldarg.0
      IL_00cb:  ldfld      ""System.Runtime.CompilerServices.ValueTaskAwaiter<bool> C.<Main>d__0.<>u__1""
      IL_00d0:  stloc.3
      IL_00d1:  ldarg.0
      IL_00d2:  ldflda     ""System.Runtime.CompilerServices.ValueTaskAwaiter<bool> C.<Main>d__0.<>u__1""
      IL_00d7:  initobj    ""System.Runtime.CompilerServices.ValueTaskAwaiter<bool>""
      IL_00dd:  ldarg.0
      IL_00de:  ldc.i4.m1
      IL_00df:  dup
      IL_00e0:  stloc.0
      IL_00e1:  stfld      ""int C.<Main>d__0.<>1__state""
      IL_00e6:  ldarg.0
      IL_00e7:  ldloca.s   V_3
      IL_00e9:  call       ""bool System.Runtime.CompilerServices.ValueTaskAwaiter<bool>.GetResult()""
      IL_00ee:  stfld      ""bool C.<Main>d__0.<>s__5""
      IL_00f3:  ldarg.0
      IL_00f4:  ldfld      ""bool C.<Main>d__0.<>s__5""
      IL_00f9:  brtrue     IL_0056
      IL_00fe:  leave.s    IL_010c
    }
    catch object
    {
      IL_0100:  stloc.s    V_6
      IL_0102:  ldarg.0
      IL_0103:  ldloc.s    V_6
      IL_0105:  stfld      ""object C.<Main>d__0.<>s__2""
      IL_010a:  leave.s    IL_010c
    }
    IL_010c:  ldarg.0
    IL_010d:  ldfld      ""System.Collections.Generic.IAsyncEnumerator<int> C.<Main>d__0.<>s__1""
    IL_0112:  brfalse.s  IL_0181
    IL_0114:  ldarg.0
    IL_0115:  ldfld      ""System.Collections.Generic.IAsyncEnumerator<int> C.<Main>d__0.<>s__1""
    IL_011a:  callvirt   ""System.Threading.Tasks.ValueTask System.IAsyncDisposable.DisposeAsync()""
    IL_011f:  stloc.s    V_8
    IL_0121:  ldloca.s   V_8
    IL_0123:  call       ""System.Runtime.CompilerServices.ValueTaskAwaiter System.Threading.Tasks.ValueTask.GetAwaiter()""
    IL_0128:  stloc.s    V_7
    IL_012a:  ldloca.s   V_7
    IL_012c:  call       ""bool System.Runtime.CompilerServices.ValueTaskAwaiter.IsCompleted.get""
    IL_0131:  brtrue.s   IL_0179
    IL_0133:  ldarg.0
    IL_0134:  ldc.i4.1
    IL_0135:  dup
    IL_0136:  stloc.0
    IL_0137:  stfld      ""int C.<Main>d__0.<>1__state""
    IL_013c:  ldarg.0
    IL_013d:  ldloc.s    V_7
    IL_013f:  stfld      ""System.Runtime.CompilerServices.ValueTaskAwaiter C.<Main>d__0.<>u__2""
    IL_0144:  ldarg.0
    IL_0145:  stloc.s    V_5
    IL_0147:  ldarg.0
    IL_0148:  ldflda     ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder C.<Main>d__0.<>t__builder""
    IL_014d:  ldloca.s   V_7
    IL_014f:  ldloca.s   V_5
    IL_0151:  call       ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.AwaitUnsafeOnCompleted<System.Runtime.CompilerServices.ValueTaskAwaiter, C.<Main>d__0>(ref System.Runtime.CompilerServices.ValueTaskAwaiter, ref C.<Main>d__0)""
    IL_0156:  nop
    IL_0157:  leave      IL_01ef
    IL_015c:  ldarg.0
    IL_015d:  ldfld      ""System.Runtime.CompilerServices.ValueTaskAwaiter C.<Main>d__0.<>u__2""
    IL_0162:  stloc.s    V_7
    IL_0164:  ldarg.0
    IL_0165:  ldflda     ""System.Runtime.CompilerServices.ValueTaskAwaiter C.<Main>d__0.<>u__2""
    IL_016a:  initobj    ""System.Runtime.CompilerServices.ValueTaskAwaiter""
    IL_0170:  ldarg.0
    IL_0171:  ldc.i4.m1
    IL_0172:  dup
    IL_0173:  stloc.0
    IL_0174:  stfld      ""int C.<Main>d__0.<>1__state""
    IL_0179:  ldloca.s   V_7
    IL_017b:  call       ""void System.Runtime.CompilerServices.ValueTaskAwaiter.GetResult()""
    IL_0180:  nop
    IL_0181:  ldarg.0
    IL_0182:  ldfld      ""object C.<Main>d__0.<>s__2""
    IL_0187:  stloc.s    V_6
    IL_0189:  ldloc.s    V_6
    IL_018b:  brfalse.s  IL_01aa
    IL_018d:  ldloc.s    V_6
    IL_018f:  isinst     ""System.Exception""
    IL_0194:  stloc.s    V_9
    IL_0196:  ldloc.s    V_9
    IL_0198:  brtrue.s   IL_019d
    IL_019a:  ldloc.s    V_6
    IL_019c:  throw
    IL_019d:  ldloc.s    V_9
    IL_019f:  call       ""System.Runtime.ExceptionServices.ExceptionDispatchInfo System.Runtime.ExceptionServices.ExceptionDispatchInfo.Capture(System.Exception)""
    IL_01a4:  callvirt   ""void System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()""
    IL_01a9:  nop
    IL_01aa:  ldarg.0
    IL_01ab:  ldfld      ""int C.<Main>d__0.<>s__3""
    IL_01b0:  pop
    IL_01b1:  ldarg.0
    IL_01b2:  ldnull
    IL_01b3:  stfld      ""object C.<Main>d__0.<>s__2""
    IL_01b8:  ldarg.0
    IL_01b9:  ldnull
    IL_01ba:  stfld      ""System.Collections.Generic.IAsyncEnumerator<int> C.<Main>d__0.<>s__1""
    IL_01bf:  leave.s    IL_01db
  }
  catch System.Exception
  {
    IL_01c1:  stloc.s    V_9
    IL_01c3:  ldarg.0
    IL_01c4:  ldc.i4.s   -2
    IL_01c6:  stfld      ""int C.<Main>d__0.<>1__state""
    IL_01cb:  ldarg.0
    IL_01cc:  ldflda     ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder C.<Main>d__0.<>t__builder""
    IL_01d1:  ldloc.s    V_9
    IL_01d3:  call       ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetException(System.Exception)""
    IL_01d8:  nop
    IL_01d9:  leave.s    IL_01ef
  }
  IL_01db:  ldarg.0
  IL_01dc:  ldc.i4.s   -2
  IL_01de:  stfld      ""int C.<Main>d__0.<>1__state""
  IL_01e3:  ldarg.0
  IL_01e4:  ldflda     ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder C.<Main>d__0.<>t__builder""
  IL_01e9:  call       ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetResult()""
  IL_01ee:  nop
  IL_01ef:  ret
}");
 
            var runtimeAsyncComp = CreateRuntimeAsyncCompilation(source);
            var runtimeAsyncVerifier = CompileAndVerify(runtimeAsyncComp, expectedOutput: CodeGenAsyncTests.ExpectedOutput(expectedOutput, isRuntimeAsync: true), verify: Verification.Fails with
            {
                ILVerifyMessage = """
                    [Main]: Return value missing on the stack. { Offset = 0x98 }
                    [MoveNextAsync]: Unexpected type on the stack. { Offset = 0x5c, Found = Int32, Expected = value '[System.Runtime]System.Threading.Tasks.ValueTask`1<bool>' }
                    [DisposeAsync]: Return value missing on the stack. { Offset = 0x68 }
                    """
            });
            runtimeAsyncVerifier.VerifyIL("C.Main()", """
                {
                  // Code size      153 (0x99)
                  .maxstack  2
                  .locals init (System.Collections.Generic.IAsyncEnumerator<int> V_0,
                                C V_1,
                                System.Threading.CancellationToken V_2,
                                object V_3,
                                int V_4, //i
                                System.Runtime.CompilerServices.DefaultInterpolatedStringHandler V_5)
                  IL_0000:  ldloca.s   V_1
                  IL_0002:  dup
                  IL_0003:  initobj    "C"
                  IL_0009:  ldloca.s   V_2
                  IL_000b:  initobj    "System.Threading.CancellationToken"
                  IL_0011:  ldloc.2
                  IL_0012:  constrained. "C"
                  IL_0018:  callvirt   "System.Collections.Generic.IAsyncEnumerator<int> System.Collections.Generic.IAsyncEnumerable<int>.GetAsyncEnumerator(System.Threading.CancellationToken)"
                  IL_001d:  stloc.0
                  IL_001e:  ldnull
                  IL_001f:  stloc.3
                  .try
                  {
                    IL_0020:  br.s       IL_0060
                    IL_0022:  ldloc.0
                    IL_0023:  callvirt   "int System.Collections.Generic.IAsyncEnumerator<int>.Current.get"
                    IL_0028:  stloc.s    V_4
                    IL_002a:  ldc.i4.6
                    IL_002b:  ldc.i4.1
                    IL_002c:  newobj     "System.Runtime.CompilerServices.DefaultInterpolatedStringHandler..ctor(int, int)"
                    IL_0031:  stloc.s    V_5
                    IL_0033:  ldloca.s   V_5
                    IL_0035:  ldstr      "Got("
                    IL_003a:  call       "void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendLiteral(string)"
                    IL_003f:  ldloca.s   V_5
                    IL_0041:  ldloc.s    V_4
                    IL_0043:  call       "void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted<int>(int)"
                    IL_0048:  ldloca.s   V_5
                    IL_004a:  ldstr      ") "
                    IL_004f:  call       "void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendLiteral(string)"
                    IL_0054:  ldloca.s   V_5
                    IL_0056:  call       "string System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.ToStringAndClear()"
                    IL_005b:  call       "void System.Console.Write(string)"
                    IL_0060:  ldloc.0
                    IL_0061:  callvirt   "System.Threading.Tasks.ValueTask<bool> System.Collections.Generic.IAsyncEnumerator<int>.MoveNextAsync()"
                    IL_0066:  call       "bool System.Runtime.CompilerServices.AsyncHelpers.Await<bool>(System.Threading.Tasks.ValueTask<bool>)"
                    IL_006b:  brtrue.s   IL_0022
                    IL_006d:  leave.s    IL_0072
                  }
                  catch object
                  {
                    IL_006f:  stloc.3
                    IL_0070:  leave.s    IL_0072
                  }
                  IL_0072:  ldloc.0
                  IL_0073:  brfalse.s  IL_0080
                  IL_0075:  ldloc.0
                  IL_0076:  callvirt   "System.Threading.Tasks.ValueTask System.IAsyncDisposable.DisposeAsync()"
                  IL_007b:  call       "void System.Runtime.CompilerServices.AsyncHelpers.Await(System.Threading.Tasks.ValueTask)"
                  IL_0080:  ldloc.3
                  IL_0081:  brfalse.s  IL_0098
                  IL_0083:  ldloc.3
                  IL_0084:  isinst     "System.Exception"
                  IL_0089:  dup
                  IL_008a:  brtrue.s   IL_008e
                  IL_008c:  ldloc.3
                  IL_008d:  throw
                  IL_008e:  call       "System.Runtime.ExceptionServices.ExceptionDispatchInfo System.Runtime.ExceptionServices.ExceptionDispatchInfo.Capture(System.Exception)"
                  IL_0093:  callvirt   "void System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()"
                  IL_0098:  ret
                }
                """);
        }
 
        [Fact]
        public void TestWithInterface_WithEarlyCompletion1()
        {
            string source = @"
using static System.Console;
using System.Collections.Generic;
using System.Threading.Tasks;
class C : IAsyncEnumerable<int>
{
    static async System.Threading.Tasks.Task Main()
    {
        await foreach (var i in new C())
        {
            Write($""Got({i}) "");
        }
        Write($""Done"");
    }
    IAsyncEnumerator<int> IAsyncEnumerable<int>.GetAsyncEnumerator(System.Threading.CancellationToken token)
    {
        return new AsyncEnumerator(2);
    }
    internal sealed class AsyncEnumerator : IAsyncEnumerator<int>
    {
        int i;
        internal AsyncEnumerator(int start) { i = start; }
        public int Current
        {
            get
            {
                Write($""Current({i}) "");
                return i;
            }
        }
        public async ValueTask<bool> MoveNextAsync()
        {
            Write($""NextAsync({i}) "");
            i++;
            return await Task.FromResult(i < 4);
        }
        public ValueTask DisposeAsync()
        {
            Write($""Dispose({i}) "");
            return new ValueTask(Task.CompletedTask); // return a completed task
        }
    }
}";
            var comp = CreateCompilationWithTasksExtensions(source + s_IAsyncEnumerable, options: TestOptions.DebugExe);
            comp.VerifyDiagnostics();
 
            CompileAndVerify(comp, expectedOutput: "NextAsync(2) Current(3) Got(3) NextAsync(3) Dispose(4) Done");
 
            var runtimeAsyncComp = CreateRuntimeAsyncCompilation(source);
            var verifier = CompileAndVerify(runtimeAsyncComp, expectedOutput: CodeGenAsyncTests.ExpectedOutput("NextAsync(2) Current(3) Got(3) NextAsync(3) Dispose(4) Done", isRuntimeAsync: true), verify: Verification.Fails with
            {
                ILVerifyMessage = """
                    [Main]: Return value missing on the stack. { Offset = 0x96 }
                    [MoveNextAsync]: Unexpected type on the stack. { Offset = 0x5c, Found = Int32, Expected = value '[System.Runtime]System.Threading.Tasks.ValueTask`1<bool>' }
                    """
            });
            verifier.VerifyIL("C.Main()", """
                {
                  // Code size      151 (0x97)
                  .maxstack  2
                  .locals init (System.Collections.Generic.IAsyncEnumerator<int> V_0,
                                System.Threading.CancellationToken V_1,
                                object V_2,
                                int V_3, //i
                                System.Runtime.CompilerServices.DefaultInterpolatedStringHandler V_4)
                  IL_0000:  newobj     "C..ctor()"
                  IL_0005:  ldloca.s   V_1
                  IL_0007:  initobj    "System.Threading.CancellationToken"
                  IL_000d:  ldloc.1
                  IL_000e:  callvirt   "System.Collections.Generic.IAsyncEnumerator<int> System.Collections.Generic.IAsyncEnumerable<int>.GetAsyncEnumerator(System.Threading.CancellationToken)"
                  IL_0013:  stloc.0
                  IL_0014:  ldnull
                  IL_0015:  stloc.2
                  .try
                  {
                    IL_0016:  br.s       IL_0054
                    IL_0018:  ldloc.0
                    IL_0019:  callvirt   "int System.Collections.Generic.IAsyncEnumerator<int>.Current.get"
                    IL_001e:  stloc.3
                    IL_001f:  ldc.i4.6
                    IL_0020:  ldc.i4.1
                    IL_0021:  newobj     "System.Runtime.CompilerServices.DefaultInterpolatedStringHandler..ctor(int, int)"
                    IL_0026:  stloc.s    V_4
                    IL_0028:  ldloca.s   V_4
                    IL_002a:  ldstr      "Got("
                    IL_002f:  call       "void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendLiteral(string)"
                    IL_0034:  ldloca.s   V_4
                    IL_0036:  ldloc.3
                    IL_0037:  call       "void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted<int>(int)"
                    IL_003c:  ldloca.s   V_4
                    IL_003e:  ldstr      ") "
                    IL_0043:  call       "void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendLiteral(string)"
                    IL_0048:  ldloca.s   V_4
                    IL_004a:  call       "string System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.ToStringAndClear()"
                    IL_004f:  call       "void System.Console.Write(string)"
                    IL_0054:  ldloc.0
                    IL_0055:  callvirt   "System.Threading.Tasks.ValueTask<bool> System.Collections.Generic.IAsyncEnumerator<int>.MoveNextAsync()"
                    IL_005a:  call       "bool System.Runtime.CompilerServices.AsyncHelpers.Await<bool>(System.Threading.Tasks.ValueTask<bool>)"
                    IL_005f:  brtrue.s   IL_0018
                    IL_0061:  leave.s    IL_0066
                  }
                  catch object
                  {
                    IL_0063:  stloc.2
                    IL_0064:  leave.s    IL_0066
                  }
                  IL_0066:  ldloc.0
                  IL_0067:  brfalse.s  IL_0074
                  IL_0069:  ldloc.0
                  IL_006a:  callvirt   "System.Threading.Tasks.ValueTask System.IAsyncDisposable.DisposeAsync()"
                  IL_006f:  call       "void System.Runtime.CompilerServices.AsyncHelpers.Await(System.Threading.Tasks.ValueTask)"
                  IL_0074:  ldloc.2
                  IL_0075:  brfalse.s  IL_008c
                  IL_0077:  ldloc.2
                  IL_0078:  isinst     "System.Exception"
                  IL_007d:  dup
                  IL_007e:  brtrue.s   IL_0082
                  IL_0080:  ldloc.2
                  IL_0081:  throw
                  IL_0082:  call       "System.Runtime.ExceptionServices.ExceptionDispatchInfo System.Runtime.ExceptionServices.ExceptionDispatchInfo.Capture(System.Exception)"
                  IL_0087:  callvirt   "void System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()"
                  IL_008c:  ldstr      "Done"
                  IL_0091:  call       "void System.Console.Write(string)"
                  IL_0096:  ret
                }
                """);
        }
 
        [Fact]
        public void TestWithInterface_WithBreakAndContinue()
        {
            string source = @"
using static System.Console;
using System.Collections.Generic;
using System.Threading.Tasks;
class C : IAsyncEnumerable<int>
{
    static async System.Threading.Tasks.Task Main()
    {
        await foreach (var i in new C())
        {
            if (i == 2 || i == 3) { Write($""Continue({i}) ""); continue; }
            if (i == 4) { Write(""Break ""); break; }
            Write($""Got({i}) "");
        }
        Write(""Done"");
    }
    IAsyncEnumerator<int> IAsyncEnumerable<int>.GetAsyncEnumerator(System.Threading.CancellationToken token)
    {
        return new AsyncEnumerator();
    }
    sealed class AsyncEnumerator : IAsyncEnumerator<int>
    {
        int i = 0;
        public int Current
        {
            get
            {
                Write($""Current({i}) "");
                return i;
            }
        }
        public async ValueTask<bool> MoveNextAsync()
        {
            Write($""NextAsync({i}) "");
            i++;
            return await Task.FromResult(i < 10);
        }
        public async ValueTask DisposeAsync()
        {
            Write($""Disp"");
            await Task.Yield();
            Write($""ose({i}) "");
        }
    }
}";
            var comp = CreateCompilationWithTasksExtensions(source + s_IAsyncEnumerable, options: TestOptions.DebugExe);
            comp.VerifyDiagnostics();
 
            string expectedOutput = "NextAsync(0) Current(1) Got(1) NextAsync(1) Current(2) Continue(2) NextAsync(2) Current(3) Continue(3) NextAsync(3) Current(4) Break Dispose(4) Done";
            CompileAndVerify(comp,
                expectedOutput: expectedOutput);
 
            var runtimeAsyncComp = CreateRuntimeAsyncCompilation(source);
            var verifier = CompileAndVerify(runtimeAsyncComp, expectedOutput: CodeGenAsyncTests.ExpectedOutput(expectedOutput, isRuntimeAsync: true), verify: Verification.Fails with
            {
                ILVerifyMessage = """
                    [Main]: Return value missing on the stack. { Offset = 0xec }
                    [MoveNextAsync]: Unexpected type on the stack. { Offset = 0x5d, Found = Int32, Expected = value '[System.Runtime]System.Threading.Tasks.ValueTask`1<bool>' }
                    [DisposeAsync]: Return value missing on the stack. { Offset = 0x68 }
                    """
            });
            verifier.VerifyIL("C.Main()", """
                {
                  // Code size      237 (0xed)
                  .maxstack  2
                  .locals init (System.Collections.Generic.IAsyncEnumerator<int> V_0,
                                System.Threading.CancellationToken V_1,
                                object V_2,
                                int V_3, //i
                                System.Runtime.CompilerServices.DefaultInterpolatedStringHandler V_4,
                                System.Runtime.CompilerServices.DefaultInterpolatedStringHandler V_5)
                  IL_0000:  newobj     "C..ctor()"
                  IL_0005:  ldloca.s   V_1
                  IL_0007:  initobj    "System.Threading.CancellationToken"
                  IL_000d:  ldloc.1
                  IL_000e:  callvirt   "System.Collections.Generic.IAsyncEnumerator<int> System.Collections.Generic.IAsyncEnumerable<int>.GetAsyncEnumerator(System.Threading.CancellationToken)"
                  IL_0013:  stloc.0
                  IL_0014:  ldnull
                  IL_0015:  stloc.2
                  .try
                  {
                    IL_0016:  br         IL_00a7
                    IL_001b:  ldloc.0
                    IL_001c:  callvirt   "int System.Collections.Generic.IAsyncEnumerator<int>.Current.get"
                    IL_0021:  stloc.3
                    IL_0022:  ldloc.3
                    IL_0023:  ldc.i4.2
                    IL_0024:  beq.s      IL_002a
                    IL_0026:  ldloc.3
                    IL_0027:  ldc.i4.3
                    IL_0028:  bne.un.s   IL_0062
                    IL_002a:  ldc.i4.s   11
                    IL_002c:  ldc.i4.1
                    IL_002d:  newobj     "System.Runtime.CompilerServices.DefaultInterpolatedStringHandler..ctor(int, int)"
                    IL_0032:  stloc.s    V_4
                    IL_0034:  ldloca.s   V_4
                    IL_0036:  ldstr      "Continue("
                    IL_003b:  call       "void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendLiteral(string)"
                    IL_0040:  ldloca.s   V_4
                    IL_0042:  ldloc.3
                    IL_0043:  call       "void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted<int>(int)"
                    IL_0048:  ldloca.s   V_4
                    IL_004a:  ldstr      ") "
                    IL_004f:  call       "void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendLiteral(string)"
                    IL_0054:  ldloca.s   V_4
                    IL_0056:  call       "string System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.ToStringAndClear()"
                    IL_005b:  call       "void System.Console.Write(string)"
                    IL_0060:  br.s       IL_00a7
                    IL_0062:  ldloc.3
                    IL_0063:  ldc.i4.4
                    IL_0064:  bne.un.s   IL_0072
                    IL_0066:  ldstr      "Break "
                    IL_006b:  call       "void System.Console.Write(string)"
                    IL_0070:  br.s       IL_00b7
                    IL_0072:  ldc.i4.6
                    IL_0073:  ldc.i4.1
                    IL_0074:  newobj     "System.Runtime.CompilerServices.DefaultInterpolatedStringHandler..ctor(int, int)"
                    IL_0079:  stloc.s    V_5
                    IL_007b:  ldloca.s   V_5
                    IL_007d:  ldstr      "Got("
                    IL_0082:  call       "void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendLiteral(string)"
                    IL_0087:  ldloca.s   V_5
                    IL_0089:  ldloc.3
                    IL_008a:  call       "void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted<int>(int)"
                    IL_008f:  ldloca.s   V_5
                    IL_0091:  ldstr      ") "
                    IL_0096:  call       "void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendLiteral(string)"
                    IL_009b:  ldloca.s   V_5
                    IL_009d:  call       "string System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.ToStringAndClear()"
                    IL_00a2:  call       "void System.Console.Write(string)"
                    IL_00a7:  ldloc.0
                    IL_00a8:  callvirt   "System.Threading.Tasks.ValueTask<bool> System.Collections.Generic.IAsyncEnumerator<int>.MoveNextAsync()"
                    IL_00ad:  call       "bool System.Runtime.CompilerServices.AsyncHelpers.Await<bool>(System.Threading.Tasks.ValueTask<bool>)"
                    IL_00b2:  brtrue     IL_001b
                    IL_00b7:  leave.s    IL_00bc
                  }
                  catch object
                  {
                    IL_00b9:  stloc.2
                    IL_00ba:  leave.s    IL_00bc
                  }
                  IL_00bc:  ldloc.0
                  IL_00bd:  brfalse.s  IL_00ca
                  IL_00bf:  ldloc.0
                  IL_00c0:  callvirt   "System.Threading.Tasks.ValueTask System.IAsyncDisposable.DisposeAsync()"
                  IL_00c5:  call       "void System.Runtime.CompilerServices.AsyncHelpers.Await(System.Threading.Tasks.ValueTask)"
                  IL_00ca:  ldloc.2
                  IL_00cb:  brfalse.s  IL_00e2
                  IL_00cd:  ldloc.2
                  IL_00ce:  isinst     "System.Exception"
                  IL_00d3:  dup
                  IL_00d4:  brtrue.s   IL_00d8
                  IL_00d6:  ldloc.2
                  IL_00d7:  throw
                  IL_00d8:  call       "System.Runtime.ExceptionServices.ExceptionDispatchInfo System.Runtime.ExceptionServices.ExceptionDispatchInfo.Capture(System.Exception)"
                  IL_00dd:  callvirt   "void System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()"
                  IL_00e2:  ldstr      "Done"
                  IL_00e7:  call       "void System.Console.Write(string)"
                  IL_00ec:  ret
                }
                """);
        }
 
        [Fact]
        public void TestWithInterface_WithGoto()
        {
            string source = @"
using static System.Console;
using System.Collections.Generic;
using System.Threading.Tasks;
class C : IAsyncEnumerable<int>
{
    static async System.Threading.Tasks.Task Main()
    {
        await foreach (var i in new C())
        {
            if (i == 2 || i == 3) { Write($""Continue({i}) ""); continue; }
            if (i == 4) { Write(""Goto ""); goto done; }
            Write($""Got({i}) "");
        }
        done:
        Write(""Done"");
    }
    IAsyncEnumerator<int> IAsyncEnumerable<int>.GetAsyncEnumerator(System.Threading.CancellationToken token)
    {
        return new AsyncEnumerator();
    }
    sealed class AsyncEnumerator : IAsyncEnumerator<int>
    {
        int i = 0;
        public int Current
        {
            get
            {
                Write($""Current({i}) "");
                return i;
            }
        }
        public async ValueTask<bool> MoveNextAsync()
        {
            Write($""NextAsync({i}) "");
            i++;
            return await Task.FromResult(i < 10);
        }
        public async ValueTask DisposeAsync()
        {
            Write($""Disp"");
            await Task.Yield();
            Write($""ose({i}) "");
        }
    }
}";
            var comp = CreateCompilationWithTasksExtensions(source + s_IAsyncEnumerable, options: TestOptions.DebugExe);
            comp.VerifyDiagnostics();
 
            string expectedOutput = "NextAsync(0) Current(1) Got(1) NextAsync(1) Current(2) Continue(2) NextAsync(2) Current(3) Continue(3) NextAsync(3) Current(4) Goto Dispose(4) Done";
            CompileAndVerify(comp,
                expectedOutput: expectedOutput);
 
            var runtimeAsyncComp = CreateRuntimeAsyncCompilation(source);
            var verifier = CompileAndVerify(runtimeAsyncComp, expectedOutput: CodeGenAsyncTests.ExpectedOutput(expectedOutput, isRuntimeAsync: true), verify: Verification.Fails with
            {
                ILVerifyMessage = """
                    [Main]: Return value missing on the stack. { Offset = 0xfc }
                    [MoveNextAsync]: Unexpected type on the stack. { Offset = 0x5d, Found = Int32, Expected = value '[System.Runtime]System.Threading.Tasks.ValueTask`1<bool>' }
                    [DisposeAsync]: Return value missing on the stack. { Offset = 0x68 }
                    """
            });
            verifier.VerifyIL("C.Main()", """
                {
                  // Code size      253 (0xfd)
                  .maxstack  2
                  .locals init (System.Collections.Generic.IAsyncEnumerator<int> V_0,
                                System.Threading.CancellationToken V_1,
                                object V_2,
                                int V_3,
                                int V_4, //i
                                System.Runtime.CompilerServices.DefaultInterpolatedStringHandler V_5,
                                System.Runtime.CompilerServices.DefaultInterpolatedStringHandler V_6)
                  IL_0000:  newobj     "C..ctor()"
                  IL_0005:  ldloca.s   V_1
                  IL_0007:  initobj    "System.Threading.CancellationToken"
                  IL_000d:  ldloc.1
                  IL_000e:  callvirt   "System.Collections.Generic.IAsyncEnumerator<int> System.Collections.Generic.IAsyncEnumerable<int>.GetAsyncEnumerator(System.Threading.CancellationToken)"
                  IL_0013:  stloc.0
                  IL_0014:  ldnull
                  IL_0015:  stloc.2
                  IL_0016:  ldc.i4.0
                  IL_0017:  stloc.3
                  .try
                  {
                    IL_0018:  br         IL_00af
                    IL_001d:  ldloc.0
                    IL_001e:  callvirt   "int System.Collections.Generic.IAsyncEnumerator<int>.Current.get"
                    IL_0023:  stloc.s    V_4
                    IL_0025:  ldloc.s    V_4
                    IL_0027:  ldc.i4.2
                    IL_0028:  beq.s      IL_002f
                    IL_002a:  ldloc.s    V_4
                    IL_002c:  ldc.i4.3
                    IL_002d:  bne.un.s   IL_0068
                    IL_002f:  ldc.i4.s   11
                    IL_0031:  ldc.i4.1
                    IL_0032:  newobj     "System.Runtime.CompilerServices.DefaultInterpolatedStringHandler..ctor(int, int)"
                    IL_0037:  stloc.s    V_5
                    IL_0039:  ldloca.s   V_5
                    IL_003b:  ldstr      "Continue("
                    IL_0040:  call       "void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendLiteral(string)"
                    IL_0045:  ldloca.s   V_5
                    IL_0047:  ldloc.s    V_4
                    IL_0049:  call       "void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted<int>(int)"
                    IL_004e:  ldloca.s   V_5
                    IL_0050:  ldstr      ") "
                    IL_0055:  call       "void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendLiteral(string)"
                    IL_005a:  ldloca.s   V_5
                    IL_005c:  call       "string System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.ToStringAndClear()"
                    IL_0061:  call       "void System.Console.Write(string)"
                    IL_0066:  br.s       IL_00af
                    IL_0068:  ldloc.s    V_4
                    IL_006a:  ldc.i4.4
                    IL_006b:  bne.un.s   IL_0079
                    IL_006d:  ldstr      "Goto "
                    IL_0072:  call       "void System.Console.Write(string)"
                    IL_0077:  br.s       IL_00c1
                    IL_0079:  ldc.i4.6
                    IL_007a:  ldc.i4.1
                    IL_007b:  newobj     "System.Runtime.CompilerServices.DefaultInterpolatedStringHandler..ctor(int, int)"
                    IL_0080:  stloc.s    V_6
                    IL_0082:  ldloca.s   V_6
                    IL_0084:  ldstr      "Got("
                    IL_0089:  call       "void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendLiteral(string)"
                    IL_008e:  ldloca.s   V_6
                    IL_0090:  ldloc.s    V_4
                    IL_0092:  call       "void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted<int>(int)"
                    IL_0097:  ldloca.s   V_6
                    IL_0099:  ldstr      ") "
                    IL_009e:  call       "void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendLiteral(string)"
                    IL_00a3:  ldloca.s   V_6
                    IL_00a5:  call       "string System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.ToStringAndClear()"
                    IL_00aa:  call       "void System.Console.Write(string)"
                    IL_00af:  ldloc.0
                    IL_00b0:  callvirt   "System.Threading.Tasks.ValueTask<bool> System.Collections.Generic.IAsyncEnumerator<int>.MoveNextAsync()"
                    IL_00b5:  call       "bool System.Runtime.CompilerServices.AsyncHelpers.Await<bool>(System.Threading.Tasks.ValueTask<bool>)"
                    IL_00ba:  brtrue     IL_001d
                    IL_00bf:  leave.s    IL_00c8
                    IL_00c1:  ldc.i4.1
                    IL_00c2:  stloc.3
                    IL_00c3:  leave.s    IL_00c8
                  }
                  catch object
                  {
                    IL_00c5:  stloc.2
                    IL_00c6:  leave.s    IL_00c8
                  }
                  IL_00c8:  ldloc.0
                  IL_00c9:  brfalse.s  IL_00d6
                  IL_00cb:  ldloc.0
                  IL_00cc:  callvirt   "System.Threading.Tasks.ValueTask System.IAsyncDisposable.DisposeAsync()"
                  IL_00d1:  call       "void System.Runtime.CompilerServices.AsyncHelpers.Await(System.Threading.Tasks.ValueTask)"
                  IL_00d6:  ldloc.2
                  IL_00d7:  brfalse.s  IL_00ee
                  IL_00d9:  ldloc.2
                  IL_00da:  isinst     "System.Exception"
                  IL_00df:  dup
                  IL_00e0:  brtrue.s   IL_00e4
                  IL_00e2:  ldloc.2
                  IL_00e3:  throw
                  IL_00e4:  call       "System.Runtime.ExceptionServices.ExceptionDispatchInfo System.Runtime.ExceptionServices.ExceptionDispatchInfo.Capture(System.Exception)"
                  IL_00e9:  callvirt   "void System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()"
                  IL_00ee:  ldloc.3
                  IL_00ef:  ldc.i4.1
                  IL_00f0:  pop
                  IL_00f1:  pop
                  IL_00f2:  ldstr      "Done"
                  IL_00f7:  call       "void System.Console.Write(string)"
                  IL_00fc:  ret
                }
                """);
        }
 
        [Fact]
        public void TestWithInterface_WithStruct()
        {
            string source = @"
using static System.Console;
using System.Collections.Generic;
using System.Threading.Tasks;
class C : IAsyncEnumerable<int>
{
    static async Task Main()
    {
        await foreach (var i in new C())
        {
            Write($""Got({i}) "");
        }
        Write($""Done"");
    }
    IAsyncEnumerator<int> IAsyncEnumerable<int>.GetAsyncEnumerator(System.Threading.CancellationToken token)
    {
        return new AsyncEnumerator(0);
    }
    internal struct AsyncEnumerator : IAsyncEnumerator<int>
    {
        int i;
        internal AsyncEnumerator(int start) { i = start; }
        public int Current
        {
            get
            {
                Write($""Current({i}) "");
                i++;
                return i;
            }
        }
        public async ValueTask<bool> MoveNextAsync()
        {
            Write($""NextAsync({i}) "");
            bool more = await Task.FromResult(i < 4);
            i = i + 100; // Note: side-effects of async methods in structs are lost
            return more;
        }
        public async ValueTask DisposeAsync()
        {
            Write($""Dispose({i}) "");
            await Task.Yield();
        }
    }
}";
            var comp = CreateCompilationWithTasksExtensions(source + s_IAsyncEnumerable, options: TestOptions.DebugExe);
            comp.VerifyDiagnostics();
 
            string expectedOutput = "NextAsync(0) Current(0) Got(1) NextAsync(1) Current(1) Got(2) NextAsync(2) Current(2) Got(3) NextAsync(3) Current(3) Got(4) NextAsync(4) Dispose(4) Done";
            CompileAndVerify(comp,
                expectedOutput: expectedOutput);
 
            var runtimeAsyncComp = CreateRuntimeAsyncCompilation(source);
            runtimeAsyncComp.VerifyEmitDiagnostics(
                // (32,38): error CS9328: Method 'C.AsyncEnumerator.MoveNextAsync()' uses a feature that is not supported by runtime async currently. Opt the method out of runtime async by attributing it with 'System.Runtime.CompilerServices.RuntimeAsyncMethodGenerationAttribute(false)'.
                //         public async ValueTask<bool> MoveNextAsync()
                Diagnostic(ErrorCode.ERR_UnsupportedFeatureInRuntimeAsync, "MoveNextAsync").WithArguments("C.AsyncEnumerator.MoveNextAsync()").WithLocation(32, 38),
                // (39,32): error CS9328: Method 'C.AsyncEnumerator.DisposeAsync()' uses a feature that is not supported by runtime async currently. Opt the method out of runtime async by attributing it with 'System.Runtime.CompilerServices.RuntimeAsyncMethodGenerationAttribute(false)'.
                //         public async ValueTask DisposeAsync()
                Diagnostic(ErrorCode.ERR_UnsupportedFeatureInRuntimeAsync, "DisposeAsync").WithArguments("C.AsyncEnumerator.DisposeAsync()").WithLocation(39, 32)
            );
            // var verifier = CompileAndVerify(runtimeAsyncComp, expectedOutput: CodeGenAsyncTests.ExpectedOutput(expectedOutput, isRuntimeAsync: true), verify: Verification.Fails with
            // {
            //     ILVerifyMessage = """
            //         [Main]: Return value missing on the stack. { Offset = 0x96 }
            //         [MoveNextAsync]: Unexpected type on the stack. { Offset = 0x5d, Found = Int32, Expected = value '[System.Runtime]System.Threading.Tasks.ValueTask`1<bool>' }
            //         [DisposeAsync]: Return value missing on the stack. { Offset = 0x5f }
            //         """
            // });
            // verifier.VerifyIL("C.Main()", """
            //     {
            //       // Code size      151 (0x97)
            //       .maxstack  2
            //       .locals init (System.Collections.Generic.IAsyncEnumerator<int> V_0,
            //                     System.Threading.CancellationToken V_1,
            //                     object V_2,
            //                     int V_3, //i
            //                     System.Runtime.CompilerServices.DefaultInterpolatedStringHandler V_4)
            //       IL_0000:  newobj     "C..ctor()"
            //       IL_0005:  ldloca.s   V_1
            //       IL_0007:  initobj    "System.Threading.CancellationToken"
            //       IL_000d:  ldloc.1
            //       IL_000e:  callvirt   "System.Collections.Generic.IAsyncEnumerator<int> System.Collections.Generic.IAsyncEnumerable<int>.GetAsyncEnumerator(System.Threading.CancellationToken)"
            //       IL_0013:  stloc.0
            //       IL_0014:  ldnull
            //       IL_0015:  stloc.2
            //       .try
            //       {
            //         IL_0016:  br.s       IL_0054
            //         IL_0018:  ldloc.0
            //         IL_0019:  callvirt   "int System.Collections.Generic.IAsyncEnumerator<int>.Current.get"
            //         IL_001e:  stloc.3
            //         IL_001f:  ldc.i4.6
            //         IL_0020:  ldc.i4.1
            //         IL_0021:  newobj     "System.Runtime.CompilerServices.DefaultInterpolatedStringHandler..ctor(int, int)"
            //         IL_0026:  stloc.s    V_4
            //         IL_0028:  ldloca.s   V_4
            //         IL_002a:  ldstr      "Got("
            //         IL_002f:  call       "void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendLiteral(string)"
            //         IL_0034:  ldloca.s   V_4
            //         IL_0036:  ldloc.3
            //         IL_0037:  call       "void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted<int>(int)"
            //         IL_003c:  ldloca.s   V_4
            //         IL_003e:  ldstr      ") "
            //         IL_0043:  call       "void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendLiteral(string)"
            //         IL_0048:  ldloca.s   V_4
            //         IL_004a:  call       "string System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.ToStringAndClear()"
            //         IL_004f:  call       "void System.Console.Write(string)"
            //         IL_0054:  ldloc.0
            //         IL_0055:  callvirt   "System.Threading.Tasks.ValueTask<bool> System.Collections.Generic.IAsyncEnumerator<int>.MoveNextAsync()"
            //         IL_005a:  call       "bool System.Runtime.CompilerServices.AsyncHelpers.Await<bool>(System.Threading.Tasks.ValueTask<bool>)"
            //         IL_005f:  brtrue.s   IL_0018
            //         IL_0061:  leave.s    IL_0066
            //       }
            //       catch object
            //       {
            //         IL_0063:  stloc.2
            //         IL_0064:  leave.s    IL_0066
            //       }
            //       IL_0066:  ldloc.0
            //       IL_0067:  brfalse.s  IL_0074
            //       IL_0069:  ldloc.0
            //       IL_006a:  callvirt   "System.Threading.Tasks.ValueTask System.IAsyncDisposable.DisposeAsync()"
            //       IL_006f:  call       "void System.Runtime.CompilerServices.AsyncHelpers.Await(System.Threading.Tasks.ValueTask)"
            //       IL_0074:  ldloc.2
            //       IL_0075:  brfalse.s  IL_008c
            //       IL_0077:  ldloc.2
            //       IL_0078:  isinst     "System.Exception"
            //       IL_007d:  dup
            //       IL_007e:  brtrue.s   IL_0082
            //       IL_0080:  ldloc.2
            //       IL_0081:  throw
            //       IL_0082:  call       "System.Runtime.ExceptionServices.ExceptionDispatchInfo System.Runtime.ExceptionServices.ExceptionDispatchInfo.Capture(System.Exception)"
            //       IL_0087:  callvirt   "void System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()"
            //       IL_008c:  ldstr      "Done"
            //       IL_0091:  call       "void System.Console.Write(string)"
            //       IL_0096:  ret
            //     }
            //     """);
        }
 
        [Fact, WorkItem(27651, "https://github.com/dotnet/roslyn/issues/27651")]
        public void TestControlFlowAnalysis()
        {
            string source = @"
class C
{
    async System.Threading.Tasks.Task M(System.Collections.Generic.IAsyncEnumerable<int> collection)
    {
        await foreach (var item in collection) { }
    }
}";
            var comp = CreateCompilationWithTasksExtensions(source + s_IAsyncEnumerable);
            comp.VerifyDiagnostics();
 
            var tree = comp.SyntaxTrees.Single();
            var model = comp.GetSemanticModel(tree);
            var loop = tree.GetRoot().DescendantNodes().OfType<ForEachStatementSyntax>().Single();
 
            var ctrlFlowAnalysis = model.AnalyzeControlFlow(loop);
            Assert.Equal(0, ctrlFlowAnalysis.ExitPoints.Count());
        }
 
        [Fact]
        public void TestWithNullLiteralCollection()
        {
            string source = @"
using System.Collections.Generic;
using System.Threading.Tasks;
class C : IAsyncEnumerable<int>
{
    async Task M()
    {
        await foreach (var i in null)
        {
        }
    }
    IAsyncEnumerator<int> IAsyncEnumerable<int>.GetAsyncEnumerator(System.Threading.CancellationToken token)
    {
        throw null;
    }
}";
            var comp = CreateCompilationWithTasksExtensions(source + s_IAsyncEnumerable);
            comp.VerifyDiagnostics(
                // (8,33): error CS0186: Use of null is not valid in this context
                //         await foreach (var i in null)
                Diagnostic(ErrorCode.ERR_NullNotValid, "null").WithLocation(8, 33)
                );
        }
 
        [Fact]
        public void TestWithNullCollection()
        {
            string source = @"
using System.Collections.Generic;
using System.Threading.Tasks;
class C : IAsyncEnumerable<int>
{
    public static async Task Main()
    {
        C c = null;
        try
        {
            await foreach (var i in c)
            {
            }
        }
        catch (System.NullReferenceException)
        {
            System.Console.Write(""Success"");
        }
    }
    IAsyncEnumerator<int> IAsyncEnumerable<int>.GetAsyncEnumerator(System.Threading.CancellationToken token)
    {
        return new AsyncEnumerator(0);
    }
    internal struct AsyncEnumerator : IAsyncEnumerator<int>
    {
        int i;
        internal AsyncEnumerator(int start) { i = start; }
        public int Current { get => throw new System.Exception(); }
        public ValueTask<bool> MoveNextAsync() => throw new System.Exception();
        public ValueTask DisposeAsync() => throw new System.Exception();
    }
}";
            var comp = CreateCompilationWithTasksExtensions(source + s_IAsyncEnumerable, options: TestOptions.DebugExe);
            comp.VerifyDiagnostics();
            CompileAndVerify(comp, expectedOutput: "Success");
 
            var runtimeAsyncComp = CreateRuntimeAsyncCompilation(source);
            var verifier = CompileAndVerify(runtimeAsyncComp, expectedOutput: CodeGenAsyncTests.ExpectedOutput("Success", isRuntimeAsync: true), verify: Verification.Fails with
            {
                ILVerifyMessage = """
                    [Main]: Return value missing on the stack. { Offset = 0x64 }
                    """
            });
            verifier.VerifyIL("C.Main()", """
                {
                  // Code size      101 (0x65)
                  .maxstack  2
                  .locals init (C V_0, //c
                                System.Collections.Generic.IAsyncEnumerator<int> V_1,
                                System.Threading.CancellationToken V_2,
                                object V_3)
                  IL_0000:  ldnull
                  IL_0001:  stloc.0
                  .try
                  {
                    IL_0002:  ldloc.0
                    IL_0003:  ldloca.s   V_2
                    IL_0005:  initobj    "System.Threading.CancellationToken"
                    IL_000b:  ldloc.2
                    IL_000c:  callvirt   "System.Collections.Generic.IAsyncEnumerator<int> System.Collections.Generic.IAsyncEnumerable<int>.GetAsyncEnumerator(System.Threading.CancellationToken)"
                    IL_0011:  stloc.1
                    IL_0012:  ldnull
                    IL_0013:  stloc.3
                    .try
                    {
                      IL_0014:  br.s       IL_001d
                      IL_0016:  ldloc.1
                      IL_0017:  callvirt   "int System.Collections.Generic.IAsyncEnumerator<int>.Current.get"
                      IL_001c:  pop
                      IL_001d:  ldloc.1
                      IL_001e:  callvirt   "System.Threading.Tasks.ValueTask<bool> System.Collections.Generic.IAsyncEnumerator<int>.MoveNextAsync()"
                      IL_0023:  call       "bool System.Runtime.CompilerServices.AsyncHelpers.Await<bool>(System.Threading.Tasks.ValueTask<bool>)"
                      IL_0028:  brtrue.s   IL_0016
                      IL_002a:  leave.s    IL_002f
                    }
                    catch object
                    {
                      IL_002c:  stloc.3
                      IL_002d:  leave.s    IL_002f
                    }
                    IL_002f:  ldloc.1
                    IL_0030:  brfalse.s  IL_003d
                    IL_0032:  ldloc.1
                    IL_0033:  callvirt   "System.Threading.Tasks.ValueTask System.IAsyncDisposable.DisposeAsync()"
                    IL_0038:  call       "void System.Runtime.CompilerServices.AsyncHelpers.Await(System.Threading.Tasks.ValueTask)"
                    IL_003d:  ldloc.3
                    IL_003e:  brfalse.s  IL_0055
                    IL_0040:  ldloc.3
                    IL_0041:  isinst     "System.Exception"
                    IL_0046:  dup
                    IL_0047:  brtrue.s   IL_004b
                    IL_0049:  ldloc.3
                    IL_004a:  throw
                    IL_004b:  call       "System.Runtime.ExceptionServices.ExceptionDispatchInfo System.Runtime.ExceptionServices.ExceptionDispatchInfo.Capture(System.Exception)"
                    IL_0050:  callvirt   "void System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()"
                    IL_0055:  leave.s    IL_0064
                  }
                  catch System.NullReferenceException
                  {
                    IL_0057:  pop
                    IL_0058:  ldstr      "Success"
                    IL_005d:  call       "void System.Console.Write(string)"
                    IL_0062:  leave.s    IL_0064
                  }
                  IL_0064:  ret
                }
                """);
        }
 
        [Fact]
        public void TestInCatch()
        {
            string source = @"
using System.Collections.Generic;
using static System.Console;
using System.Threading.Tasks;
class C : IAsyncEnumerable<int>
{
    public static async Task Main()
    {
        try
        {
            Write($""Try "");
            throw null;
        }
        catch (System.NullReferenceException)
        {
            await foreach (var i in new C())
            {
                Write($""Got({i}) "");
            }
        }
        Write($""Done"");
    }
    IAsyncEnumerator<int> IAsyncEnumerable<int>.GetAsyncEnumerator(System.Threading.CancellationToken token)
    {
        return new AsyncEnumerator(0);
    }
    internal class AsyncEnumerator : IAsyncEnumerator<int>
    {
        int i;
        internal AsyncEnumerator(int start) { i = start; }
        public int Current
        {
            get
            {
                Write($""Current({i}) "");
                return i;
            }
        }
        public async ValueTask<bool> MoveNextAsync()
        {
            Write($""NextAsync({i}) "");
            i++;
            return await Task.FromResult(i < 4);
        }
        public async ValueTask DisposeAsync()
        {
            Write($""Disp"");
            await Task.Yield();
            Write($""ose({i}) "");
        }
    }
}";
            var comp = CreateCompilationWithTasksExtensions(source + s_IAsyncEnumerable, options: TestOptions.DebugExe);
            comp.VerifyDiagnostics();
            CompileAndVerify(comp, expectedOutput: "Try NextAsync(0) Current(1) Got(1) NextAsync(1) Current(2) Got(2) NextAsync(2) Current(3) Got(3) NextAsync(3) Dispose(4) Done");
 
            var runtimeAsyncComp = CreateRuntimeAsyncCompilation(source);
            var expectedOutput = "Try NextAsync(0) Current(1) Got(1) NextAsync(1) Current(2) Got(2) NextAsync(2) Current(3) Got(3) NextAsync(3) Dispose(4) Done";
            var verifier = CompileAndVerify(runtimeAsyncComp, expectedOutput: CodeGenAsyncTests.ExpectedOutput(expectedOutput, isRuntimeAsync: true), verify: Verification.Fails with
            {
                ILVerifyMessage = """
                    [Main]: Return value missing on the stack. { Offset = 0xb2 }
                    [MoveNextAsync]: Unexpected type on the stack. { Offset = 0x5c, Found = Int32, Expected = value '[System.Runtime]System.Threading.Tasks.ValueTask`1<bool>' }
                    [DisposeAsync]: Return value missing on the stack. { Offset = 0x68 }
                    """
            });
            verifier.VerifyIL("C.Main()", """
                {
                  // Code size      179 (0xb3)
                  .maxstack  2
                  .locals init (int V_0,
                                System.Collections.Generic.IAsyncEnumerator<int> V_1,
                                System.Threading.CancellationToken V_2,
                                object V_3,
                                int V_4, //i
                                System.Runtime.CompilerServices.DefaultInterpolatedStringHandler V_5)
                  IL_0000:  ldc.i4.0
                  IL_0001:  stloc.0
                  .try
                  {
                    IL_0002:  ldstr      "Try "
                    IL_0007:  call       "void System.Console.Write(string)"
                    IL_000c:  ldnull
                    IL_000d:  throw
                  }
                  catch System.NullReferenceException
                  {
                    IL_000e:  pop
                    IL_000f:  ldc.i4.1
                    IL_0010:  stloc.0
                    IL_0011:  leave.s    IL_0013
                  }
                  IL_0013:  ldloc.0
                  IL_0014:  ldc.i4.1
                  IL_0015:  bne.un     IL_00a8
                  IL_001a:  newobj     "C..ctor()"
                  IL_001f:  ldloca.s   V_2
                  IL_0021:  initobj    "System.Threading.CancellationToken"
                  IL_0027:  ldloc.2
                  IL_0028:  callvirt   "System.Collections.Generic.IAsyncEnumerator<int> System.Collections.Generic.IAsyncEnumerable<int>.GetAsyncEnumerator(System.Threading.CancellationToken)"
                  IL_002d:  stloc.1
                  IL_002e:  ldnull
                  IL_002f:  stloc.3
                  .try
                  {
                    IL_0030:  br.s       IL_0070
                    IL_0032:  ldloc.1
                    IL_0033:  callvirt   "int System.Collections.Generic.IAsyncEnumerator<int>.Current.get"
                    IL_0038:  stloc.s    V_4
                    IL_003a:  ldc.i4.6
                    IL_003b:  ldc.i4.1
                    IL_003c:  newobj     "System.Runtime.CompilerServices.DefaultInterpolatedStringHandler..ctor(int, int)"
                    IL_0041:  stloc.s    V_5
                    IL_0043:  ldloca.s   V_5
                    IL_0045:  ldstr      "Got("
                    IL_004a:  call       "void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendLiteral(string)"
                    IL_004f:  ldloca.s   V_5
                    IL_0051:  ldloc.s    V_4
                    IL_0053:  call       "void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted<int>(int)"
                    IL_0058:  ldloca.s   V_5
                    IL_005a:  ldstr      ") "
                    IL_005f:  call       "void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendLiteral(string)"
                    IL_0064:  ldloca.s   V_5
                    IL_0066:  call       "string System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.ToStringAndClear()"
                    IL_006b:  call       "void System.Console.Write(string)"
                    IL_0070:  ldloc.1
                    IL_0071:  callvirt   "System.Threading.Tasks.ValueTask<bool> System.Collections.Generic.IAsyncEnumerator<int>.MoveNextAsync()"
                    IL_0076:  call       "bool System.Runtime.CompilerServices.AsyncHelpers.Await<bool>(System.Threading.Tasks.ValueTask<bool>)"
                    IL_007b:  brtrue.s   IL_0032
                    IL_007d:  leave.s    IL_0082
                  }
                  catch object
                  {
                    IL_007f:  stloc.3
                    IL_0080:  leave.s    IL_0082
                  }
                  IL_0082:  ldloc.1
                  IL_0083:  brfalse.s  IL_0090
                  IL_0085:  ldloc.1
                  IL_0086:  callvirt   "System.Threading.Tasks.ValueTask System.IAsyncDisposable.DisposeAsync()"
                  IL_008b:  call       "void System.Runtime.CompilerServices.AsyncHelpers.Await(System.Threading.Tasks.ValueTask)"
                  IL_0090:  ldloc.3
                  IL_0091:  brfalse.s  IL_00a8
                  IL_0093:  ldloc.3
                  IL_0094:  isinst     "System.Exception"
                  IL_0099:  dup
                  IL_009a:  brtrue.s   IL_009e
                  IL_009c:  ldloc.3
                  IL_009d:  throw
                  IL_009e:  call       "System.Runtime.ExceptionServices.ExceptionDispatchInfo System.Runtime.ExceptionServices.ExceptionDispatchInfo.Capture(System.Exception)"
                  IL_00a3:  callvirt   "void System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()"
                  IL_00a8:  ldstr      "Done"
                  IL_00ad:  call       "void System.Console.Write(string)"
                  IL_00b2:  ret
                }
                """);
        }
 
        /// Covered in greater details by <see cref="CodeGenAsyncIteratorTests.TryFinally_AwaitForeachInFinally"/>
        [Fact]
        public void TestInFinally()
        {
            string source = @"
using System.Collections.Generic;
using System.Threading.Tasks;
class C : IAsyncEnumerable<int>
{
    public static async Task Main()
    {
        try
        {
        }
        finally
        {
            await foreach (var i in new C())
            {
            }
        }
    }
    IAsyncEnumerator<int> IAsyncEnumerable<int>.GetAsyncEnumerator(System.Threading.CancellationToken token)
    {
        throw null;
    }
}";
            var comp = CreateCompilationWithTasksExtensions(source + s_IAsyncEnumerable);
            comp.VerifyDiagnostics();
        }
 
        [Fact]
        public void TestWithConversionToElement()
        {
            string source = @"
using System.Collections.Generic;
using static System.Console;
using System.Threading.Tasks;
class C : IAsyncEnumerable<int>
{
    public static async Task Main()
    {
        await foreach (Element i in new C())
        {
            Write($""Got({i}) "");
        }
        Write($""Done"");
    }
    IAsyncEnumerator<int> IAsyncEnumerable<int>.GetAsyncEnumerator(System.Threading.CancellationToken token)
    {
        return new AsyncEnumerator(0);
    }
    internal class AsyncEnumerator : IAsyncEnumerator<int>
    {
        int i;
        internal AsyncEnumerator(int start) { i = start; }
        public int Current
        {
            get
            {
                Write($""Current({i}) "");
                return i;
            }
        }
        public async ValueTask<bool> MoveNextAsync()
        {
            Write($""NextAsync({i}) "");
            i++;
            return await Task.FromResult(i < 3);
        }
        public async ValueTask DisposeAsync()
        {
            Write($""Disp"");
            await Task.Yield();
            Write($""ose({i}) "");
        }
    }
}
class Element
{
    int i;
    public static implicit operator Element(int value) { Write($""Convert({value}) ""); return new Element(value); }
    private Element(int value) { i = value; }
    public override string ToString() => i.ToString();
}";
            var comp = CreateCompilationWithTasksExtensions(source + s_IAsyncEnumerable, options: TestOptions.DebugExe);
            comp.VerifyDiagnostics();
            CompileAndVerify(comp, expectedOutput: "NextAsync(0) Current(1) Convert(1) Got(1) NextAsync(1) Current(2) Convert(2) Got(2) NextAsync(2) Dispose(3) Done");
 
            var tree = comp.SyntaxTrees.Single();
            var model = (SyntaxTreeSemanticModel)comp.GetSemanticModel(tree, ignoreAccessibility: false);
            var foreachSyntax = tree.GetRoot().DescendantNodes().OfType<ForEachStatementSyntax>().Single();
            var info = model.GetForEachStatementInfo(foreachSyntax);
 
            Assert.Equal("System.Collections.Generic.IAsyncEnumerator<System.Int32> System.Collections.Generic.IAsyncEnumerable<System.Int32>.GetAsyncEnumerator([System.Threading.CancellationToken token = default(System.Threading.CancellationToken)])",
                info.GetEnumeratorMethod.ToTestDisplayString());
            Assert.Equal("System.Threading.Tasks.ValueTask<System.Boolean> System.Collections.Generic.IAsyncEnumerator<System.Int32>.MoveNextAsync()",
                info.MoveNextMethod.ToTestDisplayString());
            Assert.Equal("System.Int32 System.Collections.Generic.IAsyncEnumerator<System.Int32>.Current { get; }",
                info.CurrentProperty.ToTestDisplayString());
            Assert.Equal("System.Threading.Tasks.ValueTask System.IAsyncDisposable.DisposeAsync()", info.DisposeMethod.ToTestDisplayString());
            Assert.Equal("System.Int32", info.ElementType.ToTestDisplayString());
            Assert.Equal(ConversionKind.ExplicitUserDefined, info.ElementConversion.Kind);
            Assert.Equal("Element Element.op_Implicit(System.Int32 value)", info.ElementConversion.MethodSymbol.ToTestDisplayString());
            Assert.Equal(ConversionKind.Identity, info.CurrentConversion.Kind);
 
            var memberModel = model.GetMemberModel(foreachSyntax);
            var boundNode = (BoundForEachStatement)memberModel.GetUpperBoundNode(foreachSyntax);
            ForEachEnumeratorInfo internalInfo = boundNode.EnumeratorInfoOpt;
            Assert.True(internalInfo.NeedsDisposal);
 
            var runtimeAsyncComp = CreateRuntimeAsyncCompilation(source);
            var expectedOutput = "NextAsync(0) Current(1) Convert(1) Got(1) NextAsync(1) Current(2) Convert(2) Got(2) NextAsync(2) Dispose(3) Done";
            var verifier = CompileAndVerify(runtimeAsyncComp, expectedOutput: CodeGenAsyncTests.ExpectedOutput(expectedOutput, isRuntimeAsync: true), verify: Verification.Fails with
            {
                ILVerifyMessage = """
                    [Main]: Return value missing on the stack. { Offset = 0x9b }
                    [MoveNextAsync]: Unexpected type on the stack. { Offset = 0x5c, Found = Int32, Expected = value '[System.Runtime]System.Threading.Tasks.ValueTask`1<bool>' }
                    [DisposeAsync]: Return value missing on the stack. { Offset = 0x68 }
                    """
            });
            verifier.VerifyIL("C.Main()", """
                {
                  // Code size      156 (0x9c)
                  .maxstack  2
                  .locals init (System.Collections.Generic.IAsyncEnumerator<int> V_0,
                                System.Threading.CancellationToken V_1,
                                object V_2,
                                Element V_3, //i
                                System.Runtime.CompilerServices.DefaultInterpolatedStringHandler V_4)
                  IL_0000:  newobj     "C..ctor()"
                  IL_0005:  ldloca.s   V_1
                  IL_0007:  initobj    "System.Threading.CancellationToken"
                  IL_000d:  ldloc.1
                  IL_000e:  callvirt   "System.Collections.Generic.IAsyncEnumerator<int> System.Collections.Generic.IAsyncEnumerable<int>.GetAsyncEnumerator(System.Threading.CancellationToken)"
                  IL_0013:  stloc.0
                  IL_0014:  ldnull
                  IL_0015:  stloc.2
                  .try
                  {
                    IL_0016:  br.s       IL_0059
                    IL_0018:  ldloc.0
                    IL_0019:  callvirt   "int System.Collections.Generic.IAsyncEnumerator<int>.Current.get"
                    IL_001e:  call       "Element Element.op_Implicit(int)"
                    IL_0023:  stloc.3
                    IL_0024:  ldc.i4.6
                    IL_0025:  ldc.i4.1
                    IL_0026:  newobj     "System.Runtime.CompilerServices.DefaultInterpolatedStringHandler..ctor(int, int)"
                    IL_002b:  stloc.s    V_4
                    IL_002d:  ldloca.s   V_4
                    IL_002f:  ldstr      "Got("
                    IL_0034:  call       "void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendLiteral(string)"
                    IL_0039:  ldloca.s   V_4
                    IL_003b:  ldloc.3
                    IL_003c:  call       "void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted<Element>(Element)"
                    IL_0041:  ldloca.s   V_4
                    IL_0043:  ldstr      ") "
                    IL_0048:  call       "void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendLiteral(string)"
                    IL_004d:  ldloca.s   V_4
                    IL_004f:  call       "string System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.ToStringAndClear()"
                    IL_0054:  call       "void System.Console.Write(string)"
                    IL_0059:  ldloc.0
                    IL_005a:  callvirt   "System.Threading.Tasks.ValueTask<bool> System.Collections.Generic.IAsyncEnumerator<int>.MoveNextAsync()"
                    IL_005f:  call       "bool System.Runtime.CompilerServices.AsyncHelpers.Await<bool>(System.Threading.Tasks.ValueTask<bool>)"
                    IL_0064:  brtrue.s   IL_0018
                    IL_0066:  leave.s    IL_006b
                  }
                  catch object
                  {
                    IL_0068:  stloc.2
                    IL_0069:  leave.s    IL_006b
                  }
                  IL_006b:  ldloc.0
                  IL_006c:  brfalse.s  IL_0079
                  IL_006e:  ldloc.0
                  IL_006f:  callvirt   "System.Threading.Tasks.ValueTask System.IAsyncDisposable.DisposeAsync()"
                  IL_0074:  call       "void System.Runtime.CompilerServices.AsyncHelpers.Await(System.Threading.Tasks.ValueTask)"
                  IL_0079:  ldloc.2
                  IL_007a:  brfalse.s  IL_0091
                  IL_007c:  ldloc.2
                  IL_007d:  isinst     "System.Exception"
                  IL_0082:  dup
                  IL_0083:  brtrue.s   IL_0087
                  IL_0085:  ldloc.2
                  IL_0086:  throw
                  IL_0087:  call       "System.Runtime.ExceptionServices.ExceptionDispatchInfo System.Runtime.ExceptionServices.ExceptionDispatchInfo.Capture(System.Exception)"
                  IL_008c:  callvirt   "void System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()"
                  IL_0091:  ldstr      "Done"
                  IL_0096:  call       "void System.Console.Write(string)"
                  IL_009b:  ret
                }
                """);
        }
 
        [Fact]
        public void TestWithNullableCollection()
        {
            string source = @"
using static System.Console;
using System.Collections.Generic;
using System.Threading.Tasks;
struct C : IAsyncEnumerable<int>
{
    static async System.Threading.Tasks.Task Main()
    {
        C? c = new C(); // non-null value
        await foreach (var i in c)
        {
            Write($""Got({i}) "");
        }
    }
    IAsyncEnumerator<int> IAsyncEnumerable<int>.GetAsyncEnumerator(System.Threading.CancellationToken token)
    {
        return new AsyncEnumerator();
    }
    sealed class AsyncEnumerator : IAsyncEnumerator<int>
    {
        int i = 0;
        public int Current
        {
            get
            {
                Write($""Current({i}) "");
                return i;
            }
        }
        public async ValueTask<bool> MoveNextAsync()
        {
            Write($""NextAsync({i}) "");
            i++;
            return await Task.FromResult(i < 3);
        }
        public async ValueTask DisposeAsync()
        {
            Write($""Disp"");
            await Task.Yield();
            Write($""ose({i}) "");
        }
    }
}";
            var comp = CreateCompilationWithTasksExtensions(source + s_IAsyncEnumerable, options: TestOptions.DebugExe);
            comp.VerifyDiagnostics();
 
            var expectedOutput = "NextAsync(0) Current(1) Got(1) NextAsync(1) Current(2) Got(2) NextAsync(2) Dispose(3)";
            CompileAndVerify(comp, expectedOutput: expectedOutput);
 
            var tree = comp.SyntaxTrees.Single();
            var model = (SyntaxTreeSemanticModel)comp.GetSemanticModel(tree, ignoreAccessibility: false);
            var foreachSyntax = tree.GetRoot().DescendantNodes().OfType<ForEachStatementSyntax>().Single();
            var info = model.GetForEachStatementInfo(foreachSyntax);
 
            Assert.Equal("System.Collections.Generic.IAsyncEnumerator<System.Int32> System.Collections.Generic.IAsyncEnumerable<System.Int32>.GetAsyncEnumerator([System.Threading.CancellationToken token = default(System.Threading.CancellationToken)])",
                info.GetEnumeratorMethod.ToTestDisplayString());
            Assert.Equal("System.Threading.Tasks.ValueTask<System.Boolean> System.Collections.Generic.IAsyncEnumerator<System.Int32>.MoveNextAsync()",
                info.MoveNextMethod.ToTestDisplayString());
            Assert.Equal("System.Int32 System.Collections.Generic.IAsyncEnumerator<System.Int32>.Current { get; }",
                info.CurrentProperty.ToTestDisplayString());
            Assert.Equal("System.Threading.Tasks.ValueTask System.IAsyncDisposable.DisposeAsync()", info.DisposeMethod.ToTestDisplayString());
            Assert.Equal("System.Int32", info.ElementType.ToTestDisplayString());
            Assert.Equal(ConversionKind.Identity, info.ElementConversion.Kind);
            Assert.Equal(ConversionKind.Identity, info.CurrentConversion.Kind);
 
            var memberModel = model.GetMemberModel(foreachSyntax);
            var boundNode = (BoundForEachStatement)memberModel.GetUpperBoundNode(foreachSyntax);
            ForEachEnumeratorInfo internalInfo = boundNode.EnumeratorInfoOpt;
            Assert.True(internalInfo.NeedsDisposal);
 
            var runtimeAsyncComp = CreateRuntimeAsyncCompilation(source);
            var verifier = CompileAndVerify(runtimeAsyncComp, expectedOutput: CodeGenAsyncTests.ExpectedOutput(expectedOutput, isRuntimeAsync: true), verify: Verification.Fails with
            {
                ILVerifyMessage = """
                    [Main]: Return value missing on the stack. { Offset = 0xae }
                    [MoveNextAsync]: Unexpected type on the stack. { Offset = 0x5c, Found = Int32, Expected = value '[System.Runtime]System.Threading.Tasks.ValueTask`1<bool>' }
                    [DisposeAsync]: Return value missing on the stack. { Offset = 0x68 }
                    """
            });
            verifier.VerifyIL("C.Main()", """
                {
                  // Code size      175 (0xaf)
                  .maxstack  2
                  .locals init (C? V_0, //c
                                C V_1,
                                System.Collections.Generic.IAsyncEnumerator<int> V_2,
                                System.Threading.CancellationToken V_3,
                                object V_4,
                                int V_5, //i
                                System.Runtime.CompilerServices.DefaultInterpolatedStringHandler V_6)
                  IL_0000:  ldloca.s   V_0
                  IL_0002:  ldloca.s   V_1
                  IL_0004:  initobj    "C"
                  IL_000a:  ldloc.1
                  IL_000b:  call       "C?..ctor(C)"
                  IL_0010:  ldloca.s   V_0
                  IL_0012:  call       "readonly C C?.Value.get"
                  IL_0017:  stloc.1
                  IL_0018:  ldloca.s   V_1
                  IL_001a:  ldloca.s   V_3
                  IL_001c:  initobj    "System.Threading.CancellationToken"
                  IL_0022:  ldloc.3
                  IL_0023:  constrained. "C"
                  IL_0029:  callvirt   "System.Collections.Generic.IAsyncEnumerator<int> System.Collections.Generic.IAsyncEnumerable<int>.GetAsyncEnumerator(System.Threading.CancellationToken)"
                  IL_002e:  stloc.2
                  IL_002f:  ldnull
                  IL_0030:  stloc.s    V_4
                  .try
                  {
                    IL_0032:  br.s       IL_0072
                    IL_0034:  ldloc.2
                    IL_0035:  callvirt   "int System.Collections.Generic.IAsyncEnumerator<int>.Current.get"
                    IL_003a:  stloc.s    V_5
                    IL_003c:  ldc.i4.6
                    IL_003d:  ldc.i4.1
                    IL_003e:  newobj     "System.Runtime.CompilerServices.DefaultInterpolatedStringHandler..ctor(int, int)"
                    IL_0043:  stloc.s    V_6
                    IL_0045:  ldloca.s   V_6
                    IL_0047:  ldstr      "Got("
                    IL_004c:  call       "void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendLiteral(string)"
                    IL_0051:  ldloca.s   V_6
                    IL_0053:  ldloc.s    V_5
                    IL_0055:  call       "void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted<int>(int)"
                    IL_005a:  ldloca.s   V_6
                    IL_005c:  ldstr      ") "
                    IL_0061:  call       "void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendLiteral(string)"
                    IL_0066:  ldloca.s   V_6
                    IL_0068:  call       "string System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.ToStringAndClear()"
                    IL_006d:  call       "void System.Console.Write(string)"
                    IL_0072:  ldloc.2
                    IL_0073:  callvirt   "System.Threading.Tasks.ValueTask<bool> System.Collections.Generic.IAsyncEnumerator<int>.MoveNextAsync()"
                    IL_0078:  call       "bool System.Runtime.CompilerServices.AsyncHelpers.Await<bool>(System.Threading.Tasks.ValueTask<bool>)"
                    IL_007d:  brtrue.s   IL_0034
                    IL_007f:  leave.s    IL_0085
                  }
                  catch object
                  {
                    IL_0081:  stloc.s    V_4
                    IL_0083:  leave.s    IL_0085
                  }
                  IL_0085:  ldloc.2
                  IL_0086:  brfalse.s  IL_0093
                  IL_0088:  ldloc.2
                  IL_0089:  callvirt   "System.Threading.Tasks.ValueTask System.IAsyncDisposable.DisposeAsync()"
                  IL_008e:  call       "void System.Runtime.CompilerServices.AsyncHelpers.Await(System.Threading.Tasks.ValueTask)"
                  IL_0093:  ldloc.s    V_4
                  IL_0095:  brfalse.s  IL_00ae
                  IL_0097:  ldloc.s    V_4
                  IL_0099:  isinst     "System.Exception"
                  IL_009e:  dup
                  IL_009f:  brtrue.s   IL_00a4
                  IL_00a1:  ldloc.s    V_4
                  IL_00a3:  throw
                  IL_00a4:  call       "System.Runtime.ExceptionServices.ExceptionDispatchInfo System.Runtime.ExceptionServices.ExceptionDispatchInfo.Capture(System.Exception)"
                  IL_00a9:  callvirt   "void System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()"
                  IL_00ae:  ret
                }
                """);
        }
 
        [Fact]
        public void TestWithNullableCollection2()
        {
            string source = @"
using static System.Console;
using System.Collections.Generic;
using System.Threading.Tasks;
struct C : IAsyncEnumerable<int>
{
    static async Task Main()
    {
        C? c = null; // null value
        try
        {
            await foreach (var i in c)
            {
                Write($""UNREACHABLE"");
            }
        }
        catch (System.InvalidOperationException)
        {
            Write($""Success"");
        }
    }
    IAsyncEnumerator<int> IAsyncEnumerable<int>.GetAsyncEnumerator(System.Threading.CancellationToken token)
    {
        throw new System.Exception();
    }
}";
            var comp = CreateCompilationWithTasksExtensions(source + s_IAsyncEnumerable, options: TestOptions.DebugExe);
            comp.VerifyDiagnostics();
            CompileAndVerify(comp, expectedOutput: "Success");
 
            var runtimeAsyncComp = CreateRuntimeAsyncCompilation(source);
            var verifier = CompileAndVerify(runtimeAsyncComp, expectedOutput: CodeGenAsyncTests.ExpectedOutput("Success", isRuntimeAsync: true), verify: Verification.Fails with
            {
                ILVerifyMessage = """
                    [Main]: Return value missing on the stack. { Offset = 0x88 }
                    """
            });
            verifier.VerifyIL("C.Main()", """
                {
                  // Code size      137 (0x89)
                  .maxstack  2
                  .locals init (C? V_0, //c
                                System.Collections.Generic.IAsyncEnumerator<int> V_1,
                                C V_2,
                                System.Threading.CancellationToken V_3,
                                object V_4)
                  IL_0000:  ldloca.s   V_0
                  IL_0002:  initobj    "C?"
                  .try
                  {
                    IL_0008:  ldloca.s   V_0
                    IL_000a:  call       "readonly C C?.Value.get"
                    IL_000f:  stloc.2
                    IL_0010:  ldloca.s   V_2
                    IL_0012:  ldloca.s   V_3
                    IL_0014:  initobj    "System.Threading.CancellationToken"
                    IL_001a:  ldloc.3
                    IL_001b:  constrained. "C"
                    IL_0021:  callvirt   "System.Collections.Generic.IAsyncEnumerator<int> System.Collections.Generic.IAsyncEnumerable<int>.GetAsyncEnumerator(System.Threading.CancellationToken)"
                    IL_0026:  stloc.1
                    IL_0027:  ldnull
                    IL_0028:  stloc.s    V_4
                    .try
                    {
                      IL_002a:  br.s       IL_003d
                      IL_002c:  ldloc.1
                      IL_002d:  callvirt   "int System.Collections.Generic.IAsyncEnumerator<int>.Current.get"
                      IL_0032:  pop
                      IL_0033:  ldstr      "UNREACHABLE"
                      IL_0038:  call       "void System.Console.Write(string)"
                      IL_003d:  ldloc.1
                      IL_003e:  callvirt   "System.Threading.Tasks.ValueTask<bool> System.Collections.Generic.IAsyncEnumerator<int>.MoveNextAsync()"
                      IL_0043:  call       "bool System.Runtime.CompilerServices.AsyncHelpers.Await<bool>(System.Threading.Tasks.ValueTask<bool>)"
                      IL_0048:  brtrue.s   IL_002c
                      IL_004a:  leave.s    IL_0050
                    }
                    catch object
                    {
                      IL_004c:  stloc.s    V_4
                      IL_004e:  leave.s    IL_0050
                    }
                    IL_0050:  ldloc.1
                    IL_0051:  brfalse.s  IL_005e
                    IL_0053:  ldloc.1
                    IL_0054:  callvirt   "System.Threading.Tasks.ValueTask System.IAsyncDisposable.DisposeAsync()"
                    IL_0059:  call       "void System.Runtime.CompilerServices.AsyncHelpers.Await(System.Threading.Tasks.ValueTask)"
                    IL_005e:  ldloc.s    V_4
                    IL_0060:  brfalse.s  IL_0079
                    IL_0062:  ldloc.s    V_4
                    IL_0064:  isinst     "System.Exception"
                    IL_0069:  dup
                    IL_006a:  brtrue.s   IL_006f
                    IL_006c:  ldloc.s    V_4
                    IL_006e:  throw
                    IL_006f:  call       "System.Runtime.ExceptionServices.ExceptionDispatchInfo System.Runtime.ExceptionServices.ExceptionDispatchInfo.Capture(System.Exception)"
                    IL_0074:  callvirt   "void System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()"
                    IL_0079:  leave.s    IL_0088
                  }
                  catch System.InvalidOperationException
                  {
                    IL_007b:  pop
                    IL_007c:  ldstr      "Success"
                    IL_0081:  call       "void System.Console.Write(string)"
                    IL_0086:  leave.s    IL_0088
                  }
                  IL_0088:  ret
                }
                """);
        }
 
        [Fact]
        public void TestWithInterfaceAndDeconstruction()
        {
            string source = @"
using static System.Console;
using System.Collections.Generic;
using System.Threading.Tasks;
class C : IAsyncEnumerable<int>
{
    static async System.Threading.Tasks.Task Main()
    {
        await foreach (var (i, j) in new C())
        {
            Write($""Got({i},{j}) "");
        }
        Write($""Done"");
    }
    IAsyncEnumerator<int> IAsyncEnumerable<int>.GetAsyncEnumerator(System.Threading.CancellationToken token)
    {
        return new AsyncEnumerator();
    }
    sealed class AsyncEnumerator : IAsyncEnumerator<int>
    {
        int i = 0;
        public int Current
        {
            get
            {
                Write($""Current({i}) "");
                return i;
            }
        }
        public async ValueTask<bool> MoveNextAsync()
        {
            Write($""NextAsync({i}) "");
            i++;
            return await Task.FromResult(i < 3);
        }
        public async ValueTask DisposeAsync()
        {
            Write($""Dispose({i}) "");
            await Task.Yield();
        }
    }
}
public static class Extensions
{
    public static void Deconstruct(this int i, out string x1, out int x2) { Write($""Deconstruct({i}) ""); x1 = i.ToString(); x2 = -i; }
}";
            var comp = CreateCompilationWithTasksExtensions(source + s_IAsyncEnumerable, options: TestOptions.DebugExe);
            comp.VerifyDiagnostics();
 
            var expectedOutput = "NextAsync(0) Current(1) Deconstruct(1) Got(1,-1) NextAsync(1) Current(2) Deconstruct(2) Got(2,-2) NextAsync(2) Dispose(3) Done";
            CompileAndVerify(comp, expectedOutput: expectedOutput);
 
            var tree = comp.SyntaxTrees.Single();
            var model = (SyntaxTreeSemanticModel)comp.GetSemanticModel(tree, ignoreAccessibility: false);
            var foreachSyntax = tree.GetRoot().DescendantNodes().OfType<ForEachVariableStatementSyntax>().Single();
            var info = model.GetForEachStatementInfo(foreachSyntax);
 
            Assert.Equal("System.Collections.Generic.IAsyncEnumerator<System.Int32> System.Collections.Generic.IAsyncEnumerable<System.Int32>.GetAsyncEnumerator([System.Threading.CancellationToken token = default(System.Threading.CancellationToken)])",
                info.GetEnumeratorMethod.ToTestDisplayString());
            Assert.Equal("System.Threading.Tasks.ValueTask<System.Boolean> System.Collections.Generic.IAsyncEnumerator<System.Int32>.MoveNextAsync()",
                info.MoveNextMethod.ToTestDisplayString());
            Assert.Equal("System.Int32 System.Collections.Generic.IAsyncEnumerator<System.Int32>.Current { get; }",
                info.CurrentProperty.ToTestDisplayString());
            Assert.Equal("System.Threading.Tasks.ValueTask System.IAsyncDisposable.DisposeAsync()", info.DisposeMethod.ToTestDisplayString());
            Assert.Equal("System.Int32", info.ElementType.ToTestDisplayString());
            Assert.Equal(ConversionKind.Identity, info.ElementConversion.Kind);
            Assert.Equal(ConversionKind.Identity, info.CurrentConversion.Kind);
 
            var memberModel = model.GetMemberModel(foreachSyntax);
            var boundNode = (BoundForEachStatement)memberModel.GetUpperBoundNode(foreachSyntax);
            ForEachEnumeratorInfo internalInfo = boundNode.EnumeratorInfoOpt;
            Assert.True(internalInfo.NeedsDisposal);
 
            var runtimeAsyncComp = CreateRuntimeAsyncCompilation(source);
            var verifier = CompileAndVerify(runtimeAsyncComp, expectedOutput: CodeGenAsyncTests.ExpectedOutput(expectedOutput, isRuntimeAsync: true), verify: Verification.Fails with
            {
                ILVerifyMessage = """
                    [Main]: Return value missing on the stack. { Offset = 0xba }
                    [MoveNextAsync]: Unexpected type on the stack. { Offset = 0x5c, Found = Int32, Expected = value '[System.Runtime]System.Threading.Tasks.ValueTask`1<bool>' }
                    [DisposeAsync]: Return value missing on the stack. { Offset = 0x5f }
                    """
            });
            verifier.VerifyIL("C.Main()", """
                {
                  // Code size      187 (0xbb)
                  .maxstack  3
                  .locals init (System.Collections.Generic.IAsyncEnumerator<int> V_0,
                                System.Threading.CancellationToken V_1,
                                object V_2,
                                string V_3, //i
                                int V_4, //j
                                string V_5,
                                int V_6,
                                System.Runtime.CompilerServices.DefaultInterpolatedStringHandler V_7)
                  IL_0000:  newobj     "C..ctor()"
                  IL_0005:  ldloca.s   V_1
                  IL_0007:  initobj    "System.Threading.CancellationToken"
                  IL_000d:  ldloc.1
                  IL_000e:  callvirt   "System.Collections.Generic.IAsyncEnumerator<int> System.Collections.Generic.IAsyncEnumerable<int>.GetAsyncEnumerator(System.Threading.CancellationToken)"
                  IL_0013:  stloc.0
                  IL_0014:  ldnull
                  IL_0015:  stloc.2
                  .try
                  {
                    IL_0016:  br.s       IL_0078
                    IL_0018:  ldloc.0
                    IL_0019:  callvirt   "int System.Collections.Generic.IAsyncEnumerator<int>.Current.get"
                    IL_001e:  ldloca.s   V_5
                    IL_0020:  ldloca.s   V_6
                    IL_0022:  call       "void Extensions.Deconstruct(int, out string, out int)"
                    IL_0027:  ldloc.s    V_5
                    IL_0029:  stloc.3
                    IL_002a:  ldloc.s    V_6
                    IL_002c:  stloc.s    V_4
                    IL_002e:  ldc.i4.7
                    IL_002f:  ldc.i4.2
                    IL_0030:  newobj     "System.Runtime.CompilerServices.DefaultInterpolatedStringHandler..ctor(int, int)"
                    IL_0035:  stloc.s    V_7
                    IL_0037:  ldloca.s   V_7
                    IL_0039:  ldstr      "Got("
                    IL_003e:  call       "void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendLiteral(string)"
                    IL_0043:  ldloca.s   V_7
                    IL_0045:  ldloc.3
                    IL_0046:  call       "void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted(string)"
                    IL_004b:  ldloca.s   V_7
                    IL_004d:  ldstr      ","
                    IL_0052:  call       "void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendLiteral(string)"
                    IL_0057:  ldloca.s   V_7
                    IL_0059:  ldloc.s    V_4
                    IL_005b:  call       "void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted<int>(int)"
                    IL_0060:  ldloca.s   V_7
                    IL_0062:  ldstr      ") "
                    IL_0067:  call       "void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendLiteral(string)"
                    IL_006c:  ldloca.s   V_7
                    IL_006e:  call       "string System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.ToStringAndClear()"
                    IL_0073:  call       "void System.Console.Write(string)"
                    IL_0078:  ldloc.0
                    IL_0079:  callvirt   "System.Threading.Tasks.ValueTask<bool> System.Collections.Generic.IAsyncEnumerator<int>.MoveNextAsync()"
                    IL_007e:  call       "bool System.Runtime.CompilerServices.AsyncHelpers.Await<bool>(System.Threading.Tasks.ValueTask<bool>)"
                    IL_0083:  brtrue.s   IL_0018
                    IL_0085:  leave.s    IL_008a
                  }
                  catch object
                  {
                    IL_0087:  stloc.2
                    IL_0088:  leave.s    IL_008a
                  }
                  IL_008a:  ldloc.0
                  IL_008b:  brfalse.s  IL_0098
                  IL_008d:  ldloc.0
                  IL_008e:  callvirt   "System.Threading.Tasks.ValueTask System.IAsyncDisposable.DisposeAsync()"
                  IL_0093:  call       "void System.Runtime.CompilerServices.AsyncHelpers.Await(System.Threading.Tasks.ValueTask)"
                  IL_0098:  ldloc.2
                  IL_0099:  brfalse.s  IL_00b0
                  IL_009b:  ldloc.2
                  IL_009c:  isinst     "System.Exception"
                  IL_00a1:  dup
                  IL_00a2:  brtrue.s   IL_00a6
                  IL_00a4:  ldloc.2
                  IL_00a5:  throw
                  IL_00a6:  call       "System.Runtime.ExceptionServices.ExceptionDispatchInfo System.Runtime.ExceptionServices.ExceptionDispatchInfo.Capture(System.Exception)"
                  IL_00ab:  callvirt   "void System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()"
                  IL_00b0:  ldstr      "Done"
                  IL_00b5:  call       "void System.Console.Write(string)"
                  IL_00ba:  ret
                }
                """);
        }
 
        [Fact]
        public void TestWithDeconstructionInNonAsyncMethod()
        {
            string source = @"
using System.Collections.Generic;
class C : IAsyncEnumerable<int>
{
    static void Main()
    {
        await foreach (var (i, j) in new C())
        {
        }
    }
    IAsyncEnumerator<int> IAsyncEnumerable<int>.GetAsyncEnumerator(System.Threading.CancellationToken token)
        => throw null;
}
public static class Extensions
{
    public static void Deconstruct(this int i, out int x1, out int x2) { x1 = i; x2 = -i; }
}";
            var comp = CreateCompilationWithTasksExtensions(source + s_IAsyncEnumerable);
            comp.VerifyDiagnostics(
                // (7,9): error CS4033: The 'await' operator can only be used within an async method. Consider marking this method with the 'async' modifier and changing its return type to 'Task'.
                //         await foreach (var (i, j) in new C())
                Diagnostic(ErrorCode.ERR_BadAwaitWithoutVoidAsyncMethod, "await").WithLocation(7, 9)
                );
        }
 
        [Fact]
        public void TestWithPatternAndDeconstructionOfTuple()
        {
            string source = @"
using static System.Console;
using System.Collections.Generic;
using System.Threading.Tasks;
class C : IAsyncEnumerable<(string, int)>
{
    public static async System.Threading.Tasks.Task Main()
    {
        await foreach (var (i, j) in new C())
        {
            Write($""Got({i},{j}) "");
        }
        Write($""Done"");
    }
    IAsyncEnumerator<(string, int)> IAsyncEnumerable<(string, int)>.GetAsyncEnumerator(System.Threading.CancellationToken token)
    {
        return new AsyncEnumerator();
    }
    sealed class AsyncEnumerator : IAsyncEnumerator<(string, int)>
    {
        int i = 0;
        public (string, int) Current
        {
            get
            {
                Write($""Current({i}) "");
                return (i.ToString(), -i);
            }
        }
        public async ValueTask<bool> MoveNextAsync()
        {
            Write($""NextAsync({i}) "");
            i++;
            return await Task.FromResult(i < 3);
        }
        public async ValueTask DisposeAsync()
        {
            Write($""Dispose({i}) "");
            await Task.Yield();
        }
    }
}";
            var comp = CreateCompilationWithTasksExtensions(source + s_IAsyncEnumerable, options: TestOptions.DebugExe);
            comp.VerifyDiagnostics();
            var expectedOutput = "NextAsync(0) Current(1) Got(1,-1) NextAsync(1) Current(2) Got(2,-2) NextAsync(2) Dispose(3) Done";
            CompileAndVerify(comp, expectedOutput: expectedOutput);
 
            var tree = comp.SyntaxTrees.Single();
            var model = comp.GetSemanticModel(tree, ignoreAccessibility: false);
            var foreachSyntax = tree.GetRoot().DescendantNodes().OfType<ForEachVariableStatementSyntax>().Single();
            var info = model.GetForEachStatementInfo(foreachSyntax);
 
            Assert.Equal("System.Collections.Generic.IAsyncEnumerator<(System.String, System.Int32)> System.Collections.Generic.IAsyncEnumerable<(System.String, System.Int32)>.GetAsyncEnumerator([System.Threading.CancellationToken token = default(System.Threading.CancellationToken)])",
                info.GetEnumeratorMethod.ToTestDisplayString());
            Assert.Equal("System.Threading.Tasks.ValueTask<System.Boolean> System.Collections.Generic.IAsyncEnumerator<(System.String, System.Int32)>.MoveNextAsync()",
                info.MoveNextMethod.ToTestDisplayString());
            Assert.Equal("(System.String, System.Int32) System.Collections.Generic.IAsyncEnumerator<(System.String, System.Int32)>.Current { get; }",
                info.CurrentProperty.ToTestDisplayString());
            Assert.Equal("System.Threading.Tasks.ValueTask System.IAsyncDisposable.DisposeAsync()", info.DisposeMethod.ToTestDisplayString());
            Assert.Equal("(System.String, System.Int32)", info.ElementType.ToTestDisplayString());
            Assert.Equal(ConversionKind.Identity, info.ElementConversion.Kind);
            Assert.Equal(ConversionKind.Identity, info.CurrentConversion.Kind);
 
            var runtimeAsyncComp = CreateRuntimeAsyncCompilation(source);
            var verifier = CompileAndVerify(runtimeAsyncComp, expectedOutput: CodeGenAsyncTests.ExpectedOutput(expectedOutput, isRuntimeAsync: true), verify: Verification.Fails with
            {
                ILVerifyMessage = """
                    [Main]: Return value missing on the stack. { Offset = 0xb8 }
                    [MoveNextAsync]: Unexpected type on the stack. { Offset = 0x5c, Found = Int32, Expected = value '[System.Runtime]System.Threading.Tasks.ValueTask`1<bool>' }
                    [DisposeAsync]: Return value missing on the stack. { Offset = 0x5f }
                    """
            });
            verifier.VerifyIL("C.Main()", """
                {
                  // Code size      185 (0xb9)
                  .maxstack  2
                  .locals init (System.Collections.Generic.IAsyncEnumerator<System.ValueTuple<string, int>> V_0,
                                System.Threading.CancellationToken V_1,
                                object V_2,
                                string V_3, //i
                                int V_4, //j
                                System.Runtime.CompilerServices.DefaultInterpolatedStringHandler V_5)
                  IL_0000:  newobj     "C..ctor()"
                  IL_0005:  ldloca.s   V_1
                  IL_0007:  initobj    "System.Threading.CancellationToken"
                  IL_000d:  ldloc.1
                  IL_000e:  callvirt   "System.Collections.Generic.IAsyncEnumerator<System.ValueTuple<string, int>> System.Collections.Generic.IAsyncEnumerable<System.ValueTuple<string, int>>.GetAsyncEnumerator(System.Threading.CancellationToken)"
                  IL_0013:  stloc.0
                  IL_0014:  ldnull
                  IL_0015:  stloc.2
                  .try
                  {
                    IL_0016:  br.s       IL_0076
                    IL_0018:  ldloc.0
                    IL_0019:  callvirt   "System.ValueTuple<string, int> System.Collections.Generic.IAsyncEnumerator<System.ValueTuple<string, int>>.Current.get"
                    IL_001e:  dup
                    IL_001f:  ldfld      "string System.ValueTuple<string, int>.Item1"
                    IL_0024:  stloc.3
                    IL_0025:  ldfld      "int System.ValueTuple<string, int>.Item2"
                    IL_002a:  stloc.s    V_4
                    IL_002c:  ldc.i4.7
                    IL_002d:  ldc.i4.2
                    IL_002e:  newobj     "System.Runtime.CompilerServices.DefaultInterpolatedStringHandler..ctor(int, int)"
                    IL_0033:  stloc.s    V_5
                    IL_0035:  ldloca.s   V_5
                    IL_0037:  ldstr      "Got("
                    IL_003c:  call       "void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendLiteral(string)"
                    IL_0041:  ldloca.s   V_5
                    IL_0043:  ldloc.3
                    IL_0044:  call       "void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted(string)"
                    IL_0049:  ldloca.s   V_5
                    IL_004b:  ldstr      ","
                    IL_0050:  call       "void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendLiteral(string)"
                    IL_0055:  ldloca.s   V_5
                    IL_0057:  ldloc.s    V_4
                    IL_0059:  call       "void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted<int>(int)"
                    IL_005e:  ldloca.s   V_5
                    IL_0060:  ldstr      ") "
                    IL_0065:  call       "void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendLiteral(string)"
                    IL_006a:  ldloca.s   V_5
                    IL_006c:  call       "string System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.ToStringAndClear()"
                    IL_0071:  call       "void System.Console.Write(string)"
                    IL_0076:  ldloc.0
                    IL_0077:  callvirt   "System.Threading.Tasks.ValueTask<bool> System.Collections.Generic.IAsyncEnumerator<System.ValueTuple<string, int>>.MoveNextAsync()"
                    IL_007c:  call       "bool System.Runtime.CompilerServices.AsyncHelpers.Await<bool>(System.Threading.Tasks.ValueTask<bool>)"
                    IL_0081:  brtrue.s   IL_0018
                    IL_0083:  leave.s    IL_0088
                  }
                  catch object
                  {
                    IL_0085:  stloc.2
                    IL_0086:  leave.s    IL_0088
                  }
                  IL_0088:  ldloc.0
                  IL_0089:  brfalse.s  IL_0096
                  IL_008b:  ldloc.0
                  IL_008c:  callvirt   "System.Threading.Tasks.ValueTask System.IAsyncDisposable.DisposeAsync()"
                  IL_0091:  call       "void System.Runtime.CompilerServices.AsyncHelpers.Await(System.Threading.Tasks.ValueTask)"
                  IL_0096:  ldloc.2
                  IL_0097:  brfalse.s  IL_00ae
                  IL_0099:  ldloc.2
                  IL_009a:  isinst     "System.Exception"
                  IL_009f:  dup
                  IL_00a0:  brtrue.s   IL_00a4
                  IL_00a2:  ldloc.2
                  IL_00a3:  throw
                  IL_00a4:  call       "System.Runtime.ExceptionServices.ExceptionDispatchInfo System.Runtime.ExceptionServices.ExceptionDispatchInfo.Capture(System.Exception)"
                  IL_00a9:  callvirt   "void System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()"
                  IL_00ae:  ldstr      "Done"
                  IL_00b3:  call       "void System.Console.Write(string)"
                  IL_00b8:  ret
                }
                """);
        }
 
        [Fact]
        public void TestWithInterfaceAndDeconstruction_ManualIteration()
        {
            string source = @"
using static System.Console;
using System.Collections.Generic;
using System.Threading.Tasks;
class C : IAsyncEnumerable<int>
{
    static async Task Main()
    {
        var e = ((IAsyncEnumerable<int>)new C()).GetAsyncEnumerator();
        try
        {
            while (await e.MoveNextAsync())
            {
                (int i, int j) = e.Current;
                Write($""Got({i},{j}) "");
            }
        }
        finally { await e.DisposeAsync(); }
 
        Write($""Done"");
    }
    IAsyncEnumerator<int> IAsyncEnumerable<int>.GetAsyncEnumerator(System.Threading.CancellationToken token)
    {
        return new AsyncEnumerator(0);
    }
    internal class AsyncEnumerator : IAsyncEnumerator<int>
    {
        int i;
        internal AsyncEnumerator(int start) { i = start; }
        public int Current
        {
            get
            {
                Write($""Current({i}) "");
                return i;
            }
        }
        public async ValueTask<bool> MoveNextAsync()
        {
            Write($""NextAsync({i}) "");
            i++;
            return await Task.FromResult(i < 3);
        }
        public async ValueTask DisposeAsync()
        {
            Write($""Disp"");
            await Task.Yield();
            Write($""ose({i}) "");
        }
    }
}
public static class Extensions
{
    public static void Deconstruct(this int i, out int x1, out int x2) { x1 = i; x2 = -i; }
}";
            var comp = CreateCompilationWithTasksExtensions(source + s_IAsyncEnumerable, options: TestOptions.DebugExe);
            comp.VerifyDiagnostics();
 
            string expectedOutput = "NextAsync(0) Current(1) Got(1,-1) NextAsync(1) Current(2) Got(2,-2) NextAsync(2) Dispose(3) Done";
            CompileAndVerify(comp, expectedOutput: expectedOutput);
 
            var runtimeAsyncComp = CreateRuntimeAsyncCompilation(source);
            var verifier = CompileAndVerify(runtimeAsyncComp, expectedOutput: CodeGenAsyncTests.ExpectedOutput(expectedOutput, isRuntimeAsync: true), verify: Verification.Fails with
            {
                ILVerifyMessage = """
                    [Main]: Return value missing on the stack. { Offset = 0xb7 }
                    [MoveNextAsync]: Unexpected type on the stack. { Offset = 0x5c, Found = Int32, Expected = value '[System.Runtime]System.Threading.Tasks.ValueTask`1<bool>' }
                    [DisposeAsync]: Return value missing on the stack. { Offset = 0x68 }
                    """
            });
            verifier.VerifyIL("C.Main()", """
                {
                  // Code size      184 (0xb8)
                  .maxstack  3
                  .locals init (System.Collections.Generic.IAsyncEnumerator<int> V_0, //e
                                System.Threading.CancellationToken V_1,
                                object V_2,
                                int V_3, //i
                                int V_4, //j
                                int V_5,
                                int V_6,
                                System.Runtime.CompilerServices.DefaultInterpolatedStringHandler V_7)
                  IL_0000:  newobj     "C..ctor()"
                  IL_0005:  ldloca.s   V_1
                  IL_0007:  initobj    "System.Threading.CancellationToken"
                  IL_000d:  ldloc.1
                  IL_000e:  callvirt   "System.Collections.Generic.IAsyncEnumerator<int> System.Collections.Generic.IAsyncEnumerable<int>.GetAsyncEnumerator(System.Threading.CancellationToken)"
                  IL_0013:  stloc.0
                  IL_0014:  ldnull
                  IL_0015:  stloc.2
                  .try
                  {
                    IL_0016:  br.s       IL_0078
                    IL_0018:  ldloc.0
                    IL_0019:  callvirt   "int System.Collections.Generic.IAsyncEnumerator<int>.Current.get"
                    IL_001e:  ldloca.s   V_5
                    IL_0020:  ldloca.s   V_6
                    IL_0022:  call       "void Extensions.Deconstruct(int, out int, out int)"
                    IL_0027:  ldloc.s    V_5
                    IL_0029:  stloc.3
                    IL_002a:  ldloc.s    V_6
                    IL_002c:  stloc.s    V_4
                    IL_002e:  ldc.i4.7
                    IL_002f:  ldc.i4.2
                    IL_0030:  newobj     "System.Runtime.CompilerServices.DefaultInterpolatedStringHandler..ctor(int, int)"
                    IL_0035:  stloc.s    V_7
                    IL_0037:  ldloca.s   V_7
                    IL_0039:  ldstr      "Got("
                    IL_003e:  call       "void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendLiteral(string)"
                    IL_0043:  ldloca.s   V_7
                    IL_0045:  ldloc.3
                    IL_0046:  call       "void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted<int>(int)"
                    IL_004b:  ldloca.s   V_7
                    IL_004d:  ldstr      ","
                    IL_0052:  call       "void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendLiteral(string)"
                    IL_0057:  ldloca.s   V_7
                    IL_0059:  ldloc.s    V_4
                    IL_005b:  call       "void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted<int>(int)"
                    IL_0060:  ldloca.s   V_7
                    IL_0062:  ldstr      ") "
                    IL_0067:  call       "void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendLiteral(string)"
                    IL_006c:  ldloca.s   V_7
                    IL_006e:  call       "string System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.ToStringAndClear()"
                    IL_0073:  call       "void System.Console.Write(string)"
                    IL_0078:  ldloc.0
                    IL_0079:  callvirt   "System.Threading.Tasks.ValueTask<bool> System.Collections.Generic.IAsyncEnumerator<int>.MoveNextAsync()"
                    IL_007e:  call       "bool System.Runtime.CompilerServices.AsyncHelpers.Await<bool>(System.Threading.Tasks.ValueTask<bool>)"
                    IL_0083:  brtrue.s   IL_0018
                    IL_0085:  leave.s    IL_008a
                  }
                  catch object
                  {
                    IL_0087:  stloc.2
                    IL_0088:  leave.s    IL_008a
                  }
                  IL_008a:  ldloc.0
                  IL_008b:  callvirt   "System.Threading.Tasks.ValueTask System.IAsyncDisposable.DisposeAsync()"
                  IL_0090:  call       "void System.Runtime.CompilerServices.AsyncHelpers.Await(System.Threading.Tasks.ValueTask)"
                  IL_0095:  ldloc.2
                  IL_0096:  brfalse.s  IL_00ad
                  IL_0098:  ldloc.2
                  IL_0099:  isinst     "System.Exception"
                  IL_009e:  dup
                  IL_009f:  brtrue.s   IL_00a3
                  IL_00a1:  ldloc.2
                  IL_00a2:  throw
                  IL_00a3:  call       "System.Runtime.ExceptionServices.ExceptionDispatchInfo System.Runtime.ExceptionServices.ExceptionDispatchInfo.Capture(System.Exception)"
                  IL_00a8:  callvirt   "void System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()"
                  IL_00ad:  ldstr      "Done"
                  IL_00b2:  call       "void System.Console.Write(string)"
                  IL_00b7:  ret
                }
                """);
        }
 
        [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/30257")]
        public void TestWithPatternAndObsolete_WithDisposableInterface()
        {
            string source = @"
using System.Threading.Tasks;
class C
{
    static async System.Threading.Tasks.Task Main()
    {
        await foreach (var i in new C())
        {
        }
    }
    [System.Obsolete]
    public AsyncEnumerator GetAsyncEnumerator(System.Threading.CancellationToken token = default)
    {
        throw null;
    }
    [System.Obsolete]
    public sealed class AsyncEnumerator : System.IAsyncDisposable
    {
        [System.Obsolete]
        public int Current { get => throw null; }
        [System.Obsolete]
        public Task<bool> MoveNextAsync() => throw null;
        [System.Obsolete]
        public ValueTask DisposeAsync() => throw null;
    }
}";
            var comp = CreateCompilationWithTasksExtensions(source + s_IAsyncEnumerable, options: TestOptions.DebugExe);
            comp.VerifyDiagnostics(
                // (7,15): warning CS0612: 'C.AsyncEnumerator.DisposeAsync()' is obsolete
                //         await foreach (var i in new C())
                Diagnostic(ErrorCode.WRN_DeprecatedSymbol, "foreach").WithArguments("C.AsyncEnumerator.DisposeAsync()").WithLocation(7, 15),
                // (7,15): warning CS0612: 'C.GetAsyncEnumerator(CancellationToken)' is obsolete
                //         await foreach (var i in new C())
                Diagnostic(ErrorCode.WRN_DeprecatedSymbol, "foreach").WithArguments("C.GetAsyncEnumerator(System.Threading.CancellationToken)").WithLocation(7, 15),
                // (7,15): warning CS0612: 'C.AsyncEnumerator.MoveNextAsync()' is obsolete
                //         await foreach (var i in new C())
                Diagnostic(ErrorCode.WRN_DeprecatedSymbol, "foreach").WithArguments("C.AsyncEnumerator.MoveNextAsync()").WithLocation(7, 15),
                // (7,15): warning CS0612: 'C.AsyncEnumerator.Current' is obsolete
                //         await foreach (var i in new C())
                Diagnostic(ErrorCode.WRN_DeprecatedSymbol, "foreach").WithArguments("C.AsyncEnumerator.Current").WithLocation(7, 15)
                );
        }
 
        [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/30257")]
        public void TestWithPatternAndObsolete_WithoutDisposableInterface()
        {
            string source = @"
using System.Threading.Tasks;
class C
{
    static async System.Threading.Tasks.Task Main()
    {
        await foreach (var i in new C())
        {
        }
    }
    [System.Obsolete]
    public AsyncEnumerator GetAsyncEnumerator(System.Threading.CancellationToken token = default)
    {
        throw null;
    }
    [System.Obsolete]
    public sealed class AsyncEnumerator
    {
        [System.Obsolete]
        public int Current { get => throw null; }
        [System.Obsolete]
        public Task<bool> MoveNextAsync() => throw null;
        [System.Obsolete]
        public ValueTask DisposeAsync() => throw null;
    }
}";
            var comp = CreateCompilationWithTasksExtensions(source + s_IAsyncEnumerable, options: TestOptions.DebugExe);
            comp.VerifyDiagnostics(
                // (7,15): warning CS0612: 'C.AsyncEnumerator.DisposeAsync()' is obsolete
                //         await foreach (var i in new C())
                Diagnostic(ErrorCode.WRN_DeprecatedSymbol, "foreach").WithArguments("C.AsyncEnumerator.DisposeAsync()").WithLocation(7, 15),
                // (7,15): warning CS0612: 'C.GetAsyncEnumerator(CancellationToken)' is obsolete
                //         await foreach (var i in new C())
                Diagnostic(ErrorCode.WRN_DeprecatedSymbol, "foreach").WithArguments("C.GetAsyncEnumerator(System.Threading.CancellationToken)").WithLocation(7, 15),
                // (7,15): warning CS0612: 'C.AsyncEnumerator.MoveNextAsync()' is obsolete
                //         await foreach (var i in new C())
                Diagnostic(ErrorCode.WRN_DeprecatedSymbol, "foreach").WithArguments("C.AsyncEnumerator.MoveNextAsync()").WithLocation(7, 15),
                // (7,15): warning CS0612: 'C.AsyncEnumerator.Current' is obsolete
                //         await foreach (var i in new C())
                Diagnostic(ErrorCode.WRN_DeprecatedSymbol, "foreach").WithArguments("C.AsyncEnumerator.Current").WithLocation(7, 15)
                );
        }
 
        [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/30257")]
        public void TestWithPatternAndObsolete_WithExplicitInterfaceImplementation()
        {
            string source = @"
using System.Threading.Tasks;
class C
{
    static async System.Threading.Tasks.Task Main()
    {
        await foreach (var i in new C())
        {
        }
    }
    public AsyncEnumerator GetAsyncEnumerator(System.Threading.CancellationToken token = default)
    {
        throw null;
    }
    public sealed class AsyncEnumerator : System.IAsyncDisposable
    {
        public int Current { get => throw null; }
        public Task<bool> MoveNextAsync() => throw null;
        [System.Obsolete]
        ValueTask System.IAsyncDisposable.DisposeAsync() => throw null;
    }
}";
            var comp = CreateCompilationWithTasksExtensions(source + s_IAsyncEnumerable);
            comp.VerifyEmitDiagnostics();
        }
 
        [Fact]
        public void TestWithUnassignedCollection()
        {
            string source = @"
using System.Collections.Generic;
class C
{
    async System.Threading.Tasks.Task M()
    {
        C c;
        await foreach (var i in c)
        {
        }
    }
    public IAsyncEnumerator<int> GetAsyncEnumerator(System.Threading.CancellationToken token = default) => throw null;
}";
            var comp = CreateCompilationWithTasksExtensions(source + s_IAsyncEnumerable);
            comp.VerifyDiagnostics(
                // (8,33): error CS0165: Use of unassigned local variable 'c'
                //         await foreach (var i in c)
                Diagnostic(ErrorCode.ERR_UseDefViolation, "c").WithArguments("c").WithLocation(8, 33)
                );
        }
 
        [Fact]
        public void TestInRegularForeach()
        {
            string source = @"
using System.Collections.Generic;
class C
{
    void M()
    {
        foreach (var i in new C())
        {
        }
    }
    public IAsyncEnumerator<int> GetAsyncEnumerator(System.Threading.CancellationToken token = default)
    {
        throw null;
    }
}";
            var comp = CreateCompilationWithTasksExtensions(source + s_IAsyncEnumerable);
            comp.VerifyDiagnostics(
                // (7,27): error CS8414: foreach statement cannot operate on variables of type 'C' because 'C' does not contain a public instance or extension definition for 'GetEnumerator'. Did you mean 'await foreach'?
                //         foreach (var i in new C())
                Diagnostic(ErrorCode.ERR_ForEachMissingMemberWrongAsync, "new C()").WithArguments("C", "GetEnumerator").WithLocation(7, 27)
                );
        }
 
        [Fact]
        public void TestWithGenericCollection()
        {
            string source = @"
using static System.Console;
using System.Collections.Generic;
using System.Threading.Tasks;
class Collection<T> : IAsyncEnumerable<T>
{
    IAsyncEnumerator<T> IAsyncEnumerable<T>.GetAsyncEnumerator(System.Threading.CancellationToken token)
    {
        return new AsyncEnumerator();
    }
    sealed class AsyncEnumerator : IAsyncEnumerator<T>
    {
        int i = 0;
        public T Current
        {
            get
            {
                Write($""Current({i}) "");
                return default;
            }
        }
        public async ValueTask<bool> MoveNextAsync()
        {
            Write($""NextAsync({i}) "");
            i++;
            return await Task.FromResult(i < 4);
        }
        public async ValueTask DisposeAsync()
        {
            Write($""Dispose({i}) "");
            await Task.Yield();
        }
    }
}
class C
{
    static async System.Threading.Tasks.Task Main()
    {
        await foreach (var i in new Collection<int>())
        {
            Write($""Got "");
        }
    }
}";
            var comp = CreateCompilationWithTasksExtensions(source + s_IAsyncEnumerable, options: TestOptions.DebugExe);
            comp.VerifyDiagnostics();
 
            var expectedOutput = "NextAsync(0) Current(1) Got NextAsync(1) Current(2) Got NextAsync(2) Current(3) Got NextAsync(3) Dispose(4)";
            CompileAndVerify(comp, expectedOutput: expectedOutput);
 
            var tree = comp.SyntaxTrees.Single();
            var model = (SyntaxTreeSemanticModel)comp.GetSemanticModel(tree, ignoreAccessibility: false);
            var foreachSyntax = tree.GetRoot().DescendantNodes().OfType<ForEachStatementSyntax>().Single();
            var info = model.GetForEachStatementInfo(foreachSyntax);
 
            Assert.Equal("System.Collections.Generic.IAsyncEnumerator<System.Int32> System.Collections.Generic.IAsyncEnumerable<System.Int32>.GetAsyncEnumerator([System.Threading.CancellationToken token = default(System.Threading.CancellationToken)])",
                info.GetEnumeratorMethod.ToTestDisplayString());
            Assert.Equal("System.Threading.Tasks.ValueTask<System.Boolean> System.Collections.Generic.IAsyncEnumerator<System.Int32>.MoveNextAsync()",
                info.MoveNextMethod.ToTestDisplayString());
            Assert.Equal("System.Int32 System.Collections.Generic.IAsyncEnumerator<System.Int32>.Current { get; }",
                info.CurrentProperty.ToTestDisplayString());
            Assert.Equal("System.Threading.Tasks.ValueTask System.IAsyncDisposable.DisposeAsync()", info.DisposeMethod.ToTestDisplayString());
            Assert.Equal("System.Int32", info.ElementType.ToTestDisplayString());
            Assert.Equal(ConversionKind.Identity, info.ElementConversion.Kind);
            Assert.Equal(ConversionKind.Identity, info.CurrentConversion.Kind);
 
            var memberModel = model.GetMemberModel(foreachSyntax);
            var boundNode = (BoundForEachStatement)memberModel.GetUpperBoundNode(foreachSyntax);
            ForEachEnumeratorInfo internalInfo = boundNode.EnumeratorInfoOpt;
            Assert.True(internalInfo.NeedsDisposal);
 
            var runtimeAsyncComp = CreateRuntimeAsyncCompilation(source);
            var verifier = CompileAndVerify(runtimeAsyncComp, expectedOutput: CodeGenAsyncTests.ExpectedOutput(expectedOutput, isRuntimeAsync: true), verify: Verification.Fails with
            {
                ILVerifyMessage = """
                    [Main]: Return value missing on the stack. { Offset = 0x61 }
                    [MoveNextAsync]: Unexpected type on the stack. { Offset = 0x5c, Found = Int32, Expected = value '[System.Runtime]System.Threading.Tasks.ValueTask`1<bool>' }
                    [DisposeAsync]: Return value missing on the stack. { Offset = 0x5f }
                    """
            });
            verifier.VerifyIL("C.Main()", """
                {
                  // Code size       98 (0x62)
                  .maxstack  2
                  .locals init (System.Collections.Generic.IAsyncEnumerator<int> V_0,
                                System.Threading.CancellationToken V_1,
                                object V_2)
                  IL_0000:  newobj     "Collection<int>..ctor()"
                  IL_0005:  ldloca.s   V_1
                  IL_0007:  initobj    "System.Threading.CancellationToken"
                  IL_000d:  ldloc.1
                  IL_000e:  callvirt   "System.Collections.Generic.IAsyncEnumerator<int> System.Collections.Generic.IAsyncEnumerable<int>.GetAsyncEnumerator(System.Threading.CancellationToken)"
                  IL_0013:  stloc.0
                  IL_0014:  ldnull
                  IL_0015:  stloc.2
                  .try
                  {
                    IL_0016:  br.s       IL_0029
                    IL_0018:  ldloc.0
                    IL_0019:  callvirt   "int System.Collections.Generic.IAsyncEnumerator<int>.Current.get"
                    IL_001e:  pop
                    IL_001f:  ldstr      "Got "
                    IL_0024:  call       "void System.Console.Write(string)"
                    IL_0029:  ldloc.0
                    IL_002a:  callvirt   "System.Threading.Tasks.ValueTask<bool> System.Collections.Generic.IAsyncEnumerator<int>.MoveNextAsync()"
                    IL_002f:  call       "bool System.Runtime.CompilerServices.AsyncHelpers.Await<bool>(System.Threading.Tasks.ValueTask<bool>)"
                    IL_0034:  brtrue.s   IL_0018
                    IL_0036:  leave.s    IL_003b
                  }
                  catch object
                  {
                    IL_0038:  stloc.2
                    IL_0039:  leave.s    IL_003b
                  }
                  IL_003b:  ldloc.0
                  IL_003c:  brfalse.s  IL_0049
                  IL_003e:  ldloc.0
                  IL_003f:  callvirt   "System.Threading.Tasks.ValueTask System.IAsyncDisposable.DisposeAsync()"
                  IL_0044:  call       "void System.Runtime.CompilerServices.AsyncHelpers.Await(System.Threading.Tasks.ValueTask)"
                  IL_0049:  ldloc.2
                  IL_004a:  brfalse.s  IL_0061
                  IL_004c:  ldloc.2
                  IL_004d:  isinst     "System.Exception"
                  IL_0052:  dup
                  IL_0053:  brtrue.s   IL_0057
                  IL_0055:  ldloc.2
                  IL_0056:  throw
                  IL_0057:  call       "System.Runtime.ExceptionServices.ExceptionDispatchInfo System.Runtime.ExceptionServices.ExceptionDispatchInfo.Capture(System.Exception)"
                  IL_005c:  callvirt   "void System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()"
                  IL_0061:  ret
                }
                """);
        }
 
        [Fact]
        public void TestWithInterfaceImplementingPattern()
        {
            string source = @"
using static System.Console;
using System.Threading.Tasks;
 
public interface ICollection<T>
{
    IMyAsyncEnumerator<T> GetAsyncEnumerator(System.Threading.CancellationToken token = default);
}
public interface IMyAsyncEnumerator<T>
{
    T Current { get; }
    Task<bool> MoveNextAsync();
}
 
public class Collection<T> : ICollection<T>
{
    public IMyAsyncEnumerator<T> GetAsyncEnumerator(System.Threading.CancellationToken token = default)
    {
        return new MyAsyncEnumerator<T>();
    }
}
public sealed class MyAsyncEnumerator<T> : IMyAsyncEnumerator<T>
{
    int i = 0;
    public T Current
    {
        get
        {
            Write($""Current({i}) "");
            return default;
        }
    }
    public async Task<bool> MoveNextAsync()
    {
        Write($""NextAsync({i}) "");
        i++;
        return await Task.FromResult(i < 4);
    }
}
 
class C
{
    static async System.Threading.Tasks.Task Main()
    {
        ICollection<int> c = new Collection<int>();
        await foreach (var i in c)
        {
            Write($""Got "");
        }
    }
}";
            var comp = CreateCompilationWithTasksExtensions(source + s_IAsyncEnumerable, options: TestOptions.DebugExe);
            comp.VerifyDiagnostics();
 
            string expectedOutput = "NextAsync(0) Current(1) Got NextAsync(1) Current(2) Got NextAsync(2) Current(3) Got NextAsync(3)";
            var verifier = CompileAndVerify(comp, expectedOutput: expectedOutput);
 
            var tree = comp.SyntaxTrees.Single();
            var model = (SyntaxTreeSemanticModel)comp.GetSemanticModel(tree, ignoreAccessibility: false);
            var foreachSyntax = tree.GetRoot().DescendantNodes().OfType<ForEachStatementSyntax>().Single();
            var info = model.GetForEachStatementInfo(foreachSyntax);
 
            Assert.Equal("IMyAsyncEnumerator<System.Int32> ICollection<System.Int32>.GetAsyncEnumerator([System.Threading.CancellationToken token = default(System.Threading.CancellationToken)])",
                info.GetEnumeratorMethod.ToTestDisplayString());
            Assert.Equal("System.Threading.Tasks.Task<System.Boolean> IMyAsyncEnumerator<System.Int32>.MoveNextAsync()",
                info.MoveNextMethod.ToTestDisplayString());
            Assert.Equal("System.Int32 IMyAsyncEnumerator<System.Int32>.Current { get; }",
                info.CurrentProperty.ToTestDisplayString());
            Assert.Null(info.DisposeMethod);
            Assert.Equal("System.Int32", info.ElementType.ToTestDisplayString());
            Assert.Equal(ConversionKind.Identity, info.ElementConversion.Kind);
            Assert.Equal(ConversionKind.Identity, info.CurrentConversion.Kind);
 
            var memberModel = model.GetMemberModel(foreachSyntax);
            var boundNode = (BoundForEachStatement)memberModel.GetUpperBoundNode(foreachSyntax);
            ForEachEnumeratorInfo internalInfo = boundNode.EnumeratorInfoOpt;
            Assert.False(internalInfo.NeedsDisposal);
 
            verifier.VerifyIL("C.<Main>d__0.System.Runtime.CompilerServices.IAsyncStateMachine.MoveNext()", @"
{
  // Code size      283 (0x11b)
  .maxstack  3
  .locals init (int V_0,
                System.Threading.CancellationToken V_1,
                System.Runtime.CompilerServices.TaskAwaiter<bool> V_2,
                C.<Main>d__0 V_3,
                System.Exception V_4)
  // sequence point: <hidden>
  IL_0000:  ldarg.0
  IL_0001:  ldfld      ""int C.<Main>d__0.<>1__state""
  IL_0006:  stloc.0
  .try
  {
    // sequence point: <hidden>
    IL_0007:  ldloc.0
    IL_0008:  brfalse.s  IL_0012
    IL_000a:  br.s       IL_000c
    IL_000c:  ldloc.0
    IL_000d:  ldc.i4.1
    IL_000e:  beq.s      IL_0017
    IL_0010:  br.s       IL_001c
    IL_0012:  br         IL_00a1
    IL_0017:  br         IL_00a1
    // sequence point: {
    IL_001c:  nop
    // sequence point: ICollection<int> c = new Collection<int>();
    IL_001d:  ldarg.0
    IL_001e:  newobj     ""Collection<int>..ctor()""
    IL_0023:  stfld      ""ICollection<int> C.<Main>d__0.<c>5__1""
    // sequence point: await foreach
    IL_0028:  nop
    // sequence point: c
    IL_0029:  ldarg.0
    IL_002a:  ldarg.0
    IL_002b:  ldfld      ""ICollection<int> C.<Main>d__0.<c>5__1""
    IL_0030:  ldloca.s   V_1
    IL_0032:  initobj    ""System.Threading.CancellationToken""
    IL_0038:  ldloc.1
    IL_0039:  callvirt   ""IMyAsyncEnumerator<int> ICollection<int>.GetAsyncEnumerator(System.Threading.CancellationToken)""
    IL_003e:  stfld      ""IMyAsyncEnumerator<int> C.<Main>d__0.<>s__2""
    // sequence point: <hidden>
    IL_0043:  br.s       IL_0063
    // sequence point: var i
    IL_0045:  ldarg.0
    IL_0046:  ldarg.0
    IL_0047:  ldfld      ""IMyAsyncEnumerator<int> C.<Main>d__0.<>s__2""
    IL_004c:  callvirt   ""int IMyAsyncEnumerator<int>.Current.get""
    IL_0051:  stfld      ""int C.<Main>d__0.<i>5__3""
    // sequence point: {
    IL_0056:  nop
    // sequence point: Write($""Got "");
    IL_0057:  ldstr      ""Got ""
    IL_005c:  call       ""void System.Console.Write(string)""
    IL_0061:  nop
    // sequence point: }
    IL_0062:  nop
    // sequence point: in
    IL_0063:  ldarg.0
    IL_0064:  ldfld      ""IMyAsyncEnumerator<int> C.<Main>d__0.<>s__2""
    IL_0069:  callvirt   ""System.Threading.Tasks.Task<bool> IMyAsyncEnumerator<int>.MoveNextAsync()""
    IL_006e:  callvirt   ""System.Runtime.CompilerServices.TaskAwaiter<bool> System.Threading.Tasks.Task<bool>.GetAwaiter()""
    IL_0073:  stloc.2
    // sequence point: <hidden>
    IL_0074:  ldloca.s   V_2
    IL_0076:  call       ""bool System.Runtime.CompilerServices.TaskAwaiter<bool>.IsCompleted.get""
    IL_007b:  brtrue.s   IL_00bd
    IL_007d:  ldarg.0
    IL_007e:  ldc.i4.0
    IL_007f:  dup
    IL_0080:  stloc.0
    IL_0081:  stfld      ""int C.<Main>d__0.<>1__state""
    // async: yield
    IL_0086:  ldarg.0
    IL_0087:  ldloc.2
    IL_0088:  stfld      ""System.Runtime.CompilerServices.TaskAwaiter<bool> C.<Main>d__0.<>u__1""
    IL_008d:  ldarg.0
    IL_008e:  stloc.3
    IL_008f:  ldarg.0
    IL_0090:  ldflda     ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder C.<Main>d__0.<>t__builder""
    IL_0095:  ldloca.s   V_2
    IL_0097:  ldloca.s   V_3
    IL_0099:  call       ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.AwaitUnsafeOnCompleted<System.Runtime.CompilerServices.TaskAwaiter<bool>, C.<Main>d__0>(ref System.Runtime.CompilerServices.TaskAwaiter<bool>, ref C.<Main>d__0)""
    IL_009e:  nop
    IL_009f:  leave.s    IL_011a
    // async: resume
    IL_00a1:  ldarg.0
    IL_00a2:  ldfld      ""System.Runtime.CompilerServices.TaskAwaiter<bool> C.<Main>d__0.<>u__1""
    IL_00a7:  stloc.2
    IL_00a8:  ldarg.0
    IL_00a9:  ldflda     ""System.Runtime.CompilerServices.TaskAwaiter<bool> C.<Main>d__0.<>u__1""
    IL_00ae:  initobj    ""System.Runtime.CompilerServices.TaskAwaiter<bool>""
    IL_00b4:  ldarg.0
    IL_00b5:  ldc.i4.m1
    IL_00b6:  dup
    IL_00b7:  stloc.0
    IL_00b8:  stfld      ""int C.<Main>d__0.<>1__state""
    IL_00bd:  ldarg.0
    IL_00be:  ldloca.s   V_2
    IL_00c0:  call       ""bool System.Runtime.CompilerServices.TaskAwaiter<bool>.GetResult()""
    IL_00c5:  stfld      ""bool C.<Main>d__0.<>s__4""
    IL_00ca:  ldarg.0
    IL_00cb:  ldfld      ""bool C.<Main>d__0.<>s__4""
    IL_00d0:  brtrue     IL_0045
    IL_00d5:  ldarg.0
    IL_00d6:  ldnull
    IL_00d7:  stfld      ""IMyAsyncEnumerator<int> C.<Main>d__0.<>s__2""
    IL_00dc:  leave.s    IL_00ff
  }
  catch System.Exception
  {
    // async: catch handler, sequence point: <hidden>
    IL_00de:  stloc.s    V_4
    IL_00e0:  ldarg.0
    IL_00e1:  ldc.i4.s   -2
    IL_00e3:  stfld      ""int C.<Main>d__0.<>1__state""
    IL_00e8:  ldarg.0
    IL_00e9:  ldnull
    IL_00ea:  stfld      ""ICollection<int> C.<Main>d__0.<c>5__1""
    IL_00ef:  ldarg.0
    IL_00f0:  ldflda     ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder C.<Main>d__0.<>t__builder""
    IL_00f5:  ldloc.s    V_4
    IL_00f7:  call       ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetException(System.Exception)""
    IL_00fc:  nop
    IL_00fd:  leave.s    IL_011a
  }
  // sequence point: }
  IL_00ff:  ldarg.0
  IL_0100:  ldc.i4.s   -2
  IL_0102:  stfld      ""int C.<Main>d__0.<>1__state""
  // sequence point: <hidden>
  IL_0107:  ldarg.0
  IL_0108:  ldnull
  IL_0109:  stfld      ""ICollection<int> C.<Main>d__0.<c>5__1""
  IL_010e:  ldarg.0
  IL_010f:  ldflda     ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder C.<Main>d__0.<>t__builder""
  IL_0114:  call       ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetResult()""
  IL_0119:  nop
  IL_011a:  ret
}", sequencePoints: "C+<Main>d__0.MoveNext", source: source);
 
            var runtimeAsyncComp = CreateRuntimeAsyncCompilation(source);
            verifier = CompileAndVerify(runtimeAsyncComp, expectedOutput: CodeGenAsyncTests.ExpectedOutput(expectedOutput, isRuntimeAsync: true), verify: Verification.Fails with
            {
                ILVerifyMessage = """
                    [MoveNextAsync]: Unexpected type on the stack. { Offset = 0x5c, Found = Int32, Expected = ref '[System.Runtime]System.Threading.Tasks.Task`1<bool>' }
                    [Main]: Return value missing on the stack. { Offset = 0x34 }
                    """
            });
            verifier.VerifyIL("C.Main()", """
                {
                  // Code size       53 (0x35)
                  .maxstack  2
                  .locals init (IMyAsyncEnumerator<int> V_0,
                                System.Threading.CancellationToken V_1)
                  IL_0000:  newobj     "Collection<int>..ctor()"
                  IL_0005:  ldloca.s   V_1
                  IL_0007:  initobj    "System.Threading.CancellationToken"
                  IL_000d:  ldloc.1
                  IL_000e:  callvirt   "IMyAsyncEnumerator<int> ICollection<int>.GetAsyncEnumerator(System.Threading.CancellationToken)"
                  IL_0013:  stloc.0
                  IL_0014:  br.s       IL_0027
                  IL_0016:  ldloc.0
                  IL_0017:  callvirt   "int IMyAsyncEnumerator<int>.Current.get"
                  IL_001c:  pop
                  IL_001d:  ldstr      "Got "
                  IL_0022:  call       "void System.Console.Write(string)"
                  IL_0027:  ldloc.0
                  IL_0028:  callvirt   "System.Threading.Tasks.Task<bool> IMyAsyncEnumerator<int>.MoveNextAsync()"
                  IL_002d:  call       "bool System.Runtime.CompilerServices.AsyncHelpers.Await<bool>(System.Threading.Tasks.Task<bool>)"
                  IL_0032:  brtrue.s   IL_0016
                  IL_0034:  ret
                }
                """);
        }
 
        [Fact]
        public void TestWithInterfaceImplementingPattern_ChildImplementsDisposeAsync()
        {
            string source = @"
using static System.Console;
using System.Threading.Tasks;
 
public interface ICollection<T>
{
    IMyAsyncEnumerator<T> GetAsyncEnumerator(System.Threading.CancellationToken token = default);
}
public interface IMyAsyncEnumerator<T>
{
    T Current { get; }
    Task<bool> MoveNextAsync();
}
 
public class Collection<T> : ICollection<T>
{
    public IMyAsyncEnumerator<T> GetAsyncEnumerator(System.Threading.CancellationToken token = default)
    {
        return new MyAsyncEnumerator<T>();
    }
}
public sealed class MyAsyncEnumerator<T> : IMyAsyncEnumerator<T>
{
    int i = 0;
    public T Current
    {
        get
        {
            Write($""Current({i}) "");
            return default;
        }
    }
    public async Task<bool> MoveNextAsync()
    {
        Write($""NextAsync({i}) "");
        i++;
        return await Task.FromResult(i < 4);
    }
    public System.Threading.Tasks.ValueTask DisposeAsync()
        => throw null;
}
 
class C
{
    static async System.Threading.Tasks.Task Main()
    {
        ICollection<int> c = new Collection<int>();
        await foreach (var i in c)
        {
            Write($""Got "");
        }
    }
}";
            // DisposeAsync on implementing type is ignored, since we don't do runtime check
            var comp = CreateCompilationWithTasksExtensions(source + s_IAsyncEnumerable, options: TestOptions.DebugExe);
            comp.VerifyDiagnostics();
 
            var expectedOutput = "NextAsync(0) Current(1) Got NextAsync(1) Current(2) Got NextAsync(2) Current(3) Got NextAsync(3)";
            var verifier = CompileAndVerify(comp, expectedOutput: expectedOutput);
 
            var tree = comp.SyntaxTrees.Single();
            var model = (SyntaxTreeSemanticModel)comp.GetSemanticModel(tree, ignoreAccessibility: false);
            var foreachSyntax = tree.GetRoot().DescendantNodes().OfType<ForEachStatementSyntax>().Single();
            var info = model.GetForEachStatementInfo(foreachSyntax);
 
            Assert.Null(info.DisposeMethod);
 
            var runtimeAsyncComp = CreateRuntimeAsyncCompilation(source);
            var verifier2 = CompileAndVerify(runtimeAsyncComp, expectedOutput: CodeGenAsyncTests.ExpectedOutput(expectedOutput, isRuntimeAsync: true), verify: Verification.Fails with
            {
                ILVerifyMessage = """
                    [MoveNextAsync]: Unexpected type on the stack. { Offset = 0x5c, Found = Int32, Expected = ref '[System.Runtime]System.Threading.Tasks.Task`1<bool>' }
                    [Main]: Return value missing on the stack. { Offset = 0x34 }
                    """
            });
            verifier2.VerifyIL("C.Main()", """
                {
                  // Code size       53 (0x35)
                  .maxstack  2
                  .locals init (IMyAsyncEnumerator<int> V_0,
                                System.Threading.CancellationToken V_1)
                  IL_0000:  newobj     "Collection<int>..ctor()"
                  IL_0005:  ldloca.s   V_1
                  IL_0007:  initobj    "System.Threading.CancellationToken"
                  IL_000d:  ldloc.1
                  IL_000e:  callvirt   "IMyAsyncEnumerator<int> ICollection<int>.GetAsyncEnumerator(System.Threading.CancellationToken)"
                  IL_0013:  stloc.0
                  IL_0014:  br.s       IL_0027
                  IL_0016:  ldloc.0
                  IL_0017:  callvirt   "int IMyAsyncEnumerator<int>.Current.get"
                  IL_001c:  pop
                  IL_001d:  ldstr      "Got "
                  IL_0022:  call       "void System.Console.Write(string)"
                  IL_0027:  ldloc.0
                  IL_0028:  callvirt   "System.Threading.Tasks.Task<bool> IMyAsyncEnumerator<int>.MoveNextAsync()"
                  IL_002d:  call       "bool System.Runtime.CompilerServices.AsyncHelpers.Await<bool>(System.Threading.Tasks.Task<bool>)"
                  IL_0032:  brtrue.s   IL_0016
                  IL_0034:  ret
                }
                """);
        }
 
        [Fact]
        public void GetAsyncEnumerator_CancellationTokenMustBeOptional()
        {
            string source = @"
using System.Collections.Generic;
using System.Threading.Tasks;
class C
{
    public static async Task Main()
    {
        await foreach (var i in new C())
        {
        }
    }
    public IAsyncEnumerator<int> GetAsyncEnumerator(System.Threading.CancellationToken token)
    {
        throw null;
    }
}";
            var comp = CreateCompilationWithTasksExtensions(new[] { source, s_IAsyncEnumerable });
            comp.VerifyDiagnostics(
                // (8,33): error CS8411: Asynchronous foreach statement cannot operate on variables of type 'C' because 'C' does not contain a suitable public instance or extension definition for 'GetAsyncEnumerator'
                //         await foreach (var i in new C())
                Diagnostic(ErrorCode.ERR_AwaitForEachMissingMember, "new C()").WithArguments("C", "GetAsyncEnumerator").WithLocation(8, 33)
                );
        }
 
        [Fact]
        [WorkItem(50182, "https://github.com/dotnet/roslyn/issues/50182")]
        public void GetAsyncEnumerator_CancellationTokenMustBeOptional_OnIAsyncEnumerable()
        {
            string source = @"
using System.Collections.Generic;
using System.Threading.Tasks;
class C
{
    public static async Task M(IAsyncEnumerable<int> e)
    {
        await foreach (var i in e)
        {
        }
    }
}
namespace System.Collections.Generic
{
    public interface IAsyncEnumerable<out T>
    {
        IAsyncEnumerator<T> GetAsyncEnumerator(System.Threading.CancellationToken token);
    }
 
    public interface IAsyncEnumerator<out T> : System.IAsyncDisposable
    {
        System.Threading.Tasks.ValueTask<bool> MoveNextAsync();
        T Current { get; }
    }
}
namespace System
{
    public interface IAsyncDisposable
    {
        System.Threading.Tasks.ValueTask DisposeAsync();
    }
}
";
            var comp = CreateCompilationWithTasksExtensions(source);
            comp.VerifyEmitDiagnostics(
                // (8,33): error CS8411: Asynchronous foreach statement cannot operate on variables of type 'IAsyncEnumerable<int>' because 'IAsyncEnumerable<int>' does not contain a suitable public instance or extension definition for 'GetAsyncEnumerator'
                //         await foreach (var i in e)
                Diagnostic(ErrorCode.ERR_AwaitForEachMissingMember, "e").WithArguments("System.Collections.Generic.IAsyncEnumerable<int>", "GetAsyncEnumerator").WithLocation(8, 33)
                );
        }
 
        [Fact]
        [WorkItem(50182, "https://github.com/dotnet/roslyn/issues/50182")]
        public void GetAsyncEnumerator_CancellationTokenMustBeOptional_OnIAsyncEnumerable_ImplicitImplementation()
        {
            string source = @"
using System.Collections.Generic;
using System.Threading.Tasks;
class C : IAsyncEnumerable<int>
{
    public static async Task M(C c)
    {
        await foreach (var i in c)
        {
        }
    }
    public IAsyncEnumerator<int> GetAsyncEnumerator(System.Threading.CancellationToken token) => throw null;
}
namespace System.Collections.Generic
{
    public interface IAsyncEnumerable<out T>
    {
        IAsyncEnumerator<T> GetAsyncEnumerator(System.Threading.CancellationToken token);
    }
 
    public interface IAsyncEnumerator<out T> : System.IAsyncDisposable
    {
        System.Threading.Tasks.ValueTask<bool> MoveNextAsync();
        T Current { get; }
    }
}
namespace System
{
    public interface IAsyncDisposable
    {
        System.Threading.Tasks.ValueTask DisposeAsync();
    }
}
";
            var comp = CreateCompilationWithTasksExtensions(source);
            comp.VerifyEmitDiagnostics(
                // (8,33): error CS8411: Asynchronous foreach statement cannot operate on variables of type 'C' because 'C' does not contain a suitable public instance or extension definition for 'GetAsyncEnumerator'
                //         await foreach (var i in c)
                Diagnostic(ErrorCode.ERR_AwaitForEachMissingMember, "c").WithArguments("C", "GetAsyncEnumerator").WithLocation(8, 33)
                );
        }
 
        [Fact]
        [WorkItem(50182, "https://github.com/dotnet/roslyn/issues/50182")]
        public void GetAsyncEnumerator_CancellationTokenMustBeOptional_OnIAsyncEnumerable_ExplicitImplementation()
        {
            string source = @"
using System.Collections.Generic;
using System.Threading.Tasks;
class C : IAsyncEnumerable<int>
{
    public static async Task M(C c)
    {
        await foreach (var i in c)
        {
        }
    }
    IAsyncEnumerator<int> IAsyncEnumerable<int>.GetAsyncEnumerator(System.Threading.CancellationToken token) => throw null;
}
namespace System.Collections.Generic
{
    public interface IAsyncEnumerable<out T>
    {
        IAsyncEnumerator<T> GetAsyncEnumerator(System.Threading.CancellationToken token);
    }
 
    public interface IAsyncEnumerator<out T> : System.IAsyncDisposable
    {
        System.Threading.Tasks.ValueTask<bool> MoveNextAsync();
        T Current { get; }
    }
}
namespace System
{
    public interface IAsyncDisposable
    {
        System.Threading.Tasks.ValueTask DisposeAsync();
    }
}
";
            var comp = CreateCompilationWithTasksExtensions(source);
            comp.VerifyEmitDiagnostics(
                // (8,33): error CS8411: Asynchronous foreach statement cannot operate on variables of type 'C' because 'C' does not contain a suitable public instance or extension definition for 'GetAsyncEnumerator'
                //         await foreach (var i in c)
                Diagnostic(ErrorCode.ERR_AwaitForEachMissingMember, "c").WithArguments("C", "GetAsyncEnumerator").WithLocation(8, 33)
                );
        }
 
        [Fact]
        public void GetAsyncEnumerator_Missing()
        {
            string source = @"
using System.Collections.Generic;
using System.Threading.Tasks;
class C : IAsyncEnumerable<int>
{
    public static async Task M(C c)
    {
        await foreach (var i in c)
        {
        }
    }
}
namespace System.Collections.Generic
{
    public interface IAsyncEnumerable<out T>
    {
    }
 
    public interface IAsyncEnumerator<out T> : System.IAsyncDisposable
    {
        System.Threading.Tasks.ValueTask<bool> MoveNextAsync();
        T Current { get; }
    }
}
namespace System
{
    public interface IAsyncDisposable
    {
        System.Threading.Tasks.ValueTask DisposeAsync();
    }
}
";
            var comp = CreateCompilationWithTasksExtensions(source);
            comp.VerifyEmitDiagnostics(
                // (8,33): error CS0656: Missing compiler required member 'System.Collections.Generic.IAsyncEnumerable`1.GetAsyncEnumerator'
                //         await foreach (var i in c)
                Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "c").WithArguments("System.Collections.Generic.IAsyncEnumerable`1", "GetAsyncEnumerator").WithLocation(8, 33)
                );
        }
 
        [Fact]
        public void GetAsyncEnumerator_WithOptionalParameter()
        {
            string source = @"
using System.Collections.Generic;
using System.Threading.Tasks;
class C
{
    public static async Task Main()
    {
        await foreach (var i in new C())
        {
        }
    }
    public IAsyncEnumerator<int> GetAsyncEnumerator(int opt = 0)
    {
        throw null;
    }
}";
            var comp = CreateCompilationWithTasksExtensions(new[] { source, s_IAsyncEnumerable });
            comp.VerifyDiagnostics();
        }
 
        [Fact]
        public void GetAsyncEnumerator_WithParams()
        {
            string source = @"
using System.Threading.Tasks;
class C
{
    public static async Task Main()
    {
        await foreach (var i in new C())
        {
        }
    }
    public Enumerator GetAsyncEnumerator(params int[] x)
    {
        return new Enumerator();
    }
    public sealed class Enumerator
    {
        public async Task<bool> MoveNextAsync()
        {
            System.Console.Write(""MoveNextAsync"");
            await Task.Yield();
            return false;
        }
        public int Current
        {
            get => throw null;
        }
    }
}";
            var comp = CreateCompilationWithTasksExtensions(new[] { source, s_IAsyncEnumerable }, options: TestOptions.DebugExe);
            comp.VerifyDiagnostics();
            CompileAndVerify(comp, expectedOutput: "MoveNextAsync");
 
            var runtimeAsyncComp = CreateRuntimeAsyncCompilation(source);
            var verifier = CompileAndVerify(runtimeAsyncComp, expectedOutput: CodeGenAsyncTests.ExpectedOutput("MoveNextAsync", isRuntimeAsync: true), verify: Verification.Fails with
            {
                ILVerifyMessage = """
                    [Main]: Return value missing on the stack. { Offset = 0x26 }
                    [MoveNextAsync]: Unexpected type on the stack. { Offset = 0x2f, Found = Int32, Expected = ref '[System.Runtime]System.Threading.Tasks.Task`1<bool>' }
                    """
            });
            verifier.VerifyIL("C.Main()", """
                {
                  // Code size       39 (0x27)
                  .maxstack  2
                  .locals init (C.Enumerator V_0)
                  IL_0000:  newobj     "C..ctor()"
                  IL_0005:  call       "int[] System.Array.Empty<int>()"
                  IL_000a:  call       "C.Enumerator C.GetAsyncEnumerator(params int[])"
                  IL_000f:  stloc.0
                  IL_0010:  br.s       IL_0019
                  IL_0012:  ldloc.0
                  IL_0013:  callvirt   "int C.Enumerator.Current.get"
                  IL_0018:  pop
                  IL_0019:  ldloc.0
                  IL_001a:  callvirt   "System.Threading.Tasks.Task<bool> C.Enumerator.MoveNextAsync()"
                  IL_001f:  call       "bool System.Runtime.CompilerServices.AsyncHelpers.Await<bool>(System.Threading.Tasks.Task<bool>)"
                  IL_0024:  brtrue.s   IL_0012
                  IL_0026:  ret
                }
                """);
        }
 
        [Fact]
        public void GetAsyncEnumerator_WithMultipleValidCandidatesWithOptionalParameters()
        {
            string source = @"
using System.Threading.Tasks;
using System.Collections.Generic;
class C
{
    public static async Task Main()
    {
        await foreach (var i in new C())
        {
        }
    }
    public IEnumerator<int> GetAsyncEnumerator(int a = 0) => throw null;
    public IEnumerator<int> GetAsyncEnumerator(bool a = true) => throw null;
}";
            var comp = CreateCompilationWithMscorlib46(source);
            comp.VerifyDiagnostics(
                    // (8,33): warning CS0278: 'C' does not implement the 'collection' pattern. 'C.GetAsyncEnumerator(int)' is ambiguous with 'C.GetAsyncEnumerator(bool)'.
                    //         await foreach (var i in new C())
                    Diagnostic(ErrorCode.WRN_PatternIsAmbiguous, "new C()").WithArguments("C", "collection", "C.GetAsyncEnumerator(int)", "C.GetAsyncEnumerator(bool)").WithLocation(8, 33),
                    // (8,33): error CS8411: Asynchronous foreach statement cannot operate on variables of type 'C' because 'C' does not contain a suitable public instance or extension definition for 'GetAsyncEnumerator'
                    //         await foreach (var i in new C())
                    Diagnostic(ErrorCode.ERR_AwaitForEachMissingMember, "new C()").WithArguments("C", "GetAsyncEnumerator").WithLocation(8, 33)
                );
        }
 
        [Fact]
        public void GetAsyncEnumerator_WithMultipleInvalidCandidates()
        {
            string source = @"
using System.Threading.Tasks;
using System.Collections.Generic;
class C
{
    public static async Task Main()
    {
        await foreach (var i in new C())
        {
        }
    }
    public IEnumerator<int> GetAsyncEnumerator(int a) => throw null;
    public IEnumerator<int> GetAsyncEnumerator(bool a) => throw null;
}";
            var comp = CreateCompilationWithMscorlib46(source);
            comp.VerifyDiagnostics(
                    // (8,33): error CS8411: Asynchronous foreach statement cannot operate on variables of type 'C' because 'C' does not contain a suitable public instance or extension definition for 'GetAsyncEnumerator'
                    //         await foreach (var i in new C())
                    Diagnostic(ErrorCode.ERR_AwaitForEachMissingMember, "new C()").WithArguments("C", "GetAsyncEnumerator").WithLocation(8, 33)
                );
        }
 
        [Fact]
        [WorkItem(32316, "https://github.com/dotnet/roslyn/issues/32316")]
        public void PatternBasedDisposal()
        {
            string source = @"
using System.Threading.Tasks;
class C
{
    public static async Task Main()
    {
        await foreach (var i in new C())
        {
        }
        System.Console.Write(""Done"");
    }
    public Enumerator GetAsyncEnumerator()
    {
        return new Enumerator();
    }
    public sealed class Enumerator
    {
        public async Task<bool> MoveNextAsync()
        {
            System.Console.Write(""MoveNextAsync "");
            await Task.Yield();
            return false;
        }
        public int Current
        {
            get => throw null;
        }
        public async Task DisposeAsync()
        {
            System.Console.Write(""DisposeAsync "");
            await Task.Yield();
        }
    }
}";
            var comp = CreateCompilationWithTasksExtensions(new[] { source, s_IAsyncEnumerable }, options: TestOptions.DebugExe);
            comp.VerifyDiagnostics();
            CompileAndVerify(comp, expectedOutput: "MoveNextAsync DisposeAsync Done");
 
            var runtimeAsyncComp = CreateRuntimeAsyncCompilation(source);
            var verifier = CompileAndVerify(runtimeAsyncComp, expectedOutput: CodeGenAsyncTests.ExpectedOutput("MoveNextAsync DisposeAsync Done", isRuntimeAsync: true), verify: Verification.Fails with
            {
                ILVerifyMessage = """
                    [Main]: Return value missing on the stack. { Offset = 0x58 }
                    [MoveNextAsync]: Unexpected type on the stack. { Offset = 0x2f, Found = Int32, Expected = ref '[System.Runtime]System.Threading.Tasks.Task`1<bool>' }
                    [DisposeAsync]: Return value missing on the stack. { Offset = 0x2e }
                    """
            });
            verifier.VerifyIL("C.Main()", """
                {
                  // Code size       89 (0x59)
                  .maxstack  2
                  .locals init (C.Enumerator V_0,
                                object V_1)
                  IL_0000:  newobj     "C..ctor()"
                  IL_0005:  call       "C.Enumerator C.GetAsyncEnumerator()"
                  IL_000a:  stloc.0
                  IL_000b:  ldnull
                  IL_000c:  stloc.1
                  .try
                  {
                    IL_000d:  br.s       IL_0016
                    IL_000f:  ldloc.0
                    IL_0010:  callvirt   "int C.Enumerator.Current.get"
                    IL_0015:  pop
                    IL_0016:  ldloc.0
                    IL_0017:  callvirt   "System.Threading.Tasks.Task<bool> C.Enumerator.MoveNextAsync()"
                    IL_001c:  call       "bool System.Runtime.CompilerServices.AsyncHelpers.Await<bool>(System.Threading.Tasks.Task<bool>)"
                    IL_0021:  brtrue.s   IL_000f
                    IL_0023:  leave.s    IL_0028
                  }
                  catch object
                  {
                    IL_0025:  stloc.1
                    IL_0026:  leave.s    IL_0028
                  }
                  IL_0028:  ldloc.0
                  IL_0029:  brfalse.s  IL_0036
                  IL_002b:  ldloc.0
                  IL_002c:  callvirt   "System.Threading.Tasks.Task C.Enumerator.DisposeAsync()"
                  IL_0031:  call       "void System.Runtime.CompilerServices.AsyncHelpers.Await(System.Threading.Tasks.Task)"
                  IL_0036:  ldloc.1
                  IL_0037:  brfalse.s  IL_004e
                  IL_0039:  ldloc.1
                  IL_003a:  isinst     "System.Exception"
                  IL_003f:  dup
                  IL_0040:  brtrue.s   IL_0044
                  IL_0042:  ldloc.1
                  IL_0043:  throw
                  IL_0044:  call       "System.Runtime.ExceptionServices.ExceptionDispatchInfo System.Runtime.ExceptionServices.ExceptionDispatchInfo.Capture(System.Exception)"
                  IL_0049:  callvirt   "void System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()"
                  IL_004e:  ldstr      "Done"
                  IL_0053:  call       "void System.Console.Write(string)"
                  IL_0058:  ret
                }
                """);
        }
 
        [Fact]
        [WorkItem(32316, "https://github.com/dotnet/roslyn/issues/32316")]
        public void PatternBasedDisposal_TwoOverloads()
        {
            string source = @"
using System.Threading.Tasks;
class C
{
    public static async Task Main()
    {
        await foreach (var i in new C())
        {
        }
        System.Console.Write(""Done"");
    }
    public Enumerator GetAsyncEnumerator()
    {
        return new Enumerator();
    }
    public sealed class Enumerator
    {
        public async Task<bool> MoveNextAsync()
        {
            System.Console.Write(""MoveNextAsync "");
            await Task.Yield();
            return false;
        }
        public int Current
        {
            get => throw null;
        }
        public async Task DisposeAsync(int i = 0)
        {
            System.Console.Write(""DisposeAsync "");
            await Task.Yield();
        }
        public Task DisposeAsync(params string[] s)
            => throw null;
    }
}";
            var comp = CreateCompilationWithTasksExtensions(new[] { source, s_IAsyncEnumerable }, options: TestOptions.DebugExe);
            comp.VerifyDiagnostics();
            CompileAndVerify(comp, expectedOutput: "MoveNextAsync DisposeAsync Done");
        }
 
        [Fact]
        [WorkItem(32316, "https://github.com/dotnet/roslyn/issues/32316")]
        public void PatternBasedDisposal_NoExtensions()
        {
            string source = @"
using System.Threading.Tasks;
public class C
{
    public static async Task Main()
    {
        await foreach (var i in new C())
        {
        }
        System.Console.Write(""Done"");
    }
    public Enumerator GetAsyncEnumerator()
    {
        return new Enumerator();
    }
    public sealed class Enumerator
    {
        public async Task<bool> MoveNextAsync()
        {
            System.Console.Write(""MoveNextAsync "");
            await Task.Yield();
            return false;
        }
        public int Current
        {
            get => throw null;
        }
    }
}
public static class Extension
{
    public static ValueTask DisposeAsync(this C.Enumerator e) => throw null;
}";
            // extension methods do not contribute to pattern-based disposal
            var comp = CreateCompilationWithTasksExtensions(new[] { source, s_IAsyncEnumerable }, options: TestOptions.DebugExe);
            comp.VerifyDiagnostics();
            CompileAndVerify(comp, expectedOutput: "MoveNextAsync Done");
 
            var runtimeAsyncComp = CreateRuntimeAsyncCompilation(source);
            var verifier = CompileAndVerify(runtimeAsyncComp, expectedOutput: CodeGenAsyncTests.ExpectedOutput("MoveNextAsync Done", isRuntimeAsync: true), verify: Verification.Fails with
            {
                ILVerifyMessage = """
                    [Main]: Return value missing on the stack. { Offset = 0x2b }
                    [MoveNextAsync]: Unexpected type on the stack. { Offset = 0x2f, Found = Int32, Expected = ref '[System.Runtime]System.Threading.Tasks.Task`1<bool>' }
                    """
            });
            verifier.VerifyIL("C.Main()", """
                {
                  // Code size       44 (0x2c)
                  .maxstack  1
                  .locals init (C.Enumerator V_0)
                  IL_0000:  newobj     "C..ctor()"
                  IL_0005:  call       "C.Enumerator C.GetAsyncEnumerator()"
                  IL_000a:  stloc.0
                  IL_000b:  br.s       IL_0014
                  IL_000d:  ldloc.0
                  IL_000e:  callvirt   "int C.Enumerator.Current.get"
                  IL_0013:  pop
                  IL_0014:  ldloc.0
                  IL_0015:  callvirt   "System.Threading.Tasks.Task<bool> C.Enumerator.MoveNextAsync()"
                  IL_001a:  call       "bool System.Runtime.CompilerServices.AsyncHelpers.Await<bool>(System.Threading.Tasks.Task<bool>)"
                  IL_001f:  brtrue.s   IL_000d
                  IL_0021:  ldstr      "Done"
                  IL_0026:  call       "void System.Console.Write(string)"
                  IL_002b:  ret
                }
                """);
        }
 
        [Fact]
        [WorkItem(32316, "https://github.com/dotnet/roslyn/issues/32316")]
        public void PatternBasedDisposal_NoExtensions_TwoExtensions()
        {
            string source = @"
using System.Threading.Tasks;
public class C
{
    public static async Task Main()
    {
        await foreach (var i in new C())
        {
        }
        System.Console.Write(""Done"");
    }
    public Enumerator GetAsyncEnumerator()
    {
        return new Enumerator();
    }
    public sealed class Enumerator
    {
        public async Task<bool> MoveNextAsync()
        {
            System.Console.Write(""MoveNextAsync "");
            await Task.Yield();
            return false;
        }
        public int Current
        {
            get => throw null;
        }
    }
}
public static class Extension1
{
    public static ValueTask DisposeAsync(this C.Enumerator c) => throw null;
}
public static class Extension2
{
    public static ValueTask DisposeAsync(this C.Enumerator c) => throw null;
}
";
            // extension methods do not contribute to pattern-based disposal
            var comp = CreateCompilationWithTasksExtensions(new[] { source, s_IAsyncEnumerable }, options: TestOptions.DebugExe);
            comp.VerifyDiagnostics();
            CompileAndVerify(comp, expectedOutput: "MoveNextAsync Done");
 
            var runtimeAsyncComp = CreateRuntimeAsyncCompilation(source);
            var verifier = CompileAndVerify(runtimeAsyncComp, expectedOutput: CodeGenAsyncTests.ExpectedOutput("MoveNextAsync Done", isRuntimeAsync: true), verify: Verification.Fails with
            {
                ILVerifyMessage = """
                    [Main]: Return value missing on the stack. { Offset = 0x2b }
                    [MoveNextAsync]: Unexpected type on the stack. { Offset = 0x2f, Found = Int32, Expected = ref '[System.Runtime]System.Threading.Tasks.Task`1<bool>' }
                    """
            });
            verifier.VerifyIL("C.Main()", """
                {
                  // Code size       44 (0x2c)
                  .maxstack  1
                  .locals init (C.Enumerator V_0)
                  IL_0000:  newobj     "C..ctor()"
                  IL_0005:  call       "C.Enumerator C.GetAsyncEnumerator()"
                  IL_000a:  stloc.0
                  IL_000b:  br.s       IL_0014
                  IL_000d:  ldloc.0
                  IL_000e:  callvirt   "int C.Enumerator.Current.get"
                  IL_0013:  pop
                  IL_0014:  ldloc.0
                  IL_0015:  callvirt   "System.Threading.Tasks.Task<bool> C.Enumerator.MoveNextAsync()"
                  IL_001a:  call       "bool System.Runtime.CompilerServices.AsyncHelpers.Await<bool>(System.Threading.Tasks.Task<bool>)"
                  IL_001f:  brtrue.s   IL_000d
                  IL_0021:  ldstr      "Done"
                  IL_0026:  call       "void System.Console.Write(string)"
                  IL_002b:  ret
                }
                """);
        }
 
        [Fact]
        [WorkItem(32316, "https://github.com/dotnet/roslyn/issues/32316")]
        public void PatternBasedDisposal_InstanceMethodPreferredOverInterface()
        {
            string source = @"
using System.Threading.Tasks;
class C
{
    public static async Task Main()
    {
        await foreach (var i in new C())
        {
        }
        System.Console.Write(""Done"");
    }
    public Enumerator GetAsyncEnumerator()
    {
        return new Enumerator();
    }
    public sealed class Enumerator : System.IAsyncDisposable
    {
        public async Task<bool> MoveNextAsync()
        {
            System.Console.Write(""MoveNextAsync "");
            await Task.Yield();
            return false;
        }
        public int Current
        {
            get => throw null;
        }
        ValueTask System.IAsyncDisposable.DisposeAsync() => throw null;
        public async ValueTask DisposeAsync()
        {
            System.Console.Write(""DisposeAsync "");
            await Task.Yield();
        }
    }
}";
            var comp = CreateCompilationWithTasksExtensions(new[] { source, s_IAsyncEnumerable }, options: TestOptions.DebugExe);
            comp.VerifyDiagnostics();
            CompileAndVerify(comp, expectedOutput: "MoveNextAsync DisposeAsync Done");
 
            var runtimeAsyncComp = CreateRuntimeAsyncCompilation(source);
            var verifier = CompileAndVerify(runtimeAsyncComp, expectedOutput: CodeGenAsyncTests.ExpectedOutput("MoveNextAsync DisposeAsync Done", isRuntimeAsync: true), verify: Verification.Fails with
            {
                ILVerifyMessage = """
                    [Main]: Return value missing on the stack. { Offset = 0x58 }
                    [MoveNextAsync]: Unexpected type on the stack. { Offset = 0x2f, Found = Int32, Expected = ref '[System.Runtime]System.Threading.Tasks.Task`1<bool>' }
                    [DisposeAsync]: Return value missing on the stack. { Offset = 0x2e }
                    """
            });
            verifier.VerifyIL("C.Main()", """
                {
                  // Code size       89 (0x59)
                  .maxstack  2
                  .locals init (C.Enumerator V_0,
                                object V_1)
                  IL_0000:  newobj     "C..ctor()"
                  IL_0005:  call       "C.Enumerator C.GetAsyncEnumerator()"
                  IL_000a:  stloc.0
                  IL_000b:  ldnull
                  IL_000c:  stloc.1
                  .try
                  {
                    IL_000d:  br.s       IL_0016
                    IL_000f:  ldloc.0
                    IL_0010:  callvirt   "int C.Enumerator.Current.get"
                    IL_0015:  pop
                    IL_0016:  ldloc.0
                    IL_0017:  callvirt   "System.Threading.Tasks.Task<bool> C.Enumerator.MoveNextAsync()"
                    IL_001c:  call       "bool System.Runtime.CompilerServices.AsyncHelpers.Await<bool>(System.Threading.Tasks.Task<bool>)"
                    IL_0021:  brtrue.s   IL_000f
                    IL_0023:  leave.s    IL_0028
                  }
                  catch object
                  {
                    IL_0025:  stloc.1
                    IL_0026:  leave.s    IL_0028
                  }
                  IL_0028:  ldloc.0
                  IL_0029:  brfalse.s  IL_0036
                  IL_002b:  ldloc.0
                  IL_002c:  callvirt   "System.Threading.Tasks.ValueTask C.Enumerator.DisposeAsync()"
                  IL_0031:  call       "void System.Runtime.CompilerServices.AsyncHelpers.Await(System.Threading.Tasks.ValueTask)"
                  IL_0036:  ldloc.1
                  IL_0037:  brfalse.s  IL_004e
                  IL_0039:  ldloc.1
                  IL_003a:  isinst     "System.Exception"
                  IL_003f:  dup
                  IL_0040:  brtrue.s   IL_0044
                  IL_0042:  ldloc.1
                  IL_0043:  throw
                  IL_0044:  call       "System.Runtime.ExceptionServices.ExceptionDispatchInfo System.Runtime.ExceptionServices.ExceptionDispatchInfo.Capture(System.Exception)"
                  IL_0049:  callvirt   "void System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()"
                  IL_004e:  ldstr      "Done"
                  IL_0053:  call       "void System.Console.Write(string)"
                  IL_0058:  ret
                }
                """);
        }
 
        [Fact]
        [WorkItem(32316, "https://github.com/dotnet/roslyn/issues/32316")]
        public void PatternBasedDisposal_ReturnsVoid()
        {
            string source = @"
using System.Threading.Tasks;
class C
{
    public static async Task Main()
    {
        await foreach (var i in new C())
        {
        }
    }
    public Enumerator GetAsyncEnumerator()
        => throw null;
    public sealed class Enumerator
    {
        public Task<bool> MoveNextAsync()
            => throw null;
        public int Current
        {
            get => throw null;
        }
        public void DisposeAsync()
            => throw null;
    }
}";
            var comp = CreateCompilationWithTasksExtensions(new[] { source, s_IAsyncEnumerable });
            comp.VerifyDiagnostics(
                // (7,33): error CS4008: Cannot await 'void'
                //         await foreach (var i in new C())
                Diagnostic(ErrorCode.ERR_BadAwaitArgVoidCall, "new C()").WithLocation(7, 33)
                );
        }
 
        [Fact]
        [WorkItem(32316, "https://github.com/dotnet/roslyn/issues/32316")]
        public void PatternBasedDisposal_ReturnsInt()
        {
            string source = @"
using System.Threading.Tasks;
class C
{
    public static async Task Main()
    {
        await foreach (var i in new C())
        {
        }
    }
    public Enumerator GetAsyncEnumerator()
    {
        return new Enumerator();
    }
    public sealed class Enumerator
    {
        public async Task<bool> MoveNextAsync()
        {
            await Task.Yield();
            return false;
        }
        public int Current
        {
            get => throw null;
        }
        public int DisposeAsync()
        {
            throw null;
        }
    }
}";
            var comp = CreateCompilationWithTasksExtensions(new[] { source, s_IAsyncEnumerable });
            comp.VerifyDiagnostics(
                // (7,33): error CS1061: 'int' does not contain a definition for 'GetAwaiter' and no accessible extension method 'GetAwaiter' accepting a first argument of type 'int' could be found (are you missing a using directive or an assembly reference?)
                //         await foreach (var i in new C())
                Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "new C()").WithArguments("int", "GetAwaiter").WithLocation(7, 33)
                );
        }
 
        [Fact]
        [WorkItem(32316, "https://github.com/dotnet/roslyn/issues/32316")]
        public void PatternBasedDisposal_ReturnsAwaitable()
        {
            string source = @"
using System.Threading.Tasks;
class C
{
    public static async Task Main()
    {
        await foreach (var i in new C())
        {
        }
        System.Console.Write(""Done"");
    }
    public Enumerator GetAsyncEnumerator()
    {
        return new Enumerator();
    }
    public sealed class Enumerator
    {
        public async Task<bool> MoveNextAsync()
        {
            System.Console.Write(""MoveNextAsync "");
            await Task.Yield();
            return false;
        }
        public int Current
        {
            get => throw null;
        }
        public Awaitable DisposeAsync()
        {
            System.Console.Write(""DisposeAsync "");
            return new Awaitable();
        }
    }
}
 
public class Awaitable
{
    public Awaiter GetAwaiter() { return new Awaiter(); }
}
public class Awaiter : System.Runtime.CompilerServices.INotifyCompletion
{
    public bool IsCompleted { get { return true; } }
    public bool GetResult() { return true; }
    public void OnCompleted(System.Action continuation) { }
}
";
            var comp = CreateCompilationWithTasksExtensions(new[] { source, s_IAsyncEnumerable }, options: TestOptions.DebugExe);
            comp.VerifyDiagnostics();
            CompileAndVerify(comp, expectedOutput: "MoveNextAsync DisposeAsync Done");
 
            var runtimeAsyncComp = CreateRuntimeAsyncCompilation(source);
            var verifier = CompileAndVerify(runtimeAsyncComp, expectedOutput: CodeGenAsyncTests.ExpectedOutput("MoveNextAsync DisposeAsync Done", isRuntimeAsync: true), verify: Verification.Fails with
            {
                ILVerifyMessage = """
                    [Main]: Return value missing on the stack. { Offset = 0x6e }
                    [MoveNextAsync]: Unexpected type on the stack. { Offset = 0x2f, Found = Int32, Expected = ref '[System.Runtime]System.Threading.Tasks.Task`1<bool>' }
                    """
            });
            verifier.VerifyIL("C.Main()", """
                {
                  // Code size      111 (0x6f)
                  .maxstack  2
                  .locals init (C.Enumerator V_0,
                                object V_1,
                                Awaiter V_2)
                  IL_0000:  newobj     "C..ctor()"
                  IL_0005:  call       "C.Enumerator C.GetAsyncEnumerator()"
                  IL_000a:  stloc.0
                  IL_000b:  ldnull
                  IL_000c:  stloc.1
                  .try
                  {
                    IL_000d:  br.s       IL_0016
                    IL_000f:  ldloc.0
                    IL_0010:  callvirt   "int C.Enumerator.Current.get"
                    IL_0015:  pop
                    IL_0016:  ldloc.0
                    IL_0017:  callvirt   "System.Threading.Tasks.Task<bool> C.Enumerator.MoveNextAsync()"
                    IL_001c:  call       "bool System.Runtime.CompilerServices.AsyncHelpers.Await<bool>(System.Threading.Tasks.Task<bool>)"
                    IL_0021:  brtrue.s   IL_000f
                    IL_0023:  leave.s    IL_0028
                  }
                  catch object
                  {
                    IL_0025:  stloc.1
                    IL_0026:  leave.s    IL_0028
                  }
                  IL_0028:  ldloc.0
                  IL_0029:  brfalse.s  IL_004c
                  IL_002b:  ldloc.0
                  IL_002c:  callvirt   "Awaitable C.Enumerator.DisposeAsync()"
                  IL_0031:  callvirt   "Awaiter Awaitable.GetAwaiter()"
                  IL_0036:  stloc.2
                  IL_0037:  ldloc.2
                  IL_0038:  callvirt   "bool Awaiter.IsCompleted.get"
                  IL_003d:  brtrue.s   IL_0045
                  IL_003f:  ldloc.2
                  IL_0040:  call       "void System.Runtime.CompilerServices.AsyncHelpers.AwaitAwaiter<Awaiter>(Awaiter)"
                  IL_0045:  ldloc.2
                  IL_0046:  callvirt   "bool Awaiter.GetResult()"
                  IL_004b:  pop
                  IL_004c:  ldloc.1
                  IL_004d:  brfalse.s  IL_0064
                  IL_004f:  ldloc.1
                  IL_0050:  isinst     "System.Exception"
                  IL_0055:  dup
                  IL_0056:  brtrue.s   IL_005a
                  IL_0058:  ldloc.1
                  IL_0059:  throw
                  IL_005a:  call       "System.Runtime.ExceptionServices.ExceptionDispatchInfo System.Runtime.ExceptionServices.ExceptionDispatchInfo.Capture(System.Exception)"
                  IL_005f:  callvirt   "void System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()"
                  IL_0064:  ldstr      "Done"
                  IL_0069:  call       "void System.Console.Write(string)"
                  IL_006e:  ret
                }
                """);
        }
 
        [Fact]
        [WorkItem(32316, "https://github.com/dotnet/roslyn/issues/32316")]
        public void PatternBasedDisposal_ReturnsTask()
        {
            string source = @"
using System.Threading.Tasks;
class C
{
    public static async Task Main()
    {
        await foreach (var i in new C())
        {
        }
        System.Console.Write(""Done"");
    }
    public Enumerator GetAsyncEnumerator()
    {
        return new Enumerator();
    }
    public sealed class Enumerator
    {
        public async Task<bool> MoveNextAsync()
        {
            System.Console.Write(""MoveNextAsync "");
            await Task.Yield();
            return false;
        }
        public int Current
        {
            get => throw null;
        }
        public async Task DisposeAsync()
        {
            System.Console.Write(""DisposeAsync "");
            await Task.Yield();
        }
    }
}
";
            var comp = CreateCompilationWithTasksExtensions(new[] { source, s_IAsyncEnumerable }, options: TestOptions.DebugExe);
            comp.VerifyDiagnostics();
            CompileAndVerify(comp, expectedOutput: "MoveNextAsync DisposeAsync Done");
 
            var runtimeAsyncComp = CreateRuntimeAsyncCompilation(source);
            var verifier = CompileAndVerify(runtimeAsyncComp, expectedOutput: CodeGenAsyncTests.ExpectedOutput("MoveNextAsync DisposeAsync Done", isRuntimeAsync: true), verify: Verification.Fails with
            {
                ILVerifyMessage = """
                    [Main]: Return value missing on the stack. { Offset = 0x58 }
                    [MoveNextAsync]: Unexpected type on the stack. { Offset = 0x2f, Found = Int32, Expected = ref '[System.Runtime]System.Threading.Tasks.Task`1<bool>' }
                    [DisposeAsync]: Return value missing on the stack. { Offset = 0x2e }
                    """
            });
            verifier.VerifyIL("C.Main()", """
                {
                  // Code size       89 (0x59)
                  .maxstack  2
                  .locals init (C.Enumerator V_0,
                                object V_1)
                  IL_0000:  newobj     "C..ctor()"
                  IL_0005:  call       "C.Enumerator C.GetAsyncEnumerator()"
                  IL_000a:  stloc.0
                  IL_000b:  ldnull
                  IL_000c:  stloc.1
                  .try
                  {
                    IL_000d:  br.s       IL_0016
                    IL_000f:  ldloc.0
                    IL_0010:  callvirt   "int C.Enumerator.Current.get"
                    IL_0015:  pop
                    IL_0016:  ldloc.0
                    IL_0017:  callvirt   "System.Threading.Tasks.Task<bool> C.Enumerator.MoveNextAsync()"
                    IL_001c:  call       "bool System.Runtime.CompilerServices.AsyncHelpers.Await<bool>(System.Threading.Tasks.Task<bool>)"
                    IL_0021:  brtrue.s   IL_000f
                    IL_0023:  leave.s    IL_0028
                  }
                  catch object
                  {
                    IL_0025:  stloc.1
                    IL_0026:  leave.s    IL_0028
                  }
                  IL_0028:  ldloc.0
                  IL_0029:  brfalse.s  IL_0036
                  IL_002b:  ldloc.0
                  IL_002c:  callvirt   "System.Threading.Tasks.Task C.Enumerator.DisposeAsync()"
                  IL_0031:  call       "void System.Runtime.CompilerServices.AsyncHelpers.Await(System.Threading.Tasks.Task)"
                  IL_0036:  ldloc.1
                  IL_0037:  brfalse.s  IL_004e
                  IL_0039:  ldloc.1
                  IL_003a:  isinst     "System.Exception"
                  IL_003f:  dup
                  IL_0040:  brtrue.s   IL_0044
                  IL_0042:  ldloc.1
                  IL_0043:  throw
                  IL_0044:  call       "System.Runtime.ExceptionServices.ExceptionDispatchInfo System.Runtime.ExceptionServices.ExceptionDispatchInfo.Capture(System.Exception)"
                  IL_0049:  callvirt   "void System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()"
                  IL_004e:  ldstr      "Done"
                  IL_0053:  call       "void System.Console.Write(string)"
                  IL_0058:  ret
                }
                """);
        }
 
        [Fact]
        [WorkItem(32316, "https://github.com/dotnet/roslyn/issues/32316")]
        public void PatternBasedDisposal_ReturnsTaskOfInt()
        {
            string source = @"
using System.Threading.Tasks;
class C
{
    public static async Task Main()
    {
        await foreach (var i in new C())
        {
        }
        System.Console.Write(""Done"");
    }
    public Enumerator GetAsyncEnumerator()
    {
        return new Enumerator();
    }
    public sealed class Enumerator
    {
        public async Task<bool> MoveNextAsync()
        {
            System.Console.Write(""MoveNextAsync "");
            await Task.Yield();
            return false;
        }
        public int Current
        {
            get => throw null;
        }
        public async Task<int> DisposeAsync()
        {
            System.Console.Write(""DisposeAsync "");
            await Task.Yield();
            return 1;
        }
    }
}
";
            // it's okay to await `Task<int>` even if we don't care about the result
            var comp = CreateCompilationWithTasksExtensions(new[] { source, s_IAsyncEnumerable }, options: TestOptions.DebugExe);
            comp.VerifyDiagnostics();
            CompileAndVerify(comp, expectedOutput: "MoveNextAsync DisposeAsync Done");
 
            var runtimeAsyncComp = CreateRuntimeAsyncCompilation(source);
            var verifier = CompileAndVerify(runtimeAsyncComp, expectedOutput: CodeGenAsyncTests.ExpectedOutput("MoveNextAsync DisposeAsync Done", isRuntimeAsync: true), verify: Verification.Fails with
            {
                ILVerifyMessage = """
                    [Main]: Return value missing on the stack. { Offset = 0x59 }
                    [MoveNextAsync]: Unexpected type on the stack. { Offset = 0x2f, Found = Int32, Expected = ref '[System.Runtime]System.Threading.Tasks.Task`1<bool>' }
                    [DisposeAsync]: Unexpected type on the stack. { Offset = 0x2f, Found = Int32, Expected = ref '[System.Runtime]System.Threading.Tasks.Task`1<int32>' }
                    """
            });
            verifier.VerifyIL("C.Main()", """
                {
                  // Code size       90 (0x5a)
                  .maxstack  2
                  .locals init (C.Enumerator V_0,
                                object V_1)
                  IL_0000:  newobj     "C..ctor()"
                  IL_0005:  call       "C.Enumerator C.GetAsyncEnumerator()"
                  IL_000a:  stloc.0
                  IL_000b:  ldnull
                  IL_000c:  stloc.1
                  .try
                  {
                    IL_000d:  br.s       IL_0016
                    IL_000f:  ldloc.0
                    IL_0010:  callvirt   "int C.Enumerator.Current.get"
                    IL_0015:  pop
                    IL_0016:  ldloc.0
                    IL_0017:  callvirt   "System.Threading.Tasks.Task<bool> C.Enumerator.MoveNextAsync()"
                    IL_001c:  call       "bool System.Runtime.CompilerServices.AsyncHelpers.Await<bool>(System.Threading.Tasks.Task<bool>)"
                    IL_0021:  brtrue.s   IL_000f
                    IL_0023:  leave.s    IL_0028
                  }
                  catch object
                  {
                    IL_0025:  stloc.1
                    IL_0026:  leave.s    IL_0028
                  }
                  IL_0028:  ldloc.0
                  IL_0029:  brfalse.s  IL_0037
                  IL_002b:  ldloc.0
                  IL_002c:  callvirt   "System.Threading.Tasks.Task<int> C.Enumerator.DisposeAsync()"
                  IL_0031:  call       "int System.Runtime.CompilerServices.AsyncHelpers.Await<int>(System.Threading.Tasks.Task<int>)"
                  IL_0036:  pop
                  IL_0037:  ldloc.1
                  IL_0038:  brfalse.s  IL_004f
                  IL_003a:  ldloc.1
                  IL_003b:  isinst     "System.Exception"
                  IL_0040:  dup
                  IL_0041:  brtrue.s   IL_0045
                  IL_0043:  ldloc.1
                  IL_0044:  throw
                  IL_0045:  call       "System.Runtime.ExceptionServices.ExceptionDispatchInfo System.Runtime.ExceptionServices.ExceptionDispatchInfo.Capture(System.Exception)"
                  IL_004a:  callvirt   "void System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()"
                  IL_004f:  ldstr      "Done"
                  IL_0054:  call       "void System.Console.Write(string)"
                  IL_0059:  ret
                }
                """);
        }
 
        [Fact]
        public void PatternBasedDisposal_WithOptionalParameter()
        {
            string source = @"
using System.Threading.Tasks;
class C
{
    public static async Task Main()
    {
        await foreach (var i in new C())
        {
        }
        System.Console.Write(""Done"");
    }
    public Enumerator GetAsyncEnumerator()
    {
        return new Enumerator();
    }
    public sealed class Enumerator
    {
        public async Task<bool> MoveNextAsync()
        {
            System.Console.Write(""MoveNextAsync "");
            await Task.Yield();
            return false;
        }
        public int Current
        {
            get => throw null;
        }
        public async Task<int> DisposeAsync(int i = 1)
        {
            System.Console.Write($""DisposeAsync {i} "");
            await Task.Yield();
            return 1;
        }
    }
}
";
            // it's okay to await `Task<int>` even if we don't care about the result
            var comp = CreateCompilationWithTasksExtensions(new[] { source, s_IAsyncEnumerable }, options: TestOptions.DebugExe);
            comp.VerifyDiagnostics();
            CompileAndVerify(comp, expectedOutput: "MoveNextAsync DisposeAsync 1 Done");
 
            var runtimeAsyncComp = CreateRuntimeAsyncCompilation(source);
            var verifier = CompileAndVerify(runtimeAsyncComp, expectedOutput: CodeGenAsyncTests.ExpectedOutput("MoveNextAsync DisposeAsync 1 Done", isRuntimeAsync: true), verify: Verification.Fails with
            {
                ILVerifyMessage = """
                    [Main]: Return value missing on the stack. { Offset = 0x5a }
                    [MoveNextAsync]: Unexpected type on the stack. { Offset = 0x2f, Found = Int32, Expected = ref '[System.Runtime]System.Threading.Tasks.Task`1<bool>' }
                    [DisposeAsync]: Unexpected type on the stack. { Offset = 0x5b, Found = Int32, Expected = ref '[System.Runtime]System.Threading.Tasks.Task`1<int32>' }
                    """
            });
            verifier.VerifyIL("C.Main()", """
                {
                  // Code size       91 (0x5b)
                  .maxstack  2
                  .locals init (C.Enumerator V_0,
                                object V_1)
                  IL_0000:  newobj     "C..ctor()"
                  IL_0005:  call       "C.Enumerator C.GetAsyncEnumerator()"
                  IL_000a:  stloc.0
                  IL_000b:  ldnull
                  IL_000c:  stloc.1
                  .try
                  {
                    IL_000d:  br.s       IL_0016
                    IL_000f:  ldloc.0
                    IL_0010:  callvirt   "int C.Enumerator.Current.get"
                    IL_0015:  pop
                    IL_0016:  ldloc.0
                    IL_0017:  callvirt   "System.Threading.Tasks.Task<bool> C.Enumerator.MoveNextAsync()"
                    IL_001c:  call       "bool System.Runtime.CompilerServices.AsyncHelpers.Await<bool>(System.Threading.Tasks.Task<bool>)"
                    IL_0021:  brtrue.s   IL_000f
                    IL_0023:  leave.s    IL_0028
                  }
                  catch object
                  {
                    IL_0025:  stloc.1
                    IL_0026:  leave.s    IL_0028
                  }
                  IL_0028:  ldloc.0
                  IL_0029:  brfalse.s  IL_0038
                  IL_002b:  ldloc.0
                  IL_002c:  ldc.i4.1
                  IL_002d:  callvirt   "System.Threading.Tasks.Task<int> C.Enumerator.DisposeAsync(int)"
                  IL_0032:  call       "int System.Runtime.CompilerServices.AsyncHelpers.Await<int>(System.Threading.Tasks.Task<int>)"
                  IL_0037:  pop
                  IL_0038:  ldloc.1
                  IL_0039:  brfalse.s  IL_0050
                  IL_003b:  ldloc.1
                  IL_003c:  isinst     "System.Exception"
                  IL_0041:  dup
                  IL_0042:  brtrue.s   IL_0046
                  IL_0044:  ldloc.1
                  IL_0045:  throw
                  IL_0046:  call       "System.Runtime.ExceptionServices.ExceptionDispatchInfo System.Runtime.ExceptionServices.ExceptionDispatchInfo.Capture(System.Exception)"
                  IL_004b:  callvirt   "void System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()"
                  IL_0050:  ldstr      "Done"
                  IL_0055:  call       "void System.Console.Write(string)"
                  IL_005a:  ret
                }
                """);
        }
 
        [Fact]
        [WorkItem(30956, "https://github.com/dotnet/roslyn/issues/30956")]
        public void GetAwaiterBoxingConversion()
        {
            var source =
@"using System;
using System.Runtime.CompilerServices;
using System.Threading.Tasks;
 
interface I1 { }
interface I2 { }
struct StructAwaitable1 : I1 { }
struct StructAwaitable2 : I2 { }
 
class Enumerable
{
    public Enumerator GetAsyncEnumerator() => new Enumerator();
    internal class Enumerator
    {
        public object Current => null;
        public StructAwaitable1 MoveNextAsync() => new StructAwaitable1();
        public StructAwaitable2 DisposeAsync() => new StructAwaitable2();
    }
}
 
static class Extensions
{
    internal static TaskAwaiter<bool> GetAwaiter(this I1 x)
    {
        if (x == null) throw new ArgumentNullException(nameof(x));
        Console.Write(x);
        return Task.FromResult(false).GetAwaiter();
    }
    internal static TaskAwaiter GetAwaiter(this I2 x)
    {
        if (x == null) throw new ArgumentNullException(nameof(x));
        Console.Write(x);
        return Task.CompletedTask.GetAwaiter();
    }
}
 
class Program
{
    static async Task Main()
    {
        await foreach (var o in new Enumerable())
        {
        }
    }
}";
            var comp = CreateCompilationWithTasksExtensions(new[] { source, s_IAsyncEnumerable }, options: TestOptions.ReleaseExe);
            CompileAndVerify(comp, expectedOutput: "StructAwaitable1StructAwaitable2");
 
            var runtimeAsyncComp = CreateRuntimeAsyncCompilation(source, options: TestOptions.ReleaseExe.WithSpecificDiagnosticOptions("SYSLIB5007", ReportDiagnostic.Suppress));
            var verifier = CompileAndVerify(runtimeAsyncComp, expectedOutput: CodeGenAsyncTests.ExpectedOutput("StructAwaitable1StructAwaitable2", isRuntimeAsync: true), verify: Verification.Fails with
            {
                ILVerifyMessage = """
                    [Main]: Return value missing on the stack. { Offset = 0x86 }
                    """
            });
            verifier.VerifyIL("Program.Main()", """
                {
                  // Code size      135 (0x87)
                  .maxstack  2
                  .locals init (Enumerable.Enumerator V_0,
                                object V_1,
                                System.Runtime.CompilerServices.TaskAwaiter<bool> V_2,
                                System.Runtime.CompilerServices.TaskAwaiter V_3)
                  IL_0000:  newobj     "Enumerable..ctor()"
                  IL_0005:  call       "Enumerable.Enumerator Enumerable.GetAsyncEnumerator()"
                  IL_000a:  stloc.0
                  IL_000b:  ldnull
                  IL_000c:  stloc.1
                  .try
                  {
                    IL_000d:  br.s       IL_0016
                    IL_000f:  ldloc.0
                    IL_0010:  callvirt   "object Enumerable.Enumerator.Current.get"
                    IL_0015:  pop
                    IL_0016:  ldloc.0
                    IL_0017:  callvirt   "StructAwaitable1 Enumerable.Enumerator.MoveNextAsync()"
                    IL_001c:  box        "StructAwaitable1"
                    IL_0021:  call       "System.Runtime.CompilerServices.TaskAwaiter<bool> Extensions.GetAwaiter(I1)"
                    IL_0026:  stloc.2
                    IL_0027:  ldloca.s   V_2
                    IL_0029:  call       "bool System.Runtime.CompilerServices.TaskAwaiter<bool>.IsCompleted.get"
                    IL_002e:  brtrue.s   IL_0036
                    IL_0030:  ldloc.2
                    IL_0031:  call       "void System.Runtime.CompilerServices.AsyncHelpers.UnsafeAwaitAwaiter<System.Runtime.CompilerServices.TaskAwaiter<bool>>(System.Runtime.CompilerServices.TaskAwaiter<bool>)"
                    IL_0036:  ldloca.s   V_2
                    IL_0038:  call       "bool System.Runtime.CompilerServices.TaskAwaiter<bool>.GetResult()"
                    IL_003d:  brtrue.s   IL_000f
                    IL_003f:  leave.s    IL_0044
                  }
                  catch object
                  {
                    IL_0041:  stloc.1
                    IL_0042:  leave.s    IL_0044
                  }
                  IL_0044:  ldloc.0
                  IL_0045:  brfalse.s  IL_006e
                  IL_0047:  ldloc.0
                  IL_0048:  callvirt   "StructAwaitable2 Enumerable.Enumerator.DisposeAsync()"
                  IL_004d:  box        "StructAwaitable2"
                  IL_0052:  call       "System.Runtime.CompilerServices.TaskAwaiter Extensions.GetAwaiter(I2)"
                  IL_0057:  stloc.3
                  IL_0058:  ldloca.s   V_3
                  IL_005a:  call       "bool System.Runtime.CompilerServices.TaskAwaiter.IsCompleted.get"
                  IL_005f:  brtrue.s   IL_0067
                  IL_0061:  ldloc.3
                  IL_0062:  call       "void System.Runtime.CompilerServices.AsyncHelpers.UnsafeAwaitAwaiter<System.Runtime.CompilerServices.TaskAwaiter>(System.Runtime.CompilerServices.TaskAwaiter)"
                  IL_0067:  ldloca.s   V_3
                  IL_0069:  call       "void System.Runtime.CompilerServices.TaskAwaiter.GetResult()"
                  IL_006e:  ldloc.1
                  IL_006f:  brfalse.s  IL_0086
                  IL_0071:  ldloc.1
                  IL_0072:  isinst     "System.Exception"
                  IL_0077:  dup
                  IL_0078:  brtrue.s   IL_007c
                  IL_007a:  ldloc.1
                  IL_007b:  throw
                  IL_007c:  call       "System.Runtime.ExceptionServices.ExceptionDispatchInfo System.Runtime.ExceptionServices.ExceptionDispatchInfo.Capture(System.Exception)"
                  IL_0081:  callvirt   "void System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()"
                  IL_0086:  ret
                }
                """);
        }
 
        [Fact]
        public void TestInvalidForeachOnConstantNullObject()
        {
            var source = @"
using System;
using System.Threading.Tasks;
public class C
{
    public static async Task Main()
    {
        await foreach (var i in (object)null)
        {
            Console.Write(i);
        }
    }
}";
            CreateCompilation(source, parseOptions: TestOptions.Regular9)
                .VerifyDiagnostics(
                    // (8,33): error CS8411: Asynchronous foreach statement cannot operate on variables of type 'object' because 'object' does not contain a suitable public instance or extension definition for 'GetAsyncEnumerator'
                    //         await foreach (var i in (object)null)
                    Diagnostic(ErrorCode.ERR_AwaitForEachMissingMember, "(object)null").WithArguments("object", "GetAsyncEnumerator").WithLocation(8, 33)
                    );
        }
 
        [Fact]
        public void TestConstantNullObjectImplementingIEnumerable()
        {
            var source = @"
using System;
using System.Threading.Tasks;
using System.Collections.Generic;
public class C
{
    public static async Task Main()
    {
        await foreach (var i in (IAsyncEnumerable<int>)null)
        {
            Console.Write(i);
        }
    }
}";
            CreateCompilationWithTasksExtensions(new[] { source, AsyncStreamsTypes }, parseOptions: TestOptions.Regular9)
                .VerifyDiagnostics(
                    // (9,33): error CS0186: Use of null is not valid in this context
                    //         await foreach (var i in (IAsyncEnumerable<int>)null)
                    Diagnostic(ErrorCode.ERR_NullNotValid, "(IAsyncEnumerable<int>)null").WithLocation(9, 33)
                    );
        }
 
        [Fact]
        public void TestConstantNullObjectWithGetAsyncEnumeratorPattern()
        {
            var source = @"
using System;
using System.Threading.Tasks;
using System.Collections.Generic;
public class C
{
    public static async Task Main()
    {
        await foreach (var i in (C)null)
        {
            Console.Write(i);
        }
    }
 
    public IAsyncEnumerator<int> GetAsyncEnumerator() => throw null;
}";
            CreateCompilationWithTasksExtensions(new[] { source, AsyncStreamsTypes }, parseOptions: TestOptions.Regular9)
                .VerifyDiagnostics(
                    // (9,33): error CS0186: Use of null is not valid in this context
                    //         await foreach (var i in (C)null)
                    Diagnostic(ErrorCode.ERR_NullNotValid, "(C)null").WithLocation(9, 33)
                    );
        }
 
        [Fact]
        public void TestConstantNullableImplementingIEnumerable()
        {
            var source = @"
using System;
using System.Threading.Tasks;
using System.Collections.Generic;
public struct C : IAsyncEnumerable<int>
{
    public static async Task Main()
    {
        await foreach (var i in (C?)null)
        {
            Console.Write(i);
        }
    }
 
    IAsyncEnumerator<int> IAsyncEnumerable<int>.GetAsyncEnumerator(System.Threading.CancellationToken cancellationToken) => throw null;
}";
            var comp = CreateCompilationWithTasksExtensions(new[] { source, AsyncStreamsTypes }, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular9);
            comp.VerifyDiagnostics();
            CompileAndVerify(comp);
 
            var runtimeAsyncComp = CreateRuntimeAsyncCompilation(source);
            var verifier = CompileAndVerify(runtimeAsyncComp, verify: Verification.Fails with
            {
                ILVerifyMessage = """
                    [Main]: Return value missing on the stack. { Offset = 0x72 }
                    """
            });
            verifier.VerifyIL("C.Main()", """
                {
                  // Code size      115 (0x73)
                  .maxstack  2
                  .locals init (System.Collections.Generic.IAsyncEnumerator<int> V_0,
                                C? V_1,
                                C V_2,
                                System.Threading.CancellationToken V_3,
                                object V_4)
                  IL_0000:  ldloca.s   V_1
                  IL_0002:  dup
                  IL_0003:  initobj    "C?"
                  IL_0009:  call       "readonly C C?.Value.get"
                  IL_000e:  stloc.2
                  IL_000f:  ldloca.s   V_2
                  IL_0011:  ldloca.s   V_3
                  IL_0013:  initobj    "System.Threading.CancellationToken"
                  IL_0019:  ldloc.3
                  IL_001a:  constrained. "C"
                  IL_0020:  callvirt   "System.Collections.Generic.IAsyncEnumerator<int> System.Collections.Generic.IAsyncEnumerable<int>.GetAsyncEnumerator(System.Threading.CancellationToken)"
                  IL_0025:  stloc.0
                  IL_0026:  ldnull
                  IL_0027:  stloc.s    V_4
                  .try
                  {
                    IL_0029:  br.s       IL_0036
                    IL_002b:  ldloc.0
                    IL_002c:  callvirt   "int System.Collections.Generic.IAsyncEnumerator<int>.Current.get"
                    IL_0031:  call       "void System.Console.Write(int)"
                    IL_0036:  ldloc.0
                    IL_0037:  callvirt   "System.Threading.Tasks.ValueTask<bool> System.Collections.Generic.IAsyncEnumerator<int>.MoveNextAsync()"
                    IL_003c:  call       "bool System.Runtime.CompilerServices.AsyncHelpers.Await<bool>(System.Threading.Tasks.ValueTask<bool>)"
                    IL_0041:  brtrue.s   IL_002b
                    IL_0043:  leave.s    IL_0049
                  }
                  catch object
                  {
                    IL_0045:  stloc.s    V_4
                    IL_0047:  leave.s    IL_0049
                  }
                  IL_0049:  ldloc.0
                  IL_004a:  brfalse.s  IL_0057
                  IL_004c:  ldloc.0
                  IL_004d:  callvirt   "System.Threading.Tasks.ValueTask System.IAsyncDisposable.DisposeAsync()"
                  IL_0052:  call       "void System.Runtime.CompilerServices.AsyncHelpers.Await(System.Threading.Tasks.ValueTask)"
                  IL_0057:  ldloc.s    V_4
                  IL_0059:  brfalse.s  IL_0072
                  IL_005b:  ldloc.s    V_4
                  IL_005d:  isinst     "System.Exception"
                  IL_0062:  dup
                  IL_0063:  brtrue.s   IL_0068
                  IL_0065:  ldloc.s    V_4
                  IL_0067:  throw
                  IL_0068:  call       "System.Runtime.ExceptionServices.ExceptionDispatchInfo System.Runtime.ExceptionServices.ExceptionDispatchInfo.Capture(System.Exception)"
                  IL_006d:  callvirt   "void System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()"
                  IL_0072:  ret
                }
                """);
        }
 
        [Fact]
        public void TestConstantNullableWithGetAsyncEnumeratorPattern()
        {
            var source = @"
using System;
using System.Threading.Tasks;
using System.Collections.Generic;
public struct C
{
    public static async Task Main()
    {
        await foreach (var i in (C?)null)
        {
            Console.Write(i);
        }
    }
 
    public IAsyncEnumerator<int> GetAsyncEnumerator() => throw null;
}";
            var comp = CreateCompilationWithTasksExtensions(new[] { source, AsyncStreamsTypes }, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular9);
            comp.VerifyDiagnostics();
            CompileAndVerify(comp);
 
            var runtimeAsyncComp = CreateRuntimeAsyncCompilation(source);
            var verifier = CompileAndVerify(runtimeAsyncComp, verify: Verification.Fails with
            {
                ILVerifyMessage = """
                    [Main]: Return value missing on the stack. { Offset = 0x5e }
                    """
            });
            verifier.VerifyIL("C.Main()", """
                {
                  // Code size       95 (0x5f)
                  .maxstack  2
                  .locals init (System.Collections.Generic.IAsyncEnumerator<int> V_0,
                                C? V_1,
                                C V_2,
                                object V_3)
                  IL_0000:  ldloca.s   V_1
                  IL_0002:  dup
                  IL_0003:  initobj    "C?"
                  IL_0009:  call       "readonly C C?.Value.get"
                  IL_000e:  stloc.2
                  IL_000f:  ldloca.s   V_2
                  IL_0011:  call       "System.Collections.Generic.IAsyncEnumerator<int> C.GetAsyncEnumerator()"
                  IL_0016:  stloc.0
                  IL_0017:  ldnull
                  IL_0018:  stloc.3
                  .try
                  {
                    IL_0019:  br.s       IL_0026
                    IL_001b:  ldloc.0
                    IL_001c:  callvirt   "int System.Collections.Generic.IAsyncEnumerator<int>.Current.get"
                    IL_0021:  call       "void System.Console.Write(int)"
                    IL_0026:  ldloc.0
                    IL_0027:  callvirt   "System.Threading.Tasks.ValueTask<bool> System.Collections.Generic.IAsyncEnumerator<int>.MoveNextAsync()"
                    IL_002c:  call       "bool System.Runtime.CompilerServices.AsyncHelpers.Await<bool>(System.Threading.Tasks.ValueTask<bool>)"
                    IL_0031:  brtrue.s   IL_001b
                    IL_0033:  leave.s    IL_0038
                  }
                  catch object
                  {
                    IL_0035:  stloc.3
                    IL_0036:  leave.s    IL_0038
                  }
                  IL_0038:  ldloc.0
                  IL_0039:  brfalse.s  IL_0046
                  IL_003b:  ldloc.0
                  IL_003c:  callvirt   "System.Threading.Tasks.ValueTask System.IAsyncDisposable.DisposeAsync()"
                  IL_0041:  call       "void System.Runtime.CompilerServices.AsyncHelpers.Await(System.Threading.Tasks.ValueTask)"
                  IL_0046:  ldloc.3
                  IL_0047:  brfalse.s  IL_005e
                  IL_0049:  ldloc.3
                  IL_004a:  isinst     "System.Exception"
                  IL_004f:  dup
                  IL_0050:  brtrue.s   IL_0054
                  IL_0052:  ldloc.3
                  IL_0053:  throw
                  IL_0054:  call       "System.Runtime.ExceptionServices.ExceptionDispatchInfo System.Runtime.ExceptionServices.ExceptionDispatchInfo.Capture(System.Exception)"
                  IL_0059:  callvirt   "void System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()"
                  IL_005e:  ret
                }
                """);
        }
 
        [Fact]
        public void TestForeachNullLiteral()
        {
            var source = @"
using System;
using System.Threading.Tasks;
public class C
{
    public static async Task Main()
    {
        await foreach (var i in null)
        {
            Console.Write(i);
        }
    }
}";
            CreateCompilation(source, parseOptions: TestOptions.Regular9)
                .VerifyDiagnostics(
                    // (8,33): error CS0186: Use of null is not valid in this context
                    //         await foreach (var i in null)
                    Diagnostic(ErrorCode.ERR_NullNotValid, "null").WithLocation(8, 33)
                    );
        }
 
        [Fact]
        public void TestForeachDefaultLiteral()
        {
            var source = @"
using System;
using System.Threading.Tasks;
public class C
{
    public static async Task Main()
    {
        await foreach (var i in default)
        {
            Console.Write(i);
        }
    }
    public sealed class Enumerator
    {
        public int Current { get; private set; }
        public Task<bool> MoveNextAsync() => Task.FromResult(Current++ != 3);
    }
}
public static class Extensions
{
    public static C.Enumerator GetAsyncEnumerator(this object self) => new C.Enumerator();
}";
            CreateCompilation(source, parseOptions: TestOptions.Regular9)
                .VerifyDiagnostics(
                    // (8,33): error CS8716: There is no target type for the default literal.
                    //         await foreach (var i in default)
                    Diagnostic(ErrorCode.ERR_DefaultLiteralNoTargetType, "default").WithLocation(8, 33)
                    );
        }
 
        [Fact]
        public void TestGetAsyncEnumeratorPatternViaExtensions()
        {
            string source = @"
using System;
using System.Threading.Tasks;
public class C
{
    public static async Task Main()
    {
        await foreach (var i in new C())
        {
            Console.Write(i);
        }
    }
    public sealed class Enumerator
    {
        public int Current { get; private set; }
        public Task<bool> MoveNextAsync() => Task.FromResult(Current++ != 3);
    }
}
public static class Extensions
{
    public static C.Enumerator GetAsyncEnumerator(this C self) => new C.Enumerator();
}";
            var comp = CreateCompilationWithMscorlib46(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular9);
            comp.VerifyDiagnostics();
            CompileAndVerify(comp, expectedOutput: "123");
 
            var tree = comp.SyntaxTrees.Single();
            var model = (SyntaxTreeSemanticModel)comp.GetSemanticModel(tree, ignoreAccessibility: false);
            var foreachSyntax = tree.GetRoot().DescendantNodes().OfType<ForEachStatementSyntax>().Single();
            var info = model.GetForEachStatementInfo(foreachSyntax);
 
            Assert.Equal("C.Enumerator Extensions.GetAsyncEnumerator(this C self)", info.GetEnumeratorMethod.ToTestDisplayString());
            Assert.Equal("System.Threading.Tasks.Task<System.Boolean> C.Enumerator.MoveNextAsync()", info.MoveNextMethod.ToTestDisplayString());
            Assert.Equal("System.Int32 C.Enumerator.Current { get; private set; }", info.CurrentProperty.ToTestDisplayString());
            Assert.Null(info.DisposeMethod);
            Assert.Equal("System.Int32", info.ElementType.ToTestDisplayString());
            Assert.Equal(ConversionKind.Identity, info.ElementConversion.Kind);
            Assert.Equal(ConversionKind.Identity, info.CurrentConversion.Kind);
 
            var runtimeAsyncComp = CreateRuntimeAsyncCompilation(source);
            var verifier = CompileAndVerify(runtimeAsyncComp, expectedOutput: CodeGenAsyncTests.ExpectedOutput("123", isRuntimeAsync: true), verify: Verification.Fails with
            {
                ILVerifyMessage = """
                    [Main]: Return value missing on the stack. { Offset = 0x25 }
                    """
            });
            verifier.VerifyIL("C.Main()", """
                {
                  // Code size       38 (0x26)
                  .maxstack  1
                  .locals init (C.Enumerator V_0)
                  IL_0000:  newobj     "C..ctor()"
                  IL_0005:  call       "C.Enumerator Extensions.GetAsyncEnumerator(C)"
                  IL_000a:  stloc.0
                  IL_000b:  br.s       IL_0018
                  IL_000d:  ldloc.0
                  IL_000e:  callvirt   "int C.Enumerator.Current.get"
                  IL_0013:  call       "void System.Console.Write(int)"
                  IL_0018:  ldloc.0
                  IL_0019:  callvirt   "System.Threading.Tasks.Task<bool> C.Enumerator.MoveNextAsync()"
                  IL_001e:  call       "bool System.Runtime.CompilerServices.AsyncHelpers.Await<bool>(System.Threading.Tasks.Task<bool>)"
                  IL_0023:  brtrue.s   IL_000d
                  IL_0025:  ret
                }
                """);
        }
 
        [Fact]
        public void TestGetAsyncEnumeratorPatternViaExtensionsWithUpcast()
        {
            string source = @"
using System;
using System.Threading.Tasks;
public class C
{
    public static async Task Main()
    {
        await foreach (var i in new C())
        {
            Console.Write(i);
        }
    }
    public sealed class Enumerator
    {
        public int Current { get; private set; }
        public Task<bool> MoveNextAsync() => Task.FromResult(Current++ != 3);
    }
}
public static class Extensions
{
    public static C.Enumerator GetAsyncEnumerator(this object self) => new C.Enumerator();
}";
            var comp = CreateCompilationWithMscorlib46(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular9);
            comp.VerifyDiagnostics();
            CompileAndVerify(comp, expectedOutput: "123");
 
            var runtimeAsyncComp = CreateRuntimeAsyncCompilation(source);
            var verifier = CompileAndVerify(runtimeAsyncComp, expectedOutput: CodeGenAsyncTests.ExpectedOutput("123", isRuntimeAsync: true), verify: Verification.Fails with
            {
                ILVerifyMessage = """
                    [Main]: Return value missing on the stack. { Offset = 0x25 }
                    """
            });
            verifier.VerifyIL("C.Main()", """
                {
                  // Code size       38 (0x26)
                  .maxstack  1
                  .locals init (C.Enumerator V_0)
                  IL_0000:  newobj     "C..ctor()"
                  IL_0005:  call       "C.Enumerator Extensions.GetAsyncEnumerator(object)"
                  IL_000a:  stloc.0
                  IL_000b:  br.s       IL_0018
                  IL_000d:  ldloc.0
                  IL_000e:  callvirt   "int C.Enumerator.Current.get"
                  IL_0013:  call       "void System.Console.Write(int)"
                  IL_0018:  ldloc.0
                  IL_0019:  callvirt   "System.Threading.Tasks.Task<bool> C.Enumerator.MoveNextAsync()"
                  IL_001e:  call       "bool System.Runtime.CompilerServices.AsyncHelpers.Await<bool>(System.Threading.Tasks.Task<bool>)"
                  IL_0023:  brtrue.s   IL_000d
                  IL_0025:  ret
                }
                """);
        }
 
        [Fact]
        public void TestGetAsyncEnumeratorPatternViaExtensionsOnDefaultObject()
        {
            string source = @"
using System;
using System.Threading.Tasks;
public class C
{
    public static async Task Main()
    {
        await foreach (var i in default(object))
        {
            Console.Write(i);
        }
    }
    public sealed class Enumerator
    {
        public int Current { get; private set; }
        public Task<bool> MoveNextAsync() => Task.FromResult(Current++ != 3);
    }
}
public static class Extensions
{
    public static C.Enumerator GetAsyncEnumerator(this object self) => new C.Enumerator();
}";
            var comp = CreateCompilationWithMscorlib46(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular9);
            comp.VerifyDiagnostics();
            CompileAndVerify(comp, expectedOutput: "123");
 
            var runtimeAsyncComp = CreateRuntimeAsyncCompilation(source);
            var verifier = CompileAndVerify(runtimeAsyncComp, expectedOutput: CodeGenAsyncTests.ExpectedOutput("123", isRuntimeAsync: true), verify: Verification.Fails with
            {
                ILVerifyMessage = """
                    [Main]: Return value missing on the stack. { Offset = 0x21 }
                    """
            });
            verifier.VerifyIL("C.Main()", """
                {
                  // Code size       34 (0x22)
                  .maxstack  1
                  .locals init (C.Enumerator V_0)
                  IL_0000:  ldnull
                  IL_0001:  call       "C.Enumerator Extensions.GetAsyncEnumerator(object)"
                  IL_0006:  stloc.0
                  IL_0007:  br.s       IL_0014
                  IL_0009:  ldloc.0
                  IL_000a:  callvirt   "int C.Enumerator.Current.get"
                  IL_000f:  call       "void System.Console.Write(int)"
                  IL_0014:  ldloc.0
                  IL_0015:  callvirt   "System.Threading.Tasks.Task<bool> C.Enumerator.MoveNextAsync()"
                  IL_001a:  call       "bool System.Runtime.CompilerServices.AsyncHelpers.Await<bool>(System.Threading.Tasks.Task<bool>)"
                  IL_001f:  brtrue.s   IL_0009
                  IL_0021:  ret
                }
                """);
        }
 
        [Fact]
        public void TestGetAsyncEnumeratorPatternViaExtensionsWithStructEnumerator()
        {
            string source = @"
using System;
using System.Threading.Tasks;
public class C
{
    public static async Task Main()
    {
        await foreach (var i in new C())
        {
            Console.Write(i);
        }
    }
    public struct Enumerator
    {
        public int Current { get; private set; }
        public Task<bool> MoveNextAsync() => Task.FromResult(Current++ != 3);
    }
}
public static class Extensions
{
    public static C.Enumerator GetAsyncEnumerator(this C self) => new C.Enumerator();
}";
            var comp = CreateCompilationWithMscorlib46(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular9);
            comp.VerifyDiagnostics();
            CompileAndVerify(comp, expectedOutput: "123");
 
            var runtimeAsyncComp = CreateRuntimeAsyncCompilation(source);
            var verifier = CompileAndVerify(runtimeAsyncComp, expectedOutput: CodeGenAsyncTests.ExpectedOutput("123", isRuntimeAsync: true), verify: Verification.Fails with
            {
                ILVerifyMessage = """
                    [Main]: Return value missing on the stack. { Offset = 0x27 }
                    """
            });
            verifier.VerifyIL("C.Main()", """
                {
                  // Code size       40 (0x28)
                  .maxstack  1
                  .locals init (C.Enumerator V_0)
                  IL_0000:  newobj     "C..ctor()"
                  IL_0005:  call       "C.Enumerator Extensions.GetAsyncEnumerator(C)"
                  IL_000a:  stloc.0
                  IL_000b:  br.s       IL_0019
                  IL_000d:  ldloca.s   V_0
                  IL_000f:  call       "readonly int C.Enumerator.Current.get"
                  IL_0014:  call       "void System.Console.Write(int)"
                  IL_0019:  ldloca.s   V_0
                  IL_001b:  call       "System.Threading.Tasks.Task<bool> C.Enumerator.MoveNextAsync()"
                  IL_0020:  call       "bool System.Runtime.CompilerServices.AsyncHelpers.Await<bool>(System.Threading.Tasks.Task<bool>)"
                  IL_0025:  brtrue.s   IL_000d
                  IL_0027:  ret
                }
                """);
        }
 
        [Fact]
        public void TestGetAsyncEnumeratorPatternViaExtensionsWithUserDefinedImplicitConversion()
        {
            string source = @"
using System;
using System.Threading.Tasks;
public class C
{
    public static implicit operator int(C c) => 0;
 
    public static async Task Main()
    {
        await foreach (var i in new C())
        {
            Console.Write(i);
        }
    }
    public sealed class Enumerator
    {
        public int Current { get; private set; }
        public Task<bool> MoveNextAsync() => Task.FromResult(Current++ != 3);
    }
}
public static class Extensions
{
    public static C.Enumerator GetAsyncEnumerator(this int self) => new C.Enumerator();
}";
            var comp = CreateCompilationWithMscorlib46(source, parseOptions: TestOptions.Regular9);
            comp.VerifyDiagnostics(
                // (10,33): error CS1929: 'C' does not contain a definition for 'GetAsyncEnumerator' and the best extension method overload 'Extensions.GetAsyncEnumerator(int)' requires a receiver of type 'int'
                //         await foreach (var i in new C())
                Diagnostic(ErrorCode.ERR_BadInstanceArgType, "new C()").WithArguments("C", "GetAsyncEnumerator", "Extensions.GetAsyncEnumerator(int)", "int").WithLocation(10, 33),
                // (10,33): error CS8411: Asynchronous foreach statement cannot operate on variables of type 'C' because 'C' does not contain a suitable public instance or extension definition for 'GetAsyncEnumerator'
                //         await foreach (var i in new C())
                Diagnostic(ErrorCode.ERR_AwaitForEachMissingMember, "new C()").WithArguments("C", "GetAsyncEnumerator").WithLocation(10, 33)
                );
        }
 
        [Fact]
        public void TestGetAsyncEnumeratorPatternViaExtensionsWithNullableValueTypeConversion()
        {
            var source = @"
using System;
using System.Threading.Tasks;
public class C
{
    public static async Task Main()
    {
        await foreach (var i in 1)
        {
            Console.Write(i);
        }
    }
    public sealed class Enumerator
    {
        public int Current { get; private set; }
        public Task<bool> MoveNextAsync() => Task.FromResult(Current++ != 3);
    }
}
public static class Extensions
{
    public static C.Enumerator GetAsyncEnumerator(this int? self) => new C.Enumerator();
}";
            CreateCompilation(source, parseOptions: TestOptions.Regular9)
                .VerifyDiagnostics(
                    // (8,33): error CS1929: 'int' does not contain a definition for 'GetAsyncEnumerator' and the best extension method overload 'Extensions.GetAsyncEnumerator(int?)' requires a receiver of type 'int?'
                    //         await foreach (var i in 1)
                    Diagnostic(ErrorCode.ERR_BadInstanceArgType, "1").WithArguments("int", "GetAsyncEnumerator", "Extensions.GetAsyncEnumerator(int?)", "int?").WithLocation(8, 33),
                    // (8,33): error CS8411: Asynchronous foreach statement cannot operate on variables of type 'int' because 'int' does not contain a suitable public instance or extension definition for 'GetAsyncEnumerator'
                    //         await foreach (var i in 1)
                    Diagnostic(ErrorCode.ERR_AwaitForEachMissingMember, "1").WithArguments("int", "GetAsyncEnumerator").WithLocation(8, 33)
                    );
        }
 
        [Fact]
        public void TestGetAsyncEnumeratorPatternViaExtensionsWithUnboxingConversion()
        {
            var source = @"
using System;
using System.Threading.Tasks;
public class C
{
    public static async Task Main()
    {
        await foreach (var i in new object())
        {
            Console.Write(i);
        }
    }
    public sealed class Enumerator
    {
        public int Current { get; private set; }
        public Task<bool> MoveNextAsync() => Task.FromResult(Current++ != 3);
    }
}
public static class Extensions
{
    public static C.Enumerator GetAsyncEnumerator(this int self) => new C.Enumerator();
}";
            CreateCompilation(source, parseOptions: TestOptions.Regular9)
                .VerifyDiagnostics(
                    // (8,33): error CS1929: 'object' does not contain a definition for 'GetAsyncEnumerator' and the best extension method overload 'Extensions.GetAsyncEnumerator(int)' requires a receiver of type 'int'
                    //         await foreach (var i in new object())
                    Diagnostic(ErrorCode.ERR_BadInstanceArgType, "new object()").WithArguments("object", "GetAsyncEnumerator", "Extensions.GetAsyncEnumerator(int)", "int").WithLocation(8, 33),
                    // (8,33): error CS8411: Asynchronous foreach statement cannot operate on variables of type 'object' because 'object' does not contain a suitable public instance or extension definition for 'GetAsyncEnumerator'
                    //         await foreach (var i in new object())
                    Diagnostic(ErrorCode.ERR_AwaitForEachMissingMember, "new object()").WithArguments("object", "GetAsyncEnumerator").WithLocation(8, 33)
                    );
        }
 
        [Fact]
        public void TestGetAsyncEnumeratorPatternViaExtensionsWithNullableUnwrapping()
        {
            var source = @"
using System;
using System.Threading.Tasks;
public class C
{
    public static async Task Main()
    {
        await foreach (var i in (int?)1)
        {
            Console.Write(i);
        }
    }
    public sealed class Enumerator
    {
        public int Current { get; private set; }
        public Task<bool> MoveNextAsync() => Task.FromResult(Current++ != 3);
    }
}
public static class Extensions
{
    public static C.Enumerator GetAsyncEnumerator(this int self) => new C.Enumerator();
}";
            CreateCompilation(source, parseOptions: TestOptions.Regular9)
                .VerifyDiagnostics(
                    // (8,33): error CS1929: 'int?' does not contain a definition for 'GetAsyncEnumerator' and the best extension method overload 'Extensions.GetAsyncEnumerator(int)' requires a receiver of type 'int'
                    //         await foreach (var i in (int?)1)
                    Diagnostic(ErrorCode.ERR_BadInstanceArgType, "(int?)1").WithArguments("int?", "GetAsyncEnumerator", "Extensions.GetAsyncEnumerator(int)", "int").WithLocation(8, 33),
                    // (8,33): error CS8411: Asynchronous foreach statement cannot operate on variables of type 'int?' because 'int?' does not contain a suitable public instance or extension definition for 'GetAsyncEnumerator'
                    //         await foreach (var i in (int?)1)
                    Diagnostic(ErrorCode.ERR_AwaitForEachMissingMember, "(int?)1").WithArguments("int?", "GetAsyncEnumerator").WithLocation(8, 33)
                    );
        }
 
        [Fact]
        public void TestGetAsyncEnumeratorPatternViaExtensionsWithZeroToEnumConversion()
        {
            var source = @"
using System;
using System.Threading.Tasks;
public enum E { Default = 0 }
public class C
{
    public static async Task Main()
    {
        await foreach (var i in 0)
        {
            Console.Write(i);
        }
    }
    public sealed class Enumerator
    {
        public int Current { get; private set; }
        public Task<bool> MoveNextAsync() => Task.FromResult(Current++ != 3);
    }
}
public static class Extensions
{
    public static C.Enumerator GetAsyncEnumerator(this E self) => new C.Enumerator();
}";
            CreateCompilation(source, parseOptions: TestOptions.Regular9)
                .VerifyDiagnostics(
                    // (9,33): error CS1929: 'int' does not contain a definition for 'GetAsyncEnumerator' and the best extension method overload 'Extensions.GetAsyncEnumerator(E)' requires a receiver of type 'E'
                    //         await foreach (var i in 0)
                    Diagnostic(ErrorCode.ERR_BadInstanceArgType, "0").WithArguments("int", "GetAsyncEnumerator", "Extensions.GetAsyncEnumerator(E)", "E").WithLocation(9, 33),
                    // (9,33): error CS8411: Asynchronous foreach statement cannot operate on variables of type 'int' because 'int' does not contain a suitable public instance or extension definition for 'GetAsyncEnumerator'
                    //         await foreach (var i in 0)
                    Diagnostic(ErrorCode.ERR_AwaitForEachMissingMember, "0").WithArguments("int", "GetAsyncEnumerator").WithLocation(9, 33)
                    );
        }
 
        [Fact]
        public void TestGetAsyncEnumeratorPatternViaExtensionsWithUnconstrainedGenericConversion()
        {
            var source = @"
using System;
using System.Threading.Tasks;
public class C
{
    public static async Task Main()
    {
        await Inner(1);
 
        async Task Inner<T>(T t)
        {
            await foreach (var i in t)
            {
                Console.Write(i);
            }
        }
    }
    public sealed class Enumerator
    {
        public int Current { get; private set; }
        public Task<bool> MoveNextAsync() => Task.FromResult(Current++ != 3);
    }
}
public static class Extensions
{
    public static C.Enumerator GetAsyncEnumerator(this object self) => new C.Enumerator();
}";
            var comp = CreateCompilationWithMscorlib46(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular9);
            comp.VerifyDiagnostics();
            CompileAndVerify(comp, expectedOutput: "123");
 
            var runtimeAsyncComp = CreateRuntimeAsyncCompilation(source);
            var verifier = CompileAndVerify(runtimeAsyncComp, expectedOutput: CodeGenAsyncTests.ExpectedOutput("123", isRuntimeAsync: true), verify: Verification.Fails with
            {
                ILVerifyMessage = """
                    [Main]: Return value missing on the stack. { Offset = 0xb }
                    [<Main>g__Inner|0_0]: Return value missing on the stack. { Offset = 0x26 }
                    """
            });
            verifier.VerifyIL("C.<Main>g__Inner|0_0<T>(T)", """
                {
                  // Code size       39 (0x27)
                  .maxstack  1
                  .locals init (C.Enumerator V_0)
                  IL_0000:  ldarg.0
                  IL_0001:  box        "T"
                  IL_0006:  call       "C.Enumerator Extensions.GetAsyncEnumerator(object)"
                  IL_000b:  stloc.0
                  IL_000c:  br.s       IL_0019
                  IL_000e:  ldloc.0
                  IL_000f:  callvirt   "int C.Enumerator.Current.get"
                  IL_0014:  call       "void System.Console.Write(int)"
                  IL_0019:  ldloc.0
                  IL_001a:  callvirt   "System.Threading.Tasks.Task<bool> C.Enumerator.MoveNextAsync()"
                  IL_001f:  call       "bool System.Runtime.CompilerServices.AsyncHelpers.Await<bool>(System.Threading.Tasks.Task<bool>)"
                  IL_0024:  brtrue.s   IL_000e
                  IL_0026:  ret
                }
                """);
        }
 
        [Fact]
        public void TestGetAsyncEnumeratorPatternViaExtensionsWithConstrainedGenericConversion()
        {
            var source = @"
using System;
using System.Threading.Tasks;
public class C
{
    public static async Task Main()
    {
        await Inner(1);
 
        async Task Inner<T>(T t) where T : IConvertible
        {
            await foreach (var i in t)
            {
                Console.Write(i);
            }
        }
    }
    public sealed class Enumerator
    {
        public int Current { get; private set; }
        public Task<bool> MoveNextAsync() => Task.FromResult(Current++ != 3);
    }
}
public static class Extensions
{
    public static C.Enumerator GetAsyncEnumerator(this IConvertible self) => new C.Enumerator();
}";
            var comp = CreateCompilationWithMscorlib46(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular9);
            comp.VerifyDiagnostics();
            CompileAndVerify(comp, expectedOutput: "123");
 
            var runtimeAsyncComp = CreateRuntimeAsyncCompilation(source);
            var verifier = CompileAndVerify(runtimeAsyncComp, expectedOutput: CodeGenAsyncTests.ExpectedOutput("123", isRuntimeAsync: true), verify: Verification.Fails with
            {
                ILVerifyMessage = """
                    [Main]: Return value missing on the stack. { Offset = 0xb }
                    [<Main>g__Inner|0_0]: Return value missing on the stack. { Offset = 0x26 }
                    """
            });
            verifier.VerifyIL("C.<Main>g__Inner|0_0<T>(T)", """
                {
                  // Code size       39 (0x27)
                  .maxstack  1
                  .locals init (C.Enumerator V_0)
                  IL_0000:  ldarg.0
                  IL_0001:  box        "T"
                  IL_0006:  call       "C.Enumerator Extensions.GetAsyncEnumerator(System.IConvertible)"
                  IL_000b:  stloc.0
                  IL_000c:  br.s       IL_0019
                  IL_000e:  ldloc.0
                  IL_000f:  callvirt   "int C.Enumerator.Current.get"
                  IL_0014:  call       "void System.Console.Write(int)"
                  IL_0019:  ldloc.0
                  IL_001a:  callvirt   "System.Threading.Tasks.Task<bool> C.Enumerator.MoveNextAsync()"
                  IL_001f:  call       "bool System.Runtime.CompilerServices.AsyncHelpers.Await<bool>(System.Threading.Tasks.Task<bool>)"
                  IL_0024:  brtrue.s   IL_000e
                  IL_0026:  ret
                }
                """);
        }
 
        [Fact]
        public void TestGetAsyncEnumeratorPatternViaExtensionsWithFormattableStringConversion1()
        {
            var source = @"
using System;
using System.Threading.Tasks;
public class C
{
    public static async Task Main()
    {
        await foreach (var i in $"" "")
        {
            Console.Write(i);
        }
    }
    public sealed class Enumerator
    {
        public int Current { get; private set; }
        public Task<bool> MoveNextAsync() => Task.FromResult(Current++ != 3);
    }
}
public static class Extensions
{
    public static C.Enumerator GetAsyncEnumerator(this FormattableString self) => throw null;
    public static C.Enumerator GetAsyncEnumerator(this object self) => new C.Enumerator();
}";
            var comp = CreateCompilationWithMscorlib46(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular9);
            comp.VerifyDiagnostics();
            CompileAndVerify(comp, expectedOutput: "123");
 
            var runtimeAsyncComp = CreateRuntimeAsyncCompilation(source);
            var verifier = CompileAndVerify(runtimeAsyncComp, expectedOutput: CodeGenAsyncTests.ExpectedOutput("123", isRuntimeAsync: true), verify: Verification.Fails with
            {
                ILVerifyMessage = """
                    [Main]: Return value missing on the stack. { Offset = 0x25 }
                    """
            });
            verifier.VerifyIL("C.Main()", """
                {
                  // Code size       38 (0x26)
                  .maxstack  1
                  .locals init (C.Enumerator V_0)
                  IL_0000:  ldstr      " "
                  IL_0005:  call       "C.Enumerator Extensions.GetAsyncEnumerator(object)"
                  IL_000a:  stloc.0
                  IL_000b:  br.s       IL_0018
                  IL_000d:  ldloc.0
                  IL_000e:  callvirt   "int C.Enumerator.Current.get"
                  IL_0013:  call       "void System.Console.Write(int)"
                  IL_0018:  ldloc.0
                  IL_0019:  callvirt   "System.Threading.Tasks.Task<bool> C.Enumerator.MoveNextAsync()"
                  IL_001e:  call       "bool System.Runtime.CompilerServices.AsyncHelpers.Await<bool>(System.Threading.Tasks.Task<bool>)"
                  IL_0023:  brtrue.s   IL_000d
                  IL_0025:  ret
                }
                """);
        }
 
        [Fact]
        public void TestGetAsyncEnumeratorPatternViaExtensionsWithFormattableStringConversion2()
        {
            var source = @"
using System;
using System.Threading.Tasks;
public class C
{
    public static async Task Main()
    {
        await foreach (var i in $"" "")
        {
            Console.Write(i);
        }
    }
    public sealed class Enumerator
    {
        public int Current { get; private set; }
        public Task<bool> MoveNextAsync() => Task.FromResult(Current++ != 3);
    }
}
public static class Extensions
{
    public static C.Enumerator GetAsyncEnumerator(this string self) => new C.Enumerator();
    public static C.Enumerator GetAsyncEnumerator(this FormattableString self) => throw null;
    public static C.Enumerator GetAsyncEnumerator(this object self) => throw null;
}";
            var comp = CreateCompilationWithMscorlib46(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular9);
            comp.VerifyDiagnostics();
            CompileAndVerify(comp, expectedOutput: "123");
 
            var runtimeAsyncComp = CreateRuntimeAsyncCompilation(source);
            var verifier = CompileAndVerify(runtimeAsyncComp, expectedOutput: CodeGenAsyncTests.ExpectedOutput("123", isRuntimeAsync: true), verify: Verification.Fails with
            {
                ILVerifyMessage = """
                    [Main]: Return value missing on the stack. { Offset = 0x25 }
                    """
            });
            verifier.VerifyIL("C.Main()", """
                {
                  // Code size       38 (0x26)
                  .maxstack  1
                  .locals init (C.Enumerator V_0)
                  IL_0000:  ldstr      " "
                  IL_0005:  call       "C.Enumerator Extensions.GetAsyncEnumerator(string)"
                  IL_000a:  stloc.0
                  IL_000b:  br.s       IL_0018
                  IL_000d:  ldloc.0
                  IL_000e:  callvirt   "int C.Enumerator.Current.get"
                  IL_0013:  call       "void System.Console.Write(int)"
                  IL_0018:  ldloc.0
                  IL_0019:  callvirt   "System.Threading.Tasks.Task<bool> C.Enumerator.MoveNextAsync()"
                  IL_001e:  call       "bool System.Runtime.CompilerServices.AsyncHelpers.Await<bool>(System.Threading.Tasks.Task<bool>)"
                  IL_0023:  brtrue.s   IL_000d
                  IL_0025:  ret
                }
                """);
        }
 
        [Fact]
        public void TestGetAsyncEnumeratorPatternViaExtensionsWithFormattableStringConversion3()
        {
            var source = @"
using System;
using System.Threading.Tasks;
public class C
{
    public static async Task Main()
    {
        await foreach (var i in $"" "")
        {
            Console.Write(i);
        }
    }
    public sealed class Enumerator
    {
        public int Current { get; private set; }
        public Task<bool> MoveNextAsync() => Task.FromResult(Current++ != 3);
    }
}
public static class Extensions
{
    public static C.Enumerator GetAsyncEnumerator(this FormattableString self) => throw null;
}";
            CreateCompilationWithMscorlib46(source, parseOptions: TestOptions.Regular9)
                .VerifyDiagnostics(
                    // (8,33): error CS1929: 'string' does not contain a definition for 'GetAsyncEnumerator' and the best extension method overload 'Extensions.GetAsyncEnumerator(FormattableString)' requires a receiver of type 'FormattableString'
                    //         await foreach (var i in $" ")
                    Diagnostic(ErrorCode.ERR_BadInstanceArgType, @"$"" """).WithArguments("string", "GetAsyncEnumerator", "Extensions.GetAsyncEnumerator(System.FormattableString)", "System.FormattableString").WithLocation(8, 33),
                    // (8,33): error CS8415: Asynchronous foreach statement cannot operate on variables of type 'string' because 'string' does not contain a public instance or extension definition for 'GetAsyncEnumerator'. Did you mean 'foreach' rather than 'await foreach'?
                    //         await foreach (var i in $" ")
                    Diagnostic(ErrorCode.ERR_AwaitForEachMissingMemberWrongAsync, @"$"" """).WithArguments("string", "GetAsyncEnumerator").WithLocation(8, 33));
 
        }
 
        [Fact]
        public void TestGetAsyncEnumeratorPatternViaExtensionsWithDelegateConversion()
        {
            var source = @"
using System;
using System.Threading.Tasks;
public class C
{
    public static async Task Main()
    {
        await foreach (var i in () => 42)
        {
            Console.Write(i);
        }
    }
    public sealed class Enumerator
    {
        public int Current { get; private set; }
        public Task<bool> MoveNextAsync() => Task.FromResult(Current++ != 3);
    }
}
public static class Extensions
{
    public static C.Enumerator GetAsyncEnumerator(this Func<int> self) => new C.Enumerator();
}";
            CreateCompilation(source, parseOptions: TestOptions.Regular9)
                .VerifyDiagnostics(
                    // (8,33): error CS0446: Foreach cannot operate on a 'lambda expression'. Did you intend to invoke the 'lambda expression'?
                    //         await foreach (var i in () => 42)
                    Diagnostic(ErrorCode.ERR_AnonMethGrpInForEach, "() => 42").WithArguments("lambda expression").WithLocation(8, 33)
                    );
        }
 
        [Fact]
        public void TestGetAsyncEnumeratorPatternViaExtensionsWithBoxing()
        {
            string source = @"
using System;
using System.Threading.Tasks;
public struct C
{
    public static async Task Main()
    {
        await foreach (var i in new C())
        {
            Console.Write(i);
        }
    }
    public sealed class Enumerator
    {
        public int Current { get; private set; }
        public Task<bool> MoveNextAsync() => Task.FromResult(Current++ != 3);
    }
}
public static class Extensions
{
    public static C.Enumerator GetAsyncEnumerator(this object self) => new C.Enumerator();
}";
            var comp = CreateCompilationWithMscorlib46(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular9);
            comp.VerifyDiagnostics();
            CompileAndVerify(comp, expectedOutput: "123");
 
            var runtimeAsyncComp = CreateRuntimeAsyncCompilation(source);
            var verifier = CompileAndVerify(runtimeAsyncComp, expectedOutput: CodeGenAsyncTests.ExpectedOutput("123", isRuntimeAsync: true), verify: Verification.Fails with
            {
                ILVerifyMessage = """
                    [Main]: Return value missing on the stack. { Offset = 0x2e }
                    """
            });
            verifier.VerifyIL("C.Main()", """
                {
                  // Code size       47 (0x2f)
                  .maxstack  1
                  .locals init (C.Enumerator V_0,
                                C V_1)
                  IL_0000:  ldloca.s   V_1
                  IL_0002:  initobj    "C"
                  IL_0008:  ldloc.1
                  IL_0009:  box        "C"
                  IL_000e:  call       "C.Enumerator Extensions.GetAsyncEnumerator(object)"
                  IL_0013:  stloc.0
                  IL_0014:  br.s       IL_0021
                  IL_0016:  ldloc.0
                  IL_0017:  callvirt   "int C.Enumerator.Current.get"
                  IL_001c:  call       "void System.Console.Write(int)"
                  IL_0021:  ldloc.0
                  IL_0022:  callvirt   "System.Threading.Tasks.Task<bool> C.Enumerator.MoveNextAsync()"
                  IL_0027:  call       "bool System.Runtime.CompilerServices.AsyncHelpers.Await<bool>(System.Threading.Tasks.Task<bool>)"
                  IL_002c:  brtrue.s   IL_0016
                  IL_002e:  ret
                }
                """);
        }
 
        [Fact]
        public void TestGetAsyncEnumeratorPatternViaExtensionsOnInterface()
        {
            var source = @"
using System;
using System.Threading.Tasks;
public interface I {}
public class C : I
{
    public static async Task Main()
    {
        await foreach (var i in new C())
        {
            Console.Write(i);
        }
    }
    public sealed class Enumerator
    {
        public int Current { get; private set; }
        public Task<bool> MoveNextAsync() => Task.FromResult(Current++ != 3);
    }
}
public static class Extensions
{
    public static C.Enumerator GetAsyncEnumerator(this I self) => new C.Enumerator();
}";
            var comp = CreateCompilationWithMscorlib46(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular9);
            comp.VerifyDiagnostics();
            CompileAndVerify(comp, expectedOutput: "123");
 
            var runtimeAsyncComp = CreateRuntimeAsyncCompilation(source);
            var verifier = CompileAndVerify(runtimeAsyncComp, expectedOutput: CodeGenAsyncTests.ExpectedOutput("123", isRuntimeAsync: true), verify: Verification.Fails with
            {
                ILVerifyMessage = """
                    [Main]: Return value missing on the stack. { Offset = 0x25 }
                    """
            });
            verifier.VerifyIL("C.Main()", """
                {
                  // Code size       38 (0x26)
                  .maxstack  1
                  .locals init (C.Enumerator V_0)
                  IL_0000:  newobj     "C..ctor()"
                  IL_0005:  call       "C.Enumerator Extensions.GetAsyncEnumerator(I)"
                  IL_000a:  stloc.0
                  IL_000b:  br.s       IL_0018
                  IL_000d:  ldloc.0
                  IL_000e:  callvirt   "int C.Enumerator.Current.get"
                  IL_0013:  call       "void System.Console.Write(int)"
                  IL_0018:  ldloc.0
                  IL_0019:  callvirt   "System.Threading.Tasks.Task<bool> C.Enumerator.MoveNextAsync()"
                  IL_001e:  call       "bool System.Runtime.CompilerServices.AsyncHelpers.Await<bool>(System.Threading.Tasks.Task<bool>)"
                  IL_0023:  brtrue.s   IL_000d
                  IL_0025:  ret
                }
                """);
        }
 
        [Fact]
        public void TestGetAsyncEnumeratorPatternViaExtensionsOnDelegate()
        {
            var source = @"
using System;
using System.Threading.Tasks;
public class C
{
    public static async Task Main()
    {
        await foreach (var i in (Func<int>)(() => 42))
        {
            Console.Write(i);
        }
    }
    public sealed class Enumerator
    {
        public int Current { get; private set; }
        public Task<bool> MoveNextAsync() => Task.FromResult(Current++ != 3);
    }
}
public static class Extensions
{
    public static C.Enumerator GetAsyncEnumerator(this Func<int> self) => new C.Enumerator();
}";
            var comp = CreateCompilationWithMscorlib46(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular9);
            comp.VerifyDiagnostics();
            CompileAndVerify(comp, expectedOutput: "123");
 
            var runtimeAsyncComp = CreateRuntimeAsyncCompilation(source);
            var verifier = CompileAndVerify(runtimeAsyncComp, expectedOutput: CodeGenAsyncTests.ExpectedOutput("123", isRuntimeAsync: true), verify: Verification.Fails with
            {
                ILVerifyMessage = """
                    [Main]: Return value missing on the stack. { Offset = 0x3f }
                    """
            });
            verifier.VerifyIL("C.Main()", """
                {
                  // Code size       64 (0x40)
                  .maxstack  2
                  .locals init (C.Enumerator V_0)
                  IL_0000:  ldsfld     "System.Func<int> C.<>c.<>9__0_0"
                  IL_0005:  dup
                  IL_0006:  brtrue.s   IL_001f
                  IL_0008:  pop
                  IL_0009:  ldsfld     "C.<>c C.<>c.<>9"
                  IL_000e:  ldftn      "int C.<>c.<Main>b__0_0()"
                  IL_0014:  newobj     "System.Func<int>..ctor(object, System.IntPtr)"
                  IL_0019:  dup
                  IL_001a:  stsfld     "System.Func<int> C.<>c.<>9__0_0"
                  IL_001f:  call       "C.Enumerator Extensions.GetAsyncEnumerator(System.Func<int>)"
                  IL_0024:  stloc.0
                  IL_0025:  br.s       IL_0032
                  IL_0027:  ldloc.0
                  IL_0028:  callvirt   "int C.Enumerator.Current.get"
                  IL_002d:  call       "void System.Console.Write(int)"
                  IL_0032:  ldloc.0
                  IL_0033:  callvirt   "System.Threading.Tasks.Task<bool> C.Enumerator.MoveNextAsync()"
                  IL_0038:  call       "bool System.Runtime.CompilerServices.AsyncHelpers.Await<bool>(System.Threading.Tasks.Task<bool>)"
                  IL_003d:  brtrue.s   IL_0027
                  IL_003f:  ret
                }
                """);
        }
 
        [Fact]
        public void TestGetAsyncEnumeratorPatternViaExtensionsOnEnum()
        {
            var source = @"
using System;
using System.Threading.Tasks;
public enum E { Default }
public class C
{
    public static async Task Main()
    {
        await foreach (var i in E.Default)
        {
            Console.Write(i);
        }
    }
    public sealed class Enumerator
    {
        public int Current { get; private set; }
        public Task<bool> MoveNextAsync() => Task.FromResult(Current++ != 3);
    }
}
public static class Extensions
{
    public static C.Enumerator GetAsyncEnumerator(this E self) => new C.Enumerator();
}";
            var comp = CreateCompilationWithMscorlib46(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular9);
            comp.VerifyDiagnostics();
            CompileAndVerify(comp, expectedOutput: "123");
 
            var runtimeAsyncComp = CreateRuntimeAsyncCompilation(source);
            var verifier = CompileAndVerify(runtimeAsyncComp, expectedOutput: CodeGenAsyncTests.ExpectedOutput("123", isRuntimeAsync: true), verify: Verification.Fails with
            {
                ILVerifyMessage = """
                    [Main]: Return value missing on the stack. { Offset = 0x21 }
                    """
            });
            verifier.VerifyIL("C.Main()", """
                {
                  // Code size       34 (0x22)
                  .maxstack  1
                  .locals init (C.Enumerator V_0)
                  IL_0000:  ldc.i4.0
                  IL_0001:  call       "C.Enumerator Extensions.GetAsyncEnumerator(E)"
                  IL_0006:  stloc.0
                  IL_0007:  br.s       IL_0014
                  IL_0009:  ldloc.0
                  IL_000a:  callvirt   "int C.Enumerator.Current.get"
                  IL_000f:  call       "void System.Console.Write(int)"
                  IL_0014:  ldloc.0
                  IL_0015:  callvirt   "System.Threading.Tasks.Task<bool> C.Enumerator.MoveNextAsync()"
                  IL_001a:  call       "bool System.Runtime.CompilerServices.AsyncHelpers.Await<bool>(System.Threading.Tasks.Task<bool>)"
                  IL_001f:  brtrue.s   IL_0009
                  IL_0021:  ret
                }
                """);
        }
 
        [Fact]
        public void TestGetAsyncEnumeratorPatternViaExtensionsOnNullable()
        {
            var source = @"
using System;
using System.Threading.Tasks;
public class C
{
    public static async Task Main()
    {
        await foreach (var i in (int?)null)
        {
            Console.Write(i);
        }
    }
    public sealed class Enumerator
    {
        public int Current { get; private set; }
        public Task<bool> MoveNextAsync() => Task.FromResult(Current++ != 3);
    }
}
public static class Extensions
{
    public static C.Enumerator GetAsyncEnumerator(this int? self) => new C.Enumerator();
}";
            var comp = CreateCompilationWithMscorlib46(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular9);
            comp.VerifyDiagnostics();
            CompileAndVerify(comp, expectedOutput: "123");
 
            var runtimeAsyncComp = CreateRuntimeAsyncCompilation(source);
            var verifier = CompileAndVerify(runtimeAsyncComp, expectedOutput: CodeGenAsyncTests.ExpectedOutput("123", isRuntimeAsync: true), verify: Verification.Fails with
            {
                ILVerifyMessage = """
                    [Main]: Return value missing on the stack. { Offset = 0x29 }
                    """
            });
            verifier.VerifyIL("C.Main()", """
                {
                  // Code size       42 (0x2a)
                  .maxstack  1
                  .locals init (C.Enumerator V_0,
                                int? V_1)
                  IL_0000:  ldloca.s   V_1
                  IL_0002:  initobj    "int?"
                  IL_0008:  ldloc.1
                  IL_0009:  call       "C.Enumerator Extensions.GetAsyncEnumerator(int?)"
                  IL_000e:  stloc.0
                  IL_000f:  br.s       IL_001c
                  IL_0011:  ldloc.0
                  IL_0012:  callvirt   "int C.Enumerator.Current.get"
                  IL_0017:  call       "void System.Console.Write(int)"
                  IL_001c:  ldloc.0
                  IL_001d:  callvirt   "System.Threading.Tasks.Task<bool> C.Enumerator.MoveNextAsync()"
                  IL_0022:  call       "bool System.Runtime.CompilerServices.AsyncHelpers.Await<bool>(System.Threading.Tasks.Task<bool>)"
                  IL_0027:  brtrue.s   IL_0011
                  IL_0029:  ret
                }
                """);
        }
 
        [Fact]
        public void TestGetAsyncEnumeratorPatternViaExtensionsOnConstantNullObject()
        {
            var source = @"
using System;
using System.Threading.Tasks;
public class C
{
    public static async Task Main()
    {
        await foreach (var i in (object)null)
        {
            Console.Write(i);
        }
    }
    public sealed class Enumerator
    {
        public int Current { get; private set; }
        public Task<bool> MoveNextAsync() => Task.FromResult(Current++ != 3);
    }
}
public static class Extensions
{
    public static C.Enumerator GetAsyncEnumerator(this object self) => new C.Enumerator();
}";
            var comp = CreateCompilationWithMscorlib46(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular9);
            comp.VerifyDiagnostics();
            CompileAndVerify(comp, expectedOutput: "123");
 
            var runtimeAsyncComp = CreateRuntimeAsyncCompilation(source);
            var verifier = CompileAndVerify(runtimeAsyncComp, expectedOutput: CodeGenAsyncTests.ExpectedOutput("123", isRuntimeAsync: true), verify: Verification.Fails with
            {
                ILVerifyMessage = """
                    [Main]: Return value missing on the stack. { Offset = 0x21 }
                    """
            });
            verifier.VerifyIL("C.Main()", """
                {
                  // Code size       34 (0x22)
                  .maxstack  1
                  .locals init (C.Enumerator V_0)
                  IL_0000:  ldnull
                  IL_0001:  call       "C.Enumerator Extensions.GetAsyncEnumerator(object)"
                  IL_0006:  stloc.0
                  IL_0007:  br.s       IL_0014
                  IL_0009:  ldloc.0
                  IL_000a:  callvirt   "int C.Enumerator.Current.get"
                  IL_000f:  call       "void System.Console.Write(int)"
                  IL_0014:  ldloc.0
                  IL_0015:  callvirt   "System.Threading.Tasks.Task<bool> C.Enumerator.MoveNextAsync()"
                  IL_001a:  call       "bool System.Runtime.CompilerServices.AsyncHelpers.Await<bool>(System.Threading.Tasks.Task<bool>)"
                  IL_001f:  brtrue.s   IL_0009
                  IL_0021:  ret
                }
                """);
        }
 
        [Fact]
        public void TestGetAsyncEnumeratorPatternViaExtensionsOnTypeParameter()
        {
            var source = @"
using System;
using System.Threading.Tasks;
public class C
{
    public static async Task Main()
    {
        await foreach (var i in new object())
        {
            Console.Write(i);
        }
    }
    public sealed class Enumerator
    {
        public int Current { get; private set; }
        public Task<bool> MoveNextAsync() => Task.FromResult(Current++ != 3);
    }
}
public static class Extensions
{
    public static C.Enumerator GetAsyncEnumerator<T>(this T self) => new C.Enumerator();
}";
            var comp = CreateCompilationWithMscorlib46(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular9);
            comp.VerifyDiagnostics();
            CompileAndVerify(comp, expectedOutput: "123");
 
            var runtimeAsyncComp = CreateRuntimeAsyncCompilation(source);
            var verifier = CompileAndVerify(runtimeAsyncComp, expectedOutput: CodeGenAsyncTests.ExpectedOutput("123", isRuntimeAsync: true), verify: Verification.Fails with
            {
                ILVerifyMessage = """
                    [Main]: Return value missing on the stack. { Offset = 0x25 }
                    """
            });
            verifier.VerifyIL("C.Main()", """
                {
                  // Code size       38 (0x26)
                  .maxstack  1
                  .locals init (C.Enumerator V_0)
                  IL_0000:  newobj     "object..ctor()"
                  IL_0005:  call       "C.Enumerator Extensions.GetAsyncEnumerator<object>(object)"
                  IL_000a:  stloc.0
                  IL_000b:  br.s       IL_0018
                  IL_000d:  ldloc.0
                  IL_000e:  callvirt   "int C.Enumerator.Current.get"
                  IL_0013:  call       "void System.Console.Write(int)"
                  IL_0018:  ldloc.0
                  IL_0019:  callvirt   "System.Threading.Tasks.Task<bool> C.Enumerator.MoveNextAsync()"
                  IL_001e:  call       "bool System.Runtime.CompilerServices.AsyncHelpers.Await<bool>(System.Threading.Tasks.Task<bool>)"
                  IL_0023:  brtrue.s   IL_000d
                  IL_0025:  ret
                }
                """);
        }
 
        [Fact]
        public void TestGetAsyncEnumeratorPatternOnRange()
        {
            var source = @"
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
public class C
{
    public static async Task Main()
    {
        await foreach (var i in 1..4)
        {
            Console.Write(i);
        }
    }
}
public static class Extensions
{
    public static async IAsyncEnumerator<int> GetAsyncEnumerator(this Range range)
    {
        await Task.Yield();
        for(var i = range.Start.Value; i < range.End.Value; i++)
        {
            yield return i;
        }
    }
}";
            var comp = CreateCompilationWithTasksExtensions(
                new[] { source, TestSources.Index, TestSources.Range, AsyncStreamsTypes },
                options: TestOptions.DebugExe,
                parseOptions: TestOptions.Regular9);
            comp.VerifyDiagnostics();
            CompileAndVerify(comp, expectedOutput: "123");
 
            var runtimeAsyncComp = CreateRuntimeAsyncCompilation(source);
            var verifier = CompileAndVerify(runtimeAsyncComp, expectedOutput: CodeGenAsyncTests.ExpectedOutput("123", isRuntimeAsync: true), verify: Verification.Fails with
            {
                ILVerifyMessage = """
                    [Main]: Return value missing on the stack. { Offset = 0x5e }
                    """
            });
            verifier.VerifyIL("C.Main()", """
                {
                  // Code size       95 (0x5f)
                  .maxstack  2
                  .locals init (System.Collections.Generic.IAsyncEnumerator<int> V_0,
                                object V_1)
                  IL_0000:  ldc.i4.1
                  IL_0001:  call       "System.Index System.Index.op_Implicit(int)"
                  IL_0006:  ldc.i4.4
                  IL_0007:  call       "System.Index System.Index.op_Implicit(int)"
                  IL_000c:  newobj     "System.Range..ctor(System.Index, System.Index)"
                  IL_0011:  call       "System.Collections.Generic.IAsyncEnumerator<int> Extensions.GetAsyncEnumerator(System.Range)"
                  IL_0016:  stloc.0
                  IL_0017:  ldnull
                  IL_0018:  stloc.1
                  .try
                  {
                    IL_0019:  br.s       IL_0026
                    IL_001b:  ldloc.0
                    IL_001c:  callvirt   "int System.Collections.Generic.IAsyncEnumerator<int>.Current.get"
                    IL_0021:  call       "void System.Console.Write(int)"
                    IL_0026:  ldloc.0
                    IL_0027:  callvirt   "System.Threading.Tasks.ValueTask<bool> System.Collections.Generic.IAsyncEnumerator<int>.MoveNextAsync()"
                    IL_002c:  call       "bool System.Runtime.CompilerServices.AsyncHelpers.Await<bool>(System.Threading.Tasks.ValueTask<bool>)"
                    IL_0031:  brtrue.s   IL_001b
                    IL_0033:  leave.s    IL_0038
                  }
                  catch object
                  {
                    IL_0035:  stloc.1
                    IL_0036:  leave.s    IL_0038
                  }
                  IL_0038:  ldloc.0
                  IL_0039:  brfalse.s  IL_0046
                  IL_003b:  ldloc.0
                  IL_003c:  callvirt   "System.Threading.Tasks.ValueTask System.IAsyncDisposable.DisposeAsync()"
                  IL_0041:  call       "void System.Runtime.CompilerServices.AsyncHelpers.Await(System.Threading.Tasks.ValueTask)"
                  IL_0046:  ldloc.1
                  IL_0047:  brfalse.s  IL_005e
                  IL_0049:  ldloc.1
                  IL_004a:  isinst     "System.Exception"
                  IL_004f:  dup
                  IL_0050:  brtrue.s   IL_0054
                  IL_0052:  ldloc.1
                  IL_0053:  throw
                  IL_0054:  call       "System.Runtime.ExceptionServices.ExceptionDispatchInfo System.Runtime.ExceptionServices.ExceptionDispatchInfo.Capture(System.Exception)"
                  IL_0059:  callvirt   "void System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()"
                  IL_005e:  ret
                }
                """);
        }
 
        [Fact]
        public void TestGetAsyncEnumeratorPatternViaExtensionsOnTuple()
        {
            var source = @"
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
public struct C
{
    public static async Task Main()
    {
        await foreach (var i in (1, 2, 3))
        {
            Console.Write(i);
        }
    }
}
public static class Extensions
{
    public static async IAsyncEnumerator<T> GetAsyncEnumerator<T>(this (T first, T second, T third) self)
    {
        await Task.Yield();
        yield return self.first;
        yield return self.second;
        yield return self.third;
    }
}";
            var comp = CreateCompilationWithTasksExtensions(new[] { source, AsyncStreamsTypes }, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular9);
            comp.VerifyDiagnostics();
            CompileAndVerify(comp, expectedOutput: "123");
 
            var runtimeAsyncComp = CreateRuntimeAsyncCompilation(source);
            var verifier = CompileAndVerify(runtimeAsyncComp, expectedOutput: CodeGenAsyncTests.ExpectedOutput("123", isRuntimeAsync: true), verify: Verification.Fails with
            {
                ILVerifyMessage = """
                    [Main]: Return value missing on the stack. { Offset = 0x55 }
                    """
            });
            verifier.VerifyIL("C.Main()", """
                {
                  // Code size       86 (0x56)
                  .maxstack  3
                  .locals init (System.Collections.Generic.IAsyncEnumerator<int> V_0,
                                object V_1)
                  IL_0000:  ldc.i4.1
                  IL_0001:  ldc.i4.2
                  IL_0002:  ldc.i4.3
                  IL_0003:  newobj     "System.ValueTuple<int, int, int>..ctor(int, int, int)"
                  IL_0008:  call       "System.Collections.Generic.IAsyncEnumerator<int> Extensions.GetAsyncEnumerator<int>(System.ValueTuple<int, int, int>)"
                  IL_000d:  stloc.0
                  IL_000e:  ldnull
                  IL_000f:  stloc.1
                  .try
                  {
                    IL_0010:  br.s       IL_001d
                    IL_0012:  ldloc.0
                    IL_0013:  callvirt   "int System.Collections.Generic.IAsyncEnumerator<int>.Current.get"
                    IL_0018:  call       "void System.Console.Write(int)"
                    IL_001d:  ldloc.0
                    IL_001e:  callvirt   "System.Threading.Tasks.ValueTask<bool> System.Collections.Generic.IAsyncEnumerator<int>.MoveNextAsync()"
                    IL_0023:  call       "bool System.Runtime.CompilerServices.AsyncHelpers.Await<bool>(System.Threading.Tasks.ValueTask<bool>)"
                    IL_0028:  brtrue.s   IL_0012
                    IL_002a:  leave.s    IL_002f
                  }
                  catch object
                  {
                    IL_002c:  stloc.1
                    IL_002d:  leave.s    IL_002f
                  }
                  IL_002f:  ldloc.0
                  IL_0030:  brfalse.s  IL_003d
                  IL_0032:  ldloc.0
                  IL_0033:  callvirt   "System.Threading.Tasks.ValueTask System.IAsyncDisposable.DisposeAsync()"
                  IL_0038:  call       "void System.Runtime.CompilerServices.AsyncHelpers.Await(System.Threading.Tasks.ValueTask)"
                  IL_003d:  ldloc.1
                  IL_003e:  brfalse.s  IL_0055
                  IL_0040:  ldloc.1
                  IL_0041:  isinst     "System.Exception"
                  IL_0046:  dup
                  IL_0047:  brtrue.s   IL_004b
                  IL_0049:  ldloc.1
                  IL_004a:  throw
                  IL_004b:  call       "System.Runtime.ExceptionServices.ExceptionDispatchInfo System.Runtime.ExceptionServices.ExceptionDispatchInfo.Capture(System.Exception)"
                  IL_0050:  callvirt   "void System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()"
                  IL_0055:  ret
                }
                """);
        }
 
        [Fact]
        public void TestGetAsyncEnumeratorPatternViaExtensionsOnTupleWithNestedConversions()
        {
            var source = @"
using System;
using System.Globalization;
using System.Linq;
using System.Collections.Generic;
using System.Threading.Tasks;
 
public struct C
{
    public static async Task Main()
    {
        await foreach (var (a, b) in (new[] { 1, 2, 3 }, new List<decimal>{ 0.1m, 0.2m, 0.3m }))
        {
            Console.WriteLine((a + b).ToString(CultureInfo.InvariantCulture));
        }
    }
}
public static class Extensions
{
    public static async IAsyncEnumerator<(T1, T2)> GetAsyncEnumerator<T1, T2>(this (IEnumerable<T1> first, IEnumerable<T2> second) self)
    {
        await Task.Yield();
        foreach(var pair in self.first.Zip(self.second, (a,b) => (a,b)))
        {
            yield return pair;
        }
    }
}";
            var comp = CreateCompilationWithTasksExtensions(new[] { source, AsyncStreamsTypes }, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular9);
            comp.VerifyDiagnostics();
            string expectedOutput = @"1.1
2.2
3.3";
            CompileAndVerify(comp, expectedOutput: expectedOutput);
 
            var runtimeAsyncComp = CreateRuntimeAsyncCompilation(source);
            var verifier = CompileAndVerify(runtimeAsyncComp, expectedOutput: CodeGenAsyncTests.ExpectedOutput(expectedOutput, isRuntimeAsync: true), verify: Verification.Fails with
            {
                ILVerifyMessage = """
                    [Main]: Return value missing on the stack. { Offset = 0xd4 }
                    """
            });
            verifier.VerifyIL("C.Main()", """
                {
                  // Code size      213 (0xd5)
                  .maxstack  9
                  .locals init (System.Collections.Generic.IAsyncEnumerator<System.ValueTuple<int, decimal>> V_0,
                                System.ValueTuple<int[], System.Collections.Generic.List<decimal>> V_1,
                                object V_2,
                                int V_3, //a
                                decimal V_4, //b
                                decimal V_5)
                  IL_0000:  ldloca.s   V_1
                  IL_0002:  ldc.i4.3
                  IL_0003:  newarr     "int"
                  IL_0008:  dup
                  IL_0009:  ldtoken    "<PrivateImplementationDetails>.__StaticArrayInitTypeSize=12 <PrivateImplementationDetails>.4636993D3E1DA4E9D6B8F87B79E8F7C6D018580D52661950EABC3845C5897A4D"
                  IL_000e:  call       "void System.Runtime.CompilerServices.RuntimeHelpers.InitializeArray(System.Array, System.RuntimeFieldHandle)"
                  IL_0013:  newobj     "System.Collections.Generic.List<decimal>..ctor()"
                  IL_0018:  dup
                  IL_0019:  ldc.i4.1
                  IL_001a:  ldc.i4.0
                  IL_001b:  ldc.i4.0
                  IL_001c:  ldc.i4.0
                  IL_001d:  ldc.i4.1
                  IL_001e:  newobj     "decimal..ctor(int, int, int, bool, byte)"
                  IL_0023:  callvirt   "void System.Collections.Generic.List<decimal>.Add(decimal)"
                  IL_0028:  dup
                  IL_0029:  ldc.i4.2
                  IL_002a:  ldc.i4.0
                  IL_002b:  ldc.i4.0
                  IL_002c:  ldc.i4.0
                  IL_002d:  ldc.i4.1
                  IL_002e:  newobj     "decimal..ctor(int, int, int, bool, byte)"
                  IL_0033:  callvirt   "void System.Collections.Generic.List<decimal>.Add(decimal)"
                  IL_0038:  dup
                  IL_0039:  ldc.i4.3
                  IL_003a:  ldc.i4.0
                  IL_003b:  ldc.i4.0
                  IL_003c:  ldc.i4.0
                  IL_003d:  ldc.i4.1
                  IL_003e:  newobj     "decimal..ctor(int, int, int, bool, byte)"
                  IL_0043:  callvirt   "void System.Collections.Generic.List<decimal>.Add(decimal)"
                  IL_0048:  call       "System.ValueTuple<int[], System.Collections.Generic.List<decimal>>..ctor(int[], System.Collections.Generic.List<decimal>)"
                  IL_004d:  ldloc.1
                  IL_004e:  ldfld      "int[] System.ValueTuple<int[], System.Collections.Generic.List<decimal>>.Item1"
                  IL_0053:  ldloc.1
                  IL_0054:  ldfld      "System.Collections.Generic.List<decimal> System.ValueTuple<int[], System.Collections.Generic.List<decimal>>.Item2"
                  IL_0059:  newobj     "System.ValueTuple<System.Collections.Generic.IEnumerable<int>, System.Collections.Generic.IEnumerable<decimal>>..ctor(System.Collections.Generic.IEnumerable<int>, System.Collections.Generic.IEnumerable<decimal>)"
                  IL_005e:  call       "System.Collections.Generic.IAsyncEnumerator<System.ValueTuple<int, decimal>> Extensions.GetAsyncEnumerator<int, decimal>(System.ValueTuple<System.Collections.Generic.IEnumerable<int>, System.Collections.Generic.IEnumerable<decimal>>)"
                  IL_0063:  stloc.0
                  IL_0064:  ldnull
                  IL_0065:  stloc.2
                  .try
                  {
                    IL_0066:  br.s       IL_009c
                    IL_0068:  ldloc.0
                    IL_0069:  callvirt   "System.ValueTuple<int, decimal> System.Collections.Generic.IAsyncEnumerator<System.ValueTuple<int, decimal>>.Current.get"
                    IL_006e:  dup
                    IL_006f:  ldfld      "int System.ValueTuple<int, decimal>.Item1"
                    IL_0074:  stloc.3
                    IL_0075:  ldfld      "decimal System.ValueTuple<int, decimal>.Item2"
                    IL_007a:  stloc.s    V_4
                    IL_007c:  ldloc.3
                    IL_007d:  call       "decimal decimal.op_Implicit(int)"
                    IL_0082:  ldloc.s    V_4
                    IL_0084:  call       "decimal decimal.op_Addition(decimal, decimal)"
                    IL_0089:  stloc.s    V_5
                    IL_008b:  ldloca.s   V_5
                    IL_008d:  call       "System.Globalization.CultureInfo System.Globalization.CultureInfo.InvariantCulture.get"
                    IL_0092:  call       "string decimal.ToString(System.IFormatProvider)"
                    IL_0097:  call       "void System.Console.WriteLine(string)"
                    IL_009c:  ldloc.0
                    IL_009d:  callvirt   "System.Threading.Tasks.ValueTask<bool> System.Collections.Generic.IAsyncEnumerator<System.ValueTuple<int, decimal>>.MoveNextAsync()"
                    IL_00a2:  call       "bool System.Runtime.CompilerServices.AsyncHelpers.Await<bool>(System.Threading.Tasks.ValueTask<bool>)"
                    IL_00a7:  brtrue.s   IL_0068
                    IL_00a9:  leave.s    IL_00ae
                  }
                  catch object
                  {
                    IL_00ab:  stloc.2
                    IL_00ac:  leave.s    IL_00ae
                  }
                  IL_00ae:  ldloc.0
                  IL_00af:  brfalse.s  IL_00bc
                  IL_00b1:  ldloc.0
                  IL_00b2:  callvirt   "System.Threading.Tasks.ValueTask System.IAsyncDisposable.DisposeAsync()"
                  IL_00b7:  call       "void System.Runtime.CompilerServices.AsyncHelpers.Await(System.Threading.Tasks.ValueTask)"
                  IL_00bc:  ldloc.2
                  IL_00bd:  brfalse.s  IL_00d4
                  IL_00bf:  ldloc.2
                  IL_00c0:  isinst     "System.Exception"
                  IL_00c5:  dup
                  IL_00c6:  brtrue.s   IL_00ca
                  IL_00c8:  ldloc.2
                  IL_00c9:  throw
                  IL_00ca:  call       "System.Runtime.ExceptionServices.ExceptionDispatchInfo System.Runtime.ExceptionServices.ExceptionDispatchInfo.Capture(System.Exception)"
                  IL_00cf:  callvirt   "void System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()"
                  IL_00d4:  ret
                }
                """);
        }
 
        [Fact]
        public void TestMoveNextAsyncPatternViaExtensions1()
        {
            string source = @"
using System;
using System.Threading.Tasks;
public class C
{
    public static async Task Main()
    {
        await foreach (var i in new C())
        {
            Console.Write(i);
        }
    }
    public sealed class Enumerator
    {
        public int Current { get; private set; }
        
    }
}
public static class Extensions
{
    public static C.Enumerator GetAsyncEnumerator(this C self) => new C.Enumerator();
    public static bool MoveNext(this C.Enumerator e) => false;
}";
            var comp = CreateCompilationWithMscorlib46(source, parseOptions: TestOptions.Regular9);
            comp.VerifyDiagnostics(
                // (8,33): error CS0117: 'C.Enumerator' does not contain a definition for 'MoveNextAsync'
                //         await foreach (var i in new C())
                Diagnostic(ErrorCode.ERR_NoSuchMember, "new C()").WithArguments("C.Enumerator", "MoveNextAsync").WithLocation(8, 33),
                // (8,33): error CS8412: Asynchronous foreach requires that the return type 'C.Enumerator' of 'Extensions.GetAsyncEnumerator(C)' must have a suitable public 'MoveNextAsync' method and public 'Current' property
                //         await foreach (var i in new C())
                Diagnostic(ErrorCode.ERR_BadGetAsyncEnumerator, "new C()").WithArguments("C.Enumerator", "Extensions.GetAsyncEnumerator(C)").WithLocation(8, 33)
                );
        }
 
        [Fact]
        public void TestMoveNextAsyncPatternViaExtensions2()
        {
            string source = @"
using System;
using System.Threading.Tasks;
public class C
{
    public static async Task Main()
    {
        await foreach (var i in new C())
        {
            Console.Write(i);
        }
    }
    public sealed class Enumerator
    {
        public int Current { get; private set; }
        
    }
 
    public C.Enumerator GetAsyncEnumerator() => new C.Enumerator();
}
public static class Extensions
{
    public static bool MoveNext(this C.Enumerator e) => false;
}";
            var comp = CreateCompilationWithMscorlib46(source, parseOptions: TestOptions.Regular9);
            comp.VerifyDiagnostics(
                // (8,33): error CS0117: 'C.Enumerator' does not contain a definition for 'MoveNextAsync'
                //         await foreach (var i in new C())
                Diagnostic(ErrorCode.ERR_NoSuchMember, "new C()").WithArguments("C.Enumerator", "MoveNextAsync").WithLocation(8, 33),
                // (8,33): error CS8412: Asynchronous foreach requires that the return type 'C.Enumerator' of 'C.GetAsyncEnumerator()' must have a suitable public 'MoveNextAsync' method and public 'Current' property
                //         await foreach (var i in new C())
                Diagnostic(ErrorCode.ERR_BadGetAsyncEnumerator, "new C()").WithArguments("C.Enumerator", "C.GetAsyncEnumerator()").WithLocation(8, 33)
                );
        }
 
        [Fact]
        public void TestPreferAsyncEnumeratorPatternFromInstanceThanViaExtension()
        {
            string source = @"
using System;
using System.Threading.Tasks;
public class C
{
    public static async Task Main()
    {
        await foreach (var i in new C())
        {
            Console.Write(i);
        }
    }
    public sealed class Enumerator1
    {
        public int Current { get; private set; }
        public Task<bool> MoveNextAsync() => Task.FromResult(Current++ != 3);
    }
    public sealed class Enumerator2
    {
        public int Current { get; private set; }
        public Task<bool> MoveNextAsync() => throw null;
    }
 
    public C.Enumerator1 GetAsyncEnumerator() => new C.Enumerator1();
}
 
public static class Extensions
{
    public static C.Enumerator2 GetAsyncEnumerator(this C self) => throw null;
}";
            var comp = CreateCompilationWithMscorlib46(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular9);
            comp.VerifyDiagnostics();
            CompileAndVerify(comp, expectedOutput: "123");
 
            var runtimeAsyncComp = CreateRuntimeAsyncCompilation(source);
            var verifier = CompileAndVerify(runtimeAsyncComp, expectedOutput: CodeGenAsyncTests.ExpectedOutput("123", isRuntimeAsync: true), verify: Verification.Fails with
            {
                ILVerifyMessage = """
                    [Main]: Return value missing on the stack. { Offset = 0x25 }
                    """
            });
            verifier.VerifyIL("C.Main()", """
                {
                  // Code size       38 (0x26)
                  .maxstack  1
                  .locals init (C.Enumerator1 V_0)
                  IL_0000:  newobj     "C..ctor()"
                  IL_0005:  call       "C.Enumerator1 C.GetAsyncEnumerator()"
                  IL_000a:  stloc.0
                  IL_000b:  br.s       IL_0018
                  IL_000d:  ldloc.0
                  IL_000e:  callvirt   "int C.Enumerator1.Current.get"
                  IL_0013:  call       "void System.Console.Write(int)"
                  IL_0018:  ldloc.0
                  IL_0019:  callvirt   "System.Threading.Tasks.Task<bool> C.Enumerator1.MoveNextAsync()"
                  IL_001e:  call       "bool System.Runtime.CompilerServices.AsyncHelpers.Await<bool>(System.Threading.Tasks.Task<bool>)"
                  IL_0023:  brtrue.s   IL_000d
                  IL_0025:  ret
                }
                """);
        }
 
        [Fact]
        public void TestPreferAsyncEnumeratorPatternFromInstanceThanViaExtensionEvenWhenInvalid()
        {
            string source = @"
using System;
using System.Threading.Tasks;
public class C
{
    public static async Task Main()
    {
        await foreach (var i in new C())
        {
            Console.Write(i);
        }
    }
    public sealed class Enumerator1
    {
    }
    public sealed class Enumerator2
    {
        public int Current { get; private set; }
        public Task<bool> MoveNextAsync() => throw null;
    }
 
    public C.Enumerator1 GetAsyncEnumerator() => throw null;
}
 
public static class Extensions
{
    public static C.Enumerator2 GetAsyncEnumerator(this C self) => throw null;
}";
            var comp = CreateCompilationWithMscorlib46(source, parseOptions: TestOptions.Regular9);
            comp.VerifyDiagnostics(
                // (8,33): error CS0117: 'C.Enumerator1' does not contain a definition for 'Current'
                //         await foreach (var i in new C())
                Diagnostic(ErrorCode.ERR_NoSuchMember, "new C()").WithArguments("C.Enumerator1", "Current").WithLocation(8, 33),
                // (8,33): error CS8412: Asynchronous foreach requires that the return type 'C.Enumerator1' of 'C.GetAsyncEnumerator()' must have a suitable public 'MoveNextAsync' method and public 'Current' property
                //         await foreach (var i in new C())
                Diagnostic(ErrorCode.ERR_BadGetAsyncEnumerator, "new C()").WithArguments("C.Enumerator1", "C.GetAsyncEnumerator()").WithLocation(8, 33));
        }
 
        [Fact]
        public void TestPreferAsyncEnumeratorPatternFromIAsyncEnumerableInterfaceThanViaExtension()
        {
            string source = @"
using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
 
public class C : IAsyncEnumerable<int>
{
    public static async Task Main()
    {
        await foreach (var i in new C())
        {
            Console.Write(i);
        }
    }
    
    public sealed class Enumerator1 : IAsyncEnumerator<int>
    {
        public int Current { get; private set; }
 
        public ValueTask<bool> MoveNextAsync() => new ValueTask<bool>(Current++ != 3);
 
        public ValueTask DisposeAsync() => new ValueTask();
    }
 
    public sealed class Enumerator2
    {
        public int Current { get; private set; }
        public Task<bool> MoveNextAsync() => throw null;
    }
 
    IAsyncEnumerator<int> IAsyncEnumerable<int>.GetAsyncEnumerator(CancellationToken cancellationToken) => new C.Enumerator1();
}
 
public static class Extensions
{
    public static C.Enumerator2 GetAsyncEnumerator(this C self) => throw null;
}";
            var comp = CreateCompilationWithTasksExtensions(new[] { source, s_IAsyncEnumerable }, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular9);
            comp.VerifyDiagnostics();
            CompileAndVerify(comp, expectedOutput: "123");
 
            var runtimeAsyncComp = CreateRuntimeAsyncCompilation(source);
            var verifier = CompileAndVerify(runtimeAsyncComp, expectedOutput: CodeGenAsyncTests.ExpectedOutput("123", isRuntimeAsync: true), verify: Verification.Fails with
            {
                ILVerifyMessage = """
                    [Main]: Return value missing on the stack. { Offset = 0x5b }
                    """
            });
            verifier.VerifyIL("C.Main()", """
                {
                  // Code size       92 (0x5c)
                  .maxstack  2
                  .locals init (System.Collections.Generic.IAsyncEnumerator<int> V_0,
                                System.Threading.CancellationToken V_1,
                                object V_2)
                  IL_0000:  newobj     "C..ctor()"
                  IL_0005:  ldloca.s   V_1
                  IL_0007:  initobj    "System.Threading.CancellationToken"
                  IL_000d:  ldloc.1
                  IL_000e:  callvirt   "System.Collections.Generic.IAsyncEnumerator<int> System.Collections.Generic.IAsyncEnumerable<int>.GetAsyncEnumerator(System.Threading.CancellationToken)"
                  IL_0013:  stloc.0
                  IL_0014:  ldnull
                  IL_0015:  stloc.2
                  .try
                  {
                    IL_0016:  br.s       IL_0023
                    IL_0018:  ldloc.0
                    IL_0019:  callvirt   "int System.Collections.Generic.IAsyncEnumerator<int>.Current.get"
                    IL_001e:  call       "void System.Console.Write(int)"
                    IL_0023:  ldloc.0
                    IL_0024:  callvirt   "System.Threading.Tasks.ValueTask<bool> System.Collections.Generic.IAsyncEnumerator<int>.MoveNextAsync()"
                    IL_0029:  call       "bool System.Runtime.CompilerServices.AsyncHelpers.Await<bool>(System.Threading.Tasks.ValueTask<bool>)"
                    IL_002e:  brtrue.s   IL_0018
                    IL_0030:  leave.s    IL_0035
                  }
                  catch object
                  {
                    IL_0032:  stloc.2
                    IL_0033:  leave.s    IL_0035
                  }
                  IL_0035:  ldloc.0
                  IL_0036:  brfalse.s  IL_0043
                  IL_0038:  ldloc.0
                  IL_0039:  callvirt   "System.Threading.Tasks.ValueTask System.IAsyncDisposable.DisposeAsync()"
                  IL_003e:  call       "void System.Runtime.CompilerServices.AsyncHelpers.Await(System.Threading.Tasks.ValueTask)"
                  IL_0043:  ldloc.2
                  IL_0044:  brfalse.s  IL_005b
                  IL_0046:  ldloc.2
                  IL_0047:  isinst     "System.Exception"
                  IL_004c:  dup
                  IL_004d:  brtrue.s   IL_0051
                  IL_004f:  ldloc.2
                  IL_0050:  throw
                  IL_0051:  call       "System.Runtime.ExceptionServices.ExceptionDispatchInfo System.Runtime.ExceptionServices.ExceptionDispatchInfo.Capture(System.Exception)"
                  IL_0056:  callvirt   "void System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()"
                  IL_005b:  ret
                }
                """);
        }
 
        [Fact]
        public void TestCannotUseExtensionGetAsyncEnumeratorOnDynamic()
        {
            var source = @"
using System;
using System.Threading.Tasks;
 
public class C
{
    public static async Task Main()
    {
        await foreach (var i in (dynamic)new C())
        {
            Console.Write(i);
        }
    }
 
    public sealed class Enumerator2
    {
        public int Current { get; private set; }
        public bool MoveNext() => throw null;
    }
}
 
public static class Extensions
{
    public static C.Enumerator2 GetAsyncEnumerator(this C self) => throw null;
}";
            // (9,33): error CS8416: Cannot use a collection of dynamic type in an asynchronous foreach
            //         await foreach (var i in (dynamic)new C())
            DiagnosticDescription expected = Diagnostic(ErrorCode.ERR_BadDynamicAwaitForEach, "(dynamic)new C()").WithLocation(9, 33);
            CreateCompilationWithCSharp(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular9)
                .VerifyDiagnostics(expected);
 
            var comp = CreateRuntimeAsyncCompilation(source);
            comp.VerifyEmitDiagnostics(expected);
        }
 
        [Fact]
        public void TestGetAsyncEnumeratorPatternViaAmbiguousExtensions()
        {
            string source = @"
using System;
using System.Threading.Tasks;
public class C
{
    public static async Task Main()
    {
        await foreach (var i in new C())
        {
            Console.Write(i);
        }
    }
    public sealed class Enumerator
    {
        public int Current { get; private set; }
        public Task<bool> MoveNextAsync() => Task.FromResult(Current++ != 3);
    }
}
public static class Extensions1
{
    public static C.Enumerator GetAsyncEnumerator(this C self) => new C.Enumerator();
}
public static class Extensions2
{
    public static C.Enumerator GetAsyncEnumerator(this C self) => new C.Enumerator();
}";
            var comp = CreateCompilationWithMscorlib46(source, parseOptions: TestOptions.Regular9);
            comp.VerifyDiagnostics(
                // (8,33): warning CS0278: 'C' does not implement the 'collection' pattern. 'Extensions1.GetAsyncEnumerator(C)' is ambiguous with 'Extensions2.GetAsyncEnumerator(C)'.
                //         await foreach (var i in new C())
                Diagnostic(ErrorCode.WRN_PatternIsAmbiguous, "new C()").WithArguments("C", "collection", "Extensions1.GetAsyncEnumerator(C)", "Extensions2.GetAsyncEnumerator(C)").WithLocation(8, 33),
                // (8,33): error CS8411: Asynchronous foreach statement cannot operate on variables of type 'C' because 'C' does not contain a suitable public instance or extension definition for 'GetAsyncEnumerator'
                //         await foreach (var i in new C())
                Diagnostic(ErrorCode.ERR_AwaitForEachMissingMember, "new C()").WithArguments("C", "GetAsyncEnumerator").WithLocation(8, 33)
                );
        }
 
        [Fact]
        public void TestGetAsyncEnumeratorPatternViaAmbiguousExtensionsWhenOneHasCorrectPattern()
        {
            var source = @"
using System;
using System.Threading.Tasks;
public class C
{
    public static async Task Main()
    {
        await foreach (var i in new C())
        {
            Console.Write(i);
        }
    }
    public sealed class Enumerator
    {
        public int Current { get; private set; }
        public Task<bool> MoveNextAsync() => Task.FromResult(Current++ != 3);
    }
}
public static class Extensions1
{
    public static int GetAsyncEnumerator(this C self) => 42;
}
public static class Extensions2
{
    public static C.Enumerator GetAsyncEnumerator(this C self) => new C.Enumerator();
}";
            CreateCompilation(source, parseOptions: TestOptions.Regular9)
                .VerifyDiagnostics(
                    // (8,33): warning CS0278: 'C' does not implement the 'collection' pattern. 'Extensions1.GetAsyncEnumerator(C)' is ambiguous with 'Extensions2.GetAsyncEnumerator(C)'.
                    //         await foreach (var i in new C())
                    Diagnostic(ErrorCode.WRN_PatternIsAmbiguous, "new C()").WithArguments("C", "collection", "Extensions1.GetAsyncEnumerator(C)", "Extensions2.GetAsyncEnumerator(C)").WithLocation(8, 33),
                    // (8,33): error CS8411: Asynchronous foreach statement cannot operate on variables of type 'C' because 'C' does not contain a suitable public instance or extension definition for 'GetAsyncEnumerator'
                    //         await foreach (var i in new C())
                    Diagnostic(ErrorCode.ERR_AwaitForEachMissingMember, "new C()").WithArguments("C", "GetAsyncEnumerator").WithLocation(8, 33)
                    );
        }
 
        [Fact]
        public void TestGetAsyncEnumeratorPatternViaAmbiguousExtensionsWhenNeitherHasCorrectPattern()
        {
            var source = @"
using System;
using System.Threading.Tasks;
public class C
{
    public static async Task Main()
    {
        await foreach (var i in new C())
        {
            Console.Write(i);
        }
    }
    public sealed class Enumerator
    {
        public int Current { get; private set; }
        public Task<bool> MoveNextAsync() => Task.FromResult(Current++ != 3);
    }
}
public static class Extensions1
{
    public static int GetAsyncEnumerator(this C self) => 42;
}
public static class Extensions2
{
    public static bool GetAsyncEnumerator(this C self) => true;
}";
            CreateCompilation(source, parseOptions: TestOptions.Regular9)
                .VerifyDiagnostics(
                    // (8,33): warning CS0278: 'C' does not implement the 'collection' pattern. 'Extensions1.GetAsyncEnumerator(C)' is ambiguous with 'Extensions2.GetAsyncEnumerator(C)'.
                    //         await foreach (var i in new C())
                    Diagnostic(ErrorCode.WRN_PatternIsAmbiguous, "new C()").WithArguments("C", "collection", "Extensions1.GetAsyncEnumerator(C)", "Extensions2.GetAsyncEnumerator(C)").WithLocation(8, 33),
                    // (8,33): error CS8411: Asynchronous foreach statement cannot operate on variables of type 'C' because 'C' does not contain a suitable public instance or extension definition for 'GetAsyncEnumerator'
                    //         await foreach (var i in new C())
                    Diagnostic(ErrorCode.ERR_AwaitForEachMissingMember, "new C()").WithArguments("C", "GetAsyncEnumerator").WithLocation(8, 33)
                    );
        }
 
        [Fact]
        public void TestGetAsyncEnumeratorPatternViaAmbiguousExtensionsWhenOneHasCorrectNumberOfParameters()
        {
            var source = @"
using System;
using System.Threading.Tasks;
public class C
{
    public static async Task Main()
    {
        await foreach (var i in new C())
        {
            Console.Write(i);
        }
    }
    public sealed class Enumerator
    {
        public int Current { get; private set; }
        public Task<bool> MoveNextAsync() => Task.FromResult(Current++ != 3);
    }
}
public static class Extensions1
{
    public static C.Enumerator GetAsyncEnumerator(this C self, int _) => throw null;
}
public static class Extensions2
{
    public static C.Enumerator GetAsyncEnumerator(this C self) => new C.Enumerator();
}";
            var comp = CreateCompilationWithMscorlib46(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular9);
            comp.VerifyDiagnostics();
            CompileAndVerify(comp, expectedOutput: "123");
 
            var runtimeAsyncComp = CreateRuntimeAsyncCompilation(source);
            var verifier = CompileAndVerify(runtimeAsyncComp, expectedOutput: CodeGenAsyncTests.ExpectedOutput("123", isRuntimeAsync: true), verify: Verification.Fails with
            {
                ILVerifyMessage = """
                    [Main]: Return value missing on the stack. { Offset = 0x25 }
                    """
            });
            verifier.VerifyIL("C.Main()", """
                {
                  // Code size       38 (0x26)
                  .maxstack  1
                  .locals init (C.Enumerator V_0)
                  IL_0000:  newobj     "C..ctor()"
                  IL_0005:  call       "C.Enumerator Extensions2.GetAsyncEnumerator(C)"
                  IL_000a:  stloc.0
                  IL_000b:  br.s       IL_0018
                  IL_000d:  ldloc.0
                  IL_000e:  callvirt   "int C.Enumerator.Current.get"
                  IL_0013:  call       "void System.Console.Write(int)"
                  IL_0018:  ldloc.0
                  IL_0019:  callvirt   "System.Threading.Tasks.Task<bool> C.Enumerator.MoveNextAsync()"
                  IL_001e:  call       "bool System.Runtime.CompilerServices.AsyncHelpers.Await<bool>(System.Threading.Tasks.Task<bool>)"
                  IL_0023:  brtrue.s   IL_000d
                  IL_0025:  ret
                }
                """);
        }
 
        [Fact]
        public void TestGetAsyncEnumeratorPatternViaAmbiguousExtensionsWhenNeitherHasCorrectNumberOfParameters()
        {
            var source = @"
using System;
using System.Threading.Tasks;
public class C
{
    public static async Task Main()
    {
        await foreach (var i in new C())
        {
            Console.Write(i);
        }
    }
    public sealed class Enumerator
    {
        public int Current { get; private set; }
        public Task<bool> MoveNextAsync() => Task.FromResult(Current++ != 3);
    }
}
public static class Extensions1
{
    public static C.Enumerator GetAsyncEnumerator(this C self, int _) => new C.Enumerator();
}
public static class Extensions2
{
    public static C.Enumerator GetAsyncEnumerator(this C self, bool _) => new C.Enumerator();
}";
            CreateCompilation(source, parseOptions: TestOptions.Regular9)
                .VerifyDiagnostics(
                    // (8,33): error CS1501: No overload for method 'GetAsyncEnumerator' takes 0 arguments
                    //         await foreach (var i in new C())
                    Diagnostic(ErrorCode.ERR_BadArgCount, "new C()").WithArguments("GetAsyncEnumerator", "0").WithLocation(8, 33),
                    // (8,33): error CS8411: Asynchronous foreach statement cannot operate on variables of type 'C' because 'C' does not contain a suitable public instance or extension definition for 'GetAsyncEnumerator'
                    //         await foreach (var i in new C())
                    Diagnostic(ErrorCode.ERR_AwaitForEachMissingMember, "new C()").WithArguments("C", "GetAsyncEnumerator").WithLocation(8, 33)
                    );
        }
 
        [Fact]
        public void TestGetAsyncEnumeratorPatternViaAmbiguousExtensionsOnDifferentInterfaces()
        {
            var source = @"
using System;
using System.Threading.Tasks;
 
public interface I1 {}
public interface I2 {}
 
public class C : I1, I2
{
    public static async Task Main()
    {
        await foreach (var i in new C())
        {
            Console.Write(i);
        }
    }
    public sealed class Enumerator
    {
        public int Current { get; private set; }
        public Task<bool> MoveNextAsync() => Task.FromResult(Current++ != 3);
    }
}
public static class Extensions1
{
    public static C.Enumerator GetAsyncEnumerator(this I1 self) => new C.Enumerator();
}
public static class Extensions2
{
    public static C.Enumerator GetAsyncEnumerator(this I2 self) => new C.Enumerator();
}";
            CreateCompilation(source, parseOptions: TestOptions.Regular9)
                .VerifyDiagnostics(
                    // (12,33): warning CS0278: 'C' does not implement the 'collection' pattern. 'Extensions1.GetAsyncEnumerator(I1)' is ambiguous with 'Extensions2.GetAsyncEnumerator(I2)'.
                    //         await foreach (var i in new C())
                    Diagnostic(ErrorCode.WRN_PatternIsAmbiguous, "new C()").WithArguments("C", "collection", "Extensions1.GetAsyncEnumerator(I1)", "Extensions2.GetAsyncEnumerator(I2)").WithLocation(12, 33),
                    // (12,33): error CS8411: Asynchronous foreach statement cannot operate on variables of type 'C' because 'C' does not contain a suitable public instance or extension definition for 'GetAsyncEnumerator'
                    //         await foreach (var i in new C())
                    Diagnostic(ErrorCode.ERR_AwaitForEachMissingMember, "new C()").WithArguments("C", "GetAsyncEnumerator").WithLocation(12, 33)
                    );
        }
 
        [Fact]
        public void TestGetAsyncEnumeratorPatternViaAmbiguousExtensionsWithMostSpecificReceiver()
        {
            var source = @"
using System;
using System.Threading.Tasks;
 
public interface I {}
public class C : I
{
    public static async Task Main()
    {
        await foreach (var i in new C())
        {
            Console.Write(i);
        }
    }
    public sealed class Enumerator
    {
        public int Current { get; private set; }
        public Task<bool> MoveNextAsync() => Task.FromResult(Current++ != 3);
    }
}
public static class Extensions1
{
    public static C.Enumerator GetAsyncEnumerator(this I self) => throw null;
}
public static class Extensions2
{
    public static C.Enumerator GetAsyncEnumerator(this C self) => new C.Enumerator();
}";
            var comp = CreateCompilationWithMscorlib46(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular9);
            comp.VerifyDiagnostics();
            CompileAndVerify(comp, expectedOutput: "123");
 
            var runtimeAsyncComp = CreateRuntimeAsyncCompilation(source);
            var verifier = CompileAndVerify(runtimeAsyncComp, expectedOutput: CodeGenAsyncTests.ExpectedOutput("123", isRuntimeAsync: true), verify: Verification.Fails with
            {
                ILVerifyMessage = """
                    [Main]: Return value missing on the stack. { Offset = 0x25 }
                    """
            });
            verifier.VerifyIL("C.Main()", """
                {
                  // Code size       38 (0x26)
                  .maxstack  1
                  .locals init (C.Enumerator V_0)
                  IL_0000:  newobj     "C..ctor()"
                  IL_0005:  call       "C.Enumerator Extensions2.GetAsyncEnumerator(C)"
                  IL_000a:  stloc.0
                  IL_000b:  br.s       IL_0018
                  IL_000d:  ldloc.0
                  IL_000e:  callvirt   "int C.Enumerator.Current.get"
                  IL_0013:  call       "void System.Console.Write(int)"
                  IL_0018:  ldloc.0
                  IL_0019:  callvirt   "System.Threading.Tasks.Task<bool> C.Enumerator.MoveNextAsync()"
                  IL_001e:  call       "bool System.Runtime.CompilerServices.AsyncHelpers.Await<bool>(System.Threading.Tasks.Task<bool>)"
                  IL_0023:  brtrue.s   IL_000d
                  IL_0025:  ret
                }
                """);
        }
 
        [Fact]
        public void TestGetAsyncEnumeratorPatternViaAmbiguousExtensionsWithMostSpecificReceiverWhenMostSpecificReceiverDoesntImplementPattern()
        {
            var source = @"
using System;
using System.Threading.Tasks;
 
public interface I {}
public class C : I
{
    public static async Task Main()
    {
        await foreach (var i in new C())
        {
            Console.Write(i);
        }
    }
    public sealed class Enumerator
    {
        public int Current { get; private set; }
        public Task<bool> MoveNextAsync() => Task.FromResult(Current++ != 3);
    }
}
public static class Extensions1
{
    public static C.Enumerator GetAsyncEnumerator(this I self) => throw null;
}
public static class Extensions2
{ 
    public static int GetAsyncEnumerator(this C self) => 42;
}";
            CreateCompilation(source, parseOptions: TestOptions.Regular9)
                .VerifyDiagnostics(
                    // (10,33): error CS0117: 'int' does not contain a definition for 'Current'
                    //         await foreach (var i in new C())
                    Diagnostic(ErrorCode.ERR_NoSuchMember, "new C()").WithArguments("int", "Current").WithLocation(10, 33),
                    // (10,33): error CS8412: Asynchronous foreach requires that the return type 'int' of 'Extensions2.GetAsyncEnumerator(C)' must have a suitable public 'MoveNextAsync' method and public 'Current' property
                    //         await foreach (var i in new C())
                    Diagnostic(ErrorCode.ERR_BadGetAsyncEnumerator, "new C()").WithArguments("int", "Extensions2.GetAsyncEnumerator(C)").WithLocation(10, 33)
                    );
        }
 
        [Fact]
        public void TestGetAsyncEnumeratorPatternViaAmbiguousExtensionsWhenOneHasOptionalParams()
        {
            var source = @"
using System;
using System.Threading.Tasks;
public class C
{
    public static async Task Main()
    {
        await foreach (var i in new C())
        {
            Console.Write(i);
        }
    }
    public sealed class Enumerator
    {
        public int Current { get; private set; }
        public Task<bool> MoveNextAsync() => Task.FromResult(Current++ != 3);
    }
}
public static class Extensions1
{
    public static C.Enumerator GetAsyncEnumerator(this C self) => new C.Enumerator();
}
public static class Extensions2
{
    public static C.Enumerator GetAsyncEnumerator(this C self, int a = 0) => throw null;
}";
            var comp = CreateCompilationWithMscorlib46(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular9);
            comp.VerifyDiagnostics();
            CompileAndVerify(comp, expectedOutput: "123");
 
            var runtimeAsyncComp = CreateRuntimeAsyncCompilation(source);
            var verifier = CompileAndVerify(runtimeAsyncComp, expectedOutput: CodeGenAsyncTests.ExpectedOutput("123", isRuntimeAsync: true), verify: Verification.Fails with
            {
                ILVerifyMessage = """
                    [Main]: Return value missing on the stack. { Offset = 0x25 }
                    """
            });
            verifier.VerifyIL("C.Main()", """
                {
                  // Code size       38 (0x26)
                  .maxstack  1
                  .locals init (C.Enumerator V_0)
                  IL_0000:  newobj     "C..ctor()"
                  IL_0005:  call       "C.Enumerator Extensions1.GetAsyncEnumerator(C)"
                  IL_000a:  stloc.0
                  IL_000b:  br.s       IL_0018
                  IL_000d:  ldloc.0
                  IL_000e:  callvirt   "int C.Enumerator.Current.get"
                  IL_0013:  call       "void System.Console.Write(int)"
                  IL_0018:  ldloc.0
                  IL_0019:  callvirt   "System.Threading.Tasks.Task<bool> C.Enumerator.MoveNextAsync()"
                  IL_001e:  call       "bool System.Runtime.CompilerServices.AsyncHelpers.Await<bool>(System.Threading.Tasks.Task<bool>)"
                  IL_0023:  brtrue.s   IL_000d
                  IL_0025:  ret
                }
                """);
        }
 
        [Fact]
        public void TestGetAsyncEnumeratorPatternViaAmbiguousExtensionsWhenOneHasFewerOptionalParams()
        {
            var source = @"
using System;
using System.Threading.Tasks;
public class C
{
    public static async Task Main()
    {
        await foreach (var i in new C())
        {
            Console.Write(i);
        }
    }
    public sealed class Enumerator
    {
        public int Current { get; private set; }
        public Task<bool> MoveNextAsync() => Task.FromResult(Current++ != 3);
    }
}
public static class Extensions1
{
    public static C.Enumerator GetAsyncEnumerator(this C self, int a = 0, int b = 1) => new C.Enumerator();
}
public static class Extensions2
{
    public static C.Enumerator GetAsyncEnumerator(this C self, int a = 0) => new C.Enumerator();
}";
            CreateCompilation(source, parseOptions: TestOptions.Regular9)
                .VerifyDiagnostics(
                    // (8,33): warning CS0278: 'C' does not implement the 'collection' pattern. 'Extensions1.GetAsyncEnumerator(C, int, int)' is ambiguous with 'Extensions2.GetAsyncEnumerator(C, int)'.
                    //         await foreach (var i in new C())
                    Diagnostic(ErrorCode.WRN_PatternIsAmbiguous, "new C()").WithArguments("C", "collection", "Extensions1.GetAsyncEnumerator(C, int, int)", "Extensions2.GetAsyncEnumerator(C, int)").WithLocation(8, 33),
                    // (8,33): error CS8411: Asynchronous foreach statement cannot operate on variables of type 'C' because 'C' does not contain a suitable public instance or extension definition for 'GetAsyncEnumerator'
                    //         await foreach (var i in new C())
                    Diagnostic(ErrorCode.ERR_AwaitForEachMissingMember, "new C()").WithArguments("C", "GetAsyncEnumerator").WithLocation(8, 33)
                    );
        }
 
        [Fact]
        public void TestGetAsyncEnumeratorPatternViaExtensionWithOptionalParameter()
        {
            string source = @"
using System;
using System.Threading.Tasks;
public class C
{
    public static async Task Main()
    {
        await foreach (var i in new C())
        {
            Console.Write(i);
        }
    }
    public sealed class Enumerator
    {
        public Enumerator(int start) => Current = start;
        public int Current { get; private set; }
        public Task<bool> MoveNextAsync() => Task.FromResult(Current++ != 3);
    }
}
public static class Extensions
{
    public static C.Enumerator GetAsyncEnumerator(this C self, int x = 1) => new C.Enumerator(x);
}";
            var comp = CreateCompilationWithMscorlib46(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular9);
            comp.VerifyDiagnostics();
            CompileAndVerify(comp, expectedOutput: "23");
 
            var runtimeAsyncComp = CreateRuntimeAsyncCompilation(source);
            var verifier = CompileAndVerify(runtimeAsyncComp, expectedOutput: CodeGenAsyncTests.ExpectedOutput("23", isRuntimeAsync: true), verify: Verification.Fails with
            {
                ILVerifyMessage = """
                    [Main]: Return value missing on the stack. { Offset = 0x26 }
                    """
            });
            verifier.VerifyIL("C.Main()", """
                {
                  // Code size       39 (0x27)
                  .maxstack  2
                  .locals init (C.Enumerator V_0)
                  IL_0000:  newobj     "C..ctor()"
                  IL_0005:  ldc.i4.1
                  IL_0006:  call       "C.Enumerator Extensions.GetAsyncEnumerator(C, int)"
                  IL_000b:  stloc.0
                  IL_000c:  br.s       IL_0019
                  IL_000e:  ldloc.0
                  IL_000f:  callvirt   "int C.Enumerator.Current.get"
                  IL_0014:  call       "void System.Console.Write(int)"
                  IL_0019:  ldloc.0
                  IL_001a:  callvirt   "System.Threading.Tasks.Task<bool> C.Enumerator.MoveNextAsync()"
                  IL_001f:  call       "bool System.Runtime.CompilerServices.AsyncHelpers.Await<bool>(System.Threading.Tasks.Task<bool>)"
                  IL_0024:  brtrue.s   IL_000e
                  IL_0026:  ret
                }
                """);
        }
 
        [Fact]
        public void TestGetAsyncEnumeratorPatternViaExtensionWithArgList()
        {
            var source = @"
using System;
using System.Threading.Tasks;
public class C
{
    public static async Task Main()
    {
        await foreach (var i in new C())
        {
            Console.Write(i);
        }
    }
    public sealed class Enumerator
    {
        public int Current { get; private set; }
        public Task<bool> MoveNextAsync() => Task.FromResult(Current++ != 3);
    }
}
public static class Extensions
{
    public static C.Enumerator GetAsyncEnumerator(this C self, __arglist) => new C.Enumerator();
}";
            CreateCompilation(source, parseOptions: TestOptions.Regular9)
                 .VerifyDiagnostics(
                    // (8,33): error CS7036: There is no argument given that corresponds to the required parameter '__arglist' of 'Extensions.GetAsyncEnumerator(C, __arglist)'
                    //         await foreach (var i in new C())
                    Diagnostic(ErrorCode.ERR_NoCorrespondingArgument, "new C()").WithArguments("__arglist", "Extensions.GetAsyncEnumerator(C, __arglist)").WithLocation(8, 33),
                    // (8,33): error CS8411: Asynchronous foreach statement cannot operate on variables of type 'C' because 'C' does not contain a suitable public instance or extension definition for 'GetAsyncEnumerator'
                    //         await foreach (var i in new C())
                    Diagnostic(ErrorCode.ERR_AwaitForEachMissingMember, "new C()").WithArguments("C", "GetAsyncEnumerator").WithLocation(8, 33)
                    );
        }
 
        [Fact]
        public void TestGetAsyncEnumeratorPatternViaExtensionWithParams()
        {
            string source = @"
using System;
using System.Threading.Tasks;
public class C
{
    public static async Task Main()
    {
        await foreach (var i in new C())
        {
            Console.Write(i);
        }
    }
    public sealed class Enumerator
    {
        public Enumerator(int[] arr) => Current = arr.Length;
        public int Current { get; private set; }
        public Task<bool> MoveNextAsync() => Task.FromResult(Current++ != 3);
    }
}
public static class Extensions
{
    public static C.Enumerator GetAsyncEnumerator(this C self, params int[] x) => new C.Enumerator(x);
}";
            var comp = CreateCompilationWithMscorlib46(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular9);
            comp.VerifyDiagnostics();
            CompileAndVerify(comp, expectedOutput: "123");
 
            var runtimeAsyncComp = CreateRuntimeAsyncCompilation(source);
            var verifier = CompileAndVerify(runtimeAsyncComp, expectedOutput: CodeGenAsyncTests.ExpectedOutput("123", isRuntimeAsync: true), verify: Verification.Fails with
            {
                ILVerifyMessage = """
                    [Main]: Return value missing on the stack. { Offset = 0x2a }
                    """
            });
            verifier.VerifyIL("C.Main()", """
                {
                  // Code size       43 (0x2b)
                  .maxstack  2
                  .locals init (C.Enumerator V_0)
                  IL_0000:  newobj     "C..ctor()"
                  IL_0005:  call       "int[] System.Array.Empty<int>()"
                  IL_000a:  call       "C.Enumerator Extensions.GetAsyncEnumerator(C, params int[])"
                  IL_000f:  stloc.0
                  IL_0010:  br.s       IL_001d
                  IL_0012:  ldloc.0
                  IL_0013:  callvirt   "int C.Enumerator.Current.get"
                  IL_0018:  call       "void System.Console.Write(int)"
                  IL_001d:  ldloc.0
                  IL_001e:  callvirt   "System.Threading.Tasks.Task<bool> C.Enumerator.MoveNextAsync()"
                  IL_0023:  call       "bool System.Runtime.CompilerServices.AsyncHelpers.Await<bool>(System.Threading.Tasks.Task<bool>)"
                  IL_0028:  brtrue.s   IL_0012
                  IL_002a:  ret
                }
                """);
        }
 
        [Fact]
        public void TestGetAsyncEnumeratorPatternViaRefExtensionOnNonAssignableVariable()
        {
            string source = @"
using System;
using System.Threading.Tasks;
public struct C
{
    public static async Task Main()
    {
        await foreach (var i in new C())
        {
            Console.Write(i);
        }
    }
    public struct Enumerator
    {
        public int Current { get; private set; }
        public Task<bool> MoveNextAsync() => Task.FromResult(Current++ != 3);
    }
}
public static class Extensions
{
    public static C.Enumerator GetAsyncEnumerator(this ref C self) => new C.Enumerator();
}";
            var comp = CreateCompilationWithMscorlib46(source, parseOptions: TestOptions.Regular9);
            comp.VerifyDiagnostics(
                // (8,33): error CS1510: A ref or out value must be an assignable variable
                //         await foreach (var i in new C())
                Diagnostic(ErrorCode.ERR_RefLvalueExpected, "new C()").WithLocation(8, 33));
        }
 
        [Fact]
        public void TestGetAsyncEnumeratorPatternViaRefExtensionOnAssignableVariable()
        {
            string source = @"
using System;
using System.Threading.Tasks;
public struct C
{
    public static async Task Main()
    {
        var c = new C();
        await foreach (var i in c)
        {
            Console.Write(i);
        }
    }
    public struct Enumerator
    {
        public int Current { get; private set; }
        public Task<bool> MoveNextAsync() => Task.FromResult(Current++ != 3);
    }
}
public static class Extensions
{
    public static C.Enumerator GetAsyncEnumerator(this ref C self) => new C.Enumerator();
}";
            var comp = CreateCompilationWithMscorlib46(source, parseOptions: TestOptions.Regular9);
            comp.VerifyDiagnostics(
                // (9,33): error CS1510: A ref or out value must be an assignable variable
                //         await foreach (var i in c)
                Diagnostic(ErrorCode.ERR_RefLvalueExpected, "c").WithLocation(9, 33)
                );
        }
 
        [Fact]
        public void TestGetAsyncEnumeratorPatternViaOutExtension()
        {
            string source = @"
using System;
using System.Threading.Tasks;
public struct C
{
    public static async Task Main()
    {
        await foreach (var i in new C())
        {
            Console.Write(i);
        }
    }
    public struct Enumerator
    {
        public int Current { get; private set; }
        public Task<bool> MoveNextAsync() => Task.FromResult(Current++ != 3);
    }
}
public static class Extensions
{
    public static C.Enumerator GetAsyncEnumerator(this out C self) => new C.Enumerator();
}";
            var comp = CreateCompilationWithMscorlib46(source, parseOptions: TestOptions.Regular9);
            comp.VerifyDiagnostics(
                // (8,33): error CS1620: Argument 1 must be passed with the 'out' keyword
                //         await foreach (var i in new C())
                Diagnostic(ErrorCode.ERR_BadArgRef, "new C()").WithArguments("1", "out").WithLocation(8, 33),
                // (8,33): error CS8411: Asynchronous foreach statement cannot operate on variables of type 'C' because 'C' does not contain a suitable public instance or extension definition for 'GetAsyncEnumerator'
                //         await foreach (var i in new C())
                Diagnostic(ErrorCode.ERR_AwaitForEachMissingMember, "new C()").WithArguments("C", "GetAsyncEnumerator").WithLocation(8, 33),
                // (21,56): error CS8328:  The parameter modifier 'out' cannot be used with 'this'
                //     public static C.Enumerator GetAsyncEnumerator(this out C self) => new C.Enumerator();
                Diagnostic(ErrorCode.ERR_BadParameterModifiers, "out").WithArguments("out", "this").WithLocation(21, 56));
        }
 
        [Theory]
        [InlineData("in", LanguageVersion.CSharp9)]
        [InlineData("ref readonly", LanguageVersion.Preview)]
        public void TestGetAsyncEnumeratorPatternViaInExtensionOnNonAssignableVariable(string modifier, LanguageVersion languageVersion)
        {
            string source = @"
using System;
using System.Threading.Tasks;
public struct C
{
    public static async Task Main()
    {
        await foreach (var i in new C())
        {
            Console.Write(i);
        }
    }
    public struct Enumerator
    {
        public int Current { get; private set; }
        public Task<bool> MoveNextAsync() => Task.FromResult(Current++ != 3);
    }
}
public static class Extensions
{
    public static C.Enumerator GetAsyncEnumerator(this " + modifier + @" C self) => new C.Enumerator();
}";
            var comp = CreateCompilationWithMscorlib46(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion));
            comp.VerifyDiagnostics();
            CompileAndVerify(comp, expectedOutput: "123");
 
            var runtimeAsyncComp = CreateRuntimeAsyncCompilation(source);
            var verifier = CompileAndVerify(runtimeAsyncComp, expectedOutput: CodeGenAsyncTests.ExpectedOutput("123", isRuntimeAsync: true), verify: Verification.Fails with
            {
                ILVerifyMessage = """
                    [Main]: Return value missing on the stack. { Offset = 0x2b }
                    """
            });
            verifier.VerifyIL("C.Main()", $$"""
                {
                  // Code size       44 (0x2c)
                  .maxstack  2
                  .locals init (C.Enumerator V_0,
                                C V_1)
                  IL_0000:  ldloca.s   V_1
                  IL_0002:  dup
                  IL_0003:  initobj    "C"
                  IL_0009:  call       "C.Enumerator Extensions.GetAsyncEnumerator({{modifier}} C)"
                  IL_000e:  stloc.0
                  IL_000f:  br.s       IL_001d
                  IL_0011:  ldloca.s   V_0
                  IL_0013:  call       "readonly int C.Enumerator.Current.get"
                  IL_0018:  call       "void System.Console.Write(int)"
                  IL_001d:  ldloca.s   V_0
                  IL_001f:  call       "System.Threading.Tasks.Task<bool> C.Enumerator.MoveNextAsync()"
                  IL_0024:  call       "bool System.Runtime.CompilerServices.AsyncHelpers.Await<bool>(System.Threading.Tasks.Task<bool>)"
                  IL_0029:  brtrue.s   IL_0011
                  IL_002b:  ret
                }
                """);
        }
 
        [Theory]
        [InlineData("in", LanguageVersion.CSharp9)]
        [InlineData("ref readonly", LanguageVersion.Preview)]
        public void TestGetAsyncEnumeratorPatternViaInExtensionOnAssignableVariable(string modifier, LanguageVersion languageVersion)
        {
            string source = @"
using System;
using System.Threading.Tasks;
public struct C
{
    public static async Task Main()
    {
        var c = new C();
        await foreach (var i in c)
        {
            Console.Write(i);
        }
    }
    public struct Enumerator
    {
        public int Current { get; private set; }
        public Task<bool> MoveNextAsync() => Task.FromResult(Current++ != 3);
    }
}
public static class Extensions
{
    public static C.Enumerator GetAsyncEnumerator(this " + modifier + @" C self) => new C.Enumerator();
}";
            var comp = CreateCompilationWithMscorlib46(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion));
            comp.VerifyDiagnostics();
            CompileAndVerify(comp, expectedOutput: "123");
 
            var runtimeAsyncComp = CreateRuntimeAsyncCompilation(source);
            var verifier = CompileAndVerify(runtimeAsyncComp, expectedOutput: CodeGenAsyncTests.ExpectedOutput("123", isRuntimeAsync: true), verify: Verification.Fails with
            {
                ILVerifyMessage = """
                    [Main]: Return value missing on the stack. { Offset = 0x2c }
                    """
            });
            verifier.VerifyIL("C.Main()", $$"""
                {
                  // Code size       45 (0x2d)
                  .maxstack  1
                  .locals init (C V_0, //c
                                C.Enumerator V_1)
                  IL_0000:  ldloca.s   V_0
                  IL_0002:  initobj    "C"
                  IL_0008:  ldloca.s   V_0
                  IL_000a:  call       "C.Enumerator Extensions.GetAsyncEnumerator({{modifier}} C)"
                  IL_000f:  stloc.1
                  IL_0010:  br.s       IL_001e
                  IL_0012:  ldloca.s   V_1
                  IL_0014:  call       "readonly int C.Enumerator.Current.get"
                  IL_0019:  call       "void System.Console.Write(int)"
                  IL_001e:  ldloca.s   V_1
                  IL_0020:  call       "System.Threading.Tasks.Task<bool> C.Enumerator.MoveNextAsync()"
                  IL_0025:  call       "bool System.Runtime.CompilerServices.AsyncHelpers.Await<bool>(System.Threading.Tasks.Task<bool>)"
                  IL_002a:  brtrue.s   IL_0012
                  IL_002c:  ret
                }
                """);
        }
 
        [Fact]
        public void TestGetAsyncEnumeratorPatternViaExtensionsCSharp8()
        {
            string source = @"
using System;
using System.Threading.Tasks;
public class C
{
    public static async Task Main()
    {
        await foreach (var i in new C())
        {
            Console.Write(i);
        }
    }
    public sealed class Enumerator
    {
        public int Current { get; private set; }
        public Task<bool> MoveNextAsync() => Task.FromResult(Current++ != 3);
    }
}
public static class Extensions
{
    public static C.Enumerator GetAsyncEnumerator(this C self) => new C.Enumerator();
}";
            var comp = CreateCompilationWithMscorlib46(source, parseOptions: TestOptions.Regular8);
            comp.VerifyDiagnostics(
                // (8,33): error CS8400: Feature 'extension GetAsyncEnumerator' is not available in C# 8.0. Please use language version 9.0 or greater.
                //         await foreach (var i in new C())
                Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion8, "new C()").WithArguments("extension GetAsyncEnumerator", "9.0").WithLocation(8, 33)
                );
        }
 
        [Fact]
        public void TestGetAsyncEnumeratorPatternViaInternalExtensions()
        {
            string source = @"
using System;
using System.Threading.Tasks;
public class C
{
    public static async Task Main()
    {
        await foreach (var i in new C())
        {
            Console.Write(i);
        }
    }
    public sealed class Enumerator
    {
        public int Current { get; private set; }
        public Task<bool> MoveNextAsync() => Task.FromResult(Current++ != 3);
    }
}
public static class Extensions
{
    internal static C.Enumerator GetAsyncEnumerator(this C self) => new C.Enumerator();
}";
            var comp = CreateCompilationWithMscorlib46(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular9);
            comp.VerifyDiagnostics();
            CompileAndVerify(comp, expectedOutput: "123");
 
            var runtimeAsyncComp = CreateRuntimeAsyncCompilation(source);
            var verifier = CompileAndVerify(runtimeAsyncComp, expectedOutput: CodeGenAsyncTests.ExpectedOutput("123", isRuntimeAsync: true), verify: Verification.Fails with
            {
                ILVerifyMessage = """
                    [Main]: Return value missing on the stack. { Offset = 0x25 }
                    """
            });
            verifier.VerifyIL("C.Main()", """
                {
                  // Code size       38 (0x26)
                  .maxstack  1
                  .locals init (C.Enumerator V_0)
                  IL_0000:  newobj     "C..ctor()"
                  IL_0005:  call       "C.Enumerator Extensions.GetAsyncEnumerator(C)"
                  IL_000a:  stloc.0
                  IL_000b:  br.s       IL_0018
                  IL_000d:  ldloc.0
                  IL_000e:  callvirt   "int C.Enumerator.Current.get"
                  IL_0013:  call       "void System.Console.Write(int)"
                  IL_0018:  ldloc.0
                  IL_0019:  callvirt   "System.Threading.Tasks.Task<bool> C.Enumerator.MoveNextAsync()"
                  IL_001e:  call       "bool System.Runtime.CompilerServices.AsyncHelpers.Await<bool>(System.Threading.Tasks.Task<bool>)"
                  IL_0023:  brtrue.s   IL_000d
                  IL_0025:  ret
                }
                """);
        }
 
        [Fact]
        public void TestGetAsyncEnumeratorPatternViaExtensionInInternalClass()
        {
            string source = @"
using System;
using System.Threading.Tasks;
public class C
{
    public static async Task Main()
    {
        await foreach (var i in new C())
        {
            Console.Write(i);
        }
    }
    public sealed class Enumerator
    {
        public int Current { get; private set; }
        public Task<bool> MoveNextAsync() => Task.FromResult(Current++ != 3);
    }
}
internal static class Extensions
{
    public static C.Enumerator GetAsyncEnumerator(this C self) => new C.Enumerator();
}";
            var comp = CreateCompilationWithMscorlib46(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular9);
            comp.VerifyDiagnostics();
            CompileAndVerify(comp, expectedOutput: "123");
 
            var runtimeAsyncComp = CreateRuntimeAsyncCompilation(source);
            var verifier = CompileAndVerify(runtimeAsyncComp, expectedOutput: CodeGenAsyncTests.ExpectedOutput("123", isRuntimeAsync: true), verify: Verification.Fails with
            {
                ILVerifyMessage = """
                    [Main]: Return value missing on the stack. { Offset = 0x25 }
                    """
            });
            verifier.VerifyIL("C.Main()", """
                {
                  // Code size       38 (0x26)
                  .maxstack  1
                  .locals init (C.Enumerator V_0)
                  IL_0000:  newobj     "C..ctor()"
                  IL_0005:  call       "C.Enumerator Extensions.GetAsyncEnumerator(C)"
                  IL_000a:  stloc.0
                  IL_000b:  br.s       IL_0018
                  IL_000d:  ldloc.0
                  IL_000e:  callvirt   "int C.Enumerator.Current.get"
                  IL_0013:  call       "void System.Console.Write(int)"
                  IL_0018:  ldloc.0
                  IL_0019:  callvirt   "System.Threading.Tasks.Task<bool> C.Enumerator.MoveNextAsync()"
                  IL_001e:  call       "bool System.Runtime.CompilerServices.AsyncHelpers.Await<bool>(System.Threading.Tasks.Task<bool>)"
                  IL_0023:  brtrue.s   IL_000d
                  IL_0025:  ret
                }
                """);
        }
 
        [Fact]
        public void TestGetAsyncEnumeratorPatternViaExtensionWithInvalidEnumerator()
        {
            var source = @"
using System;
using System.Threading.Tasks;
public class C
{
    public static async Task Main()
    {
        await foreach (var i in new C())
        {
            Console.Write(i);
        }
    }
    public sealed class Enumerator
    {
        public int Current { get; private set; }
    }
}
internal static class Extensions
{
    public static C.Enumerator GetAsyncEnumerator(this C self) => new C.Enumerator();
}";
            CreateCompilation(source, parseOptions: TestOptions.Regular9)
                .VerifyDiagnostics(
                    // (8,33): error CS0117: 'C.Enumerator' does not contain a definition for 'MoveNextAsync'
                    //         await foreach (var i in new C())
                    Diagnostic(ErrorCode.ERR_NoSuchMember, "new C()").WithArguments("C.Enumerator", "MoveNextAsync").WithLocation(8, 33),
                    // (8,33): error CS8412: Asynchronous foreach requires that the return type 'C.Enumerator' of 'Extensions.GetAsyncEnumerator(C)' must have a suitable public 'MoveNextAsync' method and public 'Current' property
                    //         await foreach (var i in new C())
                    Diagnostic(ErrorCode.ERR_BadGetAsyncEnumerator, "new C()").WithArguments("C.Enumerator", "Extensions.GetAsyncEnumerator(C)").WithLocation(8, 33)
                    );
        }
 
        [Fact]
        public void TestGetAsyncEnumeratorPatternViaExtensionWithInstanceGetAsyncEnumeratorReturningTypeWhichDoesntMatchPattern()
        {
            var source = @"
using System;
using System.Threading.Tasks;
public class C
{
    public static async Task Main()
    {
        await foreach (var i in new C())
        {
            Console.Write(i);
        }
    }
 
    public sealed class Enumerator1
    {
        public int Current { get; private set; }
    }
 
    public sealed class Enumerator2
    {
        public int Current { get; private set; }
        public Task<bool> MoveNextAsync() => Task.FromResult(Current++ != 3);
    }
 
    public Enumerator1 GetAsyncEnumerator() => new Enumerator1();
}
internal static class Extensions
{
    public static C.Enumerator2 GetAsyncEnumerator(this C self) => new C.Enumerator2();
}";
            CreateCompilation(source, parseOptions: TestOptions.Regular9)
                .VerifyDiagnostics(
                    // (8,33): error CS0117: 'C.Enumerator1' does not contain a definition for 'MoveNextAsync'
                    //         await foreach (var i in new C())
                    Diagnostic(ErrorCode.ERR_NoSuchMember, "new C()").WithArguments("C.Enumerator1", "MoveNextAsync").WithLocation(8, 33),
                    // (8,33): error CS8412: Asynchronous foreach requires that the return type 'C.Enumerator1' of 'C.GetAsyncEnumerator()' must have a suitable public 'MoveNextAsync' method and public 'Current' property
                    //         await foreach (var i in new C())
                    Diagnostic(ErrorCode.ERR_BadGetAsyncEnumerator, "new C()").WithArguments("C.Enumerator1", "C.GetAsyncEnumerator()").WithLocation(8, 33)
                );
        }
 
        [Fact]
        public void TestGetAsyncEnumeratorPatternViaExtensionWithInternalInstanceGetAsyncEnumerator()
        {
            var source = @"
using System;
using System.Threading.Tasks;
public class C
{
    public static async Task Main()
    {
        await foreach (var i in new C())
        {
            Console.Write(i);
        }
    }
 
    public sealed class Enumerator
    {
        public int Current { get; private set; }
        public Task<bool> MoveNextAsync() => Task.FromResult(Current++ != 3);
    }
 
    internal Enumerator GetAsyncEnumerator() => throw null;
}
internal static class Extensions
{
    public static C.Enumerator GetAsyncEnumerator(this C self) => new C.Enumerator();
}";
            var comp = CreateCompilationWithMscorlib46(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular9);
            comp.VerifyDiagnostics(
                // (8,33): warning CS0279: 'C' does not implement the 'async streams' pattern. 'C.GetAsyncEnumerator()' is not a public instance or extension method.
                //         await foreach (var i in new C())
                Diagnostic(ErrorCode.WRN_PatternNotPublicOrNotInstance, "new C()").WithArguments("C", "async streams", "C.GetAsyncEnumerator()").WithLocation(8, 33)
                );
            CompileAndVerify(comp, expectedOutput: "123");
        }
 
        [Fact]
        public void TestGetAsyncEnumeratorPatternViaExtensionWithInstanceGetAsyncEnumeratorWithTooManyParameters()
        {
            var source = @"
using System;
using System.Threading.Tasks;
public class C
{
    public static async Task Main()
    {
        await foreach (var i in new C())
        {
            Console.Write(i);
        }
    }
 
    public sealed class Enumerator
    {
        public int Current { get; private set; }
        public Task<bool> MoveNextAsync() => Task.FromResult(Current++ != 3);
    }
 
    internal Enumerator GetAsyncEnumerator(int a) => throw null;
}
internal static class Extensions
{
    public static C.Enumerator GetAsyncEnumerator(this C self) => new C.Enumerator();
}";
            var comp = CreateCompilationWithMscorlib46(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular9);
            comp.VerifyDiagnostics();
            CompileAndVerify(comp, expectedOutput: "123");
 
            var runtimeAsyncComp = CreateRuntimeAsyncCompilation(source);
            var verifier = CompileAndVerify(runtimeAsyncComp, expectedOutput: CodeGenAsyncTests.ExpectedOutput("123", isRuntimeAsync: true), verify: Verification.Fails with
            {
                ILVerifyMessage = """
                    [Main]: Return value missing on the stack. { Offset = 0x25 }
                    """
            });
            verifier.VerifyIL("C.Main()", """
                {
                  // Code size       38 (0x26)
                  .maxstack  1
                  .locals init (C.Enumerator V_0)
                  IL_0000:  newobj     "C..ctor()"
                  IL_0005:  call       "C.Enumerator Extensions.GetAsyncEnumerator(C)"
                  IL_000a:  stloc.0
                  IL_000b:  br.s       IL_0018
                  IL_000d:  ldloc.0
                  IL_000e:  callvirt   "int C.Enumerator.Current.get"
                  IL_0013:  call       "void System.Console.Write(int)"
                  IL_0018:  ldloc.0
                  IL_0019:  callvirt   "System.Threading.Tasks.Task<bool> C.Enumerator.MoveNextAsync()"
                  IL_001e:  call       "bool System.Runtime.CompilerServices.AsyncHelpers.Await<bool>(System.Threading.Tasks.Task<bool>)"
                  IL_0023:  brtrue.s   IL_000d
                  IL_0025:  ret
                }
                """);
        }
 
        [Fact]
        public void TestGetAsyncEnumeratorPatternViaExtensionWithStaticGetAsyncEnumeratorDeclaredInType()
        {
            var source = @"
using System;
using System.Threading.Tasks;
public class C
{
    public static async Task Main()
    {
        await foreach (var i in new C())
        {
            Console.Write(i);
        }
    }
 
    public sealed class Enumerator
    {
        public int Current { get; private set; }
        public Task<bool> MoveNextAsync() => Task.FromResult(Current++ != 3);
    }
 
    public static Enumerator GetAsyncEnumerator() => throw null;
}
internal static class Extensions
{
    public static C.Enumerator GetAsyncEnumerator(this C self) => new C.Enumerator();
}";
            var comp = CreateCompilationWithMscorlib46(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular9);
            comp.VerifyDiagnostics();
            CompileAndVerify(comp, expectedOutput: "123");
 
            var runtimeAsyncComp = CreateRuntimeAsyncCompilation(source);
            var verifier = CompileAndVerify(runtimeAsyncComp, expectedOutput: CodeGenAsyncTests.ExpectedOutput("123", isRuntimeAsync: true), verify: Verification.Fails with
            {
                ILVerifyMessage = """
                    [Main]: Return value missing on the stack. { Offset = 0x25 }
                    """
            });
            verifier.VerifyIL("C.Main()", """
                {
                  // Code size       38 (0x26)
                  .maxstack  1
                  .locals init (C.Enumerator V_0)
                  IL_0000:  newobj     "C..ctor()"
                  IL_0005:  call       "C.Enumerator Extensions.GetAsyncEnumerator(C)"
                  IL_000a:  stloc.0
                  IL_000b:  br.s       IL_0018
                  IL_000d:  ldloc.0
                  IL_000e:  callvirt   "int C.Enumerator.Current.get"
                  IL_0013:  call       "void System.Console.Write(int)"
                  IL_0018:  ldloc.0
                  IL_0019:  callvirt   "System.Threading.Tasks.Task<bool> C.Enumerator.MoveNextAsync()"
                  IL_001e:  call       "bool System.Runtime.CompilerServices.AsyncHelpers.Await<bool>(System.Threading.Tasks.Task<bool>)"
                  IL_0023:  brtrue.s   IL_000d
                  IL_0025:  ret
                }
                """);
        }
 
        [Fact]
        public void TestAwaitForEachViaExtensionImplicitImplementationOfIAsyncDisposableStruct()
        {
            var source = @"
using System;
using System.Threading.Tasks;
class C
{
    static async Task Main()
    {
        await foreach (var x in new C())
        {
            Console.Write(x);
        }
    }
}
 
static class Extensions
{
    public static Enumerator GetAsyncEnumerator(this C _) => new Enumerator();
}
 
struct Enumerator : IAsyncDisposable
{
    public int Current { get; private set; }
    public Task<bool> MoveNextAsync() => Task.FromResult(Current++ != 3);
    public ValueTask DisposeAsync() { Console.Write(""Disposed""); return new ValueTask(); }
}";
            var comp = CreateCompilationWithTasksExtensions(new[] { source, s_IAsyncEnumerable }, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular9);
            comp.VerifyDiagnostics();
            CompileAndVerify(comp, expectedOutput: @"123Disposed");
 
            var runtimeAsyncComp = CreateRuntimeAsyncCompilation(source);
            var verifier = CompileAndVerify(runtimeAsyncComp, expectedOutput: CodeGenAsyncTests.ExpectedOutput("123Disposed", isRuntimeAsync: true), verify: Verification.Fails with
            {
                ILVerifyMessage = """
                    [Main]: Return value missing on the stack. { Offset = 0x52 }
                    """
            });
            verifier.VerifyIL("C.Main()", """
                {
                  // Code size       83 (0x53)
                  .maxstack  2
                  .locals init (Enumerator V_0,
                                object V_1)
                  IL_0000:  newobj     "C..ctor()"
                  IL_0005:  call       "Enumerator Extensions.GetAsyncEnumerator(C)"
                  IL_000a:  stloc.0
                  IL_000b:  ldnull
                  IL_000c:  stloc.1
                  .try
                  {
                    IL_000d:  br.s       IL_001b
                    IL_000f:  ldloca.s   V_0
                    IL_0011:  call       "readonly int Enumerator.Current.get"
                    IL_0016:  call       "void System.Console.Write(int)"
                    IL_001b:  ldloca.s   V_0
                    IL_001d:  call       "System.Threading.Tasks.Task<bool> Enumerator.MoveNextAsync()"
                    IL_0022:  call       "bool System.Runtime.CompilerServices.AsyncHelpers.Await<bool>(System.Threading.Tasks.Task<bool>)"
                    IL_0027:  brtrue.s   IL_000f
                    IL_0029:  leave.s    IL_002e
                  }
                  catch object
                  {
                    IL_002b:  stloc.1
                    IL_002c:  leave.s    IL_002e
                  }
                  IL_002e:  ldloca.s   V_0
                  IL_0030:  call       "System.Threading.Tasks.ValueTask Enumerator.DisposeAsync()"
                  IL_0035:  call       "void System.Runtime.CompilerServices.AsyncHelpers.Await(System.Threading.Tasks.ValueTask)"
                  IL_003a:  ldloc.1
                  IL_003b:  brfalse.s  IL_0052
                  IL_003d:  ldloc.1
                  IL_003e:  isinst     "System.Exception"
                  IL_0043:  dup
                  IL_0044:  brtrue.s   IL_0048
                  IL_0046:  ldloc.1
                  IL_0047:  throw
                  IL_0048:  call       "System.Runtime.ExceptionServices.ExceptionDispatchInfo System.Runtime.ExceptionServices.ExceptionDispatchInfo.Capture(System.Exception)"
                  IL_004d:  callvirt   "void System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()"
                  IL_0052:  ret
                }
                """);
        }
 
        [Fact]
        public void TestAwaitForEachViaExtensionExplicitlyDisposableStruct()
        {
            var source = @"
using System;
using System.Threading.Tasks;
class C
{
    static async Task Main()
    {
        await foreach (var x in new C())
        {
            Console.Write(x);
        }
    }
}
 
static class Extensions
{
    public static Enumerator GetAsyncEnumerator(this C _) => new Enumerator();
}
 
struct Enumerator : IAsyncDisposable
{
    public int Current { get; private set; }
    public Task<bool> MoveNextAsync() => Task.FromResult(Current++ != 3);
    ValueTask IAsyncDisposable.DisposeAsync() { Console.Write(""Disposed""); return new ValueTask(); }
}";
 
            var comp = CreateCompilationWithTasksExtensions(new[] { source, s_IAsyncEnumerable }, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular9);
            comp.VerifyDiagnostics();
            CompileAndVerify(comp, expectedOutput: @"123Disposed");
 
            var runtimeAsyncComp = CreateRuntimeAsyncCompilation(source);
            var verifier = CompileAndVerify(runtimeAsyncComp, expectedOutput: CodeGenAsyncTests.ExpectedOutput("123Disposed", isRuntimeAsync: true), verify: Verification.Fails with
            {
                ILVerifyMessage = """
                    [Main]: Return value missing on the stack. { Offset = 0x58 }
                    """
            });
            verifier.VerifyIL("C.Main()", """
                {
                  // Code size       89 (0x59)
                  .maxstack  2
                  .locals init (Enumerator V_0,
                                object V_1)
                  IL_0000:  newobj     "C..ctor()"
                  IL_0005:  call       "Enumerator Extensions.GetAsyncEnumerator(C)"
                  IL_000a:  stloc.0
                  IL_000b:  ldnull
                  IL_000c:  stloc.1
                  .try
                  {
                    IL_000d:  br.s       IL_001b
                    IL_000f:  ldloca.s   V_0
                    IL_0011:  call       "readonly int Enumerator.Current.get"
                    IL_0016:  call       "void System.Console.Write(int)"
                    IL_001b:  ldloca.s   V_0
                    IL_001d:  call       "System.Threading.Tasks.Task<bool> Enumerator.MoveNextAsync()"
                    IL_0022:  call       "bool System.Runtime.CompilerServices.AsyncHelpers.Await<bool>(System.Threading.Tasks.Task<bool>)"
                    IL_0027:  brtrue.s   IL_000f
                    IL_0029:  leave.s    IL_002e
                  }
                  catch object
                  {
                    IL_002b:  stloc.1
                    IL_002c:  leave.s    IL_002e
                  }
                  IL_002e:  ldloca.s   V_0
                  IL_0030:  constrained. "Enumerator"
                  IL_0036:  callvirt   "System.Threading.Tasks.ValueTask System.IAsyncDisposable.DisposeAsync()"
                  IL_003b:  call       "void System.Runtime.CompilerServices.AsyncHelpers.Await(System.Threading.Tasks.ValueTask)"
                  IL_0040:  ldloc.1
                  IL_0041:  brfalse.s  IL_0058
                  IL_0043:  ldloc.1
                  IL_0044:  isinst     "System.Exception"
                  IL_0049:  dup
                  IL_004a:  brtrue.s   IL_004e
                  IL_004c:  ldloc.1
                  IL_004d:  throw
                  IL_004e:  call       "System.Runtime.ExceptionServices.ExceptionDispatchInfo System.Runtime.ExceptionServices.ExceptionDispatchInfo.Capture(System.Exception)"
                  IL_0053:  callvirt   "void System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()"
                  IL_0058:  ret
                }
                """);
        }
 
        [Fact]
        public void TestAwaitForEachViaExtensionAsyncDisposeStruct()
        {
            var source = @"
using System;
using System.Threading.Tasks;
class C
{
    static async Task Main()
    {
        await foreach (var x in new C())
        {
            Console.Write(x);
        }
    }
}
 
static class Extensions
{
    public static Enumerator GetAsyncEnumerator(this C _) => new Enumerator();
}
 
struct Enumerator
{
    public int Current { get; private set; }
    public Task<bool> MoveNextAsync() => Task.FromResult(Current++ != 3);
    public ValueTask DisposeAsync() { Console.Write(""Disposed""); return new ValueTask(); }
}";
            var comp = CreateCompilationWithTasksExtensions(new[] { source, s_IAsyncEnumerable }, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular9);
            comp.VerifyDiagnostics();
            CompileAndVerify(comp, expectedOutput: @"123Disposed");
 
            var runtimeAsyncComp = CreateRuntimeAsyncCompilation(source);
            var verifier = CompileAndVerify(runtimeAsyncComp, expectedOutput: CodeGenAsyncTests.ExpectedOutput("123Disposed", isRuntimeAsync: true), verify: Verification.Fails with
            {
                ILVerifyMessage = """
                    [Main]: Return value missing on the stack. { Offset = 0x52 }
                    """
            });
            verifier.VerifyIL("C.Main()", """
                {
                  // Code size       83 (0x53)
                  .maxstack  2
                  .locals init (Enumerator V_0,
                                object V_1)
                  IL_0000:  newobj     "C..ctor()"
                  IL_0005:  call       "Enumerator Extensions.GetAsyncEnumerator(C)"
                  IL_000a:  stloc.0
                  IL_000b:  ldnull
                  IL_000c:  stloc.1
                  .try
                  {
                    IL_000d:  br.s       IL_001b
                    IL_000f:  ldloca.s   V_0
                    IL_0011:  call       "readonly int Enumerator.Current.get"
                    IL_0016:  call       "void System.Console.Write(int)"
                    IL_001b:  ldloca.s   V_0
                    IL_001d:  call       "System.Threading.Tasks.Task<bool> Enumerator.MoveNextAsync()"
                    IL_0022:  call       "bool System.Runtime.CompilerServices.AsyncHelpers.Await<bool>(System.Threading.Tasks.Task<bool>)"
                    IL_0027:  brtrue.s   IL_000f
                    IL_0029:  leave.s    IL_002e
                  }
                  catch object
                  {
                    IL_002b:  stloc.1
                    IL_002c:  leave.s    IL_002e
                  }
                  IL_002e:  ldloca.s   V_0
                  IL_0030:  call       "System.Threading.Tasks.ValueTask Enumerator.DisposeAsync()"
                  IL_0035:  call       "void System.Runtime.CompilerServices.AsyncHelpers.Await(System.Threading.Tasks.ValueTask)"
                  IL_003a:  ldloc.1
                  IL_003b:  brfalse.s  IL_0052
                  IL_003d:  ldloc.1
                  IL_003e:  isinst     "System.Exception"
                  IL_0043:  dup
                  IL_0044:  brtrue.s   IL_0048
                  IL_0046:  ldloc.1
                  IL_0047:  throw
                  IL_0048:  call       "System.Runtime.ExceptionServices.ExceptionDispatchInfo System.Runtime.ExceptionServices.ExceptionDispatchInfo.Capture(System.Exception)"
                  IL_004d:  callvirt   "void System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()"
                  IL_0052:  ret
                }
                """);
        }
 
        [Fact]
        public void TestGetAsyncEnumeratorPatternViaExtensionsWithTaskLikeTypeMoveNext()
        {
            string source = @"
using System;
using System.Threading.Tasks;
public class C
{
    public static async Task Main()
    {
        await foreach (var i in new C())
        {
            Console.Write(i);
        }
    }
    public sealed class Enumerator
    {
        public int Current { get; private set; }
        public ValueTask<bool> MoveNextAsync() => new ValueTask<bool>(Current++ != 3);
    }
}
public static class Extensions
{
    public static C.Enumerator GetAsyncEnumerator(this C self) => new C.Enumerator();
}";
            var comp = CreateCompilationWithTasksExtensions(new[] { source, s_IAsyncEnumerable }, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular9);
            comp.VerifyDiagnostics();
            CompileAndVerify(comp, expectedOutput: "123");
 
            var runtimeAsyncComp = CreateRuntimeAsyncCompilation(source);
            var verifier = CompileAndVerify(runtimeAsyncComp, expectedOutput: CodeGenAsyncTests.ExpectedOutput("123", isRuntimeAsync: true), verify: Verification.Fails with
            {
                ILVerifyMessage = """
                    [Main]: Return value missing on the stack. { Offset = 0x25 }
                    """
            });
            verifier.VerifyIL("C.Main()", """
                {
                  // Code size       38 (0x26)
                  .maxstack  1
                  .locals init (C.Enumerator V_0)
                  IL_0000:  newobj     "C..ctor()"
                  IL_0005:  call       "C.Enumerator Extensions.GetAsyncEnumerator(C)"
                  IL_000a:  stloc.0
                  IL_000b:  br.s       IL_0018
                  IL_000d:  ldloc.0
                  IL_000e:  callvirt   "int C.Enumerator.Current.get"
                  IL_0013:  call       "void System.Console.Write(int)"
                  IL_0018:  ldloc.0
                  IL_0019:  callvirt   "System.Threading.Tasks.ValueTask<bool> C.Enumerator.MoveNextAsync()"
                  IL_001e:  call       "bool System.Runtime.CompilerServices.AsyncHelpers.Await<bool>(System.Threading.Tasks.ValueTask<bool>)"
                  IL_0023:  brtrue.s   IL_000d
                  IL_0025:  ret
                }
                """);
        }
 
        [Fact]
        public void TestWithObsoletePatternMethodsViaExtension()
        {
            string source = @"
using System;
using System.Threading.Tasks;
public class C
{
    public static async Task Main()
    {
        await foreach (var i in new C())
        {
            Console.Write(i);
        }
    }
    public sealed class Enumerator
    {
        [Obsolete]
        public int Current { get; private set; }
        [Obsolete]
        public Task<bool> MoveNextAsync() => Task.FromResult(Current++ != 3);
        [Obsolete]
        public Task DisposeAsync() { Console.Write(""Disposed""); return Task.CompletedTask; }
    }
}
[Obsolete]
public static class Extensions
{
    [Obsolete]
    public static C.Enumerator GetAsyncEnumerator(this C self) => new C.Enumerator();
}";
            var comp = CreateCompilationWithMscorlib46(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular9);
            comp.VerifyDiagnostics(
                // (8,15): warning CS0612: 'C.Enumerator.DisposeAsync()' is obsolete
                //         await foreach (var i in new C())
                Diagnostic(ErrorCode.WRN_DeprecatedSymbol, "foreach").WithArguments("C.Enumerator.DisposeAsync()").WithLocation(8, 15),
                // (8,15): warning CS0612: 'Extensions.GetAsyncEnumerator(C)' is obsolete
                //         await foreach (var i in new C())
                Diagnostic(ErrorCode.WRN_DeprecatedSymbol, "foreach").WithArguments("Extensions.GetAsyncEnumerator(C)").WithLocation(8, 15),
                // (8,15): warning CS0612: 'C.Enumerator.MoveNextAsync()' is obsolete
                //         await foreach (var i in new C())
                Diagnostic(ErrorCode.WRN_DeprecatedSymbol, "foreach").WithArguments("C.Enumerator.MoveNextAsync()").WithLocation(8, 15),
                // (8,15): warning CS0612: 'C.Enumerator.Current' is obsolete
                //         await foreach (var i in new C())
                Diagnostic(ErrorCode.WRN_DeprecatedSymbol, "foreach").WithArguments("C.Enumerator.Current").WithLocation(8, 15)
                );
            CompileAndVerify(comp, expectedOutput: "123Disposed");
 
            var runtimeAsyncComp = CreateRuntimeAsyncCompilation(source);
            var verifier = CompileAndVerify(runtimeAsyncComp, expectedOutput: CodeGenAsyncTests.ExpectedOutput("123Disposed", isRuntimeAsync: true), verify: Verification.Fails with
            {
                ILVerifyMessage = """
                    [Main]: Return value missing on the stack. { Offset = 0x52 }
                    """
            });
            verifier.VerifyIL("C.Main()", """
                {
                  // Code size       83 (0x53)
                  .maxstack  2
                  .locals init (C.Enumerator V_0,
                                object V_1)
                  IL_0000:  newobj     "C..ctor()"
                  IL_0005:  call       "C.Enumerator Extensions.GetAsyncEnumerator(C)"
                  IL_000a:  stloc.0
                  IL_000b:  ldnull
                  IL_000c:  stloc.1
                  .try
                  {
                    IL_000d:  br.s       IL_001a
                    IL_000f:  ldloc.0
                    IL_0010:  callvirt   "int C.Enumerator.Current.get"
                    IL_0015:  call       "void System.Console.Write(int)"
                    IL_001a:  ldloc.0
                    IL_001b:  callvirt   "System.Threading.Tasks.Task<bool> C.Enumerator.MoveNextAsync()"
                    IL_0020:  call       "bool System.Runtime.CompilerServices.AsyncHelpers.Await<bool>(System.Threading.Tasks.Task<bool>)"
                    IL_0025:  brtrue.s   IL_000f
                    IL_0027:  leave.s    IL_002c
                  }
                  catch object
                  {
                    IL_0029:  stloc.1
                    IL_002a:  leave.s    IL_002c
                  }
                  IL_002c:  ldloc.0
                  IL_002d:  brfalse.s  IL_003a
                  IL_002f:  ldloc.0
                  IL_0030:  callvirt   "System.Threading.Tasks.Task C.Enumerator.DisposeAsync()"
                  IL_0035:  call       "void System.Runtime.CompilerServices.AsyncHelpers.Await(System.Threading.Tasks.Task)"
                  IL_003a:  ldloc.1
                  IL_003b:  brfalse.s  IL_0052
                  IL_003d:  ldloc.1
                  IL_003e:  isinst     "System.Exception"
                  IL_0043:  dup
                  IL_0044:  brtrue.s   IL_0048
                  IL_0046:  ldloc.1
                  IL_0047:  throw
                  IL_0048:  call       "System.Runtime.ExceptionServices.ExceptionDispatchInfo System.Runtime.ExceptionServices.ExceptionDispatchInfo.Capture(System.Exception)"
                  IL_004d:  callvirt   "void System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()"
                  IL_0052:  ret
                }
                """);
        }
 
        [Fact]
        public void TestGetAsyncEnumeratorPatternViaImportedExtensions()
        {
            string source = @"
using System;
using System.Threading.Tasks;
using N;
public class C
{
    public static async Task Main()
    {
        await foreach (var i in new C())
        {
            Console.Write(i);
        }
    }
    public sealed class Enumerator
    {
        public int Current { get; private set; }
        public Task<bool> MoveNextAsync() => Task.FromResult(Current++ != 3);
    }
}
namespace N
{
    public static class Extensions
    {
        public static C.Enumerator GetAsyncEnumerator(this C self) => new C.Enumerator();
    }
}";
            var comp = CreateCompilationWithMscorlib46(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular9);
            comp.VerifyDiagnostics();
            CompileAndVerify(comp, expectedOutput: "123");
 
            var runtimeAsyncComp = CreateRuntimeAsyncCompilation(source);
            var verifier = CompileAndVerify(runtimeAsyncComp, expectedOutput: CodeGenAsyncTests.ExpectedOutput("123", isRuntimeAsync: true), verify: Verification.Fails with
            {
                ILVerifyMessage = """
                    [Main]: Return value missing on the stack. { Offset = 0x25 }
                    """
            });
            verifier.VerifyIL("C.Main()", """
                {
                  // Code size       38 (0x26)
                  .maxstack  1
                  .locals init (C.Enumerator V_0)
                  IL_0000:  newobj     "C..ctor()"
                  IL_0005:  call       "C.Enumerator N.Extensions.GetAsyncEnumerator(C)"
                  IL_000a:  stloc.0
                  IL_000b:  br.s       IL_0018
                  IL_000d:  ldloc.0
                  IL_000e:  callvirt   "int C.Enumerator.Current.get"
                  IL_0013:  call       "void System.Console.Write(int)"
                  IL_0018:  ldloc.0
                  IL_0019:  callvirt   "System.Threading.Tasks.Task<bool> C.Enumerator.MoveNextAsync()"
                  IL_001e:  call       "bool System.Runtime.CompilerServices.AsyncHelpers.Await<bool>(System.Threading.Tasks.Task<bool>)"
                  IL_0023:  brtrue.s   IL_000d
                  IL_0025:  ret
                }
                """);
        }
 
        [Fact]
        public void TestGetAsyncEnumeratorPatternViaUnimportedExtensions()
        {
            string source = @"
using System;
using System.Threading.Tasks;
public class C
{
    public static async Task Main()
    {
        await foreach (var i in new C())
        {
            Console.Write(i);
        }
    }
    public sealed class Enumerator
    {
        public int Current { get; private set; }
        public Task<bool> MoveNextAsync() => Task.FromResult(Current++ != 3);
    }
}
namespace N
{
    public static class Extensions
    {
        public static C.Enumerator GetAsyncEnumerator(this C self) => new C.Enumerator();
    }
}";
            CreateCompilationWithMscorlib46(source, parseOptions: TestOptions.Regular9)
                .VerifyDiagnostics(
                    // (8,33): error CS8411: Asynchronous foreach statement cannot operate on variables of type 'C' because 'C' does not contain a suitable public instance or extension definition for 'GetAsyncEnumerator'
                    //         await foreach (var i in new C())
                    Diagnostic(ErrorCode.ERR_AwaitForEachMissingMember, "new C()").WithArguments("C", "GetAsyncEnumerator").WithLocation(8, 33)
                    );
        }
 
        [Fact]
        public void TestWithPatternGetAsyncEnumeratorViaExtensionOnUnassignedCollection()
        {
            string source = @"
using System;
using System.Threading.Tasks;
public class C
{
    public static async Task Main()
    {
        C c;
        await foreach (var i in c)
        {
            Console.Write(i);
        }
    }
    public sealed class Enumerator
    {
        public int Current { get; private set; }
        public Task<bool> MoveNextAsync() => Task.FromResult(Current++ != 3);
    }
}
public static class Extensions
{
    public static C.Enumerator GetAsyncEnumerator(this C self) => new C.Enumerator();
}";
            var comp = CreateCompilationWithMscorlib46(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular9);
            comp.VerifyDiagnostics(
                // (9,33): error CS0165: Use of unassigned local variable 'c'
                //         await foreach (var i in c)
                Diagnostic(ErrorCode.ERR_UseDefViolation, "c").WithArguments("c").WithLocation(9, 33)
                );
        }
 
        [Fact]
        public void TestGetAsyncEnumeratorPatternViaValidExtensionInClosestNamespaceInvalidInFurtherNamespace1()
        {
            var source = @"
using System;
using System.Threading.Tasks;
using N1.N2.N3;
 
namespace N1
{
    public static class Extensions
    {
        public static int GetAsyncEnumerator(this C self) => throw null;
    }
 
    namespace N2
    {
        public static class Extensions
        {
            public static C.Enumerator GetAsyncEnumerator(this C self) => new C.Enumerator();
        }
 
        namespace N3
        {
            using N2;
            public class C
            {
                public static async Task Main()
                {
                    await foreach (var i in new C())
                    {
                        Console.Write(i);
                    }
                }
                public sealed class Enumerator
                {
                    public int Current { get; private set; }
                    public Task<bool> MoveNextAsync() => Task.FromResult(Current++ != 3);
                }
            }
        }
    }
}";
            var comp = CreateCompilationWithMscorlib46(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular9);
            comp.VerifyDiagnostics();
            CompileAndVerify(comp, expectedOutput: "123");
 
            var runtimeAsyncComp = CreateRuntimeAsyncCompilation(source);
            var verifier = CompileAndVerify(runtimeAsyncComp, expectedOutput: CodeGenAsyncTests.ExpectedOutput("123", isRuntimeAsync: true), verify: Verification.Fails with
            {
                ILVerifyMessage = """
                    [Main]: Return value missing on the stack. { Offset = 0x25 }
                    """
            });
            verifier.VerifyIL("N1.N2.N3.C.Main()", """
                {
                  // Code size       38 (0x26)
                  .maxstack  1
                  .locals init (N1.N2.N3.C.Enumerator V_0)
                  IL_0000:  newobj     "N1.N2.N3.C..ctor()"
                  IL_0005:  call       "N1.N2.N3.C.Enumerator N1.N2.Extensions.GetAsyncEnumerator(N1.N2.N3.C)"
                  IL_000a:  stloc.0
                  IL_000b:  br.s       IL_0018
                  IL_000d:  ldloc.0
                  IL_000e:  callvirt   "int N1.N2.N3.C.Enumerator.Current.get"
                  IL_0013:  call       "void System.Console.Write(int)"
                  IL_0018:  ldloc.0
                  IL_0019:  callvirt   "System.Threading.Tasks.Task<bool> N1.N2.N3.C.Enumerator.MoveNextAsync()"
                  IL_001e:  call       "bool System.Runtime.CompilerServices.AsyncHelpers.Await<bool>(System.Threading.Tasks.Task<bool>)"
                  IL_0023:  brtrue.s   IL_000d
                  IL_0025:  ret
                }
                """);
        }
 
        [Fact]
        public void TestGetAsyncEnumeratorPatternViaValidExtensionInClosestNamespaceInvalidInFurtherNamespace2()
        {
            var source = @"
using System;
using System.Threading.Tasks;
using N1;
using N3;
 
namespace N1
{
    using N2;
    public class C
    {
        public static async Task Main()
        {
            await foreach (var i in new C())
            {
                Console.Write(i);
            }
        }
        public sealed class Enumerator
        {
            public int Current { get; private set; }
            public Task<bool> MoveNextAsync() => Task.FromResult(Current++ != 3);
        }
    }
}
 
namespace N2
{
    public static class Extensions
    {
        public static C.Enumerator GetAsyncEnumerator(this C self) => new C.Enumerator();
    }
}
 
namespace N3
{
    public static class Extensions
    {
        public static int GetAsyncEnumerator(this C self) => throw null;
    }
}";
            var comp = CreateCompilationWithMscorlib46(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular9);
            comp.VerifyDiagnostics(
                // (5,1): hidden CS8019: Unnecessary using directive.
                // using N3;
                Diagnostic(ErrorCode.HDN_UnusedUsingDirective, "using N3;").WithLocation(5, 1));
            CompileAndVerify(comp, expectedOutput: "123");
 
            var runtimeAsyncComp = CreateRuntimeAsyncCompilation(source);
            var verifier = CompileAndVerify(runtimeAsyncComp, expectedOutput: CodeGenAsyncTests.ExpectedOutput("123", isRuntimeAsync: true), verify: Verification.Fails with
            {
                ILVerifyMessage = """
                    [Main]: Return value missing on the stack. { Offset = 0x25 }
                    """
            });
            verifier.VerifyIL("N1.C.Main()", """
                {
                  // Code size       38 (0x26)
                  .maxstack  1
                  .locals init (N1.C.Enumerator V_0)
                  IL_0000:  newobj     "N1.C..ctor()"
                  IL_0005:  call       "N1.C.Enumerator N2.Extensions.GetAsyncEnumerator(N1.C)"
                  IL_000a:  stloc.0
                  IL_000b:  br.s       IL_0018
                  IL_000d:  ldloc.0
                  IL_000e:  callvirt   "int N1.C.Enumerator.Current.get"
                  IL_0013:  call       "void System.Console.Write(int)"
                  IL_0018:  ldloc.0
                  IL_0019:  callvirt   "System.Threading.Tasks.Task<bool> N1.C.Enumerator.MoveNextAsync()"
                  IL_001e:  call       "bool System.Runtime.CompilerServices.AsyncHelpers.Await<bool>(System.Threading.Tasks.Task<bool>)"
                  IL_0023:  brtrue.s   IL_000d
                  IL_0025:  ret
                }
                """);
        }
 
        [Fact]
        public void TestGetAsyncEnumeratorPatternViaInvalidExtensionInClosestNamespaceValidInFurtherNamespace1()
        {
            var source = @"
using System;
using System.Threading.Tasks;
using N1.N2.N3;
 
namespace N1
{
    public static class Extensions
    {
        public static C.Enumerator GetAsyncEnumerator(this C self) => new C.Enumerator();
    }
 
    namespace N2
    {
        public static class Extensions
        {
            public static int GetAsyncEnumerator(this C self) => throw null;
        }
 
        namespace N3
        {
            using N2;
            public class C
            {
                public static async Task Main()
                {
                    await foreach (var i in new C())
                    {
                        Console.Write(i);
                    }
                }
                public sealed class Enumerator
                {
                    public int Current { get; private set; }
                    public Task<bool> MoveNextAsync() => Task.FromResult(Current++ != 3);
                }
            }
        }
    }
}";
            CreateCompilation(source, parseOptions: TestOptions.Regular9)
                .VerifyDiagnostics(
                    // (27,45): error CS0117: 'int' does not contain a definition for 'Current'
                    //                     await foreach (var i in new C())
                    Diagnostic(ErrorCode.ERR_NoSuchMember, "new C()").WithArguments("int", "Current").WithLocation(27, 45),
                    // (27,45): error CS8412: Asynchronous foreach requires that the return type 'int' of 'Extensions.GetAsyncEnumerator(C)' must have a suitable public 'MoveNextAsync' method and public 'Current' property
                    //                     await foreach (var i in new C())
                    Diagnostic(ErrorCode.ERR_BadGetAsyncEnumerator, "new C()").WithArguments("int", "N1.N2.Extensions.GetAsyncEnumerator(N1.N2.N3.C)").WithLocation(27, 45));
        }
 
        [Fact]
        public void TestGetAsyncEnumeratorPatternViaInvalidExtensionInClosestNamespaceValidInFurtherNamespace2()
        {
            var source = @"
using System;
using System.Threading.Tasks;
using N1;
using N2;
 
namespace N1
{
    using N3;
    public class C
    {
        public static async Task Main()
        {
            await foreach (var i in new C())
            {
                Console.Write(i);
            }
        }
        public sealed class Enumerator
        {
            public int Current { get; private set; }
            public Task<bool> MoveNextAsync() => Task.FromResult(Current++ != 3);
        }
    }
}
 
namespace N2
{
    public static class Extensions
    {
        public static C.Enumerator GetAsyncEnumerator(this C self) => new C.Enumerator();
    }
}
 
namespace N3
{
    public static class Extensions
    {
        public static int GetAsyncEnumerator(this C self) => throw null;
    }
}";
            CreateCompilation(source, parseOptions: TestOptions.Regular9)
                .VerifyDiagnostics(
                    // (5,1): hidden CS8019: Unnecessary using directive.
                    // using N2;
                    Diagnostic(ErrorCode.HDN_UnusedUsingDirective, "using N2;").WithLocation(5, 1),
                    // (14,37): error CS0117: 'int' does not contain a definition for 'Current'
                    //             await foreach (var i in new C())
                    Diagnostic(ErrorCode.ERR_NoSuchMember, "new C()").WithArguments("int", "Current").WithLocation(14, 37),
                    // (14,37): error CS8412: Asynchronous foreach requires that the return type 'int' of 'Extensions.GetAsyncEnumerator(C)' must have a suitable public 'MoveNextAsync' method and public 'Current' property
                    //             await foreach (var i in new C())
                    Diagnostic(ErrorCode.ERR_BadGetAsyncEnumerator, "new C()").WithArguments("int", "N3.Extensions.GetAsyncEnumerator(N1.C)").WithLocation(14, 37));
        }
 
        [Fact]
        public void TestGetAsyncEnumeratorPatternViaAccessiblePrivateExtension()
        {
            var source = @"
using System;
using System.Threading.Tasks;
public static class Program
{
    public static async Task Main()
    {
        await foreach (var i in new C())
        {
            Console.Write(i);
        }
    }
 
    private static C.Enumerator GetAsyncEnumerator(this C self) => new C.Enumerator();
}
 
public class C
{
    public sealed class Enumerator
    {
        public int Current { get; private set; }
        public Task<bool> MoveNextAsync() => Task.FromResult(Current++ != 3);
    }
}";
            var comp = CreateCompilationWithMscorlib46(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular9);
            comp.VerifyDiagnostics();
            CompileAndVerify(comp, expectedOutput: "123");
 
            var runtimeAsyncComp = CreateRuntimeAsyncCompilation(source);
            var verifier = CompileAndVerify(runtimeAsyncComp, expectedOutput: CodeGenAsyncTests.ExpectedOutput("123", isRuntimeAsync: true), verify: Verification.Fails with
            {
                ILVerifyMessage = """
                    [Main]: Return value missing on the stack. { Offset = 0x25 }
                    """
            });
            verifier.VerifyIL("Program.Main()", """
                {
                  // Code size       38 (0x26)
                  .maxstack  1
                  .locals init (C.Enumerator V_0)
                  IL_0000:  newobj     "C..ctor()"
                  IL_0005:  call       "C.Enumerator Program.GetAsyncEnumerator(C)"
                  IL_000a:  stloc.0
                  IL_000b:  br.s       IL_0018
                  IL_000d:  ldloc.0
                  IL_000e:  callvirt   "int C.Enumerator.Current.get"
                  IL_0013:  call       "void System.Console.Write(int)"
                  IL_0018:  ldloc.0
                  IL_0019:  callvirt   "System.Threading.Tasks.Task<bool> C.Enumerator.MoveNextAsync()"
                  IL_001e:  call       "bool System.Runtime.CompilerServices.AsyncHelpers.Await<bool>(System.Threading.Tasks.Task<bool>)"
                  IL_0023:  brtrue.s   IL_000d
                  IL_0025:  ret
                }
                """);
        }
 
        [Fact]
        public void TestGetAsyncEnumeratorPatternViaAccessiblePrivateExtensionInNestedClass()
        {
            var source = @"
using System;
using System.Threading.Tasks;
public static class Program
{
    public static class Inner
    {
        public static async Task Main()
        {
            await foreach (var i in new C())
            {
                Console.Write(i);
            }
        }
    }
 
    private static C.Enumerator GetAsyncEnumerator(this C self) => new C.Enumerator();
}
 
public class C
{
    public sealed class Enumerator
    {
        public int Current { get; private set; }
        public Task<bool> MoveNextAsync() => Task.FromResult(Current++ != 3);
    }
}";
            var comp = CreateCompilationWithMscorlib46(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular9);
            comp.VerifyDiagnostics();
            CompileAndVerify(comp, expectedOutput: "123");
 
            var runtimeAsyncComp = CreateRuntimeAsyncCompilation(source);
            var verifier = CompileAndVerify(runtimeAsyncComp, expectedOutput: CodeGenAsyncTests.ExpectedOutput("123", isRuntimeAsync: true), verify: Verification.Fails with
            {
                ILVerifyMessage = """
                    [Main]: Return value missing on the stack. { Offset = 0x25 }
                    """
            });
            verifier.VerifyIL("Program.Inner.Main()", """
                {
                  // Code size       38 (0x26)
                  .maxstack  1
                  .locals init (C.Enumerator V_0)
                  IL_0000:  newobj     "C..ctor()"
                  IL_0005:  call       "C.Enumerator Program.GetAsyncEnumerator(C)"
                  IL_000a:  stloc.0
                  IL_000b:  br.s       IL_0018
                  IL_000d:  ldloc.0
                  IL_000e:  callvirt   "int C.Enumerator.Current.get"
                  IL_0013:  call       "void System.Console.Write(int)"
                  IL_0018:  ldloc.0
                  IL_0019:  callvirt   "System.Threading.Tasks.Task<bool> C.Enumerator.MoveNextAsync()"
                  IL_001e:  call       "bool System.Runtime.CompilerServices.AsyncHelpers.Await<bool>(System.Threading.Tasks.Task<bool>)"
                  IL_0023:  brtrue.s   IL_000d
                  IL_0025:  ret
                }
                """);
        }
 
        [Fact]
        public void TestGetAsyncEnumeratorPatternViaInaccessiblePrivateExtension()
        {
            var source = @"
using System;
using System.Threading.Tasks;
public class C
{
    public static async Task Main()
    {
        await foreach (var i in new C())
        {
            Console.Write(i);
        }
    }
    public sealed class Enumerator
    {
        public int Current { get; private set; }
        public Task<bool> MoveNextAsync() => Task.FromResult(Current++ != 3);
    }
}
public static class Extensions
{
    private static C.Enumerator GetAsyncEnumerator(this C self) => new C.Enumerator();
}
";
            CreateCompilation(source, parseOptions: TestOptions.Regular9)
                .VerifyDiagnostics(
                    // (8,33): error CS8411: Asynchronous foreach statement cannot operate on variables of type 'C' because 'C' does not contain a suitable public instance or extension definition for 'GetAsyncEnumerator'
                    //         await foreach (var i in new C())
                    Diagnostic(ErrorCode.ERR_AwaitForEachMissingMember, "new C()").WithArguments("C", "GetAsyncEnumerator").WithLocation(8, 33)
                    );
        }
 
        [Fact]
        public void TestGetAsyncEnumeratorPatternViaExtensionWithRefReturn()
        {
            var source = @"
using System;
using System.Threading.Tasks;
public class C
{
    public static async Task Main()
    {
        await foreach (var i in new C())
        {
            Console.Write(i);
        }
        
        await foreach (var i in new C())
        {
            Console.Write(i);
        }
    }
    public struct Enumerator
    {
        public int Current { get; private set; }
        public Task<bool> MoveNextAsync() => Task.FromResult(Current++ != 3);
    }
}
public static class Extensions
{
    public static C.Enumerator Instance = new C.Enumerator();
    public static ref C.Enumerator GetAsyncEnumerator(this C self) => ref Instance;
}";
            var comp = CreateCompilationWithMscorlib46(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular9);
            comp.VerifyDiagnostics();
            CompileAndVerify(comp, expectedOutput: "123123");
 
            var runtimeAsyncComp = CreateRuntimeAsyncCompilation(source);
            var verifier = CompileAndVerify(runtimeAsyncComp, expectedOutput: CodeGenAsyncTests.ExpectedOutput("123123", isRuntimeAsync: true), verify: Verification.Fails with
            {
                ILVerifyMessage = """
                    [Main]: Return value missing on the stack. { Offset = 0x58 }
                    """
            });
            verifier.VerifyIL("C.Main()", """
                {
                  // Code size       89 (0x59)
                  .maxstack  1
                  .locals init (C.Enumerator V_0)
                  IL_0000:  newobj     "C..ctor()"
                  IL_0005:  call       "ref C.Enumerator Extensions.GetAsyncEnumerator(C)"
                  IL_000a:  ldobj      "C.Enumerator"
                  IL_000f:  stloc.0
                  IL_0010:  br.s       IL_001e
                  IL_0012:  ldloca.s   V_0
                  IL_0014:  call       "readonly int C.Enumerator.Current.get"
                  IL_0019:  call       "void System.Console.Write(int)"
                  IL_001e:  ldloca.s   V_0
                  IL_0020:  call       "System.Threading.Tasks.Task<bool> C.Enumerator.MoveNextAsync()"
                  IL_0025:  call       "bool System.Runtime.CompilerServices.AsyncHelpers.Await<bool>(System.Threading.Tasks.Task<bool>)"
                  IL_002a:  brtrue.s   IL_0012
                  IL_002c:  newobj     "C..ctor()"
                  IL_0031:  call       "ref C.Enumerator Extensions.GetAsyncEnumerator(C)"
                  IL_0036:  ldobj      "C.Enumerator"
                  IL_003b:  stloc.0
                  IL_003c:  br.s       IL_004a
                  IL_003e:  ldloca.s   V_0
                  IL_0040:  call       "readonly int C.Enumerator.Current.get"
                  IL_0045:  call       "void System.Console.Write(int)"
                  IL_004a:  ldloca.s   V_0
                  IL_004c:  call       "System.Threading.Tasks.Task<bool> C.Enumerator.MoveNextAsync()"
                  IL_0051:  call       "bool System.Runtime.CompilerServices.AsyncHelpers.Await<bool>(System.Threading.Tasks.Task<bool>)"
                  IL_0056:  brtrue.s   IL_003e
                  IL_0058:  ret
                }
                """);
        }
 
        [Theory, WorkItem(59955, "https://github.com/dotnet/roslyn/issues/59955")]
        [InlineData(true)]
        [InlineData(false)]
        public void DisposePatternPreferredOverIAsyncDisposable(bool withCSharp8)
        {
            var source = @"
using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
 
class C
{
    public static async Task Main()
    {
        await foreach (var i in new AsyncEnumerable())
        {
        }
    }
}
 
struct AsyncEnumerable : IAsyncEnumerable<int>
{
    public AsyncEnumerator GetAsyncEnumerator(CancellationToken token = default) => new AsyncEnumerator();
    IAsyncEnumerator<int> IAsyncEnumerable<int>.GetAsyncEnumerator(CancellationToken token) => throw null;
}
 
struct AsyncEnumerator : IAsyncEnumerator<int>
{
    public int Current => 0;
    public async ValueTask<bool> MoveNextAsync()
    {
        await Task.Yield();
        return false;
    }
    public async ValueTask DisposeAsync()
    {
        Console.WriteLine(""RAN"");
        await Task.Yield();
    }
 
    int IAsyncEnumerator<int>.Current => throw null;
    ValueTask<bool> IAsyncEnumerator<int>.MoveNextAsync() => throw null;
    ValueTask IAsyncDisposable.DisposeAsync() => throw null;
}
";
            var comp = CreateCompilationWithTasksExtensions(new[] { source, s_IAsyncEnumerable }, options: TestOptions.DebugExe,
                parseOptions: withCSharp8 ? TestOptions.Regular8 : TestOptions.Regular7_3);
 
            if (withCSharp8)
            {
                comp.VerifyDiagnostics();
                CompileAndVerify(comp, expectedOutput: "RAN");
 
                var runtimeAsyncComp = CreateRuntimeAsyncCompilation(source);
                var verifier = CompileAndVerify(runtimeAsyncComp, expectedOutput: CodeGenAsyncTests.ExpectedOutput("RAN", isRuntimeAsync: true), verify: Verification.Fails with
                {
                    ILVerifyMessage = """
                        [Main]: Return value missing on the stack. { Offset = 0x5b }
                        [MoveNextAsync]: Unexpected type on the stack. { Offset = 0x25, Found = Int32, Expected = value '[System.Runtime]System.Threading.Tasks.ValueTask`1<bool>' }
                        [DisposeAsync]: Return value missing on the stack. { Offset = 0x2e }
                        """
                });
                verifier.VerifyIL("C.Main()", """
                    {
                      // Code size       92 (0x5c)
                      .maxstack  2
                      .locals init (AsyncEnumerator V_0,
                                    AsyncEnumerable V_1,
                                    System.Threading.CancellationToken V_2,
                                    object V_3)
                      IL_0000:  ldloca.s   V_1
                      IL_0002:  dup
                      IL_0003:  initobj    "AsyncEnumerable"
                      IL_0009:  ldloca.s   V_2
                      IL_000b:  initobj    "System.Threading.CancellationToken"
                      IL_0011:  ldloc.2
                      IL_0012:  call       "AsyncEnumerator AsyncEnumerable.GetAsyncEnumerator(System.Threading.CancellationToken)"
                      IL_0017:  stloc.0
                      IL_0018:  ldnull
                      IL_0019:  stloc.3
                      .try
                      {
                        IL_001a:  br.s       IL_0024
                        IL_001c:  ldloca.s   V_0
                        IL_001e:  call       "int AsyncEnumerator.Current.get"
                        IL_0023:  pop
                        IL_0024:  ldloca.s   V_0
                        IL_0026:  call       "System.Threading.Tasks.ValueTask<bool> AsyncEnumerator.MoveNextAsync()"
                        IL_002b:  call       "bool System.Runtime.CompilerServices.AsyncHelpers.Await<bool>(System.Threading.Tasks.ValueTask<bool>)"
                        IL_0030:  brtrue.s   IL_001c
                        IL_0032:  leave.s    IL_0037
                      }
                      catch object
                      {
                        IL_0034:  stloc.3
                        IL_0035:  leave.s    IL_0037
                      }
                      IL_0037:  ldloca.s   V_0
                      IL_0039:  call       "System.Threading.Tasks.ValueTask AsyncEnumerator.DisposeAsync()"
                      IL_003e:  call       "void System.Runtime.CompilerServices.AsyncHelpers.Await(System.Threading.Tasks.ValueTask)"
                      IL_0043:  ldloc.3
                      IL_0044:  brfalse.s  IL_005b
                      IL_0046:  ldloc.3
                      IL_0047:  isinst     "System.Exception"
                      IL_004c:  dup
                      IL_004d:  brtrue.s   IL_0051
                      IL_004f:  ldloc.3
                      IL_0050:  throw
                      IL_0051:  call       "System.Runtime.ExceptionServices.ExceptionDispatchInfo System.Runtime.ExceptionServices.ExceptionDispatchInfo.Capture(System.Exception)"
                      IL_0056:  callvirt   "void System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()"
                      IL_005b:  ret
                    }
                    """);
            }
            else
            {
                comp.VerifyDiagnostics(
                    // (11,9): error CS8370: Feature 'async streams' is not available in C# 7.3. Please use language version 8.0 or greater.
                    //         await foreach (var i in new AsyncEnumerable())
                    Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7_3, "await").WithArguments("async streams", "8.0").WithLocation(11, 9)
                    );
            }
 
            var tree = comp.SyntaxTrees.First();
            var model = comp.GetSemanticModel(tree, ignoreAccessibility: false);
            var foreachSyntax = tree.GetRoot().DescendantNodes().OfType<ForEachStatementSyntax>().Single();
            var info = model.GetForEachStatementInfo(foreachSyntax);
 
            Assert.True(info.IsAsynchronous);
            Assert.Equal("AsyncEnumerator AsyncEnumerable.GetAsyncEnumerator([System.Threading.CancellationToken token = default(System.Threading.CancellationToken)])",
                info.GetEnumeratorMethod.ToTestDisplayString());
            Assert.Equal("System.Threading.Tasks.ValueTask<System.Boolean> AsyncEnumerator.MoveNextAsync()",
                info.MoveNextMethod.ToTestDisplayString());
            Assert.Equal("System.Int32 AsyncEnumerator.Current { get; }",
                info.CurrentProperty.ToTestDisplayString());
            Assert.Equal("System.Threading.Tasks.ValueTask AsyncEnumerator.DisposeAsync()",
                info.DisposeMethod.ToTestDisplayString());
            Assert.Equal("System.Int32", info.ElementType.ToTestDisplayString());
        }
 
        [Theory, WorkItem(59955, "https://github.com/dotnet/roslyn/issues/59955")]
        [InlineData(true)]
        [InlineData(false)]
        public void DisposePatternPreferredOverIAsyncDisposable_NoIAsyncEnumerable(bool withCSharp8)
        {
            var source = @"
using System;
using System.Threading;
using System.Threading.Tasks;
 
class C
{
    public static async Task Main()
    {
        await foreach (var i in new AsyncEnumerable())
        {
        }
    }
}
 
struct AsyncEnumerable
{
    public AsyncEnumerator GetAsyncEnumerator(CancellationToken token = default) => new AsyncEnumerator();
}
 
struct AsyncEnumerator : IAsyncDisposable
{
    public int Current => 0;
    public async ValueTask<bool> MoveNextAsync()
    {
        await Task.Yield();
        return false;
    }
    public async ValueTask DisposeAsync()
    {
        Console.WriteLine(""RAN"");
        await Task.Yield();
    }
 
    ValueTask IAsyncDisposable.DisposeAsync() => throw null;
}
";
            var comp = CreateCompilationWithTasksExtensions(new[] { source, s_IAsyncEnumerable }, options: TestOptions.DebugExe,
                parseOptions: withCSharp8 ? TestOptions.Regular8 : TestOptions.Regular7_3);
 
            if (withCSharp8)
            {
                comp.VerifyDiagnostics();
                CompileAndVerify(comp, expectedOutput: "RAN");
 
                var runtimeAsyncComp = CreateRuntimeAsyncCompilation(source);
                var verifier = CompileAndVerify(runtimeAsyncComp, expectedOutput: CodeGenAsyncTests.ExpectedOutput("RAN", isRuntimeAsync: true), verify: Verification.Fails with
                {
                    ILVerifyMessage = """
                        [Main]: Return value missing on the stack. { Offset = 0x5b }
                        [MoveNextAsync]: Unexpected type on the stack. { Offset = 0x25, Found = Int32, Expected = value '[System.Runtime]System.Threading.Tasks.ValueTask`1<bool>' }
                        [DisposeAsync]: Return value missing on the stack. { Offset = 0x2e }
                        """
                });
                verifier.VerifyIL("C.Main()", """
                    {
                      // Code size       92 (0x5c)
                      .maxstack  2
                      .locals init (AsyncEnumerator V_0,
                                    AsyncEnumerable V_1,
                                    System.Threading.CancellationToken V_2,
                                    object V_3)
                      IL_0000:  ldloca.s   V_1
                      IL_0002:  dup
                      IL_0003:  initobj    "AsyncEnumerable"
                      IL_0009:  ldloca.s   V_2
                      IL_000b:  initobj    "System.Threading.CancellationToken"
                      IL_0011:  ldloc.2
                      IL_0012:  call       "AsyncEnumerator AsyncEnumerable.GetAsyncEnumerator(System.Threading.CancellationToken)"
                      IL_0017:  stloc.0
                      IL_0018:  ldnull
                      IL_0019:  stloc.3
                      .try
                      {
                        IL_001a:  br.s       IL_0024
                        IL_001c:  ldloca.s   V_0
                        IL_001e:  call       "int AsyncEnumerator.Current.get"
                        IL_0023:  pop
                        IL_0024:  ldloca.s   V_0
                        IL_0026:  call       "System.Threading.Tasks.ValueTask<bool> AsyncEnumerator.MoveNextAsync()"
                        IL_002b:  call       "bool System.Runtime.CompilerServices.AsyncHelpers.Await<bool>(System.Threading.Tasks.ValueTask<bool>)"
                        IL_0030:  brtrue.s   IL_001c
                        IL_0032:  leave.s    IL_0037
                      }
                      catch object
                      {
                        IL_0034:  stloc.3
                        IL_0035:  leave.s    IL_0037
                      }
                      IL_0037:  ldloca.s   V_0
                      IL_0039:  call       "System.Threading.Tasks.ValueTask AsyncEnumerator.DisposeAsync()"
                      IL_003e:  call       "void System.Runtime.CompilerServices.AsyncHelpers.Await(System.Threading.Tasks.ValueTask)"
                      IL_0043:  ldloc.3
                      IL_0044:  brfalse.s  IL_005b
                      IL_0046:  ldloc.3
                      IL_0047:  isinst     "System.Exception"
                      IL_004c:  dup
                      IL_004d:  brtrue.s   IL_0051
                      IL_004f:  ldloc.3
                      IL_0050:  throw
                      IL_0051:  call       "System.Runtime.ExceptionServices.ExceptionDispatchInfo System.Runtime.ExceptionServices.ExceptionDispatchInfo.Capture(System.Exception)"
                      IL_0056:  callvirt   "void System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()"
                      IL_005b:  ret
                    }
                    """);
            }
            else
            {
                comp.VerifyDiagnostics(
                    // (10,9): error CS8370: Feature 'async streams' is not available in C# 7.3. Please use language version 8.0 or greater.
                    //         await foreach (var i in new AsyncEnumerable())
                    Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7_3, "await").WithArguments("async streams", "8.0").WithLocation(10, 9)
                    );
            }
 
            var tree = comp.SyntaxTrees.First();
            var model = comp.GetSemanticModel(tree, ignoreAccessibility: false);
            var foreachSyntax = tree.GetRoot().DescendantNodes().OfType<ForEachStatementSyntax>().Single();
            var info = model.GetForEachStatementInfo(foreachSyntax);
 
            Assert.True(info.IsAsynchronous);
            Assert.Equal("AsyncEnumerator AsyncEnumerable.GetAsyncEnumerator([System.Threading.CancellationToken token = default(System.Threading.CancellationToken)])",
                info.GetEnumeratorMethod.ToTestDisplayString());
            Assert.Equal("System.Threading.Tasks.ValueTask<System.Boolean> AsyncEnumerator.MoveNextAsync()",
                info.MoveNextMethod.ToTestDisplayString());
            Assert.Equal("System.Int32 AsyncEnumerator.Current { get; }",
                info.CurrentProperty.ToTestDisplayString());
            Assert.Equal("System.Threading.Tasks.ValueTask AsyncEnumerator.DisposeAsync()",
                info.DisposeMethod.ToTestDisplayString());
            Assert.Equal("System.Int32", info.ElementType.ToTestDisplayString());
        }
 
        [Theory, WorkItem(59955, "https://github.com/dotnet/roslyn/issues/59955")]
        [InlineData(true)]
        [InlineData(false)]
        public void AsyncEnumerationViaInterfaceUsesIAsyncDisposable(bool withCSharp8)
        {
            // The enumerator type is IAsyncEnumerator<int> so disposal uses IAsyncDisposable.DisposeAsync()
            var source = @"
using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
 
class C
{
    public static async Task Main()
    {
        await foreach (var i in new AsyncEnumerable())
        {
        }
    }
}
 
struct AsyncEnumerable : IAsyncEnumerable<int>
{
    IAsyncEnumerator<int> IAsyncEnumerable<int>.GetAsyncEnumerator(CancellationToken token) => new AsyncEnumerator();
}
 
struct AsyncEnumerator : IAsyncEnumerator<int>
{
    public ValueTask DisposeAsync() => throw null;
 
    int IAsyncEnumerator<int>.Current => 0;
    async ValueTask<bool> IAsyncEnumerator<int>.MoveNextAsync()
    {
        await Task.Yield();
        return false;
    }
    async ValueTask IAsyncDisposable.DisposeAsync()
    {
        Console.WriteLine(""RAN"");
        await Task.Yield();
    }
}
";
            var comp = CreateCompilationWithTasksExtensions(new[] { source, s_IAsyncEnumerable }, options: TestOptions.DebugExe,
                parseOptions: withCSharp8 ? TestOptions.Regular8 : TestOptions.Regular7_3);
 
            if (withCSharp8)
            {
                comp.VerifyDiagnostics();
                CompileAndVerify(comp, expectedOutput: "RAN");
 
                var runtimeAsyncComp = CreateRuntimeAsyncCompilation(source);
                var verifier = CompileAndVerify(runtimeAsyncComp, expectedOutput: CodeGenAsyncTests.ExpectedOutput("RAN", isRuntimeAsync: true), verify: Verification.Fails with
                {
                    ILVerifyMessage = """
                        [Main]: Return value missing on the stack. { Offset = 0x61 }
                        [System.Collections.Generic.IAsyncEnumerator<System.Int32>.MoveNextAsync]: Unexpected type on the stack. { Offset = 0x25, Found = Int32, Expected = value '[System.Runtime]System.Threading.Tasks.ValueTask`1<bool>' }
                        [System.IAsyncDisposable.DisposeAsync]: Return value missing on the stack. { Offset = 0x2e }
                        """
                });
                verifier.VerifyIL("C.Main()", """
                    {
                      // Code size       98 (0x62)
                      .maxstack  2
                      .locals init (System.Collections.Generic.IAsyncEnumerator<int> V_0,
                                    AsyncEnumerable V_1,
                                    System.Threading.CancellationToken V_2,
                                    object V_3)
                      IL_0000:  ldloca.s   V_1
                      IL_0002:  dup
                      IL_0003:  initobj    "AsyncEnumerable"
                      IL_0009:  ldloca.s   V_2
                      IL_000b:  initobj    "System.Threading.CancellationToken"
                      IL_0011:  ldloc.2
                      IL_0012:  constrained. "AsyncEnumerable"
                      IL_0018:  callvirt   "System.Collections.Generic.IAsyncEnumerator<int> System.Collections.Generic.IAsyncEnumerable<int>.GetAsyncEnumerator(System.Threading.CancellationToken)"
                      IL_001d:  stloc.0
                      IL_001e:  ldnull
                      IL_001f:  stloc.3
                      .try
                      {
                        IL_0020:  br.s       IL_0029
                        IL_0022:  ldloc.0
                        IL_0023:  callvirt   "int System.Collections.Generic.IAsyncEnumerator<int>.Current.get"
                        IL_0028:  pop
                        IL_0029:  ldloc.0
                        IL_002a:  callvirt   "System.Threading.Tasks.ValueTask<bool> System.Collections.Generic.IAsyncEnumerator<int>.MoveNextAsync()"
                        IL_002f:  call       "bool System.Runtime.CompilerServices.AsyncHelpers.Await<bool>(System.Threading.Tasks.ValueTask<bool>)"
                        IL_0034:  brtrue.s   IL_0022
                        IL_0036:  leave.s    IL_003b
                      }
                      catch object
                      {
                        IL_0038:  stloc.3
                        IL_0039:  leave.s    IL_003b
                      }
                      IL_003b:  ldloc.0
                      IL_003c:  brfalse.s  IL_0049
                      IL_003e:  ldloc.0
                      IL_003f:  callvirt   "System.Threading.Tasks.ValueTask System.IAsyncDisposable.DisposeAsync()"
                      IL_0044:  call       "void System.Runtime.CompilerServices.AsyncHelpers.Await(System.Threading.Tasks.ValueTask)"
                      IL_0049:  ldloc.3
                      IL_004a:  brfalse.s  IL_0061
                      IL_004c:  ldloc.3
                      IL_004d:  isinst     "System.Exception"
                      IL_0052:  dup
                      IL_0053:  brtrue.s   IL_0057
                      IL_0055:  ldloc.3
                      IL_0056:  throw
                      IL_0057:  call       "System.Runtime.ExceptionServices.ExceptionDispatchInfo System.Runtime.ExceptionServices.ExceptionDispatchInfo.Capture(System.Exception)"
                      IL_005c:  callvirt   "void System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()"
                      IL_0061:  ret
                    }
                    """);
            }
            else
            {
                comp.VerifyDiagnostics(
                    // (11,9): error CS8370: Feature 'async streams' is not available in C# 7.3. Please use language version 8.0 or greater.
                    //         await foreach (var i in new AsyncEnumerable())
                    Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7_3, "await").WithArguments("async streams", "8.0").WithLocation(11, 9)
                    );
            }
 
            var tree = comp.SyntaxTrees.First();
            var model = comp.GetSemanticModel(tree, ignoreAccessibility: false);
            var foreachSyntax = tree.GetRoot().DescendantNodes().OfType<ForEachStatementSyntax>().Single();
            var info = model.GetForEachStatementInfo(foreachSyntax);
 
            Assert.True(info.IsAsynchronous);
            Assert.Equal("System.Collections.Generic.IAsyncEnumerator<System.Int32> System.Collections.Generic.IAsyncEnumerable<System.Int32>.GetAsyncEnumerator([System.Threading.CancellationToken token = default(System.Threading.CancellationToken)])",
               info.GetEnumeratorMethod.ToTestDisplayString());
            Assert.Equal("System.Threading.Tasks.ValueTask<System.Boolean> System.Collections.Generic.IAsyncEnumerator<System.Int32>.MoveNextAsync()",
                info.MoveNextMethod.ToTestDisplayString());
            Assert.Equal("System.Int32 System.Collections.Generic.IAsyncEnumerator<System.Int32>.Current { get; }",
                info.CurrentProperty.ToTestDisplayString());
            Assert.Equal("System.Threading.Tasks.ValueTask System.IAsyncDisposable.DisposeAsync()",
                info.DisposeMethod.ToTestDisplayString());
            Assert.Equal("System.Int32", info.ElementType.ToTestDisplayString());
        }
 
        [Fact, WorkItem(59955, "https://github.com/dotnet/roslyn/issues/59955")]
        public void EnumerationViaInterfaceUsesIDisposable()
        {
            var source = @"
using System;
using System.Collections;
using System.Collections.Generic;
 
class C
{
    public static void Main()
    {
        foreach (var i in new Enumerable())
        {
        }
    }
}
 
struct Enumerable : IEnumerable<int>
{
    IEnumerator IEnumerable.GetEnumerator() => throw null;
    IEnumerator<int> IEnumerable<int>.GetEnumerator() => new Enumerator();
}
 
struct Enumerator : IEnumerator<int>
{
    public void Dispose() => throw null;
 
    int IEnumerator<int>.Current => 0;
    object IEnumerator.Current => throw null;
    void IEnumerator.Reset() => throw null;
    bool IEnumerator.MoveNext() => false;
 
    void IDisposable.Dispose()
    {
        Console.WriteLine(""RAN"");
    }
}
";
            var comp = CreateCompilationWithTasksExtensions(new[] { source, s_IAsyncEnumerable }, options: TestOptions.DebugExe);
 
            comp.VerifyDiagnostics();
            CompileAndVerify(comp, expectedOutput: "RAN");
 
            var tree = comp.SyntaxTrees.First();
            var model = comp.GetSemanticModel(tree, ignoreAccessibility: false);
            var foreachSyntax = tree.GetRoot().DescendantNodes().OfType<ForEachStatementSyntax>().Single();
            var info = model.GetForEachStatementInfo(foreachSyntax);
 
            Assert.Equal("void System.IDisposable.Dispose()", info.DisposeMethod.ToTestDisplayString());
        }
 
        [Theory, WorkItem(59955, "https://github.com/dotnet/roslyn/issues/59955")]
        [InlineData(true)]
        [InlineData(false)]
        public void DisposePatternPreferredOverIAsyncDisposable_Deconstruction(bool withCSharp8)
        {
            var source = @"
using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
 
class C
{
    public static async Task Main()
    {
        await foreach (var (i, j) in new AsyncEnumerable())
        {
        }
    }
}
 
struct AsyncEnumerable : IAsyncEnumerable<(int, int)>
{
    public AsyncEnumerator GetAsyncEnumerator(CancellationToken token = default) => new AsyncEnumerator();
    IAsyncEnumerator<(int, int)> IAsyncEnumerable<(int, int)>.GetAsyncEnumerator(CancellationToken token) => throw null;
}
 
struct AsyncEnumerator : IAsyncEnumerator<(int, int)>
{
    public (int, int) Current => (0, 0);
    public async ValueTask<bool> MoveNextAsync()
    {
        await Task.Yield();
        return false;
    }
    public async ValueTask DisposeAsync()
    {
        Console.WriteLine(""RAN"");
        await Task.Yield();
    }
 
    (int, int) IAsyncEnumerator<(int, int)>.Current => throw null;
    ValueTask<bool> IAsyncEnumerator<(int, int)>.MoveNextAsync() => throw null;
    ValueTask IAsyncDisposable.DisposeAsync() => throw null;
}
";
            var comp = CreateCompilationWithTasksExtensions(new[] { source, s_IAsyncEnumerable }, options: TestOptions.DebugExe,
                parseOptions: withCSharp8 ? TestOptions.Regular8 : TestOptions.Regular7_3);
 
            if (withCSharp8)
            {
                comp.VerifyDiagnostics();
                CompileAndVerify(comp, expectedOutput: "RAN");
 
                var runtimeAsyncComp = CreateRuntimeAsyncCompilation(source);
                var verifier = CompileAndVerify(runtimeAsyncComp, expectedOutput: CodeGenAsyncTests.ExpectedOutput("RAN", isRuntimeAsync: true), verify: Verification.Fails with
                {
                    ILVerifyMessage = """
                        [Main]: Return value missing on the stack. { Offset = 0x5b }
                        [MoveNextAsync]: Unexpected type on the stack. { Offset = 0x25, Found = Int32, Expected = value '[System.Runtime]System.Threading.Tasks.ValueTask`1<bool>' }
                        [DisposeAsync]: Return value missing on the stack. { Offset = 0x2e }
                        """
                });
                verifier.VerifyIL("C.Main()", """
                    {
                      // Code size       92 (0x5c)
                      .maxstack  2
                      .locals init (AsyncEnumerator V_0,
                                    AsyncEnumerable V_1,
                                    System.Threading.CancellationToken V_2,
                                    object V_3)
                      IL_0000:  ldloca.s   V_1
                      IL_0002:  dup
                      IL_0003:  initobj    "AsyncEnumerable"
                      IL_0009:  ldloca.s   V_2
                      IL_000b:  initobj    "System.Threading.CancellationToken"
                      IL_0011:  ldloc.2
                      IL_0012:  call       "AsyncEnumerator AsyncEnumerable.GetAsyncEnumerator(System.Threading.CancellationToken)"
                      IL_0017:  stloc.0
                      IL_0018:  ldnull
                      IL_0019:  stloc.3
                      .try
                      {
                        IL_001a:  br.s       IL_0024
                        IL_001c:  ldloca.s   V_0
                        IL_001e:  call       "System.ValueTuple<int, int> AsyncEnumerator.Current.get"
                        IL_0023:  pop
                        IL_0024:  ldloca.s   V_0
                        IL_0026:  call       "System.Threading.Tasks.ValueTask<bool> AsyncEnumerator.MoveNextAsync()"
                        IL_002b:  call       "bool System.Runtime.CompilerServices.AsyncHelpers.Await<bool>(System.Threading.Tasks.ValueTask<bool>)"
                        IL_0030:  brtrue.s   IL_001c
                        IL_0032:  leave.s    IL_0037
                      }
                      catch object
                      {
                        IL_0034:  stloc.3
                        IL_0035:  leave.s    IL_0037
                      }
                      IL_0037:  ldloca.s   V_0
                      IL_0039:  call       "System.Threading.Tasks.ValueTask AsyncEnumerator.DisposeAsync()"
                      IL_003e:  call       "void System.Runtime.CompilerServices.AsyncHelpers.Await(System.Threading.Tasks.ValueTask)"
                      IL_0043:  ldloc.3
                      IL_0044:  brfalse.s  IL_005b
                      IL_0046:  ldloc.3
                      IL_0047:  isinst     "System.Exception"
                      IL_004c:  dup
                      IL_004d:  brtrue.s   IL_0051
                      IL_004f:  ldloc.3
                      IL_0050:  throw
                      IL_0051:  call       "System.Runtime.ExceptionServices.ExceptionDispatchInfo System.Runtime.ExceptionServices.ExceptionDispatchInfo.Capture(System.Exception)"
                      IL_0056:  callvirt   "void System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()"
                      IL_005b:  ret
                    }
                    """);
            }
            else
            {
                comp.VerifyDiagnostics(
                    // (11,9): error CS8370: Feature 'async streams' is not available in C# 7.3. Please use language version 8.0 or greater.
                    //         await foreach (var i in new AsyncEnumerable())
                    Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7_3, "await").WithArguments("async streams", "8.0").WithLocation(11, 9)
                    );
            }
 
            var tree = comp.SyntaxTrees.First();
            var model = comp.GetSemanticModel(tree, ignoreAccessibility: false);
            var foreachSyntax = tree.GetRoot().DescendantNodes().OfType<ForEachVariableStatementSyntax>().Single();
            var info = model.GetForEachStatementInfo(foreachSyntax);
 
            Assert.True(info.IsAsynchronous);
            Assert.Equal("AsyncEnumerator AsyncEnumerable.GetAsyncEnumerator([System.Threading.CancellationToken token = default(System.Threading.CancellationToken)])",
                info.GetEnumeratorMethod.ToTestDisplayString());
            Assert.Equal("System.Threading.Tasks.ValueTask<System.Boolean> AsyncEnumerator.MoveNextAsync()",
                info.MoveNextMethod.ToTestDisplayString());
            Assert.Equal("(System.Int32, System.Int32) AsyncEnumerator.Current { get; }",
                info.CurrentProperty.ToTestDisplayString());
            Assert.Equal("System.Threading.Tasks.ValueTask AsyncEnumerator.DisposeAsync()",
                info.DisposeMethod.ToTestDisplayString());
            Assert.Equal("(System.Int32, System.Int32)", info.ElementType.ToTestDisplayString());
        }
 
        [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/72819")]
        public void PatternBasedFails_AwaitForeach()
        {
            var src = """
using System;
using System.Threading;
using System.Threading.Tasks;
 
interface ICustomEnumerator
{
    public int Current {get;}
 
    public ValueTask<bool> MoveNextAsync();
}
 
interface IGetEnumerator<TEnumerator> where TEnumerator : ICustomEnumerator
{
    TEnumerator GetAsyncEnumerator(CancellationToken token = default);
}
 
struct S1 : IGetEnumerator<S2>
{
    public S2 GetAsyncEnumerator(CancellationToken token = default)
    {
        return new S2();
    }
}
 
interface IMyAsyncDisposable1
{
    ValueTask DisposeAsync();
}
 
interface IMyAsyncDisposable2
{
    ValueTask DisposeAsync();
}
 
struct S2 : ICustomEnumerator, IMyAsyncDisposable1, IMyAsyncDisposable2, IAsyncDisposable
{
    ValueTask IMyAsyncDisposable1.DisposeAsync() => throw null;
    ValueTask IMyAsyncDisposable2.DisposeAsync() => throw null;
    public ValueTask DisposeAsync()
    { 
        System.Console.Write("D");
        return ValueTask.CompletedTask;
    }
 
    public int Current => throw null;
    public ValueTask<bool> MoveNextAsync()
    {
        return ValueTask.FromResult(false);
    }
}
 
class C
{
    static async Task Main()
    {
        await Test<S1, S2>();
    }
 
    static async Task Test<TEnumerable, TEnumerator>()
        where TEnumerable : IGetEnumerator<TEnumerator>
        where TEnumerator : ICustomEnumerator, IMyAsyncDisposable1, IMyAsyncDisposable2, IAsyncDisposable
    {
        await foreach (var i in default(TEnumerable))
        {
            System.Console.Write(i);
        }
    }
}
""";
            var comp = CreateCompilation(src, targetFramework: TargetFramework.Net80, options: TestOptions.ReleaseExe);
            var expectedOutput = ExecutionConditionUtil.IsMonoOrCoreClr ? "D" : null;
            CompileAndVerify(comp,
                expectedOutput: expectedOutput,
                verify: ExecutionConditionUtil.IsMonoOrCoreClr ? Verification.Passes : Verification.Skipped).VerifyDiagnostics();
 
            var runtimeAsyncComp = CreateRuntimeAsyncCompilation(src);
            var verifier = CompileAndVerify(runtimeAsyncComp, expectedOutput: CodeGenAsyncTests.ExpectedOutput(expectedOutput, isRuntimeAsync: true), verify: Verification.Fails with
            {
                ILVerifyMessage = """
                    [Main]: Return value missing on the stack. { Offset = 0xa }
                    [Test]: Return value missing on the stack. { Offset = 0x7f }
                    """
            });
            verifier.VerifyIL("C.Test<TEnumerable, TEnumerator>()", """
                {
                  // Code size      128 (0x80)
                  .maxstack  2
                  .locals init (TEnumerator V_0,
                                TEnumerable V_1,
                                System.Threading.CancellationToken V_2,
                                object V_3)
                  IL_0000:  ldloca.s   V_1
                  IL_0002:  dup
                  IL_0003:  initobj    "TEnumerable"
                  IL_0009:  ldloca.s   V_2
                  IL_000b:  initobj    "System.Threading.CancellationToken"
                  IL_0011:  ldloc.2
                  IL_0012:  constrained. "TEnumerable"
                  IL_0018:  callvirt   "TEnumerator IGetEnumerator<TEnumerator>.GetAsyncEnumerator(System.Threading.CancellationToken)"
                  IL_001d:  stloc.0
                  IL_001e:  ldnull
                  IL_001f:  stloc.3
                  .try
                  {
                    IL_0020:  br.s       IL_0034
                    IL_0022:  ldloca.s   V_0
                    IL_0024:  constrained. "TEnumerator"
                    IL_002a:  callvirt   "int ICustomEnumerator.Current.get"
                    IL_002f:  call       "void System.Console.Write(int)"
                    IL_0034:  ldloca.s   V_0
                    IL_0036:  constrained. "TEnumerator"
                    IL_003c:  callvirt   "System.Threading.Tasks.ValueTask<bool> ICustomEnumerator.MoveNextAsync()"
                    IL_0041:  call       "bool System.Runtime.CompilerServices.AsyncHelpers.Await<bool>(System.Threading.Tasks.ValueTask<bool>)"
                    IL_0046:  brtrue.s   IL_0022
                    IL_0048:  leave.s    IL_004d
                  }
                  catch object
                  {
                    IL_004a:  stloc.3
                    IL_004b:  leave.s    IL_004d
                  }
                  IL_004d:  ldloc.0
                  IL_004e:  box        "TEnumerator"
                  IL_0053:  brfalse.s  IL_0067
                  IL_0055:  ldloca.s   V_0
                  IL_0057:  constrained. "TEnumerator"
                  IL_005d:  callvirt   "System.Threading.Tasks.ValueTask System.IAsyncDisposable.DisposeAsync()"
                  IL_0062:  call       "void System.Runtime.CompilerServices.AsyncHelpers.Await(System.Threading.Tasks.ValueTask)"
                  IL_0067:  ldloc.3
                  IL_0068:  brfalse.s  IL_007f
                  IL_006a:  ldloc.3
                  IL_006b:  isinst     "System.Exception"
                  IL_0070:  dup
                  IL_0071:  brtrue.s   IL_0075
                  IL_0073:  ldloc.3
                  IL_0074:  throw
                  IL_0075:  call       "System.Runtime.ExceptionServices.ExceptionDispatchInfo System.Runtime.ExceptionServices.ExceptionDispatchInfo.Capture(System.Exception)"
                  IL_007a:  callvirt   "void System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()"
                  IL_007f:  ret
                }
                """);
        }
    }
}