File: CodeGen\CodeGenLockTests.cs
Web Access
Project: src\src\Compilers\CSharp\Test\Emit\Microsoft.CodeAnalysis.CSharp.Emit.UnitTests.csproj (Microsoft.CodeAnalysis.CSharp.Emit.UnitTests)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
 
#nullable disable
 
using Microsoft.CodeAnalysis.CSharp.Test.Utilities;
using Microsoft.CodeAnalysis.Test.Utilities;
using Roslyn.Test.Utilities;
using Xunit;
using Basic.Reference.Assemblies;
 
namespace Microsoft.CodeAnalysis.CSharp.UnitTests.CodeGen
{
    public class CodeGenLockTests : EmitMetadataTestBase
    {
        #region 4.0 codegen
 
        [Fact]
        public void LockNull()
        {
            var text =
@"
public class Test
{
    void M()
    {
        System.Console.WriteLine(""Before"");
        lock (null)
        {
            System.Console.WriteLine(""In"");
        }
        System.Console.WriteLine(""After"");
    }
}
";
            var verifier = CompileAndVerify(text);
            verifier.VerifyIL("Test.M", @"
{
  // Code size       55 (0x37)
  .maxstack  2
  .locals init (object V_0,
                bool V_1)
 -IL_0000:  ldstr      ""Before""
  IL_0005:  call       ""void System.Console.WriteLine(string)""
 -IL_000a:  ldnull
  IL_000b:  stloc.0
  IL_000c:  ldc.i4.0
  IL_000d:  stloc.1
  .try
  {
    IL_000e:  ldloc.0
    IL_000f:  ldloca.s   V_1
    IL_0011:  call       ""void System.Threading.Monitor.Enter(object, ref bool)""
   -IL_0016:  ldstr      ""In""
    IL_001b:  call       ""void System.Console.WriteLine(string)""
   -IL_0020:  leave.s    IL_002c
  }
  finally
  {
   ~IL_0022:  ldloc.1
    IL_0023:  brfalse.s  IL_002b
    IL_0025:  ldloc.0
    IL_0026:  call       ""void System.Threading.Monitor.Exit(object)""
   ~IL_002b:  endfinally
  }
 -IL_002c:  ldstr      ""After""
  IL_0031:  call       ""void System.Console.WriteLine(string)""
 -IL_0036:  ret
}", sequencePoints: "Test.M");
        }
 
        [Fact]
        public void LockLocal()
        {
            var text =
@"
public class Test
{
    void M()
    {
        object o = new object();
        System.Console.WriteLine(""Before"");
        lock (o)
        {
            System.Console.WriteLine(""In"");
        }
        System.Console.WriteLine(""After"");
    }
}
";
            var verifier = CompileAndVerify(text);
            verifier.VerifyIL("Test.M", @"
{
  // Code size       59 (0x3b)
  .maxstack  2
  .locals init (object V_0,
                bool V_1)
 -IL_0000:  newobj     ""object..ctor()""
 -IL_0005:  ldstr      ""Before""
  IL_000a:  call       ""void System.Console.WriteLine(string)""
 -IL_000f:  stloc.0
  IL_0010:  ldc.i4.0
  IL_0011:  stloc.1
  .try
  {
    IL_0012:  ldloc.0
    IL_0013:  ldloca.s   V_1
    IL_0015:  call       ""void System.Threading.Monitor.Enter(object, ref bool)""
   -IL_001a:  ldstr      ""In""
    IL_001f:  call       ""void System.Console.WriteLine(string)""
   -IL_0024:  leave.s    IL_0030
  }
  finally
  {
   ~IL_0026:  ldloc.1
    IL_0027:  brfalse.s  IL_002f
    IL_0029:  ldloc.0
    IL_002a:  call       ""void System.Threading.Monitor.Exit(object)""
   ~IL_002f:  endfinally
  }
 -IL_0030:  ldstr      ""After""
  IL_0035:  call       ""void System.Console.WriteLine(string)""
 -IL_003a:  ret
}", sequencePoints: "Test.M");
        }
 
        [Fact]
        public void LockParameter()
        {
            var text =
@"
public class Test
{
    void M(object o)
    {
        System.Console.WriteLine(""Before"");
        lock (o)
        {
            System.Console.WriteLine(""In"");
        }
        System.Console.WriteLine(""After"");
    }
}
";
            var verifier = CompileAndVerify(text);
            verifier.VerifyIL("Test.M", @"
{
  // Code size       55 (0x37)
  .maxstack  2
  .locals init (object V_0,
  bool V_1)
  IL_0000:  ldstr      ""Before""
  IL_0005:  call       ""void System.Console.WriteLine(string)""
  IL_000a:  ldarg.1
  IL_000b:  stloc.0
  IL_000c:  ldc.i4.0
  IL_000d:  stloc.1
  .try
  {
    IL_000e:  ldloc.0
    IL_000f:  ldloca.s   V_1
    IL_0011:  call       ""void System.Threading.Monitor.Enter(object, ref bool)""
    IL_0016:  ldstr      ""In""
    IL_001b:  call       ""void System.Console.WriteLine(string)""
    IL_0020:  leave.s    IL_002c
  }
  finally
  {
    IL_0022:  ldloc.1
    IL_0023:  brfalse.s  IL_002b
    IL_0025:  ldloc.0
    IL_0026:  call       ""void System.Threading.Monitor.Exit(object)""
    IL_002b:  endfinally
  }
  IL_002c:  ldstr      ""After""
  IL_0031:  call       ""void System.Console.WriteLine(string)""
  IL_0036:  ret
}");
        }
 
        [Fact]
        public void LockField()
        {
            var text =
@"
public class Test
{
    object o;
 
    void M()
    {
        System.Console.WriteLine(""Before"");
        lock (o)
        {
            System.Console.WriteLine(""In"");
        }
        System.Console.WriteLine(""After"");
    }
}
";
            var verifier = CompileAndVerify(text);
            verifier.VerifyIL("Test.M", @"
{
  // Code size       60 (0x3c)
  .maxstack  2
  .locals init (object V_0,
                bool V_1)
  IL_0000:  ldstr      ""Before""
  IL_0005:  call       ""void System.Console.WriteLine(string)""
  IL_000a:  ldarg.0
  IL_000b:  ldfld      ""object Test.o""
  IL_0010:  stloc.0
  IL_0011:  ldc.i4.0
  IL_0012:  stloc.1
  .try
  {
    IL_0013:  ldloc.0
    IL_0014:  ldloca.s   V_1
    IL_0016:  call       ""void System.Threading.Monitor.Enter(object, ref bool)""
    IL_001b:  ldstr      ""In""
    IL_0020:  call       ""void System.Console.WriteLine(string)""
    IL_0025:  leave.s    IL_0031
  }
  finally
  {
    IL_0027:  ldloc.1
    IL_0028:  brfalse.s  IL_0030
    IL_002a:  ldloc.0
    IL_002b:  call       ""void System.Threading.Monitor.Exit(object)""
    IL_0030:  endfinally
  }
  IL_0031:  ldstr      ""After""
  IL_0036:  call       ""void System.Console.WriteLine(string)""
  IL_003b:  ret
}");
        }
 
        [Fact]
        public void LockStaticField()
        {
            var text =
@"
public class Test
{
    static object o;
 
    void M()
    {
        System.Console.WriteLine(""Before"");
        lock (o)
        {
            System.Console.WriteLine(""In"");
        }
        System.Console.WriteLine(""After"");
    }
}
";
            var verifier = CompileAndVerify(text);
            verifier.VerifyIL("Test.M", @"
{
  // Code size       59 (0x3b)
  .maxstack  2
  .locals init (object V_0,
                bool V_1)
  IL_0000:  ldstr      ""Before""
  IL_0005:  call       ""void System.Console.WriteLine(string)""
  IL_000a:  ldsfld     ""object Test.o""
  IL_000f:  stloc.0
  IL_0010:  ldc.i4.0
  IL_0011:  stloc.1
  .try
  {
    IL_0012:  ldloc.0
    IL_0013:  ldloca.s   V_1
    IL_0015:  call       ""void System.Threading.Monitor.Enter(object, ref bool)""
    IL_001a:  ldstr      ""In""
    IL_001f:  call       ""void System.Console.WriteLine(string)""
    IL_0024:  leave.s    IL_0030
  }
  finally
  {
    IL_0026:  ldloc.1
    IL_0027:  brfalse.s  IL_002f
    IL_0029:  ldloc.0
    IL_002a:  call       ""void System.Threading.Monitor.Exit(object)""
    IL_002f:  endfinally
  }
  IL_0030:  ldstr      ""After""
  IL_0035:  call       ""void System.Console.WriteLine(string)""
  IL_003a:  ret
}");
        }
 
        [Fact]
        public void LockThis()
        {
            var text =
@"
public class Test
{
    void M()
    {
        System.Console.WriteLine(""Before"");
        lock (this)
        {
            System.Console.WriteLine(""In"");
        }
        System.Console.WriteLine(""After"");
    }
}
";
            var verifier = CompileAndVerify(text);
            verifier.VerifyIL("Test.M", @"
{
  // Code size       55 (0x37)
  .maxstack  2
  .locals init (Test V_0,
                bool V_1)
  IL_0000:  ldstr      ""Before""
  IL_0005:  call       ""void System.Console.WriteLine(string)""
  IL_000a:  ldarg.0
  IL_000b:  stloc.0
  IL_000c:  ldc.i4.0
  IL_000d:  stloc.1
  .try
  {
    IL_000e:  ldloc.0
    IL_000f:  ldloca.s   V_1
    IL_0011:  call       ""void System.Threading.Monitor.Enter(object, ref bool)""
    IL_0016:  ldstr      ""In""
    IL_001b:  call       ""void System.Console.WriteLine(string)""
    IL_0020:  leave.s    IL_002c
  }
  finally
  {
    IL_0022:  ldloc.1
    IL_0023:  brfalse.s  IL_002b
    IL_0025:  ldloc.0
    IL_0026:  call       ""void System.Threading.Monitor.Exit(object)""
    IL_002b:  endfinally
  }
  IL_002c:  ldstr      ""After""
  IL_0031:  call       ""void System.Console.WriteLine(string)""
  IL_0036:  ret
}");
        }
 
        [Fact]
        public void LockExpression()
        {
            var text =
@"
public class Test
{
    void M()
    {
        System.Console.WriteLine(""Before"");
        lock (new object())
        {
            System.Console.WriteLine(""In"");
        }
        System.Console.WriteLine(""After"");
    }
}
";
            var verifier = CompileAndVerify(text);
            verifier.VerifyIL("Test.M", @"
{
  // Code size       59 (0x3b)
  .maxstack  2
  .locals init (object V_0,
                bool V_1)
 -IL_0000:  ldstr      ""Before""
  IL_0005:  call       ""void System.Console.WriteLine(string)""
 -IL_000a:  newobj     ""object..ctor()""
  IL_000f:  stloc.0
  IL_0010:  ldc.i4.0
  IL_0011:  stloc.1
  .try
  {
    IL_0012:  ldloc.0
    IL_0013:  ldloca.s   V_1
    IL_0015:  call       ""void System.Threading.Monitor.Enter(object, ref bool)""
   -IL_001a:  ldstr      ""In""
    IL_001f:  call       ""void System.Console.WriteLine(string)""
   -IL_0024:  leave.s    IL_0030
  }
  finally
  {
   ~IL_0026:  ldloc.1
    IL_0027:  brfalse.s  IL_002f
    IL_0029:  ldloc.0
    IL_002a:  call       ""void System.Threading.Monitor.Exit(object)""
   ~IL_002f:  endfinally
  }
 -IL_0030:  ldstr      ""After""
  IL_0035:  call       ""void System.Console.WriteLine(string)""
 -IL_003a:  ret
}", sequencePoints: "Test.M");
        }
 
        [Fact]
        public void LockTypeParameterExpression()
        {
            var text =
@"
public class Test
{
    void M<T>(T t) where T : class
    {
        System.Console.WriteLine(""Before"");
        lock (t)
        {
            System.Console.WriteLine(""In"");
        }
        System.Console.WriteLine(""After"");
    }
}
";
            var verifier = CompileAndVerify(text);
            verifier.VerifyIL("Test.M<T>", @"
{
  // Code size       60 (0x3c)
  .maxstack  2
  .locals init (object V_0,
                bool V_1)
  IL_0000:  ldstr      ""Before""
  IL_0005:  call       ""void System.Console.WriteLine(string)""
  IL_000a:  ldarg.1
  IL_000b:  box        ""T""
  IL_0010:  stloc.0
  IL_0011:  ldc.i4.0
  IL_0012:  stloc.1
  .try
  {
    IL_0013:  ldloc.0
    IL_0014:  ldloca.s   V_1
    IL_0016:  call       ""void System.Threading.Monitor.Enter(object, ref bool)""
    IL_001b:  ldstr      ""In""
    IL_0020:  call       ""void System.Console.WriteLine(string)""
    IL_0025:  leave.s    IL_0031
  }
  finally
  {
    IL_0027:  ldloc.1
    IL_0028:  brfalse.s  IL_0030
    IL_002a:  ldloc.0
    IL_002b:  call       ""void System.Threading.Monitor.Exit(object)""
    IL_0030:  endfinally
  }
  IL_0031:  ldstr      ""After""
  IL_0036:  call       ""void System.Console.WriteLine(string)""
  IL_003b:  ret
}");
        }
 
        [Fact]
        public void LockQuery()
        {
            var text =
@"
using System.Linq;
class Test
{
    public static void Main()
    {
        System.Console.WriteLine(""Before"");
        lock (from x in ""ABC""
              select x)
        {
            System.Console.WriteLine(""In"");
        }
        System.Console.WriteLine(""After"");
    }
}
";
            var compilation = CreateCompilationWithMscorlib40AndSystemCore(text);
            CompileAndVerify(compilation).VerifyIL("Test.Main", @"
{
  // Code size       95 (0x5f)
  .maxstack  3
  .locals init (System.Collections.Generic.IEnumerable<char> V_0,
                bool V_1)
  IL_0000:  ldstr      ""Before""
  IL_0005:  call       ""void System.Console.WriteLine(string)""
  IL_000a:  ldstr      ""ABC""
  IL_000f:  ldsfld     ""System.Func<char, char> Test.<>c.<>9__0_0""
  IL_0014:  dup
  IL_0015:  brtrue.s   IL_002e
  IL_0017:  pop
  IL_0018:  ldsfld     ""Test.<>c Test.<>c.<>9""
  IL_001d:  ldftn      ""char Test.<>c.<Main>b__0_0(char)""
  IL_0023:  newobj     ""System.Func<char, char>..ctor(object, System.IntPtr)""
  IL_0028:  dup
  IL_0029:  stsfld     ""System.Func<char, char> Test.<>c.<>9__0_0""
  IL_002e:  call       ""System.Collections.Generic.IEnumerable<char> System.Linq.Enumerable.Select<char, char>(System.Collections.Generic.IEnumerable<char>, System.Func<char, char>)""
  IL_0033:  stloc.0
  IL_0034:  ldc.i4.0
  IL_0035:  stloc.1
  .try
  {
    IL_0036:  ldloc.0
    IL_0037:  ldloca.s   V_1
    IL_0039:  call       ""void System.Threading.Monitor.Enter(object, ref bool)""
    IL_003e:  ldstr      ""In""
    IL_0043:  call       ""void System.Console.WriteLine(string)""
    IL_0048:  leave.s    IL_0054
  }
  finally
  {
    IL_004a:  ldloc.1
    IL_004b:  brfalse.s  IL_0053
    IL_004d:  ldloc.0
    IL_004e:  call       ""void System.Threading.Monitor.Exit(object)""
    IL_0053:  endfinally
  }
  IL_0054:  ldstr      ""After""
  IL_0059:  call       ""void System.Console.WriteLine(string)""
  IL_005e:  ret
}
");
        }
 
        [Fact]
        public void LockDelegate()
        {
            var text =
@"
delegate void D(int p1);
partial class Test
{
    public static void Main()
    {
        D d1;
        lock (d1= PM)
        {
        }
    }
    static partial void PM(int p2);
    static partial void PM(int p2)
    {
    }
}
";
 
            CompileAndVerify(text, parseOptions: TestOptions.Regular10).VerifyIL("Test.Main", @"
{
  // Code size       36 (0x24)
  .maxstack  2
  .locals init (D V_0,
                bool V_1)
  IL_0000:  ldnull
  IL_0001:  ldftn      ""void Test.PM(int)""
  IL_0007:  newobj     ""D..ctor(object, System.IntPtr)""
  IL_000c:  stloc.0
  IL_000d:  ldc.i4.0
  IL_000e:  stloc.1
  .try
  {
    IL_000f:  ldloc.0
    IL_0010:  ldloca.s   V_1
    IL_0012:  call       ""void System.Threading.Monitor.Enter(object, ref bool)""
    IL_0017:  leave.s    IL_0023
  }
  finally
  {
    IL_0019:  ldloc.1
    IL_001a:  brfalse.s  IL_0022
    IL_001c:  ldloc.0
    IL_001d:  call       ""void System.Threading.Monitor.Exit(object)""
    IL_0022:  endfinally
  }
  IL_0023:  ret
}");
        }
 
        [Fact]
        public void InitInLock()
        {
            CompileAndVerify(@"
class Test
{
    public static void Main()
    {
        Res d;
        lock (d = new Res { x = 10, y = ""abc"" })
        {
            Test.Eval(d.x, 10);
            Test.Eval(d.y, ""abc"");
        }
    }
    static void Eval(object  x, object y)
    { }
}
class Res
{
    public int x;
    public object y;
}");
        }
 
        [Fact]
        public void ImplicitArraysInLockStatement()
        {
            CompileAndVerify(@"
class Test
{
    public static void Main()
    {
        int[] a = null;
        lock (a = new[] { 1, 2, 3 })// OK
        {
        }
 
        lock (new[] { 1, 2, 3 }) // OK
        {
        }
    }
}");
        }
 
        // Extension method call in a lock() or lock block
        [Fact()]
        public void ExtensionMethodCalledInLock()
        {
            var text =
@"
class Test
{
    public static void Main()
    {
        var myLock = new Test();
        lock (myLock.Test())
        {
        }
        lock (myLock)
        {
            Eval(myLock, myLock.Test());
        }
    }
    public static void Eval(object obj1, object obj2)
    {
    }
}
public static partial class Extensions
{
    public static object Test(this object o) { return o; }
}
";
            var compilation = CreateCompilationWithMscorlib40AndSystemCore(text);
            CompileAndVerify(compilation).VerifyIL("Test.Main", @"
{
  // Code size       72 (0x48)
  .maxstack  2
  .locals init (Test V_0, //myLock
                object V_1,
                bool V_2,
                Test V_3)
  IL_0000:  newobj     ""Test..ctor()""
  IL_0005:  stloc.0
  IL_0006:  ldloc.0
  IL_0007:  call       ""object Extensions.Test(object)""
  IL_000c:  stloc.1
  IL_000d:  ldc.i4.0
  IL_000e:  stloc.2
  .try
  {
    IL_000f:  ldloc.1
    IL_0010:  ldloca.s   V_2
    IL_0012:  call       ""void System.Threading.Monitor.Enter(object, ref bool)""
    IL_0017:  leave.s    IL_0023
  }
  finally
  {
    IL_0019:  ldloc.2
    IL_001a:  brfalse.s  IL_0022
    IL_001c:  ldloc.1
    IL_001d:  call       ""void System.Threading.Monitor.Exit(object)""
    IL_0022:  endfinally
  }
  IL_0023:  ldloc.0
  IL_0024:  stloc.3
  IL_0025:  ldc.i4.0
  IL_0026:  stloc.2
  .try
  {
    IL_0027:  ldloc.3
    IL_0028:  ldloca.s   V_2
    IL_002a:  call       ""void System.Threading.Monitor.Enter(object, ref bool)""
    IL_002f:  ldloc.0
    IL_0030:  ldloc.0
    IL_0031:  call       ""object Extensions.Test(object)""
    IL_0036:  call       ""void Test.Eval(object, object)""
    IL_003b:  leave.s    IL_0047
  }
  finally
  {
    IL_003d:  ldloc.2
    IL_003e:  brfalse.s  IL_0046
    IL_0040:  ldloc.3
    IL_0041:  call       ""void System.Threading.Monitor.Exit(object)""
    IL_0046:  endfinally
  }
  IL_0047:  ret
}");
        }
 
        // Anonymous types can appear in lock statements
        [Fact()]
        public void LockAnonymousTypes_1()
        {
            var text =
@"
class Test
{
    public static void Main()
    {
        var a = new { };
        lock (a)
        {
        }
    }
}
";
            CompileAndVerify(text).VerifyIL("Test.Main", @"
{
  // Code size       29 (0x1d)
  .maxstack  2
  .locals init (<>f__AnonymousType0 V_0,
                bool V_1)
  IL_0000:  newobj     ""<>f__AnonymousType0..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:  leave.s    IL_001c
  }
  finally
  {
    IL_0012:  ldloc.1
    IL_0013:  brfalse.s  IL_001b
    IL_0015:  ldloc.0
    IL_0016:  call       ""void System.Threading.Monitor.Exit(object)""
    IL_001b:  endfinally
  }
  IL_001c:  ret
}");
        }
 
        [Fact()]
        public void LockAnonymousTypes_2()
        {
            var text =
@"
class Test
{
    public static void Main()
    {
        var b = new { p1 = 10 };
        lock (b)
        {
        }
    }
}
";
            CompileAndVerify(text).VerifyIL("Test.Main", @"
{
  // Code size       31 (0x1f)
  .maxstack  2
  .locals init (<>f__AnonymousType0<int> V_0,
                bool V_1)
  IL_0000:  ldc.i4.s   10
  IL_0002:  newobj     ""<>f__AnonymousType0<int>..ctor(int)""
  IL_0007:  stloc.0
  IL_0008:  ldc.i4.0
  IL_0009:  stloc.1
  .try
  {
    IL_000a:  ldloc.0
    IL_000b:  ldloca.s   V_1
    IL_000d:  call       ""void System.Threading.Monitor.Enter(object, ref bool)""
    IL_0012:  leave.s    IL_001e
  }
  finally
  {
    IL_0014:  ldloc.1
    IL_0015:  brfalse.s  IL_001d
    IL_0017:  ldloc.0
    IL_0018:  call       ""void System.Threading.Monitor.Exit(object)""
    IL_001d:  endfinally
  }
  IL_001e:  ret
}");
        }
 
        [Fact()]
        public void LockAnonymousTypes_3()
        {
            var text =
@"
class Test
{
    public static void Main()
    {
        var c = new { p1 = 10.0, p2 = 'a' };
        lock (c)
        {
        }
    }
}
";
            CompileAndVerify(text).VerifyIL("Test.Main", @"
{
  // Code size       40 (0x28)
  .maxstack  2
  .locals init (<>f__AnonymousType0<double, char> V_0,
                bool V_1)
  IL_0000:  ldc.r8     10
  IL_0009:  ldc.i4.s   97
  IL_000b:  newobj     ""<>f__AnonymousType0<double, char>..ctor(double, char)""
  IL_0010:  stloc.0
  IL_0011:  ldc.i4.0
  IL_0012:  stloc.1
  .try
  {
    IL_0013:  ldloc.0
    IL_0014:  ldloca.s   V_1
    IL_0016:  call       ""void System.Threading.Monitor.Enter(object, ref bool)""
    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 LockTypeOf()
        {
            var text =
@"
class Test
{
    public static void Main()
    {
        lock (typeof(decimal))
        {
        }
    }
}
";
            CompileAndVerify(text).VerifyIL("Test.Main", @"
{
  // Code size       34 (0x22)
  .maxstack  2
  .locals init (System.Type V_0,
                bool V_1)
  IL_0000:  ldtoken    ""decimal""
  IL_0005:  call       ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)""
  IL_000a:  stloc.0
  IL_000b:  ldc.i4.0
  IL_000c:  stloc.1
  .try
  {
    IL_000d:  ldloc.0
    IL_000e:  ldloca.s   V_1
    IL_0010:  call       ""void System.Threading.Monitor.Enter(object, ref bool)""
    IL_0015:  leave.s    IL_0021
  }
  finally
  {
    IL_0017:  ldloc.1
    IL_0018:  brfalse.s  IL_0020
    IL_001a:  ldloc.0
    IL_001b:  call       ""void System.Threading.Monitor.Exit(object)""
    IL_0020:  endfinally
  }
  IL_0021:  ret
}");
        }
 
        [Fact()]
        public void LockGetType()
        {
            var text =
@"
class Test
{
    public static void Main()
    {
        var obj = new object();
        lock (obj.GetType())
        {
        }
    }
}
";
            CompileAndVerify(text).VerifyIL("Test.Main", @"
{
  // Code size       34 (0x22)
  .maxstack  2
  .locals init (System.Type V_0,
                bool V_1)
  IL_0000:  newobj     ""object..ctor()""
  IL_0005:  callvirt   ""System.Type object.GetType()""
  IL_000a:  stloc.0
  IL_000b:  ldc.i4.0
  IL_000c:  stloc.1
  .try
  {
    IL_000d:  ldloc.0
    IL_000e:  ldloca.s   V_1
    IL_0010:  call       ""void System.Threading.Monitor.Enter(object, ref bool)""
    IL_0015:  leave.s    IL_0021
  }
  finally
  {
    IL_0017:  ldloc.1
    IL_0018:  brfalse.s  IL_0020
    IL_001a:  ldloc.0
    IL_001b:  call       ""void System.Threading.Monitor.Exit(object)""
    IL_0020:  endfinally
  }
  IL_0021:  ret
}");
        }
 
        [Fact()]
        public void LockGetType_Struct()
        {
            var text =
@"
public class Test
{
    static S x = new S();
    public static  void Main()
    {
        lock (x.GetType())
        {
        }
    }
}
struct S
{ }
";
            CompileAndVerify(text).VerifyIL("Test.Main", @"
{
  // Code size       39 (0x27)
  .maxstack  2
  .locals init (System.Type V_0,
                bool V_1)
  IL_0000:  ldsfld     ""S Test.x""
  IL_0005:  box        ""S""
  IL_000a:  call       ""System.Type object.GetType()""
  IL_000f:  stloc.0
  IL_0010:  ldc.i4.0
  IL_0011:  stloc.1
  .try
  {
    IL_0012:  ldloc.0
    IL_0013:  ldloca.s   V_1
    IL_0015:  call       ""void System.Threading.Monitor.Enter(object, ref bool)""
    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 LockString()
        {
            var text =
@"
class Test
{
    public static void Main()
    {
        lock (""abc"")
        {
        }
    }
}
";
            CompileAndVerify(text).VerifyIL("Test.Main", @"
{
  // Code size       29 (0x1d)
  .maxstack  2
  .locals init (string V_0,
                bool V_1)
  IL_0000:  ldstr      ""abc""
  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:  leave.s    IL_001c
  }
  finally
  {
    IL_0012:  ldloc.1
    IL_0013:  brfalse.s  IL_001b
    IL_0015:  ldloc.0
    IL_0016:  call       ""void System.Threading.Monitor.Exit(object)""
    IL_001b:  endfinally
  }
  IL_001c:  ret
}");
        }
 
        [Fact()]
        public void NestedLock()
        {
            var text =
@"
class Test
{
    public void Main()
    {
        lock (typeof(Test))
        {
            Test C = new Test();
            lock (C)
            {
            }
        }
    }
}
";
            CompileAndVerify(text).VerifyIL("Test.Main", @"
{
  // Code size       60 (0x3c)
  .maxstack  2
  .locals init (System.Type V_0,
                bool V_1,
                Test V_2,
                bool V_3)
  IL_0000:  ldtoken    ""Test""
  IL_0005:  call       ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)""
  IL_000a:  stloc.0
  IL_000b:  ldc.i4.0
  IL_000c:  stloc.1
  .try
  {
    IL_000d:  ldloc.0
    IL_000e:  ldloca.s   V_1
    IL_0010:  call       ""void System.Threading.Monitor.Enter(object, ref bool)""
    IL_0015:  newobj     ""Test..ctor()""
    IL_001a:  stloc.2
    IL_001b:  ldc.i4.0
    IL_001c:  stloc.3
    .try
    {
      IL_001d:  ldloc.2
      IL_001e:  ldloca.s   V_3
      IL_0020:  call       ""void System.Threading.Monitor.Enter(object, ref bool)""
      IL_0025:  leave.s    IL_003b
    }
    finally
    {
      IL_0027:  ldloc.3
      IL_0028:  brfalse.s  IL_0030
      IL_002a:  ldloc.2
      IL_002b:  call       ""void System.Threading.Monitor.Exit(object)""
      IL_0030:  endfinally
    }
  }
  finally
  {
    IL_0031:  ldloc.1
    IL_0032:  brfalse.s  IL_003a
    IL_0034:  ldloc.0
    IL_0035:  call       ""void System.Threading.Monitor.Exit(object)""
    IL_003a:  endfinally
  }
  IL_003b:  ret
}");
        }
 
        [Fact()]
        public void NestedLock_2()
        {
            var text =
@"
class Test
{
    private object syncroot = new object();
    public void goo()
    {
        lock (syncroot)
        {
            lock (syncroot)
            {
            }
        }
    }
}
";
            CompileAndVerify(text).VerifyIL("Test.goo", @"
{
  // Code size       57 (0x39)
  .maxstack  2
  .locals init (object V_0,
                bool V_1,
                object V_2,
                bool V_3)
  IL_0000:  ldarg.0
  IL_0001:  ldfld      ""object Test.syncroot""
  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:  ldarg.0
    IL_0012:  ldfld      ""object Test.syncroot""
    IL_0017:  stloc.2
    IL_0018:  ldc.i4.0
    IL_0019:  stloc.3
    .try
    {
      IL_001a:  ldloc.2
      IL_001b:  ldloca.s   V_3
      IL_001d:  call       ""void System.Threading.Monitor.Enter(object, ref bool)""
      IL_0022:  leave.s    IL_0038
    }
    finally
    {
      IL_0024:  ldloc.3
      IL_0025:  brfalse.s  IL_002d
      IL_0027:  ldloc.2
      IL_0028:  call       ""void System.Threading.Monitor.Exit(object)""
      IL_002d:  endfinally
    }
  }
  finally
  {
    IL_002e:  ldloc.1
    IL_002f:  brfalse.s  IL_0037
    IL_0031:  ldloc.0
    IL_0032:  call       ""void System.Threading.Monitor.Exit(object)""
    IL_0037:  endfinally
  }
  IL_0038:  ret
}");
        }
 
        //	Yield return inside a lock statement
        [WorkItem(10765, "DevDiv_Projects/Roslyn")]
        [Fact()]
        public void YieldInLock()
        {
            var text =
@"
using System.Collections.Generic;
class Test
{
    int[] values = new int[] { 1, 2, 3, 4 };
    object lockObj = new object();
 
    public IEnumerable<int> Values()
    {
        lock (lockObj)
        {
            foreach (var i in values)
                yield return i;
        }
    }
}
";
            CompileAndVerify(text).VerifyIL("Test.Values", @"
{
  // Code size       15 (0xf)
  .maxstack  3
  IL_0000:  ldc.i4.s   -2
  IL_0002:  newobj     ""Test.<Values>d__2..ctor(int)""
  IL_0007:  dup
  IL_0008:  ldarg.0
  IL_0009:  stfld      ""Test Test.<Values>d__2.<>4__this""
  IL_000e:  ret
}");
        }
 
        [Fact()]
        public void YieldAfterLock()
        {
            var text =
@"
using System.Collections.Generic;
class Test
{
    public static void Main()
    { }
    public IEnumerable<int> Goo()
    {
        lock (new object())
        {
        }
        yield return 0;
    }
}
";
            CompileAndVerify(text);
        }
 
        // The definite assignment state of v at the beginning of expr is the same as the state of v at the beginning of stmt
        [Fact()]
        public void AssignmentInLock()
        {
            var text =
@"
class Test
{
    public static void Main()
    {
        object myLock = null;
        lock ((myLock == null).ToString())
        {
            System.Console.WriteLine(myLock.ToString());
        }
    }
}
";
            CompileAndVerify(text).VerifyIL("Test.Main", @"
{
  // Code size       49 (0x31)
  .maxstack  2
  .locals init (object V_0, //myLock
                string V_1,
                bool V_2,
                bool V_3)
  IL_0000:  ldnull
  IL_0001:  stloc.0
  IL_0002:  ldloc.0
  IL_0003:  ldnull
  IL_0004:  ceq
  IL_0006:  stloc.3
  IL_0007:  ldloca.s   V_3
  IL_0009:  call       ""string bool.ToString()""
  IL_000e:  stloc.1
  IL_000f:  ldc.i4.0
  IL_0010:  stloc.2
  .try
  {
    IL_0011:  ldloc.1
    IL_0012:  ldloca.s   V_2
    IL_0014:  call       ""void System.Threading.Monitor.Enter(object, ref bool)""
    IL_0019:  ldloc.0
    IL_001a:  callvirt   ""string object.ToString()""
    IL_001f:  call       ""void System.Console.WriteLine(string)""
    IL_0024:  leave.s    IL_0030
  }
  finally
  {
    IL_0026:  ldloc.2
    IL_0027:  brfalse.s  IL_002f
    IL_0029:  ldloc.1
    IL_002a:  call       ""void System.Threading.Monitor.Exit(object)""
    IL_002f:  endfinally
  }
  IL_0030:  ret
}");
        }
 
        // The definite assignment state of v on the control flow transfer to embedded-statement is the same as the state of v at the end of expr
        [Fact()]
        public void AssignmentInLock_1()
        {
            var text =
@"
class Test
{
    public static void Main()
    {
        object myLock;
        lock (myLock = new object())
        {
            System.Console.WriteLine(myLock);
        }
    }
}
";
            CompileAndVerify(text).VerifyIL("Test.Main", @"
{
  // Code size       37 (0x25)
  .maxstack  2
  .locals init (object V_0, //myLock
                object V_1,
                bool V_2)
  IL_0000:  newobj     ""object..ctor()""
  IL_0005:  dup
  IL_0006:  stloc.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:  ldloc.0
    IL_0013:  call       ""void System.Console.WriteLine(object)""
    IL_0018:  leave.s    IL_0024
  }
  finally
  {
    IL_001a:  ldloc.2
    IL_001b:  brfalse.s  IL_0023
    IL_001d:  ldloc.1
    IL_001e:  call       ""void System.Threading.Monitor.Exit(object)""
    IL_0023:  endfinally
  }
  IL_0024:  ret
}");
        }
 
        #endregion 4.0 codegen
 
        #region Pre-4.0 codegen
 
        [Fact]
        public void FallbackLockNull()
        {
            var text =
@"
public class Test
{
    void M()
    {
        System.Console.WriteLine(""Before"");
        lock (null)
        {
            System.Console.WriteLine(""In"");
        }
        System.Console.WriteLine(""After"");
    }
}
";
            var compilation = CreateCompilationWithCorlib20(text);
            var verifier = CompileAndVerify(compilation);
            verifier.VerifyIL("Test.M", @"
{
  // Code size       48 (0x30)
  .maxstack  1
  .locals init (object V_0)
 -IL_0000:  ldstr      ""Before""
  IL_0005:  call       ""void System.Console.WriteLine(string)""
 -IL_000a:  ldnull
  IL_000b:  stloc.0
  IL_000c:  ldloc.0
  IL_000d:  call       ""void System.Threading.Monitor.Enter(object)""
  .try
  {
   -IL_0012:  ldstr      ""In""
    IL_0017:  call       ""void System.Console.WriteLine(string)""
   -IL_001c:  leave.s    IL_0025
  }
  finally
  {
   ~IL_001e:  ldloc.0
    IL_001f:  call       ""void System.Threading.Monitor.Exit(object)""
    IL_0024:  endfinally
  }
 -IL_0025:  ldstr      ""After""
  IL_002a:  call       ""void System.Console.WriteLine(string)""
 -IL_002f:  ret
}", sequencePoints: "Test.M");
        }
 
        [Fact]
        public void FallbackLockLocal()
        {
            var text =
@"
public class Test
{
    void M()
    {
        object o = new object();
        System.Console.WriteLine(""Before"");
        lock (o)
        {
            System.Console.WriteLine(""In"");
        }
        System.Console.WriteLine(""After"");
    }
}
";
            var compilation = CreateCompilationWithCorlib20(text);
            var verifier = CompileAndVerify(compilation);
            verifier.VerifyIL("Test.M", @"
{
  // Code size       52 (0x34)
  .maxstack  2
  .locals init (object V_0)
  IL_0000:  newobj     ""object..ctor()""
  IL_0005:  ldstr      ""Before""
  IL_000a:  call       ""void System.Console.WriteLine(string)""
  IL_000f:  stloc.0
  IL_0010:  ldloc.0
  IL_0011:  call       ""void System.Threading.Monitor.Enter(object)""
  .try
  {
    IL_0016:  ldstr      ""In""
    IL_001b:  call       ""void System.Console.WriteLine(string)""
    IL_0020:  leave.s    IL_0029
  }
  finally
  {
    IL_0022:  ldloc.0
    IL_0023:  call       ""void System.Threading.Monitor.Exit(object)""
    IL_0028:  endfinally
  }
  IL_0029:  ldstr      ""After""
  IL_002e:  call       ""void System.Console.WriteLine(string)""
  IL_0033:  ret
}");
        }
 
        [Fact]
        public void FallbackLockParameter()
        {
            var text =
@"
public class Test
{
    void M(object o)
    {
        System.Console.WriteLine(""Before"");
        lock (o)
        {
            System.Console.WriteLine(""In"");
        }
        System.Console.WriteLine(""After"");
    }
}
";
            var compilation = CreateCompilationWithCorlib20(text);
            var verifier = CompileAndVerify(compilation);
            verifier.VerifyIL("Test.M", @"
{
  // Code size       48 (0x30)
  .maxstack  1
  .locals init (object V_0)
  IL_0000:  ldstr      ""Before""
  IL_0005:  call       ""void System.Console.WriteLine(string)""
  IL_000a:  ldarg.1
  IL_000b:  stloc.0
  IL_000c:  ldloc.0
  IL_000d:  call       ""void System.Threading.Monitor.Enter(object)""
  .try
  {
    IL_0012:  ldstr      ""In""
    IL_0017:  call       ""void System.Console.WriteLine(string)""
    IL_001c:  leave.s    IL_0025
  }
  finally
  {
    IL_001e:  ldloc.0
    IL_001f:  call       ""void System.Threading.Monitor.Exit(object)""
    IL_0024:  endfinally
  }
  IL_0025:  ldstr      ""After""
  IL_002a:  call       ""void System.Console.WriteLine(string)""
  IL_002f:  ret
}");
        }
 
        [Fact]
        public void FallbackLockField()
        {
            var text =
@"
public class Test
{
    object o;
 
    void M()
    {
        System.Console.WriteLine(""Before"");
        lock (o)
        {
            System.Console.WriteLine(""In"");
        }
        System.Console.WriteLine(""After"");
    }
}
";
            var compilation = CreateCompilationWithCorlib20(text);
            var verifier = CompileAndVerify(compilation);
            verifier.VerifyIL("Test.M", @"
{
  // Code size       53 (0x35)
  .maxstack  1
  .locals init (object V_0)
  IL_0000:  ldstr      ""Before""
  IL_0005:  call       ""void System.Console.WriteLine(string)""
  IL_000a:  ldarg.0
  IL_000b:  ldfld      ""object Test.o""
  IL_0010:  stloc.0
  IL_0011:  ldloc.0
  IL_0012:  call       ""void System.Threading.Monitor.Enter(object)""
  .try
  {
    IL_0017:  ldstr      ""In""
    IL_001c:  call       ""void System.Console.WriteLine(string)""
    IL_0021:  leave.s    IL_002a
  }
  finally
  {
    IL_0023:  ldloc.0
    IL_0024:  call       ""void System.Threading.Monitor.Exit(object)""
    IL_0029:  endfinally
  }
  IL_002a:  ldstr      ""After""
  IL_002f:  call       ""void System.Console.WriteLine(string)""
  IL_0034:  ret
}");
        }
 
        [Fact]
        public void FallbackLockStaticField()
        {
            var text =
@"
public class Test
{
    static object o;
 
    void M()
    {
        System.Console.WriteLine(""Before"");
        lock (o)
        {
            System.Console.WriteLine(""In"");
        }
        System.Console.WriteLine(""After"");
    }
}
";
            var compilation = CreateCompilationWithCorlib20(text);
            var verifier = CompileAndVerify(compilation);
            verifier.VerifyIL("Test.M", @"
{
  // Code size       52 (0x34)
  .maxstack  1
  .locals init (object V_0)
  IL_0000:  ldstr      ""Before""
  IL_0005:  call       ""void System.Console.WriteLine(string)""
  IL_000a:  ldsfld     ""object Test.o""
  IL_000f:  stloc.0
  IL_0010:  ldloc.0
  IL_0011:  call       ""void System.Threading.Monitor.Enter(object)""
  .try
  {
    IL_0016:  ldstr      ""In""
    IL_001b:  call       ""void System.Console.WriteLine(string)""
    IL_0020:  leave.s    IL_0029
  }
  finally
  {
    IL_0022:  ldloc.0
    IL_0023:  call       ""void System.Threading.Monitor.Exit(object)""
    IL_0028:  endfinally
  }
  IL_0029:  ldstr      ""After""
  IL_002e:  call       ""void System.Console.WriteLine(string)""
  IL_0033:  ret
}");
        }
 
        [Fact]
        public void FallbackLockThis()
        {
            var text =
@"
public class Test
{
    void M()
    {
        System.Console.WriteLine(""Before"");
        lock (this)
        {
            System.Console.WriteLine(""In"");
        }
        System.Console.WriteLine(""After"");
    }
}
";
            var compilation = CreateCompilationWithCorlib20(text);
            var verifier = CompileAndVerify(compilation);
            verifier.VerifyIL("Test.M", @"
{
  // Code size       48 (0x30)
  .maxstack  1
  .locals init (Test V_0)
  IL_0000:  ldstr      ""Before""
  IL_0005:  call       ""void System.Console.WriteLine(string)""
  IL_000a:  ldarg.0
  IL_000b:  stloc.0
  IL_000c:  ldloc.0
  IL_000d:  call       ""void System.Threading.Monitor.Enter(object)""
  .try
  {
    IL_0012:  ldstr      ""In""
    IL_0017:  call       ""void System.Console.WriteLine(string)""
    IL_001c:  leave.s    IL_0025
  }
  finally
  {
    IL_001e:  ldloc.0
    IL_001f:  call       ""void System.Threading.Monitor.Exit(object)""
    IL_0024:  endfinally
  }
  IL_0025:  ldstr      ""After""
  IL_002a:  call       ""void System.Console.WriteLine(string)""
  IL_002f:  ret
}");
        }
 
        [Fact]
        public void FallbackLockExpression()
        {
            var text =
@"
public class Test
{
    void M()
    {
        System.Console.WriteLine(""Before"");
        lock (new object())
        {
            System.Console.WriteLine(""In"");
        }
        System.Console.WriteLine(""After"");
    }
}
";
            var compilation = CreateCompilationWithCorlib20(text);
            var verifier = CompileAndVerify(compilation);
            verifier.VerifyIL("Test.M", @"
{
  // Code size       52 (0x34)
  .maxstack  1
  .locals init (object V_0)
  IL_0000:  ldstr      ""Before""
  IL_0005:  call       ""void System.Console.WriteLine(string)""
  IL_000a:  newobj     ""object..ctor()""
  IL_000f:  stloc.0
  IL_0010:  ldloc.0
  IL_0011:  call       ""void System.Threading.Monitor.Enter(object)""
  .try
  {
    IL_0016:  ldstr      ""In""
    IL_001b:  call       ""void System.Console.WriteLine(string)""
    IL_0020:  leave.s    IL_0029
  }
  finally
  {
    IL_0022:  ldloc.0
    IL_0023:  call       ""void System.Threading.Monitor.Exit(object)""
    IL_0028:  endfinally
  }
  IL_0029:  ldstr      ""After""
  IL_002e:  call       ""void System.Console.WriteLine(string)""
  IL_0033:  ret
}");
        }
 
        [Fact]
        public void FallbackLockTypeParameterExpression()
        {
            var text =
@"
public class Test
{
    void M<T>(T t) where T : class
    {
        System.Console.WriteLine(""Before"");
        lock (t)
        {
            System.Console.WriteLine(""In"");
        }
        System.Console.WriteLine(""After"");
    }
}
";
            var compilation = CreateCompilationWithCorlib20(text);
            var verifier = CompileAndVerify(compilation);
            verifier.VerifyIL("Test.M<T>", @"
{
  // Code size       53 (0x35)
  .maxstack  1
  .locals init (object V_0)
  IL_0000:  ldstr      ""Before""
  IL_0005:  call       ""void System.Console.WriteLine(string)""
  IL_000a:  ldarg.1
  IL_000b:  box        ""T""
  IL_0010:  stloc.0
  IL_0011:  ldloc.0
  IL_0012:  call       ""void System.Threading.Monitor.Enter(object)""
  .try
  {
    IL_0017:  ldstr      ""In""
    IL_001c:  call       ""void System.Console.WriteLine(string)""
    IL_0021:  leave.s    IL_002a
  }
  finally
  {
    IL_0023:  ldloc.0
    IL_0024:  call       ""void System.Threading.Monitor.Exit(object)""
    IL_0029:  endfinally
  }
  IL_002a:  ldstr      ""After""
  IL_002f:  call       ""void System.Console.WriteLine(string)""
  IL_0034:  ret
}");
        }
 
        private static CSharpCompilation CreateCompilationWithCorlib20(string text)
        {
            return CreateEmptyCompilation(new string[] { text }, new[] { Net20.References.mscorlib });
        }
 
        #endregion Pre-4.0 codegen
 
        #region Execution
 
        [Fact]
        public void ProducerConsumer()
        {
            var text =
@"
using System;
using System.Threading;
 
public class Buffer<T>
{
    private readonly object bufferLock = new object();
    private bool empty = true;
    private T item;
 
    public void Write(T newItem)
    {
        lock (bufferLock)
        {
            while (!empty) Monitor.Wait(bufferLock);
 
            item = newItem;
            empty = false;
            Console.Error.WriteLine(""{0} wrote {1}"", Thread.CurrentThread.Name, newItem);
            Monitor.PulseAll(bufferLock);
        }
    }
 
    public T Read()
    {
        lock (bufferLock)
        {
            while (empty) Monitor.Wait(bufferLock);
 
            empty = true;
            T result = item;
            Console.Error.WriteLine(""{0} read {1}"", Thread.CurrentThread.Name, result);
            Monitor.PulseAll(bufferLock);
            return result;
        }
    }
}
 
public class Program
{
    static void Main()
    {
        Buffer<int> buffer = new Buffer<int>();
 
        Thread writer = new Thread(() =>
        {
            for (int i = 0; i < 10; i++) buffer.Write(i);
        });
        writer.Name = ""Writer"";
 
        Thread reader = new Thread(() =>
        {
            for (int i = 0; i < 10; i++) buffer.Read();
        });
        reader.Name = ""Reader"";
 
        writer.Start();
        reader.Start();
        reader.Join();
        writer.Join();
    }
}
";
            CompileAndVerify(text, expectedOutput: @"Writer wrote 0
Reader read 0
Writer wrote 1
Reader read 1
Writer wrote 2
Reader read 2
Writer wrote 3
Reader read 3
Writer wrote 4
Reader read 4
Writer wrote 5
Reader read 5
Writer wrote 6
Reader read 6
Writer wrote 7
Reader read 7
Writer wrote 8
Reader read 8
Writer wrote 9
Reader read 9");
        }
 
        [Fact]
        public void ProducerConsumer_1()
        {
            var text =
@"
class C
{
    static void Main(string[] args)
    {
        D p = new D();
        System.Threading.Thread[] t = new System.Threading.Thread[20];
        for (int i = 0; i < 20; i++)
        {
            t[i] = new System.Threading.Thread(p.goo);
            t[i].Start();
        }
        for (int i = 0; i < 20; i++)
        {
            t[i].Join();
        }
        System.Console.WriteLine(p.s);
    }
}
 
class D
{
    private object syncroot = new object();
    public int s;
    public void goo()
    {
        lock (syncroot)
        {
            for (int i = 0; i < 50000; i++)
            {
                s += 1;
            }
        }
        return;
    }
}
";
            CompileAndVerify(text, expectedOutput: @"1000000");
        }
 
        #endregion Execution
 
        [Fact(), WorkItem(1106943, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/1106943")]
        public void Bug1106943_01()
        {
            var source = @"
class C1
{
    public static void Main()
    {
        lock (typeof(C1))
        {
            System.Console.WriteLine(""Inside lock."");
        }
    }
}";
 
            var compilation = CreateCompilation(source, options: TestOptions.ReleaseExe);
            compilation.MakeMemberMissing(WellKnownMember.System_Threading_Monitor__Enter);
 
            CompileAndVerify(compilation, expectedOutput: "Inside lock.");
        }
 
        [Fact(), WorkItem(1106943, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/1106943")]
        public void Bug1106943_02()
        {
            var source = @"
class C1
{
    public static void Main()
    {
        lock (typeof(C1))
        {
            System.Console.WriteLine(""Inside lock."");
        }
    }
}";
 
            var compilation = CreateCompilation(source, options: TestOptions.ReleaseExe);
            compilation.MakeMemberMissing(WellKnownMember.System_Threading_Monitor__Enter2);
 
            CompileAndVerify(compilation, expectedOutput: "Inside lock.");
        }
 
        [Fact(), WorkItem(1106943, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/1106943")]
        public void Bug1106943_03()
        {
            var source = @"
class C1
{
    public static void Main()
    {
        lock (typeof(C1))
        {
            System.Console.WriteLine(""Inside lock."");
        }
    }
}";
 
            var compilation = CreateCompilation(source, options: TestOptions.ReleaseExe);
            compilation.MakeMemberMissing(WellKnownMember.System_Threading_Monitor__Enter);
            compilation.MakeMemberMissing(WellKnownMember.System_Threading_Monitor__Enter2);
 
            compilation.VerifyEmitDiagnostics(
    // (6,9): error CS0656: Missing compiler required member 'System.Threading.Monitor.Enter'
    //         lock (typeof(C1))
    Diagnostic(ErrorCode.ERR_MissingPredefinedMember, @"lock (typeof(C1))
        {
            System.Console.WriteLine(""Inside lock."");
        }").WithArguments("System.Threading.Monitor", "Enter").WithLocation(6, 9)
                );
        }
 
        [Fact(), WorkItem(1106943, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/1106943")]
        public void Bug1106943_04()
        {
            var source = @"
class C1
{
    public static void Main()
    {
        lock (typeof(C1))
        {
            System.Console.WriteLine(""Inside lock."");
        }
    }
}";
 
            var compilation = CreateCompilation(source, options: TestOptions.ReleaseExe);
            compilation.MakeMemberMissing(WellKnownMember.System_Threading_Monitor__Exit);
 
            compilation.VerifyEmitDiagnostics(
    // (6,9): error CS0656: Missing compiler required member 'System.Threading.Monitor.Exit'
    //         lock (typeof(C1))
    Diagnostic(ErrorCode.ERR_MissingPredefinedMember, @"lock (typeof(C1))
        {
            System.Console.WriteLine(""Inside lock."");
        }").WithArguments("System.Threading.Monitor", "Exit").WithLocation(6, 9)
                );
        }
 
        [Fact(), WorkItem(1106943, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/1106943")]
        public void Bug1106943_05()
        {
            var source = @"
class C1
{
    public static void Main()
    {
        lock (typeof(C1))
        {
            System.Console.WriteLine(""Inside lock."");
        }
    }
}";
 
            var compilation = CreateCompilation(source, options: TestOptions.ReleaseExe);
            compilation.MakeMemberMissing(WellKnownMember.System_Threading_Monitor__Enter);
            compilation.MakeMemberMissing(WellKnownMember.System_Threading_Monitor__Enter2);
            compilation.MakeMemberMissing(WellKnownMember.System_Threading_Monitor__Exit);
 
            compilation.VerifyEmitDiagnostics(
    // (6,9): error CS0656: Missing compiler required member 'System.Threading.Monitor.Exit'
    //         lock (typeof(C1))
    Diagnostic(ErrorCode.ERR_MissingPredefinedMember, @"lock (typeof(C1))
        {
            System.Console.WriteLine(""Inside lock."");
        }").WithArguments("System.Threading.Monitor", "Exit").WithLocation(6, 9),
    // (6,9): error CS0656: Missing compiler required member 'System.Threading.Monitor.Enter'
    //         lock (typeof(C1))
    Diagnostic(ErrorCode.ERR_MissingPredefinedMember, @"lock (typeof(C1))
        {
            System.Console.WriteLine(""Inside lock."");
        }").WithArguments("System.Threading.Monitor", "Enter").WithLocation(6, 9)
                );
        }
 
        [Fact(), WorkItem(1106943, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/1106943")]
        public void Bug1106943_06()
        {
            var source = @"
class C1
{
    public static void Main()
    {
        lock (typeof(C1))
        {
            System.Console.WriteLine(""Inside lock."");
        }
    }
}";
 
            var compilation = CreateCompilation(source, options: TestOptions.ReleaseExe);
            compilation.MakeTypeMissing(WellKnownType.System_Threading_Monitor);
 
            compilation.VerifyEmitDiagnostics(
    // (6,9): error CS0656: Missing compiler required member 'System.Threading.Monitor.Exit'
    //         lock (typeof(C1))
    Diagnostic(ErrorCode.ERR_MissingPredefinedMember, @"lock (typeof(C1))
        {
            System.Console.WriteLine(""Inside lock."");
        }").WithArguments("System.Threading.Monitor", "Exit").WithLocation(6, 9),
    // (6,9): error CS0656: Missing compiler required member 'System.Threading.Monitor.Enter'
    //         lock (typeof(C1))
    Diagnostic(ErrorCode.ERR_MissingPredefinedMember, @"lock (typeof(C1))
        {
            System.Console.WriteLine(""Inside lock."");
        }").WithArguments("System.Threading.Monitor", "Enter").WithLocation(6, 9)
                );
        }
    }
}