From 795863aad784d0ca9ae575b589ece26b49493cae Mon Sep 17 00:00:00 2001 From: Levi Broderick Date: Sun, 3 May 2020 18:24:24 -0700 Subject: [PATCH 1/4] Work around some nullability warnings --- .../Runtime/CompilerServices/QCallHandles.cs | 14 ++++++- .../WindowsRuntime/ConstantSplittableMap.cs | 4 +- .../WindowsRuntime/DictionaryToMapAdapter.cs | 4 +- .../IReadOnlyDictionaryToIMapViewAdapter.cs | 4 +- .../System.Private.CoreLib.Shared.projitems | 1 + .../src/System/Array.cs | 2 + .../Collections/Concurrent/ConcurrentQueue.cs | 2 +- .../CodeAnalysis/NullabilityHelpers.cs | 23 +++++++++++ .../AsyncTaskMethodBuilderT.cs | 1 + .../AsyncValueTaskMethodBuilderT.cs | 1 + .../src/System/Threading/LazyInitializer.cs | 38 +++++++++++++------ .../System.Threading/ref/System.Threading.cs | 6 +-- 12 files changed, 75 insertions(+), 25 deletions(-) create mode 100644 src/libraries/System.Private.CoreLib/src/System/Diagnostics/CodeAnalysis/NullabilityHelpers.cs diff --git a/src/coreclr/src/System.Private.CoreLib/src/System/Runtime/CompilerServices/QCallHandles.cs b/src/coreclr/src/System.Private.CoreLib/src/System/Runtime/CompilerServices/QCallHandles.cs index 63a8fbf6e9c33..8936c43fb791f 100644 --- a/src/coreclr/src/System.Private.CoreLib/src/System/Runtime/CompilerServices/QCallHandles.cs +++ b/src/coreclr/src/System.Private.CoreLib/src/System/Runtime/CompilerServices/QCallHandles.cs @@ -18,6 +18,14 @@ internal unsafe ref struct StringHandleOnStack internal StringHandleOnStack([NotNull] ref string? s) { _ptr = Unsafe.AsPointer(ref s); + + // The StringHandleOnStack type itself doesn't guarantee that 's' is + // non-null. But the typical usage pattern is that this handle is + // passed to a QCall routine, and that QCall routine will ensure that + // the captured reference is non-null. So even though the [NonNull] + // annotation here is a lie we'll keep it around for convenience. + + NullabilityHelpers.SuppressNonNullAssignmentWarning(ref s); } } @@ -33,7 +41,11 @@ private ObjectHandleOnStack(void* pObject) internal static ObjectHandleOnStack Create([NotNull] ref T o) where T : class? { - return new ObjectHandleOnStack(Unsafe.AsPointer(ref o)); + // See comment in StringHandleOnStack ctor. + + void* ptr = Unsafe.AsPointer(ref o); + NullabilityHelpers.SuppressNonNullAssignmentWarning(ref o); + return new ObjectHandleOnStack(ptr); } } diff --git a/src/coreclr/src/System.Private.CoreLib/src/System/Runtime/InteropServices/WindowsRuntime/ConstantSplittableMap.cs b/src/coreclr/src/System.Private.CoreLib/src/System/Runtime/InteropServices/WindowsRuntime/ConstantSplittableMap.cs index f19d63e403449..d7cd618a07610 100644 --- a/src/coreclr/src/System.Private.CoreLib/src/System/Runtime/InteropServices/WindowsRuntime/ConstantSplittableMap.cs +++ b/src/coreclr/src/System.Private.CoreLib/src/System/Runtime/InteropServices/WindowsRuntime/ConstantSplittableMap.cs @@ -78,9 +78,7 @@ private KeyValuePair[] CreateKeyValueArray(int count, IEnumerator< public TValue Lookup(TKey key) { - bool found = TryGetValue(key, out TValue value); - - if (!found) + if (!TryGetValue(key, out TValue value)) { Debug.Assert(key != null); Exception e = new KeyNotFoundException(SR.Format(SR.Arg_KeyNotFoundWithKey, key.ToString())); diff --git a/src/coreclr/src/System.Private.CoreLib/src/System/Runtime/InteropServices/WindowsRuntime/DictionaryToMapAdapter.cs b/src/coreclr/src/System.Private.CoreLib/src/System/Runtime/InteropServices/WindowsRuntime/DictionaryToMapAdapter.cs index d24a0c9201d93..bdacad0d07f3b 100644 --- a/src/coreclr/src/System.Private.CoreLib/src/System/Runtime/InteropServices/WindowsRuntime/DictionaryToMapAdapter.cs +++ b/src/coreclr/src/System.Private.CoreLib/src/System/Runtime/InteropServices/WindowsRuntime/DictionaryToMapAdapter.cs @@ -28,9 +28,7 @@ private DictionaryToMapAdapter() internal V Lookup(K key) where K : notnull { IDictionary _this = Unsafe.As>(this); - bool keyFound = _this.TryGetValue(key, out V value); - - if (!keyFound) + if (!_this.TryGetValue(key, out V value)) { Debug.Assert(key != null); Exception e = new KeyNotFoundException(SR.Format(SR.Arg_KeyNotFoundWithKey, key.ToString())); diff --git a/src/coreclr/src/System.Private.CoreLib/src/System/Runtime/InteropServices/WindowsRuntime/IReadOnlyDictionaryToIMapViewAdapter.cs b/src/coreclr/src/System.Private.CoreLib/src/System/Runtime/InteropServices/WindowsRuntime/IReadOnlyDictionaryToIMapViewAdapter.cs index 5ba246996dccb..81c3a453b17a8 100644 --- a/src/coreclr/src/System.Private.CoreLib/src/System/Runtime/InteropServices/WindowsRuntime/IReadOnlyDictionaryToIMapViewAdapter.cs +++ b/src/coreclr/src/System.Private.CoreLib/src/System/Runtime/InteropServices/WindowsRuntime/IReadOnlyDictionaryToIMapViewAdapter.cs @@ -28,9 +28,7 @@ private IReadOnlyDictionaryToIMapViewAdapter() internal V Lookup(K key) where K : notnull { IReadOnlyDictionary _this = Unsafe.As>(this); - bool keyFound = _this.TryGetValue(key, out V value); - - if (!keyFound) + if (!_this.TryGetValue(key, out V value)) { Debug.Assert(key != null); Exception e = new KeyNotFoundException(SR.Format(SR.Arg_KeyNotFoundWithKey, key.ToString())); diff --git a/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems b/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems index 638aa0cc79f8e..81de15921b784 100644 --- a/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems +++ b/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems @@ -197,6 +197,7 @@ + diff --git a/src/libraries/System.Private.CoreLib/src/System/Array.cs b/src/libraries/System.Private.CoreLib/src/System/Array.cs index fa80d26e412b2..b311ef73abd3b 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Array.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Array.cs @@ -64,6 +64,8 @@ public static void Resize([NotNull] ref T[]? array, int newSize) Copy(larray, 0, newArray, 0, larray.Length > newSize ? newSize : larray.Length); array = newArray; } + + NullabilityHelpers.SuppressNonNullAssignmentWarning(ref array); } public static Array CreateInstance(Type elementType, params long[] lengths) diff --git a/src/libraries/System.Private.CoreLib/src/System/Collections/Concurrent/ConcurrentQueue.cs b/src/libraries/System.Private.CoreLib/src/System/Collections/Concurrent/ConcurrentQueue.cs index 480890eca55b8..b47e97c9d20c8 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Collections/Concurrent/ConcurrentQueue.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Collections/Concurrent/ConcurrentQueue.cs @@ -198,7 +198,7 @@ bool IProducerConsumerCollection.TryAdd(T item) /// For , this operation will attempt to remove the object /// from the beginning of the . /// - bool IProducerConsumerCollection.TryTake(out T item) => TryDequeue(out item); + bool IProducerConsumerCollection.TryTake([MaybeNullWhen(false)] out T item) => TryDequeue(out item); /// /// Gets a value that indicates whether the is empty. diff --git a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/CodeAnalysis/NullabilityHelpers.cs b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/CodeAnalysis/NullabilityHelpers.cs new file mode 100644 index 0000000000000..6524aa8cd03ec --- /dev/null +++ b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/CodeAnalysis/NullabilityHelpers.cs @@ -0,0 +1,23 @@ +// 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 Internal.Runtime.CompilerServices; + +namespace System.Diagnostics.CodeAnalysis +{ + internal static class NullabilityHelpers + { + /// + /// Suppresses CS8777: "Parameter 'name' must have a non-null value when exiting." + /// Used when a method accepts a 'ref' parameter that should be non-null on + /// method exit. + /// + [Conditional("NEVER")] + public static void SuppressNonNullAssignmentWarning([NotNull] ref T value) + where T : class? + { + Unsafe.SkipInit(out value!); // no-op + } + } +} diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/AsyncTaskMethodBuilderT.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/AsyncTaskMethodBuilderT.cs index 8aefd8a1773fd..c6251be585782 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/AsyncTaskMethodBuilderT.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/AsyncTaskMethodBuilderT.cs @@ -71,6 +71,7 @@ internal static void AwaitOnCompleted( catch (Exception e) { System.Threading.Tasks.Task.ThrowAsync(e, targetContext: null); + NullabilityHelpers.SuppressNonNullAssignmentWarning(ref taskField); } } diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/AsyncValueTaskMethodBuilderT.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/AsyncValueTaskMethodBuilderT.cs index d2bd7ec111a4b..206ca2be4d16b 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/AsyncValueTaskMethodBuilderT.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/AsyncValueTaskMethodBuilderT.cs @@ -161,6 +161,7 @@ internal static void AwaitOnCompleted( catch (Exception e) { System.Threading.Tasks.Task.ThrowAsync(e, targetContext: null); + NullabilityHelpers.SuppressNonNullAssignmentWarning(ref box); } } diff --git a/src/libraries/System.Private.CoreLib/src/System/Threading/LazyInitializer.cs b/src/libraries/System.Private.CoreLib/src/System/Threading/LazyInitializer.cs index 0e9ecac5877fb..ae190f434d96c 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Threading/LazyInitializer.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Threading/LazyInitializer.cs @@ -48,8 +48,12 @@ public static class LazyInitializer /// if an object was not used and to then dispose of the object appropriately. /// /// - public static T EnsureInitialized([NotNull] ref T? target) where T : class => - Volatile.Read(ref target) ?? EnsureInitializedCore(ref target); + public static T EnsureInitialized([NotNull] ref T? target) where T : class + { + T value = Volatile.Read(ref target) ?? EnsureInitializedCore(ref target); + NullabilityHelpers.SuppressNonNullAssignmentWarning(ref target); + return value; + } /// /// Initializes a target reference type with the type's default constructor (slow path) @@ -100,8 +104,12 @@ private static T EnsureInitializedCore([NotNull] ref T? target) where T : cla /// if an object was not used and to then dispose of the object appropriately. /// /// - public static T EnsureInitialized([NotNull] ref T? target, Func valueFactory) where T : class => - Volatile.Read(ref target) ?? EnsureInitializedCore(ref target, valueFactory); + public static T EnsureInitialized([NotNull] ref T? target, Func valueFactory) where T : class + { + T value = Volatile.Read(ref target) ?? EnsureInitializedCore(ref target, valueFactory); + NullabilityHelpers.SuppressNonNullAssignmentWarning(ref target); + return value; + } /// /// Initialize the target using the given delegate (slow path). @@ -133,9 +141,10 @@ private static T EnsureInitializedCore([NotNull] ref T? target, Func value /// A reference to a boolean that determines whether the target has already /// been initialized. /// A reference to an object used as the mutually exclusive lock for initializing - /// . If is null, a new object will be instantiated. + /// . If is null, and if the target hasn't already + /// been initialized, a new object will be instantiated. /// The initialized value of type . - public static T EnsureInitialized([AllowNull] ref T target, ref bool initialized, [NotNull] ref object? syncLock) + public static T EnsureInitialized([AllowNull] ref T target, ref bool initialized, [NotNullIfNotNull("syncLock")] ref object? syncLock) { // Fast path. if (Volatile.Read(ref initialized)) @@ -190,11 +199,12 @@ private static T EnsureInitializedCore([AllowNull] ref T target, ref bool ini /// A reference to a boolean that determines whether the target has already /// been initialized. /// A reference to an object used as the mutually exclusive lock for initializing - /// . If is null, a new object will be instantiated. + /// . If is null, and if the target hasn't already + /// been initialized, a new object will be instantiated. /// The invoked to initialize the /// reference or value. /// The initialized value of type . - public static T EnsureInitialized([AllowNull] ref T target, ref bool initialized, [NotNull] ref object? syncLock, Func valueFactory) + public static T EnsureInitialized([AllowNull] ref T target, ref bool initialized, [NotNullIfNotNull("syncLock")] ref object? syncLock, Func valueFactory) { // Fast path. if (Volatile.Read(ref initialized)) @@ -239,11 +249,16 @@ private static T EnsureInitializedCore([AllowNull] ref T target, ref bool ini /// The type of the reference to be initialized. Has to be reference type. /// A reference of type to initialize if it has not already been initialized. /// A reference to an object used as the mutually exclusive lock for initializing - /// . If is null, a new object will be instantiated. + /// . If is null, and if the target hasn't already + /// been initialized, a new object will be instantiated. /// The invoked to initialize the reference. /// The initialized value of type . - public static T EnsureInitialized([NotNull] ref T? target, [NotNull] ref object? syncLock, Func valueFactory) where T : class => - Volatile.Read(ref target) ?? EnsureInitializedCore(ref target, ref syncLock, valueFactory); + public static T EnsureInitialized([NotNull] ref T? target, [NotNullIfNotNull("syncLock")] ref object? syncLock, Func valueFactory) where T : class + { + T value = Volatile.Read(ref target) ?? EnsureInitializedCore(ref target, ref syncLock, valueFactory); + NullabilityHelpers.SuppressNonNullAssignmentWarning(ref target); + return value; + } /// /// Ensure the target is initialized and return the value (slow path). This overload works only for reference type targets. @@ -272,6 +287,7 @@ private static T EnsureInitializedCore([NotNull] ref T? target, [NotNull] ref } } + NullabilityHelpers.SuppressNonNullAssignmentWarning(ref target); return target!; // TODO-NULLABLE: Compiler can't infer target's non-nullness (https://github.com/dotnet/roslyn/issues/37300) } diff --git a/src/libraries/System.Threading/ref/System.Threading.cs b/src/libraries/System.Threading/ref/System.Threading.cs index 4c8dabcf6c621..719a4c35d1b0a 100644 --- a/src/libraries/System.Threading/ref/System.Threading.cs +++ b/src/libraries/System.Threading/ref/System.Threading.cs @@ -216,10 +216,10 @@ public static void MemoryBarrierProcessWide() { } public static partial class LazyInitializer { public static T EnsureInitialized([System.Diagnostics.CodeAnalysis.NotNullAttribute] ref T? target) where T : class { throw null; } - public static T EnsureInitialized([System.Diagnostics.CodeAnalysis.AllowNullAttribute] ref T target, ref bool initialized, [System.Diagnostics.CodeAnalysis.NotNullAttribute] ref object? syncLock) { throw null; } - public static T EnsureInitialized([System.Diagnostics.CodeAnalysis.AllowNullAttribute] ref T target, ref bool initialized, [System.Diagnostics.CodeAnalysis.NotNullAttribute] ref object? syncLock, System.Func valueFactory) { throw null; } + public static T EnsureInitialized([System.Diagnostics.CodeAnalysis.AllowNullAttribute] ref T target, ref bool initialized, [System.Diagnostics.CodeAnalysis.NotNullIfNotNullAttribute("syncLock")] ref object? syncLock) { throw null; } + public static T EnsureInitialized([System.Diagnostics.CodeAnalysis.AllowNullAttribute] ref T target, ref bool initialized, [System.Diagnostics.CodeAnalysis.NotNullIfNotNullAttribute("syncLock")] ref object? syncLock, System.Func valueFactory) { throw null; } public static T EnsureInitialized([System.Diagnostics.CodeAnalysis.NotNullAttribute] ref T? target, System.Func valueFactory) where T : class { throw null; } - public static T EnsureInitialized([System.Diagnostics.CodeAnalysis.NotNullAttribute] ref T? target, [System.Diagnostics.CodeAnalysis.NotNullAttribute] ref object? syncLock, System.Func valueFactory) where T : class { throw null; } + public static T EnsureInitialized([System.Diagnostics.CodeAnalysis.NotNullAttribute] ref T? target, [System.Diagnostics.CodeAnalysis.NotNullIfNotNullAttribute("syncLock")] ref object? syncLock, System.Func valueFactory) where T : class { throw null; } } public partial struct LockCookie { From 03abdbf99a8e7fad848442b1a80650a86121f045 Mon Sep 17 00:00:00 2001 From: Levi Broderick Date: Mon, 4 May 2020 10:29:10 -0700 Subject: [PATCH 2/4] PR feedback --- .../System/IO/FileLoadException.CoreCLR.cs | 2 +- .../src/System/Reflection/Assembly.CoreCLR.cs | 2 +- .../System/Reflection/Emit/AssemblyBuilder.cs | 2 +- .../src/System/Reflection/RuntimeAssembly.cs | 2 +- .../Runtime/CompilerServices/QCallHandles.cs | 18 +++------------ .../System.Private.CoreLib.Shared.projitems | 3 +-- .../src/System/Array.cs | 2 +- .../CodeAnalysis/NullabilityHelpers.cs | 23 ------------------- .../AsyncTaskMethodBuilderT.cs | 3 +-- .../AsyncValueTaskMethodBuilderT.cs | 3 +-- .../src/System/Threading/LazyInitializer.cs | 22 ++++-------------- 11 files changed, 16 insertions(+), 66 deletions(-) delete mode 100644 src/libraries/System.Private.CoreLib/src/System/Diagnostics/CodeAnalysis/NullabilityHelpers.cs diff --git a/src/coreclr/src/System.Private.CoreLib/src/System/IO/FileLoadException.CoreCLR.cs b/src/coreclr/src/System.Private.CoreLib/src/System/IO/FileLoadException.CoreCLR.cs index 2878b89a49cc4..b426926a95e3f 100644 --- a/src/coreclr/src/System.Private.CoreLib/src/System/IO/FileLoadException.CoreCLR.cs +++ b/src/coreclr/src/System.Private.CoreLib/src/System/IO/FileLoadException.CoreCLR.cs @@ -29,7 +29,7 @@ internal static string FormatFileLoadExceptionMessage(string? fileName, int hRes else GetMessageForHR(hResult, new StringHandleOnStack(ref message)); - return string.Format(format, fileName, message); + return string.Format(format!, fileName, message); } [DllImport(RuntimeHelpers.QCall, CharSet = CharSet.Unicode)] diff --git a/src/coreclr/src/System.Private.CoreLib/src/System/Reflection/Assembly.CoreCLR.cs b/src/coreclr/src/System.Private.CoreLib/src/System/Reflection/Assembly.CoreCLR.cs index c227155ef4664..8ef9d01d3ee70 100644 --- a/src/coreclr/src/System.Private.CoreLib/src/System/Reflection/Assembly.CoreCLR.cs +++ b/src/coreclr/src/System.Private.CoreLib/src/System/Reflection/Assembly.CoreCLR.cs @@ -62,7 +62,7 @@ internal static RuntimeAssembly GetExecutingAssembly(ref StackCrawlMark stackMar { RuntimeAssembly? retAssembly = null; GetExecutingAssemblyNative(new StackCrawlMarkHandle(ref stackMark), ObjectHandleOnStack.Create(ref retAssembly)); - return retAssembly; + return retAssembly!; } // Get the assembly that the current code is running from. diff --git a/src/coreclr/src/System.Private.CoreLib/src/System/Reflection/Emit/AssemblyBuilder.cs b/src/coreclr/src/System.Private.CoreLib/src/System/Reflection/Emit/AssemblyBuilder.cs index 2e0acab559016..3b190943be0d4 100644 --- a/src/coreclr/src/System.Private.CoreLib/src/System/Reflection/Emit/AssemblyBuilder.cs +++ b/src/coreclr/src/System.Private.CoreLib/src/System/Reflection/Emit/AssemblyBuilder.cs @@ -191,7 +191,7 @@ internal AssemblyBuilder(AssemblyName name, new StackCrawlMarkHandle(ref stackMark), (int)access, ObjectHandleOnStack.Create(ref retAssembly)); - _internalAssemblyBuilder = (InternalAssemblyBuilder)retAssembly; + _internalAssemblyBuilder = (InternalAssemblyBuilder)retAssembly!; _assemblyData = new AssemblyBuilderData(_internalAssemblyBuilder, access); diff --git a/src/coreclr/src/System.Private.CoreLib/src/System/Reflection/RuntimeAssembly.cs b/src/coreclr/src/System.Private.CoreLib/src/System/Reflection/RuntimeAssembly.cs index 60379a0cf9182..fd6eeb2bc23cb 100644 --- a/src/coreclr/src/System.Private.CoreLib/src/System/Reflection/RuntimeAssembly.cs +++ b/src/coreclr/src/System.Private.CoreLib/src/System/Reflection/RuntimeAssembly.cs @@ -327,7 +327,7 @@ internal static RuntimeAssembly InternalLoad(AssemblyName assemblyName, throwOnFileNotFound, ObjectHandleOnStack.Create(ref assemblyLoadContext), ObjectHandleOnStack.Create(ref retAssembly)); - return retAssembly; + return retAssembly!; } [DllImport(RuntimeHelpers.QCall, CharSet = CharSet.Unicode)] diff --git a/src/coreclr/src/System.Private.CoreLib/src/System/Runtime/CompilerServices/QCallHandles.cs b/src/coreclr/src/System.Private.CoreLib/src/System/Runtime/CompilerServices/QCallHandles.cs index 8936c43fb791f..6a3418ade5938 100644 --- a/src/coreclr/src/System.Private.CoreLib/src/System/Runtime/CompilerServices/QCallHandles.cs +++ b/src/coreclr/src/System.Private.CoreLib/src/System/Runtime/CompilerServices/QCallHandles.cs @@ -15,17 +15,9 @@ internal unsafe ref struct StringHandleOnStack { private void* _ptr; - internal StringHandleOnStack([NotNull] ref string? s) + internal StringHandleOnStack(ref string? s) { _ptr = Unsafe.AsPointer(ref s); - - // The StringHandleOnStack type itself doesn't guarantee that 's' is - // non-null. But the typical usage pattern is that this handle is - // passed to a QCall routine, and that QCall routine will ensure that - // the captured reference is non-null. So even though the [NonNull] - // annotation here is a lie we'll keep it around for convenience. - - NullabilityHelpers.SuppressNonNullAssignmentWarning(ref s); } } @@ -39,13 +31,9 @@ private ObjectHandleOnStack(void* pObject) _ptr = pObject; } - internal static ObjectHandleOnStack Create([NotNull] ref T o) where T : class? + internal static ObjectHandleOnStack Create(ref T o) where T : class? { - // See comment in StringHandleOnStack ctor. - - void* ptr = Unsafe.AsPointer(ref o); - NullabilityHelpers.SuppressNonNullAssignmentWarning(ref o); - return new ObjectHandleOnStack(ptr); + return new ObjectHandleOnStack(Unsafe.AsPointer(ref o)); } } diff --git a/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems b/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems index 81de15921b784..f872dc2bd907f 100644 --- a/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems +++ b/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems @@ -197,7 +197,6 @@ - @@ -1862,4 +1861,4 @@ - + \ No newline at end of file diff --git a/src/libraries/System.Private.CoreLib/src/System/Array.cs b/src/libraries/System.Private.CoreLib/src/System/Array.cs index b311ef73abd3b..d3753a1b6bf78 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Array.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Array.cs @@ -65,7 +65,7 @@ public static void Resize([NotNull] ref T[]? array, int newSize) array = newArray; } - NullabilityHelpers.SuppressNonNullAssignmentWarning(ref array); + Debug.Assert(array != null); } public static Array CreateInstance(Type elementType, params long[] lengths) diff --git a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/CodeAnalysis/NullabilityHelpers.cs b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/CodeAnalysis/NullabilityHelpers.cs deleted file mode 100644 index 6524aa8cd03ec..0000000000000 --- a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/CodeAnalysis/NullabilityHelpers.cs +++ /dev/null @@ -1,23 +0,0 @@ -// 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 Internal.Runtime.CompilerServices; - -namespace System.Diagnostics.CodeAnalysis -{ - internal static class NullabilityHelpers - { - /// - /// Suppresses CS8777: "Parameter 'name' must have a non-null value when exiting." - /// Used when a method accepts a 'ref' parameter that should be non-null on - /// method exit. - /// - [Conditional("NEVER")] - public static void SuppressNonNullAssignmentWarning([NotNull] ref T value) - where T : class? - { - Unsafe.SkipInit(out value!); // no-op - } - } -} diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/AsyncTaskMethodBuilderT.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/AsyncTaskMethodBuilderT.cs index c6251be585782..e195976f1f8c5 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/AsyncTaskMethodBuilderT.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/AsyncTaskMethodBuilderT.cs @@ -60,7 +60,7 @@ public void AwaitOnCompleted( AwaitOnCompleted(ref awaiter, ref stateMachine, ref m_task); internal static void AwaitOnCompleted( - ref TAwaiter awaiter, ref TStateMachine stateMachine, [NotNull] ref Task? taskField) + ref TAwaiter awaiter, ref TStateMachine stateMachine, ref Task? taskField) where TAwaiter : INotifyCompletion where TStateMachine : IAsyncStateMachine { @@ -71,7 +71,6 @@ internal static void AwaitOnCompleted( catch (Exception e) { System.Threading.Tasks.Task.ThrowAsync(e, targetContext: null); - NullabilityHelpers.SuppressNonNullAssignmentWarning(ref taskField); } } diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/AsyncValueTaskMethodBuilderT.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/AsyncValueTaskMethodBuilderT.cs index 206ca2be4d16b..c298c0533d57c 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/AsyncValueTaskMethodBuilderT.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/AsyncValueTaskMethodBuilderT.cs @@ -150,7 +150,7 @@ public void AwaitOnCompleted(ref TAwaiter awaiter, ref } internal static void AwaitOnCompleted( - ref TAwaiter awaiter, ref TStateMachine stateMachine, [NotNull] ref StateMachineBox? box) + ref TAwaiter awaiter, ref TStateMachine stateMachine, ref StateMachineBox? box) where TAwaiter : INotifyCompletion where TStateMachine : IAsyncStateMachine { @@ -161,7 +161,6 @@ internal static void AwaitOnCompleted( catch (Exception e) { System.Threading.Tasks.Task.ThrowAsync(e, targetContext: null); - NullabilityHelpers.SuppressNonNullAssignmentWarning(ref box); } } diff --git a/src/libraries/System.Private.CoreLib/src/System/Threading/LazyInitializer.cs b/src/libraries/System.Private.CoreLib/src/System/Threading/LazyInitializer.cs index ae190f434d96c..1c2a16d0c44a3 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Threading/LazyInitializer.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Threading/LazyInitializer.cs @@ -49,11 +49,7 @@ public static class LazyInitializer /// /// public static T EnsureInitialized([NotNull] ref T? target) where T : class - { - T value = Volatile.Read(ref target) ?? EnsureInitializedCore(ref target); - NullabilityHelpers.SuppressNonNullAssignmentWarning(ref target); - return value; - } + => Volatile.Read(ref target!) ?? EnsureInitializedCore(ref target); /// /// Initializes a target reference type with the type's default constructor (slow path) @@ -105,11 +101,7 @@ private static T EnsureInitializedCore([NotNull] ref T? target) where T : cla /// /// public static T EnsureInitialized([NotNull] ref T? target, Func valueFactory) where T : class - { - T value = Volatile.Read(ref target) ?? EnsureInitializedCore(ref target, valueFactory); - NullabilityHelpers.SuppressNonNullAssignmentWarning(ref target); - return value; - } + => Volatile.Read(ref target!) ?? EnsureInitializedCore(ref target, valueFactory); /// /// Initialize the target using the given delegate (slow path). @@ -254,11 +246,7 @@ private static T EnsureInitializedCore([AllowNull] ref T target, ref bool ini /// The invoked to initialize the reference. /// The initialized value of type . public static T EnsureInitialized([NotNull] ref T? target, [NotNullIfNotNull("syncLock")] ref object? syncLock, Func valueFactory) where T : class - { - T value = Volatile.Read(ref target) ?? EnsureInitializedCore(ref target, ref syncLock, valueFactory); - NullabilityHelpers.SuppressNonNullAssignmentWarning(ref target); - return value; - } + => Volatile.Read(ref target!) ?? EnsureInitializedCore(ref target, ref syncLock, valueFactory); /// /// Ensure the target is initialized and return the value (slow path). This overload works only for reference type targets. @@ -287,8 +275,8 @@ private static T EnsureInitializedCore([NotNull] ref T? target, [NotNull] ref } } - NullabilityHelpers.SuppressNonNullAssignmentWarning(ref target); - return target!; // TODO-NULLABLE: Compiler can't infer target's non-nullness (https://github.com/dotnet/roslyn/issues/37300) + Debug.Assert(target != null); + return target; } /// From ba4ecc868d88fba2e36952708f5fd21f08d69172 Mon Sep 17 00:00:00 2001 From: Levi Broderick Date: Mon, 4 May 2020 10:45:44 -0700 Subject: [PATCH 3/4] Re-introduce newline --- .../src/System.Private.CoreLib.Shared.projitems | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems b/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems index f872dc2bd907f..638aa0cc79f8e 100644 --- a/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems +++ b/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems @@ -1861,4 +1861,4 @@ - \ No newline at end of file + From 0a391f4282de5f32ba527557281a22b42835d39c Mon Sep 17 00:00:00 2001 From: Levi Broderick Date: Mon, 4 May 2020 10:47:47 -0700 Subject: [PATCH 4/4] Restore => operator placement --- .../src/System/Threading/LazyInitializer.cs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/libraries/System.Private.CoreLib/src/System/Threading/LazyInitializer.cs b/src/libraries/System.Private.CoreLib/src/System/Threading/LazyInitializer.cs index 1c2a16d0c44a3..8e2e63c2d0670 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Threading/LazyInitializer.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Threading/LazyInitializer.cs @@ -48,8 +48,8 @@ public static class LazyInitializer /// if an object was not used and to then dispose of the object appropriately. /// /// - public static T EnsureInitialized([NotNull] ref T? target) where T : class - => Volatile.Read(ref target!) ?? EnsureInitializedCore(ref target); + public static T EnsureInitialized([NotNull] ref T? target) where T : class => + Volatile.Read(ref target!) ?? EnsureInitializedCore(ref target); /// /// Initializes a target reference type with the type's default constructor (slow path) @@ -100,8 +100,8 @@ private static T EnsureInitializedCore([NotNull] ref T? target) where T : cla /// if an object was not used and to then dispose of the object appropriately. /// /// - public static T EnsureInitialized([NotNull] ref T? target, Func valueFactory) where T : class - => Volatile.Read(ref target!) ?? EnsureInitializedCore(ref target, valueFactory); + public static T EnsureInitialized([NotNull] ref T? target, Func valueFactory) where T : class => + Volatile.Read(ref target!) ?? EnsureInitializedCore(ref target, valueFactory); /// /// Initialize the target using the given delegate (slow path). @@ -245,8 +245,8 @@ private static T EnsureInitializedCore([AllowNull] ref T target, ref bool ini /// been initialized, a new object will be instantiated. /// The invoked to initialize the reference. /// The initialized value of type . - public static T EnsureInitialized([NotNull] ref T? target, [NotNullIfNotNull("syncLock")] ref object? syncLock, Func valueFactory) where T : class - => Volatile.Read(ref target!) ?? EnsureInitializedCore(ref target, ref syncLock, valueFactory); + public static T EnsureInitialized([NotNull] ref T? target, [NotNullIfNotNull("syncLock")] ref object? syncLock, Func valueFactory) where T : class => + Volatile.Read(ref target!) ?? EnsureInitializedCore(ref target, ref syncLock, valueFactory); /// /// Ensure the target is initialized and return the value (slow path). This overload works only for reference type targets.