File: Semantics\LockTests.cs
Web Access
Project: src\src\Compilers\CSharp\Test\Emit3\Microsoft.CodeAnalysis.CSharp.Emit3.UnitTests.csproj (Microsoft.CodeAnalysis.CSharp.Emit3.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.
 
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.Semantics;
 
public class LockTests : CSharpTestBase
{
    private const string LockTypeDefinition = """
        namespace System.Threading
        {
            public class Lock
            {
                public Scope EnterScope()
                {
                    Console.Write("E");
                    return new Scope();
                }
 
                public ref struct Scope
                {
                    public void Dispose()
                    {
                        Console.Write("D");
                    }
                }
            }
        }
        """;
 
    [Fact]
    public void LockVsUsing()
    {
        var source = """
            using System;
            using System.Threading;
 
            static class C
            {
                static readonly Lock _lock = new();
 
                static void Main()
                {
                    M1();
                    M2();
                }
 
                static void M1()
                {
                    Console.Write("1");
                    lock (_lock)
                    {
                        Console.Write("2");
                    }
                    Console.Write("3");
                }
 
                static void M2()
                {
                    Console.Write("1");
                    using (_lock.EnterScope())
                    {
                        Console.Write("2");
                    }
                    Console.Write("3");
                }
            }
            """;
        var verifier = CompileAndVerify([source, LockTypeDefinition], expectedOutput: "1E2D31E2D3",
            verify: Verification.FailsILVerify);
        verifier.VerifyDiagnostics();
        var il = """
            {
              // Code size       52 (0x34)
              .maxstack  1
              .locals init (System.Threading.Lock.Scope V_0)
              IL_0000:  ldstr      "1"
              IL_0005:  call       "void System.Console.Write(string)"
              IL_000a:  ldsfld     "System.Threading.Lock C._lock"
              IL_000f:  callvirt   "System.Threading.Lock.Scope System.Threading.Lock.EnterScope()"
              IL_0014:  stloc.0
              .try
              {
                IL_0015:  ldstr      "2"
                IL_001a:  call       "void System.Console.Write(string)"
                IL_001f:  leave.s    IL_0029
              }
              finally
              {
                IL_0021:  ldloca.s   V_0
                IL_0023:  call       "void System.Threading.Lock.Scope.Dispose()"
                IL_0028:  endfinally
              }
              IL_0029:  ldstr      "3"
              IL_002e:  call       "void System.Console.Write(string)"
              IL_0033:  ret
            }
            """;
        verifier.VerifyIL("C.M2", il);
        verifier.VerifyIL("C.M1", il);
    }
 
    [Fact]
    public void LockInNet9()
    {
        var source = """
            using System;
            using System.Threading;
 
            static class C
            {
                static readonly Lock _lock = new();
 
                static void Main()
                {
                    Console.Write("1");
                    lock (_lock)
                    {
                        Console.Write("2");
                    }
                    Console.Write("3");
                }
            }
            """;
        var verifier = CompileAndVerify(source,
            expectedOutput: ExecutionConditionUtil.IsMonoOrCoreClr ? "123" : null,
            targetFramework: TargetFramework.Net90,
            verify: Verification.FailsPEVerify);
        verifier.VerifyDiagnostics();
        verifier.VerifyIL("C.Main", """
            {
              // Code size       52 (0x34)
              .maxstack  1
              .locals init (System.Threading.Lock.Scope V_0)
              IL_0000:  ldstr      "1"
              IL_0005:  call       "void System.Console.Write(string)"
              IL_000a:  ldsfld     "System.Threading.Lock C._lock"
              IL_000f:  callvirt   "System.Threading.Lock.Scope System.Threading.Lock.EnterScope()"
              IL_0014:  stloc.0
              .try
              {
                IL_0015:  ldstr      "2"
                IL_001a:  call       "void System.Console.Write(string)"
                IL_001f:  leave.s    IL_0029
              }
              finally
              {
                IL_0021:  ldloca.s   V_0
                IL_0023:  call       "void System.Threading.Lock.Scope.Dispose()"
                IL_0028:  endfinally
              }
              IL_0029:  ldstr      "3"
              IL_002e:  call       "void System.Console.Write(string)"
              IL_0033:  ret
            }
            """);
    }
 
    [Fact]
    public void SemanticModel()
    {
        var source = """
            using System.Threading;
 
            Lock l = null;
            lock (l)
            {
            }
            """;
        var compilation = CreateCompilation([source, LockTypeDefinition]);
        compilation.VerifyDiagnostics();
 
        var tree = compilation.SyntaxTrees[0];
        var model = compilation.GetSemanticModel(tree);
 
        var localDecl = tree.GetRoot().DescendantNodes().OfType<LocalDeclarationStatementSyntax>().Single();
        var localSymbol = (ILocalSymbol)model.GetDeclaredSymbol(localDecl.Declaration.Variables.Single())!;
        Assert.Equal("l", localSymbol.Name);
        Assert.Equal("System.Threading.Lock", localSymbol.Type.ToTestDisplayString());
 
        var lockStatement = tree.GetRoot().DescendantNodes().OfType<LockStatementSyntax>().Single();
        var lockExprInfo = model.GetSymbolInfo(lockStatement.Expression);
        Assert.Equal(localSymbol, lockExprInfo.Symbol);
    }
 
    [Fact]
    public void MissingEnterScope()
    {
        var source = """
            System.Threading.Lock l = new();
            lock (l) { }
 
            namespace System.Threading
            {
                public class Lock { }
            }
            """;
        CreateCompilation(source).VerifyDiagnostics(
            // (2,7): error CS0656: Missing compiler required member 'System.Threading.Lock.EnterScope'
            // lock (l) { }
            Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "l").WithArguments("System.Threading.Lock", "EnterScope").WithLocation(2, 7));
    }
 
    [Fact]
    public void EnterScopeReturnsVoid()
    {
        var source = """
            System.Threading.Lock l = new();
            lock (l) { }
 
            namespace System.Threading
            {
                public class Lock
                {
                    public void EnterScope() { }
                }
            }
            """;
        CreateCompilation(source).VerifyDiagnostics(
            // (2,7): error CS0656: Missing compiler required member 'System.Threading.Lock.EnterScope'
            // lock (l) { }
            Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "l").WithArguments("System.Threading.Lock", "EnterScope").WithLocation(2, 7));
    }
 
    [Fact]
    public void EnterScopeStatic()
    {
        var source = """
            System.Threading.Lock l = new();
            lock (l) { }
 
            namespace System.Threading
            {
                public class Lock
                {
                    public static Scope EnterScope() => new Scope();
 
                    public ref struct Scope
                    {
                        public void Dispose() { }
                    }
                }
            }
            """;
        CreateCompilation(source).VerifyDiagnostics(
            // (2,7): error CS0656: Missing compiler required member 'System.Threading.Lock.EnterScope'
            // lock (l) { }
            Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "l").WithArguments("System.Threading.Lock", "EnterScope").WithLocation(2, 7));
    }
 
    [Fact]
    public void EnterScopeTakesParameters()
    {
        var source = """
            System.Threading.Lock l = new();
            lock (l) { }
 
            namespace System.Threading
            {
                public class Lock
                {
                    public Scope EnterScope(int arg) => new Scope();
 
                    public ref struct Scope
                    {
                        public void Dispose() { }
                    }
                }
            }
            """;
        CreateCompilation(source).VerifyDiagnostics(
            // (2,7): error CS0656: Missing compiler required member 'System.Threading.Lock.EnterScope'
            // lock (l) { }
            Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "l").WithArguments("System.Threading.Lock", "EnterScope").WithLocation(2, 7));
    }
 
    [Fact]
    public void EnterScopeTakesParameters_Optional()
    {
        var source = """
            System.Threading.Lock l = new();
            lock (l) { }
 
            namespace System.Threading
            {
                public class Lock
                {
                    public Scope EnterScope(int arg = 1) => new Scope();
 
                    public ref struct Scope
                    {
                        public void Dispose() { }
                    }
                }
            }
            """;
        CreateCompilation(source).VerifyDiagnostics(
            // (2,7): error CS0656: Missing compiler required member 'System.Threading.Lock.EnterScope'
            // lock (l) { }
            Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "l").WithArguments("System.Threading.Lock", "EnterScope").WithLocation(2, 7));
    }
 
    [Fact]
    public void EnterScopeTakesParameters_ParamsArray()
    {
        var source = """
            System.Threading.Lock l = new();
            lock (l) { }
 
            namespace System.Threading
            {
                public class Lock
                {
                    public Scope EnterScope(params int[] args) => new Scope();
 
                    public ref struct Scope
                    {
                        public void Dispose() { }
                    }
                }
            }
            """;
        CreateCompilation(source).VerifyDiagnostics(
            // (2,7): error CS0656: Missing compiler required member 'System.Threading.Lock.EnterScope'
            // lock (l) { }
            Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "l").WithArguments("System.Threading.Lock", "EnterScope").WithLocation(2, 7));
    }
 
    [Fact]
    public void EnterScopeMultipleOverloads_01()
    {
        var source = """
            System.Threading.Lock l = new();
            lock (l) { }
 
            namespace System.Threading
            {
                public class Lock
                {
                    public Scope EnterScope() => new Scope();
                    public Scope EnterScope() => new Scope();
 
                    public ref struct Scope
                    {
                        public void Dispose() { }
                    }
                }
            }
            """;
        CreateCompilation(source).VerifyDiagnostics(
            // (2,7): error CS0656: Missing compiler required member 'System.Threading.Lock.EnterScope'
            // lock (l) { }
            Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "l").WithArguments("System.Threading.Lock", "EnterScope").WithLocation(2, 7),
            // (9,22): error CS0111: Type 'Lock' already defines a member called 'EnterScope' with the same parameter types
            //         public Scope EnterScope() => new Scope();
            Diagnostic(ErrorCode.ERR_MemberAlreadyExists, "EnterScope").WithArguments("EnterScope", "System.Threading.Lock").WithLocation(9, 22));
    }
 
    [Fact]
    public void EnterScopeMultipleOverloads_02()
    {
        var source = """
            System.Threading.Lock l = new();
            lock (l) { System.Console.Write("L"); }
 
            namespace System.Threading
            {
                public class Lock
                {
                    public Scope EnterScope()
                    {
                        Console.Write("E");
                        return new Scope();
                    }
 
                    public Scope EnterScope(int x)
                    {
                        Console.Write("X");
                        return new Scope();
                    }
 
                    public ref struct Scope
                    {
                        public void Dispose() => Console.Write("D");
                    }
                }
            }
            """;
        CompileAndVerify(source, expectedOutput: "ELD", verify: Verification.FailsILVerify).VerifyDiagnostics();
    }
 
    [Fact]
    public void EnterScopeMultipleOverloads_03()
    {
        var source = """
            System.Threading.Lock l = new();
            lock (l) { System.Console.Write("L"); }
 
            namespace System.Threading
            {
                public class Lock
                {
                    public Scope EnterScope()
                    {
                        Console.Write("E");
                        return new Scope();
                    }
 
                    public Scope EnterScope<T>()
                    {
                        Console.Write("T");
                        return new Scope();
                    }
 
                    public ref struct Scope
                    {
                        public void Dispose() => Console.Write("D");
                    }
                }
            }
            """;
        CompileAndVerify(source, expectedOutput: "ELD", verify: Verification.FailsILVerify).VerifyDiagnostics();
    }
 
    [Fact]
    public void EnterScopeHidden()
    {
        var source = """
            System.Threading.Lock l = new();
            lock (l) { System.Console.Write("L"); }
 
            namespace System.Threading
            {
                public class LockBase
                {
                    public Lock.Scope EnterScope()
                    {
                        Console.Write("B");
                        return new();
                    }
                }
 
                public class Lock : LockBase
                {
                    public new Scope EnterScope()
                    {
                        Console.Write("E");
                        return new();
                    }
 
                    public ref struct Scope
                    {
                        public void Dispose() => Console.Write("D");
                    }
                }
            }
            """;
        CompileAndVerify(source, expectedOutput: "ELD", verify: Verification.FailsILVerify).VerifyDiagnostics();
    }
 
    [Fact]
    public void EnterScopeOverride()
    {
        var source = """
            System.Threading.Lock l = new();
            lock (l) { System.Console.Write("L"); }
 
            namespace System.Threading
            {
                public class LockBase
                {
                    public virtual Lock.Scope EnterScope()
                    {
                        Console.Write("B");
                        return new();
                    }
                }
 
                public class Lock : LockBase
                {
                    public override Scope EnterScope()
                    {
                        Console.Write("E");
                        return new();
                    }
 
                    public ref struct Scope
                    {
                        public void Dispose() => Console.Write("D");
                    }
                }
            }
            """;
        CompileAndVerify(source, expectedOutput: "ELD", verify: Verification.FailsILVerify).VerifyDiagnostics();
    }
 
    [Fact]
    public void EnterScopeVirtual()
    {
        var source = """
            System.Threading.Lock l = new System.Threading.LockDerived();
            lock (l) { System.Console.Write("L"); }
 
            namespace System.Threading
            {
                public class Lock
                {
                    public virtual Scope EnterScope()
                    {
                        Console.Write("E");
                        return new();
                    }
 
                    public ref struct Scope
                    {
                        public void Dispose() => Console.Write("D");
                    }
                }
 
                public class LockDerived : Lock
                {
                    public override Scope EnterScope()
                    {
                        Console.Write("O");
                        return new();
                    }
                }
            }
            """;
        CompileAndVerify(source, expectedOutput: "OLD", verify: Verification.FailsILVerify).VerifyDiagnostics();
    }
 
    [Fact]
    public void EnterScopeExplicitImplementation()
    {
        var source = """
            System.Threading.Lock l = new();
            lock (l) { }
 
            namespace System.Threading
            {
                public interface ILock
                {
                    Lock.Scope EnterScope();
                }
 
                public class Lock : ILock
                {
                    Scope ILock.EnterScope() => new Scope();
 
                    public ref struct Scope
                    {
                        public void Dispose() { }
                    }
                }
            }
            """;
        CreateCompilation(source).VerifyDiagnostics(
            // (2,7): error CS0656: Missing compiler required member 'System.Threading.Lock.EnterScope'
            // lock (l) { }
            Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "l").WithArguments("System.Threading.Lock", "EnterScope").WithLocation(2, 7));
    }
 
    [Fact]
    public void MissingScopeDispose()
    {
        var source = """
            System.Threading.Lock l = new();
            lock (l) { }
 
            namespace System.Threading
            {
                public class Lock
                {
                    public Scope EnterScope() => new Scope();
 
                    public ref struct Scope { }
                }
            }
            """;
        CreateCompilation(source).VerifyDiagnostics(
            // (2,7): error CS0656: Missing compiler required member 'System.Threading.Lock+Scope.Dispose'
            // lock (l) { }
            Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "l").WithArguments("System.Threading.Lock+Scope", "Dispose").WithLocation(2, 7));
    }
 
    [Fact]
    public void ScopeDisposeStatic()
    {
        var source = """
            System.Threading.Lock l = new();
            lock (l) { }
 
            namespace System.Threading
            {
                public class Lock
                {
                    public Scope EnterScope() => new Scope();
 
                    public ref struct Scope
                    {
                        public static void Dispose() { }
                    }
                }
            }
            """;
        CreateCompilation(source).VerifyDiagnostics(
            // (2,7): error CS0656: Missing compiler required member 'System.Threading.Lock+Scope.Dispose'
            // lock (l) { }
            Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "l").WithArguments("System.Threading.Lock+Scope", "Dispose").WithLocation(2, 7));
    }
 
    [Fact]
    public void ScopeDisposeReturnsNonVoid()
    {
        var source = """
            System.Threading.Lock l = new();
            lock (l) { }
 
            namespace System.Threading
            {
                public class Lock
                {
                    public Scope EnterScope() => new Scope();
 
                    public ref struct Scope
                    {
                        public int Dispose() => 1;
                    }
                }
            }
            """;
        CreateCompilation(source).VerifyDiagnostics(
            // (2,7): error CS0656: Missing compiler required member 'System.Threading.Lock+Scope.Dispose'
            // lock (l) { }
            Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "l").WithArguments("System.Threading.Lock+Scope", "Dispose").WithLocation(2, 7));
    }
 
    [Fact]
    public void ScopeDisposeTakesParameters()
    {
        var source = """
            System.Threading.Lock l = new();
            lock (l) { }
 
            namespace System.Threading
            {
                public class Lock
                {
                    public Scope EnterScope() => new Scope();
 
                    public ref struct Scope
                    {
                        public void Dispose(int x) { }
                    }
                }
            }
            """;
        CreateCompilation(source).VerifyDiagnostics(
            // (2,7): error CS0656: Missing compiler required member 'System.Threading.Lock+Scope.Dispose'
            // lock (l) { }
            Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "l").WithArguments("System.Threading.Lock+Scope", "Dispose").WithLocation(2, 7));
    }
 
    [Fact]
    public void ScopeDisposeTakesParameters_Optional()
    {
        var source = """
            System.Threading.Lock l = new();
            lock (l) { }
 
            namespace System.Threading
            {
                public class Lock
                {
                    public Scope EnterScope() => new Scope();
 
                    public ref struct Scope
                    {
                        public void Dispose(int x = 1) { }
                    }
                }
            }
            """;
        CreateCompilation(source).VerifyDiagnostics(
            // (2,7): error CS0656: Missing compiler required member 'System.Threading.Lock+Scope.Dispose'
            // lock (l) { }
            Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "l").WithArguments("System.Threading.Lock+Scope", "Dispose").WithLocation(2, 7));
    }
 
    [Fact]
    public void ScopeDisposeTakesParameters_ParamsArray()
    {
        var source = """
            System.Threading.Lock l = new();
            lock (l) { }
 
            namespace System.Threading
            {
                public class Lock
                {
                    public Scope EnterScope() => new Scope();
 
                    public ref struct Scope
                    {
                        public void Dispose(params int[] xs) { }
                    }
                }
            }
            """;
        CreateCompilation(source).VerifyDiagnostics(
            // (2,7): error CS0656: Missing compiler required member 'System.Threading.Lock+Scope.Dispose'
            // lock (l) { }
            Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "l").WithArguments("System.Threading.Lock+Scope", "Dispose").WithLocation(2, 7));
    }
 
    [Fact]
    public void ScopeDisposeMultipleOverloads_01()
    {
        var source = """
            System.Threading.Lock l = new();
            lock (l) { }
 
            namespace System.Threading
            {
                public class Lock
                {
                    public Scope EnterScope() => new Scope();
 
                    public ref struct Scope
                    {
                        public void Dispose() { }
                        public void Dispose() { }
                    }
                }
            }
            """;
        CreateCompilation(source).VerifyDiagnostics(
            // (2,7): error CS0656: Missing compiler required member 'System.Threading.Lock+Scope.Dispose'
            // lock (l) { }
            Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "l").WithArguments("System.Threading.Lock+Scope", "Dispose").WithLocation(2, 7),
            // (13,25): error CS0111: Type 'Lock.Scope' already defines a member called 'Dispose' with the same parameter types
            //             public void Dispose() { }
            Diagnostic(ErrorCode.ERR_MemberAlreadyExists, "Dispose").WithArguments("Dispose", "System.Threading.Lock.Scope").WithLocation(13, 25));
    }
 
    [Fact]
    public void ScopeDisposeMultipleOverloads_02()
    {
        var source = """
            System.Threading.Lock l = new();
            lock (l) { System.Console.Write("L"); }
 
            namespace System.Threading
            {
                public class Lock
                {
                    public Scope EnterScope()
                    {
                        Console.Write("E");
                        return new Scope();
                    }
 
                    public ref struct Scope
                    {
                        public void Dispose() => Console.Write("D");
                        public void Dispose(int x) => Console.Write("X");
                    }
                }
            }
            """;
        CompileAndVerify(source, expectedOutput: "ELD", verify: Verification.FailsILVerify).VerifyDiagnostics();
    }
 
    [Fact]
    public void ScopeDisposeMultipleOverloads_03()
    {
        var source = """
            System.Threading.Lock l = new();
            lock (l) { System.Console.Write("L"); }
 
            namespace System.Threading
            {
                public class Lock
                {
                    public Scope EnterScope()
                    {
                        Console.Write("E");
                        return new Scope();
                    }
 
                    public ref struct Scope
                    {
                        public void Dispose() => Console.Write("D");
                        public void Dispose<T>() => Console.Write("T");
                    }
                }
            }
            """;
        CompileAndVerify(source, expectedOutput: "ELD", verify: Verification.FailsILVerify).VerifyDiagnostics();
    }
 
    [Fact]
    public void InternalLock()
    {
        var source = """
            static class Program
            {
                static void Main()
                {
                    System.Threading.Lock l = new();
                    lock (l) { System.Console.Write("L"); }
                }
            }
 
            namespace System.Threading
            {
                internal class Lock
                {
                    public Scope EnterScope()
                    {
                        Console.Write("E");
                        return new Scope();
                    }
 
                    public ref struct Scope
                    {
                        public void Dispose()
                        {
                            Console.Write("D");
                        }
                    }
                }
            }
            """;
        var verifier = CompileAndVerify(source, expectedOutput: "ELD", verify: Verification.FailsILVerify);
        verifier.VerifyDiagnostics();
    }
 
    [Fact]
    public void InternalScope()
    {
        var source = """
            System.Threading.Lock l = new();
            lock (l) { }
 
            namespace System.Threading
            {
                public class Lock
                {
                    public Scope EnterScope() => new Scope();
 
                    internal ref struct Scope
                    {
                        public void Dispose() { }
                    }
                }
            }
            """;
        CreateCompilation(source).VerifyDiagnostics(
            // (2,7): error CS0656: Missing compiler required member 'System.Threading.Lock.EnterScope'
            // lock (l) { }
            Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "l").WithArguments("System.Threading.Lock", "EnterScope").WithLocation(2, 7),
            // (8,22): error CS0050: Inconsistent accessibility: return type 'Lock.Scope' is less accessible than method 'Lock.EnterScope()'
            //         public Scope EnterScope() => new Scope();
            Diagnostic(ErrorCode.ERR_BadVisReturnType, "EnterScope").WithArguments("System.Threading.Lock.EnterScope()", "System.Threading.Lock.Scope").WithLocation(8, 22));
    }
 
    [Fact]
    public void Obsolete_EnterScope()
    {
        var source = """
            using System;
            using System.Threading;
 
            Lock l = new();
            lock (l) { Console.Write("1"); }
            using (l.EnterScope()) { Console.Write("2"); }
 
            namespace System.Threading
            {
                public class Lock
                {
                    [System.Obsolete]
                    public Scope EnterScope()
                    {
                        Console.Write("E");
                        return new Scope();
                    }
 
                    public ref struct Scope
                    {
                        public void Dispose() => Console.Write("D");
                    }
                }
            }
            """;
        CompileAndVerify(source, expectedOutput: "E1DE2D", verify: Verification.FailsILVerify).VerifyDiagnostics(
            // (6,8): warning CS0612: 'Lock.EnterScope()' is obsolete
            // using (l.EnterScope()) { Console.Write("2"); }
            Diagnostic(ErrorCode.WRN_DeprecatedSymbol, "l.EnterScope()").WithArguments("System.Threading.Lock.EnterScope()").WithLocation(6, 8));
    }
 
    [Fact]
    public void Obsolete_Lock()
    {
        var source = """
            using System;
            using System.Threading;
 
            Lock l = new();
            lock (l) { Console.Write("1"); }
            using (l.EnterScope()) { Console.Write("2"); }
 
            namespace System.Threading
            {
                [System.Obsolete]
                public class Lock
                {
                    public Scope EnterScope()
                    {
                        Console.Write("E");
                        return new Scope();
                    }
 
                    public ref struct Scope
                    {
                        public void Dispose() => Console.Write("D");
                    }
                }
            }
            """;
        CompileAndVerify(source, expectedOutput: "E1DE2D", verify: Verification.FailsILVerify).VerifyDiagnostics(
            // (4,1): warning CS0612: 'Lock' is obsolete
            // Lock l = new();
            Diagnostic(ErrorCode.WRN_DeprecatedSymbol, "Lock").WithArguments("System.Threading.Lock").WithLocation(4, 1));
    }
 
    [Fact]
    public void Obsolete_Scope()
    {
        var source = """
            using System;
            using System.Threading;
 
            Lock l = new();
            lock (l) { Console.Write("1"); }
            using (l.EnterScope()) { Console.Write("2"); }
 
            namespace System.Threading
            {
                public class Lock
                {
                    public Scope EnterScope()
                    {
                        Console.Write("E");
                        return new Scope();
                    }
            
                    [System.Obsolete]
                    public ref struct Scope
                    {
                        public void Dispose() => Console.Write("D");
                    }
                }
            }
            """;
        CompileAndVerify(source, expectedOutput: "E1DE2D", verify: Verification.FailsILVerify).VerifyDiagnostics(
            // (12,16): warning CS0612: 'Lock.Scope' is obsolete
            //         public Scope EnterScope()
            Diagnostic(ErrorCode.WRN_DeprecatedSymbol, "Scope").WithArguments("System.Threading.Lock.Scope").WithLocation(12, 16),
            // (15,24): warning CS0612: 'Lock.Scope' is obsolete
            //             return new Scope();
            Diagnostic(ErrorCode.WRN_DeprecatedSymbol, "Scope").WithArguments("System.Threading.Lock.Scope").WithLocation(15, 24));
    }
 
    [Fact]
    public void Obsolete_Dispose()
    {
        var source = """
            using System;
            using System.Threading;
 
            Lock l = new();
            lock (l) { Console.Write("1"); }
            using (l.EnterScope()) { Console.Write("2"); }
 
            namespace System.Threading
            {
                public class Lock
                {
                    public Scope EnterScope()
                    {
                        Console.Write("E");
                        return new Scope();
                    }
            
                    public ref struct Scope
                    {
                        [System.Obsolete]
                        public void Dispose() => Console.Write("D");
                    }
                }
            }
            """;
        CompileAndVerify(source, expectedOutput: "E1DE2D", verify: Verification.FailsILVerify).VerifyDiagnostics(
            // (6,8): warning CS0612: 'Lock.Scope.Dispose()' is obsolete
            // using (l.EnterScope()) { Console.Write("2"); }
            Diagnostic(ErrorCode.WRN_DeprecatedSymbol, "l.EnterScope()").WithArguments("System.Threading.Lock.Scope.Dispose()").WithLocation(6, 8));
    }
 
    [Fact]
    public void GenericLock()
    {
        var source = """
            static class Program
            {
                static void Main()
                {
                    System.Threading.Lock<int> l = new();
                    lock (l) { System.Console.Write("L"); }
                }
            }
 
            namespace System.Threading
            {
                public class Lock<T>
                {
                    public Scope EnterScope()
                    {
                        Console.Write("E");
                        return new Scope();
                    }
 
                    public ref struct Scope
                    {
                        public void Dispose()
                        {
                            Console.Write("D");
                        }
                    }
                }
            }
            """;
        var verifier = CompileAndVerify(source, expectedOutput: "L", verify: Verification.FailsILVerify);
        verifier.VerifyDiagnostics();
        // Should use Monitor locking.
        verifier.VerifyIL("Program.Main", """
            {
              // Code size       39 (0x27)
              .maxstack  2
              .locals init (System.Threading.Lock<int> V_0,
                            bool V_1)
              IL_0000:  newobj     "System.Threading.Lock<int>..ctor()"
              IL_0005:  stloc.0
              IL_0006:  ldc.i4.0
              IL_0007:  stloc.1
              .try
              {
                IL_0008:  ldloc.0
                IL_0009:  ldloca.s   V_1
                IL_000b:  call       "void System.Threading.Monitor.Enter(object, ref bool)"
                IL_0010:  ldstr      "L"
                IL_0015:  call       "void System.Console.Write(string)"
                IL_001a:  leave.s    IL_0026
              }
              finally
              {
                IL_001c:  ldloc.1
                IL_001d:  brfalse.s  IL_0025
                IL_001f:  ldloc.0
                IL_0020:  call       "void System.Threading.Monitor.Exit(object)"
                IL_0025:  endfinally
              }
              IL_0026:  ret
            }
            """);
    }
 
    [Fact]
    public void GenericEnterScope()
    {
        var source = """
            System.Threading.Lock l = new();
            lock (l) { }
 
            namespace System.Threading
            {
                public class Lock
                {
                    public Scope EnterScope<T>() => new Scope();
 
                    public ref struct Scope
                    {
                        public void Dispose() { }
                    }
                }
            }
            """;
        CreateCompilation(source).VerifyDiagnostics(
            // (2,7): error CS0656: Missing compiler required member 'System.Threading.Lock.EnterScope'
            // lock (l) { }
            Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "l").WithArguments("System.Threading.Lock", "EnterScope").WithLocation(2, 7));
    }
 
    [Fact]
    public void GenericScope()
    {
        var source = """
            System.Threading.Lock l = new();
            lock (l) { }
 
            namespace System.Threading
            {
                public class Lock
                {
                    public Scope<int> EnterScope() => new Scope<int>();
 
                    public ref struct Scope<T>
                    {
                        public void Dispose() { }
                    }
                }
            }
            """;
        CreateCompilation(source).VerifyDiagnostics(
            // (2,7): error CS0656: Missing compiler required member 'System.Threading.Lock.EnterScope'
            // lock (l) { }
            Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "l").WithArguments("System.Threading.Lock", "EnterScope").WithLocation(2, 7));
    }
 
    [Fact]
    public void LockStruct()
    {
        var source = """
            System.Threading.Lock l = new();
            lock (l) { }
 
            namespace System.Threading
            {
                public struct Lock
                {
                    public Scope EnterScope() => new Scope();
 
                    public ref struct Scope
                    {
                        public void Dispose() { }
                    }
                }
            }
            """;
        CreateCompilation(source).VerifyDiagnostics(
            // (2,7): error CS0185: 'Lock' is not a reference type as required by the lock statement
            // lock (l) { }
            Diagnostic(ErrorCode.ERR_LockNeedsReference, "l").WithArguments("System.Threading.Lock").WithLocation(2, 7));
    }
 
    [Theory, CombinatorialData]
    public void ScopeRegularStruct(bool implementsIDisposable)
    {
        var source = $$"""
            static class Program
            {
                static void Main()
                {
                    System.Threading.Lock l = new();
                    lock (l) { System.Console.Write("L"); }
                }
            }
 
            namespace System.Threading
            {
                public class Lock
                {
                    public Scope EnterScope()
                    {
                        Console.Write("E");
                        return new Scope();
                    }
 
                    public struct Scope {{(implementsIDisposable ? ": IDisposable" : "")}}
                    {
                        public void Dispose()
                        {
                            Console.Write("D");
                        }
                    }
                }
            }
            """;
        CreateCompilation(source).VerifyDiagnostics(
            // (6,15): error CS0656: Missing compiler required member 'System.Threading.Lock.EnterScope'
            //         lock (l) { System.Console.Write("L"); }
            Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "l").WithArguments("System.Threading.Lock", "EnterScope").WithLocation(6, 15));
    }
 
    [Fact]
    public void ScopeMisnamed()
    {
        var source = """
            System.Threading.Lock l = new();
            lock (l) { }
 
            namespace System.Threading
            {
                public class Lock
                {
                    public MyScope EnterScope() => new MyScope();
 
                    public ref struct MyScope
                    {
                        public void Dispose() { }
                    }
                }
            }
            """;
        CreateCompilation(source).VerifyDiagnostics(
            // (2,7): error CS0656: Missing compiler required member 'System.Threading.Lock.EnterScope'
            // lock (l) { }
            Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "l").WithArguments("System.Threading.Lock", "EnterScope").WithLocation(2, 7));
    }
 
    [Fact]
    public void ScopeNotNested()
    {
        var source = """
            System.Threading.Lock l = new();
            lock (l) { }
 
            namespace System.Threading
            {
                public class Lock
                {
                    public Scope EnterScope() => new Scope();
                }
 
                public ref struct Scope
                {
                    public void Dispose() { }
                }
            }
            """;
        CreateCompilation(source).VerifyDiagnostics(
            // (2,7): error CS0656: Missing compiler required member 'System.Threading.Lock.EnterScope'
            // lock (l) { }
            Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "l").WithArguments("System.Threading.Lock", "EnterScope").WithLocation(2, 7));
    }
 
    [Fact]
    public void ScopeClass()
    {
        var source = """
            System.Threading.Lock l = new();
            lock (l) { }
 
            namespace System.Threading
            {
                public class Lock
                {
                    public Scope EnterScope() => new Scope();
 
                    public class Scope
                    {
                        public void Dispose() { }
                    }
                }
            }
            """;
        CreateCompilation(source).VerifyDiagnostics(
            // (2,7): error CS0656: Missing compiler required member 'System.Threading.Lock.EnterScope'
            // lock (l) { }
            Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "l").WithArguments("System.Threading.Lock", "EnterScope").WithLocation(2, 7));
    }
 
    [Fact]
    public void LockInterface()
    {
        var source = """
            static class Program
            {
                static void Main()
                {
                    System.Threading.Lock l = new System.Threading.MyLock();
                    lock (l) { System.Console.Write("L"); }
                }
            }
 
            namespace System.Threading
            {
                public interface Lock
                {
                    Scope EnterScope();
 
                    public ref struct Scope
                    {
                        public void Dispose()
                        {
                            Console.Write("D");
                        }
                    }
                }
            
                public class MyLock : Lock
                {
                    public Lock.Scope EnterScope()
                    {
                        Console.Write("E");
                        return new();
                    }
                }
            }
            """;
        CompileAndVerify(source, expectedOutput: "ELD", verify: Verification.FailsILVerify).VerifyDiagnostics();
    }
 
    [Fact]
    public void LockInterface_DefaultImplementation()
    {
        var source = """
            static class Program
            {
                static void Main()
                {
                    System.Threading.Lock l = new System.Threading.MyLock();
                    lock (l) { System.Console.Write("L"); }
                }
            }
 
            namespace System.Threading
            {
                public interface Lock
                {
                    Scope EnterScope()
                    {
                        Console.Write("I");
                        return new();
                    }
 
                    public ref struct Scope
                    {
                        public void Dispose()
                        {
                            Console.Write("D");
                        }
                    }
                }
            
                public class MyLock : Lock
                {
                    public Lock.Scope EnterScope()
                    {
                        Console.Write("E");
                        return new();
                    }
                }
            }
            """;
        CompileAndVerify(source, expectedOutput: ExecutionConditionUtil.IsMonoOrCoreClr ? "ELD" : null,
            verify: Verification.Fails, targetFramework: TargetFramework.Net60).VerifyDiagnostics();
    }
 
    [Fact]
    public void LockNested()
    {
        var source = """
            static class Program
            {
                static void Main()
                {
                    System.Threading.Container.Lock l = new();
                    lock (l) { System.Console.Write("L"); }
                }
            }
 
            namespace System.Threading
            {
                public class Container
                {
                    public class Lock
                    {
                        public Scope EnterScope()
                        {
                            Console.Write("E");
                            return new Scope();
                        }
 
                        public ref struct Scope
                        {
                            public void Dispose()
                            {
                                Console.Write("D");
                            }
                        }
                    }
                }
            }
            """;
        var verifier = CompileAndVerify(source, expectedOutput: "L", verify: Verification.FailsILVerify);
        verifier.VerifyDiagnostics();
        // Should use Monitor locking.
        verifier.VerifyIL("Program.Main", """
            {
              // Code size       39 (0x27)
              .maxstack  2
              .locals init (System.Threading.Container.Lock V_0,
                            bool V_1)
              IL_0000:  newobj     "System.Threading.Container.Lock..ctor()"
              IL_0005:  stloc.0
              IL_0006:  ldc.i4.0
              IL_0007:  stloc.1
              .try
              {
                IL_0008:  ldloc.0
                IL_0009:  ldloca.s   V_1
                IL_000b:  call       "void System.Threading.Monitor.Enter(object, ref bool)"
                IL_0010:  ldstr      "L"
                IL_0015:  call       "void System.Console.Write(string)"
                IL_001a:  leave.s    IL_0026
              }
              finally
              {
                IL_001c:  ldloc.1
                IL_001d:  brfalse.s  IL_0025
                IL_001f:  ldloc.0
                IL_0020:  call       "void System.Threading.Monitor.Exit(object)"
                IL_0025:  endfinally
              }
              IL_0026:  ret
            }
            """);
    }
 
    [Fact]
    public void LockInWrongNamespace()
    {
        var source = """
            static class Program
            {
                static void Main()
                {
                    Threading.Lock l = new();
                    lock (l) { System.Console.Write("L"); }
                }
            }
 
            namespace Threading
            {
                public class Lock
                {
                    public Scope EnterScope()
                    {
                        System.Console.Write("E");
                        return new Scope();
                    }
 
                    public ref struct Scope
                    {
                        public void Dispose()
                        {
                            System.Console.Write("D");
                        }
                    }
                }
            }
            """;
        var verifier = CompileAndVerify(source, expectedOutput: "L", verify: Verification.FailsILVerify);
        verifier.VerifyDiagnostics();
        // Should use Monitor locking.
        verifier.VerifyIL("Program.Main", """
            {
              // Code size       39 (0x27)
              .maxstack  2
              .locals init (Threading.Lock V_0,
                            bool V_1)
              IL_0000:  newobj     "Threading.Lock..ctor()"
              IL_0005:  stloc.0
              IL_0006:  ldc.i4.0
              IL_0007:  stloc.1
              .try
              {
                IL_0008:  ldloc.0
                IL_0009:  ldloca.s   V_1
                IL_000b:  call       "void System.Threading.Monitor.Enter(object, ref bool)"
                IL_0010:  ldstr      "L"
                IL_0015:  call       "void System.Console.Write(string)"
                IL_001a:  leave.s    IL_0026
              }
              finally
              {
                IL_001c:  ldloc.1
                IL_001d:  brfalse.s  IL_0025
                IL_001f:  ldloc.0
                IL_0020:  call       "void System.Threading.Monitor.Exit(object)"
                IL_0025:  endfinally
              }
              IL_0026:  ret
            }
            """);
    }
 
    [Fact]
    public void ExternalAssembly()
    {
        var lib = CreateCompilation(LockTypeDefinition)
            .VerifyDiagnostics()
            .EmitToImageReference();
        var source = """
            using System;
            using System.Threading;
 
            Lock l = new Lock();
            lock (l) { Console.Write("L"); }
            """;
        var verifier = CompileAndVerify(source, [lib], expectedOutput: "ELD");
        verifier.VerifyDiagnostics();
    }
 
    [Fact]
    public void MultipleLockTypes()
    {
        var source1 = """
            public static class C1
            {
                public static readonly System.Threading.Lock L = new();
            }
 
            namespace System.Threading
            {
                public class Lock
                {
                    public Scope EnterScope()
                    {
                        Console.Write("E1 ");
                        return new Scope();
                    }
 
                    public ref struct Scope
                    {
                        public void Dispose()
                        {
                            Console.Write("D1 ");
                        }
                    }
                }
            }
            """;
        var lib1 = CreateCompilation(source1)
            .VerifyDiagnostics()
            .EmitToImageReference();
 
        var source2 = """
            public static class C2
            {
                public static readonly System.Threading.Lock L = new();
            }
 
 
            namespace System.Threading
            {
                public class Lock
                {
                    public Scope EnterScope()
                    {
                        Console.Write("E2 ");
                        return new Scope();
                    }
 
                    public ref struct Scope
                    {
                        public void Dispose()
                        {
                            Console.Write("D2 ");
                        }
                    }
                }
            }
            """;
        var lib2 = CreateCompilation(source2)
            .VerifyDiagnostics()
            .EmitToImageReference();
 
        var source = """
            using System;
 
            static class Program
            {
                static void Main()
                {
                    M1();
                    M2();
                }
 
                static void M1()
                {
                    var l1 = C1.L;
                    lock (l1) { Console.Write("L1 "); }
                }
 
                static void M2()
                {
                    var l2 = C2.L;
                    lock (l2) { Console.Write("L2 "); }
                }
            }
            """;
        var verifier = CompileAndVerify(source, [lib1, lib2], expectedOutput: "E1 L1 D1 E2 L2 D2");
        verifier.VerifyDiagnostics();
    }
 
    [Fact]
    public void LangVersion()
    {
        var source = """
            using System;
            using System.Threading;
 
            Lock l = new Lock();
            lock (l) { Console.Write("L"); }
            """;
 
        CSharpTestSource sources = [source, LockTypeDefinition];
 
        CreateCompilation(sources, parseOptions: TestOptions.Regular12).VerifyDiagnostics(
            // (5,7): error CS9202: Feature 'Lock object' is not available in C# 12.0. Please use language version 13.0 or greater.
            // lock (l) { Console.Write("L"); }
            Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion12, "l").WithArguments("Lock object", "13.0").WithLocation(5, 7));
 
        var expectedOutput = "ELD";
 
        CompileAndVerify(sources, parseOptions: TestOptions.RegularPreview, expectedOutput: expectedOutput,
            verify: Verification.FailsILVerify).VerifyDiagnostics();
        CompileAndVerify(sources, expectedOutput: expectedOutput,
            verify: Verification.FailsILVerify).VerifyDiagnostics();
    }
 
    [Fact]
    public void InPlace()
    {
        var source = """
            using System;
            using System.Threading;
 
            lock (new Lock())
            {
                Console.Write("L");
            }
            """;
        var verifier = CompileAndVerify([source, LockTypeDefinition], verify: Verification.FailsILVerify,
           expectedOutput: "ELD");
        verifier.VerifyDiagnostics();
    }
 
    [Fact]
    public void EmbeddedStatement()
    {
        var source = """
            using System;
            using System.Threading;
 
            lock (new Lock()) Console.Write("L");
            """;
        var verifier = CompileAndVerify([source, LockTypeDefinition], verify: Verification.FailsILVerify,
           expectedOutput: "ELD");
        verifier.VerifyDiagnostics();
    }
 
    [Fact]
    public void EmptyStatement()
    {
        var source = """
            using System.Threading;
 
            lock (new Lock()) ;
            """;
        var verifier = CompileAndVerify([source, LockTypeDefinition], verify: Verification.FailsILVerify,
           expectedOutput: "ED");
        verifier.VerifyDiagnostics(
            // (3,19): warning CS0642: Possible mistaken empty statement
            // lock (new Lock()) ;
            Diagnostic(ErrorCode.WRN_PossibleMistakenNullStatement, ";").WithLocation(3, 19));
    }
 
    [Fact]
    public void Nullable_01()
    {
        var source = """
            #nullable enable
            using System;
            using System.Threading;
 
            static class C
            {
                static void Main()
                {
                    M(new Lock());
                }
 
                static void M(Lock? l)
                {
                    lock (l) { Console.Write("1"); }
                    lock (l) { Console.Write("2"); }
                }
            }
            """;
        var verifier = CompileAndVerify([source, LockTypeDefinition], verify: Verification.FailsILVerify,
           expectedOutput: "E1DE2D");
        verifier.VerifyDiagnostics(
            // (14,15): warning CS8602: Dereference of a possibly null reference.
            //         lock (l) { Console.Write("1"); }
            Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "l").WithLocation(14, 15));
    }
 
    [Fact]
    public void Nullable_02()
    {
        var source = """
            #nullable enable
            using System.Threading;
 
            static class C
            {
                static void Main()
                {
                    M(new Lock());
                }
 
                static void M(Lock? l)
                {
                    lock (l)
                    {
                        l.EnterScope();
                    }
                }
            }
            """;
        var verifier = CompileAndVerify([source, LockTypeDefinition], verify: Verification.FailsILVerify,
           expectedOutput: "EED");
        verifier.VerifyDiagnostics(
            // (13,15): warning CS8602: Dereference of a possibly null reference.
            //         lock (l)
            Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "l").WithLocation(13, 15));
    }
 
    [Theory, CombinatorialData]
    public void Null([CombinatorialValues("null", "default")] string expr)
    {
        var source = $$"""
            #nullable enable
            static class C
            {
                static void Main()
                {
                    try
                    {
                        M();
                    }
                    catch (System.NullReferenceException)
                    {
                        System.Console.Write("caught");
                    }
                }
                static void M()
                {
                    lock ((System.Threading.Lock){{expr}}) { }
                }
            }
            """;
        var verifier = CompileAndVerify([source, LockTypeDefinition], verify: Verification.FailsILVerify,
            expectedOutput: "caught");
        verifier.VerifyDiagnostics(
            // (17,15): warning CS8600: Converting null literal or possible null value to non-nullable type.
            //         lock ((System.Threading.Lock)null) { }
            Diagnostic(ErrorCode.WRN_ConvertingNullableToNonNullable, $"(System.Threading.Lock){expr}").WithLocation(17, 15),
            // (17,15): warning CS8602: Dereference of a possibly null reference.
            //         lock ((System.Threading.Lock)null) { }
            Diagnostic(ErrorCode.WRN_NullReferenceReceiver, $"(System.Threading.Lock){expr}").WithLocation(17, 15));
        verifier.VerifyIL("C.M", """
            {
              // Code size       18 (0x12)
              .maxstack  1
              .locals init (System.Threading.Lock.Scope V_0)
              IL_0000:  ldnull
              IL_0001:  callvirt   "System.Threading.Lock.Scope System.Threading.Lock.EnterScope()"
              IL_0006:  stloc.0
              .try
              {
                IL_0007:  leave.s    IL_0011
              }
              finally
              {
                IL_0009:  ldloca.s   V_0
                IL_000b:  call       "void System.Threading.Lock.Scope.Dispose()"
                IL_0010:  endfinally
              }
              IL_0011:  ret
            }
            """);
    }
 
    [Fact]
    public void ObjectEquality()
    {
        var source = """
            #nullable enable
            using System;
            using System.Threading;
 
            static class C
            {
                static void Main()
                {
                    Lock? l = new();
                    if (l != null)
                    {
                        lock (l) { Console.Write("1"); }
                    }
                    if (l == null)
                    {
                        throw null!;
                    }
                    if (l is { })
                    {
                        lock (l) { Console.Write("2"); }
                    }
                    if (l is { } l2)
                    {
                        lock (l2) { Console.Write("3"); }
                    }
                    if (l is not { })
                    {
                        throw null!;
                    }
                    if (l is null)
                    {
                        throw null!;
                    }
                    if (l is not null)
                    {
                        lock (l) { Console.Write("4"); }
                    }
                    if (l is not null and var l3)
                    {
                        lock (l3) { Console.Write("5"); }
                    }
                    if (null != l)
                    {
                        lock (l) { Console.Write("6"); }
                    }
                    if (null == l)
                    {
                        throw null!;
                    }
                    if (!(l == null))
                    {
                        lock (l) { Console.Write("7"); }
                    }
                    if (!(l != null))
                    {
                        throw null!;
                    }
 
                    Lock? l4 = new();
                    if (l == l4)
                    {
                        throw null!;
                    }
                    if (l != l4)
                    {
                        lock (l4) { Console.Write("8"); }
                    }
                    if (ReferenceEquals(l, l4))
                    {
                        throw null!;
                    }
                    if (((object)l) == l4)
                    {
                        throw null!;
                    }
                    if (l == new Lock())
                    {
                        throw null!;
                    }
                }
            }
            """;
        var verifier = CompileAndVerify([source, LockTypeDefinition], verify: Verification.FailsILVerify,
            expectedOutput: "E1DE2DE3DE4DE5DE6DE7DE8D");
        verifier.VerifyDiagnostics(
            // (68,29): warning CS9216: A value of type 'System.Threading.Lock' converted to a different type will use likely unintended monitor-based locking in 'lock' statement.
            //         if (ReferenceEquals(l, l4))
            Diagnostic(ErrorCode.WRN_ConvertingLock, "l").WithLocation(68, 29),
            // (68,32): warning CS9216: A value of type 'System.Threading.Lock' converted to a different type will use likely unintended monitor-based locking in 'lock' statement.
            //         if (ReferenceEquals(l, l4))
            Diagnostic(ErrorCode.WRN_ConvertingLock, "l4").WithLocation(68, 32),
            // (72,22): warning CS9216: A value of type 'System.Threading.Lock' converted to a different type will use likely unintended monitor-based locking in 'lock' statement.
            //         if (((object)l) == l4)
            Diagnostic(ErrorCode.WRN_ConvertingLock, "l").WithLocation(72, 22));
    }
 
    [Fact]
    public void Await()
    {
        var source = """
            using System.Threading;
            using System.Threading.Tasks;
 
            lock (new Lock())
            {
                await Task.Yield();
            }
            """;
        CreateCompilation([source, LockTypeDefinition]).VerifyDiagnostics(
            // (6,5): error CS1996: Cannot await in the body of a lock statement
            //     await Task.Yield();
            Diagnostic(ErrorCode.ERR_BadAwaitInLock, "await Task.Yield()").WithLocation(6, 5));
    }
 
    [Fact]
    public void AsyncMethod()
    {
        var source = """
            #pragma warning disable 1998 // async method lacks 'await' operators
            using System.Threading;
            using System.Threading.Tasks;
 
            class C
            {
                static async Task Main()
                {
                    lock (new Lock()) { System.Console.Write("L"); }
                }
            }
            """;
        var expectedOutput = "ELD";
        var verifier = CompileAndVerify([source, LockTypeDefinition], options: TestOptions.DebugExe,
            expectedOutput: expectedOutput, verify: Verification.FailsILVerify);
        verifier.VerifyDiagnostics();
        verifier.VerifyIL("C.<Main>d__0.System.Runtime.CompilerServices.IAsyncStateMachine.MoveNext", """
            {
              // Code size       94 (0x5e)
              .maxstack  2
              .locals init (int V_0,
                            System.Threading.Lock.Scope V_1,
                            System.Exception V_2)
              IL_0000:  ldarg.0
              IL_0001:  ldfld      "int C.<Main>d__0.<>1__state"
              IL_0006:  stloc.0
              .try
              {
                IL_0007:  nop
                IL_0008:  newobj     "System.Threading.Lock..ctor()"
                IL_000d:  call       "System.Threading.Lock.Scope System.Threading.Lock.EnterScope()"
                IL_0012:  stloc.1
                .try
                {
                  IL_0013:  nop
                  IL_0014:  ldstr      "L"
                  IL_0019:  call       "void System.Console.Write(string)"
                  IL_001e:  nop
                  IL_001f:  nop
                  IL_0020:  leave.s    IL_002f
                }
                finally
                {
                  IL_0022:  ldloc.0
                  IL_0023:  ldc.i4.0
                  IL_0024:  bge.s      IL_002e
                  IL_0026:  ldloca.s   V_1
                  IL_0028:  call       "void System.Threading.Lock.Scope.Dispose()"
                  IL_002d:  nop
                  IL_002e:  endfinally
                }
                IL_002f:  leave.s    IL_0049
              }
              catch System.Exception
              {
                IL_0031:  stloc.2
                IL_0032:  ldarg.0
                IL_0033:  ldc.i4.s   -2
                IL_0035:  stfld      "int C.<Main>d__0.<>1__state"
                IL_003a:  ldarg.0
                IL_003b:  ldflda     "System.Runtime.CompilerServices.AsyncTaskMethodBuilder C.<Main>d__0.<>t__builder"
                IL_0040:  ldloc.2
                IL_0041:  call       "void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetException(System.Exception)"
                IL_0046:  nop
                IL_0047:  leave.s    IL_005d
              }
              IL_0049:  ldarg.0
              IL_004a:  ldc.i4.s   -2
              IL_004c:  stfld      "int C.<Main>d__0.<>1__state"
              IL_0051:  ldarg.0
              IL_0052:  ldflda     "System.Runtime.CompilerServices.AsyncTaskMethodBuilder C.<Main>d__0.<>t__builder"
              IL_0057:  call       "void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetResult()"
              IL_005c:  nop
              IL_005d:  ret
            }
            """);
 
        verifier = CompileAndVerify([source, LockTypeDefinition], options: TestOptions.ReleaseExe,
            expectedOutput: expectedOutput, verify: Verification.FailsILVerify);
        verifier.VerifyDiagnostics();
        verifier.VerifyIL("C.<Main>d__0.System.Runtime.CompilerServices.IAsyncStateMachine.MoveNext", """
            {
              // Code size       87 (0x57)
              .maxstack  2
              .locals init (int V_0,
                            System.Threading.Lock.Scope V_1,
                            System.Exception V_2)
              IL_0000:  ldarg.0
              IL_0001:  ldfld      "int C.<Main>d__0.<>1__state"
              IL_0006:  stloc.0
              .try
              {
                IL_0007:  newobj     "System.Threading.Lock..ctor()"
                IL_000c:  call       "System.Threading.Lock.Scope System.Threading.Lock.EnterScope()"
                IL_0011:  stloc.1
                .try
                {
                  IL_0012:  ldstr      "L"
                  IL_0017:  call       "void System.Console.Write(string)"
                  IL_001c:  leave.s    IL_002a
                }
                finally
                {
                  IL_001e:  ldloc.0
                  IL_001f:  ldc.i4.0
                  IL_0020:  bge.s      IL_0029
                  IL_0022:  ldloca.s   V_1
                  IL_0024:  call       "void System.Threading.Lock.Scope.Dispose()"
                  IL_0029:  endfinally
                }
                IL_002a:  leave.s    IL_0043
              }
              catch System.Exception
              {
                IL_002c:  stloc.2
                IL_002d:  ldarg.0
                IL_002e:  ldc.i4.s   -2
                IL_0030:  stfld      "int C.<Main>d__0.<>1__state"
                IL_0035:  ldarg.0
                IL_0036:  ldflda     "System.Runtime.CompilerServices.AsyncTaskMethodBuilder C.<Main>d__0.<>t__builder"
                IL_003b:  ldloc.2
                IL_003c:  call       "void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetException(System.Exception)"
                IL_0041:  leave.s    IL_0056
              }
              IL_0043:  ldarg.0
              IL_0044:  ldc.i4.s   -2
              IL_0046:  stfld      "int C.<Main>d__0.<>1__state"
              IL_004b:  ldarg.0
              IL_004c:  ldflda     "System.Runtime.CompilerServices.AsyncTaskMethodBuilder C.<Main>d__0.<>t__builder"
              IL_0051:  call       "void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetResult()"
              IL_0056:  ret
            }
            """);
    }
 
    [Fact]
    public void AsyncMethod_WithAwait()
    {
        var source = """
            using System.Threading;
            using System.Threading.Tasks;
 
            class C
            {
                static async Task Main()
                {
                    await Task.Yield();
                    lock (new Lock()) { System.Console.Write("L"); }
                    await Task.Yield();
                }
            }
            """;
        var expectedOutput = "ELD";
        var verifier = CompileAndVerify([source, LockTypeDefinition], options: TestOptions.DebugExe,
            expectedOutput: expectedOutput, verify: Verification.FailsILVerify);
        verifier.VerifyDiagnostics();
        verifier.VerifyIL("C.<Main>d__0.System.Runtime.CompilerServices.IAsyncStateMachine.MoveNext", """
            {
              // Code size      311 (0x137)
              .maxstack  3
              .locals init (int V_0,
                            System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter V_1,
                            System.Runtime.CompilerServices.YieldAwaitable V_2,
                            C.<Main>d__0 V_3,
                            System.Threading.Lock.Scope V_4,
                            System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter V_5,
                            System.Exception V_6)
              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_0058
                IL_0014:  br         IL_00e1
                IL_0019:  nop
                IL_001a:  call       "System.Runtime.CompilerServices.YieldAwaitable System.Threading.Tasks.Task.Yield()"
                IL_001f:  stloc.2
                IL_0020:  ldloca.s   V_2
                IL_0022:  call       "System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter System.Runtime.CompilerServices.YieldAwaitable.GetAwaiter()"
                IL_0027:  stloc.1
                IL_0028:  ldloca.s   V_1
                IL_002a:  call       "bool System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter.IsCompleted.get"
                IL_002f:  brtrue.s   IL_0074
                IL_0031:  ldarg.0
                IL_0032:  ldc.i4.0
                IL_0033:  dup
                IL_0034:  stloc.0
                IL_0035:  stfld      "int C.<Main>d__0.<>1__state"
                IL_003a:  ldarg.0
                IL_003b:  ldloc.1
                IL_003c:  stfld      "System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter C.<Main>d__0.<>u__1"
                IL_0041:  ldarg.0
                IL_0042:  stloc.3
                IL_0043:  ldarg.0
                IL_0044:  ldflda     "System.Runtime.CompilerServices.AsyncTaskMethodBuilder C.<Main>d__0.<>t__builder"
                IL_0049:  ldloca.s   V_1
                IL_004b:  ldloca.s   V_3
                IL_004d:  call       "void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.AwaitUnsafeOnCompleted<System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter, C.<Main>d__0>(ref System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter, ref C.<Main>d__0)"
                IL_0052:  nop
                IL_0053:  leave      IL_0136
                IL_0058:  ldarg.0
                IL_0059:  ldfld      "System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter C.<Main>d__0.<>u__1"
                IL_005e:  stloc.1
                IL_005f:  ldarg.0
                IL_0060:  ldflda     "System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter C.<Main>d__0.<>u__1"
                IL_0065:  initobj    "System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter"
                IL_006b:  ldarg.0
                IL_006c:  ldc.i4.m1
                IL_006d:  dup
                IL_006e:  stloc.0
                IL_006f:  stfld      "int C.<Main>d__0.<>1__state"
                IL_0074:  ldloca.s   V_1
                IL_0076:  call       "void System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter.GetResult()"
                IL_007b:  nop
                IL_007c:  newobj     "System.Threading.Lock..ctor()"
                IL_0081:  call       "System.Threading.Lock.Scope System.Threading.Lock.EnterScope()"
                IL_0086:  stloc.s    V_4
                .try
                {
                  IL_0088:  nop
                  IL_0089:  ldstr      "L"
                  IL_008e:  call       "void System.Console.Write(string)"
                  IL_0093:  nop
                  IL_0094:  nop
                  IL_0095:  leave.s    IL_00a4
                }
                finally
                {
                  IL_0097:  ldloc.0
                  IL_0098:  ldc.i4.0
                  IL_0099:  bge.s      IL_00a3
                  IL_009b:  ldloca.s   V_4
                  IL_009d:  call       "void System.Threading.Lock.Scope.Dispose()"
                  IL_00a2:  nop
                  IL_00a3:  endfinally
                }
                IL_00a4:  call       "System.Runtime.CompilerServices.YieldAwaitable System.Threading.Tasks.Task.Yield()"
                IL_00a9:  stloc.2
                IL_00aa:  ldloca.s   V_2
                IL_00ac:  call       "System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter System.Runtime.CompilerServices.YieldAwaitable.GetAwaiter()"
                IL_00b1:  stloc.s    V_5
                IL_00b3:  ldloca.s   V_5
                IL_00b5:  call       "bool System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter.IsCompleted.get"
                IL_00ba:  brtrue.s   IL_00fe
                IL_00bc:  ldarg.0
                IL_00bd:  ldc.i4.1
                IL_00be:  dup
                IL_00bf:  stloc.0
                IL_00c0:  stfld      "int C.<Main>d__0.<>1__state"
                IL_00c5:  ldarg.0
                IL_00c6:  ldloc.s    V_5
                IL_00c8:  stfld      "System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter C.<Main>d__0.<>u__1"
                IL_00cd:  ldarg.0
                IL_00ce:  stloc.3
                IL_00cf:  ldarg.0
                IL_00d0:  ldflda     "System.Runtime.CompilerServices.AsyncTaskMethodBuilder C.<Main>d__0.<>t__builder"
                IL_00d5:  ldloca.s   V_5
                IL_00d7:  ldloca.s   V_3
                IL_00d9:  call       "void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.AwaitUnsafeOnCompleted<System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter, C.<Main>d__0>(ref System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter, ref C.<Main>d__0)"
                IL_00de:  nop
                IL_00df:  leave.s    IL_0136
                IL_00e1:  ldarg.0
                IL_00e2:  ldfld      "System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter C.<Main>d__0.<>u__1"
                IL_00e7:  stloc.s    V_5
                IL_00e9:  ldarg.0
                IL_00ea:  ldflda     "System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter C.<Main>d__0.<>u__1"
                IL_00ef:  initobj    "System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter"
                IL_00f5:  ldarg.0
                IL_00f6:  ldc.i4.m1
                IL_00f7:  dup
                IL_00f8:  stloc.0
                IL_00f9:  stfld      "int C.<Main>d__0.<>1__state"
                IL_00fe:  ldloca.s   V_5
                IL_0100:  call       "void System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter.GetResult()"
                IL_0105:  nop
                IL_0106:  leave.s    IL_0122
              }
              catch System.Exception
              {
                IL_0108:  stloc.s    V_6
                IL_010a:  ldarg.0
                IL_010b:  ldc.i4.s   -2
                IL_010d:  stfld      "int C.<Main>d__0.<>1__state"
                IL_0112:  ldarg.0
                IL_0113:  ldflda     "System.Runtime.CompilerServices.AsyncTaskMethodBuilder C.<Main>d__0.<>t__builder"
                IL_0118:  ldloc.s    V_6
                IL_011a:  call       "void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetException(System.Exception)"
                IL_011f:  nop
                IL_0120:  leave.s    IL_0136
              }
              IL_0122:  ldarg.0
              IL_0123:  ldc.i4.s   -2
              IL_0125:  stfld      "int C.<Main>d__0.<>1__state"
              IL_012a:  ldarg.0
              IL_012b:  ldflda     "System.Runtime.CompilerServices.AsyncTaskMethodBuilder C.<Main>d__0.<>t__builder"
              IL_0130:  call       "void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetResult()"
              IL_0135:  nop
              IL_0136:  ret
            }
            """);
 
        verifier = CompileAndVerify([source, LockTypeDefinition], options: TestOptions.ReleaseExe,
            expectedOutput: expectedOutput, verify: Verification.FailsILVerify);
        verifier.VerifyDiagnostics();
        verifier.VerifyIL("C.<Main>d__0.System.Runtime.CompilerServices.IAsyncStateMachine.MoveNext", """
            {
              // Code size      282 (0x11a)
              .maxstack  3
              .locals init (int V_0,
                            System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter V_1,
                            System.Runtime.CompilerServices.YieldAwaitable V_2,
                            System.Threading.Lock.Scope V_3,
                            System.Exception V_4)
              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_004b
                IL_000a:  ldloc.0
                IL_000b:  ldc.i4.1
                IL_000c:  beq        IL_00c8
                IL_0011:  call       "System.Runtime.CompilerServices.YieldAwaitable System.Threading.Tasks.Task.Yield()"
                IL_0016:  stloc.2
                IL_0017:  ldloca.s   V_2
                IL_0019:  call       "System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter System.Runtime.CompilerServices.YieldAwaitable.GetAwaiter()"
                IL_001e:  stloc.1
                IL_001f:  ldloca.s   V_1
                IL_0021:  call       "bool System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter.IsCompleted.get"
                IL_0026:  brtrue.s   IL_0067
                IL_0028:  ldarg.0
                IL_0029:  ldc.i4.0
                IL_002a:  dup
                IL_002b:  stloc.0
                IL_002c:  stfld      "int C.<Main>d__0.<>1__state"
                IL_0031:  ldarg.0
                IL_0032:  ldloc.1
                IL_0033:  stfld      "System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter C.<Main>d__0.<>u__1"
                IL_0038:  ldarg.0
                IL_0039:  ldflda     "System.Runtime.CompilerServices.AsyncTaskMethodBuilder C.<Main>d__0.<>t__builder"
                IL_003e:  ldloca.s   V_1
                IL_0040:  ldarg.0
                IL_0041:  call       "void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.AwaitUnsafeOnCompleted<System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter, C.<Main>d__0>(ref System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter, ref C.<Main>d__0)"
                IL_0046:  leave      IL_0119
                IL_004b:  ldarg.0
                IL_004c:  ldfld      "System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter C.<Main>d__0.<>u__1"
                IL_0051:  stloc.1
                IL_0052:  ldarg.0
                IL_0053:  ldflda     "System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter C.<Main>d__0.<>u__1"
                IL_0058:  initobj    "System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter"
                IL_005e:  ldarg.0
                IL_005f:  ldc.i4.m1
                IL_0060:  dup
                IL_0061:  stloc.0
                IL_0062:  stfld      "int C.<Main>d__0.<>1__state"
                IL_0067:  ldloca.s   V_1
                IL_0069:  call       "void System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter.GetResult()"
                IL_006e:  newobj     "System.Threading.Lock..ctor()"
                IL_0073:  call       "System.Threading.Lock.Scope System.Threading.Lock.EnterScope()"
                IL_0078:  stloc.3
                .try
                {
                  IL_0079:  ldstr      "L"
                  IL_007e:  call       "void System.Console.Write(string)"
                  IL_0083:  leave.s    IL_0091
                }
                finally
                {
                  IL_0085:  ldloc.0
                  IL_0086:  ldc.i4.0
                  IL_0087:  bge.s      IL_0090
                  IL_0089:  ldloca.s   V_3
                  IL_008b:  call       "void System.Threading.Lock.Scope.Dispose()"
                  IL_0090:  endfinally
                }
                IL_0091:  call       "System.Runtime.CompilerServices.YieldAwaitable System.Threading.Tasks.Task.Yield()"
                IL_0096:  stloc.2
                IL_0097:  ldloca.s   V_2
                IL_0099:  call       "System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter System.Runtime.CompilerServices.YieldAwaitable.GetAwaiter()"
                IL_009e:  stloc.1
                IL_009f:  ldloca.s   V_1
                IL_00a1:  call       "bool System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter.IsCompleted.get"
                IL_00a6:  brtrue.s   IL_00e4
                IL_00a8:  ldarg.0
                IL_00a9:  ldc.i4.1
                IL_00aa:  dup
                IL_00ab:  stloc.0
                IL_00ac:  stfld      "int C.<Main>d__0.<>1__state"
                IL_00b1:  ldarg.0
                IL_00b2:  ldloc.1
                IL_00b3:  stfld      "System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter C.<Main>d__0.<>u__1"
                IL_00b8:  ldarg.0
                IL_00b9:  ldflda     "System.Runtime.CompilerServices.AsyncTaskMethodBuilder C.<Main>d__0.<>t__builder"
                IL_00be:  ldloca.s   V_1
                IL_00c0:  ldarg.0
                IL_00c1:  call       "void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.AwaitUnsafeOnCompleted<System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter, C.<Main>d__0>(ref System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter, ref C.<Main>d__0)"
                IL_00c6:  leave.s    IL_0119
                IL_00c8:  ldarg.0
                IL_00c9:  ldfld      "System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter C.<Main>d__0.<>u__1"
                IL_00ce:  stloc.1
                IL_00cf:  ldarg.0
                IL_00d0:  ldflda     "System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter C.<Main>d__0.<>u__1"
                IL_00d5:  initobj    "System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter"
                IL_00db:  ldarg.0
                IL_00dc:  ldc.i4.m1
                IL_00dd:  dup
                IL_00de:  stloc.0
                IL_00df:  stfld      "int C.<Main>d__0.<>1__state"
                IL_00e4:  ldloca.s   V_1
                IL_00e6:  call       "void System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter.GetResult()"
                IL_00eb:  leave.s    IL_0106
              }
              catch System.Exception
              {
                IL_00ed:  stloc.s    V_4
                IL_00ef:  ldarg.0
                IL_00f0:  ldc.i4.s   -2
                IL_00f2:  stfld      "int C.<Main>d__0.<>1__state"
                IL_00f7:  ldarg.0
                IL_00f8:  ldflda     "System.Runtime.CompilerServices.AsyncTaskMethodBuilder C.<Main>d__0.<>t__builder"
                IL_00fd:  ldloc.s    V_4
                IL_00ff:  call       "void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetException(System.Exception)"
                IL_0104:  leave.s    IL_0119
              }
              IL_0106:  ldarg.0
              IL_0107:  ldc.i4.s   -2
              IL_0109:  stfld      "int C.<Main>d__0.<>1__state"
              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:  ret
            }
            """);
    }
 
    [Fact]
    public void AsyncMethod_AwaitResource()
    {
        var source = """
            #pragma warning disable 1998 // async method lacks 'await' operators
            using System.Threading;
            using System.Threading.Tasks;
 
            class C
            {
                static async Task Main()
                {
                    lock (await GetLock()) { System.Console.Write("L"); }
                }
 
                static async Task<Lock> GetLock() => new Lock();
            }
            """;
        var expectedOutput = "ELD";
        var verifier = CompileAndVerify([source, LockTypeDefinition], options: TestOptions.DebugExe,
            expectedOutput: expectedOutput, verify: Verification.FailsILVerify);
        verifier.VerifyDiagnostics();
        verifier.VerifyIL("C.<Main>d__0.System.Runtime.CompilerServices.IAsyncStateMachine.MoveNext", """
            {
              // Code size      211 (0xd3)
              .maxstack  3
              .locals init (int V_0,
                            System.Threading.Lock.Scope V_1,
                            System.Runtime.CompilerServices.TaskAwaiter<System.Threading.Lock> V_2,
                            C.<Main>d__0 V_3,
                            System.Exception V_4)
              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_000c
                IL_000a:  br.s       IL_000e
                IL_000c:  br.s       IL_004a
                IL_000e:  nop
                IL_000f:  call       "System.Threading.Tasks.Task<System.Threading.Lock> C.GetLock()"
                IL_0014:  callvirt   "System.Runtime.CompilerServices.TaskAwaiter<System.Threading.Lock> System.Threading.Tasks.Task<System.Threading.Lock>.GetAwaiter()"
                IL_0019:  stloc.2
                IL_001a:  ldloca.s   V_2
                IL_001c:  call       "bool System.Runtime.CompilerServices.TaskAwaiter<System.Threading.Lock>.IsCompleted.get"
                IL_0021:  brtrue.s   IL_0066
                IL_0023:  ldarg.0
                IL_0024:  ldc.i4.0
                IL_0025:  dup
                IL_0026:  stloc.0
                IL_0027:  stfld      "int C.<Main>d__0.<>1__state"
                IL_002c:  ldarg.0
                IL_002d:  ldloc.2
                IL_002e:  stfld      "System.Runtime.CompilerServices.TaskAwaiter<System.Threading.Lock> C.<Main>d__0.<>u__1"
                IL_0033:  ldarg.0
                IL_0034:  stloc.3
                IL_0035:  ldarg.0
                IL_0036:  ldflda     "System.Runtime.CompilerServices.AsyncTaskMethodBuilder C.<Main>d__0.<>t__builder"
                IL_003b:  ldloca.s   V_2
                IL_003d:  ldloca.s   V_3
                IL_003f:  call       "void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.AwaitUnsafeOnCompleted<System.Runtime.CompilerServices.TaskAwaiter<System.Threading.Lock>, C.<Main>d__0>(ref System.Runtime.CompilerServices.TaskAwaiter<System.Threading.Lock>, ref C.<Main>d__0)"
                IL_0044:  nop
                IL_0045:  leave      IL_00d2
                IL_004a:  ldarg.0
                IL_004b:  ldfld      "System.Runtime.CompilerServices.TaskAwaiter<System.Threading.Lock> C.<Main>d__0.<>u__1"
                IL_0050:  stloc.2
                IL_0051:  ldarg.0
                IL_0052:  ldflda     "System.Runtime.CompilerServices.TaskAwaiter<System.Threading.Lock> C.<Main>d__0.<>u__1"
                IL_0057:  initobj    "System.Runtime.CompilerServices.TaskAwaiter<System.Threading.Lock>"
                IL_005d:  ldarg.0
                IL_005e:  ldc.i4.m1
                IL_005f:  dup
                IL_0060:  stloc.0
                IL_0061:  stfld      "int C.<Main>d__0.<>1__state"
                IL_0066:  ldarg.0
                IL_0067:  ldloca.s   V_2
                IL_0069:  call       "System.Threading.Lock System.Runtime.CompilerServices.TaskAwaiter<System.Threading.Lock>.GetResult()"
                IL_006e:  stfld      "System.Threading.Lock C.<Main>d__0.<>s__1"
                IL_0073:  ldarg.0
                IL_0074:  ldfld      "System.Threading.Lock C.<Main>d__0.<>s__1"
                IL_0079:  callvirt   "System.Threading.Lock.Scope System.Threading.Lock.EnterScope()"
                IL_007e:  stloc.1
                IL_007f:  ldarg.0
                IL_0080:  ldnull
                IL_0081:  stfld      "System.Threading.Lock C.<Main>d__0.<>s__1"
                .try
                {
                  IL_0086:  nop
                  IL_0087:  ldstr      "L"
                  IL_008c:  call       "void System.Console.Write(string)"
                  IL_0091:  nop
                  IL_0092:  nop
                  IL_0093:  leave.s    IL_00a2
                }
                finally
                {
                  IL_0095:  ldloc.0
                  IL_0096:  ldc.i4.0
                  IL_0097:  bge.s      IL_00a1
                  IL_0099:  ldloca.s   V_1
                  IL_009b:  call       "void System.Threading.Lock.Scope.Dispose()"
                  IL_00a0:  nop
                  IL_00a1:  endfinally
                }
                IL_00a2:  leave.s    IL_00be
              }
              catch System.Exception
              {
                IL_00a4:  stloc.s    V_4
                IL_00a6:  ldarg.0
                IL_00a7:  ldc.i4.s   -2
                IL_00a9:  stfld      "int C.<Main>d__0.<>1__state"
                IL_00ae:  ldarg.0
                IL_00af:  ldflda     "System.Runtime.CompilerServices.AsyncTaskMethodBuilder C.<Main>d__0.<>t__builder"
                IL_00b4:  ldloc.s    V_4
                IL_00b6:  call       "void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetException(System.Exception)"
                IL_00bb:  nop
                IL_00bc:  leave.s    IL_00d2
              }
              IL_00be:  ldarg.0
              IL_00bf:  ldc.i4.s   -2
              IL_00c1:  stfld      "int C.<Main>d__0.<>1__state"
              IL_00c6:  ldarg.0
              IL_00c7:  ldflda     "System.Runtime.CompilerServices.AsyncTaskMethodBuilder C.<Main>d__0.<>t__builder"
              IL_00cc:  call       "void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetResult()"
              IL_00d1:  nop
              IL_00d2:  ret
            }
            """);
 
        verifier = CompileAndVerify([source, LockTypeDefinition], options: TestOptions.ReleaseExe,
            expectedOutput: expectedOutput, verify: Verification.FailsILVerify);
        verifier.VerifyDiagnostics();
        verifier.VerifyIL("C.<Main>d__0.System.Runtime.CompilerServices.IAsyncStateMachine.MoveNext", """
            {
              // Code size      172 (0xac)
              .maxstack  3
              .locals init (int V_0,
                            System.Threading.Lock.Scope V_1,
                            System.Runtime.CompilerServices.TaskAwaiter<System.Threading.Lock> V_2,
                            System.Exception V_3)
              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_003e
                IL_000a:  call       "System.Threading.Tasks.Task<System.Threading.Lock> C.GetLock()"
                IL_000f:  callvirt   "System.Runtime.CompilerServices.TaskAwaiter<System.Threading.Lock> System.Threading.Tasks.Task<System.Threading.Lock>.GetAwaiter()"
                IL_0014:  stloc.2
                IL_0015:  ldloca.s   V_2
                IL_0017:  call       "bool System.Runtime.CompilerServices.TaskAwaiter<System.Threading.Lock>.IsCompleted.get"
                IL_001c:  brtrue.s   IL_005a
                IL_001e:  ldarg.0
                IL_001f:  ldc.i4.0
                IL_0020:  dup
                IL_0021:  stloc.0
                IL_0022:  stfld      "int C.<Main>d__0.<>1__state"
                IL_0027:  ldarg.0
                IL_0028:  ldloc.2
                IL_0029:  stfld      "System.Runtime.CompilerServices.TaskAwaiter<System.Threading.Lock> C.<Main>d__0.<>u__1"
                IL_002e:  ldarg.0
                IL_002f:  ldflda     "System.Runtime.CompilerServices.AsyncTaskMethodBuilder C.<Main>d__0.<>t__builder"
                IL_0034:  ldloca.s   V_2
                IL_0036:  ldarg.0
                IL_0037:  call       "void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.AwaitUnsafeOnCompleted<System.Runtime.CompilerServices.TaskAwaiter<System.Threading.Lock>, C.<Main>d__0>(ref System.Runtime.CompilerServices.TaskAwaiter<System.Threading.Lock>, ref C.<Main>d__0)"
                IL_003c:  leave.s    IL_00ab
                IL_003e:  ldarg.0
                IL_003f:  ldfld      "System.Runtime.CompilerServices.TaskAwaiter<System.Threading.Lock> C.<Main>d__0.<>u__1"
                IL_0044:  stloc.2
                IL_0045:  ldarg.0
                IL_0046:  ldflda     "System.Runtime.CompilerServices.TaskAwaiter<System.Threading.Lock> C.<Main>d__0.<>u__1"
                IL_004b:  initobj    "System.Runtime.CompilerServices.TaskAwaiter<System.Threading.Lock>"
                IL_0051:  ldarg.0
                IL_0052:  ldc.i4.m1
                IL_0053:  dup
                IL_0054:  stloc.0
                IL_0055:  stfld      "int C.<Main>d__0.<>1__state"
                IL_005a:  ldloca.s   V_2
                IL_005c:  call       "System.Threading.Lock System.Runtime.CompilerServices.TaskAwaiter<System.Threading.Lock>.GetResult()"
                IL_0061:  callvirt   "System.Threading.Lock.Scope System.Threading.Lock.EnterScope()"
                IL_0066:  stloc.1
                .try
                {
                  IL_0067:  ldstr      "L"
                  IL_006c:  call       "void System.Console.Write(string)"
                  IL_0071:  leave.s    IL_007f
                }
                finally
                {
                  IL_0073:  ldloc.0
                  IL_0074:  ldc.i4.0
                  IL_0075:  bge.s      IL_007e
                  IL_0077:  ldloca.s   V_1
                  IL_0079:  call       "void System.Threading.Lock.Scope.Dispose()"
                  IL_007e:  endfinally
                }
                IL_007f:  leave.s    IL_0098
              }
              catch System.Exception
              {
                IL_0081:  stloc.3
                IL_0082:  ldarg.0
                IL_0083:  ldc.i4.s   -2
                IL_0085:  stfld      "int C.<Main>d__0.<>1__state"
                IL_008a:  ldarg.0
                IL_008b:  ldflda     "System.Runtime.CompilerServices.AsyncTaskMethodBuilder C.<Main>d__0.<>t__builder"
                IL_0090:  ldloc.3
                IL_0091:  call       "void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetException(System.Exception)"
                IL_0096:  leave.s    IL_00ab
              }
              IL_0098:  ldarg.0
              IL_0099:  ldc.i4.s   -2
              IL_009b:  stfld      "int C.<Main>d__0.<>1__state"
              IL_00a0:  ldarg.0
              IL_00a1:  ldflda     "System.Runtime.CompilerServices.AsyncTaskMethodBuilder C.<Main>d__0.<>t__builder"
              IL_00a6:  call       "void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetResult()"
              IL_00ab:  ret
            }
            """);
    }
 
    [Fact]
    public void AsyncLocalFunction()
    {
        var source = """
            #pragma warning disable 1998 // async method lacks 'await' operators
            using System.Threading;
 
            async void local()
            {
                lock (new Lock()) { System.Console.Write("L"); }
            }
 
            local();
            """;
        var expectedOutput = "ELD";
        var verifier = CompileAndVerify([source, LockTypeDefinition], options: TestOptions.DebugExe,
            expectedOutput: expectedOutput, verify: Verification.FailsILVerify);
        verifier.VerifyDiagnostics();
        verifier.VerifyIL("Program.<<<Main>$>g__local|0_0>d.System.Runtime.CompilerServices.IAsyncStateMachine.MoveNext", """
            {
              // Code size       94 (0x5e)
              .maxstack  2
              .locals init (int V_0,
                            System.Threading.Lock.Scope V_1,
                            System.Exception V_2)
              IL_0000:  ldarg.0
              IL_0001:  ldfld      "int Program.<<<Main>$>g__local|0_0>d.<>1__state"
              IL_0006:  stloc.0
              .try
              {
                IL_0007:  nop
                IL_0008:  newobj     "System.Threading.Lock..ctor()"
                IL_000d:  call       "System.Threading.Lock.Scope System.Threading.Lock.EnterScope()"
                IL_0012:  stloc.1
                .try
                {
                  IL_0013:  nop
                  IL_0014:  ldstr      "L"
                  IL_0019:  call       "void System.Console.Write(string)"
                  IL_001e:  nop
                  IL_001f:  nop
                  IL_0020:  leave.s    IL_002f
                }
                finally
                {
                  IL_0022:  ldloc.0
                  IL_0023:  ldc.i4.0
                  IL_0024:  bge.s      IL_002e
                  IL_0026:  ldloca.s   V_1
                  IL_0028:  call       "void System.Threading.Lock.Scope.Dispose()"
                  IL_002d:  nop
                  IL_002e:  endfinally
                }
                IL_002f:  leave.s    IL_0049
              }
              catch System.Exception
              {
                IL_0031:  stloc.2
                IL_0032:  ldarg.0
                IL_0033:  ldc.i4.s   -2
                IL_0035:  stfld      "int Program.<<<Main>$>g__local|0_0>d.<>1__state"
                IL_003a:  ldarg.0
                IL_003b:  ldflda     "System.Runtime.CompilerServices.AsyncVoidMethodBuilder Program.<<<Main>$>g__local|0_0>d.<>t__builder"
                IL_0040:  ldloc.2
                IL_0041:  call       "void System.Runtime.CompilerServices.AsyncVoidMethodBuilder.SetException(System.Exception)"
                IL_0046:  nop
                IL_0047:  leave.s    IL_005d
              }
              IL_0049:  ldarg.0
              IL_004a:  ldc.i4.s   -2
              IL_004c:  stfld      "int Program.<<<Main>$>g__local|0_0>d.<>1__state"
              IL_0051:  ldarg.0
              IL_0052:  ldflda     "System.Runtime.CompilerServices.AsyncVoidMethodBuilder Program.<<<Main>$>g__local|0_0>d.<>t__builder"
              IL_0057:  call       "void System.Runtime.CompilerServices.AsyncVoidMethodBuilder.SetResult()"
              IL_005c:  nop
              IL_005d:  ret
            }
            """);
 
        verifier = CompileAndVerify([source, LockTypeDefinition], options: TestOptions.ReleaseExe,
            expectedOutput: expectedOutput, verify: Verification.FailsILVerify);
        verifier.VerifyDiagnostics();
        verifier.VerifyIL("Program.<<<Main>$>g__local|0_0>d.System.Runtime.CompilerServices.IAsyncStateMachine.MoveNext", """
            {
              // Code size       87 (0x57)
              .maxstack  2
              .locals init (int V_0,
                            System.Threading.Lock.Scope V_1,
                            System.Exception V_2)
              IL_0000:  ldarg.0
              IL_0001:  ldfld      "int Program.<<<Main>$>g__local|0_0>d.<>1__state"
              IL_0006:  stloc.0
              .try
              {
                IL_0007:  newobj     "System.Threading.Lock..ctor()"
                IL_000c:  call       "System.Threading.Lock.Scope System.Threading.Lock.EnterScope()"
                IL_0011:  stloc.1
                .try
                {
                  IL_0012:  ldstr      "L"
                  IL_0017:  call       "void System.Console.Write(string)"
                  IL_001c:  leave.s    IL_002a
                }
                finally
                {
                  IL_001e:  ldloc.0
                  IL_001f:  ldc.i4.0
                  IL_0020:  bge.s      IL_0029
                  IL_0022:  ldloca.s   V_1
                  IL_0024:  call       "void System.Threading.Lock.Scope.Dispose()"
                  IL_0029:  endfinally
                }
                IL_002a:  leave.s    IL_0043
              }
              catch System.Exception
              {
                IL_002c:  stloc.2
                IL_002d:  ldarg.0
                IL_002e:  ldc.i4.s   -2
                IL_0030:  stfld      "int Program.<<<Main>$>g__local|0_0>d.<>1__state"
                IL_0035:  ldarg.0
                IL_0036:  ldflda     "System.Runtime.CompilerServices.AsyncVoidMethodBuilder Program.<<<Main>$>g__local|0_0>d.<>t__builder"
                IL_003b:  ldloc.2
                IL_003c:  call       "void System.Runtime.CompilerServices.AsyncVoidMethodBuilder.SetException(System.Exception)"
                IL_0041:  leave.s    IL_0056
              }
              IL_0043:  ldarg.0
              IL_0044:  ldc.i4.s   -2
              IL_0046:  stfld      "int Program.<<<Main>$>g__local|0_0>d.<>1__state"
              IL_004b:  ldarg.0
              IL_004c:  ldflda     "System.Runtime.CompilerServices.AsyncVoidMethodBuilder Program.<<<Main>$>g__local|0_0>d.<>t__builder"
              IL_0051:  call       "void System.Runtime.CompilerServices.AsyncVoidMethodBuilder.SetResult()"
              IL_0056:  ret
            }
            """);
    }
 
    [Fact]
    public void AsyncLocalFunction_WithAwait()
    {
        var source = """
            using System.Threading;
            using System.Threading.Tasks;
 
            async Task local()
            {
                await Task.Yield();
                lock (new Lock()) { System.Console.Write("L"); }
                await Task.Yield();
            }
 
            await local();
            """;
        var expectedOutput = "ELD";
        var verifier = CompileAndVerify([source, LockTypeDefinition], options: TestOptions.DebugExe,
            expectedOutput: expectedOutput, verify: Verification.FailsILVerify);
        verifier.VerifyDiagnostics();
        verifier.VerifyIL("Program.<<<Main>$>g__local|0_0>d.System.Runtime.CompilerServices.IAsyncStateMachine.MoveNext", """
            {
              // Code size      311 (0x137)
              .maxstack  3
              .locals init (int V_0,
                            System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter V_1,
                            System.Runtime.CompilerServices.YieldAwaitable V_2,
                            Program.<<<Main>$>g__local|0_0>d V_3,
                            System.Threading.Lock.Scope V_4,
                            System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter V_5,
                            System.Exception V_6)
              IL_0000:  ldarg.0
              IL_0001:  ldfld      "int Program.<<<Main>$>g__local|0_0>d.<>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_0058
                IL_0014:  br         IL_00e1
                IL_0019:  nop
                IL_001a:  call       "System.Runtime.CompilerServices.YieldAwaitable System.Threading.Tasks.Task.Yield()"
                IL_001f:  stloc.2
                IL_0020:  ldloca.s   V_2
                IL_0022:  call       "System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter System.Runtime.CompilerServices.YieldAwaitable.GetAwaiter()"
                IL_0027:  stloc.1
                IL_0028:  ldloca.s   V_1
                IL_002a:  call       "bool System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter.IsCompleted.get"
                IL_002f:  brtrue.s   IL_0074
                IL_0031:  ldarg.0
                IL_0032:  ldc.i4.0
                IL_0033:  dup
                IL_0034:  stloc.0
                IL_0035:  stfld      "int Program.<<<Main>$>g__local|0_0>d.<>1__state"
                IL_003a:  ldarg.0
                IL_003b:  ldloc.1
                IL_003c:  stfld      "System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter Program.<<<Main>$>g__local|0_0>d.<>u__1"
                IL_0041:  ldarg.0
                IL_0042:  stloc.3
                IL_0043:  ldarg.0
                IL_0044:  ldflda     "System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.<<<Main>$>g__local|0_0>d.<>t__builder"
                IL_0049:  ldloca.s   V_1
                IL_004b:  ldloca.s   V_3
                IL_004d:  call       "void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.AwaitUnsafeOnCompleted<System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter, Program.<<<Main>$>g__local|0_0>d>(ref System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter, ref Program.<<<Main>$>g__local|0_0>d)"
                IL_0052:  nop
                IL_0053:  leave      IL_0136
                IL_0058:  ldarg.0
                IL_0059:  ldfld      "System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter Program.<<<Main>$>g__local|0_0>d.<>u__1"
                IL_005e:  stloc.1
                IL_005f:  ldarg.0
                IL_0060:  ldflda     "System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter Program.<<<Main>$>g__local|0_0>d.<>u__1"
                IL_0065:  initobj    "System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter"
                IL_006b:  ldarg.0
                IL_006c:  ldc.i4.m1
                IL_006d:  dup
                IL_006e:  stloc.0
                IL_006f:  stfld      "int Program.<<<Main>$>g__local|0_0>d.<>1__state"
                IL_0074:  ldloca.s   V_1
                IL_0076:  call       "void System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter.GetResult()"
                IL_007b:  nop
                IL_007c:  newobj     "System.Threading.Lock..ctor()"
                IL_0081:  call       "System.Threading.Lock.Scope System.Threading.Lock.EnterScope()"
                IL_0086:  stloc.s    V_4
                .try
                {
                  IL_0088:  nop
                  IL_0089:  ldstr      "L"
                  IL_008e:  call       "void System.Console.Write(string)"
                  IL_0093:  nop
                  IL_0094:  nop
                  IL_0095:  leave.s    IL_00a4
                }
                finally
                {
                  IL_0097:  ldloc.0
                  IL_0098:  ldc.i4.0
                  IL_0099:  bge.s      IL_00a3
                  IL_009b:  ldloca.s   V_4
                  IL_009d:  call       "void System.Threading.Lock.Scope.Dispose()"
                  IL_00a2:  nop
                  IL_00a3:  endfinally
                }
                IL_00a4:  call       "System.Runtime.CompilerServices.YieldAwaitable System.Threading.Tasks.Task.Yield()"
                IL_00a9:  stloc.2
                IL_00aa:  ldloca.s   V_2
                IL_00ac:  call       "System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter System.Runtime.CompilerServices.YieldAwaitable.GetAwaiter()"
                IL_00b1:  stloc.s    V_5
                IL_00b3:  ldloca.s   V_5
                IL_00b5:  call       "bool System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter.IsCompleted.get"
                IL_00ba:  brtrue.s   IL_00fe
                IL_00bc:  ldarg.0
                IL_00bd:  ldc.i4.1
                IL_00be:  dup
                IL_00bf:  stloc.0
                IL_00c0:  stfld      "int Program.<<<Main>$>g__local|0_0>d.<>1__state"
                IL_00c5:  ldarg.0
                IL_00c6:  ldloc.s    V_5
                IL_00c8:  stfld      "System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter Program.<<<Main>$>g__local|0_0>d.<>u__1"
                IL_00cd:  ldarg.0
                IL_00ce:  stloc.3
                IL_00cf:  ldarg.0
                IL_00d0:  ldflda     "System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.<<<Main>$>g__local|0_0>d.<>t__builder"
                IL_00d5:  ldloca.s   V_5
                IL_00d7:  ldloca.s   V_3
                IL_00d9:  call       "void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.AwaitUnsafeOnCompleted<System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter, Program.<<<Main>$>g__local|0_0>d>(ref System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter, ref Program.<<<Main>$>g__local|0_0>d)"
                IL_00de:  nop
                IL_00df:  leave.s    IL_0136
                IL_00e1:  ldarg.0
                IL_00e2:  ldfld      "System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter Program.<<<Main>$>g__local|0_0>d.<>u__1"
                IL_00e7:  stloc.s    V_5
                IL_00e9:  ldarg.0
                IL_00ea:  ldflda     "System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter Program.<<<Main>$>g__local|0_0>d.<>u__1"
                IL_00ef:  initobj    "System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter"
                IL_00f5:  ldarg.0
                IL_00f6:  ldc.i4.m1
                IL_00f7:  dup
                IL_00f8:  stloc.0
                IL_00f9:  stfld      "int Program.<<<Main>$>g__local|0_0>d.<>1__state"
                IL_00fe:  ldloca.s   V_5
                IL_0100:  call       "void System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter.GetResult()"
                IL_0105:  nop
                IL_0106:  leave.s    IL_0122
              }
              catch System.Exception
              {
                IL_0108:  stloc.s    V_6
                IL_010a:  ldarg.0
                IL_010b:  ldc.i4.s   -2
                IL_010d:  stfld      "int Program.<<<Main>$>g__local|0_0>d.<>1__state"
                IL_0112:  ldarg.0
                IL_0113:  ldflda     "System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.<<<Main>$>g__local|0_0>d.<>t__builder"
                IL_0118:  ldloc.s    V_6
                IL_011a:  call       "void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetException(System.Exception)"
                IL_011f:  nop
                IL_0120:  leave.s    IL_0136
              }
              IL_0122:  ldarg.0
              IL_0123:  ldc.i4.s   -2
              IL_0125:  stfld      "int Program.<<<Main>$>g__local|0_0>d.<>1__state"
              IL_012a:  ldarg.0
              IL_012b:  ldflda     "System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.<<<Main>$>g__local|0_0>d.<>t__builder"
              IL_0130:  call       "void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetResult()"
              IL_0135:  nop
              IL_0136:  ret
            }
            """);
 
        verifier = CompileAndVerify([source, LockTypeDefinition], options: TestOptions.ReleaseExe,
            expectedOutput: expectedOutput, verify: Verification.FailsILVerify);
        verifier.VerifyDiagnostics();
        verifier.VerifyIL("Program.<<<Main>$>g__local|0_0>d.System.Runtime.CompilerServices.IAsyncStateMachine.MoveNext", """
            {
              // Code size      282 (0x11a)
              .maxstack  3
              .locals init (int V_0,
                            System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter V_1,
                            System.Runtime.CompilerServices.YieldAwaitable V_2,
                            System.Threading.Lock.Scope V_3,
                            System.Exception V_4)
              IL_0000:  ldarg.0
              IL_0001:  ldfld      "int Program.<<<Main>$>g__local|0_0>d.<>1__state"
              IL_0006:  stloc.0
              .try
              {
                IL_0007:  ldloc.0
                IL_0008:  brfalse.s  IL_004b
                IL_000a:  ldloc.0
                IL_000b:  ldc.i4.1
                IL_000c:  beq        IL_00c8
                IL_0011:  call       "System.Runtime.CompilerServices.YieldAwaitable System.Threading.Tasks.Task.Yield()"
                IL_0016:  stloc.2
                IL_0017:  ldloca.s   V_2
                IL_0019:  call       "System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter System.Runtime.CompilerServices.YieldAwaitable.GetAwaiter()"
                IL_001e:  stloc.1
                IL_001f:  ldloca.s   V_1
                IL_0021:  call       "bool System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter.IsCompleted.get"
                IL_0026:  brtrue.s   IL_0067
                IL_0028:  ldarg.0
                IL_0029:  ldc.i4.0
                IL_002a:  dup
                IL_002b:  stloc.0
                IL_002c:  stfld      "int Program.<<<Main>$>g__local|0_0>d.<>1__state"
                IL_0031:  ldarg.0
                IL_0032:  ldloc.1
                IL_0033:  stfld      "System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter Program.<<<Main>$>g__local|0_0>d.<>u__1"
                IL_0038:  ldarg.0
                IL_0039:  ldflda     "System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.<<<Main>$>g__local|0_0>d.<>t__builder"
                IL_003e:  ldloca.s   V_1
                IL_0040:  ldarg.0
                IL_0041:  call       "void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.AwaitUnsafeOnCompleted<System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter, Program.<<<Main>$>g__local|0_0>d>(ref System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter, ref Program.<<<Main>$>g__local|0_0>d)"
                IL_0046:  leave      IL_0119
                IL_004b:  ldarg.0
                IL_004c:  ldfld      "System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter Program.<<<Main>$>g__local|0_0>d.<>u__1"
                IL_0051:  stloc.1
                IL_0052:  ldarg.0
                IL_0053:  ldflda     "System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter Program.<<<Main>$>g__local|0_0>d.<>u__1"
                IL_0058:  initobj    "System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter"
                IL_005e:  ldarg.0
                IL_005f:  ldc.i4.m1
                IL_0060:  dup
                IL_0061:  stloc.0
                IL_0062:  stfld      "int Program.<<<Main>$>g__local|0_0>d.<>1__state"
                IL_0067:  ldloca.s   V_1
                IL_0069:  call       "void System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter.GetResult()"
                IL_006e:  newobj     "System.Threading.Lock..ctor()"
                IL_0073:  call       "System.Threading.Lock.Scope System.Threading.Lock.EnterScope()"
                IL_0078:  stloc.3
                .try
                {
                  IL_0079:  ldstr      "L"
                  IL_007e:  call       "void System.Console.Write(string)"
                  IL_0083:  leave.s    IL_0091
                }
                finally
                {
                  IL_0085:  ldloc.0
                  IL_0086:  ldc.i4.0
                  IL_0087:  bge.s      IL_0090
                  IL_0089:  ldloca.s   V_3
                  IL_008b:  call       "void System.Threading.Lock.Scope.Dispose()"
                  IL_0090:  endfinally
                }
                IL_0091:  call       "System.Runtime.CompilerServices.YieldAwaitable System.Threading.Tasks.Task.Yield()"
                IL_0096:  stloc.2
                IL_0097:  ldloca.s   V_2
                IL_0099:  call       "System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter System.Runtime.CompilerServices.YieldAwaitable.GetAwaiter()"
                IL_009e:  stloc.1
                IL_009f:  ldloca.s   V_1
                IL_00a1:  call       "bool System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter.IsCompleted.get"
                IL_00a6:  brtrue.s   IL_00e4
                IL_00a8:  ldarg.0
                IL_00a9:  ldc.i4.1
                IL_00aa:  dup
                IL_00ab:  stloc.0
                IL_00ac:  stfld      "int Program.<<<Main>$>g__local|0_0>d.<>1__state"
                IL_00b1:  ldarg.0
                IL_00b2:  ldloc.1
                IL_00b3:  stfld      "System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter Program.<<<Main>$>g__local|0_0>d.<>u__1"
                IL_00b8:  ldarg.0
                IL_00b9:  ldflda     "System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.<<<Main>$>g__local|0_0>d.<>t__builder"
                IL_00be:  ldloca.s   V_1
                IL_00c0:  ldarg.0
                IL_00c1:  call       "void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.AwaitUnsafeOnCompleted<System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter, Program.<<<Main>$>g__local|0_0>d>(ref System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter, ref Program.<<<Main>$>g__local|0_0>d)"
                IL_00c6:  leave.s    IL_0119
                IL_00c8:  ldarg.0
                IL_00c9:  ldfld      "System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter Program.<<<Main>$>g__local|0_0>d.<>u__1"
                IL_00ce:  stloc.1
                IL_00cf:  ldarg.0
                IL_00d0:  ldflda     "System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter Program.<<<Main>$>g__local|0_0>d.<>u__1"
                IL_00d5:  initobj    "System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter"
                IL_00db:  ldarg.0
                IL_00dc:  ldc.i4.m1
                IL_00dd:  dup
                IL_00de:  stloc.0
                IL_00df:  stfld      "int Program.<<<Main>$>g__local|0_0>d.<>1__state"
                IL_00e4:  ldloca.s   V_1
                IL_00e6:  call       "void System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter.GetResult()"
                IL_00eb:  leave.s    IL_0106
              }
              catch System.Exception
              {
                IL_00ed:  stloc.s    V_4
                IL_00ef:  ldarg.0
                IL_00f0:  ldc.i4.s   -2
                IL_00f2:  stfld      "int Program.<<<Main>$>g__local|0_0>d.<>1__state"
                IL_00f7:  ldarg.0
                IL_00f8:  ldflda     "System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.<<<Main>$>g__local|0_0>d.<>t__builder"
                IL_00fd:  ldloc.s    V_4
                IL_00ff:  call       "void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetException(System.Exception)"
                IL_0104:  leave.s    IL_0119
              }
              IL_0106:  ldarg.0
              IL_0107:  ldc.i4.s   -2
              IL_0109:  stfld      "int Program.<<<Main>$>g__local|0_0>d.<>1__state"
              IL_010e:  ldarg.0
              IL_010f:  ldflda     "System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.<<<Main>$>g__local|0_0>d.<>t__builder"
              IL_0114:  call       "void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetResult()"
              IL_0119:  ret
            }
            """);
    }
 
    [Fact]
    public void AsyncLambda()
    {
        var source = """
            #pragma warning disable 1998 // async method lacks 'await' operators
            using System.Threading;
 
            var lam = async () =>
            {
                lock (new Lock()) { System.Console.Write("L"); }
            };
 
            await lam();
            """;
        var expectedOutput = "ELD";
        var verifier = CompileAndVerify([source, LockTypeDefinition], options: TestOptions.DebugExe,
            expectedOutput: expectedOutput, verify: Verification.FailsILVerify);
        verifier.VerifyDiagnostics();
        verifier.VerifyIL("Program.<>c.<<<Main>$>b__0_0>d.System.Runtime.CompilerServices.IAsyncStateMachine.MoveNext", """
            {
              // Code size       94 (0x5e)
              .maxstack  2
              .locals init (int V_0,
                            System.Threading.Lock.Scope V_1,
                            System.Exception V_2)
              IL_0000:  ldarg.0
              IL_0001:  ldfld      "int Program.<>c.<<<Main>$>b__0_0>d.<>1__state"
              IL_0006:  stloc.0
              .try
              {
                IL_0007:  nop
                IL_0008:  newobj     "System.Threading.Lock..ctor()"
                IL_000d:  call       "System.Threading.Lock.Scope System.Threading.Lock.EnterScope()"
                IL_0012:  stloc.1
                .try
                {
                  IL_0013:  nop
                  IL_0014:  ldstr      "L"
                  IL_0019:  call       "void System.Console.Write(string)"
                  IL_001e:  nop
                  IL_001f:  nop
                  IL_0020:  leave.s    IL_002f
                }
                finally
                {
                  IL_0022:  ldloc.0
                  IL_0023:  ldc.i4.0
                  IL_0024:  bge.s      IL_002e
                  IL_0026:  ldloca.s   V_1
                  IL_0028:  call       "void System.Threading.Lock.Scope.Dispose()"
                  IL_002d:  nop
                  IL_002e:  endfinally
                }
                IL_002f:  leave.s    IL_0049
              }
              catch System.Exception
              {
                IL_0031:  stloc.2
                IL_0032:  ldarg.0
                IL_0033:  ldc.i4.s   -2
                IL_0035:  stfld      "int Program.<>c.<<<Main>$>b__0_0>d.<>1__state"
                IL_003a:  ldarg.0
                IL_003b:  ldflda     "System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.<>c.<<<Main>$>b__0_0>d.<>t__builder"
                IL_0040:  ldloc.2
                IL_0041:  call       "void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetException(System.Exception)"
                IL_0046:  nop
                IL_0047:  leave.s    IL_005d
              }
              IL_0049:  ldarg.0
              IL_004a:  ldc.i4.s   -2
              IL_004c:  stfld      "int Program.<>c.<<<Main>$>b__0_0>d.<>1__state"
              IL_0051:  ldarg.0
              IL_0052:  ldflda     "System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.<>c.<<<Main>$>b__0_0>d.<>t__builder"
              IL_0057:  call       "void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetResult()"
              IL_005c:  nop
              IL_005d:  ret
            }
            """);
 
        verifier = CompileAndVerify([source, LockTypeDefinition], options: TestOptions.ReleaseExe,
            expectedOutput: expectedOutput, verify: Verification.FailsILVerify);
        verifier.VerifyDiagnostics();
        verifier.VerifyIL("Program.<>c.<<<Main>$>b__0_0>d.System.Runtime.CompilerServices.IAsyncStateMachine.MoveNext", """
            {
              // Code size       87 (0x57)
              .maxstack  2
              .locals init (int V_0,
                            System.Threading.Lock.Scope V_1,
                            System.Exception V_2)
              IL_0000:  ldarg.0
              IL_0001:  ldfld      "int Program.<>c.<<<Main>$>b__0_0>d.<>1__state"
              IL_0006:  stloc.0
              .try
              {
                IL_0007:  newobj     "System.Threading.Lock..ctor()"
                IL_000c:  call       "System.Threading.Lock.Scope System.Threading.Lock.EnterScope()"
                IL_0011:  stloc.1
                .try
                {
                  IL_0012:  ldstr      "L"
                  IL_0017:  call       "void System.Console.Write(string)"
                  IL_001c:  leave.s    IL_002a
                }
                finally
                {
                  IL_001e:  ldloc.0
                  IL_001f:  ldc.i4.0
                  IL_0020:  bge.s      IL_0029
                  IL_0022:  ldloca.s   V_1
                  IL_0024:  call       "void System.Threading.Lock.Scope.Dispose()"
                  IL_0029:  endfinally
                }
                IL_002a:  leave.s    IL_0043
              }
              catch System.Exception
              {
                IL_002c:  stloc.2
                IL_002d:  ldarg.0
                IL_002e:  ldc.i4.s   -2
                IL_0030:  stfld      "int Program.<>c.<<<Main>$>b__0_0>d.<>1__state"
                IL_0035:  ldarg.0
                IL_0036:  ldflda     "System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.<>c.<<<Main>$>b__0_0>d.<>t__builder"
                IL_003b:  ldloc.2
                IL_003c:  call       "void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetException(System.Exception)"
                IL_0041:  leave.s    IL_0056
              }
              IL_0043:  ldarg.0
              IL_0044:  ldc.i4.s   -2
              IL_0046:  stfld      "int Program.<>c.<<<Main>$>b__0_0>d.<>1__state"
              IL_004b:  ldarg.0
              IL_004c:  ldflda     "System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.<>c.<<<Main>$>b__0_0>d.<>t__builder"
              IL_0051:  call       "void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetResult()"
              IL_0056:  ret
            }
            """);
    }
 
    [Fact]
    public void AsyncLambda_WithAwait()
    {
        var source = """
            using System.Threading;
            using System.Threading.Tasks;
 
            var lam = async () =>
            {
                await Task.Yield();
                lock (new Lock()) { System.Console.Write("L"); }
                await Task.Yield();
            };
 
            await lam();
            """;
        var expectedOutput = "ELD";
        var verifier = CompileAndVerify([source, LockTypeDefinition], options: TestOptions.DebugExe,
            expectedOutput: expectedOutput, verify: Verification.FailsILVerify);
        verifier.VerifyDiagnostics();
        verifier.VerifyIL("Program.<>c.<<<Main>$>b__0_0>d.System.Runtime.CompilerServices.IAsyncStateMachine.MoveNext", """
            {
              // Code size      311 (0x137)
              .maxstack  3
              .locals init (int V_0,
                            System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter V_1,
                            System.Runtime.CompilerServices.YieldAwaitable V_2,
                            Program.<>c.<<<Main>$>b__0_0>d V_3,
                            System.Threading.Lock.Scope V_4,
                            System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter V_5,
                            System.Exception V_6)
              IL_0000:  ldarg.0
              IL_0001:  ldfld      "int Program.<>c.<<<Main>$>b__0_0>d.<>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_0058
                IL_0014:  br         IL_00e1
                IL_0019:  nop
                IL_001a:  call       "System.Runtime.CompilerServices.YieldAwaitable System.Threading.Tasks.Task.Yield()"
                IL_001f:  stloc.2
                IL_0020:  ldloca.s   V_2
                IL_0022:  call       "System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter System.Runtime.CompilerServices.YieldAwaitable.GetAwaiter()"
                IL_0027:  stloc.1
                IL_0028:  ldloca.s   V_1
                IL_002a:  call       "bool System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter.IsCompleted.get"
                IL_002f:  brtrue.s   IL_0074
                IL_0031:  ldarg.0
                IL_0032:  ldc.i4.0
                IL_0033:  dup
                IL_0034:  stloc.0
                IL_0035:  stfld      "int Program.<>c.<<<Main>$>b__0_0>d.<>1__state"
                IL_003a:  ldarg.0
                IL_003b:  ldloc.1
                IL_003c:  stfld      "System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter Program.<>c.<<<Main>$>b__0_0>d.<>u__1"
                IL_0041:  ldarg.0
                IL_0042:  stloc.3
                IL_0043:  ldarg.0
                IL_0044:  ldflda     "System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.<>c.<<<Main>$>b__0_0>d.<>t__builder"
                IL_0049:  ldloca.s   V_1
                IL_004b:  ldloca.s   V_3
                IL_004d:  call       "void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.AwaitUnsafeOnCompleted<System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter, Program.<>c.<<<Main>$>b__0_0>d>(ref System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter, ref Program.<>c.<<<Main>$>b__0_0>d)"
                IL_0052:  nop
                IL_0053:  leave      IL_0136
                IL_0058:  ldarg.0
                IL_0059:  ldfld      "System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter Program.<>c.<<<Main>$>b__0_0>d.<>u__1"
                IL_005e:  stloc.1
                IL_005f:  ldarg.0
                IL_0060:  ldflda     "System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter Program.<>c.<<<Main>$>b__0_0>d.<>u__1"
                IL_0065:  initobj    "System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter"
                IL_006b:  ldarg.0
                IL_006c:  ldc.i4.m1
                IL_006d:  dup
                IL_006e:  stloc.0
                IL_006f:  stfld      "int Program.<>c.<<<Main>$>b__0_0>d.<>1__state"
                IL_0074:  ldloca.s   V_1
                IL_0076:  call       "void System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter.GetResult()"
                IL_007b:  nop
                IL_007c:  newobj     "System.Threading.Lock..ctor()"
                IL_0081:  call       "System.Threading.Lock.Scope System.Threading.Lock.EnterScope()"
                IL_0086:  stloc.s    V_4
                .try
                {
                  IL_0088:  nop
                  IL_0089:  ldstr      "L"
                  IL_008e:  call       "void System.Console.Write(string)"
                  IL_0093:  nop
                  IL_0094:  nop
                  IL_0095:  leave.s    IL_00a4
                }
                finally
                {
                  IL_0097:  ldloc.0
                  IL_0098:  ldc.i4.0
                  IL_0099:  bge.s      IL_00a3
                  IL_009b:  ldloca.s   V_4
                  IL_009d:  call       "void System.Threading.Lock.Scope.Dispose()"
                  IL_00a2:  nop
                  IL_00a3:  endfinally
                }
                IL_00a4:  call       "System.Runtime.CompilerServices.YieldAwaitable System.Threading.Tasks.Task.Yield()"
                IL_00a9:  stloc.2
                IL_00aa:  ldloca.s   V_2
                IL_00ac:  call       "System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter System.Runtime.CompilerServices.YieldAwaitable.GetAwaiter()"
                IL_00b1:  stloc.s    V_5
                IL_00b3:  ldloca.s   V_5
                IL_00b5:  call       "bool System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter.IsCompleted.get"
                IL_00ba:  brtrue.s   IL_00fe
                IL_00bc:  ldarg.0
                IL_00bd:  ldc.i4.1
                IL_00be:  dup
                IL_00bf:  stloc.0
                IL_00c0:  stfld      "int Program.<>c.<<<Main>$>b__0_0>d.<>1__state"
                IL_00c5:  ldarg.0
                IL_00c6:  ldloc.s    V_5
                IL_00c8:  stfld      "System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter Program.<>c.<<<Main>$>b__0_0>d.<>u__1"
                IL_00cd:  ldarg.0
                IL_00ce:  stloc.3
                IL_00cf:  ldarg.0
                IL_00d0:  ldflda     "System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.<>c.<<<Main>$>b__0_0>d.<>t__builder"
                IL_00d5:  ldloca.s   V_5
                IL_00d7:  ldloca.s   V_3
                IL_00d9:  call       "void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.AwaitUnsafeOnCompleted<System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter, Program.<>c.<<<Main>$>b__0_0>d>(ref System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter, ref Program.<>c.<<<Main>$>b__0_0>d)"
                IL_00de:  nop
                IL_00df:  leave.s    IL_0136
                IL_00e1:  ldarg.0
                IL_00e2:  ldfld      "System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter Program.<>c.<<<Main>$>b__0_0>d.<>u__1"
                IL_00e7:  stloc.s    V_5
                IL_00e9:  ldarg.0
                IL_00ea:  ldflda     "System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter Program.<>c.<<<Main>$>b__0_0>d.<>u__1"
                IL_00ef:  initobj    "System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter"
                IL_00f5:  ldarg.0
                IL_00f6:  ldc.i4.m1
                IL_00f7:  dup
                IL_00f8:  stloc.0
                IL_00f9:  stfld      "int Program.<>c.<<<Main>$>b__0_0>d.<>1__state"
                IL_00fe:  ldloca.s   V_5
                IL_0100:  call       "void System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter.GetResult()"
                IL_0105:  nop
                IL_0106:  leave.s    IL_0122
              }
              catch System.Exception
              {
                IL_0108:  stloc.s    V_6
                IL_010a:  ldarg.0
                IL_010b:  ldc.i4.s   -2
                IL_010d:  stfld      "int Program.<>c.<<<Main>$>b__0_0>d.<>1__state"
                IL_0112:  ldarg.0
                IL_0113:  ldflda     "System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.<>c.<<<Main>$>b__0_0>d.<>t__builder"
                IL_0118:  ldloc.s    V_6
                IL_011a:  call       "void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetException(System.Exception)"
                IL_011f:  nop
                IL_0120:  leave.s    IL_0136
              }
              IL_0122:  ldarg.0
              IL_0123:  ldc.i4.s   -2
              IL_0125:  stfld      "int Program.<>c.<<<Main>$>b__0_0>d.<>1__state"
              IL_012a:  ldarg.0
              IL_012b:  ldflda     "System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.<>c.<<<Main>$>b__0_0>d.<>t__builder"
              IL_0130:  call       "void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetResult()"
              IL_0135:  nop
              IL_0136:  ret
            }
            """);
 
        verifier = CompileAndVerify([source, LockTypeDefinition], options: TestOptions.ReleaseExe,
            expectedOutput: expectedOutput, verify: Verification.FailsILVerify);
        verifier.VerifyDiagnostics();
        verifier.VerifyIL("Program.<>c.<<<Main>$>b__0_0>d.System.Runtime.CompilerServices.IAsyncStateMachine.MoveNext", """
            {
              // Code size      282 (0x11a)
              .maxstack  3
              .locals init (int V_0,
                            System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter V_1,
                            System.Runtime.CompilerServices.YieldAwaitable V_2,
                            System.Threading.Lock.Scope V_3,
                            System.Exception V_4)
              IL_0000:  ldarg.0
              IL_0001:  ldfld      "int Program.<>c.<<<Main>$>b__0_0>d.<>1__state"
              IL_0006:  stloc.0
              .try
              {
                IL_0007:  ldloc.0
                IL_0008:  brfalse.s  IL_004b
                IL_000a:  ldloc.0
                IL_000b:  ldc.i4.1
                IL_000c:  beq        IL_00c8
                IL_0011:  call       "System.Runtime.CompilerServices.YieldAwaitable System.Threading.Tasks.Task.Yield()"
                IL_0016:  stloc.2
                IL_0017:  ldloca.s   V_2
                IL_0019:  call       "System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter System.Runtime.CompilerServices.YieldAwaitable.GetAwaiter()"
                IL_001e:  stloc.1
                IL_001f:  ldloca.s   V_1
                IL_0021:  call       "bool System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter.IsCompleted.get"
                IL_0026:  brtrue.s   IL_0067
                IL_0028:  ldarg.0
                IL_0029:  ldc.i4.0
                IL_002a:  dup
                IL_002b:  stloc.0
                IL_002c:  stfld      "int Program.<>c.<<<Main>$>b__0_0>d.<>1__state"
                IL_0031:  ldarg.0
                IL_0032:  ldloc.1
                IL_0033:  stfld      "System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter Program.<>c.<<<Main>$>b__0_0>d.<>u__1"
                IL_0038:  ldarg.0
                IL_0039:  ldflda     "System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.<>c.<<<Main>$>b__0_0>d.<>t__builder"
                IL_003e:  ldloca.s   V_1
                IL_0040:  ldarg.0
                IL_0041:  call       "void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.AwaitUnsafeOnCompleted<System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter, Program.<>c.<<<Main>$>b__0_0>d>(ref System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter, ref Program.<>c.<<<Main>$>b__0_0>d)"
                IL_0046:  leave      IL_0119
                IL_004b:  ldarg.0
                IL_004c:  ldfld      "System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter Program.<>c.<<<Main>$>b__0_0>d.<>u__1"
                IL_0051:  stloc.1
                IL_0052:  ldarg.0
                IL_0053:  ldflda     "System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter Program.<>c.<<<Main>$>b__0_0>d.<>u__1"
                IL_0058:  initobj    "System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter"
                IL_005e:  ldarg.0
                IL_005f:  ldc.i4.m1
                IL_0060:  dup
                IL_0061:  stloc.0
                IL_0062:  stfld      "int Program.<>c.<<<Main>$>b__0_0>d.<>1__state"
                IL_0067:  ldloca.s   V_1
                IL_0069:  call       "void System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter.GetResult()"
                IL_006e:  newobj     "System.Threading.Lock..ctor()"
                IL_0073:  call       "System.Threading.Lock.Scope System.Threading.Lock.EnterScope()"
                IL_0078:  stloc.3
                .try
                {
                  IL_0079:  ldstr      "L"
                  IL_007e:  call       "void System.Console.Write(string)"
                  IL_0083:  leave.s    IL_0091
                }
                finally
                {
                  IL_0085:  ldloc.0
                  IL_0086:  ldc.i4.0
                  IL_0087:  bge.s      IL_0090
                  IL_0089:  ldloca.s   V_3
                  IL_008b:  call       "void System.Threading.Lock.Scope.Dispose()"
                  IL_0090:  endfinally
                }
                IL_0091:  call       "System.Runtime.CompilerServices.YieldAwaitable System.Threading.Tasks.Task.Yield()"
                IL_0096:  stloc.2
                IL_0097:  ldloca.s   V_2
                IL_0099:  call       "System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter System.Runtime.CompilerServices.YieldAwaitable.GetAwaiter()"
                IL_009e:  stloc.1
                IL_009f:  ldloca.s   V_1
                IL_00a1:  call       "bool System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter.IsCompleted.get"
                IL_00a6:  brtrue.s   IL_00e4
                IL_00a8:  ldarg.0
                IL_00a9:  ldc.i4.1
                IL_00aa:  dup
                IL_00ab:  stloc.0
                IL_00ac:  stfld      "int Program.<>c.<<<Main>$>b__0_0>d.<>1__state"
                IL_00b1:  ldarg.0
                IL_00b2:  ldloc.1
                IL_00b3:  stfld      "System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter Program.<>c.<<<Main>$>b__0_0>d.<>u__1"
                IL_00b8:  ldarg.0
                IL_00b9:  ldflda     "System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.<>c.<<<Main>$>b__0_0>d.<>t__builder"
                IL_00be:  ldloca.s   V_1
                IL_00c0:  ldarg.0
                IL_00c1:  call       "void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.AwaitUnsafeOnCompleted<System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter, Program.<>c.<<<Main>$>b__0_0>d>(ref System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter, ref Program.<>c.<<<Main>$>b__0_0>d)"
                IL_00c6:  leave.s    IL_0119
                IL_00c8:  ldarg.0
                IL_00c9:  ldfld      "System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter Program.<>c.<<<Main>$>b__0_0>d.<>u__1"
                IL_00ce:  stloc.1
                IL_00cf:  ldarg.0
                IL_00d0:  ldflda     "System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter Program.<>c.<<<Main>$>b__0_0>d.<>u__1"
                IL_00d5:  initobj    "System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter"
                IL_00db:  ldarg.0
                IL_00dc:  ldc.i4.m1
                IL_00dd:  dup
                IL_00de:  stloc.0
                IL_00df:  stfld      "int Program.<>c.<<<Main>$>b__0_0>d.<>1__state"
                IL_00e4:  ldloca.s   V_1
                IL_00e6:  call       "void System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter.GetResult()"
                IL_00eb:  leave.s    IL_0106
              }
              catch System.Exception
              {
                IL_00ed:  stloc.s    V_4
                IL_00ef:  ldarg.0
                IL_00f0:  ldc.i4.s   -2
                IL_00f2:  stfld      "int Program.<>c.<<<Main>$>b__0_0>d.<>1__state"
                IL_00f7:  ldarg.0
                IL_00f8:  ldflda     "System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.<>c.<<<Main>$>b__0_0>d.<>t__builder"
                IL_00fd:  ldloc.s    V_4
                IL_00ff:  call       "void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetException(System.Exception)"
                IL_0104:  leave.s    IL_0119
              }
              IL_0106:  ldarg.0
              IL_0107:  ldc.i4.s   -2
              IL_0109:  stfld      "int Program.<>c.<<<Main>$>b__0_0>d.<>1__state"
              IL_010e:  ldarg.0
              IL_010f:  ldflda     "System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.<>c.<<<Main>$>b__0_0>d.<>t__builder"
              IL_0114:  call       "void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetResult()"
              IL_0119:  ret
            }
            """);
    }
 
    [Fact]
    public void Yield()
    {
        var source = """
            using System.Collections.Generic;
            using System.Threading;
 
            class C
            {
                IEnumerable<int> M()
                {
                    yield return 1;
                    lock (new Lock())
                    {
                        yield return 2;
                    }
                    yield return 3;
                }
            }
            """;
        CreateCompilation([source, LockTypeDefinition]).VerifyEmitDiagnostics(
            // (9,15): error CS4007: Instance of type 'System.Threading.Lock.Scope' cannot be preserved across 'await' or 'yield' boundary.
            //         lock (new Lock())
            Diagnostic(ErrorCode.ERR_ByRefTypeAndAwait, "new Lock()").WithArguments("System.Threading.Lock.Scope").WithLocation(9, 15));
    }
 
    [Fact]
    public void Yield_Break()
    {
        var source = """
            #pragma warning disable CS0162 // Unreachable code detected
            using System;
            using System.Collections.Generic;
            using System.Threading;
 
            static class Program
            {
                static void Main()
                {
                    foreach (var x in M())
                    {
                        Console.Write(x);
                    }
                }
 
                static IEnumerable<int> M()
                {
                    yield return 1;
                    lock (new Lock())
                    {
                        Console.Write("L");
                        yield break;
                        Console.Write("B");
                    }
                    yield return 2;
                }
            }
            """;
        var expectedOutput = "1ELD";
        var verifier = CompileAndVerify([source, LockTypeDefinition], options: TestOptions.ReleaseExe,
            verify: Verification.FailsILVerify, expectedOutput: expectedOutput);
        verifier.VerifyDiagnostics();
 
        verifier = CompileAndVerify([source, LockTypeDefinition], options: TestOptions.DebugExe,
            verify: Verification.FailsILVerify, expectedOutput: expectedOutput);
        verifier.VerifyDiagnostics();
    }
 
    [Fact]
    public void Yield_AroundOnly()
    {
        var source = """
            using System;
            using System.Collections.Generic;
            using System.Threading;
 
            static class Program
            {
                static void Main()
                {
                    foreach (var x in M())
                    {
                        Console.Write(x);
                    }
                }
 
                static IEnumerable<int> M()
                {
                    yield return 1;
                    lock (new Lock())
                    {
                        Console.Write("L");
                    }
                    yield return 2;
                }
            }
            """;
        var expectedOutput = "1ELD2";
        var verifier = CompileAndVerify([source, LockTypeDefinition], options: TestOptions.ReleaseExe,
            verify: Verification.FailsILVerify, expectedOutput: expectedOutput);
        verifier.VerifyDiagnostics();
 
        verifier = CompileAndVerify([source, LockTypeDefinition], options: TestOptions.DebugExe,
            verify: Verification.FailsILVerify, expectedOutput: expectedOutput);
        verifier.VerifyDiagnostics();
    }
 
    [Fact]
    public void Yield_Async()
    {
        var source = """
            using System.Collections.Generic;
            using System.Threading;
            using System.Threading.Tasks;
 
            class C
            {
                async IAsyncEnumerable<int> M()
                {
                    yield return 1;
                    lock (new Lock())
                    {
                        yield return 2;
                    }
                    await Task.Yield();
                    yield return 3;
                }
            }
            """;
        CreateCompilationWithTasksExtensions([source, LockTypeDefinition, AsyncStreamsTypes]).VerifyEmitDiagnostics(
            // (10,15): error CS4007: Instance of type 'System.Threading.Lock.Scope' cannot be preserved across 'await' or 'yield' boundary.
            //         lock (new Lock())
            Diagnostic(ErrorCode.ERR_ByRefTypeAndAwait, "new Lock()").WithArguments("System.Threading.Lock.Scope").WithLocation(10, 15));
    }
 
    [Fact]
    public void Yield_Async_Break()
    {
        var source = """
            #pragma warning disable CS0162 // Unreachable code detected
            using System;
            using System.Collections.Generic;
            using System.Threading;
            using System.Threading.Tasks;
 
            static class Program
            {
                static async Task Main()
                {
                    await foreach (var x in M())
                    {
                        Console.Write(x);
                    }
                }
 
                async static IAsyncEnumerable<int> M()
                {
                    yield return 1;
                    await Task.Yield();
                    lock (new Lock())
                    {
                        Console.Write("L");
                        yield break;
                        Console.Write("B");
                    }
                    await Task.Yield();
                    yield return 2;
                }
            }
            """;
        var expectedOutput = "1ELD";
        var comp = CreateCompilationWithTasksExtensions([source, LockTypeDefinition, AsyncStreamsTypes], options: TestOptions.ReleaseExe);
        var verifier = CompileAndVerify(comp, verify: Verification.FailsILVerify, expectedOutput: expectedOutput);
        verifier.VerifyDiagnostics();
 
        comp = CreateCompilationWithTasksExtensions([source, LockTypeDefinition, AsyncStreamsTypes], options: TestOptions.DebugExe);
        verifier = CompileAndVerify(comp, verify: Verification.FailsILVerify, expectedOutput: expectedOutput);
        verifier.VerifyDiagnostics();
    }
 
    [Fact]
    public void Yield_Async_AroundOnly()
    {
        var source = """
            using System;
            using System.Collections.Generic;
            using System.Threading;
            using System.Threading.Tasks;
 
            static class Program
            {
                static async Task Main()
                {
                    await foreach (var x in M())
                    {
                        Console.Write(x);
                    }
                }
 
                static async IAsyncEnumerable<int> M()
                {
                    yield return 1;
                    lock (new Lock())
                    {
                        Console.Write("L");
                    }
                    await Task.Yield();
                    yield return 2;
                }
            }
            """;
        var expectedOutput = "1ELD2";
        var comp = CreateCompilationWithTasksExtensions([source, LockTypeDefinition, AsyncStreamsTypes], options: TestOptions.DebugExe);
        var verifier = CompileAndVerify(comp, expectedOutput: expectedOutput, verify: Verification.FailsILVerify);
        verifier.VerifyDiagnostics();
        verifier.VerifyIL("Program.<M>d__1.System.Runtime.CompilerServices.IAsyncStateMachine.MoveNext", """
            {
              // Code size      414 (0x19e)
              .maxstack  3
              .locals init (int V_0,
                            System.Threading.Lock.Scope V_1,
                            System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter V_2,
                            System.Runtime.CompilerServices.YieldAwaitable V_3,
                            Program.<M>d__1 V_4,
                            System.Exception V_5)
              IL_0000:  ldarg.0
              IL_0001:  ldfld      "int Program.<M>d__1.<>1__state"
              IL_0006:  stloc.0
              .try
              {
                IL_0007:  ldloc.0
                IL_0008:  ldc.i4.s   -5
                IL_000a:  sub
                IL_000b:  switch    (
                    IL_002a,
                    IL_002f,
                    IL_0031,
                    IL_0038,
                    IL_0038,
                    IL_0033)
                IL_0028:  br.s       IL_0038
                IL_002a:  br         IL_0125
                IL_002f:  br.s       IL_0065
                IL_0031:  br.s       IL_0038
                IL_0033:  br         IL_00ee
                IL_0038:  ldarg.0
                IL_0039:  ldfld      "bool Program.<M>d__1.<>w__disposeMode"
                IL_003e:  brfalse.s  IL_0045
                IL_0040:  leave      IL_0167
                IL_0045:  ldarg.0
                IL_0046:  ldc.i4.m1
                IL_0047:  dup
                IL_0048:  stloc.0
                IL_0049:  stfld      "int Program.<M>d__1.<>1__state"
                IL_004e:  nop
                IL_004f:  ldarg.0
                IL_0050:  ldc.i4.1
                IL_0051:  stfld      "int Program.<M>d__1.<>2__current"
                IL_0056:  ldarg.0
                IL_0057:  ldc.i4.s   -4
                IL_0059:  dup
                IL_005a:  stloc.0
                IL_005b:  stfld      "int Program.<M>d__1.<>1__state"
                IL_0060:  leave      IL_0190
                IL_0065:  ldarg.0
                IL_0066:  ldc.i4.m1
                IL_0067:  dup
                IL_0068:  stloc.0
                IL_0069:  stfld      "int Program.<M>d__1.<>1__state"
                IL_006e:  ldarg.0
                IL_006f:  ldfld      "bool Program.<M>d__1.<>w__disposeMode"
                IL_0074:  brfalse.s  IL_007b
                IL_0076:  leave      IL_0167
                IL_007b:  newobj     "System.Threading.Lock..ctor()"
                IL_0080:  call       "System.Threading.Lock.Scope System.Threading.Lock.EnterScope()"
                IL_0085:  stloc.1
                .try
                {
                  IL_0086:  nop
                  IL_0087:  ldstr      "L"
                  IL_008c:  call       "void System.Console.Write(string)"
                  IL_0091:  nop
                  IL_0092:  nop
                  IL_0093:  leave.s    IL_00a2
                }
                finally
                {
                  IL_0095:  ldloc.0
                  IL_0096:  ldc.i4.m1
                  IL_0097:  bne.un.s   IL_00a1
                  IL_0099:  ldloca.s   V_1
                  IL_009b:  call       "void System.Threading.Lock.Scope.Dispose()"
                  IL_00a0:  nop
                  IL_00a1:  endfinally
                }
                IL_00a2:  ldarg.0
                IL_00a3:  ldfld      "bool Program.<M>d__1.<>w__disposeMode"
                IL_00a8:  brfalse.s  IL_00af
                IL_00aa:  leave      IL_0167
                IL_00af:  call       "System.Runtime.CompilerServices.YieldAwaitable System.Threading.Tasks.Task.Yield()"
                IL_00b4:  stloc.3
                IL_00b5:  ldloca.s   V_3
                IL_00b7:  call       "System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter System.Runtime.CompilerServices.YieldAwaitable.GetAwaiter()"
                IL_00bc:  stloc.2
                IL_00bd:  ldloca.s   V_2
                IL_00bf:  call       "bool System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter.IsCompleted.get"
                IL_00c4:  brtrue.s   IL_010a
                IL_00c6:  ldarg.0
                IL_00c7:  ldc.i4.0
                IL_00c8:  dup
                IL_00c9:  stloc.0
                IL_00ca:  stfld      "int Program.<M>d__1.<>1__state"
                IL_00cf:  ldarg.0
                IL_00d0:  ldloc.2
                IL_00d1:  stfld      "System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter Program.<M>d__1.<>u__1"
                IL_00d6:  ldarg.0
                IL_00d7:  stloc.s    V_4
                IL_00d9:  ldarg.0
                IL_00da:  ldflda     "System.Runtime.CompilerServices.AsyncIteratorMethodBuilder Program.<M>d__1.<>t__builder"
                IL_00df:  ldloca.s   V_2
                IL_00e1:  ldloca.s   V_4
                IL_00e3:  call       "void System.Runtime.CompilerServices.AsyncIteratorMethodBuilder.AwaitUnsafeOnCompleted<System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter, Program.<M>d__1>(ref System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter, ref Program.<M>d__1)"
                IL_00e8:  nop
                IL_00e9:  leave      IL_019d
                IL_00ee:  ldarg.0
                IL_00ef:  ldfld      "System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter Program.<M>d__1.<>u__1"
                IL_00f4:  stloc.2
                IL_00f5:  ldarg.0
                IL_00f6:  ldflda     "System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter Program.<M>d__1.<>u__1"
                IL_00fb:  initobj    "System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter"
                IL_0101:  ldarg.0
                IL_0102:  ldc.i4.m1
                IL_0103:  dup
                IL_0104:  stloc.0
                IL_0105:  stfld      "int Program.<M>d__1.<>1__state"
                IL_010a:  ldloca.s   V_2
                IL_010c:  call       "void System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter.GetResult()"
                IL_0111:  nop
                IL_0112:  ldarg.0
                IL_0113:  ldc.i4.2
                IL_0114:  stfld      "int Program.<M>d__1.<>2__current"
                IL_0119:  ldarg.0
                IL_011a:  ldc.i4.s   -5
                IL_011c:  dup
                IL_011d:  stloc.0
                IL_011e:  stfld      "int Program.<M>d__1.<>1__state"
                IL_0123:  leave.s    IL_0190
                IL_0125:  ldarg.0
                IL_0126:  ldc.i4.m1
                IL_0127:  dup
                IL_0128:  stloc.0
                IL_0129:  stfld      "int Program.<M>d__1.<>1__state"
                IL_012e:  ldarg.0
                IL_012f:  ldfld      "bool Program.<M>d__1.<>w__disposeMode"
                IL_0134:  brfalse.s  IL_0138
                IL_0136:  leave.s    IL_0167
                IL_0138:  leave.s    IL_0167
              }
              catch System.Exception
              {
                IL_013a:  stloc.s    V_5
                IL_013c:  ldarg.0
                IL_013d:  ldc.i4.s   -2
                IL_013f:  stfld      "int Program.<M>d__1.<>1__state"
                IL_0144:  ldarg.0
                IL_0145:  ldc.i4.0
                IL_0146:  stfld      "int Program.<M>d__1.<>2__current"
                IL_014b:  ldarg.0
                IL_014c:  ldflda     "System.Runtime.CompilerServices.AsyncIteratorMethodBuilder Program.<M>d__1.<>t__builder"
                IL_0151:  call       "void System.Runtime.CompilerServices.AsyncIteratorMethodBuilder.Complete()"
                IL_0156:  nop
                IL_0157:  ldarg.0
                IL_0158:  ldflda     "System.Threading.Tasks.Sources.ManualResetValueTaskSourceCore<bool> Program.<M>d__1.<>v__promiseOfValueOrEnd"
                IL_015d:  ldloc.s    V_5
                IL_015f:  call       "void System.Threading.Tasks.Sources.ManualResetValueTaskSourceCore<bool>.SetException(System.Exception)"
                IL_0164:  nop
                IL_0165:  leave.s    IL_019d
              }
              IL_0167:  ldarg.0
              IL_0168:  ldc.i4.s   -2
              IL_016a:  stfld      "int Program.<M>d__1.<>1__state"
              IL_016f:  ldarg.0
              IL_0170:  ldc.i4.0
              IL_0171:  stfld      "int Program.<M>d__1.<>2__current"
              IL_0176:  ldarg.0
              IL_0177:  ldflda     "System.Runtime.CompilerServices.AsyncIteratorMethodBuilder Program.<M>d__1.<>t__builder"
              IL_017c:  call       "void System.Runtime.CompilerServices.AsyncIteratorMethodBuilder.Complete()"
              IL_0181:  nop
              IL_0182:  ldarg.0
              IL_0183:  ldflda     "System.Threading.Tasks.Sources.ManualResetValueTaskSourceCore<bool> Program.<M>d__1.<>v__promiseOfValueOrEnd"
              IL_0188:  ldc.i4.0
              IL_0189:  call       "void System.Threading.Tasks.Sources.ManualResetValueTaskSourceCore<bool>.SetResult(bool)"
              IL_018e:  nop
              IL_018f:  ret
              IL_0190:  ldarg.0
              IL_0191:  ldflda     "System.Threading.Tasks.Sources.ManualResetValueTaskSourceCore<bool> Program.<M>d__1.<>v__promiseOfValueOrEnd"
              IL_0196:  ldc.i4.1
              IL_0197:  call       "void System.Threading.Tasks.Sources.ManualResetValueTaskSourceCore<bool>.SetResult(bool)"
              IL_019c:  nop
              IL_019d:  ret
            }
            """);
 
        comp = CreateCompilationWithTasksExtensions([source, LockTypeDefinition, AsyncStreamsTypes], options: TestOptions.ReleaseExe);
        verifier = CompileAndVerify(comp, expectedOutput: expectedOutput, verify: Verification.FailsILVerify);
        verifier.VerifyDiagnostics();
        verifier.VerifyIL("Program.<M>d__1.System.Runtime.CompilerServices.IAsyncStateMachine.MoveNext", """
            {
              // Code size      383 (0x17f)
              .maxstack  3
              .locals init (int V_0,
                            System.Threading.Lock.Scope V_1,
                            System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter V_2,
                            System.Runtime.CompilerServices.YieldAwaitable V_3,
                            Program.<M>d__1 V_4,
                            System.Exception V_5)
              IL_0000:  ldarg.0
              IL_0001:  ldfld      "int Program.<M>d__1.<>1__state"
              IL_0006:  stloc.0
              .try
              {
                IL_0007:  ldloc.0
                IL_0008:  ldc.i4.s   -5
                IL_000a:  sub
                IL_000b:  switch    (
                    IL_010e,
                    IL_0054,
                    IL_0028,
                    IL_0028,
                    IL_0028,
                    IL_00d8)
                IL_0028:  ldarg.0
                IL_0029:  ldfld      "bool Program.<M>d__1.<>w__disposeMode"
                IL_002e:  brfalse.s  IL_0035
                IL_0030:  leave      IL_014b
                IL_0035:  ldarg.0
                IL_0036:  ldc.i4.m1
                IL_0037:  dup
                IL_0038:  stloc.0
                IL_0039:  stfld      "int Program.<M>d__1.<>1__state"
                IL_003e:  ldarg.0
                IL_003f:  ldc.i4.1
                IL_0040:  stfld      "int Program.<M>d__1.<>2__current"
                IL_0045:  ldarg.0
                IL_0046:  ldc.i4.s   -4
                IL_0048:  dup
                IL_0049:  stloc.0
                IL_004a:  stfld      "int Program.<M>d__1.<>1__state"
                IL_004f:  leave      IL_0172
                IL_0054:  ldarg.0
                IL_0055:  ldc.i4.m1
                IL_0056:  dup
                IL_0057:  stloc.0
                IL_0058:  stfld      "int Program.<M>d__1.<>1__state"
                IL_005d:  ldarg.0
                IL_005e:  ldfld      "bool Program.<M>d__1.<>w__disposeMode"
                IL_0063:  brfalse.s  IL_006a
                IL_0065:  leave      IL_014b
                IL_006a:  newobj     "System.Threading.Lock..ctor()"
                IL_006f:  call       "System.Threading.Lock.Scope System.Threading.Lock.EnterScope()"
                IL_0074:  stloc.1
                .try
                {
                  IL_0075:  ldstr      "L"
                  IL_007a:  call       "void System.Console.Write(string)"
                  IL_007f:  leave.s    IL_008d
                }
                finally
                {
                  IL_0081:  ldloc.0
                  IL_0082:  ldc.i4.m1
                  IL_0083:  bne.un.s   IL_008c
                  IL_0085:  ldloca.s   V_1
                  IL_0087:  call       "void System.Threading.Lock.Scope.Dispose()"
                  IL_008c:  endfinally
                }
                IL_008d:  ldarg.0
                IL_008e:  ldfld      "bool Program.<M>d__1.<>w__disposeMode"
                IL_0093:  brfalse.s  IL_009a
                IL_0095:  leave      IL_014b
                IL_009a:  call       "System.Runtime.CompilerServices.YieldAwaitable System.Threading.Tasks.Task.Yield()"
                IL_009f:  stloc.3
                IL_00a0:  ldloca.s   V_3
                IL_00a2:  call       "System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter System.Runtime.CompilerServices.YieldAwaitable.GetAwaiter()"
                IL_00a7:  stloc.2
                IL_00a8:  ldloca.s   V_2
                IL_00aa:  call       "bool System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter.IsCompleted.get"
                IL_00af:  brtrue.s   IL_00f4
                IL_00b1:  ldarg.0
                IL_00b2:  ldc.i4.0
                IL_00b3:  dup
                IL_00b4:  stloc.0
                IL_00b5:  stfld      "int Program.<M>d__1.<>1__state"
                IL_00ba:  ldarg.0
                IL_00bb:  ldloc.2
                IL_00bc:  stfld      "System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter Program.<M>d__1.<>u__1"
                IL_00c1:  ldarg.0
                IL_00c2:  stloc.s    V_4
                IL_00c4:  ldarg.0
                IL_00c5:  ldflda     "System.Runtime.CompilerServices.AsyncIteratorMethodBuilder Program.<M>d__1.<>t__builder"
                IL_00ca:  ldloca.s   V_2
                IL_00cc:  ldloca.s   V_4
                IL_00ce:  call       "void System.Runtime.CompilerServices.AsyncIteratorMethodBuilder.AwaitUnsafeOnCompleted<System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter, Program.<M>d__1>(ref System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter, ref Program.<M>d__1)"
                IL_00d3:  leave      IL_017e
                IL_00d8:  ldarg.0
                IL_00d9:  ldfld      "System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter Program.<M>d__1.<>u__1"
                IL_00de:  stloc.2
                IL_00df:  ldarg.0
                IL_00e0:  ldflda     "System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter Program.<M>d__1.<>u__1"
                IL_00e5:  initobj    "System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter"
                IL_00eb:  ldarg.0
                IL_00ec:  ldc.i4.m1
                IL_00ed:  dup
                IL_00ee:  stloc.0
                IL_00ef:  stfld      "int Program.<M>d__1.<>1__state"
                IL_00f4:  ldloca.s   V_2
                IL_00f6:  call       "void System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter.GetResult()"
                IL_00fb:  ldarg.0
                IL_00fc:  ldc.i4.2
                IL_00fd:  stfld      "int Program.<M>d__1.<>2__current"
                IL_0102:  ldarg.0
                IL_0103:  ldc.i4.s   -5
                IL_0105:  dup
                IL_0106:  stloc.0
                IL_0107:  stfld      "int Program.<M>d__1.<>1__state"
                IL_010c:  leave.s    IL_0172
                IL_010e:  ldarg.0
                IL_010f:  ldc.i4.m1
                IL_0110:  dup
                IL_0111:  stloc.0
                IL_0112:  stfld      "int Program.<M>d__1.<>1__state"
                IL_0117:  ldarg.0
                IL_0118:  ldfld      "bool Program.<M>d__1.<>w__disposeMode"
                IL_011d:  pop
                IL_011e:  leave.s    IL_014b
              }
              catch System.Exception
              {
                IL_0120:  stloc.s    V_5
                IL_0122:  ldarg.0
                IL_0123:  ldc.i4.s   -2
                IL_0125:  stfld      "int Program.<M>d__1.<>1__state"
                IL_012a:  ldarg.0
                IL_012b:  ldc.i4.0
                IL_012c:  stfld      "int Program.<M>d__1.<>2__current"
                IL_0131:  ldarg.0
                IL_0132:  ldflda     "System.Runtime.CompilerServices.AsyncIteratorMethodBuilder Program.<M>d__1.<>t__builder"
                IL_0137:  call       "void System.Runtime.CompilerServices.AsyncIteratorMethodBuilder.Complete()"
                IL_013c:  ldarg.0
                IL_013d:  ldflda     "System.Threading.Tasks.Sources.ManualResetValueTaskSourceCore<bool> Program.<M>d__1.<>v__promiseOfValueOrEnd"
                IL_0142:  ldloc.s    V_5
                IL_0144:  call       "void System.Threading.Tasks.Sources.ManualResetValueTaskSourceCore<bool>.SetException(System.Exception)"
                IL_0149:  leave.s    IL_017e
              }
              IL_014b:  ldarg.0
              IL_014c:  ldc.i4.s   -2
              IL_014e:  stfld      "int Program.<M>d__1.<>1__state"
              IL_0153:  ldarg.0
              IL_0154:  ldc.i4.0
              IL_0155:  stfld      "int Program.<M>d__1.<>2__current"
              IL_015a:  ldarg.0
              IL_015b:  ldflda     "System.Runtime.CompilerServices.AsyncIteratorMethodBuilder Program.<M>d__1.<>t__builder"
              IL_0160:  call       "void System.Runtime.CompilerServices.AsyncIteratorMethodBuilder.Complete()"
              IL_0165:  ldarg.0
              IL_0166:  ldflda     "System.Threading.Tasks.Sources.ManualResetValueTaskSourceCore<bool> Program.<M>d__1.<>v__promiseOfValueOrEnd"
              IL_016b:  ldc.i4.0
              IL_016c:  call       "void System.Threading.Tasks.Sources.ManualResetValueTaskSourceCore<bool>.SetResult(bool)"
              IL_0171:  ret
              IL_0172:  ldarg.0
              IL_0173:  ldflda     "System.Threading.Tasks.Sources.ManualResetValueTaskSourceCore<bool> Program.<M>d__1.<>v__promiseOfValueOrEnd"
              IL_0178:  ldc.i4.1
              IL_0179:  call       "void System.Threading.Tasks.Sources.ManualResetValueTaskSourceCore<bool>.SetResult(bool)"
              IL_017e:  ret
            }
            """);
    }
 
    [Theory, CombinatorialData]
    public void CastToObject([CombinatorialValues("object ", "dynamic")] string type)
    {
        var source = $$"""
            using System;
            using System.Threading;
 
            Lock l = new();
 
            {{type}} o = l;
            lock (o) { Console.Write("1"); }
 
            lock (({{type}})l) { Console.Write("2"); }
 
            lock (l as {{type}}) { Console.Write("3"); }
 
            o = l as {{type}};
            lock (o) { Console.Write("4"); }
 
            static {{type}} Cast1<T>(T t) => t;
            lock (Cast1(l)) { Console.Write("5"); }
 
            static {{type}} Cast2<T>(T t) where T : class => t;
            lock (Cast2(l)) { Console.Write("6"); }
 
            static {{type}} Cast3<T>(T t) where T : Lock => t;
            lock (Cast3(l)) { Console.Write("7"); }
            """;
        var verifier = CompileAndVerify([source, LockTypeDefinition], verify: Verification.FailsILVerify,
           expectedOutput: "1234567");
        verifier.VerifyDiagnostics(
            // 0.cs(6,13): warning CS9216: A value of type 'System.Threading.Lock' converted to a different type will use likely unintended monitor-based locking in 'lock' statement.
            // object  o = l;
            Diagnostic(ErrorCode.WRN_ConvertingLock, "l").WithLocation(6, 13),
            // 0.cs(9,16): warning CS9216: A value of type 'System.Threading.Lock' converted to a different type will use likely unintended monitor-based locking in 'lock' statement.
            // lock ((object )l) { Console.Write("2"); }
            Diagnostic(ErrorCode.WRN_ConvertingLock, "l").WithLocation(9, 16),
            // 0.cs(11,7): warning CS9216: A value of type 'System.Threading.Lock' converted to a different type will use likely unintended monitor-based locking in 'lock' statement.
            // lock (l as object ) { Console.Write("3"); }
            Diagnostic(ErrorCode.WRN_ConvertingLock, "l").WithLocation(11, 7),
            // 0.cs(13,5): warning CS9216: A value of type 'System.Threading.Lock' converted to a different type will use likely unintended monitor-based locking in 'lock' statement.
            // o = l as object ;
            Diagnostic(ErrorCode.WRN_ConvertingLock, "l").WithLocation(13, 5));
    }
 
    [Fact]
    public void CastToSelf()
    {
        var source = """
            using System;
            using System.Threading;
 
            Lock l = new();
 
            Lock o = l;
            lock (o) { Console.Write("1"); }
 
            lock ((Lock)l) { Console.Write("2"); }
 
            lock (l as Lock) { Console.Write("3"); }
 
            o = l as Lock;
            lock (o) { Console.Write("4"); }
 
            static Lock Cast1<T>(T t) => (Lock)(object)t;
            lock (Cast1(l)) { Console.Write("5"); }
 
            static Lock Cast2<T>(T t) where T : class => (Lock)(object)t;
            lock (Cast2(l)) { Console.Write("6"); }
 
            static Lock Cast3<T>(T t) where T : Lock => t;
            lock (Cast3(l)) { Console.Write("7"); }
            """;
        var verifier = CompileAndVerify([source, LockTypeDefinition], verify: Verification.FailsILVerify,
           expectedOutput: "E1DE2DE3DE4DE5DE6DE7D");
        verifier.VerifyDiagnostics();
    }
 
    [Fact]
    public void CommonType()
    {
        var source = """
            using System;
            using System.Threading;
 
            var array1 = new[] { new Lock(), new Lock() };
            Console.WriteLine(array1.GetType());
 
            var array2 = new[] { new Lock(), new object() };
            Console.WriteLine(array2.GetType());
            """;
        var verifier = CompileAndVerify([source, LockTypeDefinition], verify: Verification.FailsILVerify, expectedOutput: """
            System.Threading.Lock[]
            System.Object[]
            """);
        verifier.VerifyDiagnostics(
            // 0.cs(7,22): warning CS9216: A value of type 'System.Threading.Lock' converted to a different type will use likely unintended monitor-based locking in 'lock' statement.
            // var array2 = new[] { new Lock(), new object() };
            Diagnostic(ErrorCode.WRN_ConvertingLock, "new Lock()").WithLocation(7, 22));
    }
 
    [Theory, CombinatorialData]
    public void CastToBase([CombinatorialValues("interface", "class")] string baseKind)
    {
        var source = $$"""
            using System;
            using System.Threading;
 
            static class Program
            {
                static void Main()
                {
                    M1();
                    M2();
                }
 
                static void M1()
                {
                    ILock l1 = new Lock();
                    lock (l1) { Console.Write("1"); }
                }
 
                static void M2()
                {
                    ILock l2 = new Lock();
                    lock ((Lock)l2) { Console.Write("2"); }
                }
            }
 
            namespace System.Threading
            {
                public {{baseKind}} ILock { }
 
                public class Lock : ILock
                {
                    public Scope EnterScope()
                    {
                        Console.Write("E");
                        return new Scope();
                    }
 
                    public ref struct Scope
                    {
                        public void Dispose()
                        {
                            Console.Write("D");
                        }
                    }
                }
            }
            """;
        var verifier = CompileAndVerify(source, verify: Verification.FailsILVerify,
           expectedOutput: "1E2D");
        verifier.VerifyDiagnostics(
            // (14,20): warning CS9216: A value of type 'System.Threading.Lock' converted to a different type will use likely unintended monitor-based locking in 'lock' statement.
            //         ILock l1 = new Lock();
            Diagnostic(ErrorCode.WRN_ConvertingLock, "new Lock()").WithLocation(14, 20),
            // (20,20): warning CS9216: A value of type 'System.Threading.Lock' converted to a different type will use likely unintended monitor-based locking in 'lock' statement.
            //         ILock l2 = new Lock();
            Diagnostic(ErrorCode.WRN_ConvertingLock, "new Lock()").WithLocation(20, 20));
        // Should use Monitor locking.
        verifier.VerifyIL("Program.M1", """
            {
              // Code size       39 (0x27)
              .maxstack  2
              .locals init (System.Threading.ILock V_0,
                            bool V_1)
              IL_0000:  newobj     "System.Threading.Lock..ctor()"
              IL_0005:  stloc.0
              IL_0006:  ldc.i4.0
              IL_0007:  stloc.1
              .try
              {
                IL_0008:  ldloc.0
                IL_0009:  ldloca.s   V_1
                IL_000b:  call       "void System.Threading.Monitor.Enter(object, ref bool)"
                IL_0010:  ldstr      "1"
                IL_0015:  call       "void System.Console.Write(string)"
                IL_001a:  leave.s    IL_0026
              }
              finally
              {
                IL_001c:  ldloc.1
                IL_001d:  brfalse.s  IL_0025
                IL_001f:  ldloc.0
                IL_0020:  call       "void System.Threading.Monitor.Exit(object)"
                IL_0025:  endfinally
              }
              IL_0026:  ret
            }
            """);
    }
 
    [Fact]
    public void DerivedLock()
    {
        var source = """
            using System;
            using System.Threading;
 
            static class Program
            {
                static void Main()
                {
                    var l1 = M1();
                    var l2 = M2(l1);
                    M3(l2);
                    M4(l2);
                }
 
                static DerivedLock M1()
                {
                    DerivedLock l1 = new DerivedLock();
                    lock (l1) { Console.Write("1"); }
                    return l1;
                }
 
                static Lock M2(DerivedLock l1)
                {
                    Lock l2 = l1;
                    lock (l2) { Console.Write("2"); }
                    return l2;
                }
 
                static void M3(Lock l2)
                {
                    DerivedLock l3 = (DerivedLock)l2;
                    lock (l3) { Console.Write("3"); }
                }
            
                static void M4(Lock l2)
                {
                    IDerivedLock l4 = (IDerivedLock)l2;
                    lock (l4) { Console.Write("4"); }
                }
            }
 
            namespace System.Threading
            {
                public class Lock
                {
                    public Scope EnterScope()
                    {
                        Console.Write("E");
                        return new Scope();
                    }
 
                    public ref struct Scope
                    {
                        public void Dispose()
                        {
                            Console.Write("D");
                        }
                    }
                }
 
                public class DerivedLock : Lock, IDerivedLock { }
 
                public interface IDerivedLock { }
            }
            """;
        var verifier = CompileAndVerify(source, verify: Verification.FailsILVerify,
           expectedOutput: "1E2D34");
        verifier.VerifyDiagnostics(
            // (30,39): warning CS9216: A value of type 'System.Threading.Lock' converted to a different type will use likely unintended monitor-based locking in 'lock' statement.
            //         DerivedLock l3 = (DerivedLock)l2;
            Diagnostic(ErrorCode.WRN_ConvertingLock, "l2").WithLocation(30, 39),
            // (36,41): warning CS9216: A value of type 'System.Threading.Lock' converted to a different type will use likely unintended monitor-based locking in 'lock' statement.
            //         IDerivedLock l4 = (IDerivedLock)l2;
            Diagnostic(ErrorCode.WRN_ConvertingLock, "l2").WithLocation(36, 41));
        // Should use Monitor locking.
        verifier.VerifyIL("Program.M1", """
            {
              // Code size       42 (0x2a)
              .maxstack  2
              .locals init (System.Threading.DerivedLock V_0, //l1
                            System.Threading.DerivedLock V_1,
                            bool V_2)
              IL_0000:  newobj     "System.Threading.DerivedLock..ctor()"
              IL_0005:  stloc.0
              IL_0006:  ldloc.0
              IL_0007:  stloc.1
              IL_0008:  ldc.i4.0
              IL_0009:  stloc.2
              .try
              {
                IL_000a:  ldloc.1
                IL_000b:  ldloca.s   V_2
                IL_000d:  call       "void System.Threading.Monitor.Enter(object, ref bool)"
                IL_0012:  ldstr      "1"
                IL_0017:  call       "void System.Console.Write(string)"
                IL_001c:  leave.s    IL_0028
              }
              finally
              {
                IL_001e:  ldloc.2
                IL_001f:  brfalse.s  IL_0027
                IL_0021:  ldloc.1
                IL_0022:  call       "void System.Threading.Monitor.Exit(object)"
                IL_0027:  endfinally
              }
              IL_0028:  ldloc.0
              IL_0029:  ret
            }
            """);
        // Should use Monitor locking.
        verifier.VerifyIL("Program.M3", """
            {
              // Code size       40 (0x28)
              .maxstack  2
              .locals init (System.Threading.DerivedLock V_0,
                            bool V_1)
              IL_0000:  ldarg.0
              IL_0001:  castclass  "System.Threading.DerivedLock"
              IL_0006:  stloc.0
              IL_0007:  ldc.i4.0
              IL_0008:  stloc.1
              .try
              {
                IL_0009:  ldloc.0
                IL_000a:  ldloca.s   V_1
                IL_000c:  call       "void System.Threading.Monitor.Enter(object, ref bool)"
                IL_0011:  ldstr      "3"
                IL_0016:  call       "void System.Console.Write(string)"
                IL_001b:  leave.s    IL_0027
              }
              finally
              {
                IL_001d:  ldloc.1
                IL_001e:  brfalse.s  IL_0026
                IL_0020:  ldloc.0
                IL_0021:  call       "void System.Threading.Monitor.Exit(object)"
                IL_0026:  endfinally
              }
              IL_0027:  ret
            }
            """);
        // Should use Monitor locking.
        verifier.VerifyIL("Program.M4", """
            {
              // Code size       40 (0x28)
              .maxstack  2
              .locals init (System.Threading.IDerivedLock V_0,
                            bool V_1)
              IL_0000:  ldarg.0
              IL_0001:  castclass  "System.Threading.IDerivedLock"
              IL_0006:  stloc.0
              IL_0007:  ldc.i4.0
              IL_0008:  stloc.1
              .try
              {
                IL_0009:  ldloc.0
                IL_000a:  ldloca.s   V_1
                IL_000c:  call       "void System.Threading.Monitor.Enter(object, ref bool)"
                IL_0011:  ldstr      "4"
                IL_0016:  call       "void System.Console.Write(string)"
                IL_001b:  leave.s    IL_0027
              }
              finally
              {
                IL_001d:  ldloc.1
                IL_001e:  brfalse.s  IL_0026
                IL_0020:  ldloc.0
                IL_0021:  call       "void System.Threading.Monitor.Exit(object)"
                IL_0026:  endfinally
              }
              IL_0027:  ret
            }
            """);
    }
 
    [Fact]
    public void Downcast()
    {
        var source = """
            using System;
            using System.Threading;
 
            object o = new Lock();
            lock ((Lock)o) { Console.Write("L"); }
            """;
        var verifier = CompileAndVerify([source, LockTypeDefinition], verify: Verification.FailsILVerify,
           expectedOutput: "ELD");
        verifier.VerifyDiagnostics(
            // 0.cs(4,12): warning CS9216: A value of type 'System.Threading.Lock' converted to a different type will use likely unintended monitor-based locking in 'lock' statement.
            // object o = new Lock();
            Diagnostic(ErrorCode.WRN_ConvertingLock, "new Lock()").WithLocation(4, 12));
    }
 
    [Fact]
    public void OtherConversions()
    {
        var source = """
            #nullable enable
            using System.Threading;
 
            I i = new Lock();
            Lock? l = new Lock();
            C c = new Lock();
            D d = new Lock();
            d = (D)new Lock();
 
            interface I { }
 
            class C
            {
                public static implicit operator C(Lock l) => new C();
            }
 
            class D
            {
                public static explicit operator D(Lock l) => new D();
            }
            """;
        // No warnings about converting `Lock` expected.
        CreateCompilation([source, LockTypeDefinition]).VerifyDiagnostics(
            // 0.cs(4,7): error CS0266: Cannot implicitly convert type 'System.Threading.Lock' to 'I'. An explicit conversion exists (are you missing a cast?)
            // I i = new Lock();
            Diagnostic(ErrorCode.ERR_NoImplicitConvCast, "new Lock()").WithArguments("System.Threading.Lock", "I").WithLocation(4, 7),
            // 0.cs(7,7): error CS0266: Cannot implicitly convert type 'System.Threading.Lock' to 'D'. An explicit conversion exists (are you missing a cast?)
            // D d = new Lock();
            Diagnostic(ErrorCode.ERR_NoImplicitConvCast, "new Lock()").WithArguments("System.Threading.Lock", "D").WithLocation(7, 7));
    }
 
    [Theory]
    [InlineData("")]
    [InlineData("where T : class")]
    [InlineData("where T : Lock")]
    public void GenericParameter(string constraint)
    {
        var source = $$"""
            using System;
            using System.Threading;
 
            C.M(new Lock());
 
            static class C
            {
                public static void M<T>(T t) {{constraint}}
                {
                    lock (t) { Console.Write("L"); }
                }
            }
            """;
        var verifier = CompileAndVerify([source, LockTypeDefinition], verify: Verification.FailsILVerify,
           expectedOutput: "L");
        verifier.VerifyDiagnostics();
        // Should use Monitor locking.
        verifier.VerifyIL("C.M<T>", """
            {
              // Code size       40 (0x28)
              .maxstack  2
              .locals init (object V_0,
                            bool V_1)
              IL_0000:  ldarg.0
              IL_0001:  box        "T"
              IL_0006:  stloc.0
              IL_0007:  ldc.i4.0
              IL_0008:  stloc.1
              .try
              {
                IL_0009:  ldloc.0
                IL_000a:  ldloca.s   V_1
                IL_000c:  call       "void System.Threading.Monitor.Enter(object, ref bool)"
                IL_0011:  ldstr      "L"
                IL_0016:  call       "void System.Console.Write(string)"
                IL_001b:  leave.s    IL_0027
              }
              finally
              {
                IL_001d:  ldloc.1
                IL_001e:  brfalse.s  IL_0026
                IL_0020:  ldloc.0
                IL_0021:  call       "void System.Threading.Monitor.Exit(object)"
                IL_0026:  endfinally
              }
              IL_0027:  ret
            }
            """);
    }
 
    [Fact]
    public void GenericParameter_Object()
    {
        var source = """
            using System;
            using System.Threading;
 
            C.M<object>(new Lock());
 
            static class C
            {
                public static void M<T>(T t)
                {
                    lock (t) { Console.Write("L"); }
                }
            }
            """;
        var verifier = CompileAndVerify([source, LockTypeDefinition], verify: Verification.FailsILVerify,
           expectedOutput: "L");
        verifier.VerifyDiagnostics(
            // (4,13): warning CS9216: A value of type 'System.Threading.Lock' converted to a different type will use likely unintended monitor-based locking in 'lock' statement.
            // C.M<object>(new Lock());
            Diagnostic(ErrorCode.WRN_ConvertingLock, "new Lock()").WithLocation(4, 13));
        // Should use Monitor locking.
        verifier.VerifyIL("C.M<T>", """
            {
              // Code size       40 (0x28)
              .maxstack  2
              .locals init (object V_0,
                            bool V_1)
              IL_0000:  ldarg.0
              IL_0001:  box        "T"
              IL_0006:  stloc.0
              IL_0007:  ldc.i4.0
              IL_0008:  stloc.1
              .try
              {
                IL_0009:  ldloc.0
                IL_000a:  ldloca.s   V_1
                IL_000c:  call       "void System.Threading.Monitor.Enter(object, ref bool)"
                IL_0011:  ldstr      "L"
                IL_0016:  call       "void System.Console.Write(string)"
                IL_001b:  leave.s    IL_0027
              }
              finally
              {
                IL_001d:  ldloc.1
                IL_001e:  brfalse.s  IL_0026
                IL_0020:  ldloc.0
                IL_0021:  call       "void System.Threading.Monitor.Exit(object)"
                IL_0026:  endfinally
              }
              IL_0027:  ret
            }
            """);
    }
 
    [Fact]
    public void UseSiteError_EnterScope()
    {
        // namespace System.Threading
        // {
        //     public class Lock
        //     {
        //         [System.Runtime.CompilerServices.CompilerFeatureRequiredAttribute("Test")]
        //         public Scope EnterScope() => throw null;
        //
        //         public ref struct Scope
        //         {
        //             public void Dispose() { }
        //         }
        //     }
        // }
        var ilSource = """
            .class public auto ansi sealed beforefieldinit System.Threading.Lock extends System.Object
            {
                .method public hidebysig specialname rtspecialname instance void .ctor() cil managed
                {
                    .maxstack 8
                    ret
                }
 
                .method public hidebysig instance class System.Threading.Lock/Scope EnterScope () cil managed
                {
                    .custom instance void System.Runtime.CompilerServices.CompilerFeatureRequiredAttribute::.ctor(string) = (
                        01 00 04 54 65 73 74 00 00
                    )
                    .maxstack 8
                    ldnull
                    throw
                }
 
                .class nested public sequential ansi sealed beforefieldinit Scope extends System.ValueType
                {
                    .custom instance void System.Runtime.CompilerServices.IsByRefLikeAttribute::.ctor() = (
                        01 00 00 00
                    )
 
                    .pack 0
                    .size 1
 
                    .method public hidebysig instance void Dispose () cil managed
                    {
                        .maxstack 8
                        ret
                    }
                }
            }
 
            .class public auto ansi sealed beforefieldinit System.Runtime.CompilerServices.CompilerFeatureRequiredAttribute extends System.Object
            {
                .method public hidebysig specialname rtspecialname instance void .ctor(string s) cil managed
                {
                    .maxstack 8
                    ret
                }
            }
 
            .class public auto ansi sealed beforefieldinit System.Runtime.CompilerServices.IsByRefLikeAttribute extends System.Object
            {
                .method public hidebysig specialname rtspecialname instance void .ctor() cil managed
                {
                    .maxstack 8
                    ret
                }
            }
            """;
        var source = """
            class C
            {
                void M(System.Threading.Lock l)
                {
                    lock (l) { }
                }
            }
            """;
        CreateCompilationWithIL(source, ilSource).VerifyDiagnostics(
            // (5,15): error CS9041: 'Lock.EnterScope()' requires compiler feature 'Test', which is not supported by this version of the C# compiler.
            //         lock (l) { }
            Diagnostic(ErrorCode.ERR_UnsupportedCompilerFeature, "l").WithArguments("System.Threading.Lock.EnterScope()", "Test").WithLocation(5, 15));
    }
 
    [Fact]
    public void UseSiteError_Scope()
    {
        // namespace System.Threading
        // {
        //     public class Lock
        //     {
        //         public Scope EnterScope() => throw null;
        //
        //         [System.Runtime.CompilerServices.CompilerFeatureRequiredAttribute("Test")]
        //         public ref struct Scope
        //         {
        //             public void Dispose() { }
        //         }
        //     }
        // }
        var ilSource = """
            .class public auto ansi sealed beforefieldinit System.Threading.Lock extends System.Object
            {
                .method public hidebysig specialname rtspecialname instance void .ctor() cil managed
                {
                    .maxstack 8
                    ret
                }
 
                .method public hidebysig instance class System.Threading.Lock/Scope EnterScope () cil managed
                {
                    .maxstack 8
                    ldnull
                    throw
                }
 
                .class nested public sequential ansi sealed beforefieldinit Scope extends System.ValueType
                {
                    .custom instance void System.Runtime.CompilerServices.IsByRefLikeAttribute::.ctor() = (
                        01 00 00 00
                    )
 
                    .custom instance void System.Runtime.CompilerServices.CompilerFeatureRequiredAttribute::.ctor(string) = (
                        01 00 04 54 65 73 74 00 00
                    )
 
                    .pack 0
                    .size 1
 
                    .method public hidebysig instance void Dispose () cil managed
                    {
                        .maxstack 8
                        ret
                    }
                }
            }
 
            .class public auto ansi sealed beforefieldinit System.Runtime.CompilerServices.CompilerFeatureRequiredAttribute extends System.Object
            {
                .method public hidebysig specialname rtspecialname instance void .ctor(string s) cil managed
                {
                    .maxstack 8
                    ret
                }
            }
 
            .class public auto ansi sealed beforefieldinit System.Runtime.CompilerServices.IsByRefLikeAttribute extends System.Object
            {
                .method public hidebysig specialname rtspecialname instance void .ctor() cil managed
                {
                    .maxstack 8
                    ret
                }
            }
            """;
        var source = """
            class C
            {
                void M(System.Threading.Lock l)
                {
                    lock (l) { }
                }
            }
            """;
        CreateCompilationWithIL(source, ilSource).VerifyDiagnostics(
            // (5,15): error CS9041: 'Lock.Scope' requires compiler feature 'Test', which is not supported by this version of the C# compiler.
            //         lock (l) { }
            Diagnostic(ErrorCode.ERR_UnsupportedCompilerFeature, "l").WithArguments("System.Threading.Lock.Scope", "Test").WithLocation(5, 15));
    }
 
    [Fact]
    public void UseSiteError_Dispose()
    {
        // namespace System.Threading
        // {
        //     public class Lock
        //     {
        //         public Scope EnterScope() => throw null;
        //
        //         public ref struct Scope
        //         {
        //             [System.Runtime.CompilerServices.CompilerFeatureRequiredAttribute("Test")]
        //             public void Dispose() { }
        //         }
        //     }
        // }
        var ilSource = """
            .class public auto ansi sealed beforefieldinit System.Threading.Lock extends System.Object
            {
                .method public hidebysig specialname rtspecialname instance void .ctor() cil managed
                {
                    .maxstack 8
                    ret
                }
 
                .method public hidebysig instance class System.Threading.Lock/Scope EnterScope () cil managed
                {
                    .maxstack 8
                    ldnull
                    throw
                }
 
                .class nested public sequential ansi sealed beforefieldinit Scope extends System.ValueType
                {
                    .custom instance void System.Runtime.CompilerServices.IsByRefLikeAttribute::.ctor() = (
                        01 00 00 00
                    )
 
                    .pack 0
                    .size 1
 
                    .method public hidebysig instance void Dispose () cil managed
                    {
                        .custom instance void System.Runtime.CompilerServices.CompilerFeatureRequiredAttribute::.ctor(string) = (
                            01 00 04 54 65 73 74 00 00
                        )
                        .maxstack 8
                        ret
                    }
                }
            }
 
            .class public auto ansi sealed beforefieldinit System.Runtime.CompilerServices.CompilerFeatureRequiredAttribute extends System.Object
            {
                .method public hidebysig specialname rtspecialname instance void .ctor(string s) cil managed
                {
                    .maxstack 8
                    ret
                }
            }
 
            .class public auto ansi sealed beforefieldinit System.Runtime.CompilerServices.IsByRefLikeAttribute extends System.Object
            {
                .method public hidebysig specialname rtspecialname instance void .ctor() cil managed
                {
                    .maxstack 8
                    ret
                }
            }
            """;
        var source = """
            class C
            {
                void M(System.Threading.Lock l)
                {
                    lock (l) { }
                }
            }
            """;
        CreateCompilationWithIL(source, ilSource).VerifyDiagnostics(
            // (5,15): error CS9041: 'Lock.Scope.Dispose()' requires compiler feature 'Test', which is not supported by this version of the C# compiler.
            //         lock (l) { }
            Diagnostic(ErrorCode.ERR_UnsupportedCompilerFeature, "l").WithArguments("System.Threading.Lock.Scope.Dispose()", "Test").WithLocation(5, 15));
    }
}