Nullable: Interlocked, Volatile (dotnet/coreclr#23655)
authorStephen Toub <stoub@microsoft.com>
Tue, 2 Apr 2019 18:53:47 +0000 (14:53 -0400)
committerGitHub <noreply@github.com>
Tue, 2 Apr 2019 18:53:47 +0000 (14:53 -0400)
Also fixing the class? annotation on public LazyInitializer methods.

Commit migrated from https://github.com/dotnet/coreclr/commit/d8bcff11111e4da740986d3725722c2f28515e2a

src/coreclr/src/System.Private.CoreLib/src/System/Threading/Interlocked.cs
src/libraries/System.Private.CoreLib/src/System/Threading/LazyInitializer.cs
src/libraries/System.Private.CoreLib/src/System/Threading/Volatile.cs

index 8744b4c..844c888 100644 (file)
@@ -2,6 +2,7 @@
 // The .NET Foundation licenses this file to you under the MIT license.
 // See the LICENSE file in the project root for more information.
 
+#nullable enable
 using System.Runtime.CompilerServices;
 using Internal.Runtime.CompilerServices;
 using System.Runtime.InteropServices;
@@ -59,7 +60,7 @@ namespace System.Threading
         public static extern double Exchange(ref double location1, double value);
 
         [MethodImplAttribute(MethodImplOptions.InternalCall)]
-        public static extern object Exchange(ref object location1, object value);
+        public static extern object? Exchange(ref object? location1, object? value);
 
         [MethodImplAttribute(MethodImplOptions.InternalCall)]
         public static extern IntPtr Exchange(ref IntPtr location1, IntPtr value);
@@ -67,9 +68,9 @@ namespace System.Threading
         // This whole method reduces to a single call to Exchange(ref object, object) but
         // the JIT thinks that it will generate more native code than it actually does.
         [MethodImpl(MethodImplOptions.AggressiveInlining)]
-        public static T Exchange<T>(ref T location1, T value) where T : class
+        public static T Exchange<T>(ref T location1, T value) where T : class?
         {
-            return Unsafe.As<T>(Exchange(ref Unsafe.As<T, object>(ref location1), value));
+            return Unsafe.As<T>(Exchange(ref Unsafe.As<T, object?>(ref location1), value));
         }
 
         /// <summary>
@@ -88,7 +89,7 @@ namespace System.Threading
         public static extern double CompareExchange(ref double location1, double value, double comparand);
 
         [MethodImplAttribute(MethodImplOptions.InternalCall)]
-        public static extern object CompareExchange(ref object location1, object value, object comparand);
+        public static extern object? CompareExchange(ref object? location1, object? value, object? comparand);
 
         [MethodImplAttribute(MethodImplOptions.InternalCall)]
         public static extern IntPtr CompareExchange(ref IntPtr location1, IntPtr value, IntPtr comparand);
@@ -102,9 +103,9 @@ namespace System.Threading
         //     ret
         // The workaround is no longer strictly necessary now that we have Unsafe.As but it does
         // have the advantage of being less sensitive to JIT's inliner decisions.
-        public static T CompareExchange<T>(ref T location1, T value, T comparand) where T : class
+        public static T CompareExchange<T>(ref T location1, T value, T comparand) where T : class?
         {
-            return Unsafe.As<T>(CompareExchange(ref Unsafe.As<T, object>(ref location1), value, comparand));
+            return Unsafe.As<T>(CompareExchange(ref Unsafe.As<T, object?>(ref location1), value, comparand));
         }
 
         // BCL-internal overload that returns success via a ref bool param, useful for reliable spin locks.
index 7f28a9f..b25db6a 100644 (file)
@@ -48,7 +48,7 @@ namespace System.Threading
         /// if an object was not used and to then dispose of the object appropriately.
         /// </para>
         /// </remarks>
-        public static T EnsureInitialized<T>(ref T target) where T : class =>
+        public static T EnsureInitialized<T>(ref T target) where T : class? =>
             Volatile.Read(ref target) ?? EnsureInitializedCore(ref target);
 
         /// <summary>
@@ -57,7 +57,7 @@ namespace System.Threading
         /// <typeparam name="T">The reference type of the reference to be initialized.</typeparam>
         /// <param name="target">The variable that need to be initialized</param>
         /// <returns>The initialized variable</returns>
-        private static T EnsureInitializedCore<T>(ref T target) where T : class
+        private static T EnsureInitializedCore<T>(ref T target) where T : class?
         {
             try
             {
@@ -100,7 +100,7 @@ namespace System.Threading
         /// if an object was not used and to then dispose of the object appropriately.
         /// </para>
         /// </remarks>
-        public static T EnsureInitialized<T>(ref T target, Func<T> valueFactory) where T : class =>
+        public static T EnsureInitialized<T>(ref T target, Func<T> valueFactory) where T : class? =>
             Volatile.Read(ref target) ?? EnsureInitializedCore(ref target, valueFactory);
 
         /// <summary>
@@ -110,7 +110,7 @@ namespace System.Threading
         /// <param name="target">The variable that need to be initialized</param>
         /// <param name="valueFactory">The delegate that will be executed to initialize the target</param>
         /// <returns>The initialized variable</returns>
-        private static T EnsureInitializedCore<T>(ref T target, Func<T> valueFactory) where T : class
+        private static T EnsureInitializedCore<T>(ref T target, Func<T> valueFactory) where T : class?
         {
             T value = valueFactory();
             if (value == null)
@@ -242,7 +242,7 @@ namespace System.Threading
         /// <paramref name="target"/>. If <paramref name="syncLock"/> is null, a new object will be instantiated.</param>
         /// <param name="valueFactory">The <see cref="T:System.Func{T}"/> invoked to initialize the reference.</param>
         /// <returns>The initialized value of type <typeparamref name="T"/>.</returns>
-        public static T EnsureInitialized<T>(ref T target, ref object? syncLock, Func<T> valueFactory) where T : class =>
+        public static T EnsureInitialized<T>(ref T target, ref object? syncLock, Func<T> valueFactory) where T : class? =>
             Volatile.Read(ref target) ?? EnsureInitializedCore(ref target, ref syncLock, valueFactory);
 
         /// <summary>
@@ -257,7 +257,7 @@ namespace System.Threading
         /// The <see cref="T:System.Func{T}"/> to invoke in order to produce the lazily-initialized value.
         /// </param>
         /// <returns>The initialized object.</returns>
-        private static T EnsureInitializedCore<T>(ref T target, ref object? syncLock, Func<T> valueFactory) where T : class
+        private static T EnsureInitializedCore<T>(ref T target, ref object? syncLock, Func<T> valueFactory) where T : class?
         {
             // Lazily initialize the lock if necessary and then double check if initialization is still required.
             lock (EnsureLockInitialized(ref syncLock))
@@ -284,6 +284,6 @@ namespace System.Threading
         private static object EnsureLockInitialized(ref object? syncLock) =>
             syncLock ??
             Interlocked.CompareExchange(ref syncLock, new object(), null) ??
-            syncLock;
+            syncLock!; // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761
     }
 }
index 845d2d0..4ace8f9 100644 (file)
@@ -2,6 +2,7 @@
 // The .NET Foundation licenses this file to you under the MIT license.
 // See the LICENSE file in the project root for more information.
 
+#nullable enable
 using System.Runtime.CompilerServices;
 using System.Runtime.Versioning;
 using Internal.Runtime.CompilerServices;
@@ -214,16 +215,16 @@ namespace System.Threading
         #endregion
 
         #region T
-        private struct VolatileObject { public volatile object Value; }
+        private struct VolatileObject { public volatile object? Value; }
 
         [Intrinsic]
         [NonVersionable]
-        public static T Read<T>(ref T location) where T : class =>
+        public static T Read<T>(ref T location) where T : class? =>
             Unsafe.As<T>(Unsafe.As<T, VolatileObject>(ref location).Value);
 
         [Intrinsic]
         [NonVersionable]
-        public static void Write<T>(ref T location, T value) where T : class =>
+        public static void Write<T>(ref T location, T value) where T : class? =>
             Unsafe.As<T, VolatileObject>(ref location).Value = value;
         #endregion
     }