/
githubmirror
/
roslyn
Обзор
Документация
Войти
/
githubmirror
/
roslyn
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
src/Compilers/CSharp/Test/Emit3/Semantics/LockTests.cs
4 850 строк
195 KB
Copilot
Remove CS1998 warning entirely and remove dependent C# code fix providers (#80144)
19 сен 2025, 20:17
Не верифицирован
19 сен 2025, 20:17
84133cc
Код
Авторство
О чём код?
// 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 = """ 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 = """ 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 = """ 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 = """ 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)); } }