diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/IteratorTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/IteratorTests.cs index 34be3f12005c3..aff952a025c5c 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/IteratorTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/IteratorTests.cs @@ -106,6 +106,179 @@ IEnumerable I() ); } + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/72443")] + public void YieldInLock_Async() + { + var source = """ + using System; + using System.Collections.Generic; + using System.Threading; + using System.Threading.Tasks; + + try + { + await new C().ProcessValueAsync(); + } + catch (SynchronizationLockException e) + { + Console.WriteLine(e.Message); + } + + public class C + { + public async Task ProcessValueAsync() + { + await foreach (int item in GetValuesAsync()) + { + await Task.Delay(1); + } + } + + private async IAsyncEnumerable GetValuesAsync() + { + await Task.Yield(); + lock (this) + { + for (int i = 0; i < 10; i++) + { + yield return i; + + if (i == 8) + { + yield break; + } + } + } + } + } + """ + AsyncStreamsTypes; + + var expectedOutput = "Object synchronization method was called from an unsynchronized block of code."; + + var comp = CreateCompilationWithTasksExtensions(source, options: TestOptions.ReleaseExe.WithWarningLevel(8)); + CompileAndVerify(comp, expectedOutput: expectedOutput).VerifyDiagnostics(); + + var expectedDiagnostics = new[] + { + // (32,17): warning CS9230: 'yield return' should not be used in the body of a lock statement + // yield return i; + Diagnostic(ErrorCode.WRN_BadYieldInLock, "yield").WithLocation(32, 17) + }; + + comp = CreateCompilationWithTasksExtensions(source, options: TestOptions.ReleaseExe.WithWarningLevel(9)); + CompileAndVerify(comp, expectedOutput: expectedOutput).VerifyDiagnostics(expectedDiagnostics); + + comp = CreateCompilationWithTasksExtensions(source, options: TestOptions.ReleaseExe); + CompileAndVerify(comp, expectedOutput: expectedOutput).VerifyDiagnostics(expectedDiagnostics); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/72443")] + public void YieldInLock_Sync() + { + var source = """ + using System; + using System.Collections.Generic; + using System.Threading; + + object o = new object(); + Console.WriteLine($"Before: {Monitor.IsEntered(o)}"); + using (IEnumerator e = GetValues(o).GetEnumerator()) + { + Console.WriteLine($"Inside: {Monitor.IsEntered(o)}"); + while (e.MoveNext()) + { + Console.WriteLine($"{e.Current}: {Monitor.IsEntered(o)}"); + } + Console.WriteLine($"Done: {Monitor.IsEntered(o)}"); + } + Console.WriteLine($"After: {Monitor.IsEntered(o)}"); + + static IEnumerable GetValues(object obj) + { + lock (obj) + { + for (int i = 0; i < 3; i++) + { + yield return i; + + if (i == 1) + { + yield break; + } + } + } + } + """; + + var expectedOutput = """ + Before: False + Inside: False + 0: True + 1: True + Done: False + After: False + """; + + CompileAndVerify(source, options: TestOptions.ReleaseExe.WithWarningLevel(8), + expectedOutput: expectedOutput).VerifyDiagnostics(); + + var expectedDiagnostics = new[] + { + // (24,13): warning CS9230: 'yield return' should not be used in the body of a lock statement + // yield return i; + Diagnostic(ErrorCode.WRN_BadYieldInLock, "yield").WithLocation(24, 13) + }; + + CompileAndVerify(source, options: TestOptions.ReleaseExe.WithWarningLevel(9), + expectedOutput: expectedOutput).VerifyDiagnostics(expectedDiagnostics); + + CompileAndVerify(source, expectedOutput: expectedOutput).VerifyDiagnostics(expectedDiagnostics); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/72443")] + public void YieldInLock_Nested() + { + var source = """ + using System.Collections.Generic; + + class C + { + IEnumerable M() + { + yield return 1; + lock (this) + { + yield return 2; + + local(); + + IEnumerable local() + { + yield return 3; + + lock (this) + { + yield return 4; + + yield break; + } + } + + yield break; + } + } + } + """; + + CreateCompilation(source).VerifyDiagnostics( + // (10,13): warning CS9230: 'yield return' should not be used in the body of a lock statement + // yield return 2; + Diagnostic(ErrorCode.WRN_BadYieldInLock, "yield").WithLocation(10, 13), + // (20,21): warning CS9230: 'yield return' should not be used in the body of a lock statement + // yield return 4; + Diagnostic(ErrorCode.WRN_BadYieldInLock, "yield").WithLocation(20, 21)); + } + [WorkItem(546081, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/546081")] [Fact] public void IteratorBlockWithUnreachableCode()