From 4a1275434fff99206f2a28f5f0e87f124069eb7f Mon Sep 17 00:00:00 2001 From: Stephen Toub Date: Tue, 28 May 2019 06:04:13 -0400 Subject: [PATCH] Add and apply nullable attributes (#24679) * Add and apply nullable attributes * Adapt to API review decisions * Address PR feedback --- .../System.Private.CoreLib.csproj | 4 +- .../shared/Internal/Win32/RegistryKey.cs | 12 +- .../shared/Interop/Unix/Interop.Errors.cs | 2 - .../Unix/System.Native/Interop.MountPoints.cs | 4 +- .../Interop/Windows/Kernel32/Interop.CreateFile.cs | 6 +- .../Windows/Kernel32/Interop.CreateFile2.cs | 5 +- .../Windows/Kernel32/Interop.FindFirstFileEx.cs | 5 +- .../Kernel32/Interop.GetFileAttributesEx.cs | 5 +- .../shared/System.Private.CoreLib.Shared.projitems | 1 + .../shared/System/AppContext.cs | 2 +- .../shared/System/AppDomain.cs | 4 +- src/System.Private.CoreLib/shared/System/Array.cs | 139 +++++++++++---------- .../shared/System/ArraySegment.cs | 4 +- .../shared/System/BitConverter.cs | 16 +-- .../shared/System/CharEnumerator.cs | 2 +- .../shared/System/Collections/ArrayList.cs | 8 +- .../Collections/Concurrent/ConcurrentQueue.cs | 21 ++-- .../Concurrent/ConcurrentQueueSegment.cs | 15 +-- .../Concurrent/IProducerConsumerCollection.cs | 3 +- .../System/Collections/Generic/ArraySortHelper.cs | 3 +- .../shared/System/Collections/Generic/Comparer.cs | 7 +- .../System/Collections/Generic/Dictionary.cs | 105 ++++++++-------- .../System/Collections/Generic/EqualityComparer.cs | 15 +-- .../shared/System/Collections/Generic/IComparer.cs | 3 +- .../System/Collections/Generic/IDictionary.cs | 3 +- .../Collections/Generic/IEqualityComparer.cs | 6 +- .../Collections/Generic/IReadOnlyDictionary.cs | 4 +- .../shared/System/Collections/Generic/List.cs | 41 +++--- .../Generic/NonRandomizedStringEqualityComparer.cs | 2 - .../HashHelpers.SerializationInfoTable.cs | 2 +- .../shared/System/Collections/IDictionary.cs | 24 ++-- .../System/Collections/ListDictionaryInternal.cs | 2 +- .../System/Collections/ObjectModel/Collection.cs | 22 ++-- .../Collections/ObjectModel/ReadOnlyCollection.cs | 10 +- .../shared/System/Convert.cs | 21 +++- .../shared/System/DateTimeOffset.cs | 4 +- .../shared/System/DefaultBinder.cs | 6 +- .../shared/System/Delegate.cs | 7 +- .../Diagnostics/CodeAnalysis/NullableAttributes.cs | 83 ++++++++++++ .../System/Diagnostics/Contracts/Contracts.cs | 9 +- .../shared/System/Diagnostics/Debug.cs | 12 +- .../shared/System/Diagnostics/DebugProvider.cs | 2 +- .../shared/System/Diagnostics/StackTrace.cs | 2 +- .../Diagnostics/Tracing/DiagnosticCounter.cs | 2 +- .../System/Diagnostics/Tracing/EventProvider.cs | 4 +- .../System/Diagnostics/Tracing/EventSource.cs | 46 +++---- .../Tracing/TraceLogging/ConcurrentSet.cs | 2 +- .../Tracing/TraceLogging/EventPayload.cs | 5 +- .../Tracing/TraceLogging/PropertyValue.cs | 40 +++--- .../Diagnostics/Tracing/TraceLogging/Statics.cs | 17 +-- .../Tracing/TraceLogging/TypeAnalysis.cs | 2 +- src/System.Private.CoreLib/shared/System/Enum.cs | 5 +- .../shared/System/Environment.Unix.cs | 4 +- .../shared/System/Environment.Win32.cs | 2 +- .../shared/System/Environment.cs | 6 +- .../System/Globalization/CalendarData.Unix.cs | 3 +- .../System/Globalization/CalendarData.Windows.cs | 8 +- .../shared/System/Globalization/CalendarData.cs | 4 - .../shared/System/Globalization/CompareInfo.cs | 4 +- .../System/Globalization/CultureData.Windows.cs | 6 +- .../shared/System/Globalization/CultureData.cs | 4 +- .../shared/System/Globalization/DateTimeParse.cs | 2 +- .../System/Globalization/IdnMapping.Windows.cs | 2 + .../System/Globalization/JapaneseCalendar.Win32.cs | 4 +- .../Globalization/JapaneseLunisolarCalendar.cs | 2 +- .../shared/System/Globalization/SortVersion.cs | 2 + .../System/Globalization/TextElementEnumerator.cs | 4 +- .../shared/System/Globalization/TimeSpanParse.cs | 2 +- .../shared/System/IComparable.cs | 4 +- .../shared/System/IEquatable.cs | 4 +- .../shared/System/IO/FileStream.Unix.cs | 8 +- .../shared/System/IO/FileStream.Windows.cs | 2 +- .../shared/System/IO/MemoryStream.cs | 4 +- .../shared/System/IO/Path.cs | 13 +- .../shared/System/IO/PathInternal.Windows.cs | 2 + .../shared/System/IO/Stream.cs | 16 ++- .../shared/System/IO/StreamReader.cs | 1 + .../shared/System/IO/StreamWriter.cs | 2 + .../shared/System/IO/TextReader.cs | 12 +- .../shared/System/IO/TextWriter.cs | 29 +++-- .../shared/System/IO/UnmanagedMemoryStream.cs | 4 +- src/System.Private.CoreLib/shared/System/Lazy.cs | 7 +- src/System.Private.CoreLib/shared/System/Math.cs | 3 + src/System.Private.CoreLib/shared/System/Memory.cs | 6 +- .../shared/System/MemoryExtensions.Fast.cs | 10 +- .../shared/System/Number.Parsing.cs | 3 + .../shared/System/Numerics/Vector.cs | 2 + .../shared/System/Numerics/Vector.tt | 1 + .../shared/System/Reflection/SignatureType.cs | 6 +- .../System/Resources/FastResourceComparer.cs | 8 +- .../shared/System/Resources/ResourceManager.cs | 4 +- .../shared/System/Resources/ResourceReader.Core.cs | 2 + .../shared/System/Resources/ResourceReader.cs | 24 ++-- .../shared/System/Resources/ResourceSet.cs | 6 +- .../shared/System/Resources/RuntimeResourceSet.cs | 4 +- .../Runtime/CompilerServices/AsyncMethodBuilder.cs | 35 +++--- .../CompilerServices/ConditionalWeakTable.cs | 13 +- .../CompilerServices/DateTimeConstantAttribute.cs | 4 +- .../System/Runtime/CompilerServices/ICastable.cs | 4 +- .../Runtime/CompilerServices/RuntimeHelpers.cs | 4 +- .../System/Runtime/CompilerServices/StrongBox.cs | 6 +- .../Runtime/CompilerServices/YieldAwaitable.cs | 4 +- .../ExceptionServices/ExceptionDispatchInfo.cs | 3 + .../Runtime/InteropServices/Marshal.NoCom.cs | 16 +-- .../System/Runtime/InteropServices/Marshal.Unix.cs | 2 - .../Runtime/InteropServices/Marshal.Windows.cs | 2 - .../System/Runtime/InteropServices/Marshal.cs | 17 ++- .../Runtime/InteropServices/MemoryMarshal.cs | 11 +- .../Runtime/InteropServices/NativeLibrary.cs | 2 +- .../System/Runtime/Loader/AssemblyLoadContext.cs | 8 +- .../Runtime/Serialization/SerializationInfo.cs | 56 ++++----- .../Serialization/SerializationInfoEnumerator.cs | 2 +- .../shared/System/Span.Fast.cs | 4 +- .../shared/System/SpanHelpers.T.cs | 14 +-- .../shared/System/String.Comparison.cs | 4 + .../shared/System/String.Searching.cs | 2 +- src/System.Private.CoreLib/shared/System/String.cs | 8 +- .../shared/System/StringComparer.cs | 20 +-- .../shared/System/Text/DecoderBestFitFallback.cs | 2 +- .../shared/System/Text/DecoderExceptionFallback.cs | 2 + .../shared/System/Text/DecoderFallback.cs | 6 +- .../shared/System/Text/DecoderNLS.cs | 1 - .../System/Text/DecoderReplacementFallback.cs | 1 - .../shared/System/Text/EncoderBestFitFallback.cs | 2 +- .../shared/System/Text/EncoderFallback.cs | 6 +- .../System/Text/EncoderReplacementFallback.cs | 1 - .../shared/System/Text/Encoding.cs | 5 + .../shared/System/Text/EncodingData.cs | 1 - .../shared/System/Text/EncodingTable.cs | 2 +- .../shared/System/Text/StringBuilder.cs | 10 +- .../shared/System/Text/StringRuneEnumerator.cs | 2 +- .../shared/System/Text/UTF32Encoding.cs | 2 +- .../shared/System/Text/UTF8Encoding.cs | 20 +-- .../shared/System/Text/Unicode/Utf8Utility.cs | 2 + .../shared/System/Text/UnicodeEncoding.cs | 4 +- .../shared/System/Text/ValueStringBuilder.cs | 2 - .../shared/System/Threading/AsyncLocal.cs | 14 ++- .../shared/System/Threading/CancellationToken.cs | 2 + .../System/Threading/CancellationTokenSource.cs | 6 +- .../System/Threading/EventWaitHandle.Windows.cs | 4 +- .../shared/System/Threading/EventWaitHandle.cs | 3 +- .../shared/System/Threading/ExecutionContext.cs | 14 ++- .../shared/System/Threading/LazyInitializer.cs | 27 ++-- .../shared/System/Threading/Mutex.Windows.cs | 2 +- .../shared/System/Threading/Mutex.cs | 7 +- .../System/Threading/ReaderWriterLockSlim.cs | 27 ++-- .../shared/System/Threading/Semaphore.cs | 3 +- .../Tasks/ConcurrentExclusiveSchedulerPair.cs | 10 +- .../shared/System/Threading/Tasks/Future.cs | 50 ++++---- .../shared/System/Threading/Tasks/FutureFactory.cs | 91 +++++++------- .../Threading/Tasks/ProducerConsumerQueues.cs | 15 +-- .../Threading/Tasks/Sources/IValueTaskSource.cs | 4 +- .../Sources/ManualResetValueTaskSourceCore.cs | 11 +- .../shared/System/Threading/Tasks/Task.cs | 96 +++++++------- .../System/Threading/Tasks/TaskCompletionSource.cs | 8 +- .../System/Threading/Tasks/TaskContinuation.cs | 2 +- .../shared/System/Threading/Tasks/TaskFactory.cs | 16 +-- .../shared/System/Threading/Tasks/TaskScheduler.cs | 2 +- .../shared/System/Threading/Tasks/ValueTask.cs | 7 +- .../shared/System/Threading/Thread.cs | 8 +- .../shared/System/Threading/ThreadLocal.cs | 16 ++- .../shared/System/Threading/Timer.cs | 2 +- .../shared/System/Threading/Volatile.cs | 4 +- .../shared/System/Threading/WaitHandle.cs | 6 +- .../shared/System/ThrowHelper.cs | 56 ++++++++- .../shared/System/TimeZone.cs | 2 +- .../shared/System/TimeZoneInfo.AdjustmentRule.cs | 4 +- .../shared/System/TimeZoneInfo.Unix.cs | 14 ++- .../shared/System/TimeZoneInfo.Win32.cs | 10 +- .../shared/System/TimeZoneInfo.cs | 13 +- src/System.Private.CoreLib/shared/System/Tuple.cs | 38 +++--- .../shared/System/Type.Helpers.cs | 14 +-- .../shared/System/ValueTuple.cs | 32 ++--- .../shared/System/Version.cs | 9 +- .../shared/System/WinRTFolderPaths.cs | 2 +- .../src/System/Array.CoreCLR.cs | 2 +- .../src/System/Attribute.CoreCLR.cs | 2 +- .../Generic/EqualityComparer.CoreCLR.cs | 4 +- .../Collections/ObjectModel/ReadOnlyDictionary.cs | 23 ++-- .../Diagnostics/Eventing/XplatEventLogger.cs | 2 +- .../src/System/Environment.CoreCLR.cs | 4 + .../src/System/IO/FileLoadException.CoreCLR.cs | 2 +- .../src/System/MulticastDelegate.cs | 6 +- .../src/System/Reflection/Assembly.CoreCLR.cs | 2 +- .../System/Reflection/Emit/DynamicILGenerator.cs | 2 +- .../src/System/Reflection/Emit/DynamicMethod.cs | 4 +- .../src/System/Reflection/Emit/ILGenerator.cs | 6 +- .../src/System/Reflection/Emit/ISymWrapperCore.cs | 4 +- .../src/System/Reflection/Emit/MethodBuilder.cs | 2 +- .../src/System/Reflection/Emit/SymbolType.cs | 2 +- .../src/System/Reflection/RuntimeAssembly.cs | 4 +- .../System/Reflection/RuntimeConstructorInfo.cs | 2 + .../src/System/Reflection/RuntimeMethodInfo.cs | 4 +- src/System.Private.CoreLib/src/System/RtType.cs | 13 +- .../Runtime/CompilerServices/ICastableHelpers.cs | 6 +- .../System/Runtime/CompilerServices/jithelpers.cs | 5 +- .../Runtime/InteropServices/ComEventsMethod.cs | 4 +- .../EnumeratorViewOfEnumVariant.cs | 2 +- .../Runtime/InteropServices/Marshal.CoreCLR.cs | 20 ++- .../WindowsRuntime/CLRIReferenceImpl.cs | 4 +- .../WindowsRuntime/ConstantSplittableMap.cs | 9 +- .../WindowsRuntime/EventRegistrationTokenTable.cs | 13 +- .../IMapViewToIReadOnlyDictionaryAdapter.cs | 7 +- .../WindowsRuntime/IteratorToEnumeratorAdapter.cs | 2 +- .../WindowsRuntime/MapToDictionaryAdapter.cs | 7 +- .../WindowsRuntime/WindowsRuntimeMarshal.cs | 6 +- .../Runtime/Loader/AssemblyDependencyResolver.cs | 4 +- .../src/System/StubHelpers.cs | 4 +- .../src/System/Threading/Interlocked.cs | 7 +- .../src/System/Threading/Monitor.cs | 2 + .../src/System/Threading/ThreadPool.CoreCLR.cs | 6 +- .../src/System/Utf8String.Construction.cs | 2 +- .../src/System/Utf8String.cs | 7 +- .../src/System/WeakReferenceOfT.cs | 5 +- 214 files changed, 1241 insertions(+), 956 deletions(-) create mode 100644 src/System.Private.CoreLib/shared/System/Diagnostics/CodeAnalysis/NullableAttributes.cs diff --git a/src/System.Private.CoreLib/System.Private.CoreLib.csproj b/src/System.Private.CoreLib/System.Private.CoreLib.csproj index 353fa82..1a6a581 100644 --- a/src/System.Private.CoreLib/System.Private.CoreLib.csproj +++ b/src/System.Private.CoreLib/System.Private.CoreLib.csproj @@ -54,8 +54,8 @@ prompt 4 true - - 649,1573,1591,0419,3021,CS8609 + + $(NoWarn);649,1573,1591,0419,3021,CS8609 enable diff --git a/src/System.Private.CoreLib/shared/Internal/Win32/RegistryKey.cs b/src/System.Private.CoreLib/shared/Internal/Win32/RegistryKey.cs index 6ea8cf9..912ddce 100644 --- a/src/System.Private.CoreLib/shared/Internal/Win32/RegistryKey.cs +++ b/src/System.Private.CoreLib/shared/Internal/Win32/RegistryKey.cs @@ -6,6 +6,7 @@ using System; using System.Buffers; using System.Collections.Generic; using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.IO; using System.Security; @@ -219,7 +220,8 @@ namespace Internal.Win32 return GetValue(name, null); } - public object? GetValue(string name, object? defaultValue) // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 + [return: NotNullIfNotNull("defaultValue")] + public object? GetValue(string name, object? defaultValue) { object? data = defaultValue; int type = 0; @@ -369,7 +371,7 @@ namespace Internal.Win32 // make sure the string is null terminated before processing the data if (blob.Length > 0 && blob[blob.Length - 1] != (char)0) { - Array.Resize(ref blob!, blob.Length + 1); // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 + Array.Resize(ref blob!, blob.Length + 1); // TODO-NULLABLE: Remove ! when nullable attributes are respected } string[] strings = Array.Empty(); @@ -414,13 +416,13 @@ namespace Internal.Win32 { if (strings.Length == stringsCount) { - Array.Resize(ref strings!, stringsCount > 0 ? stringsCount * 2 : 4); // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 + Array.Resize(ref strings!, stringsCount > 0 ? stringsCount * 2 : 4); // TODO-NULLABLE: Remove ! when nullable attributes are respected } - strings![stringsCount++] = toAdd; // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 + strings![stringsCount++] = toAdd; // TODO-NULLABLE: Remove ! when nullable attributes are respected } } - Array.Resize(ref strings!, stringsCount); // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 + Array.Resize(ref strings!, stringsCount); // TODO-NULLABLE: Remove ! when nullable attributes are respected data = strings; } break; diff --git a/src/System.Private.CoreLib/shared/Interop/Unix/Interop.Errors.cs b/src/System.Private.CoreLib/shared/Interop/Unix/Interop.Errors.cs index 3022329..2e597e7 100644 --- a/src/System.Private.CoreLib/shared/Interop/Unix/Interop.Errors.cs +++ b/src/System.Private.CoreLib/shared/Interop/Unix/Interop.Errors.cs @@ -145,9 +145,7 @@ internal static partial class Interop return Interop.Sys.StrError(RawErrno); } -#pragma warning disable CS8609 // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/23268 public override string ToString() -#pragma warning restore CS8609 { return $"RawErrno: {RawErrno} Error: {Error} GetErrorMessage: {GetErrorMessage()}"; // No localization required; text is member names used for debugging purposes } diff --git a/src/System.Private.CoreLib/shared/Interop/Unix/System.Native/Interop.MountPoints.cs b/src/System.Private.CoreLib/shared/Interop/Unix/System.Native/Interop.MountPoints.cs index 212d515..a2fe207 100644 --- a/src/System.Private.CoreLib/shared/Interop/Unix/System.Native/Interop.MountPoints.cs +++ b/src/System.Private.CoreLib/shared/Interop/Unix/System.Native/Interop.MountPoints.cs @@ -27,13 +27,13 @@ internal static partial class Interop { if (count == found.Length) { - Array.Resize(ref found!, count * 2); // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 + Array.Resize(ref found!, count * 2); // TODO-NULLABLE: Remove ! when nullable attributes are respected } found[count++] = Marshal.PtrToStringAnsi((IntPtr)name)!; }); } - Array.Resize(ref found!, count); // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 + Array.Resize(ref found!, count); // TODO-NULLABLE: Remove ! when nullable attributes are respected return found; } } diff --git a/src/System.Private.CoreLib/shared/Interop/Windows/Kernel32/Interop.CreateFile.cs b/src/System.Private.CoreLib/shared/Interop/Windows/Kernel32/Interop.CreateFile.cs index d925be1..de68a36 100644 --- a/src/System.Private.CoreLib/shared/Interop/Windows/Kernel32/Interop.CreateFile.cs +++ b/src/System.Private.CoreLib/shared/Interop/Windows/Kernel32/Interop.CreateFile.cs @@ -4,7 +4,6 @@ using Microsoft.Win32.SafeHandles; using System; -using System.Diagnostics; using System.IO; using System.Runtime.InteropServices; @@ -34,9 +33,8 @@ internal partial class Interop int dwFlagsAndAttributes, IntPtr hTemplateFile) { - string? lpFileNameWithPrefix = PathInternal.EnsureExtendedPrefixIfNeeded(lpFileName); - Debug.Assert(lpFileNameWithPrefix != null, "null not expected when non-null passed"); // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 - return CreateFilePrivate(lpFileNameWithPrefix, dwDesiredAccess, dwShareMode, ref securityAttrs, dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile); + lpFileName = PathInternal.EnsureExtendedPrefixIfNeeded(lpFileName)!; // TODO-NULLABLE: Remove ! when nullable attributes are respected + return CreateFilePrivate(lpFileName, dwDesiredAccess, dwShareMode, ref securityAttrs, dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile); } } } diff --git a/src/System.Private.CoreLib/shared/Interop/Windows/Kernel32/Interop.CreateFile2.cs b/src/System.Private.CoreLib/shared/Interop/Windows/Kernel32/Interop.CreateFile2.cs index 8866982..49e7485 100644 --- a/src/System.Private.CoreLib/shared/Interop/Windows/Kernel32/Interop.CreateFile2.cs +++ b/src/System.Private.CoreLib/shared/Interop/Windows/Kernel32/Interop.CreateFile2.cs @@ -26,9 +26,8 @@ internal partial class Interop FileMode dwCreationDisposition, ref Kernel32.CREATEFILE2_EXTENDED_PARAMETERS pCreateExParams) { - string? lpFileNameWithPrefix = PathInternal.EnsureExtendedPrefixIfNeeded(lpFileName); - Debug.Assert(lpFileNameWithPrefix != null, "null not expected when non-null passed"); // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 - return CreateFile2Private(lpFileNameWithPrefix, dwDesiredAccess, dwShareMode, dwCreationDisposition, ref pCreateExParams); + lpFileName = PathInternal.EnsureExtendedPrefixIfNeeded(lpFileName)!; // TODO-NULLABLE: Remove ! when nullable attributes are respected + return CreateFile2Private(lpFileName, dwDesiredAccess, dwShareMode, dwCreationDisposition, ref pCreateExParams); } } } diff --git a/src/System.Private.CoreLib/shared/Interop/Windows/Kernel32/Interop.FindFirstFileEx.cs b/src/System.Private.CoreLib/shared/Interop/Windows/Kernel32/Interop.FindFirstFileEx.cs index 80fb2e7..52dcd54 100644 --- a/src/System.Private.CoreLib/shared/Interop/Windows/Kernel32/Interop.FindFirstFileEx.cs +++ b/src/System.Private.CoreLib/shared/Interop/Windows/Kernel32/Interop.FindFirstFileEx.cs @@ -21,11 +21,10 @@ internal partial class Interop internal static SafeFindHandle FindFirstFile(string fileName, ref WIN32_FIND_DATA data) { - string? fileNameWithPrefix = PathInternal.EnsureExtendedPrefixIfNeeded(fileName); - Debug.Assert(fileNameWithPrefix != null, "null not expected when non-null passed"); // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 + fileName = PathInternal.EnsureExtendedPrefixIfNeeded(fileName)!; // TODO-NULLABLE: Remove ! when nullable attributes are respected // use FindExInfoBasic since we don't care about short name and it has better perf - return FindFirstFileExPrivate(fileNameWithPrefix, FINDEX_INFO_LEVELS.FindExInfoBasic, ref data, FINDEX_SEARCH_OPS.FindExSearchNameMatch, IntPtr.Zero, 0); + return FindFirstFileExPrivate(fileName, FINDEX_INFO_LEVELS.FindExInfoBasic, ref data, FINDEX_SEARCH_OPS.FindExSearchNameMatch, IntPtr.Zero, 0); } internal enum FINDEX_INFO_LEVELS : uint diff --git a/src/System.Private.CoreLib/shared/Interop/Windows/Kernel32/Interop.GetFileAttributesEx.cs b/src/System.Private.CoreLib/shared/Interop/Windows/Kernel32/Interop.GetFileAttributesEx.cs index b833e8b..e3f18fe 100644 --- a/src/System.Private.CoreLib/shared/Interop/Windows/Kernel32/Interop.GetFileAttributesEx.cs +++ b/src/System.Private.CoreLib/shared/Interop/Windows/Kernel32/Interop.GetFileAttributesEx.cs @@ -21,9 +21,8 @@ internal partial class Interop internal static bool GetFileAttributesEx(string name, GET_FILEEX_INFO_LEVELS fileInfoLevel, ref WIN32_FILE_ATTRIBUTE_DATA lpFileInformation) { - string? nameWithExtendedPrefix = PathInternal.EnsureExtendedPrefixIfNeeded(name); - Debug.Assert(nameWithExtendedPrefix != null, "null not expected when non-null is passed"); // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 - return GetFileAttributesExPrivate(nameWithExtendedPrefix, fileInfoLevel, ref lpFileInformation); + name = PathInternal.EnsureExtendedPrefixIfNeeded(name)!; // TODO-NULLABLE: Remove ! when nullable attributes are respected + return GetFileAttributesExPrivate(name, fileInfoLevel, ref lpFileInformation); } } } diff --git a/src/System.Private.CoreLib/shared/System.Private.CoreLib.Shared.projitems b/src/System.Private.CoreLib/shared/System.Private.CoreLib.Shared.projitems index 2edb4b3..0b8bdde 100644 --- a/src/System.Private.CoreLib/shared/System.Private.CoreLib.Shared.projitems +++ b/src/System.Private.CoreLib/shared/System.Private.CoreLib.Shared.projitems @@ -198,6 +198,7 @@ + diff --git a/src/System.Private.CoreLib/shared/System/AppContext.cs b/src/System.Private.CoreLib/shared/System/AppContext.cs index 15b7351..7f81a43 100644 --- a/src/System.Private.CoreLib/shared/System/AppContext.cs +++ b/src/System.Private.CoreLib/shared/System/AppContext.cs @@ -126,7 +126,7 @@ namespace System Interlocked.CompareExchange(ref s_switches, new Dictionary(), null); } - lock (s_switches!) // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 + lock (s_switches!) // TODO-NULLABLE: Remove ! when compiler specially-recognizes CompareExchange for nullability { s_switches[switchName] = isEnabled; } diff --git a/src/System.Private.CoreLib/shared/System/AppDomain.cs b/src/System.Private.CoreLib/shared/System/AppDomain.cs index 0884c61..2d8cd9c 100644 --- a/src/System.Private.CoreLib/shared/System/AppDomain.cs +++ b/src/System.Private.CoreLib/shared/System/AppDomain.cs @@ -409,7 +409,7 @@ namespace System (Func)mi.CreateDelegate(typeof(Func))); } - principal = s_getUnauthenticatedPrincipal!(); // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 + principal = s_getUnauthenticatedPrincipal!(); // TODO-NULLABLE: Remove ! when nullable attributes are respected break; case PrincipalPolicy.WindowsPrincipal: @@ -425,7 +425,7 @@ namespace System (Func)mi.CreateDelegate(typeof(Func))); } - principal = s_getWindowsPrincipal!(); // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 + principal = s_getWindowsPrincipal!(); // TODO-NULLABLE: Remove ! when nullable attributes are respected break; } } diff --git a/src/System.Private.CoreLib/shared/System/Array.cs b/src/System.Private.CoreLib/shared/System/Array.cs index 049385b..11479d8 100644 --- a/src/System.Private.CoreLib/shared/System/Array.cs +++ b/src/System.Private.CoreLib/shared/System/Array.cs @@ -6,6 +6,7 @@ using System.Collections; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using Internal.Runtime.CompilerServices; @@ -36,10 +37,10 @@ namespace System } // T[] implements IList. - return new ReadOnlyCollection(array!); // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 + return new ReadOnlyCollection(array!); // TODO-NULLABLE: Remove ! when [DoesNotReturn] respected } - public static void Resize(ref T[]? array, int newSize) // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 + public static void Resize([NotNull] ref T[]? array, int newSize) { if (newSize < 0) ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.newSize, ExceptionResource.ArgumentOutOfRange_NeedNonNegNum); @@ -65,7 +66,7 @@ namespace System { ThrowHelper.ThrowArgumentNullException(ExceptionArgument.lengths); } - if (lengths!.Length == 0) // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 + if (lengths!.Length == 0) // TODO-NULLABLE: Remove ! when [DoesNotReturn] respected ThrowHelper.ThrowArgumentException(ExceptionResource.Arg_NeedAtLeast1Rank); int[] intLengths = new int[lengths.Length]; @@ -149,7 +150,7 @@ namespace System { if (indices == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.indices); - if (Rank != indices!.Length) // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 + if (Rank != indices!.Length) // TODO-NULLABLE: Remove ! when [DoesNotReturn] respected ThrowHelper.ThrowArgumentException(ExceptionResource.Arg_RankIndices); int[] intIndices = new int[indices.Length]; @@ -209,7 +210,7 @@ namespace System { if (indices == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.indices); - if (Rank != indices!.Length) // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 + if (Rank != indices!.Length) // TODO-NULLABLE: Remove ! when [DoesNotReturn] respected ThrowHelper.ThrowArgumentException(ExceptionResource.Arg_RankIndices); int[] intIndices = new int[indices.Length]; @@ -324,7 +325,7 @@ namespace System int i = 0; int c = 0; - while (i < o!.Length && c == 0) // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 + while (i < o!.Length && c == 0) // TODO-NULLABLE: Remove ! when [DoesNotReturn] respected { object? left = GetValue(i); object? right = o.GetValue(i); @@ -383,7 +384,7 @@ namespace System for (int i = (this.Length >= 8 ? this.Length - 8 : 0); i < this.Length; i++) { - ret = CombineHashCodes(ret, comparer!.GetHashCode(GetValue(i)!)); // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 + ret = CombineHashCodes(ret, comparer!.GetHashCode(GetValue(i)!)); // TODO-NULLABLE: Remove ! when [DoesNotReturn] respected } return ret; @@ -406,7 +407,7 @@ namespace System { if (array == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array); - return BinarySearch(array!, array!.GetLowerBound(0), array.Length, value, null); // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 + return BinarySearch(array!, array!.GetLowerBound(0), array.Length, value, null); // TODO-NULLABLE: Remove ! when [DoesNotReturn] respected } // Searches a section of an array for a given element using a binary search @@ -445,7 +446,7 @@ namespace System { if (array == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array); - return BinarySearch(array!, array!.GetLowerBound(0), array.Length, value, comparer); // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 + return BinarySearch(array!, array!.GetLowerBound(0), array.Length, value, comparer); // TODO-NULLABLE: Remove ! when [DoesNotReturn] respected } // Searches a section of an array for a given element using a binary search @@ -467,7 +468,7 @@ namespace System { if (array == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array); - int lb = array!.GetLowerBound(0); // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 + int lb = array!.GetLowerBound(0); // TODO-NULLABLE: Remove ! when [DoesNotReturn] respected if (index < lb) ThrowHelper.ThrowIndexArgumentOutOfRange_NeedNonNegNumException(); if (length < 0) @@ -552,14 +553,14 @@ namespace System { if (array == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array); - return BinarySearch(array!, 0, array!.Length, value, null); // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 + return BinarySearch(array!, 0, array!.Length, value, null); // TODO-NULLABLE: Remove ! when [DoesNotReturn] respected } public static int BinarySearch(T[] array, T value, System.Collections.Generic.IComparer? comparer) { if (array == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array); - return BinarySearch(array!, 0, array!.Length, value, comparer); // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 + return BinarySearch(array!, 0, array!.Length, value, comparer); // TODO-NULLABLE: Remove ! when [DoesNotReturn] respected } public static int BinarySearch(T[] array, int index, int length, T value) @@ -576,7 +577,7 @@ namespace System if (length < 0) ThrowHelper.ThrowLengthArgumentOutOfRange_ArgumentOutOfRange_NeedNonNegNum(); - if (array!.Length - index < length) // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 + if (array!.Length - index < length) // TODO-NULLABLE: Remove ! when [DoesNotReturn] respected ThrowHelper.ThrowArgumentException(ExceptionResource.Argument_InvalidOffLen); return ArraySortHelper.Default.BinarySearch(array, index, length, value, comparer); @@ -594,10 +595,10 @@ namespace System ThrowHelper.ThrowArgumentNullException(ExceptionArgument.converter); } - TOutput[] newArray = new TOutput[array!.Length]; // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 + TOutput[] newArray = new TOutput[array!.Length]; // TODO-NULLABLE: Remove ! when [DoesNotReturn] respected for (int i = 0; i < array.Length; i++) { - newArray[i] = converter!(array[i]); // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 + newArray[i] = converter!(array[i]); // TODO-NULLABLE: Remove ! when [DoesNotReturn] respected } return newArray; } @@ -614,7 +615,7 @@ namespace System if (array != null && array.Rank != 1) ThrowHelper.ThrowArgumentException(ExceptionResource.Arg_RankMultiDimNotSupported); // Note: Array.Copy throws a RankException and we want a consistent ArgumentException for all the IList CopyTo methods. - Array.Copy(this, GetLowerBound(0), array!, index, Length); // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 + Array.Copy(this, GetLowerBound(0), array!, index, Length); // TODO-NULLABLE: Remove ! when [DoesNotReturn] respected } public void CopyTo(Array array, long index) @@ -648,7 +649,7 @@ namespace System ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array); } - for (int i = 0; i < array!.Length; i++) // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 + for (int i = 0; i < array!.Length; i++) // TODO-NULLABLE: Remove ! when [DoesNotReturn] respected { array[i] = value; } @@ -661,22 +662,23 @@ namespace System ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array); } - if (startIndex < 0 || startIndex > array!.Length) // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 + if (startIndex < 0 || startIndex > array!.Length) // TODO-NULLABLE: Remove ! when [DoesNotReturn] respected { ThrowHelper.ThrowStartIndexArgumentOutOfRange_ArgumentOutOfRange_Index(); } - if (count < 0 || startIndex > array!.Length - count) // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 + if (count < 0 || startIndex > array!.Length - count) // TODO-NULLABLE: Remove ! when [DoesNotReturn] respected { ThrowHelper.ThrowCountArgumentOutOfRange_ArgumentOutOfRange_Count(); } for (int i = startIndex; i < startIndex + count; i++) { - array![i] = value; // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 + array![i] = value; // TODO-NULLABLE: Remove ! when [DoesNotReturn] respected } } + [return: MaybeNull] public static T Find(T[] array, Predicate match) { if (array == null) @@ -689,14 +691,14 @@ namespace System ThrowHelper.ThrowArgumentNullException(ExceptionArgument.match); } - for (int i = 0; i < array!.Length; i++) // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 + for (int i = 0; i < array!.Length; i++) // TODO-NULLABLE: Remove ! when [DoesNotReturn] respected { - if (match!(array[i])) // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 + if (match!(array[i])) // TODO-NULLABLE: Remove ! when [DoesNotReturn] respected { return array[i]; } } - return default!; // TODO-NULLABLE-GENERIC + return default!; } public static T[] FindAll(T[] array, Predicate match) @@ -712,9 +714,9 @@ namespace System } List list = new List(); - for (int i = 0; i < array!.Length; i++) // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 + for (int i = 0; i < array!.Length; i++) // TODO-NULLABLE: Remove ! when [DoesNotReturn] respected { - if (match!(array[i])) // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 + if (match!(array[i])) // TODO-NULLABLE: Remove ! when [DoesNotReturn] respected { list.Add(array[i]); } @@ -729,7 +731,7 @@ namespace System ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array); } - return FindIndex(array!, 0, array!.Length, match); // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 + return FindIndex(array!, 0, array!.Length, match); // TODO-NULLABLE: Remove ! when [DoesNotReturn] respected } public static int FindIndex(T[] array, int startIndex, Predicate match) @@ -739,7 +741,7 @@ namespace System ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array); } - return FindIndex(array!, startIndex, array!.Length - startIndex, match); // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 + return FindIndex(array!, startIndex, array!.Length - startIndex, match); // TODO-NULLABLE: Remove ! when [DoesNotReturn] respected } public static int FindIndex(T[] array, int startIndex, int count, Predicate match) @@ -749,12 +751,12 @@ namespace System ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array); } - if (startIndex < 0 || startIndex > array!.Length) // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 + if (startIndex < 0 || startIndex > array!.Length) // TODO-NULLABLE: Remove ! when [DoesNotReturn] respected { ThrowHelper.ThrowStartIndexArgumentOutOfRange_ArgumentOutOfRange_Index(); } - if (count < 0 || startIndex > array!.Length - count) // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 + if (count < 0 || startIndex > array!.Length - count) // TODO-NULLABLE: Remove ! when [DoesNotReturn] respected { ThrowHelper.ThrowCountArgumentOutOfRange_ArgumentOutOfRange_Count(); } @@ -767,12 +769,13 @@ namespace System int endIndex = startIndex + count; for (int i = startIndex; i < endIndex; i++) { - if (match!(array![i])) // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 + if (match!(array![i])) // TODO-NULLABLE: Remove ! when [DoesNotReturn] respected return i; } return -1; } + [return: MaybeNull] public static T FindLast(T[] array, Predicate match) { if (array == null) @@ -785,14 +788,14 @@ namespace System ThrowHelper.ThrowArgumentNullException(ExceptionArgument.match); } - for (int i = array!.Length - 1; i >= 0; i--) // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 + for (int i = array!.Length - 1; i >= 0; i--) // TODO-NULLABLE: Remove ! when [DoesNotReturn] respected { - if (match!(array[i])) // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 + if (match!(array[i])) // TODO-NULLABLE: Remove ! when [DoesNotReturn] respected { return array[i]; } } - return default!; // TODO-NULLABLE-GENERIC + return default!; } public static int FindLastIndex(T[] array, Predicate match) @@ -802,7 +805,7 @@ namespace System ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array); } - return FindLastIndex(array!, array!.Length - 1, array.Length, match); // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 + return FindLastIndex(array!, array!.Length - 1, array.Length, match); // TODO-NULLABLE: Remove ! when [DoesNotReturn] respected } public static int FindLastIndex(T[] array, int startIndex, Predicate match) @@ -812,7 +815,7 @@ namespace System ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array); } - return FindLastIndex(array!, startIndex, startIndex + 1, match); // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 + return FindLastIndex(array!, startIndex, startIndex + 1, match); // TODO-NULLABLE: Remove ! when [DoesNotReturn] respected } public static int FindLastIndex(T[] array, int startIndex, int count, Predicate match) @@ -827,7 +830,7 @@ namespace System ThrowHelper.ThrowArgumentNullException(ExceptionArgument.match); } - if (array!.Length == 0) // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 + if (array!.Length == 0) // TODO-NULLABLE: Remove ! when [DoesNotReturn] respected { // Special case for 0 length List if (startIndex != -1) @@ -853,7 +856,7 @@ namespace System int endIndex = startIndex - count; for (int i = startIndex; i > endIndex; i--) { - if (match!(array[i])) // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 + if (match!(array[i])) // TODO-NULLABLE: Remove ! when [DoesNotReturn] respected { return i; } @@ -873,9 +876,9 @@ namespace System ThrowHelper.ThrowArgumentNullException(ExceptionArgument.action); } - for (int i = 0; i < array!.Length; i++) // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 + for (int i = 0; i < array!.Length; i++) // TODO-NULLABLE: Remove ! when [DoesNotReturn] respected { - action!(array[i]); // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 + action!(array[i]); // TODO-NULLABLE: Remove ! when [DoesNotReturn] respected } } @@ -887,7 +890,7 @@ namespace System { if (array == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array); - return IndexOf(array!, value, array!.GetLowerBound(0), array.Length); // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 + return IndexOf(array!, value, array!.GetLowerBound(0), array.Length); // TODO-NULLABLE: Remove ! when [DoesNotReturn] respected } // Returns the index of the first occurrence of a given value in a range of @@ -900,7 +903,7 @@ namespace System { if (array == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array); - int lb = array!.GetLowerBound(0); // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 + int lb = array!.GetLowerBound(0); // TODO-NULLABLE: Remove ! when [DoesNotReturn] respected return IndexOf(array, value, startIndex, array.Length - startIndex + lb); } @@ -914,7 +917,7 @@ namespace System { if (array == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array); - if (array!.Rank != 1) // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 + if (array!.Rank != 1) // TODO-NULLABLE: Remove ! when [DoesNotReturn] respected ThrowHelper.ThrowRankException(ExceptionResource.Rank_MultiDimNotSupported); int lb = array.GetLowerBound(0); @@ -984,7 +987,7 @@ namespace System ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array); } - return IndexOf(array!, value, 0, array!.Length); // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 + return IndexOf(array!, value, 0, array!.Length); // TODO-NULLABLE: Remove ! when [DoesNotReturn] respected } public static int IndexOf(T[] array, T value, int startIndex) @@ -994,7 +997,7 @@ namespace System ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array); } - return IndexOf(array!, value, startIndex, array!.Length - startIndex); // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 + return IndexOf(array!, value, startIndex, array!.Length - startIndex); // TODO-NULLABLE: Remove ! when [DoesNotReturn] respected } public static int IndexOf(T[] array, T value, int startIndex, int count) @@ -1004,7 +1007,7 @@ namespace System ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array); } - if ((uint)startIndex > (uint)array!.Length) // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 + if ((uint)startIndex > (uint)array!.Length) // TODO-NULLABLE: Remove ! when [DoesNotReturn] respected { ThrowHelper.ThrowStartIndexArgumentOutOfRange_ArgumentOutOfRange_Index(); } @@ -1068,7 +1071,7 @@ namespace System { if (array == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array); - int lb = array!.GetLowerBound(0); // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 + int lb = array!.GetLowerBound(0); // TODO-NULLABLE: Remove ! when [DoesNotReturn] respected return LastIndexOf(array, value, array.Length - 1 + lb, array.Length); } @@ -1081,7 +1084,7 @@ namespace System { if (array == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array); - int lb = array!.GetLowerBound(0); // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 + int lb = array!.GetLowerBound(0); // TODO-NULLABLE: Remove ! when [DoesNotReturn] respected return LastIndexOf(array, value, startIndex, startIndex + 1 - lb); } @@ -1095,7 +1098,7 @@ namespace System { if (array == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array); - int lb = array!.GetLowerBound(0); // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 + int lb = array!.GetLowerBound(0); // TODO-NULLABLE: Remove ! when [DoesNotReturn] respected if (array.Length == 0) { return lb - 1; @@ -1167,7 +1170,7 @@ namespace System ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array); } - return LastIndexOf(array!, value, array!.Length - 1, array.Length); // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 + return LastIndexOf(array!, value, array!.Length - 1, array.Length); // TODO-NULLABLE: Remove ! when [DoesNotReturn] respected } public static int LastIndexOf(T[] array, T value, int startIndex) @@ -1177,7 +1180,7 @@ namespace System ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array); } // if array is empty and startIndex is 0, we need to pass 0 as count - return LastIndexOf(array!, value, startIndex, (array!.Length == 0) ? 0 : (startIndex + 1)); // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 + return LastIndexOf(array!, value, startIndex, (array!.Length == 0) ? 0 : (startIndex + 1)); // TODO-NULLABLE: Remove ! when [DoesNotReturn] respected } public static int LastIndexOf(T[] array, T value, int startIndex, int count) @@ -1187,7 +1190,7 @@ namespace System ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array); } - if (array!.Length == 0) // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 + if (array!.Length == 0) // TODO-NULLABLE: Remove ! when [DoesNotReturn] respected { // // Special case for 0 length List @@ -1282,7 +1285,7 @@ namespace System { if (array == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array); - Reverse(array!, array!.GetLowerBound(0), array.Length); // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 + Reverse(array!, array!.GetLowerBound(0), array.Length); // TODO-NULLABLE: Remove ! when [DoesNotReturn] respected } // Reverses the elements in a range of an array. Following a call to this @@ -1295,7 +1298,7 @@ namespace System { if (array == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array); - int lowerBound = array!.GetLowerBound(0); // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 + int lowerBound = array!.GetLowerBound(0); // TODO-NULLABLE: Remove ! when [DoesNotReturn] respected if (index < lowerBound) ThrowHelper.ThrowIndexArgumentOutOfRange_NeedNonNegNumException(); if (length < 0) @@ -1338,7 +1341,7 @@ namespace System { if (array == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array); - Reverse(array!, 0, array!.Length); // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 + Reverse(array!, 0, array!.Length); // TODO-NULLABLE: Remove ! when [DoesNotReturn] respected } public static void Reverse(T[] array, int index, int length) @@ -1349,7 +1352,7 @@ namespace System ThrowHelper.ThrowIndexArgumentOutOfRange_NeedNonNegNumException(); if (length < 0) ThrowHelper.ThrowLengthArgumentOutOfRange_ArgumentOutOfRange_NeedNonNegNum(); - if (array!.Length - index < length) // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 + if (array!.Length - index < length) // TODO-NULLABLE: Remove ! when [DoesNotReturn] respected ThrowHelper.ThrowArgumentException(ExceptionResource.Argument_InvalidOffLen); if (length <= 1) @@ -1375,7 +1378,7 @@ namespace System { if (array == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array); - Sort(array!, null, array!.GetLowerBound(0), array.Length, null); // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 + Sort(array!, null, array!.GetLowerBound(0), array.Length, null); // TODO-NULLABLE: Remove ! when [DoesNotReturn] respected } // Sorts the elements of two arrays based on the keys in the first array. @@ -1388,7 +1391,7 @@ namespace System { if (keys == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.keys); - Sort(keys!, items, keys!.GetLowerBound(0), keys.Length, null); // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 + Sort(keys!, items, keys!.GetLowerBound(0), keys.Length, null); // TODO-NULLABLE: Remove ! when [DoesNotReturn] respected } // Sorts the elements in a section of an array. The sort compares the @@ -1436,7 +1439,7 @@ namespace System { if (keys == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.keys); - Sort(keys!, items, keys!.GetLowerBound(0), keys.Length, comparer); // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 + Sort(keys!, items, keys!.GetLowerBound(0), keys.Length, comparer); // TODO-NULLABLE: Remove ! when [DoesNotReturn] respected } // Sorts the elements in a section of an array. The sort compares the @@ -1462,7 +1465,7 @@ namespace System { if (keys == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.keys); - if (keys!.Rank != 1 || (items != null && items.Rank != 1)) // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 + if (keys!.Rank != 1 || (items != null && items.Rank != 1)) // TODO-NULLABLE: Remove ! when [DoesNotReturn] respected ThrowHelper.ThrowRankException(ExceptionResource.Rank_MultiDimNotSupported); int keysLowerBound = keys.GetLowerBound(0); if (items != null && keysLowerBound != items.GetLowerBound(0)) @@ -1485,14 +1488,14 @@ namespace System { if (array == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array); - Sort(array!, 0, array!.Length, null); // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 + Sort(array!, 0, array!.Length, null); // TODO-NULLABLE: Remove ! when [DoesNotReturn] respected } public static void Sort(TKey[] keys, TValue[]? items) { if (keys == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.keys); - Sort(keys!, items, 0, keys!.Length, null); // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 + Sort(keys!, items, 0, keys!.Length, null); // TODO-NULLABLE: Remove ! when [DoesNotReturn] respected } public static void Sort(T[] array, int index, int length) @@ -1509,14 +1512,14 @@ namespace System { if (array == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array); - Sort(array!, 0, array!.Length, comparer); // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 + Sort(array!, 0, array!.Length, comparer); // TODO-NULLABLE: Remove ! when [DoesNotReturn] respected } public static void Sort(TKey[] keys, TValue[]? items, System.Collections.Generic.IComparer? comparer) { if (keys == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.keys); - Sort(keys!, items, 0, keys!.Length, comparer); // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 + Sort(keys!, items, 0, keys!.Length, comparer); // TODO-NULLABLE: Remove ! when [DoesNotReturn] respected } public static void Sort(T[] array, int index, int length, System.Collections.Generic.IComparer? comparer) @@ -1527,7 +1530,7 @@ namespace System ThrowHelper.ThrowIndexArgumentOutOfRange_NeedNonNegNumException(); if (length < 0) ThrowHelper.ThrowLengthArgumentOutOfRange_ArgumentOutOfRange_NeedNonNegNum(); - if (array!.Length - index < length) // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 + if (array!.Length - index < length) // TODO-NULLABLE: Remove ! when [DoesNotReturn] respected ThrowHelper.ThrowArgumentException(ExceptionResource.Argument_InvalidOffLen); if (length > 1) @@ -1554,7 +1557,7 @@ namespace System ThrowHelper.ThrowIndexArgumentOutOfRange_NeedNonNegNumException(); if (length < 0) ThrowHelper.ThrowLengthArgumentOutOfRange_ArgumentOutOfRange_NeedNonNegNum(); - if (keys!.Length - index < length || (items != null && index > items.Length - length)) // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 + if (keys!.Length - index < length || (items != null && index > items.Length - length)) // TODO-NULLABLE: Remove ! when [DoesNotReturn] respected ThrowHelper.ThrowArgumentException(ExceptionResource.Argument_InvalidOffLen); if (length > 1) @@ -1591,7 +1594,7 @@ namespace System ThrowHelper.ThrowArgumentNullException(ExceptionArgument.comparison); } - ArraySortHelper.Sort(array!, 0, array!.Length, comparison!); // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 + ArraySortHelper.Sort(array!, 0, array!.Length, comparison!); // TODO-NULLABLE: Remove ! when [DoesNotReturn] respected } public static bool TrueForAll(T[] array, Predicate match) @@ -1606,9 +1609,9 @@ namespace System ThrowHelper.ThrowArgumentNullException(ExceptionArgument.match); } - for (int i = 0; i < array!.Length; i++) // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 + for (int i = 0; i < array!.Length; i++) // TODO-NULLABLE: Remove ! when [DoesNotReturn] respected { - if (!match!(array[i])) // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 + if (!match!(array[i])) // TODO-NULLABLE: Remove ! when [DoesNotReturn] respected { return false; } diff --git a/src/System.Private.CoreLib/shared/System/ArraySegment.cs b/src/System.Private.CoreLib/shared/System/ArraySegment.cs index 8098d22..0f6e05f 100644 --- a/src/System.Private.CoreLib/shared/System/ArraySegment.cs +++ b/src/System.Private.CoreLib/shared/System/ArraySegment.cs @@ -43,7 +43,7 @@ namespace System _array = array; _offset = 0; - _count = array!.Length; // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 + _count = array!.Length; // TODO-NULLABLE: Remove ! when [DoesNotReturn] respected } public ArraySegment(T[] array, int offset, int count) @@ -323,7 +323,7 @@ namespace System Debug.Assert(arraySegment.Array != null); Debug.Assert(arraySegment.Offset >= 0); Debug.Assert(arraySegment.Count >= 0); - Debug.Assert(arraySegment.Offset + arraySegment.Count <= arraySegment.Array!.Length); // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/34792 + Debug.Assert(arraySegment.Offset + arraySegment.Count <= arraySegment.Array!.Length); // TODO-NULLABLE: Manually-implemented property (https://github.com/dotnet/roslyn/issues/34792) _array = arraySegment.Array; _start = arraySegment.Offset; diff --git a/src/System.Private.CoreLib/shared/System/BitConverter.cs b/src/System.Private.CoreLib/shared/System/BitConverter.cs index 129c009..f6f6b98 100644 --- a/src/System.Private.CoreLib/shared/System/BitConverter.cs +++ b/src/System.Private.CoreLib/shared/System/BitConverter.cs @@ -236,7 +236,7 @@ namespace System { if (value == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.value); - if (unchecked((uint)startIndex) >= unchecked((uint)value!.Length)) // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 + if (unchecked((uint)startIndex) >= unchecked((uint)value!.Length)) // TODO-NULLABLE: Remove ! when [DoesNotReturn] respected ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.startIndex, ExceptionResource.ArgumentOutOfRange_Index); if (startIndex > value.Length - sizeof(short)) ThrowHelper.ThrowArgumentException(ExceptionResource.Arg_ArrayPlusOffTooSmall, ExceptionArgument.value); @@ -257,7 +257,7 @@ namespace System { if (value == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.value); - if (unchecked((uint)startIndex) >= unchecked((uint)value!.Length)) // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 + if (unchecked((uint)startIndex) >= unchecked((uint)value!.Length)) // TODO-NULLABLE: Remove ! when [DoesNotReturn] respected ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.startIndex, ExceptionResource.ArgumentOutOfRange_Index); if (startIndex > value.Length - sizeof(int)) ThrowHelper.ThrowArgumentException(ExceptionResource.Arg_ArrayPlusOffTooSmall, ExceptionArgument.value); @@ -278,7 +278,7 @@ namespace System { if (value == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.value); - if (unchecked((uint)startIndex) >= unchecked((uint)value!.Length)) // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 + if (unchecked((uint)startIndex) >= unchecked((uint)value!.Length)) // TODO-NULLABLE: Remove ! when [DoesNotReturn] respected ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.startIndex, ExceptionResource.ArgumentOutOfRange_Index); if (startIndex > value.Length - sizeof(long)) ThrowHelper.ThrowArgumentException(ExceptionResource.Arg_ArrayPlusOffTooSmall, ExceptionArgument.value); @@ -363,11 +363,11 @@ namespace System { if (value == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.value); - if (startIndex < 0 || startIndex >= value!.Length && startIndex > 0) // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 + if (startIndex < 0 || startIndex >= value!.Length && startIndex > 0) // TODO-NULLABLE: Remove ! when [DoesNotReturn] respected ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.startIndex, ExceptionResource.ArgumentOutOfRange_Index); if (length < 0) throw new ArgumentOutOfRangeException(nameof(length), SR.ArgumentOutOfRange_GenericPositive); - if (startIndex > value!.Length - length) // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 + if (startIndex > value!.Length - length) // TODO-NULLABLE: Remove ! when [DoesNotReturn] respected ThrowHelper.ThrowArgumentException(ExceptionResource.Arg_ArrayPlusOffTooSmall, ExceptionArgument.value); if (length == 0) @@ -409,7 +409,7 @@ namespace System { if (value == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.value); - return ToString(value!, 0, value!.Length); // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 + return ToString(value!, 0, value!.Length); // TODO-NULLABLE: Remove ! when [DoesNotReturn] respected } // Converts an array of bytes into a String. @@ -417,7 +417,7 @@ namespace System { if (value == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.value); - return ToString(value!, startIndex, value!.Length - startIndex); // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 + return ToString(value!, startIndex, value!.Length - startIndex); // TODO-NULLABLE: Remove ! when [DoesNotReturn] respected } /*==================================ToBoolean=================================== @@ -435,7 +435,7 @@ namespace System ThrowHelper.ThrowArgumentNullException(ExceptionArgument.value); if (startIndex < 0) ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.startIndex, ExceptionResource.ArgumentOutOfRange_Index); - if (startIndex > value!.Length - 1) // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 + if (startIndex > value!.Length - 1) // TODO-NULLABLE: Remove ! when [DoesNotReturn] respected ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.startIndex, ExceptionResource.ArgumentOutOfRange_Index); // differs from other overloads, which throw base ArgumentException return value[startIndex] != 0; diff --git a/src/System.Private.CoreLib/shared/System/CharEnumerator.cs b/src/System.Private.CoreLib/shared/System/CharEnumerator.cs index 3adf3b0..1e77538 100644 --- a/src/System.Private.CoreLib/shared/System/CharEnumerator.cs +++ b/src/System.Private.CoreLib/shared/System/CharEnumerator.cs @@ -54,7 +54,7 @@ namespace System _str = null; } - object? IEnumerator.Current // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/23268 + object? IEnumerator.Current { get { return Current; } } diff --git a/src/System.Private.CoreLib/shared/System/Collections/ArrayList.cs b/src/System.Private.CoreLib/shared/System/Collections/ArrayList.cs index c5f3abd..ba4a323 100644 --- a/src/System.Private.CoreLib/shared/System/Collections/ArrayList.cs +++ b/src/System.Private.CoreLib/shared/System/Collections/ArrayList.cs @@ -295,7 +295,7 @@ namespace System.Collections else { for (int i = 0; i < _size; i++) - if ((_items[i] != null) && (_items[i]!.Equals(item))) // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/34644 + if ((_items[i] != null) && (_items[i]!.Equals(item))) // TODO-NULLABLE: Indexer nullability tracked (https://github.com/dotnet/roslyn/issues/34644) return true; return false; } @@ -969,7 +969,7 @@ namespace System.Collections else { for (int i = startIndex; i < endIndex; i++) - if (_list[i] != null && _list[i]!.Equals(value)) // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/34644 + if (_list[i] != null && _list[i]!.Equals(value)) // TODO-NULLABLE: Indexer nullability tracked (https://github.com/dotnet/roslyn/issues/34644) return i; return -1; } @@ -1040,7 +1040,7 @@ namespace System.Collections else { for (int i = startIndex; i >= endIndex; i--) - if (_list[i] != null && _list[i]!.Equals(value)) // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/34644 + if (_list[i] != null && _list[i]!.Equals(value)) // TODO-NULLABLE: Indexer nullability tracked (https://github.com/dotnet/roslyn/issues/34644) return i; return -1; } @@ -2521,7 +2521,7 @@ namespace System.Collections else { for (int i = 0; i < _baseSize; i++) - if (_baseList[_baseIndex + i] != null && _baseList[_baseIndex + i]!.Equals(item)) // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/34644 + if (_baseList[_baseIndex + i] != null && _baseList[_baseIndex + i]!.Equals(item)) // TODO-NULLABLE: Indexer nullability tracked (https://github.com/dotnet/roslyn/issues/34644) return true; return false; } diff --git a/src/System.Private.CoreLib/shared/System/Collections/Concurrent/ConcurrentQueue.cs b/src/System.Private.CoreLib/shared/System/Collections/Concurrent/ConcurrentQueue.cs index f80f4d1..e62e372 100644 --- a/src/System.Private.CoreLib/shared/System/Collections/Concurrent/ConcurrentQueue.cs +++ b/src/System.Private.CoreLib/shared/System/Collections/Concurrent/ConcurrentQueue.cs @@ -4,6 +4,7 @@ using System.Collections.Generic; using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.Threading; namespace System.Collections.Concurrent @@ -99,7 +100,7 @@ namespace System.Collections.Concurrent // Initialize the segment and add all of the data to it. _tail = _head = new ConcurrentQueueSegment(length); - foreach (T item in collection!) // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 + foreach (T item in collection!) // TODO-NULLABLE: Remove ! when [DoesNotReturn] respected { Enqueue(item); } @@ -146,7 +147,7 @@ namespace System.Collections.Concurrent // Otherwise, fall back to the slower path that first copies the contents // to an array, and then uses that array's non-generic CopyTo to do the copy. - ToArray().CopyTo(array!, index); // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 + ToArray().CopyTo(array!, index); // TODO-NULLABLE: Remove ! when [DoesNotReturn] respected } /// @@ -163,7 +164,7 @@ namespace System.Collections.Concurrent /// cref="ICollection"/>. This property is not supported. /// /// The SyncRoot property is not supported. - object ICollection.SyncRoot { get { ThrowHelper.ThrowNotSupportedException(ExceptionResource.ConcurrentCollection_SyncRoot_NotSupported); return default!; } } // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 + object ICollection.SyncRoot { get { ThrowHelper.ThrowNotSupportedException(ExceptionResource.ConcurrentCollection_SyncRoot_NotSupported); return default!; } } // TODO-NULLABLE: Remove ! when [DoesNotReturn] respected /// Returns an enumerator that iterates through a collection. /// An that can be used to iterate through the collection. @@ -461,7 +462,7 @@ namespace System.Collections.Concurrent // Get the number of items to be enumerated long count = GetCount(head, headHead, tail, tailTail); - if (index > array!.Length - count) // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 + if (index > array!.Length - count) // TODO-NULLABLE: Remove ! when [DoesNotReturn] respected { ThrowHelper.ThrowArgumentException(ExceptionResource.Arg_ArrayPlusOffTooSmall); } @@ -678,12 +679,12 @@ namespace System.Collections.Concurrent /// true if an element was removed and returned from the beginning of the /// successfully; otherwise, false. /// - public bool TryDequeue(out T result) => // TODO-GENERIC-NULLABLE + public bool TryDequeue([MaybeNullWhen(false)] out T result) => _head.TryDequeue(out result) || // fast-path that operates just on the head segment TryDequeueSlow(out result); // slow path that needs to fix up segments /// Tries to dequeue an item, removing empty segments as needed. - private bool TryDequeueSlow(out T item) + private bool TryDequeueSlow([MaybeNullWhen(false)] out T item) { while (true) { @@ -701,7 +702,7 @@ namespace System.Collections.Concurrent // check and this check, another item could have arrived). if (head._nextSegment == null) { - item = default!; // TODO-NULLABLE-GENERIC + item = default!; return false; } @@ -742,13 +743,13 @@ namespace System.Collections.Concurrent /// For determining whether the collection contains any items, use of the /// property is recommended rather than peeking. /// - public bool TryPeek(out T result) => TryPeek(out result, resultUsed: true); // TODO-GENERIC-NULLABLE + public bool TryPeek([MaybeNullWhen(false)] out T result) => TryPeek(out result, resultUsed: true); /// Attempts to retrieve the value for the first element in the queue. /// The value of the first element, if found. /// true if the result is needed; otherwise false if only the true/false outcome is needed. /// true if an element was found; otherwise, false. - private bool TryPeek(out T result, bool resultUsed) + private bool TryPeek([MaybeNullWhen(false)] out T result, bool resultUsed) { // Starting with the head segment, look through all of the segments // for the first one we can find that's not empty. @@ -795,7 +796,7 @@ namespace System.Collections.Concurrent // and we'll traverse to that segment. } - result = default!; // TODO-NULLABLE-GENERIC + result = default!; return false; } diff --git a/src/System.Private.CoreLib/shared/System/Collections/Concurrent/ConcurrentQueueSegment.cs b/src/System.Private.CoreLib/shared/System/Collections/Concurrent/ConcurrentQueueSegment.cs index c120d77..fcf0539 100644 --- a/src/System.Private.CoreLib/shared/System/Collections/Concurrent/ConcurrentQueueSegment.cs +++ b/src/System.Private.CoreLib/shared/System/Collections/Concurrent/ConcurrentQueueSegment.cs @@ -4,6 +4,7 @@ #nullable enable using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.Runtime.InteropServices; using System.Threading; @@ -127,7 +128,7 @@ namespace System.Collections.Concurrent } /// Tries to dequeue an element from the queue. - public bool TryDequeue(out T item) // TODO-NULLABLE-GENERIC + public bool TryDequeue([MaybeNullWhen(false)] out T item) { Slot[] slots = _slots; @@ -165,7 +166,7 @@ namespace System.Collections.Concurrent // If we're preserving, though, we don't zero out the slot, as we need it for // enumerations, peeking, ToArray, etc. And we don't update the sequence number, // so that an enqueuer will see it as full and be forced to move to a new segment. - slots[slotsIndex].Item = default!; // TODO-NULLABLE-GENERIC + slots[slotsIndex].Item = default!; // TODO-NULLABLE: Remove ! when nullable attributes are respected Volatile.Write(ref slots[slotsIndex].SequenceNumber, currentHead + slots.Length); } return true; @@ -184,7 +185,7 @@ namespace System.Collections.Concurrent int currentTail = Volatile.Read(ref _headAndTail.Tail); if (currentTail - currentHead <= 0 || (frozen && (currentTail - FreezeOffset - currentHead <= 0))) { - item = default!; // TODO-NULLABLE-GENERIC + item = default!; return false; } @@ -199,7 +200,7 @@ namespace System.Collections.Concurrent } /// Tries to peek at an element from the queue, without removing it. - public bool TryPeek(out T result, bool resultUsed) // TODO-NULLABLE-GENERIC + public bool TryPeek([MaybeNullWhen(false)] out T result, bool resultUsed) { if (resultUsed) { @@ -229,7 +230,7 @@ namespace System.Collections.Concurrent int diff = sequenceNumber - (currentHead + 1); if (diff == 0) { - result = resultUsed ? slots[slotsIndex].Item : default!; // TODO-NULLABLE-GENERIC + result = resultUsed ? slots[slotsIndex].Item : default!; return true; } else if (diff < 0) @@ -245,7 +246,7 @@ namespace System.Collections.Concurrent int currentTail = Volatile.Read(ref _headAndTail.Tail); if (currentTail - currentHead <= 0 || (frozen && (currentTail - FreezeOffset - currentHead <= 0))) { - result = default!; // TODO-NULLABLE-GENERIC + result = default!; return false; } @@ -322,7 +323,7 @@ namespace System.Collections.Concurrent internal struct Slot { /// The item. - public T Item; // SOS's ThreadPool command depends on this being at the beginning of the struct when T is a reference type + [AllowNull, MaybeNull] public T Item; // SOS's ThreadPool command depends on this being at the beginning of the struct when T is a reference type /// The sequence number for this slot, used to synchronize between enqueuers and dequeuers. public int SequenceNumber; } diff --git a/src/System.Private.CoreLib/shared/System/Collections/Concurrent/IProducerConsumerCollection.cs b/src/System.Private.CoreLib/shared/System/Collections/Concurrent/IProducerConsumerCollection.cs index 3f77483..e33c840 100644 --- a/src/System.Private.CoreLib/shared/System/Collections/Concurrent/IProducerConsumerCollection.cs +++ b/src/System.Private.CoreLib/shared/System/Collections/Concurrent/IProducerConsumerCollection.cs @@ -3,6 +3,7 @@ // See the LICENSE file in the project root for more information. using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; namespace System.Collections.Concurrent { @@ -58,7 +59,7 @@ namespace System.Collections.Concurrent /// unspecified. /// /// true if an object was removed and returned successfully; otherwise, false. - bool TryTake(out T item); // TODO-NULLABLE-GENERIC + bool TryTake([MaybeNullWhen(false)] out T item); /// /// Copies the elements contained in the to a new array. diff --git a/src/System.Private.CoreLib/shared/System/Collections/Generic/ArraySortHelper.cs b/src/System.Private.CoreLib/shared/System/Collections/Generic/ArraySortHelper.cs index 084ecdf..2ec14db 100644 --- a/src/System.Private.CoreLib/shared/System/Collections/Generic/ArraySortHelper.cs +++ b/src/System.Private.CoreLib/shared/System/Collections/Generic/ArraySortHelper.cs @@ -14,7 +14,7 @@ ===========================================================*/ using System.Diagnostics; -using System.Runtime.CompilerServices; +using System.Diagnostics.CodeAnalysis; namespace System.Collections.Generic { @@ -38,6 +38,7 @@ namespace System.Collections.Generic return result; } + [DoesNotReturn] internal static void ThrowOrIgnoreBadComparer(object? comparer) { throw new ArgumentException(SR.Format(SR.Arg_BogusIComparer, comparer)); diff --git a/src/System.Private.CoreLib/shared/System/Collections/Generic/Comparer.cs b/src/System.Private.CoreLib/shared/System/Collections/Generic/Comparer.cs index 28cb0af..80187be 100644 --- a/src/System.Private.CoreLib/shared/System/Collections/Generic/Comparer.cs +++ b/src/System.Private.CoreLib/shared/System/Collections/Generic/Comparer.cs @@ -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. +using System.Diagnostics.CodeAnalysis; using System.Runtime.CompilerServices; using System.Runtime.Serialization; @@ -21,7 +22,7 @@ namespace System.Collections.Generic return new ComparisonComparer(comparison); } - public abstract int Compare(T x, T y); // TODO-NULLABLE-GENERIC: x and y must be marked as nullable + public abstract int Compare([AllowNull] T x, [AllowNull] T y); int IComparer.Compare(object? x, object? y) { @@ -58,7 +59,7 @@ namespace System.Collections.Generic // Needs to be public to support binary serialization compatibility public sealed partial class GenericComparer : Comparer where T : IComparable { - public override int Compare(T x, T y) // TODO-NULLABLE-GENERIC: x and y must be marked as nullable + public override int Compare([AllowNull] T x, [AllowNull] T y) { if (x != null) { @@ -106,7 +107,7 @@ namespace System.Collections.Generic // Needs to be public to support binary serialization compatibility public sealed partial class ObjectComparer : Comparer { - public override int Compare(T x, T y) // TODO-NULLABLE-GENERIC: x and y must be marked as nullable + public override int Compare([AllowNull] T x, [AllowNull] T y) { return System.Collections.Comparer.Default.Compare(x, y); } diff --git a/src/System.Private.CoreLib/shared/System/Collections/Generic/Dictionary.cs b/src/System.Private.CoreLib/shared/System/Collections/Generic/Dictionary.cs index 296a607..d79924c 100644 --- a/src/System.Private.CoreLib/shared/System/Collections/Generic/Dictionary.cs +++ b/src/System.Private.CoreLib/shared/System/Collections/Generic/Dictionary.cs @@ -3,6 +3,7 @@ // See the LICENSE file in the project root for more information. using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.Runtime.CompilerServices; using System.Runtime.Serialization; @@ -99,7 +100,7 @@ namespace System.Collections.Generic // avoid the enumerator allocation and overhead by looping through the entries array directly. // We only do this when dictionary is Dictionary and not a subclass, to maintain // back-compat with subclasses that may have overridden the enumerator behavior. - if (dictionary!.GetType() == typeof(Dictionary)) // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 + if (dictionary!.GetType() == typeof(Dictionary)) // TODO-NULLABLE: Remove ! when [DoesNotReturn] respected { Dictionary d = (Dictionary)dictionary; int count = d._count; @@ -130,7 +131,7 @@ namespace System.Collections.Generic ThrowHelper.ThrowArgumentNullException(ExceptionArgument.collection); } - foreach (KeyValuePair pair in collection!) // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 + foreach (KeyValuePair pair in collection!) // TODO-NULLABLE: Remove ! when [DoesNotReturn] respected { Add(pair.Key, pair.Value); } @@ -218,7 +219,7 @@ namespace System.Collections.Generic int i = FindEntry(key); if (i >= 0) return _entries![i].value; ThrowHelper.ThrowKeyNotFoundException(key); - return default!; // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 (annotating ThrowHelper removes this return statement). + return default!; // TODO-NULLABLE: Remove ! when [DoesNotReturn] respected } set { @@ -289,7 +290,7 @@ namespace System.Collections.Generic } else { - if (default(TValue)! != null) // TODO-NULLABLE-GENERIC: https://github.com/dotnet/roslyn/issues/34757 + if (default(TValue)! != null) // TODO-NULLABLE: default(T) == null warning (https://github.com/dotnet/roslyn/issues/34757) { // ValueType: Devirtualize with EqualityComparer.Default intrinsic for (int i = 0; i < _count; i++) @@ -319,7 +320,7 @@ namespace System.Collections.Generic ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array); } - if ((uint)index > (uint)array!.Length) // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 + if ((uint)index > (uint)array!.Length) // TODO-NULLABLE: Remove ! when [DoesNotReturn] respected { ThrowHelper.ThrowIndexArgumentOutOfRange_NeedNonNegNumException(); } @@ -353,7 +354,7 @@ namespace System.Collections.Generic ThrowHelper.ThrowArgumentNullException(ExceptionArgument.info); } - info!.AddValue(VersionName, _version); // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 + info!.AddValue(VersionName, _version); // TODO-NULLABLE: Remove ! when [DoesNotReturn] respected info.AddValue(ComparerName, _comparer ?? EqualityComparer.Default, typeof(IEqualityComparer)); info.AddValue(HashSizeName, _buckets == null ? 0 : _buckets.Length); // This is the length of the bucket array @@ -382,10 +383,10 @@ namespace System.Collections.Generic IEqualityComparer? comparer = _comparer; if (comparer == null) { - uint hashCode = (uint)key!.GetHashCode(); // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 + uint hashCode = (uint)key!.GetHashCode(); // TODO-NULLABLE: Remove ! when [DoesNotReturn] respected // Value in _buckets is 1-based i = buckets[hashCode % (uint)buckets.Length] - 1; - if (default(TKey)! != null) // TODO-NULLABLE-GENERIC: https://github.com/dotnet/roslyn/issues/34757 + if (default(TKey)! != null) // TODO-NULLABLE: default(T) == null warning (https://github.com/dotnet/roslyn/issues/34757) { // ValueType: Devirtualize with EqualityComparer.Default intrinsic do @@ -485,21 +486,22 @@ namespace System.Collections.Generic { Initialize(0); } + Debug.Assert(_buckets != null); Entry[]? entries = _entries; Debug.Assert(entries != null, "expected entries to be non-null"); IEqualityComparer? comparer = _comparer; - uint hashCode = (uint)((comparer == null) ? key!.GetHashCode() : comparer.GetHashCode(key)); // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 + uint hashCode = (uint)((comparer == null) ? key!.GetHashCode() : comparer.GetHashCode(key)); // TODO-NULLABLE: Remove ! when [DoesNotReturn] respected int collisionCount = 0; - ref int bucket = ref _buckets![hashCode % (uint)_buckets.Length]; // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 (Initialize inits sets _buckets to non null) + ref int bucket = ref _buckets[hashCode % (uint)_buckets.Length]; // Value in _buckets is 1-based int i = bucket - 1; if (comparer == null) { - if (default(TKey)! != null) // TODO-NULLABLE-GENERIC: https://github.com/dotnet/roslyn/issues/34757 + if (default(TKey)! != null) // TODO-NULLABLE: default(T) == null warning (https://github.com/dotnet/roslyn/issues/34757) { // ValueType: Devirtualize with EqualityComparer.Default intrinsic do @@ -660,7 +662,7 @@ namespace System.Collections.Generic _version++; // Value types never rehash - if (default(TKey)! == null && collisionCount > HashHelpers.HashCollisionThreshold && comparer is NonRandomizedStringEqualityComparer) // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/34757 + if (default(TKey)! == null && collisionCount > HashHelpers.HashCollisionThreshold && comparer is NonRandomizedStringEqualityComparer) // TODO-NULLABLE: default(T) == null warning (https://github.com/dotnet/roslyn/issues/34757) { // If we hit the collision threshold we'll need to switch to the comparer which is using randomized string hashing // i.e. EqualityComparer.Default. @@ -698,7 +700,7 @@ namespace System.Collections.Generic ThrowHelper.ThrowSerializationException(ExceptionResource.Serialization_MissingKeys); } - for (int i = 0; i < array!.Length; i++) // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 + for (int i = 0; i < array!.Length; i++) // TODO-NULLABLE: Remove ! when [DoesNotReturn] respected { if (array[i].Key == null) { @@ -722,7 +724,7 @@ namespace System.Collections.Generic private void Resize(int newSize, bool forceNewHashCodes) { // Value types never rehash - Debug.Assert(!forceNewHashCodes || default(TKey)! == null); // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/34757 + Debug.Assert(!forceNewHashCodes || default(TKey)! == null); // TODO-NULLABLE: default(T) == null warning (https://github.com/dotnet/roslyn/issues/34757) Debug.Assert(_entries != null, "_entries should be non-null"); Debug.Assert(newSize >= _entries.Length); @@ -732,7 +734,7 @@ namespace System.Collections.Generic int count = _count; Array.Copy(_entries, 0, entries, 0, count); - if (default(TKey)! == null && forceNewHashCodes) // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/34757 + if (default(TKey)! == null && forceNewHashCodes) // TODO-NULLABLE: default(T) == null warning (https://github.com/dotnet/roslyn/issues/34757) { for (int i = 0; i < count; i++) { @@ -776,7 +778,7 @@ namespace System.Collections.Generic if (buckets != null) { Debug.Assert(entries != null, "entries should be non-null"); - uint hashCode = (uint)(_comparer?.GetHashCode(key) ?? key!.GetHashCode()); // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 + uint hashCode = (uint)(_comparer?.GetHashCode(key) ?? key!.GetHashCode()); // TODO-NULLABLE: Remove ! when [DoesNotReturn] respected uint bucket = hashCode % (uint)buckets.Length; int last = -1; // Value in buckets is 1-based @@ -803,11 +805,11 @@ namespace System.Collections.Generic if (RuntimeHelpers.IsReferenceOrContainsReferences()) { - entry.key = default!; // TODO-NULLABLE-GENERIC + entry.key = default!; } if (RuntimeHelpers.IsReferenceOrContainsReferences()) { - entry.value = default!; // TODO-NULLABLE-GENERIC + entry.value = default!; } _freeList = i; _freeCount++; @@ -831,7 +833,7 @@ namespace System.Collections.Generic // This overload is a copy of the overload Remove(TKey key) with one additional // statement to copy the value for entry being removed into the output parameter. // Code has been intentionally duplicated for performance reasons. - public bool Remove(TKey key, out TValue value) // TODO-NULLABLE-GENERIC: https://github.com/dotnet/roslyn/issues/26761 + public bool Remove(TKey key, [MaybeNullWhen(false)] out TValue value) { if (key == null) { @@ -844,7 +846,7 @@ namespace System.Collections.Generic if (buckets != null) { Debug.Assert(entries != null, "entries should be non-null"); - uint hashCode = (uint)(_comparer?.GetHashCode(key) ?? key!.GetHashCode()); // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 + uint hashCode = (uint)(_comparer?.GetHashCode(key) ?? key!.GetHashCode()); // TODO-NULLABLE: Remove ! when [DoesNotReturn] respected uint bucket = hashCode % (uint)buckets.Length; int last = -1; // Value in buckets is 1-based @@ -873,11 +875,11 @@ namespace System.Collections.Generic if (RuntimeHelpers.IsReferenceOrContainsReferences()) { - entry.key = default!; // TODO-NULLABLE-GENERIC + entry.key = default!; } if (RuntimeHelpers.IsReferenceOrContainsReferences()) { - entry.value = default!; // TODO-NULLABLE-GENERIC + entry.value = default!; } _freeList = i; _freeCount++; @@ -895,11 +897,11 @@ namespace System.Collections.Generic collisionCount++; } } - value = default!; // TODO-NULLABLE-GENERIC + value = default!; return false; } - public bool TryGetValue(TKey key, out TValue value) // TODO-NULLABLE-GENERIC: https://github.com/dotnet/roslyn/issues/26761 + public bool TryGetValue(TKey key, [MaybeNullWhen(false)] out TValue value) { int i = FindEntry(key); if (i >= 0) @@ -907,7 +909,7 @@ namespace System.Collections.Generic value = _entries![i].value; return true; } - value = default!; // TODO-NULLABLE-GENERIC + value = default!; return false; } @@ -923,7 +925,7 @@ namespace System.Collections.Generic { if (array == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array); - if (array!.Rank != 1) // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 + if (array!.Rank != 1) // TODO-NULLABLE: Remove ! when [DoesNotReturn] respected ThrowHelper.ThrowArgumentException(ExceptionResource.Arg_RankMultiDimNotSupported); if (array.GetLowerBound(0) != 0) ThrowHelper.ThrowArgumentException(ExceptionResource.Arg_NonZeroLowerBound); @@ -963,7 +965,7 @@ namespace System.Collections.Generic { if (entries![i].next >= -1) { - objects![index++] = new KeyValuePair(entries[i].key, entries[i].value); // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 + objects![index++] = new KeyValuePair(entries[i].key, entries[i].value); // TODO-NULLABLE: Remove ! when [DoesNotReturn] respected } } } @@ -1063,7 +1065,8 @@ namespace System.Collections.Generic ICollection IDictionary.Values => (ICollection)Values; - object? IDictionary.this[object key] // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/2384 + [DisallowNull] + object? IDictionary.this[object key] { get { @@ -1087,7 +1090,7 @@ namespace System.Collections.Generic try { - TKey tempKey = (TKey)key!; // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 + TKey tempKey = (TKey)key!; // TODO-NULLABLE: Remove ! when [DoesNotReturn] respected try { this[tempKey] = (TValue)value!; @@ -1123,7 +1126,7 @@ namespace System.Collections.Generic try { - TKey tempKey = (TKey)key!; // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 + TKey tempKey = (TKey)key!; // TODO-NULLABLE: Remove ! when [DoesNotReturn] respected try { @@ -1213,7 +1216,7 @@ namespace System.Collections.Generic { } - object? IEnumerator.Current // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/23268 + object? IEnumerator.Current { get { @@ -1296,7 +1299,7 @@ namespace System.Collections.Generic { ThrowHelper.ThrowArgumentNullException(ExceptionArgument.dictionary); } - _dictionary = dictionary!; // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 + _dictionary = dictionary!; // TODO-NULLABLE: Remove ! when [DoesNotReturn] respected } public Enumerator GetEnumerator() @@ -1309,12 +1312,12 @@ namespace System.Collections.Generic ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array); } - if (index < 0 || index > array!.Length) // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 + if (index < 0 || index > array!.Length) // TODO-NULLABLE: Remove ! when [DoesNotReturn] respected { ThrowHelper.ThrowIndexArgumentOutOfRange_NeedNonNegNumException(); } - if (array!.Length - index < _dictionary.Count) // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 + if (array!.Length - index < _dictionary.Count) // TODO-NULLABLE: Remove ! when [DoesNotReturn] respected { ThrowHelper.ThrowArgumentException(ExceptionResource.Arg_ArrayPlusOffTooSmall); } @@ -1356,7 +1359,7 @@ namespace System.Collections.Generic { if (array == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array); - if (array!.Rank != 1) // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 + if (array!.Rank != 1) // TODO-NULLABLE: Remove ! when [DoesNotReturn] respected ThrowHelper.ThrowArgumentException(ExceptionResource.Arg_RankMultiDimNotSupported); if (array.GetLowerBound(0) != 0) ThrowHelper.ThrowArgumentException(ExceptionResource.Arg_NonZeroLowerBound); @@ -1383,7 +1386,7 @@ namespace System.Collections.Generic { for (int i = 0; i < count; i++) { - if (entries![i].next >= -1) objects![index++] = entries[i].key; // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 (objects) + if (entries![i].next >= -1) objects![index++] = entries[i].key; // TODO-NULLABLE: Remove ! when [DoesNotReturn] respected } } catch (ArrayTypeMismatchException) @@ -1402,14 +1405,14 @@ namespace System.Collections.Generic private readonly Dictionary _dictionary; private int _index; private readonly int _version; - private TKey _currentKey; + [AllowNull, MaybeNull] private TKey _currentKey; internal Enumerator(Dictionary dictionary) { _dictionary = dictionary; _version = dictionary._version; _index = 0; - _currentKey = default!; // TODO-NULLABLE-GENERIC + _currentKey = default!; // TODO-NULLABLE: Remove ! when nullable attributes are respected } public void Dispose() @@ -1435,13 +1438,13 @@ namespace System.Collections.Generic } _index = _dictionary._count + 1; - _currentKey = default!; // TODO-NULLABLE-GENERIC + _currentKey = default!; // TODO-NULLABLE: Remove ! when nullable attributes are respected return false; } - public TKey Current => _currentKey; + public TKey Current => _currentKey!; - object? IEnumerator.Current // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/23268 + object? IEnumerator.Current { get { @@ -1462,7 +1465,7 @@ namespace System.Collections.Generic } _index = 0; - _currentKey = default!; // TODO-NULLABLE-GENERIC + _currentKey = default!; // TODO-NULLABLE: Remove ! when nullable attributes are respected } } } @@ -1479,7 +1482,7 @@ namespace System.Collections.Generic { ThrowHelper.ThrowArgumentNullException(ExceptionArgument.dictionary); } - _dictionary = dictionary!; // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 + _dictionary = dictionary!; // TODO-NULLABLE: Remove ! when [DoesNotReturn] respected } public Enumerator GetEnumerator() @@ -1492,7 +1495,7 @@ namespace System.Collections.Generic ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array); } - if ((uint)index > array!.Length) // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 + if ((uint)index > array!.Length) // TODO-NULLABLE: Remove ! when [DoesNotReturn] respected { ThrowHelper.ThrowIndexArgumentOutOfRange_NeedNonNegNumException(); } @@ -1539,7 +1542,7 @@ namespace System.Collections.Generic { if (array == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array); - if (array!.Rank != 1) // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 + if (array!.Rank != 1) // TODO-NULLABLE: Remove ! when [DoesNotReturn] respected ThrowHelper.ThrowArgumentException(ExceptionResource.Arg_RankMultiDimNotSupported); if (array.GetLowerBound(0) != 0) ThrowHelper.ThrowArgumentException(ExceptionResource.Arg_NonZeroLowerBound); @@ -1566,7 +1569,7 @@ namespace System.Collections.Generic { for (int i = 0; i < count; i++) { - if (entries![i].next >= -1) objects![index++] = entries[i].value!; // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 + if (entries![i].next >= -1) objects![index++] = entries[i].value!; // TODO-NULLABLE: Remove ! when [DoesNotReturn] respected } } catch (ArrayTypeMismatchException) @@ -1585,14 +1588,14 @@ namespace System.Collections.Generic private readonly Dictionary _dictionary; private int _index; private readonly int _version; - private TValue _currentValue; + [AllowNull, MaybeNull] private TValue _currentValue; internal Enumerator(Dictionary dictionary) { _dictionary = dictionary; _version = dictionary._version; _index = 0; - _currentValue = default!; // TODO-NULLABLE-GENERIC + _currentValue = default!; // TODO-NULLABLE: Remove ! when nullable attributes are respected } public void Dispose() @@ -1617,11 +1620,11 @@ namespace System.Collections.Generic } } _index = _dictionary._count + 1; - _currentValue = default!; // TODO-NULLABLE-GENERIC + _currentValue = default!; // TODO-NULLABLE: Remove ! when nullable attributes are respected return false; } - public TValue Current => _currentValue; + public TValue Current => _currentValue!; object? IEnumerator.Current { @@ -1643,7 +1646,7 @@ namespace System.Collections.Generic ThrowHelper.ThrowInvalidOperationException_InvalidOperation_EnumFailedVersion(); } _index = 0; - _currentValue = default!; // TODO-NULLABLE-GENERIC + _currentValue = default!; // TODO-NULLABLE: Remove ! when nullable attributes are respected } } } diff --git a/src/System.Private.CoreLib/shared/System/Collections/Generic/EqualityComparer.cs b/src/System.Private.CoreLib/shared/System/Collections/Generic/EqualityComparer.cs index b6040ad..86a4e2a 100644 --- a/src/System.Private.CoreLib/shared/System/Collections/Generic/EqualityComparer.cs +++ b/src/System.Private.CoreLib/shared/System/Collections/Generic/EqualityComparer.cs @@ -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. +using System.Diagnostics.CodeAnalysis; using System.Runtime.CompilerServices; using System.Runtime.Serialization; @@ -13,10 +14,10 @@ namespace System.Collections.Generic { // public static EqualityComparer Default is runtime-specific - public abstract bool Equals(T x, T y); - public abstract int GetHashCode(T obj); // TODO-NULLABLE-GENERIC: Shouldn't accept nulls. + public abstract bool Equals([AllowNull] T x, [AllowNull] T y); + public abstract int GetHashCode([DisallowNull] T obj); -#pragma warning disable CS8617 // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/30958 +#pragma warning disable CS8617 // TODO-NULLABLE: Covariant parameter types (https://github.com/dotnet/roslyn/issues/30958) int IEqualityComparer.GetHashCode(object? obj) #pragma warning restore CS8617 { @@ -44,7 +45,7 @@ namespace System.Collections.Generic public sealed partial class GenericEqualityComparer : EqualityComparer where T : IEquatable { [MethodImpl(MethodImplOptions.AggressiveInlining)] - public override bool Equals(T x, T y) + public override bool Equals([AllowNull] T x, [AllowNull] T y) { if (x != null) { @@ -56,7 +57,7 @@ namespace System.Collections.Generic } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public override int GetHashCode(T obj) => obj?.GetHashCode() ?? 0; + public override int GetHashCode([DisallowNull] T obj) => obj?.GetHashCode() ?? 0; // Equals method for the comparer itself. // If in the future this type is made sealed, change the is check to obj != null && GetType() == obj.GetType(). @@ -102,7 +103,7 @@ namespace System.Collections.Generic public sealed partial class ObjectEqualityComparer : EqualityComparer { [MethodImpl(MethodImplOptions.AggressiveInlining)] - public override bool Equals(T x, T y) + public override bool Equals([AllowNull] T x, [AllowNull] T y) { if (x != null) { @@ -114,7 +115,7 @@ namespace System.Collections.Generic } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public override int GetHashCode(T obj) => obj?.GetHashCode() ?? 0; + public override int GetHashCode([DisallowNull] T obj) => obj?.GetHashCode() ?? 0; // Equals method for the comparer itself. public override bool Equals(object? obj) => diff --git a/src/System.Private.CoreLib/shared/System/Collections/Generic/IComparer.cs b/src/System.Private.CoreLib/shared/System/Collections/Generic/IComparer.cs index 200ce17..064aa31 100644 --- a/src/System.Private.CoreLib/shared/System/Collections/Generic/IComparer.cs +++ b/src/System.Private.CoreLib/shared/System/Collections/Generic/IComparer.cs @@ -3,6 +3,7 @@ // See the LICENSE file in the project root for more information. using System; +using System.Diagnostics.CodeAnalysis; namespace System.Collections.Generic { @@ -15,6 +16,6 @@ namespace System.Collections.Generic // value less than zero if x is less than y, zero if x is equal to y, or a // value greater than zero if x is greater than y. // - int Compare(T x, T y); // TODO-NULLABLE-GENERIC: must work with nulls + int Compare([AllowNull] T x, [AllowNull] T y); } } diff --git a/src/System.Private.CoreLib/shared/System/Collections/Generic/IDictionary.cs b/src/System.Private.CoreLib/shared/System/Collections/Generic/IDictionary.cs index 75bc1bc..a93ec25 100644 --- a/src/System.Private.CoreLib/shared/System/Collections/Generic/IDictionary.cs +++ b/src/System.Private.CoreLib/shared/System/Collections/Generic/IDictionary.cs @@ -3,6 +3,7 @@ // See the LICENSE file in the project root for more information. using System; +using System.Diagnostics.CodeAnalysis; namespace System.Collections.Generic { @@ -45,6 +46,6 @@ namespace System.Collections.Generic // bool Remove(TKey key); - bool TryGetValue(TKey key, out TValue value); // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 + bool TryGetValue(TKey key, [MaybeNullWhen(false)] out TValue value); } } diff --git a/src/System.Private.CoreLib/shared/System/Collections/Generic/IEqualityComparer.cs b/src/System.Private.CoreLib/shared/System/Collections/Generic/IEqualityComparer.cs index 54925e9..025d693 100644 --- a/src/System.Private.CoreLib/shared/System/Collections/Generic/IEqualityComparer.cs +++ b/src/System.Private.CoreLib/shared/System/Collections/Generic/IEqualityComparer.cs @@ -2,6 +2,8 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +using System.Diagnostics.CodeAnalysis; + namespace System.Collections.Generic { // The generic IEqualityComparer interface implements methods to if check two objects are equal @@ -9,8 +11,8 @@ namespace System.Collections.Generic // It is use in Dictionary class. public interface IEqualityComparer { - bool Equals(T x, T y); - int GetHashCode(T obj); // TODO-NULLABLE-GENERIC: This generally doesn't accept nulls. + bool Equals([AllowNull] T x, [AllowNull] T y); + int GetHashCode([DisallowNull] T obj); } } diff --git a/src/System.Private.CoreLib/shared/System/Collections/Generic/IReadOnlyDictionary.cs b/src/System.Private.CoreLib/shared/System/Collections/Generic/IReadOnlyDictionary.cs index 1d57383..48e9602 100644 --- a/src/System.Private.CoreLib/shared/System/Collections/Generic/IReadOnlyDictionary.cs +++ b/src/System.Private.CoreLib/shared/System/Collections/Generic/IReadOnlyDictionary.cs @@ -2,7 +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. -using System; +using System.Diagnostics.CodeAnalysis; namespace System.Collections.Generic { @@ -10,7 +10,7 @@ namespace System.Collections.Generic public interface IReadOnlyDictionary : IReadOnlyCollection> where TKey : object { bool ContainsKey(TKey key); - bool TryGetValue(TKey key, out TValue value); // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 + bool TryGetValue(TKey key, [MaybeNullWhen(false)] out TValue value); TValue this[TKey key] { get; } IEnumerable Keys { get; } diff --git a/src/System.Private.CoreLib/shared/System/Collections/Generic/List.cs b/src/System.Private.CoreLib/shared/System/Collections/Generic/List.cs index 760220a..4a27224 100644 --- a/src/System.Private.CoreLib/shared/System/Collections/Generic/List.cs +++ b/src/System.Private.CoreLib/shared/System/Collections/Generic/List.cs @@ -4,6 +4,7 @@ using System.Collections.ObjectModel; using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.Runtime.CompilerServices; using System.Threading; @@ -170,10 +171,10 @@ namespace System.Collections.Generic { // Non-null values are fine. Only accept nulls if T is a class or Nullable. // Note that default(T) is not equal to null for value types except when T is Nullable. - return ((value is T) || (value == null && default(T)! == null)); // https://github.com/dotnet/roslyn/issues/34757 + return ((value is T) || (value == null && default(T)! == null)); // default(T) == null warning (https://github.com/dotnet/roslyn/issues/34757) } - object? IList.this[int index] // TODO-NULLABLE-GENERIC: nullability is the same as of T + object? IList.this[int index] { get { @@ -225,7 +226,7 @@ namespace System.Collections.Generic _items[size] = item; } - int IList.Add(object? item) // TODO-NULLABLE-GENERIC: nullable if default(T) can be null + int IList.Add(object? item) { ThrowHelper.IfNullAndNullsAreIllegalThenThrow(item, ExceptionArgument.item); @@ -345,7 +346,7 @@ namespace System.Collections.Generic List list = new List(_size); for (int i = 0; i < _size; i++) { - list._items[i] = converter!(_items[i]); // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 + list._items[i] = converter!(_items[i]); // TODO-NULLABLE: Remove ! when [DoesNotReturn] respected } list._size = _size; return list; @@ -418,6 +419,7 @@ namespace System.Collections.Generic public bool Exists(Predicate match) => FindIndex(match) != -1; + [return: MaybeNull] public T Find(Predicate match) { if (match == null) @@ -432,7 +434,7 @@ namespace System.Collections.Generic return _items[i]; } } - return default!; // TODO-NULLABLE-GENERIC: return value is nullable when T can be nullable + return default!; } public List FindAll(Predicate match) @@ -445,7 +447,7 @@ namespace System.Collections.Generic List list = new List(); for (int i = 0; i < _size; i++) { - if (match!(_items[i])) // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 + if (match!(_items[i])) // TODO-NULLABLE: Remove ! when [DoesNotReturn] respected { list.Add(_items[i]); } @@ -484,6 +486,7 @@ namespace System.Collections.Generic return -1; } + [return: MaybeNull] public T FindLast(Predicate match) { if (match == null) @@ -498,7 +501,7 @@ namespace System.Collections.Generic return _items[i]; } } - return default!; // TODO-NULLABLE-GENERIC: return value is nullable when T can be nullable + return default!; } public int FindLastIndex(Predicate match) @@ -540,7 +543,7 @@ namespace System.Collections.Generic int endIndex = startIndex - count; for (int i = startIndex; i > endIndex; i--) { - if (match!(_items[i])) // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 + if (match!(_items[i])) // TODO-NULLABLE: Remove ! when [DoesNotReturn] respected { return i; } @@ -619,7 +622,7 @@ namespace System.Collections.Generic public int IndexOf(T item) => Array.IndexOf(_items, item, 0, _size); - int IList.IndexOf(object? item) // TODO-NULLABLE-GENERIC: nullability == nullability(T) + int IList.IndexOf(object? item) { if (IsCompatibleObject(item)) { @@ -685,7 +688,7 @@ namespace System.Collections.Generic _version++; } - void IList.Insert(int index, object? item) // TODO-NULLABLE-GENERIC: nullable when T can be null + void IList.Insert(int index, object? item) { ThrowHelper.IfNullAndNullsAreIllegalThenThrow(item, ExceptionArgument.item); @@ -744,7 +747,7 @@ namespace System.Collections.Generic } else { - using (IEnumerator en = collection!.GetEnumerator()) // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 + using (IEnumerator en = collection!.GetEnumerator()) // TODO-NULLABLE: Remove ! when [DoesNotReturn] respected { while (en.MoveNext()) { @@ -844,7 +847,7 @@ namespace System.Collections.Generic return false; } - void IList.Remove(object? item) // TODO-NULLABLE-GENERIC: nullable when T can be null + void IList.Remove(object? item) { if (IsCompatibleObject(item)) { @@ -864,7 +867,7 @@ namespace System.Collections.Generic int freeIndex = 0; // the first free slot in items array // Find the first item which needs to be removed. - while (freeIndex < _size && !match!(_items[freeIndex])) freeIndex++; // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 + while (freeIndex < _size && !match!(_items[freeIndex])) freeIndex++; // TODO-NULLABLE: Remove ! when [DoesNotReturn] respected if (freeIndex >= _size) return 0; int current = freeIndex + 1; @@ -1023,7 +1026,7 @@ namespace System.Collections.Generic if (_size > 1) { - ArraySortHelper.Sort(_items, 0, _size, comparison!); // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 + ArraySortHelper.Sort(_items, 0, _size, comparison!); // TODO-NULLABLE: Remove ! when [DoesNotReturn] respected } _version++; } @@ -1082,14 +1085,14 @@ namespace System.Collections.Generic private readonly List _list; private int _index; private readonly int _version; - private T _current; // TODO-NULLABLE-GENERIC: nullable when T can be null + [AllowNull, MaybeNull] private T _current; internal Enumerator(List list) { _list = list; _index = 0; _version = list._version; - _current = default!; + _current = default!; // TODO-NULLABLE: Remove ! when nullable attributes are respected } public void Dispose() @@ -1117,11 +1120,11 @@ namespace System.Collections.Generic } _index = _list._size + 1; - _current = default!; + _current = default!; // TODO-NULLABLE: Remove ! when nullable attributes are respected return false; } - public T Current => _current; + public T Current => _current!; object? IEnumerator.Current { @@ -1143,7 +1146,7 @@ namespace System.Collections.Generic } _index = 0; - _current = default!; + _current = default!; // TODO-NULLABLE: Remove ! when nullable attributes are respected } } } diff --git a/src/System.Private.CoreLib/shared/System/Collections/Generic/NonRandomizedStringEqualityComparer.cs b/src/System.Private.CoreLib/shared/System/Collections/Generic/NonRandomizedStringEqualityComparer.cs index 26ffdf7..f042a6b 100644 --- a/src/System.Private.CoreLib/shared/System/Collections/Generic/NonRandomizedStringEqualityComparer.cs +++ b/src/System.Private.CoreLib/shared/System/Collections/Generic/NonRandomizedStringEqualityComparer.cs @@ -28,9 +28,7 @@ namespace System.Collections.Generic public void GetObjectData(SerializationInfo info, StreamingContext context) { // We are doing this to stay compatible with .NET Framework. -#pragma warning disable CS8631 // TODO-NULLABLE-GENERIC: https://github.com/dotnet/roslyn/issues/35406 info.SetType(typeof(GenericEqualityComparer)); -#pragma warning restore } } } diff --git a/src/System.Private.CoreLib/shared/System/Collections/HashHelpers.SerializationInfoTable.cs b/src/System.Private.CoreLib/shared/System/Collections/HashHelpers.SerializationInfoTable.cs index b3aa57c..64cf029 100644 --- a/src/System.Private.CoreLib/shared/System/Collections/HashHelpers.SerializationInfoTable.cs +++ b/src/System.Private.CoreLib/shared/System/Collections/HashHelpers.SerializationInfoTable.cs @@ -22,7 +22,7 @@ namespace System.Collections if (s_serializationInfoTable == null) Interlocked.CompareExchange(ref s_serializationInfoTable, new ConditionalWeakTable(), null); - return s_serializationInfoTable!; // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/34901 + return s_serializationInfoTable!; // TODO-NULLABLE: Remove ! when compiler specially-recognizes CompareExchange for nullability } } } diff --git a/src/System.Private.CoreLib/shared/System/Collections/IDictionary.cs b/src/System.Private.CoreLib/shared/System/Collections/IDictionary.cs index 0389563..5512500 100644 --- a/src/System.Private.CoreLib/shared/System/Collections/IDictionary.cs +++ b/src/System.Private.CoreLib/shared/System/Collections/IDictionary.cs @@ -2,6 +2,8 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +using System.Diagnostics.CodeAnalysis; + namespace System.Collections { // An IDictionary is a possibly unordered set of key-value pairs. @@ -13,46 +15,36 @@ namespace System.Collections // Interfaces are not serializable // The Item property provides methods to read and edit entries // in the Dictionary. - object? this[object key] // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/2384 + [DisallowNull] + object? this[object key] { get; set; } // Returns a collections of the keys in this dictionary. - ICollection Keys - { - get; - } + ICollection Keys {get; } // Returns a collections of the values in this dictionary. - ICollection Values - { - get; - } + ICollection Values { get; } // Returns whether this dictionary contains a particular key. - // bool Contains(object key); // Adds a key-value pair to the dictionary. - // void Add(object key, object? value); // Removes all pairs from the dictionary. void Clear(); - bool IsReadOnly - { get; } + bool IsReadOnly { get; } - bool IsFixedSize - { get; } + bool IsFixedSize { get; } // Returns an IDictionaryEnumerator for this dictionary. new IDictionaryEnumerator GetEnumerator(); // Removes a particular key from the dictionary. - // void Remove(object key); } } diff --git a/src/System.Private.CoreLib/shared/System/Collections/ListDictionaryInternal.cs b/src/System.Private.CoreLib/shared/System/Collections/ListDictionaryInternal.cs index 13daac5..b6b5462 100644 --- a/src/System.Private.CoreLib/shared/System/Collections/ListDictionaryInternal.cs +++ b/src/System.Private.CoreLib/shared/System/Collections/ListDictionaryInternal.cs @@ -283,7 +283,7 @@ namespace System.Collections current = null; } -#pragma warning disable CS8612 // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/30958 +#pragma warning disable CS8612 // TODO-NULLABLE: Covariant parameter types (https://github.com/dotnet/roslyn/issues/30958) public object Current #pragma warning restore CS8612 { diff --git a/src/System.Private.CoreLib/shared/System/Collections/ObjectModel/Collection.cs b/src/System.Private.CoreLib/shared/System/Collections/ObjectModel/Collection.cs index f8c9b87..6cf8438 100644 --- a/src/System.Private.CoreLib/shared/System/Collections/ObjectModel/Collection.cs +++ b/src/System.Private.CoreLib/shared/System/Collections/ObjectModel/Collection.cs @@ -26,7 +26,7 @@ namespace System.Collections.ObjectModel { ThrowHelper.ThrowArgumentNullException(ExceptionArgument.list); } - items = list!; // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 + items = list!; // TODO-NULLABLE: Remove ! when [DoesNotReturn] respected } public int Count @@ -133,7 +133,7 @@ namespace System.Collections.ObjectModel ThrowHelper.ThrowArgumentOutOfRange_IndexException(); } - InsertItemsRange(index, collection!); // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 + InsertItemsRange(index, collection!); // TODO-NULLABLE: Remove ! when [DoesNotReturn] respected } public bool Remove(T item) @@ -201,7 +201,7 @@ namespace System.Collections.ObjectModel ThrowHelper.ThrowArgumentNullException(ExceptionArgument.collection); } - ReplaceItemsRange(index, count, collection!); // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 + ReplaceItemsRange(index, count, collection!); // TODO-NULLABLE: Remove ! when [DoesNotReturn] respected } public void RemoveAt(int index) @@ -308,7 +308,7 @@ namespace System.Collections.ObjectModel ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array); } - if (array!.Rank != 1) // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 + if (array!.Rank != 1) // TODO-NULLABLE: Remove ! when [DoesNotReturn] respected { ThrowHelper.ThrowArgumentException(ExceptionResource.Arg_RankMultiDimNotSupported); } @@ -362,7 +362,7 @@ namespace System.Collections.ObjectModel { for (int i = 0; i < count; i++) { - objects![index++] = items[i]; // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 + objects![index++] = items[i]; // TODO-NULLABLE: Remove ! when [DoesNotReturn] respected } } catch (ArrayTypeMismatchException) @@ -381,7 +381,7 @@ namespace System.Collections.ObjectModel try { - this[index] = (T)value!; // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 + this[index] = (T)value!; } catch (InvalidCastException) { @@ -424,7 +424,7 @@ namespace System.Collections.ObjectModel try { - Add((T)value!); // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 + Add((T)value!); } catch (InvalidCastException) { @@ -438,7 +438,7 @@ namespace System.Collections.ObjectModel { if (IsCompatibleObject(value)) { - return Contains((T)value!); // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 + return Contains((T)value!); } return false; } @@ -447,7 +447,7 @@ namespace System.Collections.ObjectModel { if (IsCompatibleObject(value)) { - return IndexOf((T)value!); // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 + return IndexOf((T)value!); } return -1; } @@ -462,7 +462,7 @@ namespace System.Collections.ObjectModel try { - Insert(index, (T)value!); // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 + Insert(index, (T)value!); } catch (InvalidCastException) { @@ -479,7 +479,7 @@ namespace System.Collections.ObjectModel if (IsCompatibleObject(value)) { - Remove((T)value!); // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 + Remove((T)value!); } } diff --git a/src/System.Private.CoreLib/shared/System/Collections/ObjectModel/ReadOnlyCollection.cs b/src/System.Private.CoreLib/shared/System/Collections/ObjectModel/ReadOnlyCollection.cs index c29d449..69b3424 100644 --- a/src/System.Private.CoreLib/shared/System/Collections/ObjectModel/ReadOnlyCollection.cs +++ b/src/System.Private.CoreLib/shared/System/Collections/ObjectModel/ReadOnlyCollection.cs @@ -21,7 +21,7 @@ namespace System.Collections.ObjectModel { ThrowHelper.ThrowArgumentNullException(ExceptionArgument.list); } - this.list = list!; // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 + this.list = list!; // TODO-NULLABLE: Remove ! when [DoesNotReturn] respected } public int Count @@ -127,7 +127,7 @@ namespace System.Collections.ObjectModel ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array); } - if (array!.Rank != 1) // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 + if (array!.Rank != 1) // TODO-NULLABLE: Remove ! when [DoesNotReturn] respected { ThrowHelper.ThrowArgumentException(ExceptionResource.Arg_RankMultiDimNotSupported); } @@ -181,7 +181,7 @@ namespace System.Collections.ObjectModel { for (int i = 0; i < count; i++) { - objects![index++] = list[i]; // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 + objects![index++] = list[i]; // TODO-NULLABLE: Remove ! when [DoesNotReturn] respected } } catch (ArrayTypeMismatchException) @@ -232,7 +232,7 @@ namespace System.Collections.ObjectModel { if (IsCompatibleObject(value)) { - return Contains((T)value!); // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 + return Contains((T)value!); } return false; } @@ -241,7 +241,7 @@ namespace System.Collections.ObjectModel { if (IsCompatibleObject(value)) { - return IndexOf((T)value!); // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 + return IndexOf((T)value!); } return -1; } diff --git a/src/System.Private.CoreLib/shared/System/Convert.cs b/src/System.Private.CoreLib/shared/System/Convert.cs index 46192a2..412528c 100644 --- a/src/System.Private.CoreLib/shared/System/Convert.cs +++ b/src/System.Private.CoreLib/shared/System/Convert.cs @@ -11,6 +11,7 @@ using System.Runtime.InteropServices; using System.Runtime.Versioning; using System.Security; using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; namespace System { @@ -311,7 +312,8 @@ namespace System return ChangeType(value, conversionType, CultureInfo.CurrentCulture); } - public static object? ChangeType(object? value, Type conversionType, IFormatProvider? provider) // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 + [return: NotNullIfNotNull("value")] + public static object? ChangeType(object? value, Type conversionType, IFormatProvider? provider) { if (conversionType is null) { @@ -372,22 +374,31 @@ namespace System return ic.ToType(conversionType, provider); } + [DoesNotReturn] private static void ThrowCharOverflowException() { throw new OverflowException(SR.Overflow_Char); } + [DoesNotReturn] private static void ThrowByteOverflowException() { throw new OverflowException(SR.Overflow_Byte); } + [DoesNotReturn] private static void ThrowSByteOverflowException() { throw new OverflowException(SR.Overflow_SByte); } + [DoesNotReturn] private static void ThrowInt16OverflowException() { throw new OverflowException(SR.Overflow_Int16); } + [DoesNotReturn] private static void ThrowUInt16OverflowException() { throw new OverflowException(SR.Overflow_UInt16); } + [DoesNotReturn] private static void ThrowInt32OverflowException() { throw new OverflowException(SR.Overflow_Int32); } + [DoesNotReturn] private static void ThrowUInt32OverflowException() { throw new OverflowException(SR.Overflow_UInt32); } + [DoesNotReturn] private static void ThrowInt64OverflowException() { throw new OverflowException(SR.Overflow_Int64); } + [DoesNotReturn] private static void ThrowUInt64OverflowException() { throw new OverflowException(SR.Overflow_UInt64); } // Conversions to Boolean @@ -2153,14 +2164,16 @@ namespace System return value.ToString(provider); } - public static string? ToString(string? value) // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 + [return: NotNullIfNotNull("value")] + public static string? ToString(string? value) { return value; } - public static string? ToString(string? value, IFormatProvider? provider) // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 + [return: NotNullIfNotNull("value")] + public static string? ToString(string? value, IFormatProvider? provider) { - return value; // avoid the null check + return value; } diff --git a/src/System.Private.CoreLib/shared/System/DateTimeOffset.cs b/src/System.Private.CoreLib/shared/System/DateTimeOffset.cs index d2cb079..e328726 100644 --- a/src/System.Private.CoreLib/shared/System/DateTimeOffset.cs +++ b/src/System.Private.CoreLib/shared/System/DateTimeOffset.cs @@ -658,7 +658,7 @@ namespace System public static DateTimeOffset Parse(string input, IFormatProvider? formatProvider) { if (input == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.input); - return Parse(input!, formatProvider, DateTimeStyles.None); // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 + return Parse(input!, formatProvider, DateTimeStyles.None); // TODO-NULLABLE: Remove ! when [DoesNotReturn] respected } public static DateTimeOffset Parse(string input, IFormatProvider? formatProvider, DateTimeStyles styles) @@ -689,7 +689,7 @@ namespace System { if (input == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.input); if (format == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.format); - return ParseExact(input!, format!, formatProvider, DateTimeStyles.None); // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 + return ParseExact(input!, format!, formatProvider, DateTimeStyles.None); // TODO-NULLABLE: Remove ! when [DoesNotReturn] respected } // Constructs a DateTimeOffset from a string. The string must specify a diff --git a/src/System.Private.CoreLib/shared/System/DefaultBinder.cs b/src/System.Private.CoreLib/shared/System/DefaultBinder.cs index 6e6379e..0aef8ad 100644 --- a/src/System.Private.CoreLib/shared/System/DefaultBinder.cs +++ b/src/System.Private.CoreLib/shared/System/DefaultBinder.cs @@ -84,7 +84,7 @@ namespace System { if (args[i] != null) { - argTypes[i] = args[i]!.GetType(); //TODO-NULLABLE https://github.com/dotnet/csharplang/issues/2388 + argTypes[i] = args[i]!.GetType(); } } #endregion @@ -106,7 +106,7 @@ namespace System continue; // Validate the parameters. - ParameterInfo[] par = candidates[i]!.GetParametersNoCopy(); // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/34644 + ParameterInfo[] par = candidates[i]!.GetParametersNoCopy(); // TODO-NULLABLE: Indexer nullability tracked (https://github.com/dotnet/roslyn/issues/34644) #region Match method by parameter count if (par.Length == 0) @@ -114,7 +114,7 @@ namespace System #region No formal parameters if (args.Length != 0) { - if ((candidates[i]!.CallingConvention & CallingConventions.VarArgs) == 0) // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/34644 + if ((candidates[i]!.CallingConvention & CallingConventions.VarArgs) == 0) // TODO-NULLABLE: Indexer nullability tracked (https://github.com/dotnet/roslyn/issues/34644) continue; } diff --git a/src/System.Private.CoreLib/shared/System/Delegate.cs b/src/System.Private.CoreLib/shared/System/Delegate.cs index 5c4def4..62c3910 100644 --- a/src/System.Private.CoreLib/shared/System/Delegate.cs +++ b/src/System.Private.CoreLib/shared/System/Delegate.cs @@ -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. +using System.Diagnostics.CodeAnalysis; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Serialization; @@ -12,7 +13,9 @@ namespace System { public virtual object Clone() => MemberwiseClone(); - public static Delegate? Combine(Delegate? a, Delegate? b) // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 + [return: NotNullIfNotNull("a")] + [return: NotNullIfNotNull("b")] + public static Delegate? Combine(Delegate? a, Delegate? b) { if (a is null) return b; @@ -20,7 +23,7 @@ namespace System return a.CombineImpl(b); } - public static Delegate? Combine(params Delegate?[]? delegates) // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 + public static Delegate? Combine(params Delegate?[]? delegates) { if (delegates == null || delegates.Length == 0) return null; diff --git a/src/System.Private.CoreLib/shared/System/Diagnostics/CodeAnalysis/NullableAttributes.cs b/src/System.Private.CoreLib/shared/System/Diagnostics/CodeAnalysis/NullableAttributes.cs new file mode 100644 index 0000000..640ff8f --- /dev/null +++ b/src/System.Private.CoreLib/shared/System/Diagnostics/CodeAnalysis/NullableAttributes.cs @@ -0,0 +1,83 @@ +// 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. + +namespace System.Diagnostics.CodeAnalysis +{ + /// Specifies that null is allowed as an input even if the corresponding type disallows it. + [AttributeUsage(AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.Property, Inherited = false)] + public sealed class AllowNullAttribute : Attribute { } + + /// Specifies that null is disallowed as an input even if the corresponding type allows it. + [AttributeUsage(AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.Property, Inherited = false)] + public sealed class DisallowNullAttribute : Attribute { } + + /// Specifies that an output may be null even if the corresponding type disallows it. + [AttributeUsage(AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.Property | AttributeTargets.ReturnValue, Inherited = false)] + public sealed class MaybeNullAttribute : Attribute { } + + /// Specifies that an output will not be null even if the corresponding type allows it. + [AttributeUsage(AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.Property | AttributeTargets.ReturnValue, Inherited = false)] + public sealed class NotNullAttribute : Attribute { } + + /// Specifies that when a method returns , the parameter may be null even if the corresponding type disallows it. + [AttributeUsage(AttributeTargets.Parameter, Inherited = false)] + public sealed class MaybeNullWhenAttribute : Attribute + { + /// Initializes the attribute with the specified return value condition. + /// + /// The return value condition. If the method returns this value, the associated parameter may be null. + /// + public MaybeNullWhenAttribute(bool returnValue) => ReturnValue = returnValue; + + /// Gets the return value condition. + public bool ReturnValue { get; } + } + + /// Specifies that when a method returns , the parameter will not be null even if the corresponding type allows it. + [AttributeUsage(AttributeTargets.Parameter, Inherited = false)] + public sealed class NotNullWhenAttribute : Attribute + { + /// Initializes the attribute with the specified return value condition. + /// + /// The return value condition. If the method returns this value, the associated parameter will not be null. + /// + public NotNullWhenAttribute(bool returnValue) => ReturnValue = returnValue; + + /// Gets the return value condition. + public bool ReturnValue { get; } + } + + /// Specifies that the output will be non-null if the named parameter is non-null. + [AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Property | AttributeTargets.ReturnValue, AllowMultiple = true, Inherited = false)] + public sealed class NotNullIfNotNullAttribute : Attribute + { + /// Initializes the attribute with the associated parameter name. + /// + /// The associated parameter name. The output will be non-null if the argument to the parameter specified is non-null. + /// + public NotNullIfNotNullAttribute(string parameterName) => ParameterName = parameterName; + + /// Gets the associated parameter name. + public string ParameterName { get; } + } + + /// Applied to a method that will never return under any circumstance. + [AttributeUsage(AttributeTargets.Method, Inherited = false)] + public sealed class DoesNotReturnAttribute : Attribute { } + + /// Specifies that the method will not return if the associated Boolean parameter is passed the specified value. + [AttributeUsage(AttributeTargets.Parameter, Inherited = false)] + public sealed class DoesNotReturnIfAttribute : Attribute + { + /// Initializes the attribute with the specified parameter value. + /// + /// The condition parameter value. Code after the method will be considered unreachable by diagnostics if the argument to + /// the associated parameter matches this value. + /// + public DoesNotReturnIfAttribute(bool parameterValue) => ParameterValue = parameterValue; + + /// Gets the condition parameter value. + public bool ParameterValue { get; } + } +} diff --git a/src/System.Private.CoreLib/shared/System/Diagnostics/Contracts/Contracts.cs b/src/System.Private.CoreLib/shared/System/Diagnostics/Contracts/Contracts.cs index 13d13f1..af6c1a3 100644 --- a/src/System.Private.CoreLib/shared/System/Diagnostics/Contracts/Contracts.cs +++ b/src/System.Private.CoreLib/shared/System/Diagnostics/Contracts/Contracts.cs @@ -18,6 +18,7 @@ #define DEBUG // The behavior of this contract library should be consistent regardless of build type. using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; using System.Reflection; namespace System.Diagnostics.Contracts @@ -245,7 +246,7 @@ namespace System.Diagnostics.Contracts [Pure] [Conditional("DEBUG")] [Conditional("CONTRACTS_FULL")] - public static void Assume(bool condition) + public static void Assume([DoesNotReturnIf(false)] bool condition) { if (!condition) { @@ -264,7 +265,7 @@ namespace System.Diagnostics.Contracts [Pure] [Conditional("DEBUG")] [Conditional("CONTRACTS_FULL")] - public static void Assume(bool condition, string? userMessage) + public static void Assume([DoesNotReturnIf(false)] bool condition, string? userMessage) { if (!condition) { @@ -283,7 +284,7 @@ namespace System.Diagnostics.Contracts [Pure] [Conditional("DEBUG")] [Conditional("CONTRACTS_FULL")] - public static void Assert(bool condition) + public static void Assert([DoesNotReturnIf(false)] bool condition) { if (!condition) ReportFailure(ContractFailureKind.Assert, null, null, null); @@ -297,7 +298,7 @@ namespace System.Diagnostics.Contracts [Pure] [Conditional("DEBUG")] [Conditional("CONTRACTS_FULL")] - public static void Assert(bool condition, string? userMessage) + public static void Assert([DoesNotReturnIf(false)] bool condition, string? userMessage) { if (!condition) ReportFailure(ContractFailureKind.Assert, userMessage, null, null); diff --git a/src/System.Private.CoreLib/shared/System/Diagnostics/Debug.cs b/src/System.Private.CoreLib/shared/System/Diagnostics/Debug.cs index 8d77fc2..251ac22 100644 --- a/src/System.Private.CoreLib/shared/System/Diagnostics/Debug.cs +++ b/src/System.Private.CoreLib/shared/System/Diagnostics/Debug.cs @@ -4,6 +4,8 @@ // Do not remove this, it is needed to retain calls to these conditional methods in release builds #define DEBUG + +using System.Diagnostics.CodeAnalysis; using System.Threading; namespace System.Diagnostics @@ -85,19 +87,19 @@ namespace System.Diagnostics } [System.Diagnostics.Conditional("DEBUG")] - public static void Assert(bool condition) + public static void Assert([DoesNotReturnIf(false)] bool condition) { Assert(condition, string.Empty, string.Empty); } [System.Diagnostics.Conditional("DEBUG")] - public static void Assert(bool condition, string? message) + public static void Assert([DoesNotReturnIf(false)] bool condition, string? message) { Assert(condition, message, string.Empty); } [System.Diagnostics.Conditional("DEBUG")] - public static void Assert(bool condition, string? message, string? detailMessage) + public static void Assert([DoesNotReturnIf(false)] bool condition, string? message, string? detailMessage) { if (!condition) { @@ -121,19 +123,21 @@ namespace System.Diagnostics } [System.Diagnostics.Conditional("DEBUG")] + [DoesNotReturn] public static void Fail(string? message) { Fail(message, string.Empty); } [System.Diagnostics.Conditional("DEBUG")] + [DoesNotReturn] public static void Fail(string? message, string? detailMessage) { s_provider.Fail(message, detailMessage); } [System.Diagnostics.Conditional("DEBUG")] - public static void Assert(bool condition, string? message, string detailMessageFormat, params object?[] args) + public static void Assert([DoesNotReturnIf(false)] bool condition, string? message, string detailMessageFormat, params object?[] args) { Assert(condition, message, string.Format(detailMessageFormat, args)); } diff --git a/src/System.Private.CoreLib/shared/System/Diagnostics/DebugProvider.cs b/src/System.Private.CoreLib/shared/System/Diagnostics/DebugProvider.cs index 2e82810..939f371 100644 --- a/src/System.Private.CoreLib/shared/System/Diagnostics/DebugProvider.cs +++ b/src/System.Private.CoreLib/shared/System/Diagnostics/DebugProvider.cs @@ -97,7 +97,7 @@ namespace System.Diagnostics int indentCount = Debug.IndentSize * Debug.IndentLevel; if (_indentString?.Length == indentCount) { - return _indentString!; // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/34942 + return _indentString!; // TODO-NULLABLE: Null conditional access (https://github.com/dotnet/roslyn/issues/34942) } return _indentString = new string(' ', indentCount); } diff --git a/src/System.Private.CoreLib/shared/System/Diagnostics/StackTrace.cs b/src/System.Private.CoreLib/shared/System/Diagnostics/StackTrace.cs index 1e3e9f6..107d4eb 100644 --- a/src/System.Private.CoreLib/shared/System/Diagnostics/StackTrace.cs +++ b/src/System.Private.CoreLib/shared/System/Diagnostics/StackTrace.cs @@ -226,7 +226,7 @@ namespace System.Diagnostics isAsync = typeof(IAsyncStateMachine).IsAssignableFrom(declaringType); if (isAsync || typeof(IEnumerator).IsAssignableFrom(declaringType)) { - methodChanged = TryResolveStateMachineMethod(ref mb!, out declaringType); // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 + methodChanged = TryResolveStateMachineMethod(ref mb!, out declaringType); // TODO-NULLABLE: Pass non-null string? to string ref (https://github.com/dotnet/roslyn/issues/34874) } } diff --git a/src/System.Private.CoreLib/shared/System/Diagnostics/Tracing/DiagnosticCounter.cs b/src/System.Private.CoreLib/shared/System/Diagnostics/Tracing/DiagnosticCounter.cs index 84450ab..af48288 100644 --- a/src/System.Private.CoreLib/shared/System/Diagnostics/Tracing/DiagnosticCounter.cs +++ b/src/System.Private.CoreLib/shared/System/Diagnostics/Tracing/DiagnosticCounter.cs @@ -59,7 +59,7 @@ namespace System.Diagnostics.Tracing if (_group != null) { _group.Remove(this); - _group = null!; // TODO-NULLABLE: should not be nulled out + _group = null!; // TODO-NULLABLE: Avoid nulling out in Dispose } } diff --git a/src/System.Private.CoreLib/shared/System/Diagnostics/Tracing/EventProvider.cs b/src/System.Private.CoreLib/shared/System/Diagnostics/Tracing/EventProvider.cs index caa7fae..fde1b47 100644 --- a/src/System.Private.CoreLib/shared/System/Diagnostics/Tracing/EventProvider.cs +++ b/src/System.Private.CoreLib/shared/System/Diagnostics/Tracing/EventProvider.cs @@ -322,7 +322,7 @@ namespace System.Diagnostics.Tracing GetDataFromController(etwSessionId, filterData, out command, out data, out keyIndex)) { args = new Dictionary(4); - Debug.Assert(data != null); // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 + Debug.Assert(data != null); while (keyIndex < data.Length) { int keyEnd = FindNull(data, keyIndex); @@ -602,7 +602,7 @@ namespace System.Diagnostics.Tracing /// starts, and the command being issued associated with that data. /// private unsafe bool GetDataFromController(int etwSessionId, - Interop.Advapi32.EVENT_FILTER_DESCRIPTOR* filterData, out ControllerCommand command, out byte[]? data, out int dataStart) + Interop.Advapi32.EVENT_FILTER_DESCRIPTOR* filterData, out ControllerCommand command, out byte[]? data, out int dataStart) { data = null; dataStart = 0; diff --git a/src/System.Private.CoreLib/shared/System/Diagnostics/Tracing/EventSource.cs b/src/System.Private.CoreLib/shared/System/Diagnostics/Tracing/EventSource.cs index 9f59da9..6412676 100644 --- a/src/System.Private.CoreLib/shared/System/Diagnostics/Tracing/EventSource.cs +++ b/src/System.Private.CoreLib/shared/System/Diagnostics/Tracing/EventSource.cs @@ -164,7 +164,6 @@ // opportunity to expose this format to EventListeners in the future. // using System; -using System.Runtime.CompilerServices; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Diagnostics; @@ -1365,14 +1364,14 @@ namespace System.Diagnostics.Tracing if (m_etwProvider != null) { m_etwProvider.Dispose(); - m_etwProvider = null!; // TODO-NULLABLE: should not be nulled out on Dispose + m_etwProvider = null!; // TODO-NULLABLE: Avoid nulling out in Dispose } #endif #if FEATURE_PERFTRACING if (m_eventPipeProvider != null) { m_eventPipeProvider.Dispose(); - m_eventPipeProvider = null!; // TODO-NULLABLE: should not be nulled out on Dispose + m_eventPipeProvider = null!; // TODO-NULLABLE: Avoid nulling out in Dispose } #endif } @@ -1735,7 +1734,7 @@ namespace System.Diagnostics.Tracing hash.Start(); hash.Append(namespaceBytes); hash.Append(bytes); - Array.Resize(ref bytes!, 16); // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 + Array.Resize(ref bytes!, 16); // TODO-NULLABLE: Remove ! when nullable attributes are respected hash.Finish(bytes); bytes[7] = unchecked((byte)((bytes[7] & 0x0F) | 0x50)); // Set high 4 bits of octet 7 to 5, as per RFC 4122 @@ -3106,7 +3105,7 @@ namespace System.Diagnostics.Tracing foreach (CustomAttributeNamedArgument namedArgument in data.NamedArguments) { - PropertyInfo p = t.GetProperty(namedArgument.MemberInfo.Name, BindingFlags.Public | BindingFlags.Instance)!; // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 + PropertyInfo p = t.GetProperty(namedArgument.MemberInfo.Name, BindingFlags.Public | BindingFlags.Instance)!; object value = namedArgument.TypedValue.Value!; if (p.PropertyType.IsEnum) @@ -3430,7 +3429,7 @@ namespace System.Diagnostics.Tracing // overwrite inline message with the localized message if (msg != null) eventAttribute.Message = msg; - AddEventDescriptor(ref eventData!, eventName, eventAttribute, args, hasRelatedActivityID); // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/34874 + AddEventDescriptor(ref eventData!, eventName, eventAttribute, args, hasRelatedActivityID); // TODO-NULLABLE: Remove ! when nullable attributes are respected } } } @@ -3441,7 +3440,7 @@ namespace System.Diagnostics.Tracing if (source != null) { Debug.Assert(eventData != null); - TrimEventDescriptors(ref eventData!); // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/34874 + TrimEventDescriptors(ref eventData!); // TODO-NULLABLE: Pass non-null string? to string ref (https://github.com/dotnet/roslyn/issues/34874) source.m_eventData = eventData; // officially initialize it. We do this at most once (it is racy otherwise). #if FEATURE_MANAGED_ETW_CHANNELS source.m_channelData = manifest.GetChannelData(); @@ -3473,12 +3472,11 @@ namespace System.Diagnostics.Tracing exception = e; } - // TODO-NULLABLE: possible bug: if error is thrown before manifest is assigned in non-strict mode, this will NRE - if ((flags & EventManifestOptions.Strict) != 0 && (manifest!.Errors.Count > 0 || exception != null)) + if ((flags & EventManifestOptions.Strict) != 0 && (manifest?.Errors.Count > 0 || exception != null)) { string msg = string.Empty; - if (manifest.Errors.Count > 0) + if (manifest?.Errors.Count > 0) { bool firstError = true; foreach (string error in manifest.Errors) @@ -3554,13 +3552,15 @@ namespace System.Diagnostics.Tracing // Helper used by code:CreateManifestAndDescriptors to add a code:EventData descriptor for a method // with the code:EventAttribute 'eventAttribute'. resourceManger may be null in which case we populate it // it is populated if we need to look up message resources - private static void AddEventDescriptor(ref EventMetadata[] eventData, string eventName, - EventAttribute eventAttribute, ParameterInfo[] eventParameters, - bool hasRelatedActivityID) + private static void AddEventDescriptor( + [NotNull] ref EventMetadata[] eventData, + string eventName, + EventAttribute eventAttribute, + ParameterInfo[] eventParameters, + bool hasRelatedActivityID) { - if (eventData == null || eventData.Length <= eventAttribute.EventId) + if (eventData.Length <= eventAttribute.EventId) { - Debug.Assert(eventData != null); // TODO-NULLABLE: possible bug in the code: NRE when eventData == null EventMetadata[] newValues = new EventMetadata[Math.Max(eventData.Length + 16, eventAttribute.EventId + 1)]; Array.Copy(eventData, 0, newValues, 0, eventData.Length); eventData = newValues; @@ -4509,7 +4509,7 @@ namespace System.Diagnostics.Tracing { if (s_EventSources == null) Interlocked.CompareExchange(ref s_EventSources, new List(2), null); - return s_EventSources!; // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/34901 + return s_EventSources!; // TODO-NULLABLE: Remove ! when compiler specially-recognizes CompareExchange for nullability } } @@ -6045,7 +6045,7 @@ namespace System.Diagnostics.Tracing if (resources != null && eventMessage == null) eventMessage = resources.GetString("event_" + eventName, CultureInfo.InvariantCulture); - Debug.Assert(info.Attribs != null); // TODO-NULLABLE: Bug - Attribs is documented that it can be null in which case this code will NRE + Debug.Assert(info.Attribs != null); if (info.Attribs.EventChannelType == EventChannelType.Admin && eventMessage == null) ManifestError(SR.Format(SR.EventSource_EventWithAdminChannelMustHaveMessage, eventName, info.Name)); return info.Name; @@ -6187,7 +6187,7 @@ namespace System.Diagnostics.Tracing } } - private static void UpdateStringBuilder(ref StringBuilder? stringBuilder, string eventMessage, int startIndex, int count) // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 nullable in, non-nullable out + private static void UpdateStringBuilder([NotNull] ref StringBuilder? stringBuilder, string eventMessage, int startIndex, int count) { if (stringBuilder == null) stringBuilder = new StringBuilder(); @@ -6209,14 +6209,14 @@ namespace System.Diagnostics.Tracing if (stringBuilder == null) return eventMessage; UpdateStringBuilder(ref stringBuilder, eventMessage, writtenSoFar, i - writtenSoFar); - return stringBuilder!.ToString(); // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 + return stringBuilder!.ToString(); // TODO-NULLABLE: Remove ! when nullable attributes are respected } if (eventMessage[i] == '%') { // handle format message escaping character '%' by escaping it UpdateStringBuilder(ref stringBuilder, eventMessage, writtenSoFar, i - writtenSoFar); - stringBuilder!.Append("%%"); // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 + stringBuilder!.Append("%%"); // TODO-NULLABLE: Remove ! when nullable attributes are respected i++; writtenSoFar = i; } @@ -6225,7 +6225,7 @@ namespace System.Diagnostics.Tracing { // handle C# escaped '{" and '}' UpdateStringBuilder(ref stringBuilder, eventMessage, writtenSoFar, i - writtenSoFar); - stringBuilder!.Append(eventMessage[i]); // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 + stringBuilder!.Append(eventMessage[i]); // TODO-NULLABLE: Remove ! when nullable attributes are respected i++; i++; writtenSoFar = i; } @@ -6244,7 +6244,7 @@ namespace System.Diagnostics.Tracing i++; UpdateStringBuilder(ref stringBuilder, eventMessage, writtenSoFar, leftBracket - writtenSoFar); int manIndex = TranslateIndexToManifestConvention(argNum, evtName); - stringBuilder!.Append('%').Append(manIndex); // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 + stringBuilder!.Append('%').Append(manIndex); // TODO-NULLABLE: Remove ! when nullable attributes are respected // An '!' after the insert specifier {n} will be interpreted as a literal. // We'll escape it so that mc.exe does not attempt to consider it the // beginning of a format string. @@ -6264,7 +6264,7 @@ namespace System.Diagnostics.Tracing { UpdateStringBuilder(ref stringBuilder, eventMessage, writtenSoFar, i - writtenSoFar); i++; - stringBuilder!.Append(s_escapes[chIdx]); // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 + stringBuilder!.Append(s_escapes[chIdx]); // TODO-NULLABLE: Remove ! when nullable attributes are respected writtenSoFar = i; } else diff --git a/src/System.Private.CoreLib/shared/System/Diagnostics/Tracing/TraceLogging/ConcurrentSet.cs b/src/System.Private.CoreLib/shared/System/Diagnostics/Tracing/TraceLogging/ConcurrentSet.cs index a15dfaa..fca673d 100644 --- a/src/System.Private.CoreLib/shared/System/Diagnostics/Tracing/TraceLogging/ConcurrentSet.cs +++ b/src/System.Private.CoreLib/shared/System/Diagnostics/Tracing/TraceLogging/ConcurrentSet.cs @@ -110,7 +110,7 @@ namespace System.Diagnostics.Tracing Array.Copy(oldItems, lo, newItems, lo + 1, oldLength - lo); } - newItems = Interlocked.CompareExchange(ref this.items, newItems, oldItems)!; // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/34901 + newItems = Interlocked.CompareExchange(ref this.items, newItems, oldItems)!; if (oldItems != newItems) { oldItems = newItems; diff --git a/src/System.Private.CoreLib/shared/System/Diagnostics/Tracing/TraceLogging/EventPayload.cs b/src/System.Private.CoreLib/shared/System/Diagnostics/Tracing/TraceLogging/EventPayload.cs index 010d512..3572352 100644 --- a/src/System.Private.CoreLib/shared/System/Diagnostics/Tracing/TraceLogging/EventPayload.cs +++ b/src/System.Private.CoreLib/shared/System/Diagnostics/Tracing/TraceLogging/EventPayload.cs @@ -3,9 +3,10 @@ // See the LICENSE file in the project root for more information. using System; -using System.Collections.Generic; using System.Collections; +using System.Collections.Generic; using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; #if !ES_BUILD_AGAINST_DOTNET_V35 using Contract = System.Diagnostics.Contracts.Contract; @@ -128,7 +129,7 @@ namespace System.Diagnostics.Tracing throw new System.NotSupportedException(); } - public bool TryGetValue(string key, out object? value) + public bool TryGetValue(string key, [MaybeNullWhen(false)] out object? value) { if (key == null) throw new System.ArgumentNullException(nameof(key)); diff --git a/src/System.Private.CoreLib/shared/System/Diagnostics/Tracing/TraceLogging/PropertyValue.cs b/src/System.Private.CoreLib/shared/System/Diagnostics/Tracing/TraceLogging/PropertyValue.cs index 61ed204..3d0afdd 100644 --- a/src/System.Private.CoreLib/shared/System/Diagnostics/Tracing/TraceLogging/PropertyValue.cs +++ b/src/System.Private.CoreLib/shared/System/Diagnostics/Tracing/TraceLogging/PropertyValue.cs @@ -241,32 +241,32 @@ namespace System.Diagnostics.Tracing if (!Statics.IsValueType(type)) { var getter = (Func)GetGetMethod(property, type); - return container => new PropertyValue(getter((TContainer)container.ReferenceValue!)); // TODO-NULLABLE-GENERIC: Re-review + return container => new PropertyValue(getter((TContainer)container.ReferenceValue!)); } else { if (type.GetTypeInfo().IsEnum) type = Enum.GetUnderlyingType(type); - if (type == typeof(bool)) { var f = (Func)GetGetMethod(property, type); return container => new PropertyValue(f((TContainer)container.ReferenceValue!)); } // TODO-NULLABLE-GENERIC: Re-review - if (type == typeof(byte)) { var f = (Func)GetGetMethod(property, type); return container => new PropertyValue(f((TContainer)container.ReferenceValue!)); } // TODO-NULLABLE-GENERIC: Re-review - if (type == typeof(sbyte)) { var f = (Func)GetGetMethod(property, type); return container => new PropertyValue(f((TContainer)container.ReferenceValue!)); } // TODO-NULLABLE-GENERIC: Re-review - if (type == typeof(char)) { var f = (Func)GetGetMethod(property, type); return container => new PropertyValue(f((TContainer)container.ReferenceValue!)); } // TODO-NULLABLE-GENERIC: Re-review - if (type == typeof(short)) { var f = (Func)GetGetMethod(property, type); return container => new PropertyValue(f((TContainer)container.ReferenceValue!)); } // TODO-NULLABLE-GENERIC: Re-review - if (type == typeof(ushort)) { var f = (Func)GetGetMethod(property, type); return container => new PropertyValue(f((TContainer)container.ReferenceValue!)); } // TODO-NULLABLE-GENERIC: Re-review - if (type == typeof(int)) { var f = (Func)GetGetMethod(property, type); return container => new PropertyValue(f((TContainer)container.ReferenceValue!)); } // TODO-NULLABLE-GENERIC: Re-review - if (type == typeof(uint)) { var f = (Func)GetGetMethod(property, type); return container => new PropertyValue(f((TContainer)container.ReferenceValue!)); } // TODO-NULLABLE-GENERIC: Re-review - if (type == typeof(long)) { var f = (Func)GetGetMethod(property, type); return container => new PropertyValue(f((TContainer)container.ReferenceValue!)); } // TODO-NULLABLE-GENERIC: Re-review - if (type == typeof(ulong)) { var f = (Func)GetGetMethod(property, type); return container => new PropertyValue(f((TContainer)container.ReferenceValue!)); } // TODO-NULLABLE-GENERIC: Re-review - if (type == typeof(IntPtr)) { var f = (Func)GetGetMethod(property, type); return container => new PropertyValue(f((TContainer)container.ReferenceValue!)); } // TODO-NULLABLE-GENERIC: Re-review - if (type == typeof(UIntPtr)) { var f = (Func)GetGetMethod(property, type); return container => new PropertyValue(f((TContainer)container.ReferenceValue!)); } // TODO-NULLABLE-GENERIC: Re-review - if (type == typeof(float)) { var f = (Func)GetGetMethod(property, type); return container => new PropertyValue(f((TContainer)container.ReferenceValue!)); } // TODO-NULLABLE-GENERIC: Re-review - if (type == typeof(double)) { var f = (Func)GetGetMethod(property, type); return container => new PropertyValue(f((TContainer)container.ReferenceValue!)); } // TODO-NULLABLE-GENERIC: Re-review - if (type == typeof(Guid)) { var f = (Func)GetGetMethod(property, type); return container => new PropertyValue(f((TContainer)container.ReferenceValue!)); } // TODO-NULLABLE-GENERIC: Re-review - if (type == typeof(DateTime)) { var f = (Func)GetGetMethod(property, type); return container => new PropertyValue(f((TContainer)container.ReferenceValue!)); } // TODO-NULLABLE-GENERIC: Re-review - if (type == typeof(DateTimeOffset)) { var f = (Func)GetGetMethod(property, type); return container => new PropertyValue(f((TContainer)container.ReferenceValue!)); } // TODO-NULLABLE-GENERIC: Re-review - if (type == typeof(TimeSpan)) { var f = (Func)GetGetMethod(property, type); return container => new PropertyValue(f((TContainer)container.ReferenceValue!)); } // TODO-NULLABLE-GENERIC: Re-review - if (type == typeof(decimal)) { var f = (Func)GetGetMethod(property, type); return container => new PropertyValue(f((TContainer)container.ReferenceValue!)); } // TODO-NULLABLE-GENERIC: Re-review + if (type == typeof(bool)) { var f = (Func)GetGetMethod(property, type); return container => new PropertyValue(f((TContainer)container.ReferenceValue!)); } + if (type == typeof(byte)) { var f = (Func)GetGetMethod(property, type); return container => new PropertyValue(f((TContainer)container.ReferenceValue!)); } + if (type == typeof(sbyte)) { var f = (Func)GetGetMethod(property, type); return container => new PropertyValue(f((TContainer)container.ReferenceValue!)); } + if (type == typeof(char)) { var f = (Func)GetGetMethod(property, type); return container => new PropertyValue(f((TContainer)container.ReferenceValue!)); } + if (type == typeof(short)) { var f = (Func)GetGetMethod(property, type); return container => new PropertyValue(f((TContainer)container.ReferenceValue!)); } + if (type == typeof(ushort)) { var f = (Func)GetGetMethod(property, type); return container => new PropertyValue(f((TContainer)container.ReferenceValue!)); } + if (type == typeof(int)) { var f = (Func)GetGetMethod(property, type); return container => new PropertyValue(f((TContainer)container.ReferenceValue!)); } + if (type == typeof(uint)) { var f = (Func)GetGetMethod(property, type); return container => new PropertyValue(f((TContainer)container.ReferenceValue!)); } + if (type == typeof(long)) { var f = (Func)GetGetMethod(property, type); return container => new PropertyValue(f((TContainer)container.ReferenceValue!)); } + if (type == typeof(ulong)) { var f = (Func)GetGetMethod(property, type); return container => new PropertyValue(f((TContainer)container.ReferenceValue!)); } + if (type == typeof(IntPtr)) { var f = (Func)GetGetMethod(property, type); return container => new PropertyValue(f((TContainer)container.ReferenceValue!)); } + if (type == typeof(UIntPtr)) { var f = (Func)GetGetMethod(property, type); return container => new PropertyValue(f((TContainer)container.ReferenceValue!)); } + if (type == typeof(float)) { var f = (Func)GetGetMethod(property, type); return container => new PropertyValue(f((TContainer)container.ReferenceValue!)); } + if (type == typeof(double)) { var f = (Func)GetGetMethod(property, type); return container => new PropertyValue(f((TContainer)container.ReferenceValue!)); } + if (type == typeof(Guid)) { var f = (Func)GetGetMethod(property, type); return container => new PropertyValue(f((TContainer)container.ReferenceValue!)); } + if (type == typeof(DateTime)) { var f = (Func)GetGetMethod(property, type); return container => new PropertyValue(f((TContainer)container.ReferenceValue!)); } + if (type == typeof(DateTimeOffset)) { var f = (Func)GetGetMethod(property, type); return container => new PropertyValue(f((TContainer)container.ReferenceValue!)); } + if (type == typeof(TimeSpan)) { var f = (Func)GetGetMethod(property, type); return container => new PropertyValue(f((TContainer)container.ReferenceValue!)); } + if (type == typeof(decimal)) { var f = (Func)GetGetMethod(property, type); return container => new PropertyValue(f((TContainer)container.ReferenceValue!)); } return container => new PropertyValue(property.GetValue(container.ReferenceValue)); } diff --git a/src/System.Private.CoreLib/shared/System/Diagnostics/Tracing/TraceLogging/Statics.cs b/src/System.Private.CoreLib/shared/System/Diagnostics/Tracing/TraceLogging/Statics.cs index 379a67a..0affe93 100644 --- a/src/System.Private.CoreLib/shared/System/Diagnostics/Tracing/TraceLogging/Statics.cs +++ b/src/System.Private.CoreLib/shared/System/Diagnostics/Tracing/TraceLogging/Statics.cs @@ -10,6 +10,7 @@ using System.Runtime.CompilerServices; using Encoding = System.Text.Encoding; using Microsoft.Reflection; +using System.Diagnostics.CodeAnalysis; #if ES_BUILD_STANDALONE using Environment = Microsoft.Diagnostics.Tracing.Internal.Environment; @@ -421,10 +422,10 @@ namespace System.Diagnostics.Tracing return result; } - public static AttributeType GetCustomAttribute(PropertyInfo propInfo) - where AttributeType : Attribute? + public static AttributeType? GetCustomAttribute(PropertyInfo propInfo) + where AttributeType : Attribute { - AttributeType result = null!; // TODO-NULLABLE-GENERIC: re-review + AttributeType? result = null; #if (ES_BUILD_PCL || ES_BUILD_PN) foreach (var attrib in propInfo.GetCustomAttributes(false)) { @@ -441,10 +442,10 @@ namespace System.Diagnostics.Tracing return result; } - public static AttributeType GetCustomAttribute(Type type) - where AttributeType : Attribute? + public static AttributeType? GetCustomAttribute(Type type) + where AttributeType : Attribute { - AttributeType result = null!; // TODO-NULLABLE-GENERIC: re-review + AttributeType? result = null; #if (ES_BUILD_PCL || ES_BUILD_PN) foreach (var attrib in type.GetTypeInfo().GetCustomAttributes(false)) { @@ -537,9 +538,9 @@ namespace System.Diagnostics.Tracing recursionCheck.Add(dataType); - var eventAttrib = Statics.GetCustomAttribute(dataType); + var eventAttrib = Statics.GetCustomAttribute(dataType); if (eventAttrib != null || - Statics.GetCustomAttribute(dataType) != null || + Statics.GetCustomAttribute(dataType) != null || IsGenericMatch(dataType, typeof(KeyValuePair<,>))) { var analysis = new TypeAnalysis(dataType, eventAttrib, recursionCheck); diff --git a/src/System.Private.CoreLib/shared/System/Diagnostics/Tracing/TraceLogging/TypeAnalysis.cs b/src/System.Private.CoreLib/shared/System/Diagnostics/Tracing/TraceLogging/TypeAnalysis.cs index 3ade2b2..ff99f5e 100644 --- a/src/System.Private.CoreLib/shared/System/Diagnostics/Tracing/TraceLogging/TypeAnalysis.cs +++ b/src/System.Private.CoreLib/shared/System/Diagnostics/Tracing/TraceLogging/TypeAnalysis.cs @@ -59,7 +59,7 @@ namespace System.Diagnostics.Tracing var propertyType = propertyInfo.PropertyType; var propertyTypeInfo = TraceLoggingTypeInfo.GetInstance(propertyType, recursionCheck); - var fieldAttribute = Statics.GetCustomAttribute(propertyInfo); + var fieldAttribute = Statics.GetCustomAttribute(propertyInfo); string propertyName = fieldAttribute != null && fieldAttribute.Name != null diff --git a/src/System.Private.CoreLib/shared/System/Enum.cs b/src/System.Private.CoreLib/shared/System/Enum.cs index 0f07c75..df7c1ee 100644 --- a/src/System.Private.CoreLib/shared/System/Enum.cs +++ b/src/System.Private.CoreLib/shared/System/Enum.cs @@ -3,6 +3,7 @@ // See the LICENSE file in the project root for more information. using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.Reflection; using System.Runtime.CompilerServices; @@ -493,7 +494,7 @@ namespace System default: parsed = TryParseRareEnum(rt, value, valueSpan, ignoreCase, throwOnFailure, out object? objectResult); - result = parsed ? (TEnum)objectResult! : default; // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/34976 + result = parsed ? (TEnum)objectResult! : default; return parsed; } } @@ -645,7 +646,7 @@ namespace System } /// Tries to parse the value of an enum with an underlying type that can't be expressed in C# (e.g. char, bool, double, etc.) - private static bool TryParseRareEnum(RuntimeType enumType, string? originalValueString, ReadOnlySpan value, bool ignoreCase, bool throwOnFailure, out object? result) + private static bool TryParseRareEnum(RuntimeType enumType, string? originalValueString, ReadOnlySpan value, bool ignoreCase, bool throwOnFailure, [NotNullWhen(true)] out object? result) { Debug.Assert( enumType.GetEnumUnderlyingType() != typeof(sbyte) && diff --git a/src/System.Private.CoreLib/shared/System/Environment.Unix.cs b/src/System.Private.CoreLib/shared/System/Environment.Unix.cs index fa343ac..0d802dc 100644 --- a/src/System.Private.CoreLib/shared/System/Environment.Unix.cs +++ b/src/System.Private.CoreLib/shared/System/Environment.Unix.cs @@ -75,14 +75,16 @@ namespace System { Debug.Assert(option == SpecialFolderOption.Create); +#pragma warning disable CS8634 // TODO-NULLABLE: Remove warning disable when nullable attributes are respected // TODO #11151: Replace with Directory.CreateDirectory once we have access to System.IO.FileSystem here. Func createDirectory = LazyInitializer.EnsureInitialized(ref s_directoryCreateDirectory, () => { Type dirType = Type.GetType("System.IO.Directory, System.IO.FileSystem, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a", throwOnError: true)!; MethodInfo mi = dirType.GetTypeInfo().GetDeclaredMethod("CreateDirectory")!; return (Func)mi.CreateDelegate(typeof(Func)); - })!; // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 + })!; // TODO-NULLABLE: Remove ! when nullable attributes are respected createDirectory(path); +#pragma warning restore CS8634 return path; } diff --git a/src/System.Private.CoreLib/shared/System/Environment.Win32.cs b/src/System.Private.CoreLib/shared/System/Environment.Win32.cs index ca3b48c..d536f5c 100644 --- a/src/System.Private.CoreLib/shared/System/Environment.Win32.cs +++ b/src/System.Private.CoreLib/shared/System/Environment.Win32.cs @@ -80,7 +80,7 @@ namespace System { foreach (string name in environmentKey.GetValueNames()) { - string? value = environmentKey.GetValue(name, "")!.ToString(); // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 + string? value = environmentKey.GetValue(name, "")!.ToString(); // TODO-NULLABLE: Remove ! when nullable attributes are respected try { results.Add(name, value); diff --git a/src/System.Private.CoreLib/shared/System/Environment.cs b/src/System.Private.CoreLib/shared/System/Environment.cs index dd3fc7f..319ae9b 100644 --- a/src/System.Private.CoreLib/shared/System/Environment.cs +++ b/src/System.Private.CoreLib/shared/System/Environment.cs @@ -122,7 +122,7 @@ namespace System { Interlocked.CompareExchange(ref s_osVersion, GetOSVersion(), null); } - return s_osVersion!; // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 + return s_osVersion!; // TODO-NULLABLE: Remove ! when compiler specially-recognizes CompareExchange for nullability } } @@ -149,7 +149,7 @@ namespace System versionSpan = versionSpan.Slice(0, separatorIndex); // Return zeros rather then failing if the version string fails to parse - return Version.TryParse(versionSpan, out Version? version) ? version! : new Version(); // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 + return Version.TryParse(versionSpan, out Version? version) ? version! : new Version(); // TODO-NULLABLE: Remove ! when nullable attributes are respected } } @@ -167,7 +167,7 @@ namespace System { using (currentProcess) { - object? result = processType!.GetMethod("get_WorkingSet64")?.Invoke(currentProcess, BindingFlags.DoNotWrapExceptions, null, null, null); // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/2388 + object? result = processType!.GetMethod("get_WorkingSet64")?.Invoke(currentProcess, BindingFlags.DoNotWrapExceptions, null, null, null); if (result is long) return (long)result; } } diff --git a/src/System.Private.CoreLib/shared/System/Globalization/CalendarData.Unix.cs b/src/System.Private.CoreLib/shared/System/Globalization/CalendarData.Unix.cs index 61924a6..c149570 100644 --- a/src/System.Private.CoreLib/shared/System/Globalization/CalendarData.Unix.cs +++ b/src/System.Private.CoreLib/shared/System/Globalization/CalendarData.Unix.cs @@ -35,7 +35,8 @@ namespace System.Globalization private bool LoadCalendarDataFromSystem(string localeName, CalendarId calendarId) { bool result = true; - // TODO-NULLABLE: these can return null but are later replaced with String.Empty or other non-nullable value + + // these can return null but are later replaced with String.Empty or other non-nullable value result &= GetCalendarInfo(localeName, calendarId, CalendarDataType.NativeName, out this.sNativeName!); result &= GetCalendarInfo(localeName, calendarId, CalendarDataType.MonthDay, out this.sMonthDay!); diff --git a/src/System.Private.CoreLib/shared/System/Globalization/CalendarData.Windows.cs b/src/System.Private.CoreLib/shared/System/Globalization/CalendarData.Windows.cs index f8075d4..bee8ab8 100644 --- a/src/System.Private.CoreLib/shared/System/Globalization/CalendarData.Windows.cs +++ b/src/System.Private.CoreLib/shared/System/Globalization/CalendarData.Windows.cs @@ -100,10 +100,10 @@ namespace System.Globalization // // Clean up the escaping of the formats - this.saShortDates = CultureData.ReescapeWin32Strings(this.saShortDates)!; // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 - this.saLongDates = CultureData.ReescapeWin32Strings(this.saLongDates)!; // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 - this.saYearMonths = CultureData.ReescapeWin32Strings(this.saYearMonths)!; // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 - this.sMonthDay = CultureData.ReescapeWin32String(this.sMonthDay)!; // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 + this.saShortDates = CultureData.ReescapeWin32Strings(this.saShortDates)!; + this.saLongDates = CultureData.ReescapeWin32Strings(this.saLongDates)!; + this.saYearMonths = CultureData.ReescapeWin32Strings(this.saYearMonths)!; + this.sMonthDay = CultureData.ReescapeWin32String(this.sMonthDay)!; return ret; } diff --git a/src/System.Private.CoreLib/shared/System/Globalization/CalendarData.cs b/src/System.Private.CoreLib/shared/System/Globalization/CalendarData.cs index 6ca9e8d..aae2c00 100644 --- a/src/System.Private.CoreLib/shared/System/Globalization/CalendarData.cs +++ b/src/System.Private.CoreLib/shared/System/Globalization/CalendarData.cs @@ -13,10 +13,6 @@ namespace System.Globalization // NOTE: Calendars depend on the locale name that creates it. Only a few // properties are available without locales using CalendarData.GetCalendar(CalendarData) // - // TODO-NULLABLE: this class requires refactoring for proper annotations - // currently from user of this class all fields are non-nullable. - // To avoid potential breaking changes lots of workaround have - // been used to suppress errors internal partial class CalendarData { // Max calendars diff --git a/src/System.Private.CoreLib/shared/System/Globalization/CompareInfo.cs b/src/System.Private.CoreLib/shared/System/Globalization/CompareInfo.cs index 5cf1992..dd4da0d 100644 --- a/src/System.Private.CoreLib/shared/System/Globalization/CompareInfo.cs +++ b/src/System.Private.CoreLib/shared/System/Globalization/CompareInfo.cs @@ -170,8 +170,8 @@ namespace System.Globalization [OnDeserializing] private void OnDeserializing(StreamingContext ctx) { - // TODO-NULLABLE: this becomes null for a brief moment before deserialization - // after serialization is finished it is never null + // this becomes null for a brief moment before deserialization + // after serialization is finished it is never null. m_name = null!; } diff --git a/src/System.Private.CoreLib/shared/System/Globalization/CultureData.Windows.cs b/src/System.Private.CoreLib/shared/System/Globalization/CultureData.Windows.cs index 912fce6..28315b9 100644 --- a/src/System.Private.CoreLib/shared/System/Globalization/CultureData.Windows.cs +++ b/src/System.Private.CoreLib/shared/System/Globalization/CultureData.Windows.cs @@ -4,7 +4,7 @@ using System.Collections.Generic; using System.Diagnostics; -using System.Runtime.CompilerServices; +using System.Diagnostics.CodeAnalysis; using System.Runtime.InteropServices; using System.Text; using Internal.Runtime.CompilerServices; @@ -356,6 +356,7 @@ namespace System.Globalization /// /// We don't build the stringbuilder unless we find something to change /// + [return: NotNullIfNotNull("str")] internal static string? ReescapeWin32String(string? str) { // If we don't have data, then don't try anything @@ -424,13 +425,14 @@ namespace System.Globalization return result.ToString(); } + [return: NotNullIfNotNull("array")] internal static string[]? ReescapeWin32Strings(string[]? array) { if (array != null) { for (int i = 0; i < array.Length; i++) { - array[i] = ReescapeWin32String(array[i])!; // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 + array[i] = ReescapeWin32String(array[i])!; // TODO-NULLABLE: Remove ! when nullable attributes are respected } } diff --git a/src/System.Private.CoreLib/shared/System/Globalization/CultureData.cs b/src/System.Private.CoreLib/shared/System/Globalization/CultureData.cs index a5d2ef6..d29668e 100644 --- a/src/System.Private.CoreLib/shared/System/Globalization/CultureData.cs +++ b/src/System.Private.CoreLib/shared/System/Globalization/CultureData.cs @@ -796,9 +796,9 @@ namespace System.Globalization { case "zh-CHS": case "zh-CHT": - return _sName!; // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/34273 + return _sName; } - return _sRealName!; + return _sRealName; } } diff --git a/src/System.Private.CoreLib/shared/System/Globalization/DateTimeParse.cs b/src/System.Private.CoreLib/shared/System/Globalization/DateTimeParse.cs index 3bc6288..511a440 100644 --- a/src/System.Private.CoreLib/shared/System/Globalization/DateTimeParse.cs +++ b/src/System.Private.CoreLib/shared/System/Globalization/DateTimeParse.cs @@ -191,7 +191,7 @@ namespace System // for (int i = 0; i < formats.Length; i++) { - if (formats[i] == null || formats[i]!.Length == 0) // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/34644 + if (formats[i] == null || formats[i]!.Length == 0) // TODO-NULLABLE: Indexer nullability tracked (https://github.com/dotnet/roslyn/issues/34644) { result.SetBadFormatSpecifierFailure(); return false; diff --git a/src/System.Private.CoreLib/shared/System/Globalization/IdnMapping.Windows.cs b/src/System.Private.CoreLib/shared/System/Globalization/IdnMapping.Windows.cs index 6622e64..6a97c04 100644 --- a/src/System.Private.CoreLib/shared/System/Globalization/IdnMapping.Windows.cs +++ b/src/System.Private.CoreLib/shared/System/Globalization/IdnMapping.Windows.cs @@ -3,6 +3,7 @@ // See the LICENSE file in the project root for more information. using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.Runtime.InteropServices; namespace System.Globalization @@ -114,6 +115,7 @@ namespace System.Globalization } } + [DoesNotReturn] private static void ThrowForZeroLength(bool unicode) { int lastError = Marshal.GetLastWin32Error(); diff --git a/src/System.Private.CoreLib/shared/System/Globalization/JapaneseCalendar.Win32.cs b/src/System.Private.CoreLib/shared/System/Globalization/JapaneseCalendar.Win32.cs index 8e5941f..ffea420 100644 --- a/src/System.Private.CoreLib/shared/System/Globalization/JapaneseCalendar.Win32.cs +++ b/src/System.Private.CoreLib/shared/System/Globalization/JapaneseCalendar.Win32.cs @@ -92,10 +92,10 @@ namespace System.Globalization Array.Resize(ref registryEraRanges, iFoundEras); // Sort them - Array.Sort(registryEraRanges!, CompareEraRanges); // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 + Array.Sort(registryEraRanges!, CompareEraRanges); // TODO-NULLABLE: Remove ! when nullable attributes are respected // Clean up era information - for (int i = 0; i < registryEraRanges!.Length; i++) // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 + for (int i = 0; i < registryEraRanges!.Length; i++) // TODO-NULLABLE: Remove ! when nullable attributes are respected { // eras count backwards from length to 1 (and are 1 based indexes into string arrays) registryEraRanges[i].era = registryEraRanges.Length - i; diff --git a/src/System.Private.CoreLib/shared/System/Globalization/JapaneseLunisolarCalendar.cs b/src/System.Private.CoreLib/shared/System/Globalization/JapaneseLunisolarCalendar.cs index 7190300..cdaded6 100644 --- a/src/System.Private.CoreLib/shared/System/Globalization/JapaneseLunisolarCalendar.cs +++ b/src/System.Private.CoreLib/shared/System/Globalization/JapaneseLunisolarCalendar.cs @@ -201,7 +201,7 @@ namespace System.Globalization // If we didn't copy any then something was wrong, just return base if (newIndex == 0) return baseEras; - Array.Resize(ref newEras!, newIndex); // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 + Array.Resize(ref newEras!, newIndex); // TODO-NULLABLE: Remove ! when nullable attributes are respected return newEras; } diff --git a/src/System.Private.CoreLib/shared/System/Globalization/SortVersion.cs b/src/System.Private.CoreLib/shared/System/Globalization/SortVersion.cs index b76eeb1..89c3fa2 100644 --- a/src/System.Private.CoreLib/shared/System/Globalization/SortVersion.cs +++ b/src/System.Private.CoreLib/shared/System/Globalization/SortVersion.cs @@ -44,7 +44,9 @@ namespace System.Globalization return obj is SortVersion otherVersion && Equals(otherVersion); } +#pragma warning disable CS8614 // TODO-NULLABLE: Covariant interface arguments (https://github.com/dotnet/roslyn/issues/35817) public bool Equals(SortVersion? other) +#pragma warning restore CS8614 { if (other == null) { diff --git a/src/System.Private.CoreLib/shared/System/Globalization/TextElementEnumerator.cs b/src/System.Private.CoreLib/shared/System/Globalization/TextElementEnumerator.cs index d896c7d..5ff3d84 100644 --- a/src/System.Private.CoreLib/shared/System/Globalization/TextElementEnumerator.cs +++ b/src/System.Private.CoreLib/shared/System/Globalization/TextElementEnumerator.cs @@ -50,7 +50,9 @@ namespace System.Globalization return true; } - public object? Current => GetTextElement(); // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/23268 +#pragma warning disable CS8612 // TODO-NULLABLE: Covariant return types (https://github.com/dotnet/roslyn/issues/23268) + public object Current => GetTextElement(); +#pragma warning restore CS8612 public string GetTextElement() { diff --git a/src/System.Private.CoreLib/shared/System/Globalization/TimeSpanParse.cs b/src/System.Private.CoreLib/shared/System/Globalization/TimeSpanParse.cs index 1066561..6b4ea6a 100644 --- a/src/System.Private.CoreLib/shared/System/Globalization/TimeSpanParse.cs +++ b/src/System.Private.CoreLib/shared/System/Globalization/TimeSpanParse.cs @@ -1690,7 +1690,7 @@ namespace System.Globalization // one of the formats. for (int i = 0; i < formats.Length; i++) { - // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/34644 + // TODO-NULLABLE: Indexer nullability tracked (https://github.com/dotnet/roslyn/issues/34644) if (formats[i] == null || formats[i]!.Length == 0) { return result.SetBadFormatSpecifierFailure(); diff --git a/src/System.Private.CoreLib/shared/System/IComparable.cs b/src/System.Private.CoreLib/shared/System/IComparable.cs index 8c4f38e..c87f572 100644 --- a/src/System.Private.CoreLib/shared/System/IComparable.cs +++ b/src/System.Private.CoreLib/shared/System/IComparable.cs @@ -2,6 +2,8 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +using System.Diagnostics.CodeAnalysis; + namespace System { // The IComparable interface is implemented by classes that support an @@ -32,6 +34,6 @@ namespace System // if this is equal to object, or a value greater than zero // if this is greater than object. // - int CompareTo(T other); + int CompareTo([AllowNull] T other); } } diff --git a/src/System.Private.CoreLib/shared/System/IEquatable.cs b/src/System.Private.CoreLib/shared/System/IEquatable.cs index b2c96a9..1182d02 100644 --- a/src/System.Private.CoreLib/shared/System/IEquatable.cs +++ b/src/System.Private.CoreLib/shared/System/IEquatable.cs @@ -2,11 +2,13 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +using System.Diagnostics.CodeAnalysis; + namespace System { public interface IEquatable { - bool Equals(T other); + bool Equals([AllowNull] T other); } } diff --git a/src/System.Private.CoreLib/shared/System/IO/FileStream.Unix.cs b/src/System.Private.CoreLib/shared/System/IO/FileStream.Unix.cs index e3fe604..59cb890 100644 --- a/src/System.Private.CoreLib/shared/System/IO/FileStream.Unix.cs +++ b/src/System.Private.CoreLib/shared/System/IO/FileStream.Unix.cs @@ -290,7 +290,7 @@ namespace System.IO // override may already exist on a derived type. if (_useAsyncIO && _writePos > 0) { - return new ValueTask(Task.Factory.StartNew(s => ((FileStream)s!).Dispose(), this, // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 + return new ValueTask(Task.Factory.StartNew(s => ((FileStream)s!).Dispose(), this, CancellationToken.None, TaskCreationOptions.DenyChildAttach, TaskScheduler.Default)); } @@ -364,7 +364,7 @@ namespace System.IO if (CanWrite) { return Task.Factory.StartNew( - state => ((FileStream)state!).FlushOSBuffer(), // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 + state => ((FileStream)state!).FlushOSBuffer(), this, cancellationToken, TaskCreationOptions.DenyChildAttach, @@ -568,7 +568,7 @@ namespace System.IO // whereas on Windows it may happen before the write has completed. Debug.Assert(t.Status == TaskStatus.RanToCompletion); - var thisRef = (FileStream)s!; // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 + var thisRef = (FileStream)s!; Debug.Assert(thisRef._asyncState != null); try { @@ -727,7 +727,7 @@ namespace System.IO // whereas on Windows it may happen before the write has completed. Debug.Assert(t.Status == TaskStatus.RanToCompletion); - var thisRef = (FileStream)s!; // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 + var thisRef = (FileStream)s!; Debug.Assert(thisRef._asyncState != null); try { diff --git a/src/System.Private.CoreLib/shared/System/IO/FileStream.Windows.cs b/src/System.Private.CoreLib/shared/System/IO/FileStream.Windows.cs index bfab0c1..be48833 100644 --- a/src/System.Private.CoreLib/shared/System/IO/FileStream.Windows.cs +++ b/src/System.Private.CoreLib/shared/System/IO/FileStream.Windows.cs @@ -1587,7 +1587,7 @@ namespace System.IO if (CanWrite) { return Task.Factory.StartNew( - state => ((FileStream)state!).FlushOSBuffer(), // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 + state => ((FileStream)state!).FlushOSBuffer(), this, cancellationToken, TaskCreationOptions.DenyChildAttach, diff --git a/src/System.Private.CoreLib/shared/System/IO/MemoryStream.cs b/src/System.Private.CoreLib/shared/System/IO/MemoryStream.cs index b8a11d9..11a41f7 100644 --- a/src/System.Private.CoreLib/shared/System/IO/MemoryStream.cs +++ b/src/System.Private.CoreLib/shared/System/IO/MemoryStream.cs @@ -451,7 +451,7 @@ namespace System.IO // it then fall back to doing the ArrayPool/copy behavior. return new ValueTask( MemoryMarshal.TryGetArray(buffer, out ArraySegment destinationArray) ? - Read(destinationArray.Array!, destinationArray.Offset, destinationArray.Count) : // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 + Read(destinationArray.Array!, destinationArray.Offset, destinationArray.Count) : Read(buffer.Span)); } catch (OperationCanceledException oce) @@ -766,7 +766,7 @@ namespace System.IO // Unlike ReadAsync, we could delegate to WriteAsync(byte[], ...) here, but we don't for consistency. if (MemoryMarshal.TryGetArray(buffer, out ArraySegment sourceArray)) { - Write(sourceArray.Array!, sourceArray.Offset, sourceArray.Count); // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 + Write(sourceArray.Array!, sourceArray.Offset, sourceArray.Count); } else { diff --git a/src/System.Private.CoreLib/shared/System/IO/Path.cs b/src/System.Private.CoreLib/shared/System/IO/Path.cs index 674cc6e..b0c3df3 100644 --- a/src/System.Private.CoreLib/shared/System/IO/Path.cs +++ b/src/System.Private.CoreLib/shared/System/IO/Path.cs @@ -4,6 +4,7 @@ #nullable enable using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.Runtime.InteropServices; using System.Text; @@ -46,7 +47,8 @@ namespace System.IO // returns null. If path does not contain a file extension, // the new file extension is appended to the path. If extension // is null, any existing extension is removed from path. - public static string? ChangeExtension(string? path, string? extension) // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 + [return: NotNullIfNotNull("path")] + public static string? ChangeExtension(string? path, string? extension) { if (path == null) return null; @@ -99,7 +101,7 @@ namespace System.IO /// /// Directory separators are normalized in the returned string. /// - public static string? GetDirectoryName(string? path) // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 + public static string? GetDirectoryName(string? path) { if (path == null || PathInternal.IsEffectivelyEmpty(path.AsSpan())) return null; @@ -147,7 +149,8 @@ namespace System.IO /// The returned value is null if the given path is null or empty if the given path does not include an /// extension. /// - public static string? GetExtension(string? path) // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 + [return: NotNullIfNotNull("path")] + public static string? GetExtension(string? path) { if (path == null) return null; @@ -186,6 +189,7 @@ namespace System.IO /// the characters of path that follow the last separator in path. The resulting string is /// null if path is null. /// + [return: NotNullIfNotNull("path")] public static string? GetFileName(string? path) { if (path == null) @@ -217,7 +221,8 @@ namespace System.IO return path; } - public static string? GetFileNameWithoutExtension(string? path) // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 + [return: NotNullIfNotNull("path")] + public static string? GetFileNameWithoutExtension(string? path) { if (path == null) return null; diff --git a/src/System.Private.CoreLib/shared/System/IO/PathInternal.Windows.cs b/src/System.Private.CoreLib/shared/System/IO/PathInternal.Windows.cs index 40ed96f..8247465 100644 --- a/src/System.Private.CoreLib/shared/System/IO/PathInternal.Windows.cs +++ b/src/System.Private.CoreLib/shared/System/IO/PathInternal.Windows.cs @@ -3,6 +3,7 @@ // See the LICENSE file in the project root for more information. #nullable enable +using System.Diagnostics.CodeAnalysis; using System.Runtime.CompilerServices; using System.Text; @@ -87,6 +88,7 @@ namespace System.IO /// away from paths during normalization, but if we see such a path at this point it should be /// normalized and has retained the final characters. (Typically from one of the *Info classes) /// + [return: NotNullIfNotNull("path")] internal static string? EnsureExtendedPrefixIfNeeded(string? path) { if (path != null && (path.Length >= MaxShortPath || EndsWithPeriodOrSpace(path))) diff --git a/src/System.Private.CoreLib/shared/System/IO/Stream.cs b/src/System.Private.CoreLib/shared/System/IO/Stream.cs index e6288cb..51cc816 100644 --- a/src/System.Private.CoreLib/shared/System/IO/Stream.cs +++ b/src/System.Private.CoreLib/shared/System/IO/Stream.cs @@ -42,7 +42,11 @@ namespace System.IO { // Lazily-initialize _asyncActiveSemaphore. As we're never accessing the SemaphoreSlim's // WaitHandle, we don't need to worry about Disposing it. - return LazyInitializer.EnsureInitialized(ref _asyncActiveSemaphore!, () => new SemaphoreSlim(1, 1)); // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 +#pragma warning disable CS8634 // TODO-NULLABLE: Remove warning disable when nullable attributes are respected +#pragma warning disable CS8603 // TODO-NULLABLE: Remove warning disable when nullable attributes are respected + return LazyInitializer.EnsureInitialized(ref _asyncActiveSemaphore, () => new SemaphoreSlim(1, 1)); +#pragma warning restore CS8603 +#pragma warning restore CS8634 } public abstract bool CanRead @@ -255,7 +259,7 @@ namespace System.IO public virtual Task FlushAsync(CancellationToken cancellationToken) { - return Task.Factory.StartNew(state => ((Stream)state!).Flush(), this, // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 + return Task.Factory.StartNew(state => ((Stream)state!).Flush(), this, cancellationToken, TaskCreationOptions.DenyChildAttach, TaskScheduler.Default); } @@ -380,7 +384,7 @@ namespace System.IO { if (MemoryMarshal.TryGetArray(buffer, out ArraySegment array)) { - return new ValueTask(ReadAsync(array.Array!, array.Offset, array.Count, cancellationToken)); // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 + return new ValueTask(ReadAsync(array.Array!, array.Offset, array.Count, cancellationToken)); } else { @@ -511,7 +515,7 @@ namespace System.IO asyncWaiter.ContinueWith((t, state) => { Debug.Assert(t.IsCompletedSuccessfully, "The semaphore wait should always complete successfully."); - var rwt = (ReadWriteTask)state!; // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 + var rwt = (ReadWriteTask)state!; Debug.Assert(rwt._stream != null); rwt._stream.RunReadWriteTask(rwt); // RunReadWriteTask(readWriteTask); }, readWriteTask, default, TaskContinuationOptions.ExecuteSynchronously, TaskScheduler.Default); @@ -691,7 +695,7 @@ namespace System.IO { if (MemoryMarshal.TryGetArray(buffer, out ArraySegment array)) { - return new ValueTask(WriteAsync(array.Array!, array.Offset, array.Count, cancellationToken)); // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 + return new ValueTask(WriteAsync(array.Array!, array.Offset, array.Count, cancellationToken)); } else { @@ -1061,7 +1065,7 @@ namespace System.IO { get { - return LazyInitializer.EnsureInitialized(ref _waitHandle!, () => new ManualResetEvent(true)); // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 + return LazyInitializer.EnsureInitialized(ref _waitHandle!, () => new ManualResetEvent(true)); // Remove ! when nullable attributes are respected } } diff --git a/src/System.Private.CoreLib/shared/System/IO/StreamReader.cs b/src/System.Private.CoreLib/shared/System/IO/StreamReader.cs index a59ac58..0ebcede 100644 --- a/src/System.Private.CoreLib/shared/System/IO/StreamReader.cs +++ b/src/System.Private.CoreLib/shared/System/IO/StreamReader.cs @@ -84,6 +84,7 @@ namespace System.IO } } + [DoesNotReturn] private static void ThrowAsyncIOInProgress() => throw new InvalidOperationException(SR.InvalidOperation_AsyncIOInProgress); diff --git a/src/System.Private.CoreLib/shared/System/IO/StreamWriter.cs b/src/System.Private.CoreLib/shared/System/IO/StreamWriter.cs index 87557e8..9d143ed 100644 --- a/src/System.Private.CoreLib/shared/System/IO/StreamWriter.cs +++ b/src/System.Private.CoreLib/shared/System/IO/StreamWriter.cs @@ -3,6 +3,7 @@ // See the LICENSE file in the project root for more information. using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Text; @@ -56,6 +57,7 @@ namespace System.IO } } + [DoesNotReturn] private static void ThrowAsyncIOInProgress() => throw new InvalidOperationException(SR.InvalidOperation_AsyncIOInProgress); diff --git a/src/System.Private.CoreLib/shared/System/IO/TextReader.cs b/src/System.Private.CoreLib/shared/System/IO/TextReader.cs index a49463f..5afc919 100644 --- a/src/System.Private.CoreLib/shared/System/IO/TextReader.cs +++ b/src/System.Private.CoreLib/shared/System/IO/TextReader.cs @@ -209,7 +209,7 @@ namespace System.IO { return Task.Factory.StartNew(state => { - return ((TextReader)state!).ReadLine(); // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 + return ((TextReader)state!).ReadLine(); }, this, CancellationToken.None, TaskCreationOptions.DenyChildAttach, TaskScheduler.Default); } @@ -253,10 +253,10 @@ namespace System.IO public virtual ValueTask ReadAsync(Memory buffer, CancellationToken cancellationToken = default) => new ValueTask(MemoryMarshal.TryGetArray(buffer, out ArraySegment array) ? - ReadAsync(array.Array!, array.Offset, array.Count) : // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 + ReadAsync(array.Array!, array.Offset, array.Count) : Task.Factory.StartNew(state => { - var t = (Tuple>)state!; // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 + var t = (Tuple>)state!; return t.Item1.Read(t.Item2.Span); }, Tuple.Create(this, buffer), cancellationToken, TaskCreationOptions.DenyChildAttach, TaskScheduler.Default)); @@ -265,7 +265,7 @@ namespace System.IO var tuple = new Tuple>(this, buffer); return new ValueTask(Task.Factory.StartNew(state => { - var t = (Tuple>)state!; // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 + var t = (Tuple>)state!; return t.Item1.Read(t.Item2.Span); }, tuple, cancellationToken, TaskCreationOptions.DenyChildAttach, TaskScheduler.Default)); @@ -291,10 +291,10 @@ namespace System.IO public virtual ValueTask ReadBlockAsync(Memory buffer, CancellationToken cancellationToken = default) => new ValueTask(MemoryMarshal.TryGetArray(buffer, out ArraySegment array) ? - ReadBlockAsync(array.Array!, array.Offset, array.Count) : // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 + ReadBlockAsync(array.Array!, array.Offset, array.Count) : Task.Factory.StartNew(state => { - var t = (Tuple>)state!; // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 + var t = (Tuple>)state!; return t.Item1.ReadBlock(t.Item2.Span); }, Tuple.Create(this, buffer), cancellationToken, TaskCreationOptions.DenyChildAttach, TaskScheduler.Default)); diff --git a/src/System.Private.CoreLib/shared/System/IO/TextWriter.cs b/src/System.Private.CoreLib/shared/System/IO/TextWriter.cs index 890c35e..9dfb140 100644 --- a/src/System.Private.CoreLib/shared/System/IO/TextWriter.cs +++ b/src/System.Private.CoreLib/shared/System/IO/TextWriter.cs @@ -9,6 +9,7 @@ using System.Threading.Tasks; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Buffers; +using System.Diagnostics.CodeAnalysis; namespace System.IO { @@ -117,7 +118,8 @@ namespace System.IO /// the TextWriter to be readable by a TextReader, only one of the following line /// terminator strings should be used: "\r", "\n", or "\r\n". /// - public virtual string? NewLine // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/2384 + [AllowNull] + public virtual string NewLine { get { return CoreNewLineStr; } set @@ -545,7 +547,7 @@ namespace System.IO var tuple = new Tuple(this, value); return Task.Factory.StartNew(state => { - var t = (Tuple)state!; // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 + var t = (Tuple)state!; t.Item1.Write(t.Item2); }, tuple, CancellationToken.None, TaskCreationOptions.DenyChildAttach, TaskScheduler.Default); @@ -556,7 +558,7 @@ namespace System.IO var tuple = new Tuple(this, value); return Task.Factory.StartNew(state => { - var t = (Tuple)state!; // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 + var t = (Tuple)state!; t.Item1.Write(t.Item2); }, tuple, CancellationToken.None, TaskCreationOptions.DenyChildAttach, TaskScheduler.Default); @@ -598,7 +600,7 @@ namespace System.IO var tuple = new Tuple(this, buffer, index, count); return Task.Factory.StartNew(state => { - var t = (Tuple)state!; // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 + var t = (Tuple)state!; t.Item1.Write(t.Item2, t.Item3, t.Item4); }, tuple, CancellationToken.None, TaskCreationOptions.DenyChildAttach, TaskScheduler.Default); @@ -606,11 +608,11 @@ namespace System.IO public virtual Task WriteAsync(ReadOnlyMemory buffer, CancellationToken cancellationToken = default) => cancellationToken.IsCancellationRequested ? Task.FromCanceled(cancellationToken) : - MemoryMarshal.TryGetArray(buffer, out ArraySegment array) ? // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 + MemoryMarshal.TryGetArray(buffer, out ArraySegment array) ? WriteAsync(array.Array!, array.Offset, array.Count) : Task.Factory.StartNew(state => { - var t = (Tuple>)state!; // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 + var t = (Tuple>)state!; t.Item1.Write(t.Item2.Span); }, Tuple.Create(this, buffer), cancellationToken, TaskCreationOptions.DenyChildAttach, TaskScheduler.Default); @@ -619,7 +621,7 @@ namespace System.IO var tuple = new Tuple(this, value); return Task.Factory.StartNew(state => { - var t = (Tuple)state!; // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 + var t = (Tuple)state!; t.Item1.WriteLine(t.Item2); }, tuple, CancellationToken.None, TaskCreationOptions.DenyChildAttach, TaskScheduler.Default); @@ -630,7 +632,7 @@ namespace System.IO var tuple = new Tuple(this, value); return Task.Factory.StartNew(state => { - var t = (Tuple)state!; // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 + var t = (Tuple)state!; t.Item1.WriteLine(t.Item2); }, tuple, CancellationToken.None, TaskCreationOptions.DenyChildAttach, TaskScheduler.Default); @@ -673,7 +675,7 @@ namespace System.IO var tuple = new Tuple(this, buffer, index, count); return Task.Factory.StartNew(state => { - var t = (Tuple)state!; // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 + var t = (Tuple)state!; t.Item1.WriteLine(t.Item2, t.Item3, t.Item4); }, tuple, CancellationToken.None, TaskCreationOptions.DenyChildAttach, TaskScheduler.Default); @@ -681,11 +683,11 @@ namespace System.IO public virtual Task WriteLineAsync(ReadOnlyMemory buffer, CancellationToken cancellationToken = default) => cancellationToken.IsCancellationRequested ? Task.FromCanceled(cancellationToken) : - MemoryMarshal.TryGetArray(buffer, out ArraySegment array) ? // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 + MemoryMarshal.TryGetArray(buffer, out ArraySegment array) ? WriteLineAsync(array.Array!, array.Offset, array.Count) : Task.Factory.StartNew(state => { - var t = (Tuple>)state!; // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 + var t = (Tuple>)state!; t.Item1.WriteLine(t.Item2.Span); }, Tuple.Create(this, buffer), cancellationToken, TaskCreationOptions.DenyChildAttach, TaskScheduler.Default); @@ -698,7 +700,7 @@ namespace System.IO { return Task.Factory.StartNew(state => { - ((TextWriter)state!).Flush(); // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 + ((TextWriter)state!).Flush(); }, this, CancellationToken.None, TaskCreationOptions.DenyChildAttach, TaskScheduler.Default); } @@ -766,7 +768,8 @@ namespace System.IO public override IFormatProvider FormatProvider => _out.FormatProvider; - public override string? NewLine + [AllowNull] + public override string NewLine { [MethodImpl(MethodImplOptions.Synchronized)] get { return _out.NewLine; } diff --git a/src/System.Private.CoreLib/shared/System/IO/UnmanagedMemoryStream.cs b/src/System.Private.CoreLib/shared/System/IO/UnmanagedMemoryStream.cs index eeaed0a..e6f67bc 100644 --- a/src/System.Private.CoreLib/shared/System/IO/UnmanagedMemoryStream.cs +++ b/src/System.Private.CoreLib/shared/System/IO/UnmanagedMemoryStream.cs @@ -511,7 +511,7 @@ namespace System.IO // it then fall back to doing the ArrayPool/copy behavior. return new ValueTask( MemoryMarshal.TryGetArray(buffer, out ArraySegment destinationArray) ? - Read(destinationArray.Array!, destinationArray.Offset, destinationArray.Count) : // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 + Read(destinationArray.Array!, destinationArray.Offset, destinationArray.Count) : Read(buffer.Span)); } catch (Exception ex) @@ -796,7 +796,7 @@ namespace System.IO // Unlike ReadAsync, we could delegate to WriteAsync(byte[], ...) here, but we don't for consistency. if (MemoryMarshal.TryGetArray(buffer, out ArraySegment sourceArray)) { - Write(sourceArray.Array!, sourceArray.Offset, sourceArray.Count); // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 + Write(sourceArray.Array!, sourceArray.Offset, sourceArray.Count); } else { diff --git a/src/System.Private.CoreLib/shared/System/Lazy.cs b/src/System.Private.CoreLib/shared/System/Lazy.cs index 5bd3a9a..b341136 100644 --- a/src/System.Private.CoreLib/shared/System/Lazy.cs +++ b/src/System.Private.CoreLib/shared/System/Lazy.cs @@ -11,6 +11,7 @@ // =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.Runtime.ExceptionServices; using System.Threading; @@ -87,6 +88,7 @@ namespace System _exceptionDispatch = ExceptionDispatchInfo.Capture(exception); } + [DoesNotReturn] internal void ThrowException() { Debug.Assert(_exceptionDispatch != null, "execution path is invalid"); @@ -192,7 +194,7 @@ namespace System private Func? _factory; // _value eventually stores the lazily created value. It is valid when _state = null. - private T _value = default!; // TODO-NULLABLE-GENERIC + private T _value = default!; /// /// Initializes a new instance of the class that @@ -444,13 +446,14 @@ namespace System } /// Gets the value of the Lazy<T> for debugging display purposes. + [MaybeNull] internal T ValueForDebugDisplay { get { if (!IsValueCreated) { - return default!; // TODO-NULLABLE-GENERIC + return default!; } return _value; } diff --git a/src/System.Private.CoreLib/shared/System/Math.cs b/src/System.Private.CoreLib/shared/System/Math.cs index ac9be48..014589c 100644 --- a/src/System.Private.CoreLib/shared/System/Math.cs +++ b/src/System.Private.CoreLib/shared/System/Math.cs @@ -14,6 +14,7 @@ //This class contains only static members and doesn't require serialization. using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.Runtime; using System.Runtime.CompilerServices; using System.Runtime.Versioning; @@ -99,6 +100,7 @@ namespace System return decimal.Abs(value); } + [DoesNotReturn] [StackTraceHidden] private static void ThrowAbsOverflow() { @@ -984,6 +986,7 @@ namespace System return d; } + [DoesNotReturn] private static void ThrowMinMaxException(T min, T max) { throw new ArgumentException(SR.Format(SR.Argument_MinMaxValue, min, max)); diff --git a/src/System.Private.CoreLib/shared/System/Memory.cs b/src/System.Private.CoreLib/shared/System/Memory.cs index 54f0147..6d63973 100644 --- a/src/System.Private.CoreLib/shared/System/Memory.cs +++ b/src/System.Private.CoreLib/shared/System/Memory.cs @@ -54,7 +54,7 @@ namespace System this = default; return; // returns default } - if (default(T)! == null && array.GetType() != typeof(T[])) // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/34757 + if (default(T)! == null && array.GetType() != typeof(T[])) // TODO-NULLABLE: default(T) == null warning (https://github.com/dotnet/roslyn/issues/34757) ThrowHelper.ThrowArrayTypeMismatchException(); _object = array; @@ -72,7 +72,7 @@ namespace System this = default; return; // returns default } - if (default(T)! == null && array.GetType() != typeof(T[])) // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/34757 + if (default(T)! == null && array.GetType() != typeof(T[])) // TODO-NULLABLE: default(T) == null warning (https://github.com/dotnet/roslyn/issues/34757) ThrowHelper.ThrowArrayTypeMismatchException(); if ((uint)start > (uint)array.Length) ThrowHelper.ThrowArgumentOutOfRangeException(); @@ -104,7 +104,7 @@ namespace System this = default; return; // returns default } - if (default(T)! == null && array.GetType() != typeof(T[])) // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/34757 + if (default(T)! == null && array.GetType() != typeof(T[])) // TODO-NULLABLE: default(T) == null warning (https://github.com/dotnet/roslyn/issues/34757) ThrowHelper.ThrowArrayTypeMismatchException(); #if BIT64 // See comment in Span.Slice for how this works. diff --git a/src/System.Private.CoreLib/shared/System/MemoryExtensions.Fast.cs b/src/System.Private.CoreLib/shared/System/MemoryExtensions.Fast.cs index 4af4937..6de285d 100644 --- a/src/System.Private.CoreLib/shared/System/MemoryExtensions.Fast.cs +++ b/src/System.Private.CoreLib/shared/System/MemoryExtensions.Fast.cs @@ -237,7 +237,7 @@ namespace System if (GlobalizationMode.Invariant) TextInfo.ToLowerAsciiInvariant(source, destination); else - culture!.TextInfo.ChangeCaseToLower(source, destination); // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 + culture!.TextInfo.ChangeCaseToLower(source, destination); // TODO-NULLABLE: Remove ! when [DoesNotReturn] respected return source.Length; } @@ -288,7 +288,7 @@ namespace System if (GlobalizationMode.Invariant) TextInfo.ToUpperAsciiInvariant(source, destination); else - culture!.TextInfo.ChangeCaseToUpper(source, destination); // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 + culture!.TextInfo.ChangeCaseToUpper(source, destination); // TODO-NULLABLE: Remove ! when [DoesNotReturn] respected return source.Length; } @@ -392,7 +392,7 @@ namespace System ThrowHelper.ThrowArgumentOutOfRangeException(); return default; } - if (default(T)! == null && array.GetType() != typeof(T[])) // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/34757 + if (default(T)! == null && array.GetType() != typeof(T[])) // TODO-NULLABLE: default(T) == null warning (https://github.com/dotnet/roslyn/issues/34757) ThrowHelper.ThrowArrayTypeMismatchException(); if ((uint)start > (uint)array.Length) ThrowHelper.ThrowArgumentOutOfRangeException(); @@ -414,7 +414,7 @@ namespace System return default; } - if (default(T)! == null && array.GetType() != typeof(T[])) // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/34757 + if (default(T)! == null && array.GetType() != typeof(T[])) // TODO-NULLABLE: default(T) == null warning (https://github.com/dotnet/roslyn/issues/34757) ThrowHelper.ThrowArrayTypeMismatchException(); int actualIndex = startIndex.GetOffset(array.Length); @@ -441,7 +441,7 @@ namespace System return default; } - if (default(T)! == null && array.GetType() != typeof(T[])) // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/34757 + if (default(T)! == null && array.GetType() != typeof(T[])) // TODO-NULLABLE: default(T) == null warning (https://github.com/dotnet/roslyn/issues/34757) ThrowHelper.ThrowArrayTypeMismatchException(); (int start, int length) = range.GetOffsetAndLength(array.Length); diff --git a/src/System.Private.CoreLib/shared/System/Number.Parsing.cs b/src/System.Private.CoreLib/shared/System/Number.Parsing.cs index e304e4d..c5369d1 100644 --- a/src/System.Private.CoreLib/shared/System/Number.Parsing.cs +++ b/src/System.Private.CoreLib/shared/System/Number.Parsing.cs @@ -3,6 +3,7 @@ // See the LICENSE file in the project root for more information. using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; @@ -1926,8 +1927,10 @@ namespace System Overflow } + [DoesNotReturn] internal static void ThrowOverflowOrFormatException(ParsingStatus status, TypeCode type = 0) => throw GetException(status, type); + [DoesNotReturn] internal static void ThrowOverflowException(TypeCode type) => throw GetException(ParsingStatus.Overflow, type); private static Exception GetException(ParsingStatus status, TypeCode type) diff --git a/src/System.Private.CoreLib/shared/System/Numerics/Vector.cs b/src/System.Private.CoreLib/shared/System/Numerics/Vector.cs index 92b16a4..b49d8b1 100644 --- a/src/System.Private.CoreLib/shared/System/Numerics/Vector.cs +++ b/src/System.Private.CoreLib/shared/System/Numerics/Vector.cs @@ -6,6 +6,7 @@ #if netcoreapp using Internal.Runtime.CompilerServices; #endif +using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.Numerics.Hashing; using System.Runtime.CompilerServices; @@ -5351,6 +5352,7 @@ namespace System.Numerics #endregion Same-Size Conversion #region Throw Helpers + [DoesNotReturn] internal static void ThrowInsufficientNumberOfElementsException(int requiredElementCount) { throw new IndexOutOfRangeException(SR.Format(SR.Arg_InsufficientNumberOfElements, requiredElementCount, "values")); diff --git a/src/System.Private.CoreLib/shared/System/Numerics/Vector.tt b/src/System.Private.CoreLib/shared/System/Numerics/Vector.tt index ac64bac..ed2b606 100644 --- a/src/System.Private.CoreLib/shared/System/Numerics/Vector.tt +++ b/src/System.Private.CoreLib/shared/System/Numerics/Vector.tt @@ -1890,6 +1890,7 @@ namespace System.Numerics #endregion Same-Size Conversion #region Throw Helpers + [DoesNotReturn] internal static void ThrowInsufficientNumberOfElementsException(int requiredElementCount) { throw new IndexOutOfRangeException(SR.Format(SR.Arg_InsufficientNumberOfElements, requiredElementCount, "values")); diff --git a/src/System.Private.CoreLib/shared/System/Reflection/SignatureType.cs b/src/System.Private.CoreLib/shared/System/Reflection/SignatureType.cs index 298ca51..d5674bc 100644 --- a/src/System.Private.CoreLib/shared/System/Reflection/SignatureType.cs +++ b/src/System.Private.CoreLib/shared/System/Reflection/SignatureType.cs @@ -76,7 +76,7 @@ namespace System.Reflection public sealed override Assembly Assembly => throw new NotSupportedException(SR.NotSupported_SignatureType); public sealed override Module Module => throw new NotSupportedException(SR.NotSupported_SignatureType); -#pragma warning disable CS8608 // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/23268 +#pragma warning disable CS8608 // TODO-NULLABLE: Covariant return types (https://github.com/dotnet/roslyn/issues/23268) public sealed override Type ReflectedType => throw new NotSupportedException(SR.NotSupported_SignatureType); public sealed override Type BaseType => throw new NotSupportedException(SR.NotSupported_SignatureType); #pragma warning restore CS8608 @@ -86,7 +86,7 @@ namespace System.Reflection public sealed override int MetadataToken => throw new NotSupportedException(SR.NotSupported_SignatureType); public sealed override bool HasSameMetadataDefinitionAs(MemberInfo other) => throw new NotSupportedException(SR.NotSupported_SignatureType); -#pragma warning disable CS8608 // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/23268 +#pragma warning disable CS8608 // TODO-NULLABLE: Covariant return types (https://github.com/dotnet/roslyn/issues/23268) public sealed override Type DeclaringType => throw new NotSupportedException(SR.NotSupported_SignatureType); public sealed override MethodBase DeclaringMethod => throw new NotSupportedException(SR.NotSupported_SignatureType); #pragma warning restore CS8608 @@ -143,7 +143,7 @@ namespace System.Reflection public sealed override bool IsSubclassOf(Type c) => throw new NotSupportedException(SR.NotSupported_SignatureType); protected sealed override bool IsValueTypeImpl() => throw new NotSupportedException(SR.NotSupported_SignatureType); -#pragma warning disable CS8608 // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/23268 +#pragma warning disable CS8608 // TODO-NULLABLE: Covariant return types (https://github.com/dotnet/roslyn/issues/23268) public sealed override StructLayoutAttribute StructLayoutAttribute => throw new NotSupportedException(SR.NotSupported_SignatureType); #pragma warning restore CS8608 diff --git a/src/System.Private.CoreLib/shared/System/Resources/FastResourceComparer.cs b/src/System.Private.CoreLib/shared/System/Resources/FastResourceComparer.cs index 16c9fd0..31a8fd6 100644 --- a/src/System.Private.CoreLib/shared/System/Resources/FastResourceComparer.cs +++ b/src/System.Private.CoreLib/shared/System/Resources/FastResourceComparer.cs @@ -18,10 +18,11 @@ using System.Collections; using System.Collections.Generic; using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; namespace System.Resources { - internal sealed class FastResourceComparer : IComparer, IEqualityComparer, IComparer, IEqualityComparer // TODO-NULLABLE: IEqualityComparer.GetHashCode does not accept nulls but Equals does + internal sealed class FastResourceComparer : IComparer, IEqualityComparer, IComparer, IEqualityComparer { internal static readonly FastResourceComparer Default = new FastResourceComparer(); @@ -32,10 +33,9 @@ namespace System.Resources return FastResourceComparer.HashFunction(s); } - public int GetHashCode(string? key) // TODO-NULLABLE: argument should be non-nullable but IEqualityComparer.Equals accepts null + public int GetHashCode([DisallowNull] string? key) { - Debug.Assert(key != null, "TODO-NULLABLE"); - return FastResourceComparer.HashFunction(key); + return FastResourceComparer.HashFunction(key!); } // This hash function MUST be publically documented with the resource diff --git a/src/System.Private.CoreLib/shared/System/Resources/ResourceManager.cs b/src/System.Private.CoreLib/shared/System/Resources/ResourceManager.cs index 6dcb475..3de4b31 100644 --- a/src/System.Private.CoreLib/shared/System/Resources/ResourceManager.cs +++ b/src/System.Private.CoreLib/shared/System/Resources/ResourceManager.cs @@ -303,7 +303,7 @@ namespace System.Resources lock (localResourceSets) { -#pragma warning disable CS8619 // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/35131 +#pragma warning disable CS8619 // TODO-NULLABLE: Deconstruct KeyValuePair (https://github.com/dotnet/roslyn/issues/35131) foreach ((_, ResourceSet resourceSet) in localResourceSets) #pragma warning restore CS8619 { @@ -489,7 +489,7 @@ namespace System.Resources // that had resources. foreach (CultureInfo updateCultureInfo in mgr) { - AddResourceSet(localResourceSets, updateCultureInfo.Name, ref rs!); // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/34874 + AddResourceSet(localResourceSets, updateCultureInfo.Name, ref rs!); // TODO-NULLABLE: Pass non-null string? to string ref (https://github.com/dotnet/roslyn/issues/34874) // stop when we've added current or reached invariant (top of chain) if (updateCultureInfo == foundCulture) diff --git a/src/System.Private.CoreLib/shared/System/Resources/ResourceReader.Core.cs b/src/System.Private.CoreLib/shared/System/Resources/ResourceReader.Core.cs index 86e543b..94f7f62 100644 --- a/src/System.Private.CoreLib/shared/System/Resources/ResourceReader.Core.cs +++ b/src/System.Private.CoreLib/shared/System/Resources/ResourceReader.Core.cs @@ -67,6 +67,7 @@ namespace System.Resources private void InitializeBinaryFormatter() { +#pragma warning disable CS8634 // TODO-NULLABLE: Remove warning disable when nullable attributes are respected LazyInitializer.EnsureInitialized(ref s_binaryFormatterType, () => Type.GetType("System.Runtime.Serialization.Formatters.Binary.BinaryFormatter, System.Runtime.Serialization.Formatters, Version=0.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a", throwOnError: true)); @@ -81,6 +82,7 @@ namespace System.Resources .MakeGenericMethod(s_binaryFormatterType)! .Invoke(null, new object[] { binaryFormatterDeserialize })!; }); +#pragma warning restore CS8634 _binaryFormatter = Activator.CreateInstance(s_binaryFormatterType!)!; } diff --git a/src/System.Private.CoreLib/shared/System/Resources/ResourceReader.cs b/src/System.Private.CoreLib/shared/System/Resources/ResourceReader.cs index 4b28092..e83f166 100644 --- a/src/System.Private.CoreLib/shared/System/Resources/ResourceReader.cs +++ b/src/System.Private.CoreLib/shared/System/Resources/ResourceReader.cs @@ -161,11 +161,11 @@ namespace System.Resources // Close the stream in a thread-safe way. This fix means // that we may call Close n times, but that's safe. BinaryReader copyOfStore = _store; - _store = null!; // TODO-NULLABLE: dispose should not null this out + _store = null!; // TODO-NULLABLE: Avoid nulling out in Dispose if (copyOfStore != null) copyOfStore.Close(); } - _store = null!; // TODO-NULLABLE: dispose should not null this out + _store = null!; // TODO-NULLABLE: Avoid nulling out in Dispose _namePositions = null; _nameHashes = null; _ums = null; @@ -960,7 +960,7 @@ namespace System.Resources } } Debug.Assert(_typeTable[typeIndex] != null, "Should have found a type!"); - return _typeTable[typeIndex]!; // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/34644 + return _typeTable[typeIndex]!; // TODO-NULLABLE: Indexer nullability tracked (https://github.com/dotnet/roslyn/issues/34644) } private string TypeNameFromTypeCode(ResourceTypeCode typeCode) @@ -1030,22 +1030,12 @@ namespace System.Resources } } - public object? Current // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/23268 - { - get - { - return Entry; - } - } +#pragma warning disable CS8612 // TODO-NULLABLE: Covariant return types (https://github.com/dotnet/roslyn/issues/23268) + public object Current => Entry; +#pragma warning restore CS8612 // Warning: This requires that you call the Key or Entry property FIRST before calling it! - internal int DataPosition - { - get - { - return _dataPosition; - } - } + internal int DataPosition => _dataPosition; public DictionaryEntry Entry { diff --git a/src/System.Private.CoreLib/shared/System/Resources/ResourceSet.cs b/src/System.Private.CoreLib/shared/System/Resources/ResourceSet.cs index 936e43c..4f5edf8 100644 --- a/src/System.Private.CoreLib/shared/System/Resources/ResourceSet.cs +++ b/src/System.Private.CoreLib/shared/System/Resources/ResourceSet.cs @@ -29,7 +29,7 @@ namespace System.Resources public class ResourceSet : IDisposable, IEnumerable { protected IResourceReader Reader = null!; - internal Hashtable? Table; // TODO-NULLABLE: should not be nulled out in Dispose + internal Hashtable? Table; // TODO-NULLABLE: Avoid nulling out in Dispose private Hashtable? _caseInsensitiveTable; // For case-insensitive lookups. @@ -92,11 +92,11 @@ namespace System.Resources { // Close the Reader in a thread-safe way. IResourceReader? copyOfReader = Reader; - Reader = null!; // TODO-NULLABLE: should not be nulled out in the Dispose + Reader = null!; // TODO-NULLABLE: Avoid nulling out in Dispose if (copyOfReader != null) copyOfReader.Close(); } - Reader = null!; // TODO-NULLABLE: should not be nulled out in the Dispose + Reader = null!; // TODO-NULLABLE: Avoid nulling out in Dispose _caseInsensitiveTable = null; Table = null; } diff --git a/src/System.Private.CoreLib/shared/System/Resources/RuntimeResourceSet.cs b/src/System.Private.CoreLib/shared/System/Resources/RuntimeResourceSet.cs index 0cb229d..0d33f3a 100644 --- a/src/System.Private.CoreLib/shared/System/Resources/RuntimeResourceSet.cs +++ b/src/System.Private.CoreLib/shared/System/Resources/RuntimeResourceSet.cs @@ -176,12 +176,12 @@ namespace System.Resources // for arbitrarily long times, since the object is usually a string // literal that will live for the lifetime of the appdomain. The // value is a ResourceLocator instance, which might cache the object. - private Dictionary? _resCache; // TODO-NULLABLE: should not be nulled out in Dispose + private Dictionary? _resCache; // TODO-NULLABLE: Avoid nulling out in Dispose // For our special load-on-demand reader, cache the cast. The // RuntimeResourceSet's implementation knows how to treat this reader specially. - private ResourceReader? _defaultReader; // TODO-NULLABLE: should not be nulled out in Dispose + private ResourceReader? _defaultReader; // TODO-NULLABLE: Avoid nulling out in Dispose // This is a lookup table for case-insensitive lookups, and may be null. // Consider always using a case-insensitive resource cache, as we don't diff --git a/src/System.Private.CoreLib/shared/System/Runtime/CompilerServices/AsyncMethodBuilder.cs b/src/System.Private.CoreLib/shared/System/Runtime/CompilerServices/AsyncMethodBuilder.cs index f33f0c7..9fcb418 100644 --- a/src/System.Private.CoreLib/shared/System/Runtime/CompilerServices/AsyncMethodBuilder.cs +++ b/src/System.Private.CoreLib/shared/System/Runtime/CompilerServices/AsyncMethodBuilder.cs @@ -18,6 +18,7 @@ using System.Threading; using System.Threading.Tasks; using System.Text; using Internal.Runtime.CompilerServices; +using System.Diagnostics.CodeAnalysis; namespace System.Runtime.CompilerServices { @@ -131,7 +132,7 @@ namespace System.Runtime.CompilerServices // and decrement its outstanding operation count. try { - System.Threading.Tasks.Task.ThrowAsync(exception!, targetContext: _synchronizationContext); // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 + System.Threading.Tasks.Task.ThrowAsync(exception!, targetContext: _synchronizationContext); // TODO-NULLABLE: Remove ! when [DoesNotReturn] respected } finally { @@ -143,7 +144,7 @@ namespace System.Runtime.CompilerServices // Otherwise, queue the exception to be thrown on the ThreadPool. This will // result in a crash unless legacy exception behavior is enabled by a config // file or a CLR host. - System.Threading.Tasks.Task.ThrowAsync(exception!, targetContext: null); // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 + System.Threading.Tasks.Task.ThrowAsync(exception!, targetContext: null); // TODO-NULLABLE: Remove ! when [DoesNotReturn] respected } // The exception was propagated already; we don't need or want to fault the builder, just mark it as completed. @@ -314,7 +315,7 @@ namespace System.Runtime.CompilerServices { #if !PROJECTN /// A cached task for default(TResult). - internal readonly static Task s_defaultResultTask = AsyncTaskCache.CreateCacheableTask(default(TResult)!); // TODO-NULLABLE-GENERIC + internal readonly static Task s_defaultResultTask = AsyncTaskCache.CreateCacheableTask(default(TResult)!); // TODO-NULLABLE: Remove ! when nullable attributes are respected #endif /// The lazily-initialized built task. @@ -396,17 +397,17 @@ namespace System.Runtime.CompilerServices // The null tests here ensure that the jit can optimize away the interface // tests when TAwaiter is a ref type. - if ((null != (object)default(TAwaiter)!) && (awaiter is ITaskAwaiter)) // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/34757 + if ((null != (object)default(TAwaiter)!) && (awaiter is ITaskAwaiter)) // TODO-NULLABLE: default(T) == null warning (https://github.com/dotnet/roslyn/issues/34757) { ref TaskAwaiter ta = ref Unsafe.As(ref awaiter); // relies on TaskAwaiter/TaskAwaiter having the same layout TaskAwaiter.UnsafeOnCompletedInternal(ta.m_task, box, continueOnCapturedContext: true); } - else if ((null != (object)default(TAwaiter)!) && (awaiter is IConfiguredTaskAwaiter)) // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/34757 + else if ((null != (object)default(TAwaiter)!) && (awaiter is IConfiguredTaskAwaiter)) // TODO-NULLABLE: default(T) == null warning (https://github.com/dotnet/roslyn/issues/34757) { ref ConfiguredTaskAwaitable.ConfiguredTaskAwaiter ta = ref Unsafe.As(ref awaiter); TaskAwaiter.UnsafeOnCompletedInternal(ta.m_task, box, ta.m_continueOnCapturedContext); } - else if ((null != (object)default(TAwaiter)!) && (awaiter is IStateMachineBoxAwareAwaiter)) // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/34757 + else if ((null != (object)default(TAwaiter)!) && (awaiter is IStateMachineBoxAwareAwaiter)) // TODO-NULLABLE: default(T) == null warning (https://github.com/dotnet/roslyn/issues/34757) { try { @@ -568,7 +569,7 @@ namespace System.Runtime.CompilerServices /// A delegate to the method. private Action? _moveNextAction; /// The state machine itself. - public TStateMachine StateMachine = default!; // mutable struct; do not make this readonly. SOS DumpAsync command depends on this name. // TODO-NULLABLE-GENERIC + [AllowNull, MaybeNull] public TStateMachine StateMachine = default!; // mutable struct; do not make this readonly. SOS DumpAsync command depends on this name. // TODO-NULLABLE: Remove ! when nullable attributes are respected /// Captured ExecutionContext with which to invoke ; may be null. public ExecutionContext? Context; @@ -612,7 +613,7 @@ namespace System.Runtime.CompilerServices // Clear out state now that the async method has completed. // This avoids keeping arbitrary state referenced by lifted locals // if this Task / state machine box is held onto. - StateMachine = default!; // TODO-NULLABLE-GENERIC + StateMachine = default!; // TODO-NULLABLE: Remove ! when nullable attributes are respected Context = default; #if !CORERT @@ -703,7 +704,7 @@ namespace System.Runtime.CompilerServices /// Completes the already initialized task with the specified result. /// The result to use to complete the task. - private void SetExistingTaskResult(TResult result) + private void SetExistingTaskResult([AllowNull] TResult result) { Debug.Assert(m_task != null, "Expected non-null task"); @@ -755,7 +756,7 @@ namespace System.Runtime.CompilerServices else { // Otherwise, complete the task that's there. - SetExistingTaskResult(default!); // TODO-NULLABLE-GENERIC + SetExistingTaskResult(default!); // Remove ! when nullable attributes are respected } } @@ -779,7 +780,7 @@ namespace System.Runtime.CompilerServices // If the exception represents cancellation, cancel the task. Otherwise, fault the task. bool successfullySet = exception is OperationCanceledException oce ? task.TrySetCanceled(oce.CancellationToken, oce) : - task.TrySetException(exception!); // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 + task.TrySetException(exception!); // TODO-NULLABLE: Remove ! when [DoesNotReturn] respected // Unlike with TaskCompletionSource, we do not need to spin here until _taskAndStateMachine is completed, // since AsyncTaskMethodBuilder.SetException should not be immediately followed by any code @@ -863,7 +864,7 @@ namespace System.Runtime.CompilerServices // find a cached value, since static fields (even if readonly and integral types) // require special access helpers in this NGEN'd and domain-neutral. - if (null != (object)default(TResult)!) // help the JIT avoid the value type branches for ref types // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/34757 + if (null != (object)default(TResult)!) // help the JIT avoid the value type branches for ref types // TODO-NULLABLE: default(T) == null warning (https://github.com/dotnet/roslyn/issues/34757) { // Special case simple value types: // - Boolean @@ -879,7 +880,7 @@ namespace System.Runtime.CompilerServices // For Boolean, we cache all possible values. if (typeof(TResult) == typeof(bool)) // only the relevant branches are kept for each value-type generic instantiation { - bool value = (bool)(object)result!; // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/34976 + bool value = (bool)(object)result!; Task task = value ? AsyncTaskCache.TrueTask : AsyncTaskCache.FalseTask; return Unsafe.As>(task); // UnsafeCast avoids type check we know will succeed } @@ -889,7 +890,7 @@ namespace System.Runtime.CompilerServices // Compare to constants to avoid static field access if outside of cached range. // We compare to the upper bound first, as we're more likely to cache miss on the upper side than on the // lower side, due to positive values being more common than negative as return values. - int value = (int)(object)result!; // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/34976 + int value = (int)(object)result!; if (value < AsyncTaskCache.EXCLUSIVE_INT32_MAX && value >= AsyncTaskCache.INCLUSIVE_INT32_MIN) { @@ -908,7 +909,7 @@ namespace System.Runtime.CompilerServices (typeof(TResult) == typeof(short) && default(short) == (short)(object)result!) || (typeof(TResult) == typeof(ushort) && default(ushort) == (ushort)(object)result!) || (typeof(TResult) == typeof(IntPtr) && default == (IntPtr)(object)result!) || - (typeof(TResult) == typeof(UIntPtr) && default == (UIntPtr)(object)result!)) // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/34976 + (typeof(TResult) == typeof(UIntPtr) && default == (UIntPtr)(object)result!)) { return s_defaultResultTask; } @@ -958,7 +959,7 @@ namespace System.Runtime.CompilerServices /// Specifies the result type. /// The result for the task. /// The cacheable task. - internal static Task CreateCacheableTask(TResult result) => + internal static Task CreateCacheableTask([AllowNull] TResult result) => new Task(false, result, (TaskCreationOptions)InternalTaskOptions.DoNotDispose, default); } @@ -1008,7 +1009,7 @@ namespace System.Runtime.CompilerServices try { - stateMachine!.MoveNext(); // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 + stateMachine!.MoveNext(); // TODO-NULLABLE: Remove ! when [DoesNotReturn] respected } finally { diff --git a/src/System.Private.CoreLib/shared/System/Runtime/CompilerServices/ConditionalWeakTable.cs b/src/System.Private.CoreLib/shared/System/Runtime/CompilerServices/ConditionalWeakTable.cs index bbbf58d..7322bbe 100644 --- a/src/System.Private.CoreLib/shared/System/Runtime/CompilerServices/ConditionalWeakTable.cs +++ b/src/System.Private.CoreLib/shared/System/Runtime/CompilerServices/ConditionalWeakTable.cs @@ -5,6 +5,7 @@ using System.Collections; using System.Collections.Generic; using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.Threading; using Internal.Runtime.CompilerServices; @@ -51,7 +52,7 @@ namespace System.Runtime.CompilerServices /// The key may get garbaged collected during the TryGetValue operation. If so, TryGetValue /// may at its discretion, return "false" and set "value" to the default (as if the key was not present.) /// - public bool TryGetValue(TKey key, out TValue value) + public bool TryGetValue(TKey key, [MaybeNullWhen(false)] out TValue value) { if (key is null) { @@ -362,7 +363,7 @@ namespace System.Runtime.CompilerServices } } - object? IEnumerator.Current => Current; // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/23268 + object? IEnumerator.Current => Current; public void Reset() { } } @@ -502,7 +503,7 @@ namespace System.Runtime.CompilerServices } /// Worker for finding a key/value pair. Must hold _lock. - internal bool TryGetValueWorker(TKey key, out TValue value) + internal bool TryGetValueWorker(TKey key, [MaybeNullWhen(false)] out TValue value) { Debug.Assert(key != null); // Key already validated as non-null @@ -536,7 +537,7 @@ namespace System.Runtime.CompilerServices } /// Gets the entry at the specified entry index. - internal bool TryGetEntry(int index, out TKey key, out TValue value) + internal bool TryGetEntry(int index, [MaybeNullWhen(false)] out TKey key, [MaybeNullWhen(false)] out TValue value) { if (index < _entries.Length) { @@ -551,8 +552,8 @@ namespace System.Runtime.CompilerServices } } - key = default!; // TODO-NULLABLE-GENERIC - value = default!; // TODO-NULLABLE-GENERIC + key = default!; + value = default!; return false; } diff --git a/src/System.Private.CoreLib/shared/System/Runtime/CompilerServices/DateTimeConstantAttribute.cs b/src/System.Private.CoreLib/shared/System/Runtime/CompilerServices/DateTimeConstantAttribute.cs index 1b5bc37..ee9250b 100644 --- a/src/System.Private.CoreLib/shared/System/Runtime/CompilerServices/DateTimeConstantAttribute.cs +++ b/src/System.Private.CoreLib/shared/System/Runtime/CompilerServices/DateTimeConstantAttribute.cs @@ -14,6 +14,8 @@ namespace System.Runtime.CompilerServices _date = new DateTime(ticks); } - public override object? Value => _date; // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/23268 +#pragma warning disable CS8608 + public override object Value => _date; +#pragma warning restore CS8608 } } diff --git a/src/System.Private.CoreLib/shared/System/Runtime/CompilerServices/ICastable.cs b/src/System.Private.CoreLib/shared/System/Runtime/CompilerServices/ICastable.cs index 95c5149..7320c2d 100644 --- a/src/System.Private.CoreLib/shared/System/Runtime/CompilerServices/ICastable.cs +++ b/src/System.Private.CoreLib/shared/System/Runtime/CompilerServices/ICastable.cs @@ -2,6 +2,8 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +using System.Diagnostics.CodeAnalysis; + namespace System.Runtime.CompilerServices { /// @@ -31,7 +33,7 @@ namespace System.Runtime.CompilerServices // because this is the only guard placed before an interface invocation at runtime. If a type decides // it no longer wants to implement a given interface it has no way to synchronize with callers that // have already cached this relationship and can invoke directly via the interface pointer. - bool IsInstanceOfInterface(RuntimeTypeHandle interfaceType, out Exception? castError); + bool IsInstanceOfInterface(RuntimeTypeHandle interfaceType, [NotNullWhen(true)] out Exception? castError); // This is called as part of the interface dispatch mechanism when the dispatcher logic cannot find // the given interface type in the interface map of this object. diff --git a/src/System.Private.CoreLib/shared/System/Runtime/CompilerServices/RuntimeHelpers.cs b/src/System.Private.CoreLib/shared/System/Runtime/CompilerServices/RuntimeHelpers.cs index ab7b1d5..b251c0b 100644 --- a/src/System.Private.CoreLib/shared/System/Runtime/CompilerServices/RuntimeHelpers.cs +++ b/src/System.Private.CoreLib/shared/System/Runtime/CompilerServices/RuntimeHelpers.cs @@ -23,9 +23,9 @@ namespace System.Runtime.CompilerServices ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array); } - (int offset, int length) = range.GetOffsetAndLength(array!.Length); // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 + (int offset, int length) = range.GetOffsetAndLength(array!.Length); // TODO-NULLABLE: Remove ! when [DoesNotReturn] respected - if (default(T)! != null || typeof(T[]) == array.GetType()) // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/34757 + if (default(T)! != null || typeof(T[]) == array.GetType()) // TODO-NULLABLE: default(T) == null warning (https://github.com/dotnet/roslyn/issues/34757) { // We know the type of the array to be exactly T[]. diff --git a/src/System.Private.CoreLib/shared/System/Runtime/CompilerServices/StrongBox.cs b/src/System.Private.CoreLib/shared/System/Runtime/CompilerServices/StrongBox.cs index c2f681e..7b59222 100644 --- a/src/System.Private.CoreLib/shared/System/Runtime/CompilerServices/StrongBox.cs +++ b/src/System.Private.CoreLib/shared/System/Runtime/CompilerServices/StrongBox.cs @@ -2,6 +2,8 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +using System.Diagnostics.CodeAnalysis; + namespace System.Runtime.CompilerServices { /// @@ -15,7 +17,7 @@ namespace System.Runtime.CompilerServices /// This is explicitly exposed as a field instead of a property to enable loading the address of the field. /// [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1051:DoNotDeclareVisibleInstanceFields")] - public T Value = default!; // TODO-NULLABLE-GENERIC + [MaybeNull] public T Value = default!; /// /// Initializes a new StrongBox which can receive a value when used in a reference call. @@ -41,7 +43,7 @@ namespace System.Runtime.CompilerServices } set { - Value = (T)value!; // TODO-NULLABLE-GENERIC + Value = (T)value!; } } } diff --git a/src/System.Private.CoreLib/shared/System/Runtime/CompilerServices/YieldAwaitable.cs b/src/System.Private.CoreLib/shared/System/Runtime/CompilerServices/YieldAwaitable.cs index c6b19d6..87c610f 100644 --- a/src/System.Private.CoreLib/shared/System/Runtime/CompilerServices/YieldAwaitable.cs +++ b/src/System.Private.CoreLib/shared/System/Runtime/CompilerServices/YieldAwaitable.cs @@ -130,7 +130,7 @@ namespace System.Runtime.CompilerServices SynchronizationContext? syncCtx = SynchronizationContext.Current; if (syncCtx != null && syncCtx.GetType() != typeof(SynchronizationContext)) { - syncCtx.Post(s => ((IAsyncStateMachineBox)s!).MoveNext(), box); // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 + syncCtx.Post(s => ((IAsyncStateMachineBox)s!).MoveNext(), box); } else { @@ -141,7 +141,7 @@ namespace System.Runtime.CompilerServices } else { - Task.Factory.StartNew(s => ((IAsyncStateMachineBox)s!).MoveNext(), box, default, TaskCreationOptions.PreferFairness, scheduler); // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 + Task.Factory.StartNew(s => ((IAsyncStateMachineBox)s!).MoveNext(), box, default, TaskCreationOptions.PreferFairness, scheduler); } } } diff --git a/src/System.Private.CoreLib/shared/System/Runtime/ExceptionServices/ExceptionDispatchInfo.cs b/src/System.Private.CoreLib/shared/System/Runtime/ExceptionServices/ExceptionDispatchInfo.cs index 3578d43..8610978 100644 --- a/src/System.Private.CoreLib/shared/System/Runtime/ExceptionServices/ExceptionDispatchInfo.cs +++ b/src/System.Private.CoreLib/shared/System/Runtime/ExceptionServices/ExceptionDispatchInfo.cs @@ -3,6 +3,7 @@ // See the LICENSE file in the project root for more information. using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; namespace System.Runtime.ExceptionServices { @@ -53,6 +54,7 @@ namespace System.Runtime.ExceptionServices // This method will restore the original stack trace and bucketing details before throwing // the exception so that it is easy, from debugging standpoint, to understand what really went wrong on // the original thread. + [DoesNotReturn] [StackTraceHidden] public void Throw() { @@ -63,6 +65,7 @@ namespace System.Runtime.ExceptionServices // Throws the source exception, maintaining the original bucketing details and augmenting // rather than replacing the original stack trace. + [DoesNotReturn] public static void Throw(Exception source) => Capture(source).Throw(); } } diff --git a/src/System.Private.CoreLib/shared/System/Runtime/InteropServices/Marshal.NoCom.cs b/src/System.Private.CoreLib/shared/System/Runtime/InteropServices/Marshal.NoCom.cs index 896312f..4ec8f58 100644 --- a/src/System.Private.CoreLib/shared/System/Runtime/InteropServices/Marshal.NoCom.cs +++ b/src/System.Private.CoreLib/shared/System/Runtime/InteropServices/Marshal.NoCom.cs @@ -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. +using System.Diagnostics.CodeAnalysis; using System.Reflection; using System.Runtime.InteropServices.ComTypes; @@ -35,9 +36,8 @@ namespace System.Runtime.InteropServices { } - public static IntPtr CreateAggregatedObject(IntPtr pOuter, T o) + public static IntPtr CreateAggregatedObject(IntPtr pOuter, T o) where T : object { - // TODO-NULLABLE-GENERIC: T cannot be null throw new PlatformNotSupportedException(SR.PlatformNotSupported_ComInterop); } @@ -46,9 +46,8 @@ namespace System.Runtime.InteropServices throw new PlatformNotSupportedException(SR.PlatformNotSupported_ComInterop); } - public static TWrapper CreateWrapperOfType(T o) + public static TWrapper CreateWrapperOfType([AllowNull] T o) { - // TODO-NULLABLE-GENERIC: T can be null throw new PlatformNotSupportedException(SR.PlatformNotSupported_ComInterop); } @@ -72,9 +71,8 @@ namespace System.Runtime.InteropServices throw new PlatformNotSupportedException(SR.PlatformNotSupported_ComInterop); } - public static IntPtr GetComInterfaceForObject(T o) + public static IntPtr GetComInterfaceForObject([DisallowNull] T o) { - // TODO-NULLABLE-GENERIC: T cannot be null throw new PlatformNotSupportedException(SR.PlatformNotSupported_ComInterop); } @@ -103,9 +101,8 @@ namespace System.Runtime.InteropServices throw new PlatformNotSupportedException(SR.PlatformNotSupported_ComInterop); } - public static void GetNativeVariantForObject(T obj, IntPtr pDstNativeVariant) + public static void GetNativeVariantForObject([AllowNull] T obj, IntPtr pDstNativeVariant) { - // TODO-NULLABLE-GENERIC: T can be null throw new PlatformNotSupportedException(SR.PlatformNotSupported_ComInterop); } @@ -124,9 +121,9 @@ namespace System.Runtime.InteropServices throw new PlatformNotSupportedException(SR.PlatformNotSupported_ComInterop); } + [return: MaybeNull] public static T GetObjectForNativeVariant(IntPtr pSrcNativeVariant) { - // TODO-NULLABLE-GENERIC: T can be null throw new PlatformNotSupportedException(SR.PlatformNotSupported_ComInterop); } @@ -135,7 +132,6 @@ namespace System.Runtime.InteropServices throw new PlatformNotSupportedException(SR.PlatformNotSupported_ComInterop); } - // TODO-NULLABLE-GENERIC: T[] contents can be null public static T[] GetObjectsForNativeVariants(IntPtr aSrcNativeVariant, int cVars) { throw new PlatformNotSupportedException(SR.PlatformNotSupported_ComInterop); diff --git a/src/System.Private.CoreLib/shared/System/Runtime/InteropServices/Marshal.Unix.cs b/src/System.Private.CoreLib/shared/System/Runtime/InteropServices/Marshal.Unix.cs index f4634fd..c0e9bd6 100644 --- a/src/System.Private.CoreLib/shared/System/Runtime/InteropServices/Marshal.Unix.cs +++ b/src/System.Private.CoreLib/shared/System/Runtime/InteropServices/Marshal.Unix.cs @@ -9,8 +9,6 @@ namespace System.Runtime.InteropServices { public static partial class Marshal { - // TODO-NULLABLE: This has different behavior from the other PtrToString(IntPtr, int) functions - // This is due to PtrToStringUTF8 on Unix and is being resolved independently public static string? PtrToStringAuto(IntPtr ptr, int len) { return PtrToStringUTF8(ptr, len); diff --git a/src/System.Private.CoreLib/shared/System/Runtime/InteropServices/Marshal.Windows.cs b/src/System.Private.CoreLib/shared/System/Runtime/InteropServices/Marshal.Windows.cs index a7ee8b3..f4027d0 100644 --- a/src/System.Private.CoreLib/shared/System/Runtime/InteropServices/Marshal.Windows.cs +++ b/src/System.Private.CoreLib/shared/System/Runtime/InteropServices/Marshal.Windows.cs @@ -8,8 +8,6 @@ namespace System.Runtime.InteropServices { public static partial class Marshal { - // TODO-NULLABLE: This has different behavior from the other PtrToString(IntPtr, int) functions - // This is due to PtrToStringUTF8 on Unix and is being resolved independently public static string? PtrToStringAuto(IntPtr ptr, int len) { return PtrToStringUni(ptr, len); diff --git a/src/System.Private.CoreLib/shared/System/Runtime/InteropServices/Marshal.cs b/src/System.Private.CoreLib/shared/System/Runtime/InteropServices/Marshal.cs index 6834685..e9485bf 100644 --- a/src/System.Private.CoreLib/shared/System/Runtime/InteropServices/Marshal.cs +++ b/src/System.Private.CoreLib/shared/System/Runtime/InteropServices/Marshal.cs @@ -8,6 +8,7 @@ using System.Runtime.CompilerServices; using System.Text; using Internal.Runtime.CompilerServices; +using System.Diagnostics.CodeAnalysis; #if BIT64 using nuint = System.UInt64; @@ -95,8 +96,7 @@ namespace System.Runtime.InteropServices return string.CreateStringFromEncoding((byte*)ptr, nbBytes, Encoding.UTF8); } - // TODO-NULLABLE: This has different behavior from the other PtrToString(IntPtr, int) functions - public static unsafe string? PtrToStringUTF8(IntPtr ptr, int byteLen) + public static unsafe string PtrToStringUTF8(IntPtr ptr, int byteLen) { if (ptr == IntPtr.Zero) { @@ -530,9 +530,8 @@ namespace System.Runtime.InteropServices } } - public static void StructureToPtr(T structure, IntPtr ptr, bool fDeleteOld) + public static void StructureToPtr([DisallowNull] T structure, IntPtr ptr, bool fDeleteOld) { - // TODO-NULLABLE-GENERIC: T cannot be null StructureToPtr((object)structure!, ptr, fDeleteOld); } @@ -571,13 +570,12 @@ namespace System.Runtime.InteropServices PtrToStructureHelper(ptr, structure, allowValueClasses: false); } - public static void PtrToStructure(IntPtr ptr, T structure) + public static void PtrToStructure(IntPtr ptr, [DisallowNull] T structure) { - // TODO-NULLABLE-GENERIC: T cannot be null PtrToStructure(ptr, (object)structure!); } - // TODO-NULLABLE-GENERIC: T can be null + [return: MaybeNull] public static T PtrToStructure(IntPtr ptr) => (T)PtrToStructure(ptr, typeof(T))!; public static void DestroyStructure(IntPtr ptr) => DestroyStructure(ptr, typeof(T)); @@ -898,10 +896,9 @@ namespace System.Runtime.InteropServices return GetFunctionPointerForDelegateInternal(d); } - public static IntPtr GetFunctionPointerForDelegate(TDelegate d) + public static IntPtr GetFunctionPointerForDelegate(TDelegate d) where TDelegate : object { - // TODO-NULLABLE-GENERIC: T cannot be null - return GetFunctionPointerForDelegate((Delegate)(object)d!); + return GetFunctionPointerForDelegate((Delegate)(object)d); } public static int GetHRForLastWin32Error() diff --git a/src/System.Private.CoreLib/shared/System/Runtime/InteropServices/MemoryMarshal.cs b/src/System.Private.CoreLib/shared/System/Runtime/InteropServices/MemoryMarshal.cs index 6816d3c..314bc02 100644 --- a/src/System.Private.CoreLib/shared/System/Runtime/InteropServices/MemoryMarshal.cs +++ b/src/System.Private.CoreLib/shared/System/Runtime/InteropServices/MemoryMarshal.cs @@ -8,6 +8,7 @@ using System.Collections.Generic; using System.Diagnostics; using Internal.Runtime.CompilerServices; +using System.Diagnostics.CodeAnalysis; namespace System.Runtime.InteropServices { @@ -55,7 +56,7 @@ namespace System.Runtime.InteropServices Debug.Assert(obj is MemoryManager); if (Unsafe.As>(obj).TryGetArray(out ArraySegment tempArraySegment)) { - segment = new ArraySegment(tempArraySegment.Array!, tempArraySegment.Offset + index, length); // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 + segment = new ArraySegment(tempArraySegment.Array!, tempArraySegment.Offset + index, length); return true; } } @@ -86,7 +87,7 @@ namespace System.Runtime.InteropServices /// The memory to get the manager for. /// The returned manager of the . /// A indicating if it was successful. - public static bool TryGetMemoryManager(ReadOnlyMemory memory, out TManager? manager) // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 + public static bool TryGetMemoryManager(ReadOnlyMemory memory, [NotNullWhen(true)] out TManager? manager) where TManager : MemoryManager { TManager? localManager; // Use register for null comparison rather than byref @@ -105,7 +106,7 @@ namespace System.Runtime.InteropServices /// The offset from the start of the that the represents. /// The length of the that the represents. /// A indicating if it was successful. - public static bool TryGetMemoryManager(ReadOnlyMemory memory, out TManager? manager, out int start, out int length) // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 + public static bool TryGetMemoryManager(ReadOnlyMemory memory, [NotNullWhen(true)] out TManager? manager, out int start, out int length) where TManager : MemoryManager { TManager? localManager; // Use register for null comparison rather than byref @@ -141,7 +142,7 @@ namespace System.Runtime.InteropServices /// The starting location in . /// The number of items in . /// - public static bool TryGetString(ReadOnlyMemory memory, out string? text, out int start, out int length) + public static bool TryGetString(ReadOnlyMemory memory, [NotNullWhen(true)] out string? text, out int start, out int length) { if (memory.GetObjectStartLength(out int offset, out int count) is string s) { @@ -306,7 +307,7 @@ namespace System.Runtime.InteropServices ThrowHelper.ThrowArgumentOutOfRangeException(); return default; } - if (default(T)! == null && array.GetType() != typeof(T[])) // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/34757 + if (default(T)! == null && array.GetType() != typeof(T[])) // TODO-NULLABLE: default(T) == null warning (https://github.com/dotnet/roslyn/issues/34757) ThrowHelper.ThrowArrayTypeMismatchException(); if ((uint)start > (uint)array.Length || (uint)length > (uint)(array.Length - start)) ThrowHelper.ThrowArgumentOutOfRangeException(); diff --git a/src/System.Private.CoreLib/shared/System/Runtime/InteropServices/NativeLibrary.cs b/src/System.Private.CoreLib/shared/System/Runtime/InteropServices/NativeLibrary.cs index b50a2e6..30d50fe 100644 --- a/src/System.Private.CoreLib/shared/System/Runtime/InteropServices/NativeLibrary.cs +++ b/src/System.Private.CoreLib/shared/System/Runtime/InteropServices/NativeLibrary.cs @@ -208,7 +208,7 @@ namespace System.Runtime.InteropServices try { - s_nativeDllResolveMap!.Add(assembly, resolver); // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 + s_nativeDllResolveMap!.Add(assembly, resolver); // TODO-NULLABLE: Remove ! when compiler specially-recognizes CompareExchange for nullability } catch (ArgumentException) { diff --git a/src/System.Private.CoreLib/shared/System/Runtime/Loader/AssemblyLoadContext.cs b/src/System.Private.CoreLib/shared/System/Runtime/Loader/AssemblyLoadContext.cs index 7ee3dfa..cd11839 100644 --- a/src/System.Private.CoreLib/shared/System/Runtime/Loader/AssemblyLoadContext.cs +++ b/src/System.Private.CoreLib/shared/System/Runtime/Loader/AssemblyLoadContext.cs @@ -118,7 +118,7 @@ namespace System.Runtime.Loader private void RaiseUnloadEvent() { // Ensure that we raise the Unload event only once - Interlocked.Exchange(ref _unloading, null!)?.Invoke(this); // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 + Interlocked.Exchange(ref _unloading, null!)?.Invoke(this); } private void InitiateUnload() @@ -442,7 +442,7 @@ namespace System.Runtime.Loader } } - private static AsyncLocal? s_asyncLocalCurrent; + private static AsyncLocal? s_asyncLocalCurrent; /// Nullable current AssemblyLoadContext used for context sensitive reflection APIs /// @@ -477,9 +477,9 @@ namespace System.Runtime.Loader { if (s_asyncLocalCurrent == null) { - Interlocked.CompareExchange?>(ref s_asyncLocalCurrent, new AsyncLocal(), null); + Interlocked.CompareExchange?>(ref s_asyncLocalCurrent, new AsyncLocal(), null); } - s_asyncLocalCurrent!.Value = value!; // TODO-NULLABLE-GENERIC + s_asyncLocalCurrent!.Value = value; // Remove ! when compiler specially-recognizes CompareExchange for nullability } /// Enter scope using this AssemblyLoadContext for ContextualReflection diff --git a/src/System.Private.CoreLib/shared/System/Runtime/Serialization/SerializationInfo.cs b/src/System.Private.CoreLib/shared/System/Runtime/Serialization/SerializationInfo.cs index 015fb00..afcf0ed 100644 --- a/src/System.Private.CoreLib/shared/System/Runtime/Serialization/SerializationInfo.cs +++ b/src/System.Private.CoreLib/shared/System/Runtime/Serialization/SerializationInfo.cs @@ -539,104 +539,104 @@ namespace System.Runtime.Serialization public bool GetBoolean(string name) { Type foundType; - object value = GetElement(name, out foundType)!; // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/34976 - return ReferenceEquals(foundType, typeof(bool)) ? (bool)value : _converter.ToBoolean(value); // if value is null To* method will either deal with it or throw + object? value = GetElement(name, out foundType); + return ReferenceEquals(foundType, typeof(bool)) ? (bool)value! : _converter.ToBoolean(value!); // if value is null To* method will either deal with it or throw } public char GetChar(string name) { Type foundType; - object value = GetElement(name, out foundType)!; - return ReferenceEquals(foundType, typeof(char)) ? (char)value : _converter.ToChar(value); + object? value = GetElement(name, out foundType); + return ReferenceEquals(foundType, typeof(char)) ? (char)value! : _converter.ToChar(value!); } [CLSCompliant(false)] public sbyte GetSByte(string name) { Type foundType; - object value = GetElement(name, out foundType)!; - return ReferenceEquals(foundType, typeof(sbyte)) ? (sbyte)value : _converter.ToSByte(value); + object? value = GetElement(name, out foundType); + return ReferenceEquals(foundType, typeof(sbyte)) ? (sbyte)value! : _converter.ToSByte(value!); } public byte GetByte(string name) { Type foundType; - object value = GetElement(name, out foundType)!; - return ReferenceEquals(foundType, typeof(byte)) ? (byte)value : _converter.ToByte(value); + object? value = GetElement(name, out foundType); + return ReferenceEquals(foundType, typeof(byte)) ? (byte)value! : _converter.ToByte(value!); } public short GetInt16(string name) { Type foundType; - object value = GetElement(name, out foundType)!; - return ReferenceEquals(foundType, typeof(short)) ? (short)value : _converter.ToInt16(value); + object? value = GetElement(name, out foundType); + return ReferenceEquals(foundType, typeof(short)) ? (short)value! : _converter.ToInt16(value!); } [CLSCompliant(false)] public ushort GetUInt16(string name) { Type foundType; - object value = GetElement(name, out foundType)!; - return ReferenceEquals(foundType, typeof(ushort)) ? (ushort)value : _converter.ToUInt16(value); + object? value = GetElement(name, out foundType); + return ReferenceEquals(foundType, typeof(ushort)) ? (ushort)value! : _converter.ToUInt16(value!); } public int GetInt32(string name) { Type foundType; - object value = GetElement(name, out foundType)!; - return ReferenceEquals(foundType, typeof(int)) ? (int)value : _converter.ToInt32(value); + object? value = GetElement(name, out foundType); + return ReferenceEquals(foundType, typeof(int)) ? (int)value! : _converter.ToInt32(value!); } [CLSCompliant(false)] public uint GetUInt32(string name) { Type foundType; - object value = GetElement(name, out foundType)!; - return ReferenceEquals(foundType, typeof(uint)) ? (uint)value : _converter.ToUInt32(value); + object? value = GetElement(name, out foundType); + return ReferenceEquals(foundType, typeof(uint)) ? (uint)value! : _converter.ToUInt32(value!); } public long GetInt64(string name) { Type foundType; - object value = GetElement(name, out foundType)!; - return ReferenceEquals(foundType, typeof(long)) ? (long)value : _converter.ToInt64(value); + object? value = GetElement(name, out foundType); + return ReferenceEquals(foundType, typeof(long)) ? (long)value! : _converter.ToInt64(value!); } [CLSCompliant(false)] public ulong GetUInt64(string name) { Type foundType; - object value = GetElement(name, out foundType)!; - return ReferenceEquals(foundType, typeof(ulong)) ? (ulong)value : _converter.ToUInt64(value); + object? value = GetElement(name, out foundType); + return ReferenceEquals(foundType, typeof(ulong)) ? (ulong)value! : _converter.ToUInt64(value!); } public float GetSingle(string name) { Type foundType; - object value = GetElement(name, out foundType)!; - return ReferenceEquals(foundType, typeof(float)) ? (float)value : _converter.ToSingle(value); + object? value = GetElement(name, out foundType); + return ReferenceEquals(foundType, typeof(float)) ? (float)value! : _converter.ToSingle(value!); } public double GetDouble(string name) { Type foundType; - object value = GetElement(name, out foundType)!; - return ReferenceEquals(foundType, typeof(double)) ? (double)value : _converter.ToDouble(value); + object? value = GetElement(name, out foundType); + return ReferenceEquals(foundType, typeof(double)) ? (double)value! : _converter.ToDouble(value!); } public decimal GetDecimal(string name) { Type foundType; - object value = GetElement(name, out foundType)!; - return ReferenceEquals(foundType, typeof(decimal)) ? (decimal)value : _converter.ToDecimal(value); + object? value = GetElement(name, out foundType); + return ReferenceEquals(foundType, typeof(decimal)) ? (decimal)value! : _converter.ToDecimal(value!); } public DateTime GetDateTime(string name) { Type foundType; - object value = GetElement(name, out foundType)!; - return ReferenceEquals(foundType, typeof(DateTime)) ? (DateTime)value : _converter.ToDateTime(value); + object? value = GetElement(name, out foundType); + return ReferenceEquals(foundType, typeof(DateTime)) ? (DateTime)value! : _converter.ToDateTime(value!); } public string? GetString(string name) diff --git a/src/System.Private.CoreLib/shared/System/Runtime/Serialization/SerializationInfoEnumerator.cs b/src/System.Private.CoreLib/shared/System/Runtime/Serialization/SerializationInfoEnumerator.cs index 6712a3b..65c34cb 100644 --- a/src/System.Private.CoreLib/shared/System/Runtime/Serialization/SerializationInfoEnumerator.cs +++ b/src/System.Private.CoreLib/shared/System/Runtime/Serialization/SerializationInfoEnumerator.cs @@ -70,7 +70,7 @@ namespace System.Runtime.Serialization return _current; } - object? IEnumerator.Current => Current; // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/23268 + object? IEnumerator.Current => Current; public SerializationEntry Current { diff --git a/src/System.Private.CoreLib/shared/System/Span.Fast.cs b/src/System.Private.CoreLib/shared/System/Span.Fast.cs index 456e1ec..75faa07 100644 --- a/src/System.Private.CoreLib/shared/System/Span.Fast.cs +++ b/src/System.Private.CoreLib/shared/System/Span.Fast.cs @@ -49,7 +49,7 @@ namespace System this = default; return; // returns default } - if (default(T)! == null && array.GetType() != typeof(T[])) // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/34757 + if (default(T)! == null && array.GetType() != typeof(T[])) // TODO-NULLABLE: default(T) == null warning (https://github.com/dotnet/roslyn/issues/34757) ThrowHelper.ThrowArrayTypeMismatchException(); _pointer = new ByReference(ref Unsafe.As(ref array.GetRawSzArrayData())); @@ -78,7 +78,7 @@ namespace System this = default; return; // returns default } - if (default(T)! == null && array.GetType() != typeof(T[])) // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/34757 + if (default(T)! == null && array.GetType() != typeof(T[])) // TODO-NULLABLE: default(T) == null warning (https://github.com/dotnet/roslyn/issues/34757) ThrowHelper.ThrowArrayTypeMismatchException(); #if BIT64 // See comment in Span.Slice for how this works. diff --git a/src/System.Private.CoreLib/shared/System/SpanHelpers.T.cs b/src/System.Private.CoreLib/shared/System/SpanHelpers.T.cs index 37bc43f..035e31b 100644 --- a/src/System.Private.CoreLib/shared/System/SpanHelpers.T.cs +++ b/src/System.Private.CoreLib/shared/System/SpanHelpers.T.cs @@ -57,7 +57,7 @@ namespace System IntPtr index = (IntPtr)0; // Use IntPtr for arithmetic to avoid unnecessary 64->32->64 truncations - if (default(T)! != null || (object)value != null) // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/34757 + if (default(T)! != null || (object)value != null) // TODO-NULLABLE: default(T) == null warning (https://github.com/dotnet/roslyn/issues/34757) { while (length >= 8) { @@ -127,7 +127,7 @@ namespace System Debug.Assert(length >= 0); IntPtr index = (IntPtr)0; // Use IntPtr for arithmetic to avoid unnecessary 64->32->64 truncations - if (default(T)! != null || (object)value != null) // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/34757 + if (default(T)! != null || (object)value != null) // TODO-NULLABLE: default(T) == null warning (https://github.com/dotnet/roslyn/issues/34757) { while (length >= 8) { @@ -216,7 +216,7 @@ namespace System T lookUp; int index = 0; - if (default(T)! != null || ((object)value0 != null && (object)value1 != null)) // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/34757 + if (default(T)! != null || ((object)value0 != null && (object)value1 != null)) // TODO-NULLABLE: default(T) == null warning (https://github.com/dotnet/roslyn/issues/34757) { while ((length - index) >= 8) { @@ -321,7 +321,7 @@ namespace System T lookUp; int index = 0; - if (default(T)! != null || ((object)value0 != null && (object)value1 != null && (object)value2 != null)) // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/34757 + if (default(T)! != null || ((object)value0 != null && (object)value1 != null && (object)value2 != null)) // TODO-NULLABLE: default(T) == null warning (https://github.com/dotnet/roslyn/issues/34757) { while ((length - index) >= 8) { @@ -484,7 +484,7 @@ namespace System { Debug.Assert(length >= 0); - if (default(T)! != null || (object)value != null) // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/34757 + if (default(T)! != null || (object)value != null) // TODO-NULLABLE: default(T) == null warning (https://github.com/dotnet/roslyn/issues/34757) { while (length >= 8) { @@ -567,7 +567,7 @@ namespace System Debug.Assert(length >= 0); T lookUp; - if (default(T)! != null || ((object)value0 != null && (object)value1 != null)) // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/34757 + if (default(T)! != null || ((object)value0 != null && (object)value1 != null)) // TODO-NULLABLE: default(T) == null warning (https://github.com/dotnet/roslyn/issues/34757) { while (length >= 8) { @@ -671,7 +671,7 @@ namespace System Debug.Assert(length >= 0); T lookUp; - if (default(T)! != null || ((object)value0 != null && (object)value1 != null)) // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/34757 + if (default(T)! != null || ((object)value0 != null && (object)value1 != null)) // TODO-NULLABLE: default(T) == null warning (https://github.com/dotnet/roslyn/issues/34757) { while (length >= 8) { diff --git a/src/System.Private.CoreLib/shared/System/String.Comparison.cs b/src/System.Private.CoreLib/shared/System/String.Comparison.cs index a420fc8..6bf3de7 100644 --- a/src/System.Private.CoreLib/shared/System/String.Comparison.cs +++ b/src/System.Private.CoreLib/shared/System/String.Comparison.cs @@ -522,7 +522,9 @@ namespace System // Determines the sorting relation of StrB to the current instance. // +#pragma warning disable CS8614 // TODO-NULLABLE: Covariant interface arguments (https://github.com/dotnet/roslyn/issues/35817) public int CompareTo(string? strB) +#pragma warning restore CS8614 { return string.Compare(this, strB, StringComparison.CurrentCulture); } @@ -616,7 +618,9 @@ namespace System } // Determines whether two strings match. +#pragma warning disable CS8614 // TODO-NULLABLE: Covariant interface arguments (https://github.com/dotnet/roslyn/issues/35817) public bool Equals(string? value) +#pragma warning restore CS8614 { if (object.ReferenceEquals(this, value)) return true; diff --git a/src/System.Private.CoreLib/shared/System/String.Searching.cs b/src/System.Private.CoreLib/shared/System/String.Searching.cs index 3d386b7..ab98daf 100644 --- a/src/System.Private.CoreLib/shared/System/String.Searching.cs +++ b/src/System.Private.CoreLib/shared/System/String.Searching.cs @@ -18,7 +18,7 @@ namespace System return SpanHelpers.IndexOf( ref _firstChar, Length, - ref value!._firstChar, // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 + ref value!._firstChar, // TODO-NULLABLE: Remove ! when [DoesNotReturn] respected value.Length) >= 0; } diff --git a/src/System.Private.CoreLib/shared/System/String.cs b/src/System.Private.CoreLib/shared/System/String.cs index 60a82de..160ce4b 100644 --- a/src/System.Private.CoreLib/shared/System/String.cs +++ b/src/System.Private.CoreLib/shared/System/String.cs @@ -6,6 +6,7 @@ using System.Buffers; using System.Collections; using System.Collections.Generic; using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; @@ -22,7 +23,7 @@ namespace System [Serializable] [System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")] - public sealed partial class String : IComparable, IEnumerable, IConvertible, IEnumerable, IComparable, IEquatable, ICloneable + public sealed partial class String : IComparable, IEnumerable, IConvertible, IEnumerable, IComparable, IEquatable, ICloneable { /* * CONSTRUCTORS @@ -436,7 +437,7 @@ namespace System } [NonVersionable] - public static bool IsNullOrEmpty(string? value) + public static bool IsNullOrEmpty([NotNullWhen(false)] string? value) { // Using 0u >= (uint)value.Length rather than // value.Length == 0 as it will elide the bounds check to @@ -447,7 +448,7 @@ namespace System return (value == null || 0u >= (uint)value.Length) ? true : false; } - public static bool IsNullOrWhiteSpace(string? value) + public static bool IsNullOrWhiteSpace([NotNullWhen(false)] string? value) { if (value == null) return true; @@ -675,6 +676,7 @@ namespace System return length; } + [DoesNotReturn] private static void ThrowMustBeNullTerminatedString() { throw new ArgumentException(SR.Arg_MustBeNullTerminatedString); diff --git a/src/System.Private.CoreLib/shared/System/StringComparer.cs b/src/System.Private.CoreLib/shared/System/StringComparer.cs index 83c81ae..ef7281f 100644 --- a/src/System.Private.CoreLib/shared/System/StringComparer.cs +++ b/src/System.Private.CoreLib/shared/System/StringComparer.cs @@ -161,7 +161,9 @@ namespace System public abstract int Compare(string? x, string? y); public abstract bool Equals(string? x, string? y); - public abstract int GetHashCode(string? obj); // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/23268 +#pragma warning disable CS8614 // Remove warning disable when nullable attributes are respected + public abstract int GetHashCode(string obj); +#pragma warning restore CS8614 } [Serializable] @@ -214,7 +216,7 @@ namespace System return _compareInfo.Compare(x, y, _options) == 0; } - public override int GetHashCode(string? obj) // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/23268 + public override int GetHashCode(string obj) { if (obj == null) { @@ -291,7 +293,7 @@ namespace System return x.Equals(y); } - public override int GetHashCode(string? obj) // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/23268 + public override int GetHashCode(string obj) { if (obj == null) { @@ -300,10 +302,10 @@ namespace System if (_ignoreCase) { - return obj!.GetHashCodeOrdinalIgnoreCase(); // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 + return obj!.GetHashCodeOrdinalIgnoreCase(); // TODO-NULLABLE: Remove ! when [DoesNotReturn] respected } - return obj!.GetHashCode(); // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 + return obj!.GetHashCode(); // TODO-NULLABLE: Remove ! when [DoesNotReturn] respected } // Equals method for the comparer itself. @@ -334,13 +336,13 @@ namespace System public override bool Equals(string? x, string? y) => string.Equals(x, y); - public override int GetHashCode(string? obj) // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/23268 + public override int GetHashCode(string obj) { if (obj == null) { ThrowHelper.ThrowArgumentNullException(ExceptionArgument.obj); } - return obj!.GetHashCode(); // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 + return obj!.GetHashCode(); // TODO-NULLABLE: Remove ! when [DoesNotReturn] respected } public void GetObjectData(SerializationInfo info, StreamingContext context) @@ -379,13 +381,13 @@ namespace System return CompareInfo.EqualsOrdinalIgnoreCase(ref x.GetRawStringData(), ref y.GetRawStringData(), x.Length); } - public override int GetHashCode(string? obj) // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/23268 + public override int GetHashCode(string obj) { if (obj == null) { ThrowHelper.ThrowArgumentNullException(ExceptionArgument.obj); } - return obj!.GetHashCodeOrdinalIgnoreCase(); // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 + return obj!.GetHashCodeOrdinalIgnoreCase(); // TODO-NULLABLE: Remove ! when [DoesNotReturn] respected } public void GetObjectData(SerializationInfo info, StreamingContext context) diff --git a/src/System.Private.CoreLib/shared/System/Text/DecoderBestFitFallback.cs b/src/System.Private.CoreLib/shared/System/Text/DecoderBestFitFallback.cs index 98f3061..9122641 100644 --- a/src/System.Private.CoreLib/shared/System/Text/DecoderBestFitFallback.cs +++ b/src/System.Private.CoreLib/shared/System/Text/DecoderBestFitFallback.cs @@ -72,7 +72,7 @@ namespace System.Text object o = new object(); Interlocked.CompareExchange(ref s_InternalSyncObject, o, null); } - return s_InternalSyncObject!; // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 + return s_InternalSyncObject!; // TODO-NULLABLE: Remove ! when compiler specially-recognizes CompareExchange for nullability } } diff --git a/src/System.Private.CoreLib/shared/System/Text/DecoderExceptionFallback.cs b/src/System.Private.CoreLib/shared/System/Text/DecoderExceptionFallback.cs index 338724c..3c1b360 100644 --- a/src/System.Private.CoreLib/shared/System/Text/DecoderExceptionFallback.cs +++ b/src/System.Private.CoreLib/shared/System/Text/DecoderExceptionFallback.cs @@ -3,6 +3,7 @@ // See the LICENSE file in the project root for more information. using System; +using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.Runtime.Serialization; @@ -73,6 +74,7 @@ namespace System.Text } } + [DoesNotReturn] private void Throw(byte[] bytesUnknown, int index) { bytesUnknown = bytesUnknown ?? Array.Empty(); diff --git a/src/System.Private.CoreLib/shared/System/Text/DecoderFallback.cs b/src/System.Private.CoreLib/shared/System/Text/DecoderFallback.cs index 4b4bcb6..aa3f65b 100644 --- a/src/System.Private.CoreLib/shared/System/Text/DecoderFallback.cs +++ b/src/System.Private.CoreLib/shared/System/Text/DecoderFallback.cs @@ -3,6 +3,7 @@ // See the LICENSE file in the project root for more information. using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.Threading; @@ -14,11 +15,11 @@ namespace System.Text private static DecoderFallback? s_exceptionFallback; public static DecoderFallback ReplacementFallback => - s_replacementFallback ?? Interlocked.CompareExchange(ref s_replacementFallback, new DecoderReplacementFallback(), null) ?? s_replacementFallback!; // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 + s_replacementFallback ?? Interlocked.CompareExchange(ref s_replacementFallback, new DecoderReplacementFallback(), null) ?? s_replacementFallback!; // TODO-NULLABLE: Remove ! when compiler specially-recognizes CompareExchange for nullability public static DecoderFallback ExceptionFallback => - s_exceptionFallback ?? Interlocked.CompareExchange(ref s_exceptionFallback, new DecoderExceptionFallback(), null) ?? s_exceptionFallback!; // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 + s_exceptionFallback ?? Interlocked.CompareExchange(ref s_exceptionFallback, new DecoderExceptionFallback(), null) ?? s_exceptionFallback!; // TODO-NULLABLE: Remove ! when compiler specially-recognizes CompareExchange for nullability // Fallback // @@ -296,6 +297,7 @@ namespace System.Text } // private helper methods + [DoesNotReturn] internal void ThrowLastBytesRecursive(byte[] bytesUnknown) { bytesUnknown = bytesUnknown ?? Array.Empty(); diff --git a/src/System.Private.CoreLib/shared/System/Text/DecoderNLS.cs b/src/System.Private.CoreLib/shared/System/Text/DecoderNLS.cs index 7e627fd..5b0247a 100644 --- a/src/System.Private.CoreLib/shared/System/Text/DecoderNLS.cs +++ b/src/System.Private.CoreLib/shared/System/Text/DecoderNLS.cs @@ -398,7 +398,6 @@ namespace System.Text // opportunity for any code before us to make forward progress, so we must fail immediately. _encoding.ThrowCharsOverflow(this, nothingDecoded: true); - // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 throw null!; // will never reach this point } diff --git a/src/System.Private.CoreLib/shared/System/Text/DecoderReplacementFallback.cs b/src/System.Private.CoreLib/shared/System/Text/DecoderReplacementFallback.cs index 57413ec..beb58e0 100644 --- a/src/System.Private.CoreLib/shared/System/Text/DecoderReplacementFallback.cs +++ b/src/System.Private.CoreLib/shared/System/Text/DecoderReplacementFallback.cs @@ -109,7 +109,6 @@ namespace System.Text // Construction public DecoderReplacementFallbackBuffer(DecoderReplacementFallback fallback) { - // TODO-NULLABLE: NullReferenceException (fallback) _strDefault = fallback.DefaultString; } diff --git a/src/System.Private.CoreLib/shared/System/Text/EncoderBestFitFallback.cs b/src/System.Private.CoreLib/shared/System/Text/EncoderBestFitFallback.cs index dddb1d5..518ceb7 100644 --- a/src/System.Private.CoreLib/shared/System/Text/EncoderBestFitFallback.cs +++ b/src/System.Private.CoreLib/shared/System/Text/EncoderBestFitFallback.cs @@ -72,7 +72,7 @@ namespace System.Text object o = new object(); Interlocked.CompareExchange(ref s_InternalSyncObject, o, null); } - return s_InternalSyncObject!; // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 + return s_InternalSyncObject!; // TODO-NULLABLE: Remove ! when compiler specially-recognizes CompareExchange for nullability } } diff --git a/src/System.Private.CoreLib/shared/System/Text/EncoderFallback.cs b/src/System.Private.CoreLib/shared/System/Text/EncoderFallback.cs index c3a03ab..8fa9e6d 100644 --- a/src/System.Private.CoreLib/shared/System/Text/EncoderFallback.cs +++ b/src/System.Private.CoreLib/shared/System/Text/EncoderFallback.cs @@ -4,6 +4,7 @@ using System.Buffers; using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.Threading; namespace System.Text @@ -22,7 +23,7 @@ namespace System.Text if (s_replacementFallback == null) Interlocked.CompareExchange(ref s_replacementFallback, new EncoderReplacementFallback(), null); - return s_replacementFallback!; // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 + return s_replacementFallback!; // TODO-NULLABLE: Remove ! when compiler specially-recognizes CompareExchange for nullability } } @@ -34,7 +35,7 @@ namespace System.Text if (s_exceptionFallback == null) Interlocked.CompareExchange(ref s_exceptionFallback, new EncoderExceptionFallback(), null); - return s_exceptionFallback!; // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 + return s_exceptionFallback!; // TODO-NULLABLE: Remove ! when compiler specially-recognizes CompareExchange for nullability } } @@ -376,6 +377,7 @@ namespace System.Text } // private helper methods + [DoesNotReturn] internal void ThrowLastCharRecursive(int charRecursive) { // Throw it, using our complete character diff --git a/src/System.Private.CoreLib/shared/System/Text/EncoderReplacementFallback.cs b/src/System.Private.CoreLib/shared/System/Text/EncoderReplacementFallback.cs index e124e41..99f0fe9 100644 --- a/src/System.Private.CoreLib/shared/System/Text/EncoderReplacementFallback.cs +++ b/src/System.Private.CoreLib/shared/System/Text/EncoderReplacementFallback.cs @@ -110,7 +110,6 @@ namespace System.Text // Construction public EncoderReplacementFallbackBuffer(EncoderReplacementFallback fallback) { - // TODO-NULLABLE: NullReferenceException // 2X in case we're a surrogate pair _strDefault = fallback.DefaultString + fallback.DefaultString; } diff --git a/src/System.Private.CoreLib/shared/System/Text/Encoding.cs b/src/System.Private.CoreLib/shared/System/Text/Encoding.cs index ef7ba78..a1180a1 100644 --- a/src/System.Private.CoreLib/shared/System/Text/Encoding.cs +++ b/src/System.Private.CoreLib/shared/System/Text/Encoding.cs @@ -3,6 +3,7 @@ // See the LICENSE file in the project root for more information. using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.Runtime.InteropServices; using System.Runtime.Serialization; @@ -1181,6 +1182,7 @@ namespace System.Text return Array.Empty(); } + [DoesNotReturn] internal void ThrowBytesOverflow() { // Special message to include fallback type in case fallback's GetMaxCharCount is broken @@ -1204,12 +1206,15 @@ namespace System.Text encoder!.ClearMustFlush(); } + [DoesNotReturn] [StackTraceHidden] internal static void ThrowConversionOverflow() { throw new ArgumentException(SR.Argument_ConversionOverflow); } + [DoesNotReturn] + [StackTraceHidden] internal void ThrowCharsOverflow() { // Special message to include fallback type in case fallback's GetMaxCharCount is broken diff --git a/src/System.Private.CoreLib/shared/System/Text/EncodingData.cs b/src/System.Private.CoreLib/shared/System/Text/EncodingData.cs index 8a9d2a5..01837fc 100644 --- a/src/System.Private.CoreLib/shared/System/Text/EncodingData.cs +++ b/src/System.Private.CoreLib/shared/System/Text/EncodingData.cs @@ -6,7 +6,6 @@ // https://github.com/dotnet/buildtools/blob/6736870b84e06b75e7df32bb84d442db1b2afa10/src/Microsoft.DotNet.Build.Tasks/PackageFiles/encoding.targets // -// TODO-NULLABLE: We should edit original source instead: https://github.com/dotnet/buildtools/blob/master/src/Microsoft.DotNet.Build.Tasks/GenerateEncodingTable.cs#L235 namespace System.Text { internal static partial class EncodingTable diff --git a/src/System.Private.CoreLib/shared/System/Text/EncodingTable.cs b/src/System.Private.CoreLib/shared/System/Text/EncodingTable.cs index 6616227..4c0bd4a 100644 --- a/src/System.Private.CoreLib/shared/System/Text/EncodingTable.cs +++ b/src/System.Private.CoreLib/shared/System/Text/EncodingTable.cs @@ -159,7 +159,7 @@ namespace System.Text return null; } - CodePageDataItem? data = s_codePageToCodePageData![index]; // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 + CodePageDataItem? data = s_codePageToCodePageData![index]; // TODO-NULLABLE: Remove ! when compiler specially-recognizes CompareExchange for nullability if (data == null) { Interlocked.CompareExchange(ref s_codePageToCodePageData[index], InternalGetCodePageDataItem(codePage, index), null); diff --git a/src/System.Private.CoreLib/shared/System/Text/StringBuilder.cs b/src/System.Private.CoreLib/shared/System/Text/StringBuilder.cs index ec9d2c4..e55e4a5 100644 --- a/src/System.Private.CoreLib/shared/System/Text/StringBuilder.cs +++ b/src/System.Private.CoreLib/shared/System/Text/StringBuilder.cs @@ -637,7 +637,7 @@ namespace System.Text ThrowHelper.ThrowInvalidOperationException_InvalidOperation_EnumOpCantHappen(); } - return new ReadOnlyMemory(_currentChunk!.m_ChunkChars, 0, _currentChunk.m_ChunkLength); // TODO-NULLABLE: https://github.com/dotnet/csharplang#538 + return new ReadOnlyMemory(_currentChunk!.m_ChunkChars, 0, _currentChunk.m_ChunkLength); // TODO-NULLABLE: Remove ! when [DoesNotReturn] respected } } @@ -1335,7 +1335,7 @@ namespace System.Text if (values[0] != null) { - Append(values[0]!.ToString()); // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/34644 + Append(values[0]!.ToString()); // TODO-NULLABLE: Indexer nullability tracked (https://github.com/dotnet/roslyn/issues/34644) } for (int i = 1; i < values.Length; i++) @@ -1343,7 +1343,7 @@ namespace System.Text Append(separator, separatorLength); if (values[i] != null) { - Append(values[i]!.ToString()); // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/34644 + Append(values[i]!.ToString()); // TODO-NULLABLE: Indexer nullability tracked (https://github.com/dotnet/roslyn/issues/34644) } } return this; @@ -1905,9 +1905,9 @@ namespace System.Text } else if (replacementsCount >= replacements.Length) { - Array.Resize(ref replacements!, replacements.Length * 3 / 2 + 4); // Grow by ~1.5x, but more in the begining // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 + Array.Resize(ref replacements!, replacements.Length * 3 / 2 + 4); // Grow by ~1.5x, but more in the begining // TODO-NULLABLE: Remove ! when nullable attributes are respected } - replacements![replacementsCount++] = indexInChunk; // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 + replacements![replacementsCount++] = indexInChunk; // TODO-NULLABLE: Remove ! when nullable attributes are respected indexInChunk += oldValue.Length; count -= oldValue.Length; } diff --git a/src/System.Private.CoreLib/shared/System/Text/StringRuneEnumerator.cs b/src/System.Private.CoreLib/shared/System/Text/StringRuneEnumerator.cs index 99001f7..37c45db 100644 --- a/src/System.Private.CoreLib/shared/System/Text/StringRuneEnumerator.cs +++ b/src/System.Private.CoreLib/shared/System/Text/StringRuneEnumerator.cs @@ -50,7 +50,7 @@ namespace System.Text return true; } - object? IEnumerator.Current => _current; // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/23268 + object? IEnumerator.Current => _current; void IDisposable.Dispose() { diff --git a/src/System.Private.CoreLib/shared/System/Text/UTF32Encoding.cs b/src/System.Private.CoreLib/shared/System/Text/UTF32Encoding.cs index 1fc50d2..cc733ef 100644 --- a/src/System.Private.CoreLib/shared/System/Text/UTF32Encoding.cs +++ b/src/System.Private.CoreLib/shared/System/Text/UTF32Encoding.cs @@ -519,7 +519,7 @@ namespace System.Text // We mustn't have left over fallback data when not converting if (encoder._throwOnOverflow && fallbackBuffer.Remaining > 0) - throw new ArgumentException(SR.Format(SR.Argument_EncoderFallbackNotEmpty, this.EncodingName, encoder.Fallback!.GetType())); // TODO-NULLABLE: NullReferenceException + throw new ArgumentException(SR.Format(SR.Argument_EncoderFallbackNotEmpty, this.EncodingName, encoder.Fallback?.GetType())); } else { diff --git a/src/System.Private.CoreLib/shared/System/Text/UTF8Encoding.cs b/src/System.Private.CoreLib/shared/System/Text/UTF8Encoding.cs index 5a33c6d..89bd8c5 100644 --- a/src/System.Private.CoreLib/shared/System/Text/UTF8Encoding.cs +++ b/src/System.Private.CoreLib/shared/System/Text/UTF8Encoding.cs @@ -138,7 +138,7 @@ namespace System.Text ThrowHelper.ThrowArgumentOutOfRangeException((index < 0) ? ExceptionArgument.index : ExceptionArgument.count, ExceptionResource.ArgumentOutOfRange_NeedNonNegNum); } - if (chars!.Length - index < count) // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 + if (chars!.Length - index < count) // TODO-NULLABLE: Remove ! when [DoesNotReturn] respected { ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.chars, ExceptionResource.ArgumentOutOfRange_IndexCountBuffer); } @@ -165,7 +165,7 @@ namespace System.Text fixed (char* pChars = chars) { - return GetByteCountCommon(pChars, chars!.Length); // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 + return GetByteCountCommon(pChars, chars!.Length); // TODO-NULLABLE: Remove ! when [DoesNotReturn] respected } } @@ -275,12 +275,12 @@ namespace System.Text resource: ExceptionResource.ArgumentOutOfRange_NeedNonNegNum); } - if (s!.Length - charIndex < charCount) // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 + if (s!.Length - charIndex < charCount) // TODO-NULLABLE: Remove ! when [DoesNotReturn] respected { ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.s, ExceptionResource.ArgumentOutOfRange_IndexCount); } - if ((uint)byteIndex > bytes!.Length) // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 + if ((uint)byteIndex > bytes!.Length) // TODO-NULLABLE: Remove ! when [DoesNotReturn] respected { ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.byteIndex, ExceptionResource.ArgumentOutOfRange_Index); } @@ -325,12 +325,12 @@ namespace System.Text resource: ExceptionResource.ArgumentOutOfRange_NeedNonNegNum); } - if (chars!.Length - charIndex < charCount) // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 + if (chars!.Length - charIndex < charCount) // TODO-NULLABLE: Remove ! when [DoesNotReturn] respected { ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.chars, ExceptionResource.ArgumentOutOfRange_IndexCount); } - if ((uint)byteIndex > bytes!.Length) // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 + if ((uint)byteIndex > bytes!.Length) // TODO-NULLABLE: Remove ! when [DoesNotReturn] respected { ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.byteIndex, ExceptionResource.ArgumentOutOfRange_Index); } @@ -443,7 +443,7 @@ namespace System.Text ThrowHelper.ThrowArgumentOutOfRangeException((index < 0) ? ExceptionArgument.index : ExceptionArgument.count, ExceptionResource.ArgumentOutOfRange_NeedNonNegNum); } - if (bytes!.Length - index < count) // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 + if (bytes!.Length - index < count) // TODO-NULLABLE: Remove ! when [DoesNotReturn] respected { ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.bytes, ExceptionResource.ArgumentOutOfRange_IndexCountBuffer); } @@ -510,12 +510,12 @@ namespace System.Text resource: ExceptionResource.ArgumentOutOfRange_NeedNonNegNum); } - if (bytes!.Length - byteIndex < byteCount) // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 + if (bytes!.Length - byteIndex < byteCount) // TODO-NULLABLE: Remove ! when [DoesNotReturn] respected { ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.bytes, ExceptionResource.ArgumentOutOfRange_IndexCountBuffer); } - if ((uint)charIndex > (uint)chars!.Length) // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 + if ((uint)charIndex > (uint)chars!.Length) // TODO-NULLABLE: Remove ! when [DoesNotReturn] respected { ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.charIndex, ExceptionResource.ArgumentOutOfRange_Index); } @@ -672,7 +672,7 @@ namespace System.Text resource: ExceptionResource.ArgumentOutOfRange_NeedNonNegNum); } - if (bytes!.Length - index < count) // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 + if (bytes!.Length - index < count) // TODO-NULLABLE: Remove ! when [DoesNotReturn] respected { ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.bytes, ExceptionResource.ArgumentOutOfRange_IndexCountBuffer); } diff --git a/src/System.Private.CoreLib/shared/System/Text/Unicode/Utf8Utility.cs b/src/System.Private.CoreLib/shared/System/Text/Unicode/Utf8Utility.cs index 7daf0cf..5c8a409 100644 --- a/src/System.Private.CoreLib/shared/System/Text/Unicode/Utf8Utility.cs +++ b/src/System.Private.CoreLib/shared/System/Text/Unicode/Utf8Utility.cs @@ -4,6 +4,7 @@ using System.Buffers; using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.IO; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; @@ -50,6 +51,7 @@ namespace System.Text.Unicode /// but where all invalid UTF-8 sequences have been replaced /// with U+FFD. /// + [return: NotNullIfNotNull("value")] public static Utf8String? ValidateAndFixupUtf8String(Utf8String? value) { if (Utf8String.IsNullOrEmpty(value)) diff --git a/src/System.Private.CoreLib/shared/System/Text/UnicodeEncoding.cs b/src/System.Private.CoreLib/shared/System/Text/UnicodeEncoding.cs index d541f65..f153f03 100644 --- a/src/System.Private.CoreLib/shared/System/Text/UnicodeEncoding.cs +++ b/src/System.Private.CoreLib/shared/System/Text/UnicodeEncoding.cs @@ -390,7 +390,7 @@ namespace System.Text { fallbackBuffer = encoder.FallbackBuffer; if (fallbackBuffer.Remaining > 0) - throw new ArgumentException(SR.Format(SR.Argument_EncoderFallbackNotEmpty, this.EncodingName, encoder.Fallback!.GetType())); // TODO-NULLABLE: NullReferenceException + throw new ArgumentException(SR.Format(SR.Argument_EncoderFallbackNotEmpty, this.EncodingName, encoder.Fallback?.GetType())); // Set our internal fallback interesting things. fallbackBuffer.InternalInitialize(charStart, charEnd, encoder, false); @@ -679,7 +679,7 @@ namespace System.Text // We always need the fallback buffer in get bytes so we can flush any remaining ones if necessary fallbackBuffer = encoder.FallbackBuffer; if (fallbackBuffer.Remaining > 0 && encoder._throwOnOverflow) - throw new ArgumentException(SR.Format(SR.Argument_EncoderFallbackNotEmpty, this.EncodingName, encoder.Fallback!.GetType())); // TODO-NULLABLE: NullReferenceException + throw new ArgumentException(SR.Format(SR.Argument_EncoderFallbackNotEmpty, this.EncodingName, encoder.Fallback?.GetType())); // Set our internal fallback interesting things. fallbackBuffer.InternalInitialize(charStart, charEnd, encoder, false); diff --git a/src/System.Private.CoreLib/shared/System/Text/ValueStringBuilder.cs b/src/System.Private.CoreLib/shared/System/Text/ValueStringBuilder.cs index 5c95e29f..de7fc50 100644 --- a/src/System.Private.CoreLib/shared/System/Text/ValueStringBuilder.cs +++ b/src/System.Private.CoreLib/shared/System/Text/ValueStringBuilder.cs @@ -83,9 +83,7 @@ namespace System.Text } } -#pragma warning disable CS8609 // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/23268 public override string ToString() -#pragma warning restore CS8609 { var s = _chars.Slice(0, _pos).ToString(); Dispose(); diff --git a/src/System.Private.CoreLib/shared/System/Threading/AsyncLocal.cs b/src/System.Private.CoreLib/shared/System/Threading/AsyncLocal.cs index a61af6d..cf279ac 100644 --- a/src/System.Private.CoreLib/shared/System/Threading/AsyncLocal.cs +++ b/src/System.Private.CoreLib/shared/System/Threading/AsyncLocal.cs @@ -4,6 +4,7 @@ using System.Collections.Generic; using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; namespace System.Threading { @@ -56,12 +57,13 @@ namespace System.Threading m_valueChangedHandler = valueChangedHandler; } + [MaybeNull] public T Value { get { object? obj = ExecutionContext.GetLocalValue(this); - return (obj == null) ? default! : (T)obj; // TODO-NULLABLE-GENERIC + return (obj == null) ? default! : (T)obj; // TODO-NULLABLE: Remove ! when nullable attributes are respected } set { @@ -72,8 +74,8 @@ namespace System.Threading void IAsyncLocal.OnValueChanged(object? previousValueObj, object? currentValueObj, bool contextChanged) { Debug.Assert(m_valueChangedHandler != null); - T previousValue = previousValueObj == null ? default! : (T)previousValueObj; // TODO-NULLABLE-GENERIC - T currentValue = currentValueObj == null ? default! : (T)currentValueObj; // TODO-NULLABLE-GENERIC + T previousValue = previousValueObj == null ? default! : (T)previousValueObj; + T currentValue = currentValueObj == null ? default! : (T)currentValueObj; m_valueChangedHandler(new AsyncLocalValueChangedArgs(previousValue, currentValue, contextChanged)); } } @@ -88,8 +90,8 @@ namespace System.Threading public readonly struct AsyncLocalValueChangedArgs { - public T PreviousValue { get; } - public T CurrentValue { get; } + [MaybeNull] public T PreviousValue { get; } + [MaybeNull] public T CurrentValue { get; } // // If the value changed because we changed to a different ExecutionContext, this is true. If it changed @@ -97,7 +99,7 @@ namespace System.Threading // public bool ThreadContextChanged { get; } - internal AsyncLocalValueChangedArgs(T previousValue, T currentValue, bool contextChanged) + internal AsyncLocalValueChangedArgs([AllowNull] T previousValue, [AllowNull] T currentValue, bool contextChanged) { PreviousValue = previousValue; CurrentValue = currentValue; diff --git a/src/System.Private.CoreLib/shared/System/Threading/CancellationToken.cs b/src/System.Private.CoreLib/shared/System/Threading/CancellationToken.cs index 769b4e0..42d54f6 100644 --- a/src/System.Private.CoreLib/shared/System/Threading/CancellationToken.cs +++ b/src/System.Private.CoreLib/shared/System/Threading/CancellationToken.cs @@ -3,6 +3,7 @@ // See the LICENSE file in the project root for more information. using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; namespace System.Threading { @@ -348,6 +349,7 @@ namespace System.Threading } // Throws an OCE; separated out to enable better inlining of ThrowIfCancellationRequested + [DoesNotReturn] private void ThrowOperationCanceledException() => throw new OperationCanceledException(SR.OperationCanceled, this); } diff --git a/src/System.Private.CoreLib/shared/System/Threading/CancellationTokenSource.cs b/src/System.Private.CoreLib/shared/System/Threading/CancellationTokenSource.cs index 02ab1c4..4c17056 100644 --- a/src/System.Private.CoreLib/shared/System/Threading/CancellationTokenSource.cs +++ b/src/System.Private.CoreLib/shared/System/Threading/CancellationTokenSource.cs @@ -4,6 +4,7 @@ using System.Collections.Generic; using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.Threading.Tasks; namespace System.Threading @@ -132,10 +133,10 @@ namespace System.Threading // 2. if IsCancellationRequested = false, then NotifyCancellation will see that the event exists, and will call Set(). if (IsCancellationRequested) { - _kernelEvent!.Set(); // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 + _kernelEvent!.Set(); // TODO-NULLABLE: Remove ! when compiler specially-recognizes CompareExchange for nullability } - return _kernelEvent!; // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 + return _kernelEvent!; // TODO-NULLABLE: Remove ! when compiler specially-recognizes CompareExchange for nullability } } @@ -466,6 +467,7 @@ namespace System.Threading } /// Throws an . Separated out from ThrowIfDisposed to help with inlining. + [DoesNotReturn] private static void ThrowObjectDisposedException() => throw new ObjectDisposedException(null, SR.CancellationTokenSource_Disposed); diff --git a/src/System.Private.CoreLib/shared/System/Threading/EventWaitHandle.Windows.cs b/src/System.Private.CoreLib/shared/System/Threading/EventWaitHandle.Windows.cs index 7241d61..87971df 100644 --- a/src/System.Private.CoreLib/shared/System/Threading/EventWaitHandle.Windows.cs +++ b/src/System.Private.CoreLib/shared/System/Threading/EventWaitHandle.Windows.cs @@ -76,7 +76,7 @@ namespace System.Threading public bool Reset() { - bool res = Interop.Kernel32.ResetEvent(SafeWaitHandle!); // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/2384 + bool res = Interop.Kernel32.ResetEvent(SafeWaitHandle); if (!res) throw Win32Marshal.GetExceptionForLastWin32Error(); return res; @@ -84,7 +84,7 @@ namespace System.Threading public bool Set() { - bool res = Interop.Kernel32.SetEvent(SafeWaitHandle!); // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/2384 + bool res = Interop.Kernel32.SetEvent(SafeWaitHandle); if (!res) throw Win32Marshal.GetExceptionForLastWin32Error(); return res; diff --git a/src/System.Private.CoreLib/shared/System/Threading/EventWaitHandle.cs b/src/System.Private.CoreLib/shared/System/Threading/EventWaitHandle.cs index bafa736..96c2ef8 100644 --- a/src/System.Private.CoreLib/shared/System/Threading/EventWaitHandle.cs +++ b/src/System.Private.CoreLib/shared/System/Threading/EventWaitHandle.cs @@ -3,6 +3,7 @@ // See the LICENSE file in the project root for more information. using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.IO; namespace System.Threading @@ -44,7 +45,7 @@ namespace System.Threading } } - public static bool TryOpenExisting(string name, out EventWaitHandle? result) // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 + public static bool TryOpenExisting(string name, [NotNullWhen(true)] out EventWaitHandle? result) { return OpenExistingWorker(name, out result) == OpenExistingResult.Success; } diff --git a/src/System.Private.CoreLib/shared/System/Threading/ExecutionContext.cs b/src/System.Private.CoreLib/shared/System/Threading/ExecutionContext.cs index 64f2f18..c1cae56 100644 --- a/src/System.Private.CoreLib/shared/System/Threading/ExecutionContext.cs +++ b/src/System.Private.CoreLib/shared/System/Threading/ExecutionContext.cs @@ -12,6 +12,7 @@ ===========================================================*/ using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.Runtime.CompilerServices; using System.Runtime.ExceptionServices; using System.Runtime.Serialization; @@ -393,8 +394,8 @@ namespace System.Threading if (previousChangeNotifications != null && nextChangeNotifications != null) { // Notifications can't exist without values - Debug.Assert(previousExecutionCtx!.m_localValues != null); // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/2388 - Debug.Assert(nextExecutionCtx!.m_localValues != null); // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/2388 + Debug.Assert(previousExecutionCtx!.m_localValues != null); + Debug.Assert(nextExecutionCtx!.m_localValues != null); // Both contexts have change notifications, check previousExecutionCtx first foreach (IAsyncLocal local in previousChangeNotifications) { @@ -428,7 +429,7 @@ namespace System.Threading else if (previousChangeNotifications != null) { // Notifications can't exist without values - Debug.Assert(previousExecutionCtx!.m_localValues != null); // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/2388 + Debug.Assert(previousExecutionCtx!.m_localValues != null); // No current values, so just check previous against null foreach (IAsyncLocal local in previousChangeNotifications) { @@ -442,9 +443,9 @@ namespace System.Threading else // Implied: nextChangeNotifications != null { // Notifications can't exist without values - Debug.Assert(nextExecutionCtx!.m_localValues != null); // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/2388 + Debug.Assert(nextExecutionCtx!.m_localValues != null); // No previous values, so just check current against null - foreach (IAsyncLocal local in nextChangeNotifications!) // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/2388 + foreach (IAsyncLocal local in nextChangeNotifications!) { nextExecutionCtx.m_localValues.TryGetValue(local, out object? currentValue); if (currentValue != null) @@ -462,6 +463,7 @@ namespace System.Threading } } + [DoesNotReturn] [StackTraceHidden] private static void ThrowNullContext() { @@ -544,7 +546,7 @@ namespace System.Threading { int newNotificationIndex = newChangeNotifications.Length; Array.Resize(ref newChangeNotifications, newNotificationIndex + 1); - newChangeNotifications![newNotificationIndex] = local; // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 + newChangeNotifications![newNotificationIndex] = local; // TODO-NULLABLE: Remove ! when nullable attributes are respected } } diff --git a/src/System.Private.CoreLib/shared/System/Threading/LazyInitializer.cs b/src/System.Private.CoreLib/shared/System/Threading/LazyInitializer.cs index 5ae8415..51e45c1 100644 --- a/src/System.Private.CoreLib/shared/System/Threading/LazyInitializer.cs +++ b/src/System.Private.CoreLib/shared/System/Threading/LazyInitializer.cs @@ -9,6 +9,7 @@ // =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; namespace System.Threading { @@ -47,7 +48,7 @@ namespace System.Threading /// if an object was not used and to then dispose of the object appropriately. /// /// - public static T EnsureInitialized(ref T target) where T : class? => + public static T EnsureInitialized([AllowNull] ref T target) where T : class => Volatile.Read(ref target) ?? EnsureInitializedCore(ref target); /// @@ -56,11 +57,11 @@ namespace System.Threading /// The reference type of the reference to be initialized. /// The variable that need to be initialized /// The initialized variable - private static T EnsureInitializedCore(ref T target) where T : class? + private static T EnsureInitializedCore([AllowNull] ref T target) where T : class { try { - Interlocked.CompareExchange(ref target, Activator.CreateInstance(), null!); // TODO-NULLABLE-GENERIC + Interlocked.CompareExchange(ref target, Activator.CreateInstance(), null!); } catch (MissingMethodException) { @@ -99,7 +100,7 @@ namespace System.Threading /// if an object was not used and to then dispose of the object appropriately. /// /// - public static T EnsureInitialized(ref T target, Func valueFactory) where T : class? => + public static T EnsureInitialized([AllowNull] ref T target, Func valueFactory) where T : class => Volatile.Read(ref target) ?? EnsureInitializedCore(ref target, valueFactory); /// @@ -109,7 +110,7 @@ namespace System.Threading /// The variable that need to be initialized /// The delegate that will be executed to initialize the target /// The initialized variable - private static T EnsureInitializedCore(ref T target, Func valueFactory) where T : class? + private static T EnsureInitializedCore([AllowNull] ref T target, Func valueFactory) where T : class { T value = valueFactory(); if (value == null) @@ -117,7 +118,7 @@ namespace System.Threading throw new InvalidOperationException(SR.Lazy_StaticInit_InvalidOperation); } - Interlocked.CompareExchange(ref target, value, null!); // TODO-NULLABLE-GENERIC + Interlocked.CompareExchange(ref target, value, null!); Debug.Assert(target != null); return target; } @@ -134,7 +135,7 @@ namespace System.Threading /// A reference to an object used as the mutually exclusive lock for initializing /// . If is null, a new object will be instantiated. /// The initialized value of type . - public static T EnsureInitialized(ref T target, ref bool initialized, ref object? syncLock) + public static T EnsureInitialized([AllowNull] ref T target, ref bool initialized, ref object? syncLock) { // Fast path. if (Volatile.Read(ref initialized)) @@ -156,7 +157,7 @@ namespace System.Threading /// a new object will be instantiated. /// /// The initialized object. - private static T EnsureInitializedCore(ref T target, ref bool initialized, ref object? syncLock) + private static T EnsureInitializedCore([AllowNull] ref T target, ref bool initialized, ref object? syncLock) { // Lazily initialize the lock if necessary and then double check if initialization is still required. lock (EnsureLockInitialized(ref syncLock)) @@ -193,7 +194,7 @@ namespace System.Threading /// The invoked to initialize the /// reference or value. /// The initialized value of type . - public static T EnsureInitialized(ref T target, ref bool initialized, ref object? syncLock, Func valueFactory) + public static T EnsureInitialized([AllowNull] ref T target, ref bool initialized, ref object? syncLock, Func valueFactory) { // Fast path. if (Volatile.Read(ref initialized)) @@ -217,7 +218,7 @@ namespace System.Threading /// The to invoke in order to produce the lazily-initialized value. /// /// The initialized object. - private static T EnsureInitializedCore(ref T target, ref bool initialized, ref object? syncLock, Func valueFactory) + private static T EnsureInitializedCore([AllowNull] ref T target, ref bool initialized, ref object? syncLock, Func valueFactory) { // Lazily initialize the lock if necessary and then double check if initialization is still required. lock (EnsureLockInitialized(ref syncLock)) @@ -241,7 +242,7 @@ namespace System.Threading /// . If is null, a new object will be instantiated. /// The invoked to initialize the reference. /// The initialized value of type . - public static T EnsureInitialized(ref T target, ref object? syncLock, Func valueFactory) where T : class? => + public static T EnsureInitialized([AllowNull] ref T target, ref object? syncLock, Func valueFactory) where T : class => Volatile.Read(ref target) ?? EnsureInitializedCore(ref target, ref syncLock, valueFactory); /// @@ -256,7 +257,7 @@ namespace System.Threading /// The to invoke in order to produce the lazily-initialized value. /// /// The initialized object. - private static T EnsureInitializedCore(ref T target, ref object? syncLock, Func valueFactory) where T : class? + private static T EnsureInitializedCore([AllowNull] ref T target, ref object? syncLock, Func valueFactory) where T : class { // Lazily initialize the lock if necessary and then double check if initialization is still required. lock (EnsureLockInitialized(ref syncLock)) @@ -283,6 +284,6 @@ namespace System.Threading private static object EnsureLockInitialized(ref object? syncLock) => syncLock ?? Interlocked.CompareExchange(ref syncLock, new object(), null) ?? - syncLock!; // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 + syncLock!; // TODO-NULLABLE: Remove ! when compiler specially-recognizes CompareExchange for nullability } } diff --git a/src/System.Private.CoreLib/shared/System/Threading/Mutex.Windows.cs b/src/System.Private.CoreLib/shared/System/Threading/Mutex.Windows.cs index 6d89a5e..7226538 100644 --- a/src/System.Private.CoreLib/shared/System/Threading/Mutex.Windows.cs +++ b/src/System.Private.CoreLib/shared/System/Threading/Mutex.Windows.cs @@ -88,7 +88,7 @@ namespace System.Threading // in a Mutex's ACL is MUTEX_ALL_ACCESS (0x1F0001). public void ReleaseMutex() { - if (!Interop.Kernel32.ReleaseMutex(SafeWaitHandle!)) // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/2384 + if (!Interop.Kernel32.ReleaseMutex(SafeWaitHandle)) { throw new ApplicationException(SR.Arg_SynchronizationLockException); } diff --git a/src/System.Private.CoreLib/shared/System/Threading/Mutex.cs b/src/System.Private.CoreLib/shared/System/Threading/Mutex.cs index 50cd42a..2d8313c 100644 --- a/src/System.Private.CoreLib/shared/System/Threading/Mutex.cs +++ b/src/System.Private.CoreLib/shared/System/Threading/Mutex.cs @@ -2,11 +2,12 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using System.IO; using Microsoft.Win32; using Microsoft.Win32.SafeHandles; -using System.Runtime.InteropServices; using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; +using System.IO; +using System.Runtime.InteropServices; namespace System.Threading { @@ -57,7 +58,7 @@ namespace System.Threading } } - public static bool TryOpenExisting(string name, out Mutex? result) => // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 + public static bool TryOpenExisting(string name, [NotNullWhen(true)] out Mutex? result) => OpenExistingWorker(name, out result) == OpenExistingResult.Success; } } diff --git a/src/System.Private.CoreLib/shared/System/Threading/ReaderWriterLockSlim.cs b/src/System.Private.CoreLib/shared/System/Threading/ReaderWriterLockSlim.cs index f05ef52..47f26ef 100644 --- a/src/System.Private.CoreLib/shared/System/Threading/ReaderWriterLockSlim.cs +++ b/src/System.Private.CoreLib/shared/System/Threading/ReaderWriterLockSlim.cs @@ -3,6 +3,7 @@ // See the LICENSE file in the project root for more information. using System.Diagnostics; // for TraceInformation +using System.Diagnostics.CodeAnalysis; using System.Runtime.CompilerServices; namespace System.Threading @@ -195,7 +196,7 @@ namespace System.Threading /// could not be found. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - private ReaderWriterCount? GetThreadRWCount(bool dontAllocate) // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 + private ReaderWriterCount? GetThreadRWCount(bool dontAllocate) { ReaderWriterCount? rwc = t_rwc; ReaderWriterCount? empty = null; @@ -318,7 +319,7 @@ namespace System.Threading _spinLock.Enter(EnterSpinLockReason.EnterAnyRead); - lrwc = GetThreadRWCount(dontAllocate: false)!; // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 + lrwc = GetThreadRWCount(dontAllocate: false)!; //Check if the reader lock is already acquired. Note, we could //check the presence of a reader by not allocating rwc (But that @@ -343,7 +344,7 @@ namespace System.Threading else { _spinLock.Enter(EnterSpinLockReason.EnterAnyRead); - lrwc = GetThreadRWCount(dontAllocate: false)!; // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 + lrwc = GetThreadRWCount(dontAllocate: false)!; if (lrwc.readercount > 0) { lrwc.readercount++; @@ -401,7 +402,7 @@ namespace System.Threading _spinLock.Enter(EnterSpinLockReason.EnterAnyRead); //The per-thread structure may have been recycled as the lock is acquired (due to message pumping), load again. if (IsRwHashEntryChanged(lrwc)) - lrwc = GetThreadRWCount(dontAllocate: false)!; // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 + lrwc = GetThreadRWCount(dontAllocate: false)!; continue; } @@ -410,7 +411,7 @@ namespace System.Threading { LazyCreateEvent(ref _readEvent, EnterLockType.Read); if (IsRwHashEntryChanged(lrwc)) - lrwc = GetThreadRWCount(dontAllocate: false)!; // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 + lrwc = GetThreadRWCount(dontAllocate: false)!; continue; // since we left the lock, start over. } @@ -420,7 +421,7 @@ namespace System.Threading return false; } if (IsRwHashEntryChanged(lrwc)) - lrwc = GetThreadRWCount(dontAllocate: false)!; // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 + lrwc = GetThreadRWCount(dontAllocate: false)!; } _spinLock.Exit(); @@ -502,7 +503,7 @@ namespace System.Threading } _spinLock.Enter(enterMyLockReason); - lrwc = GetThreadRWCount(dontAllocate: false)!; // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 + lrwc = GetThreadRWCount(dontAllocate: false)!; if (id == _writeLockOwnerId) { @@ -555,7 +556,7 @@ namespace System.Threading if (lrwc != null) { if (IsRwHashEntryChanged(lrwc)) - lrwc = GetThreadRWCount(dontAllocate: false)!; // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 + lrwc = GetThreadRWCount(dontAllocate: false)!; if (lrwc.readercount > 0) { @@ -624,7 +625,7 @@ namespace System.Threading { Debug.Assert(lrwc != null, "Initialized based on _fIsReentrant earlier in the method"); if (IsRwHashEntryChanged(lrwc)) - lrwc = GetThreadRWCount(dontAllocate: false)!; // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 + lrwc = GetThreadRWCount(dontAllocate: false)!; lrwc.writercount++; } @@ -688,7 +689,7 @@ namespace System.Threading else { _spinLock.Enter(EnterSpinLockReason.EnterAnyRead); - lrwc = GetThreadRWCount(dontAllocate: false)!; // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 + lrwc = GetThreadRWCount(dontAllocate: false)!; if (id == _upgradeLockOwnerId) { @@ -767,7 +768,7 @@ namespace System.Threading //thread did not grab the entry. Debug.Assert(lrwc != null, "Initialized based on _fIsReentrant earlier in the method"); if (IsRwHashEntryChanged(lrwc)) - lrwc = GetThreadRWCount(dontAllocate: false)!; // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 + lrwc = GetThreadRWCount(dontAllocate: false)!; lrwc.upgradecount++; } @@ -829,7 +830,7 @@ namespace System.Threading else { _spinLock.Enter(EnterSpinLockReason.ExitAnyWrite); - lrwc = GetThreadRWCount(dontAllocate: false)!; // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 + lrwc = GetThreadRWCount(dontAllocate: false)!; if (lrwc == null) { @@ -913,7 +914,7 @@ namespace System.Threading /// while holding a spin lock). If all goes well, reenter the lock and /// set 'waitEvent' /// - private void LazyCreateEvent(ref EventWaitHandle? waitEvent, EnterLockType enterLockType) // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 + private void LazyCreateEvent([NotNull] ref EventWaitHandle? waitEvent, EnterLockType enterLockType) { #if DEBUG Debug.Assert(_spinLock.IsHeld); diff --git a/src/System.Private.CoreLib/shared/System/Threading/Semaphore.cs b/src/System.Private.CoreLib/shared/System/Threading/Semaphore.cs index a87405f..f012274 100644 --- a/src/System.Private.CoreLib/shared/System/Threading/Semaphore.cs +++ b/src/System.Private.CoreLib/shared/System/Threading/Semaphore.cs @@ -5,6 +5,7 @@ using Microsoft.Win32; using Microsoft.Win32.SafeHandles; using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.IO; using System.Runtime.InteropServices; @@ -52,7 +53,7 @@ namespace System.Threading } } - public static bool TryOpenExisting(string name, out Semaphore? result) => // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 + public static bool TryOpenExisting(string name, [NotNullWhen(true)] out Semaphore? result) => OpenExistingWorker(name, out result) == OpenExistingResult.Success; public int Release() => ReleaseCore(1); diff --git a/src/System.Private.CoreLib/shared/System/Threading/Tasks/ConcurrentExclusiveSchedulerPair.cs b/src/System.Private.CoreLib/shared/System/Threading/Tasks/ConcurrentExclusiveSchedulerPair.cs index 9065ae1..50014bf 100644 --- a/src/System.Private.CoreLib/shared/System/Threading/Tasks/ConcurrentExclusiveSchedulerPair.cs +++ b/src/System.Private.CoreLib/shared/System/Threading/Tasks/ConcurrentExclusiveSchedulerPair.cs @@ -152,7 +152,11 @@ namespace System.Threading.Tasks private CompletionState EnsureCompletionStateInitialized() { // ValueLock not needed, but it's ok if it's held - return LazyInitializer.EnsureInitialized(ref m_completionState!, () => new CompletionState()); // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 +#pragma warning disable CS8634 // TODO-NULLABLE: Remove warning disable when nullable attributes are respected +#pragma warning disable CS8603 // TODO-NULLABLE: Remove warning disable when nullable attributes are respected + return LazyInitializer.EnsureInitialized(ref m_completionState!, () => new CompletionState()); +#pragma warning restore CS8603 +#pragma warning restore CS8634 } /// Gets whether completion has been requested. @@ -297,7 +301,7 @@ namespace System.Threading.Tasks { try { - processingTask = new Task(thisPair => ((ConcurrentExclusiveSchedulerPair)thisPair!).ProcessExclusiveTasks(), this, // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 + processingTask = new Task(thisPair => ((ConcurrentExclusiveSchedulerPair)thisPair!).ProcessExclusiveTasks(), this, default, GetCreationOptionsForTask(fairly)); processingTask.Start(m_underlyingTaskScheduler); // When we call Start, if the underlying scheduler throws in QueueTask, TPL will fault the task and rethrow @@ -327,7 +331,7 @@ namespace System.Threading.Tasks { try { - processingTask = new Task(thisPair => ((ConcurrentExclusiveSchedulerPair)thisPair!).ProcessConcurrentTasks(), this, // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 + processingTask = new Task(thisPair => ((ConcurrentExclusiveSchedulerPair)thisPair!).ProcessConcurrentTasks(), this, default, GetCreationOptionsForTask(fairly)); processingTask.Start(m_underlyingTaskScheduler); // See above logic for why we use new + Start rather than StartNew } diff --git a/src/System.Private.CoreLib/shared/System/Threading/Tasks/Future.cs b/src/System.Private.CoreLib/shared/System/Threading/Tasks/Future.cs index c82372c..1a7899d 100644 --- a/src/System.Private.CoreLib/shared/System/Threading/Tasks/Future.cs +++ b/src/System.Private.CoreLib/shared/System/Threading/Tasks/Future.cs @@ -12,6 +12,7 @@ using System.Collections.Generic; using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.Runtime.CompilerServices; using System.Runtime.ExceptionServices; @@ -60,7 +61,8 @@ namespace System.Threading.Tasks [DebuggerDisplay("Id = {Id}, Status = {Status}, Method = {DebuggerDisplayMethodDescription}, Result = {DebuggerDisplayResultDescription}")] public class Task : Task { - internal TResult m_result = default!; // The value itself, if set. // TODO-NULLABLE-GENERIC + // The value itself, if set. + [MaybeNull] internal TResult m_result = default!; // TODO-NULLABLE: Remove ! when nullable attributes are respected private static readonly TaskFactory s_Factory = new TaskFactory(); @@ -95,7 +97,7 @@ namespace System.Threading.Tasks m_result = result; } - internal Task(bool canceled, TResult result, TaskCreationOptions creationOptions, CancellationToken ct) + internal Task(bool canceled, [AllowNull] TResult result, TaskCreationOptions creationOptions, CancellationToken ct) : base(canceled, creationOptions, ct) { if (!canceled) @@ -209,7 +211,7 @@ namespace System.Threading.Tasks /// /// The argument is null. /// - public Task(Func function, object? state) // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 + public Task(Func function, object? state) : this(function, state, null, default, TaskCreationOptions.None, InternalTaskOptions.None, null) { @@ -230,7 +232,7 @@ namespace System.Threading.Tasks /// The provided CancellationToken /// has already been disposed. /// - public Task(Func function, object? state, CancellationToken cancellationToken) // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 + public Task(Func function, object? state, CancellationToken cancellationToken) : this(function, state, null, cancellationToken, TaskCreationOptions.None, InternalTaskOptions.None, null) { @@ -255,7 +257,7 @@ namespace System.Threading.Tasks /// The argument specifies an invalid value for . /// - public Task(Func function, object? state, TaskCreationOptions creationOptions) // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 + public Task(Func function, object? state, TaskCreationOptions creationOptions) : this(function, state, Task.InternalCurrentIfAttached(creationOptions), default, creationOptions, InternalTaskOptions.None, null) { @@ -285,7 +287,7 @@ namespace System.Threading.Tasks /// The provided CancellationToken /// has already been disposed. /// - public Task(Func function, object? state, CancellationToken cancellationToken, TaskCreationOptions creationOptions) // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 + public Task(Func function, object? state, CancellationToken cancellationToken, TaskCreationOptions creationOptions) : this(function, state, Task.InternalCurrentIfAttached(creationOptions), cancellationToken, creationOptions, InternalTaskOptions.None, null) { @@ -337,7 +339,7 @@ namespace System.Threading.Tasks } // Create and schedule the future. - Task f = new Task(function!, parent, cancellationToken, creationOptions, internalOptions | InternalTaskOptions.QueuedByRuntime, scheduler); // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 + Task f = new Task(function!, parent, cancellationToken, creationOptions, internalOptions | InternalTaskOptions.QueuedByRuntime, scheduler); // TODO-NULLABLE: Remove ! when [DoesNotReturn] respected f.ScheduleAndStart(false); return f; @@ -357,7 +359,7 @@ namespace System.Threading.Tasks } // Create and schedule the future. - Task f = new Task(function!, state, parent, cancellationToken, creationOptions, internalOptions | InternalTaskOptions.QueuedByRuntime, scheduler); // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 + Task f = new Task(function!, state, parent, cancellationToken, creationOptions, internalOptions | InternalTaskOptions.QueuedByRuntime, scheduler); // TODO-NULLABLE: Remove ! when [DoesNotReturn] respected f.ScheduleAndStart(false); return f; @@ -383,7 +385,7 @@ namespace System.Threading.Tasks // internal helper function breaks out logic used by TaskCompletionSource - internal bool TrySetResult(TResult result) + internal bool TrySetResult([AllowNull] TResult result) { Debug.Assert(m_action == null, "Task.TrySetResult(): non-null m_action"); @@ -725,13 +727,13 @@ namespace System.Threading.Tasks out internalOptions); Task continuationTask = new ContinuationTaskFromResultTask( - this, continuationAction!, null, // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 + this, continuationAction!, null, // TODO-NULLABLE: Remove ! when [DoesNotReturn] respected creationOptions, internalOptions ); // Register the continuation. If synchronous execution is requested, this may // actually invoke the continuation before returning. - ContinueWithCore(continuationTask, scheduler!, cancellationToken, continuationOptions); // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 + ContinueWithCore(continuationTask, scheduler!, cancellationToken, continuationOptions); // TODO-NULLABLE: Remove ! when [DoesNotReturn] respected return continuationTask; } @@ -756,7 +758,7 @@ namespace System.Threading.Tasks /// /// The argument is null. /// - public Task ContinueWith(Action, object?> continuationAction, object? state) // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 + public Task ContinueWith(Action, object?> continuationAction, object? state) { return ContinueWith(continuationAction, state, TaskScheduler.Current, default, TaskContinuationOptions.None); } @@ -783,7 +785,7 @@ namespace System.Threading.Tasks /// The provided CancellationToken /// has already been disposed. /// - public Task ContinueWith(Action, object?> continuationAction, object? state, CancellationToken cancellationToken) // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 + public Task ContinueWith(Action, object?> continuationAction, object? state, CancellationToken cancellationToken) { return ContinueWith(continuationAction, state, TaskScheduler.Current, cancellationToken, TaskContinuationOptions.None); } @@ -812,7 +814,7 @@ namespace System.Threading.Tasks /// /// The argument is null. /// - public Task ContinueWith(Action, object?> continuationAction, object? state, TaskScheduler scheduler) // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 + public Task ContinueWith(Action, object?> continuationAction, object? state, TaskScheduler scheduler) { return ContinueWith(continuationAction, state, scheduler, default, TaskContinuationOptions.None); } @@ -846,7 +848,7 @@ namespace System.Threading.Tasks /// The argument specifies an invalid value for TaskContinuationOptions. /// - public Task ContinueWith(Action, object?> continuationAction, object? state, TaskContinuationOptions continuationOptions) // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 + public Task ContinueWith(Action, object?> continuationAction, object? state, TaskContinuationOptions continuationOptions) { return ContinueWith(continuationAction, state, TaskScheduler.Current, default, continuationOptions); } @@ -890,14 +892,14 @@ namespace System.Threading.Tasks /// The provided CancellationToken /// has already been disposed. /// - public Task ContinueWith(Action, object?> continuationAction, object? state, CancellationToken cancellationToken, // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 + public Task ContinueWith(Action, object?> continuationAction, object? state, CancellationToken cancellationToken, TaskContinuationOptions continuationOptions, TaskScheduler scheduler) { return ContinueWith(continuationAction, state, scheduler, cancellationToken, continuationOptions); } // Same as the above overload, only with a stack mark. - internal Task ContinueWith(Action, object?> continuationAction, object? state, TaskScheduler scheduler, CancellationToken cancellationToken, // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 + internal Task ContinueWith(Action, object?> continuationAction, object? state, TaskScheduler scheduler, CancellationToken cancellationToken, TaskContinuationOptions continuationOptions) { if (continuationAction == null) @@ -918,13 +920,13 @@ namespace System.Threading.Tasks out internalOptions); Task continuationTask = new ContinuationTaskFromResultTask( - this, continuationAction!, state, // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 + this, continuationAction!, state, // TODO-NULLABLE: Remove ! when [DoesNotReturn] respected creationOptions, internalOptions ); // Register the continuation. If synchronous execution is requested, this may // actually invoke the continuation before returning. - ContinueWithCore(continuationTask, scheduler!, cancellationToken, continuationOptions); // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 + ContinueWithCore(continuationTask, scheduler!, cancellationToken, continuationOptions); // TODO-NULLABLE: Remove ! when [DoesNotReturn] respected return continuationTask; } @@ -1134,13 +1136,13 @@ namespace System.Threading.Tasks out internalOptions); Task continuationFuture = new ContinuationResultTaskFromResultTask( - this, continuationFunction!, null, // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 + this, continuationFunction!, null, // TODO-NULLABLE: Remove ! when [DoesNotReturn] respected creationOptions, internalOptions ); // Register the continuation. If synchronous execution is requested, this may // actually invoke the continuation before returning. - ContinueWithCore(continuationFuture, scheduler!, cancellationToken, continuationOptions); // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 + ContinueWithCore(continuationFuture, scheduler!, cancellationToken, continuationOptions); // TODO-NULLABLE: Remove ! when [DoesNotReturn] respected return continuationFuture; } @@ -1357,13 +1359,13 @@ namespace System.Threading.Tasks out internalOptions); Task continuationFuture = new ContinuationResultTaskFromResultTask( - this, continuationFunction!, state, // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 + this, continuationFunction!, state, // TODO-NULLABLE: Remove ! when [DoesNotReturn] respected creationOptions, internalOptions ); // Register the continuation. If synchronous execution is requested, this may // actually invoke the continuation before returning. - ContinueWithCore(continuationFuture, scheduler!, cancellationToken, continuationOptions); // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 + ContinueWithCore(continuationFuture, scheduler!, cancellationToken, continuationOptions); // TODO-NULLABLE: Remove ! when [DoesNotReturn] respected return continuationFuture; } @@ -1384,7 +1386,7 @@ namespace System.Threading.Tasks m_task = task; } - public TResult Result { get { return m_task.Status == TaskStatus.RanToCompletion ? m_task.Result : default!; } } // TODO-NULLABLE-GENERIC + [MaybeNull] public TResult Result { get { return m_task.Status == TaskStatus.RanToCompletion ? m_task.Result : default!; } } public object? AsyncState { get { return m_task.AsyncState; } } public TaskCreationOptions CreationOptions { get { return m_task.CreationOptions; } } public Exception? Exception { get { return m_task.Exception; } } diff --git a/src/System.Private.CoreLib/shared/System/Threading/Tasks/FutureFactory.cs b/src/System.Private.CoreLib/shared/System/Threading/Tasks/FutureFactory.cs index e8be5bd..139e32f 100644 --- a/src/System.Private.CoreLib/shared/System/Threading/Tasks/FutureFactory.cs +++ b/src/System.Private.CoreLib/shared/System/Threading/Tasks/FutureFactory.cs @@ -3,6 +3,7 @@ // See the LICENSE file in the project root for more information. using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; namespace System.Threading.Tasks { @@ -376,7 +377,7 @@ namespace System.Threading.Tasks /// However, unless creation and scheduling must be separated, StartNew is the recommended approach /// for both simplicity and performance. /// - public Task StartNew(Func function, object? state) // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 + public Task StartNew(Func function, object? state) { Task? currTask = Task.InternalCurrent; return Task.StartNew(currTask, function, state, m_defaultCancellationToken, @@ -405,7 +406,7 @@ namespace System.Threading.Tasks /// However, unless creation and scheduling must be separated, StartNew is the recommended approach /// for both simplicity and performance. /// - public Task StartNew(Func function, object? state, CancellationToken cancellationToken) // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 + public Task StartNew(Func function, object? state, CancellationToken cancellationToken) { Task? currTask = Task.InternalCurrent; return Task.StartNew(currTask, function, state, cancellationToken, @@ -436,7 +437,7 @@ namespace System.Threading.Tasks /// However, unless creation and scheduling must be separated, StartNew is the recommended approach /// for both simplicity and performance. /// - public Task StartNew(Func function, object? state, TaskCreationOptions creationOptions) // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 + public Task StartNew(Func function, object? state, TaskCreationOptions creationOptions) { Task? currTask = Task.InternalCurrent; return Task.StartNew(currTask, function, state, m_defaultCancellationToken, @@ -478,7 +479,7 @@ namespace System.Threading.Tasks /// However, unless creation and scheduling must be separated, StartNew is the recommended approach /// for both simplicity and performance. /// - public Task StartNew(Func function, object? state, CancellationToken cancellationToken, TaskCreationOptions creationOptions, TaskScheduler scheduler) // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 + public Task StartNew(Func function, object? state, CancellationToken cancellationToken, TaskCreationOptions creationOptions, TaskScheduler scheduler) { return Task.StartNew(Task.InternalCurrentIfAttached(creationOptions), function, state, cancellationToken, creationOptions, InternalTaskOptions.None, scheduler); @@ -500,7 +501,7 @@ namespace System.Threading.Tasks Exception? ex = null; OperationCanceledException? oce = null; - TResult result = default!; // TODO-NULLABLE-GENERIC + TResult result = default!; try { @@ -671,9 +672,9 @@ namespace System.Threading.Tasks if (Task.s_asyncDebuggingEnabled) Task.AddToActiveTasks(t); - if (asyncResult!.IsCompleted) // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 + if (asyncResult!.IsCompleted) // TODO-NULLABLE: Remove ! when [DoesNotReturn] respected { - try { t.InternalRunSynchronously(scheduler!, waitForCompletion: false); } // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 + try { t.InternalRunSynchronously(scheduler!, waitForCompletion: false); } // TODO-NULLABLE: Remove ! when [DoesNotReturn] respected catch (Exception e) { promise.TrySetException(e); } // catch and log any scheduler exceptions } else @@ -682,7 +683,7 @@ namespace System.Threading.Tasks asyncResult.AsyncWaitHandle, delegate { - try { t.InternalRunSynchronously(scheduler!, waitForCompletion: false); } // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 + try { t.InternalRunSynchronously(scheduler!, waitForCompletion: false); } // TODO-NULLABLE: Remove ! when [DoesNotReturn] respected catch (Exception e) { promise.TrySetException(e); } // catch and log any scheduler exceptions }, null, @@ -712,7 +713,7 @@ namespace System.Threading.Tasks /// public Task FromAsync( Func beginMethod, - Func endMethod, object? state) // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 + Func endMethod, object? state) { return FromAsyncImpl(beginMethod, endMethod, null, state, m_defaultCreationOptions); } @@ -741,7 +742,7 @@ namespace System.Threading.Tasks /// public Task FromAsync( Func beginMethod, - Func endMethod, object? state, TaskCreationOptions creationOptions) // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 + Func endMethod, object? state, TaskCreationOptions creationOptions) { return FromAsyncImpl(beginMethod, endMethod, null, state, creationOptions); } @@ -765,7 +766,7 @@ namespace System.Threading.Tasks Task promise = new Task(state, creationOptions); if (AsyncCausalityTracer.LoggingOn) - AsyncCausalityTracer.TraceOperationCreation(promise, "TaskFactory.FromAsync: " + beginMethod!.Method.Name); // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 + AsyncCausalityTracer.TraceOperationCreation(promise, "TaskFactory.FromAsync: " + beginMethod!.Method.Name); // TODO-NULLABLE: Remove ! when [DoesNotReturn] respected if (Task.s_asyncDebuggingEnabled) Task.AddToActiveTasks(promise); @@ -773,7 +774,7 @@ namespace System.Threading.Tasks try { //if we don't require synchronization, a faster set result path is taken - var asyncResult = beginMethod!(iar => // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 + var asyncResult = beginMethod!(iar => // TODO-NULLABLE: Remove ! when [DoesNotReturn] respected { if (!iar.CompletedSynchronously) FromAsyncCoreLogic(iar, endFunction, endAction, promise, requiresSynchronization: true); @@ -824,7 +825,7 @@ namespace System.Threading.Tasks public Task FromAsync( Func beginMethod, Func endMethod, - TArg1 arg1, object? state) // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 + TArg1 arg1, object? state) { return FromAsyncImpl(beginMethod, endMethod, null, arg1, state, m_defaultCreationOptions); } @@ -858,7 +859,7 @@ namespace System.Threading.Tasks public Task FromAsync( Func beginMethod, Func endMethod, - TArg1 arg1, object? state, TaskCreationOptions creationOptions) // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 + TArg1 arg1, object? state, TaskCreationOptions creationOptions) { return FromAsyncImpl(beginMethod, endMethod, null, arg1, state, creationOptions); } @@ -882,7 +883,7 @@ namespace System.Threading.Tasks Task promise = new Task(state, creationOptions); if (AsyncCausalityTracer.LoggingOn) - AsyncCausalityTracer.TraceOperationCreation(promise, "TaskFactory.FromAsync: " + beginMethod!.Method.Name); // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 + AsyncCausalityTracer.TraceOperationCreation(promise, "TaskFactory.FromAsync: " + beginMethod!.Method.Name); // TODO-NULLABLE: Remove ! when [DoesNotReturn] respected if (Task.s_asyncDebuggingEnabled) Task.AddToActiveTasks(promise); @@ -890,7 +891,7 @@ namespace System.Threading.Tasks try { //if we don't require synchronization, a faster set result path is taken - var asyncResult = beginMethod!(arg1, iar => // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 + var asyncResult = beginMethod!(arg1, iar => // TODO-NULLABLE: Remove ! when [DoesNotReturn] respected { if (!iar.CompletedSynchronously) FromAsyncCoreLogic(iar, endFunction, endAction, promise, requiresSynchronization: true); @@ -945,7 +946,7 @@ namespace System.Threading.Tasks public Task FromAsync( Func beginMethod, Func endMethod, - TArg1 arg1, TArg2 arg2, object? state) // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 + TArg1 arg1, TArg2 arg2, object? state) { return FromAsyncImpl(beginMethod, endMethod, null, arg1, arg2, state, m_defaultCreationOptions); } @@ -983,7 +984,7 @@ namespace System.Threading.Tasks public Task FromAsync( Func beginMethod, Func endMethod, - TArg1 arg1, TArg2 arg2, object? state, TaskCreationOptions creationOptions) // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 + TArg1 arg1, TArg2 arg2, object? state, TaskCreationOptions creationOptions) { return FromAsyncImpl(beginMethod, endMethod, null, arg1, arg2, state, creationOptions); } @@ -992,7 +993,7 @@ namespace System.Threading.Tasks // method can access the logic w/o declaring a TaskFactory instance. internal static Task FromAsyncImpl(Func beginMethod, Func? endFunction, Action? endAction, - TArg1 arg1, TArg2 arg2, object? state, TaskCreationOptions creationOptions) // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 + TArg1 arg1, TArg2 arg2, object? state, TaskCreationOptions creationOptions) { if (beginMethod == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.beginMethod); @@ -1007,7 +1008,7 @@ namespace System.Threading.Tasks Task promise = new Task(state, creationOptions); if (AsyncCausalityTracer.LoggingOn) - AsyncCausalityTracer.TraceOperationCreation(promise, "TaskFactory.FromAsync: " + beginMethod!.Method.Name); // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 + AsyncCausalityTracer.TraceOperationCreation(promise, "TaskFactory.FromAsync: " + beginMethod!.Method.Name); // TODO-NULLABLE: Remove ! when [DoesNotReturn] respected if (Task.s_asyncDebuggingEnabled) Task.AddToActiveTasks(promise); @@ -1015,7 +1016,7 @@ namespace System.Threading.Tasks try { //if we don't require synchronization, a faster set result path is taken - var asyncResult = beginMethod!(arg1, arg2, iar => // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 + var asyncResult = beginMethod!(arg1, arg2, iar => // TODO-NULLABLE: Remove ! when [DoesNotReturn] respected { if (!iar.CompletedSynchronously) FromAsyncCoreLogic(iar, endFunction, endAction, promise, requiresSynchronization: true); @@ -1140,7 +1141,7 @@ namespace System.Threading.Tasks Task promise = new Task(state, creationOptions); if (AsyncCausalityTracer.LoggingOn) - AsyncCausalityTracer.TraceOperationCreation(promise, "TaskFactory.FromAsync: " + beginMethod!.Method.Name); // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 + AsyncCausalityTracer.TraceOperationCreation(promise, "TaskFactory.FromAsync: " + beginMethod!.Method.Name); // TODO-NULLABLE: Remove ! when [DoesNotReturn] respected if (Task.s_asyncDebuggingEnabled) Task.AddToActiveTasks(promise); @@ -1148,7 +1149,7 @@ namespace System.Threading.Tasks try { //if we don't require synchronization, a faster set result path is taken - var asyncResult = beginMethod!(arg1, arg2, arg3, iar => // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 + var asyncResult = beginMethod!(arg1, arg2, arg3, iar => // TODO-NULLABLE: Remove ! when [DoesNotReturn] respected { if (!iar.CompletedSynchronously) FromAsyncCoreLogic(iar, endFunction, endAction, promise, requiresSynchronization: true); @@ -1228,7 +1229,7 @@ namespace System.Threading.Tasks internal static readonly AsyncCallback s_completeFromAsyncResult = CompleteFromAsyncResult; /// A reference to the object on which the begin/end methods are invoked. - private TInstance m_thisRef; + [AllowNull, MaybeNull] private TInstance m_thisRef; /// The end method. private Func? m_endMethod; @@ -1253,13 +1254,13 @@ namespace System.Threading.Tasks // Validate argument if (asyncResult == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.asyncResult); - var promise = asyncResult!.AsyncState as FromAsyncTrimPromise; // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 + var promise = asyncResult!.AsyncState as FromAsyncTrimPromise; // TODO-NULLABLE: Remove ! when [DoesNotReturn] respected if (promise == null) ThrowHelper.ThrowArgumentException(ExceptionResource.InvalidOperation_WrongAsyncResultOrEndCalledMultiple, ExceptionArgument.asyncResult); // Grab the relevant state and then null it out so that the task doesn't hold onto the state unnecessarily - var thisRef = promise!.m_thisRef; // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 + var thisRef = promise!.m_thisRef; // TODO-NULLABLE: Remove ! when [DoesNotReturn] respected var endMethod = promise.m_endMethod; - promise.m_thisRef = default!; // TODO-NULLABLE-GENERIC + promise.m_thisRef = default!; // TODO-NULLABLE: Remove ! when nullable attributes are respected promise.m_endMethod = null; if (endMethod == null) ThrowHelper.ThrowArgumentException(ExceptionResource.InvalidOperation_WrongAsyncResultOrEndCalledMultiple, ExceptionArgument.asyncResult); @@ -1267,7 +1268,7 @@ namespace System.Threading.Tasks // we'll instead complete the promise at the call site. if (!asyncResult.CompletedSynchronously) { - promise.Complete(thisRef, endMethod!, asyncResult, requiresSynchronization: true); // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 + promise.Complete(thisRef, endMethod!, asyncResult, requiresSynchronization: true); // TODO-NULLABLE: Remove ! when [DoesNotReturn] respected } } @@ -1322,7 +1323,7 @@ namespace System.Threading.Tasks { TaskCreationOptions tco; Task.CreationOptionsFromContinuationOptions(continuationOptions, out tco, out _); - return new Task(true, default!, tco, ct); // TODO-NULLABLE-GENERIC + return new Task(true, default!, tco, ct); // TODO-NULLABLE: Remove ! when nullable attributes are respected } // @@ -1610,7 +1611,7 @@ namespace System.Threading.Tasks if (scheduler == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.scheduler); // Check tasks array and make defensive copy - Task[] tasksCopy = TaskFactory.CheckMultiContinuationTasksAndCopy(tasks!); // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 + Task[] tasksCopy = TaskFactory.CheckMultiContinuationTasksAndCopy(tasks!); // TODO-NULLABLE: Remove ! when [DoesNotReturn] respected // Bail early if cancellation has been requested. if (cancellationToken.IsCancellationRequested @@ -1629,7 +1630,7 @@ namespace System.Threading.Tasks return starter.ContinueWith( // use a cached delegate GenericDelegateCache.CWAllFuncDelegate, - continuationFunction, scheduler!, cancellationToken, continuationOptions); // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 + continuationFunction, scheduler!, cancellationToken, continuationOptions); // TODO-NULLABLE: Remove ! when [DoesNotReturn] respected } else { @@ -1638,7 +1639,7 @@ namespace System.Threading.Tasks return starter.ContinueWith( // use a cached delegate GenericDelegateCache.CWAllActionDelegate, - continuationAction, scheduler!, cancellationToken, continuationOptions); // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 + continuationAction, scheduler!, cancellationToken, continuationOptions); // TODO-NULLABLE: Remove ! when [DoesNotReturn] respected } } @@ -1656,7 +1657,7 @@ namespace System.Threading.Tasks if (scheduler == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.scheduler); // Check tasks array and make defensive copy - Task[] tasksCopy = TaskFactory.CheckMultiContinuationTasksAndCopy(tasks!); // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 + Task[] tasksCopy = TaskFactory.CheckMultiContinuationTasksAndCopy(tasks!); // TODO-NULLABLE: Remove ! when [DoesNotReturn] respected // Bail early if cancellation has been requested. if (cancellationToken.IsCancellationRequested @@ -1682,7 +1683,7 @@ namespace System.Threading.Tasks Debug.Assert(state is Func); return ((Func)state)(completedTasks.Result); }, - continuationFunction, scheduler!, cancellationToken, continuationOptions); // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 + continuationFunction, scheduler!, cancellationToken, continuationOptions); // TODO-NULLABLE: Remove ! when [DoesNotReturn] respected } else { @@ -1695,9 +1696,9 @@ namespace System.Threading.Tasks { completedTasks.NotifyDebuggerOfWaitCompletionIfNecessary(); Debug.Assert(state is Action); - ((Action)state)(completedTasks.Result); return default!; // TODO-NULLABLE-GENERIC + ((Action)state)(completedTasks.Result); return default!; }, - continuationAction, scheduler!, cancellationToken, continuationOptions); // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 + continuationAction, scheduler!, cancellationToken, continuationOptions); // TODO-NULLABLE: Remove ! when [DoesNotReturn] respected } } @@ -1980,7 +1981,7 @@ namespace System.Threading.Tasks // check arguments TaskFactory.CheckMultiTaskContinuationOptions(continuationOptions); if (tasks == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.tasks); - if (tasks!.Length == 0) ThrowHelper.ThrowArgumentException(ExceptionResource.Task_MultiTaskContinuation_EmptyTaskList, ExceptionArgument.tasks); // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 + if (tasks!.Length == 0) ThrowHelper.ThrowArgumentException(ExceptionResource.Task_MultiTaskContinuation_EmptyTaskList, ExceptionArgument.tasks); // TODO-NULLABLE: Remove ! when [DoesNotReturn] respected //ArgumentNullException of continuationFunction or continuationAction is checked by the caller Debug.Assert((continuationFunction != null) != (continuationAction != null), "Expected exactly one of endFunction/endAction to be non-null"); @@ -2008,7 +2009,7 @@ namespace System.Threading.Tasks Debug.Assert(state is Func); return ((Func)state)(completedTask.Result); }, - continuationFunction, scheduler!, cancellationToken, continuationOptions); // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 + continuationFunction, scheduler!, cancellationToken, continuationOptions); // TODO-NULLABLE: Remove ! when [DoesNotReturn] respected } else { @@ -2020,9 +2021,9 @@ namespace System.Threading.Tasks { Debug.Assert(state is Action); ((Action)state)(completedTask.Result); - return default!; // TODO-NULLABLE-GENERIC + return default!; }, - continuationAction, scheduler!, cancellationToken, continuationOptions); // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 + continuationAction, scheduler!, cancellationToken, continuationOptions); // TODO-NULLABLE: Remove ! when [DoesNotReturn] respected } } @@ -2036,7 +2037,7 @@ namespace System.Threading.Tasks // check arguments TaskFactory.CheckMultiTaskContinuationOptions(continuationOptions); if (tasks == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.tasks); - if (tasks!.Length == 0) ThrowHelper.ThrowArgumentException(ExceptionResource.Task_MultiTaskContinuation_EmptyTaskList, ExceptionArgument.tasks); // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 + if (tasks!.Length == 0) ThrowHelper.ThrowArgumentException(ExceptionResource.Task_MultiTaskContinuation_EmptyTaskList, ExceptionArgument.tasks); // TODO-NULLABLE: Remove ! when [DoesNotReturn] respected //ArgumentNullException of continuationFunction or continuationAction is checked by the caller Debug.Assert((continuationFunction != null) != (continuationAction != null), "Expected exactly one of endFunction/endAction to be non-null"); if (scheduler == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.scheduler); @@ -2058,7 +2059,7 @@ namespace System.Threading.Tasks return starter.ContinueWith( // Use a cached delegate GenericDelegateCache.CWAnyFuncDelegate, - continuationFunction, scheduler!, cancellationToken, continuationOptions); // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 + continuationFunction, scheduler!, cancellationToken, continuationOptions); // TODO-NULLABLE: Remove ! when [DoesNotReturn] respected } else { @@ -2066,7 +2067,7 @@ namespace System.Threading.Tasks return starter.ContinueWith( // Use a cached delegate GenericDelegateCache.CWAnyActionDelegate, - continuationAction, scheduler!, cancellationToken, continuationOptions); // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 + continuationAction, scheduler!, cancellationToken, continuationOptions); // TODO-NULLABLE: Remove ! when [DoesNotReturn] respected } } } @@ -2094,7 +2095,7 @@ namespace System.Threading.Tasks var action = (Action>)state; var arg = (Task)wrappedWinner.Result; action(arg); - return default!; // TODO-NULLABLE-GENERIC + return default!; }; // ContinueWith delegate for TaskFactory.ContinueWhenAllImpl(non-null continuationFunction) @@ -2115,7 +2116,7 @@ namespace System.Threading.Tasks Debug.Assert(state is Action[]>); var action = (Action[]>)state; action(wrappedAntecedents.Result); - return default!; // TODO-NULLABLE-GENERIC + return default!; }; } } diff --git a/src/System.Private.CoreLib/shared/System/Threading/Tasks/ProducerConsumerQueues.cs b/src/System.Private.CoreLib/shared/System/Threading/Tasks/ProducerConsumerQueues.cs index 157ad5d..9fa82ed 100644 --- a/src/System.Private.CoreLib/shared/System/Threading/Tasks/ProducerConsumerQueues.cs +++ b/src/System.Private.CoreLib/shared/System/Threading/Tasks/ProducerConsumerQueues.cs @@ -25,6 +25,7 @@ using System.Collections; using System.Collections.Concurrent; using System.Collections.Generic; using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.Runtime.InteropServices; namespace System.Threading.Tasks @@ -42,7 +43,7 @@ namespace System.Threading.Tasks /// The dequeued item. /// true if an item could be dequeued; otherwise, false. /// This method is meant to be thread-safe subject to the particular nature of the implementation. - bool TryDequeue(out T result); + bool TryDequeue([MaybeNullWhen(false)] out T result); /// Gets whether the collection is currently empty. /// This method may or may not be thread-safe. @@ -67,7 +68,7 @@ namespace System.Threading.Tasks /// Attempts to dequeue an item from the queue. /// The dequeued item. /// true if an item could be dequeued; otherwise, false. - bool IProducerConsumerQueue.TryDequeue(out T result) { return base.TryDequeue(out result); } + bool IProducerConsumerQueue.TryDequeue([MaybeNullWhen(false)] out T result) { return base.TryDequeue(out result); } /// Gets whether the collection is currently empty. bool IProducerConsumerQueue.IsEmpty { get { return base.IsEmpty; } } @@ -194,7 +195,7 @@ namespace System.Threading.Tasks /// Attempts to dequeue an item from the queue. /// The dequeued item. /// true if an item could be dequeued; otherwise, false. - public bool TryDequeue(out T result) + public bool TryDequeue([MaybeNullWhen(false)] out T result) { Segment segment = m_head; var array = segment.m_array; @@ -204,7 +205,7 @@ namespace System.Threading.Tasks if (first != segment.m_state.m_lastCopy) { result = array[first]; - array[first] = default!; // Clear the slot to release the element // TODO-NULLABLE-GENERIC + array[first] = default!; // Clear the slot to release the element segment.m_state.m_first = (first + 1) & (array.Length - 1); return true; } @@ -217,7 +218,7 @@ namespace System.Threading.Tasks /// The segment from which the item was dequeued. /// The dequeued item. /// true if an item could be dequeued; otherwise, false. - private bool TryDequeueSlow(ref Segment segment, ref T[] array, out T result) + private bool TryDequeueSlow(ref Segment segment, ref T[] array, [MaybeNullWhen(false)] out T result) { Debug.Assert(segment != null, "Expected a non-null segment."); Debug.Assert(array != null, "Expected a non-null item array."); @@ -239,12 +240,12 @@ namespace System.Threading.Tasks if (first == segment.m_state.m_last) { - result = default!; // TODO-NULLABLE-GENERIC + result = default!; return false; } result = array[first]; - array[first] = default!; // Clear the slot to release the element // TODO-NULLABLE-GENERIC + array[first] = default!; // Clear the slot to release the element segment.m_state.m_first = (first + 1) & (segment.m_array.Length - 1); segment.m_state.m_lastCopy = segment.m_state.m_last; // Refresh m_lastCopy to ensure that m_first has not passed m_lastCopy diff --git a/src/System.Private.CoreLib/shared/System/Threading/Tasks/Sources/IValueTaskSource.cs b/src/System.Private.CoreLib/shared/System/Threading/Tasks/Sources/IValueTaskSource.cs index 8f46037..5f071b2 100644 --- a/src/System.Private.CoreLib/shared/System/Threading/Tasks/Sources/IValueTaskSource.cs +++ b/src/System.Private.CoreLib/shared/System/Threading/Tasks/Sources/IValueTaskSource.cs @@ -53,7 +53,7 @@ namespace System.Threading.Tasks.Sources /// The state object to pass to when it's invoked. /// Opaque value that was provided to the 's constructor. /// The flags describing the behavior of the continuation. - void OnCompleted(Action continuation, object? state, short token, ValueTaskSourceOnCompletedFlags flags); // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 + void OnCompleted(Action continuation, object? state, short token, ValueTaskSourceOnCompletedFlags flags); /// Gets the result of the . /// Opaque value that was provided to the 's constructor. @@ -73,7 +73,7 @@ namespace System.Threading.Tasks.Sources /// The state object to pass to when it's invoked. /// Opaque value that was provided to the 's constructor. /// The flags describing the behavior of the continuation. - void OnCompleted(Action continuation, object? state, short token, ValueTaskSourceOnCompletedFlags flags); // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 + void OnCompleted(Action continuation, object? state, short token, ValueTaskSourceOnCompletedFlags flags); /// Gets the result of the . /// Opaque value that was provided to the 's constructor. diff --git a/src/System.Private.CoreLib/shared/System/Threading/Tasks/Sources/ManualResetValueTaskSourceCore.cs b/src/System.Private.CoreLib/shared/System/Threading/Tasks/Sources/ManualResetValueTaskSourceCore.cs index fd68a49..e72328a 100644 --- a/src/System.Private.CoreLib/shared/System/Threading/Tasks/Sources/ManualResetValueTaskSourceCore.cs +++ b/src/System.Private.CoreLib/shared/System/Threading/Tasks/Sources/ManualResetValueTaskSourceCore.cs @@ -3,6 +3,7 @@ // See the LICENSE file in the project root for more information. using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.Runtime.ExceptionServices; using System.Runtime.InteropServices; @@ -31,7 +32,7 @@ namespace System.Threading.Tasks.Sources /// Whether the current operation has completed. private bool _completed; /// The result with which the operation succeeded, or the default value if it hasn't yet completed or failed. - private TResult _result; + [AllowNull, MaybeNull] private TResult _result; /// The exception with which the operation failed, or null if it hasn't yet completed or completed successfully. private ExceptionDispatchInfo? _error; /// The current version of this value, used to help prevent misuse. @@ -47,7 +48,7 @@ namespace System.Threading.Tasks.Sources // Reset/update state for the next use/await of this instance. _version++; _completed = false; - _result = default!; // TODO-NULLABLE-GENERIC + _result = default!; // TODO-NULLABLE: Remove ! when nullable attributes are respected _error = null; _executionContext = null; _capturedContext = null; @@ -106,7 +107,7 @@ namespace System.Threading.Tasks.Sources /// The state object to pass to when it's invoked. /// Opaque value that was provided to the 's constructor. /// The flags describing the behavior of the continuation. - public void OnCompleted(Action continuation, object? state, short token, ValueTaskSourceOnCompletedFlags flags) // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 + public void OnCompleted(Action continuation, object? state, short token, ValueTaskSourceOnCompletedFlags flags) { if (continuation == null) { @@ -175,7 +176,7 @@ namespace System.Threading.Tasks.Sources case SynchronizationContext sc: sc.Post(s => { - var tuple = (Tuple, object?>)s!; // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 + var tuple = (Tuple, object?>)s!; tuple.Item1(tuple.Item2); }, Tuple.Create(continuation, state)); break; @@ -254,7 +255,7 @@ namespace System.Threading.Tasks.Sources case SynchronizationContext sc: sc.Post(s => { - var state = (Tuple, object?>)s!; // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 + var state = (Tuple, object?>)s!; state.Item1(state.Item2); }, Tuple.Create(_continuation, _continuationState)); break; diff --git a/src/System.Private.CoreLib/shared/System/Threading/Tasks/Task.cs b/src/System.Private.CoreLib/shared/System/Threading/Tasks/Task.cs index a4a6592..4fb8d9a 100644 --- a/src/System.Private.CoreLib/shared/System/Threading/Tasks/Task.cs +++ b/src/System.Private.CoreLib/shared/System/Threading/Tasks/Task.cs @@ -207,12 +207,14 @@ namespace System.Threading.Tasks { Debug.Assert(task != null, "Null Task objects can't be added to the ActiveTasks collection"); +#pragma warning disable CS8634 // TODO-NULLABLE: Remove warning disable when nullable attributes are respected LazyInitializer.EnsureInitialized(ref s_currentActiveTasks, () => new Dictionary()); +#pragma warning restore CS8634 int taskId = task.Id; - lock (s_currentActiveTasks!) // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 + lock (s_currentActiveTasks!) // TODO-NULLABLE: Remove ! when nullable attributes are respected { - s_currentActiveTasks![taskId] = task; // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 + s_currentActiveTasks[taskId] = task; } //always return true to keep signature as bool for backwards compatibility return true; @@ -427,7 +429,7 @@ namespace System.Threading.Tasks /// /// The argument is null. /// - public Task(Action action, object? state) // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 + public Task(Action action, object? state) : this(action, state, null, default, TaskCreationOptions.None, InternalTaskOptions.None, null) { } @@ -444,7 +446,7 @@ namespace System.Threading.Tasks /// The provided CancellationToken /// has already been disposed. /// - public Task(Action action, object? state, CancellationToken cancellationToken) // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 + public Task(Action action, object? state, CancellationToken cancellationToken) : this(action, state, null, cancellationToken, TaskCreationOptions.None, InternalTaskOptions.None, null) { } @@ -465,7 +467,7 @@ namespace System.Threading.Tasks /// The argument specifies an invalid value for . /// - public Task(Action action, object? state, TaskCreationOptions creationOptions) // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 + public Task(Action action, object? state, TaskCreationOptions creationOptions) : this(action, state, Task.InternalCurrentIfAttached(creationOptions), default, creationOptions, InternalTaskOptions.None, null) { } @@ -490,7 +492,7 @@ namespace System.Threading.Tasks /// The provided CancellationToken /// has already been disposed. /// - public Task(Action action, object? state, CancellationToken cancellationToken, TaskCreationOptions creationOptions) // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 + public Task(Action action, object? state, CancellationToken cancellationToken, TaskCreationOptions creationOptions) : this(action, state, Task.InternalCurrentIfAttached(creationOptions), cancellationToken, creationOptions, InternalTaskOptions.None, null) { } @@ -634,7 +636,7 @@ namespace System.Threading.Tasks if (antecedent == null) { // if no antecedent was specified, use this task's reference as the cancellation state object - ctr = cancellationToken.UnsafeRegister(t => ((Task)t!).InternalCancel(false), this); // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 + ctr = cancellationToken.UnsafeRegister(t => ((Task)t!).InternalCancel(false), this); } else { @@ -1050,7 +1052,7 @@ namespace System.Threading.Tasks ThrowHelper.ThrowArgumentNullException(ExceptionArgument.scheduler); } - InternalRunSynchronously(scheduler!, waitForCompletion: true); // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 + InternalRunSynchronously(scheduler!, waitForCompletion: true); // TODO-NULLABLE: Remove ! when [DoesNotReturn] respected } // @@ -1356,7 +1358,9 @@ namespace System.Threading.Tasks /// The initialized contingent properties object. internal ContingentProperties EnsureContingentPropertiesInitialized() { - return LazyInitializer.EnsureInitialized(ref m_contingentProperties, () => new ContingentProperties())!; // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 +#pragma warning disable CS8634 // TODO-NULLABLE: Remove warning disable when nullable attributes are respected + return LazyInitializer.EnsureInitialized(ref m_contingentProperties, () => new ContingentProperties())!; +#pragma warning restore CS8634 } /// @@ -1525,7 +1529,7 @@ namespace System.Threading.Tasks } } - return contingentProps.m_completionEvent!; // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 + return contingentProps.m_completionEvent!; // TODO-NULLABLE: Remove ! when compiler specially-recognizes CompareExchange for nullability } } @@ -1815,7 +1819,7 @@ namespace System.Threading.Tasks lock (props) { - props.m_exceptionsHolder!.Add(exceptionObject, representsCancellation); // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 + props.m_exceptionsHolder!.Add(exceptionObject, representsCancellation); // TODO-NULLABLE: Remove ! when compiler specially-recognizes CompareExchange for nullability } } @@ -3613,13 +3617,13 @@ namespace System.Threading.Tasks CreationOptionsFromContinuationOptions(continuationOptions, out creationOptions, out internalOptions); Task continuationTask = new ContinuationTaskFromTask( - this, continuationAction!, null, // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 + this, continuationAction!, null, // TODO-NULLABLE: Remove ! when [DoesNotReturn] respected creationOptions, internalOptions ); // Register the continuation. If synchronous execution is requested, this may // actually invoke the continuation before returning. - ContinueWithCore(continuationTask, scheduler!, cancellationToken, continuationOptions); // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 + ContinueWithCore(continuationTask, scheduler!, cancellationToken, continuationOptions); // TODO-NULLABLE: Remove ! when [DoesNotReturn] respected return continuationTask; } @@ -3803,13 +3807,13 @@ namespace System.Threading.Tasks CreationOptionsFromContinuationOptions(continuationOptions, out creationOptions, out internalOptions); Task continuationTask = new ContinuationTaskFromTask( - this, continuationAction!, state, // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 + this, continuationAction!, state, // TODO-NULLABLE: Remove ! when [DoesNotReturn] respected creationOptions, internalOptions ); // Register the continuation. If synchronous execution is requested, this may // actually invoke the continuation before returning. - ContinueWithCore(continuationTask, scheduler!, cancellationToken, continuationOptions); // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 + ContinueWithCore(continuationTask, scheduler!, cancellationToken, continuationOptions); // TODO-NULLABLE: Remove ! when [DoesNotReturn] respected return continuationTask; } @@ -4006,13 +4010,13 @@ namespace System.Threading.Tasks CreationOptionsFromContinuationOptions(continuationOptions, out creationOptions, out internalOptions); Task continuationTask = new ContinuationResultTaskFromTask( - this, continuationFunction!, null, // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 + this, continuationFunction!, null, // TODO-NULLABLE: Remove ! when [DoesNotReturn] respected creationOptions, internalOptions ); // Register the continuation. If synchronous execution is requested, this may // actually invoke the continuation before returning. - ContinueWithCore(continuationTask, scheduler!, cancellationToken, continuationOptions); // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 + ContinueWithCore(continuationTask, scheduler!, cancellationToken, continuationOptions); // TODO-NULLABLE: Remove ! when [DoesNotReturn] respected return continuationTask; } @@ -4213,13 +4217,13 @@ namespace System.Threading.Tasks CreationOptionsFromContinuationOptions(continuationOptions, out creationOptions, out internalOptions); Task continuationTask = new ContinuationResultTaskFromTask( - this, continuationFunction!, state, // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 + this, continuationFunction!, state, // TODO-NULLABLE: Remove ! when [DoesNotReturn] respected creationOptions, internalOptions ); // Register the continuation. If synchronous execution is requested, this may // actually invoke the continuation before returning. - ContinueWithCore(continuationTask, scheduler!, cancellationToken, continuationOptions); // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 + ContinueWithCore(continuationTask, scheduler!, cancellationToken, continuationOptions); // TODO-NULLABLE: Remove ! when [DoesNotReturn] respected return continuationTask; } @@ -4724,7 +4728,7 @@ namespace System.Threading.Tasks bool returnValue = true; // Collects incomplete tasks in "waitedOnTaskList" - for (int i = tasks!.Length - 1; i >= 0; i--) // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 + for (int i = tasks!.Length - 1; i >= 0; i--) // TODO-NULLABLE: Remove ! when [DoesNotReturn] respected { Task task = tasks[i]; @@ -4733,7 +4737,7 @@ namespace System.Threading.Tasks ThrowHelper.ThrowArgumentException(ExceptionResource.Task_WaitMulti_NullTask, ExceptionArgument.tasks); } - bool taskIsCompleted = task!.IsCompleted; // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 + bool taskIsCompleted = task!.IsCompleted; // TODO-NULLABLE: Remove ! when [DoesNotReturn] respected if (!taskIsCompleted) { // try inlining the task only if we have an infinite timeout and an empty cancellation token @@ -5089,7 +5093,7 @@ namespace System.Threading.Tasks // Make a pass through the loop to check for any tasks that may have // already been completed, and to verify that no tasks are null. - for (int taskIndex = 0; taskIndex < tasks!.Length; taskIndex++) // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 + for (int taskIndex = 0; taskIndex < tasks!.Length; taskIndex++) // TODO-NULLABLE: Remove ! when [DoesNotReturn] respected { Task task = tasks[taskIndex]; @@ -5098,7 +5102,7 @@ namespace System.Threading.Tasks ThrowHelper.ThrowArgumentException(ExceptionResource.Task_WaitMulti_NullTask, ExceptionArgument.tasks); } - if (signaledTaskIndex == -1 && task!.IsCompleted) // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 + if (signaledTaskIndex == -1 && task!.IsCompleted) // TODO-NULLABLE: Remove ! when [DoesNotReturn] respected { // We found our first completed task. Store it, but we can't just return here, // as we still need to validate the whole array for nulls. @@ -5150,7 +5154,7 @@ namespace System.Threading.Tasks if (exception == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.exception); var task = new Task(); - bool succeeded = task.TrySetException(exception!); // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 + bool succeeded = task.TrySetException(exception!); // TODO-NULLABLE: Remove ! when [DoesNotReturn] respected Debug.Assert(succeeded, "This should always succeed on a new task."); return task; } @@ -5164,7 +5168,7 @@ namespace System.Threading.Tasks if (exception == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.exception); var task = new Task(); - bool succeeded = task.TrySetException(exception!); // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 + bool succeeded = task.TrySetException(exception!); // TODO-NULLABLE: Remove ! when [DoesNotReturn] respected Debug.Assert(succeeded, "This should always succeed on a new task."); return task; } @@ -5187,7 +5191,7 @@ namespace System.Threading.Tasks { if (!cancellationToken.IsCancellationRequested) ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.cancellationToken); - return new Task(true, default!, TaskCreationOptions.None, cancellationToken); // TODO-NULLABLE-GENERIC + return new Task(true, default!, TaskCreationOptions.None, cancellationToken); // TODO-NULLABLE: Remove ! when nullable attributes are respected } /// Creates a that's completed due to cancellation with the specified exception. @@ -5324,7 +5328,7 @@ namespace System.Threading.Tasks return Task.FromCanceled(cancellationToken); // Kick off initial Task, which will call the user-supplied function and yield a Task. - Task task1 = Task.Factory.StartNew(function!, cancellationToken, TaskCreationOptions.DenyChildAttach, TaskScheduler.Default); // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 + Task task1 = Task.Factory.StartNew(function!, cancellationToken, TaskCreationOptions.DenyChildAttach, TaskScheduler.Default); // TODO-NULLABLE: Remove ! when [DoesNotReturn] respected // Create a promise-style Task to be used as a proxy for the operation // Set lookForOce == true so that unwrap logic can be on the lookout for OCEs thrown as faults from task1, to support in-delegate cancellation. @@ -5369,7 +5373,7 @@ namespace System.Threading.Tasks return Task.FromCanceled(cancellationToken); // Kick off initial Task, which will call the user-supplied function and yield a Task. - Task?> task1 = Task?>.Factory.StartNew(function!, cancellationToken, TaskCreationOptions.DenyChildAttach, TaskScheduler.Default); // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 + Task?> task1 = Task?>.Factory.StartNew(function!, cancellationToken, TaskCreationOptions.DenyChildAttach, TaskScheduler.Default); // TODO-NULLABLE: Remove ! when [DoesNotReturn] respected // Create a promise-style Task to be used as a proxy for the operation // Set lookForOce == true so that unwrap logic can be on the lookout for OCEs thrown as faults from task1, to support in-delegate cancellation. @@ -5492,7 +5496,7 @@ namespace System.Threading.Tasks if (millisecondsDelay != Timeout.Infinite) // no need to create the timer if it's an infinite timeout { - _timer = new TimerQueueTimer(state => ((DelayPromise)state!).CompleteTimedOut(), this, (uint)millisecondsDelay, Timeout.UnsignedInfinite, flowExecutionContext: false); // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 + _timer = new TimerQueueTimer(state => ((DelayPromise)state!).CompleteTimedOut(), this, (uint)millisecondsDelay, Timeout.UnsignedInfinite, flowExecutionContext: false); if (IsCanceled) { // Handle rare race condition where cancellation occurs prior to our having created and stored the timer, in which case @@ -5531,7 +5535,7 @@ namespace System.Threading.Tasks Debug.Assert(token.CanBeCanceled); _token = token; - _registration = token.UnsafeRegister(state => ((DelayPromiseWithCancellation)state!).CompleteCanceled(), this); // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 + _registration = token.UnsafeRegister(state => ((DelayPromiseWithCancellation)state!).CompleteCanceled(), this); } private void CompleteCanceled() @@ -5596,7 +5600,7 @@ namespace System.Threading.Tasks foreach (var task in tasks) { if (task == null) ThrowHelper.ThrowArgumentException(ExceptionResource.Task_MultiTaskContinuation_NullTask, ExceptionArgument.tasks); - taskArray[index++] = task!; // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 + taskArray[index++] = task!; // TODO-NULLABLE: Remove ! when [DoesNotReturn] respected } return InternalWhenAll(taskArray); } @@ -5604,10 +5608,10 @@ namespace System.Threading.Tasks // Do some argument checking and convert tasks to a List (and later an array). if (tasks == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.tasks); List taskList = new List(); - foreach (Task task in tasks!) // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 + foreach (Task task in tasks!) // TODO-NULLABLE: Remove ! when [DoesNotReturn] respected { if (task == null) ThrowHelper.ThrowArgumentException(ExceptionResource.Task_MultiTaskContinuation_NullTask, ExceptionArgument.tasks); - taskList.Add(task!); // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 + taskList.Add(task!); // TODO-NULLABLE: Remove ! when [DoesNotReturn] respected } // Delegate the rest to InternalWhenAll() @@ -5646,7 +5650,7 @@ namespace System.Threading.Tasks // Do some argument checking and make a defensive copy of the tasks array if (tasks == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.tasks); - int taskCount = tasks!.Length; // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 + int taskCount = tasks!.Length; // TODO-NULLABLE: Remove ! when [DoesNotReturn] respected if (taskCount == 0) return InternalWhenAll(tasks); // Small optimization in the case of an empty array. Task[] tasksCopy = new Task[taskCount]; @@ -5654,7 +5658,7 @@ namespace System.Threading.Tasks { Task task = tasks[i]; if (task == null) ThrowHelper.ThrowArgumentException(ExceptionResource.Task_MultiTaskContinuation_NullTask, ExceptionArgument.tasks); - tasksCopy[i] = task!; // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 + tasksCopy[i] = task!; // TODO-NULLABLE: Remove ! when [DoesNotReturn] respected } // The rest can be delegated to InternalWhenAll() @@ -5840,7 +5844,7 @@ namespace System.Threading.Tasks foreach (var task in tasks) { if (task == null) ThrowHelper.ThrowArgumentException(ExceptionResource.Task_MultiTaskContinuation_NullTask, ExceptionArgument.tasks); - taskArray[index++] = task!; // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 + taskArray[index++] = task!; // TODO-NULLABLE: Remove ! when [DoesNotReturn] respected } return InternalWhenAll(taskArray); } @@ -5848,10 +5852,10 @@ namespace System.Threading.Tasks // Do some argument checking and convert tasks into a List (later an array) if (tasks == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.tasks); List> taskList = new List>(); - foreach (Task task in tasks!) // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 + foreach (Task task in tasks!) // TODO-NULLABLE: Remove ! when [DoesNotReturn] respected { if (task == null) ThrowHelper.ThrowArgumentException(ExceptionResource.Task_MultiTaskContinuation_NullTask, ExceptionArgument.tasks); - taskList.Add(task!); // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 + taskList.Add(task!); // TODO-NULLABLE: Remove ! when [DoesNotReturn] respected } // Delegate the rest to InternalWhenAll(). @@ -5893,7 +5897,7 @@ namespace System.Threading.Tasks // Do some argument checking and make a defensive copy of the tasks array if (tasks == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.tasks); - int taskCount = tasks!.Length; // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 + int taskCount = tasks!.Length; // TODO-NULLABLE: Remove ! when [DoesNotReturn] respected if (taskCount == 0) return InternalWhenAll(tasks); // small optimization in the case of an empty task array Task[] tasksCopy = new Task[taskCount]; @@ -5901,7 +5905,7 @@ namespace System.Threading.Tasks { Task task = tasks[i]; if (task == null) ThrowHelper.ThrowArgumentException(ExceptionResource.Task_MultiTaskContinuation_NullTask, ExceptionArgument.tasks); - tasksCopy[i] = task!; // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 + tasksCopy[i] = task!; // TODO-NULLABLE: Remove ! when [DoesNotReturn] respected } // Delegate the rest to InternalWhenAll() @@ -6060,7 +6064,7 @@ namespace System.Threading.Tasks public static Task WhenAny(params Task[] tasks) { if (tasks == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.tasks); - if (tasks!.Length == 0) // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 + if (tasks!.Length == 0) // TODO-NULLABLE: Remove ! when [DoesNotReturn] respected { ThrowHelper.ThrowArgumentException(ExceptionResource.Task_MultiTaskContinuation_EmptyTaskList, ExceptionArgument.tasks); } @@ -6073,7 +6077,7 @@ namespace System.Threading.Tasks { Task task = tasks[i]; if (task == null) ThrowHelper.ThrowArgumentException(ExceptionResource.Task_MultiTaskContinuation_NullTask, ExceptionArgument.tasks); - tasksCopy[i] = task!; // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 + tasksCopy[i] = task!; // TODO-NULLABLE: Remove ! when [DoesNotReturn] respected } // Previously implemented CommonCWAnyLogic() can handle the rest @@ -6102,10 +6106,10 @@ namespace System.Threading.Tasks // Make a defensive copy, as the user may manipulate the tasks collection // after we return but before the WhenAny asynchronously completes. List taskList = new List(); - foreach (Task task in tasks!) // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 + foreach (Task task in tasks!) // TODO-NULLABLE: Remove ! when [DoesNotReturn] respected { if (task == null) ThrowHelper.ThrowArgumentException(ExceptionResource.Task_MultiTaskContinuation_NullTask, ExceptionArgument.tasks); - taskList.Add(task!); // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 + taskList.Add(task!); // TODO-NULLABLE: Remove ! when [DoesNotReturn] respected } if (taskList.Count == 0) @@ -6597,7 +6601,7 @@ namespace System.Threading.Tasks ThreadPool.UnsafeQueueUserWorkItem(state => { // InvokeCore(completingTask); - var tuple = (Tuple, Task>)state!; // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 + var tuple = (Tuple, Task>)state!; tuple.Item1.InvokeCore(tuple.Item2); }, Tuple.Create, Task>(this, completingTask)); } @@ -6673,7 +6677,7 @@ namespace System.Threading.Tasks if (Task.s_asyncDebuggingEnabled) RemoveFromActiveTasks(this); - result = TrySetResult(taskTResult != null ? taskTResult.Result : default!); // TODO-NULLABLE-GENERIC + result = TrySetResult(taskTResult != null ? taskTResult.Result : default!); // TODO-NULLABLE: Remove ! when nullable attributes are respected break; } return result; diff --git a/src/System.Private.CoreLib/shared/System/Threading/Tasks/TaskCompletionSource.cs b/src/System.Private.CoreLib/shared/System/Threading/Tasks/TaskCompletionSource.cs index 8773eb4..b0c79e6 100644 --- a/src/System.Private.CoreLib/shared/System/Threading/Tasks/TaskCompletionSource.cs +++ b/src/System.Private.CoreLib/shared/System/Threading/Tasks/TaskCompletionSource.cs @@ -150,7 +150,7 @@ namespace System.Threading.Tasks { if (exception == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.exception); - bool rval = _task.TrySetException(exception!); // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 + bool rval = _task.TrySetException(exception!); // TODO-NULLABLE: Remove ! when [DoesNotReturn] respected if (!rval && !_task.IsCompleted) SpinUntilCompleted(); return rval; } @@ -180,11 +180,11 @@ namespace System.Threading.Tasks if (exceptions == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.exceptions); List defensiveCopy = new List(); - foreach (Exception e in exceptions!) // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 + foreach (Exception e in exceptions!) // TODO-NULLABLE: Remove ! when [DoesNotReturn] respected { if (e == null) ThrowHelper.ThrowArgumentException(ExceptionResource.TaskCompletionSourceT_TrySetException_NullException, ExceptionArgument.exceptions); - defensiveCopy.Add(e!); // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 + defensiveCopy.Add(e!); // TODO-NULLABLE: Remove ! when [DoesNotReturn] respected } if (defensiveCopy.Count == 0) @@ -216,7 +216,7 @@ namespace System.Threading.Tasks { if (exception == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.exception); - if (!TrySetException(exception!)) // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 + if (!TrySetException(exception!)) // TODO-NULLABLE: Remove ! when [DoesNotReturn] respected { ThrowHelper.ThrowInvalidOperationException(ExceptionResource.TaskT_TransitionToFinal_AlreadyCompleted); } diff --git a/src/System.Private.CoreLib/shared/System/Threading/Tasks/TaskContinuation.cs b/src/System.Private.CoreLib/shared/System/Threading/Tasks/TaskContinuation.cs index 65547fb..fbe7733 100644 --- a/src/System.Private.CoreLib/shared/System/Threading/Tasks/TaskContinuation.cs +++ b/src/System.Private.CoreLib/shared/System/Threading/Tasks/TaskContinuation.cs @@ -492,7 +492,7 @@ namespace System.Threading.Tasks { try { - ((Action)state!)(); // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 + ((Action)state!)(); } catch (Exception exception) { diff --git a/src/System.Private.CoreLib/shared/System/Threading/Tasks/TaskFactory.cs b/src/System.Private.CoreLib/shared/System/Threading/Tasks/TaskFactory.cs index 3929a08..786e132 100644 --- a/src/System.Private.CoreLib/shared/System/Threading/Tasks/TaskFactory.cs +++ b/src/System.Private.CoreLib/shared/System/Threading/Tasks/TaskFactory.cs @@ -396,7 +396,7 @@ namespace System.Threading.Tasks /// However, unless creation and scheduling must be separated, StartNew is the recommended approach /// for both simplicity and performance. /// - public Task StartNew(Action action, object? state) // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 + public Task StartNew(Action action, object? state) { Task? currTask = Task.InternalCurrent; return Task.InternalStartNew(currTask, action, state, m_defaultCancellationToken, GetDefaultScheduler(currTask), @@ -425,7 +425,7 @@ namespace System.Threading.Tasks /// However, unless creation and scheduling must be separated, StartNew is the recommended approach /// for both simplicity and performance. /// - public Task StartNew(Action action, object? state, CancellationToken cancellationToken) // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 + public Task StartNew(Action action, object? state, CancellationToken cancellationToken) { Task? currTask = Task.InternalCurrent; return Task.InternalStartNew(currTask, action, state, cancellationToken, GetDefaultScheduler(currTask), @@ -455,7 +455,7 @@ namespace System.Threading.Tasks /// However, unless creation and scheduling must be separated, StartNew is the recommended approach /// for both simplicity and performance. /// - public Task StartNew(Action action, object? state, TaskCreationOptions creationOptions) // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 + public Task StartNew(Action action, object? state, TaskCreationOptions creationOptions) { Task? currTask = Task.InternalCurrent; return Task.InternalStartNew(currTask, action, state, m_defaultCancellationToken, GetDefaultScheduler(currTask), @@ -496,7 +496,7 @@ namespace System.Threading.Tasks /// However, unless creation and scheduling must be separated, StartNew is the recommended approach /// for both simplicity and performance. /// - public Task StartNew(Action action, object? state, CancellationToken cancellationToken, // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 + public Task StartNew(Action action, object? state, CancellationToken cancellationToken, TaskCreationOptions creationOptions, TaskScheduler scheduler) { return Task.InternalStartNew( @@ -657,7 +657,7 @@ namespace System.Threading.Tasks /// However, unless creation and scheduling must be separated, StartNew is the recommended approach /// for both simplicity and performance. /// - public Task StartNew(Func function, object? state) // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 + public Task StartNew(Func function, object? state) { Task? currTask = Task.InternalCurrent; return Task.StartNew(currTask, function, state, m_defaultCancellationToken, @@ -690,7 +690,7 @@ namespace System.Threading.Tasks /// However, unless creation and scheduling must be separated, StartNew is the recommended approach /// for both simplicity and performance. /// - public Task StartNew(Func function, object? state, CancellationToken cancellationToken) // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 + public Task StartNew(Func function, object? state, CancellationToken cancellationToken) { Task? currTask = Task.InternalCurrent; return Task.StartNew(currTask, function, state, cancellationToken, @@ -724,7 +724,7 @@ namespace System.Threading.Tasks /// However, unless creation and scheduling must be separated, StartNew is the recommended approach /// for both simplicity and performance. /// - public Task StartNew(Func function, object? state, TaskCreationOptions creationOptions) // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 + public Task StartNew(Func function, object? state, TaskCreationOptions creationOptions) { Task? currTask = Task.InternalCurrent; return Task.StartNew(currTask, function, state, m_defaultCancellationToken, @@ -769,7 +769,7 @@ namespace System.Threading.Tasks /// However, unless creation and scheduling must be separated, StartNew is the recommended approach /// for both simplicity and performance. /// - public Task StartNew(Func function, object? state, CancellationToken cancellationToken, // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 + public Task StartNew(Func function, object? state, CancellationToken cancellationToken, TaskCreationOptions creationOptions, TaskScheduler scheduler) { return Task.StartNew( diff --git a/src/System.Private.CoreLib/shared/System/Threading/Tasks/TaskScheduler.cs b/src/System.Private.CoreLib/shared/System/Threading/Tasks/TaskScheduler.cs index b6afade..f79a87a 100644 --- a/src/System.Private.CoreLib/shared/System/Threading/Tasks/TaskScheduler.cs +++ b/src/System.Private.CoreLib/shared/System/Threading/Tasks/TaskScheduler.cs @@ -298,7 +298,7 @@ namespace System.Threading.Tasks Interlocked.CompareExchange(ref s_activeTaskSchedulers, new ConditionalWeakTable(), null); activeTaskSchedulers = s_activeTaskSchedulers; } - activeTaskSchedulers!.Add(this, null); // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 + activeTaskSchedulers!.Add(this, null); // TODO-NULLABLE: Remove ! when compiler specially-recognizes CompareExchange for nullability } /// diff --git a/src/System.Private.CoreLib/shared/System/Threading/Tasks/ValueTask.cs b/src/System.Private.CoreLib/shared/System/Threading/Tasks/ValueTask.cs index 884ae0b..75c6fd9 100644 --- a/src/System.Private.CoreLib/shared/System/Threading/Tasks/ValueTask.cs +++ b/src/System.Private.CoreLib/shared/System/Threading/Tasks/ValueTask.cs @@ -4,6 +4,7 @@ using System.Collections.Generic; using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Threading.Tasks.Sources; @@ -415,7 +416,7 @@ namespace System.Threading.Tasks /// null if has the result, otherwise a or a . internal readonly object? _obj; /// The result to be used if the operation completed successfully synchronously. - internal readonly TResult _result; + [AllowNull] internal readonly TResult _result; /// Opaque value passed through to the . internal readonly short _token; /// true to continue on the captured context; otherwise, false. @@ -449,7 +450,7 @@ namespace System.Threading.Tasks _obj = task; - _result = default!; // TODO-NULLABLE-GENERIC + _result = default!; // TODO-NULLABLE: Remove ! when nullable attributes are respected _continueOnCapturedContext = true; _token = 0; } @@ -468,7 +469,7 @@ namespace System.Threading.Tasks _obj = source; _token = token; - _result = default!; // TODO-NULLABLE-GENERIC + _result = default!; // TODO-NULLABLE: Remove ! when nullable attributes are respected _continueOnCapturedContext = true; } diff --git a/src/System.Private.CoreLib/shared/System/Threading/Thread.cs b/src/System.Private.CoreLib/shared/System/Threading/Thread.cs index 39f0f63..9707b03 100644 --- a/src/System.Private.CoreLib/shared/System/Threading/Thread.cs +++ b/src/System.Private.CoreLib/shared/System/Threading/Thread.cs @@ -4,6 +4,7 @@ using System.Collections.Generic; using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.Runtime.ConstrainedExecution; using System.Security.Principal; @@ -151,7 +152,7 @@ namespace System.Threading } Interlocked.CompareExchange(ref s_asyncLocalPrincipal, new AsyncLocal(), null); } - s_asyncLocalPrincipal!.Value = value; // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 + s_asyncLocalPrincipal!.Value = value; // TODO-NULLABLE: Remove ! when compiler specially-recognizes CompareExchange for nullability } } @@ -282,7 +283,8 @@ namespace System.Threading public static int VolatileRead(ref int address) => Volatile.Read(ref address); public static long VolatileRead(ref long address) => Volatile.Read(ref address); public static IntPtr VolatileRead(ref IntPtr address) => Volatile.Read(ref address); - public static object? VolatileRead(ref object? address) => Volatile.Read(ref address); // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 + [return: NotNullIfNotNull("address")] + public static object? VolatileRead(ref object? address) => Volatile.Read(ref address); [CLSCompliant(false)] public static sbyte VolatileRead(ref sbyte address) => Volatile.Read(ref address); public static float VolatileRead(ref float address) => Volatile.Read(ref address); @@ -300,7 +302,7 @@ namespace System.Threading public static void VolatileWrite(ref int address, int value) => Volatile.Write(ref address, value); public static void VolatileWrite(ref long address, long value) => Volatile.Write(ref address, value); public static void VolatileWrite(ref IntPtr address, IntPtr value) => Volatile.Write(ref address, value); - public static void VolatileWrite(ref object? address, object? value) => Volatile.Write(ref address, value); + public static void VolatileWrite([NotNullIfNotNull("value")] ref object? address, object? value) => Volatile.Write(ref address, value); [CLSCompliant(false)] public static void VolatileWrite(ref sbyte address, sbyte value) => Volatile.Write(ref address, value); public static void VolatileWrite(ref float address, float value) => Volatile.Write(ref address, value); diff --git a/src/System.Private.CoreLib/shared/System/Threading/ThreadLocal.cs b/src/System.Private.CoreLib/shared/System/Threading/ThreadLocal.cs index f57afb9..1126ea3 100644 --- a/src/System.Private.CoreLib/shared/System/Threading/ThreadLocal.cs +++ b/src/System.Private.CoreLib/shared/System/Threading/ThreadLocal.cs @@ -4,6 +4,7 @@ using System.Collections.Generic; using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; // A class that provides a simple, lightweight implementation of thread-local lazy-initialization, where a value is initialized once per accessing // thread; this provides an alternative to using a ThreadStatic static variable and having @@ -201,7 +202,7 @@ namespace System.Threading // And clear the references from the slot table to the linked slot and the value so that // both can get garbage collected. - slotArray[id].Value!._value = default!; // TODO-NULLABLE-GENERIC + slotArray[id].Value!._value = default!; // TODO-NULLABLE: Remove ! when nullable attributes are respected slotArray[id].Value = null; } } @@ -248,6 +249,7 @@ namespace System.Threading /// will be used. /// [DebuggerBrowsable(DebuggerBrowsableState.Never)] + [MaybeNull] public T Value { get @@ -304,6 +306,7 @@ namespace System.Threading } } + [return: MaybeNull] private T GetValueSlow() { // If the object has been disposed, the id will be -1. @@ -319,7 +322,7 @@ namespace System.Threading T value; if (_valueFactory == null) { - value = default!; // TODO-NULLABLE-GENERIC + value = default!; } else { @@ -466,7 +469,7 @@ namespace System.Threading { // We can safely read linkedSlot.Value. Even if this ThreadLocal has been disposed in the meantime, the LinkedSlot // objects will never be assigned to another ThreadLocal instance. - valueList.Add(linkedSlot._value); + valueList.Add(linkedSlot._value!); } return valueList; @@ -493,7 +496,7 @@ namespace System.Threading { // We can safely read linkedSlot.Value. Even if this ThreadLocal has been disposed in the meantime, the LinkedSlot // objects will never be assigned to another ThreadLocal instance. - yield return linkedSlot._value; + yield return linkedSlot._value!; } } } @@ -536,6 +539,7 @@ namespace System.Threading /// Gets the value of the ThreadLocal<T> for debugging display purposes. It takes care of getting /// the value for the current thread in the ThreadLocal mode. + [MaybeNull] internal T ValueForDebugDisplay { get @@ -545,7 +549,7 @@ namespace System.Threading LinkedSlot? slot; if (slotArray == null || id >= slotArray.Length || (slot = slotArray[id].Value) == null || !_initialized) - return default!; // TODO-NULLABLE-GENERIC + return default!; return slot._value; } } @@ -671,7 +675,7 @@ namespace System.Threading internal volatile LinkedSlotVolatile[]? _slotArray; // The value for this slot. - internal T _value = default!; // TODO-NULLABLE-GENERIC + [AllowNull, MaybeNull] internal T _value = default!; // TODO-NULLABLE: Remove ! when nullable attributes are respected } /// diff --git a/src/System.Private.CoreLib/shared/System/Threading/Timer.cs b/src/System.Private.CoreLib/shared/System/Threading/Timer.cs index 8789065..be94ccb 100644 --- a/src/System.Private.CoreLib/shared/System/Threading/Timer.cs +++ b/src/System.Private.CoreLib/shared/System/Threading/Timer.cs @@ -612,7 +612,7 @@ namespace System.Threading if (toSignal is WaitHandle wh) { - EventWaitHandle.Set(wh.SafeWaitHandle!); // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/2384 + EventWaitHandle.Set(wh.SafeWaitHandle); } else { diff --git a/src/System.Private.CoreLib/shared/System/Threading/Volatile.cs b/src/System.Private.CoreLib/shared/System/Threading/Volatile.cs index 26d33a4..5c1df63 100644 --- a/src/System.Private.CoreLib/shared/System/Threading/Volatile.cs +++ b/src/System.Private.CoreLib/shared/System/Threading/Volatile.cs @@ -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. +using System.Diagnostics.CodeAnalysis; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using Internal.Runtime.CompilerServices; @@ -218,12 +219,13 @@ namespace System.Threading [Intrinsic] [NonVersionable] + [return: NotNullIfNotNull("location")] public static T Read(ref T location) where T : class? => Unsafe.As(Unsafe.As(ref location).Value); [Intrinsic] [NonVersionable] - public static void Write(ref T location, T value) where T : class? => + public static void Write([NotNullIfNotNull("value")] ref T location, T value) where T : class? => Unsafe.As(ref location).Value = value; #endregion } diff --git a/src/System.Private.CoreLib/shared/System/Threading/WaitHandle.cs b/src/System.Private.CoreLib/shared/System/Threading/WaitHandle.cs index 20aa3f7..75965a3 100644 --- a/src/System.Private.CoreLib/shared/System/Threading/WaitHandle.cs +++ b/src/System.Private.CoreLib/shared/System/Threading/WaitHandle.cs @@ -3,6 +3,7 @@ // See the LICENSE file in the project root for more information. using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using Microsoft.Win32.SafeHandles; namespace System.Threading @@ -78,7 +79,8 @@ namespace System.Threading } } - public SafeWaitHandle? SafeWaitHandle // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/2384 + [AllowNull] + public SafeWaitHandle SafeWaitHandle { get { @@ -334,7 +336,7 @@ namespace System.Threading { if (safeWaitHandles[i] != null) { - safeWaitHandles[i]!.DangerousRelease(); // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/34644 + safeWaitHandles[i]!.DangerousRelease(); // TODO-NULLABLE: Indexer nullability tracked (https://github.com/dotnet/roslyn/issues/34644) safeWaitHandles[i] = null; } } diff --git a/src/System.Private.CoreLib/shared/System/ThrowHelper.cs b/src/System.Private.CoreLib/shared/System/ThrowHelper.cs index f6805d8..e79b785 100644 --- a/src/System.Private.CoreLib/shared/System/ThrowHelper.cs +++ b/src/System.Private.CoreLib/shared/System/ThrowHelper.cs @@ -38,6 +38,7 @@ using System.Buffers; using System.Collections.Generic; using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.Runtime.CompilerServices; using System.Runtime.Serialization; @@ -46,83 +47,98 @@ namespace System [StackTraceHidden] internal static class ThrowHelper { + [DoesNotReturn] internal static void ThrowArrayTypeMismatchException() { throw new ArrayTypeMismatchException(); } + [DoesNotReturn] internal static void ThrowInvalidTypeWithPointersNotSupported(Type targetType) { throw new ArgumentException(SR.Format(SR.Argument_InvalidTypeWithPointersNotSupported, targetType)); } + [DoesNotReturn] internal static void ThrowIndexOutOfRangeException() { throw new IndexOutOfRangeException(); } + [DoesNotReturn] internal static void ThrowArgumentOutOfRangeException() { throw new ArgumentOutOfRangeException(); } + [DoesNotReturn] internal static void ThrowArgumentException_DestinationTooShort() { throw new ArgumentException(SR.Argument_DestinationTooShort, "destination"); } + [DoesNotReturn] internal static void ThrowArgumentException_OverlapAlignmentMismatch() { throw new ArgumentException(SR.Argument_OverlapAlignmentMismatch); } + [DoesNotReturn] internal static void ThrowArgumentException_CannotExtractScalar(ExceptionArgument argument) { throw GetArgumentException(ExceptionResource.Argument_CannotExtractScalar, argument); } + [DoesNotReturn] internal static void ThrowArgumentOutOfRange_IndexException() { throw GetArgumentOutOfRangeException(ExceptionArgument.index, ExceptionResource.ArgumentOutOfRange_Index); } + [DoesNotReturn] internal static void ThrowIndexArgumentOutOfRange_NeedNonNegNumException() { throw GetArgumentOutOfRangeException(ExceptionArgument.index, ExceptionResource.ArgumentOutOfRange_NeedNonNegNum); } + [DoesNotReturn] internal static void ThrowValueArgumentOutOfRange_NeedNonNegNumException() { throw GetArgumentOutOfRangeException(ExceptionArgument.value, ExceptionResource.ArgumentOutOfRange_NeedNonNegNum); } + [DoesNotReturn] internal static void ThrowLengthArgumentOutOfRange_ArgumentOutOfRange_NeedNonNegNum() { throw GetArgumentOutOfRangeException(ExceptionArgument.length, ExceptionResource.ArgumentOutOfRange_NeedNonNegNum); } + [DoesNotReturn] internal static void ThrowStartIndexArgumentOutOfRange_ArgumentOutOfRange_Index() { throw GetArgumentOutOfRangeException(ExceptionArgument.startIndex, ExceptionResource.ArgumentOutOfRange_Index); } + [DoesNotReturn] internal static void ThrowCountArgumentOutOfRange_ArgumentOutOfRange_Count() { throw GetArgumentOutOfRangeException(ExceptionArgument.count, ExceptionResource.ArgumentOutOfRange_Count); } + [DoesNotReturn] internal static void ThrowWrongKeyTypeArgumentException(T key, Type targetType) { // Generic key to move the boxing to the right hand side of throw throw GetWrongKeyTypeArgumentException((object?)key, targetType); } + [DoesNotReturn] internal static void ThrowWrongValueTypeArgumentException(T value, Type targetType) { // Generic key to move the boxing to the right hand side of throw @@ -134,23 +150,27 @@ namespace System return new ArgumentException(SR.Format(SR.Argument_AddingDuplicateWithKey, key)); } + [DoesNotReturn] internal static void ThrowAddingDuplicateWithKeyArgumentException(T key) { // Generic key to move the boxing to the right hand side of throw throw GetAddingDuplicateWithKeyArgumentException((object?)key); } + [DoesNotReturn] internal static void ThrowKeyNotFoundException(T key) { // Generic key to move the boxing to the right hand side of throw throw GetKeyNotFoundException((object?)key); } + [DoesNotReturn] internal static void ThrowArgumentException(ExceptionResource resource) { throw GetArgumentException(resource); } + [DoesNotReturn] internal static void ThrowArgumentException(ExceptionResource resource, ExceptionArgument argument) { throw GetArgumentException(resource, argument); @@ -161,171 +181,205 @@ namespace System return new ArgumentNullException(GetArgumentName(argument)); } + [DoesNotReturn] internal static void ThrowArgumentNullException(ExceptionArgument argument) { throw GetArgumentNullException(argument); } + [DoesNotReturn] internal static void ThrowArgumentNullException(ExceptionResource resource) { throw new ArgumentNullException(GetResourceString(resource)); } + [DoesNotReturn] internal static void ThrowArgumentNullException(ExceptionArgument argument, ExceptionResource resource) { throw new ArgumentNullException(GetArgumentName(argument), GetResourceString(resource)); } + [DoesNotReturn] internal static void ThrowArgumentOutOfRangeException(ExceptionArgument argument) { throw new ArgumentOutOfRangeException(GetArgumentName(argument)); } + [DoesNotReturn] internal static void ThrowArgumentOutOfRangeException(ExceptionArgument argument, ExceptionResource resource) { throw GetArgumentOutOfRangeException(argument, resource); } + [DoesNotReturn] internal static void ThrowArgumentOutOfRangeException(ExceptionArgument argument, int paramNumber, ExceptionResource resource) { throw GetArgumentOutOfRangeException(argument, paramNumber, resource); } + [DoesNotReturn] internal static void ThrowInvalidOperationException() { throw new InvalidOperationException(); } + [DoesNotReturn] internal static void ThrowInvalidOperationException(ExceptionResource resource) { throw GetInvalidOperationException(resource); } + [DoesNotReturn] internal static void ThrowInvalidOperationException_OutstandingReferences() { throw new InvalidOperationException(SR.Memory_OutstandingReferences); } + [DoesNotReturn] internal static void ThrowInvalidOperationException(ExceptionResource resource, Exception e) { throw new InvalidOperationException(GetResourceString(resource), e); } + [DoesNotReturn] internal static void ThrowSerializationException(ExceptionResource resource) { throw new SerializationException(GetResourceString(resource)); } + [DoesNotReturn] internal static void ThrowSecurityException(ExceptionResource resource) { throw new System.Security.SecurityException(GetResourceString(resource)); } + [DoesNotReturn] internal static void ThrowRankException(ExceptionResource resource) { throw new RankException(GetResourceString(resource)); } + [DoesNotReturn] internal static void ThrowNotSupportedException(ExceptionResource resource) { throw new NotSupportedException(GetResourceString(resource)); } + [DoesNotReturn] internal static void ThrowUnauthorizedAccessException(ExceptionResource resource) { throw new UnauthorizedAccessException(GetResourceString(resource)); } + [DoesNotReturn] internal static void ThrowObjectDisposedException(string objectName, ExceptionResource resource) { throw new ObjectDisposedException(objectName, GetResourceString(resource)); } + [DoesNotReturn] internal static void ThrowObjectDisposedException(ExceptionResource resource) { throw new ObjectDisposedException(null, GetResourceString(resource)); } + [DoesNotReturn] internal static void ThrowNotSupportedException() { throw new NotSupportedException(); } + [DoesNotReturn] internal static void ThrowAggregateException(List exceptions) { throw new AggregateException(exceptions); } + [DoesNotReturn] internal static void ThrowOutOfMemoryException() { throw new OutOfMemoryException(); } + [DoesNotReturn] internal static void ThrowArgumentException_Argument_InvalidArrayType() { throw new ArgumentException(SR.Argument_InvalidArrayType); } + [DoesNotReturn] internal static void ThrowInvalidOperationException_InvalidOperation_EnumNotStarted() { throw new InvalidOperationException(SR.InvalidOperation_EnumNotStarted); } + [DoesNotReturn] internal static void ThrowInvalidOperationException_InvalidOperation_EnumEnded() { throw new InvalidOperationException(SR.InvalidOperation_EnumEnded); } + [DoesNotReturn] internal static void ThrowInvalidOperationException_EnumCurrent(int index) { throw GetInvalidOperationException_EnumCurrent(index); } + [DoesNotReturn] internal static void ThrowInvalidOperationException_InvalidOperation_EnumFailedVersion() { throw new InvalidOperationException(SR.InvalidOperation_EnumFailedVersion); } + [DoesNotReturn] internal static void ThrowInvalidOperationException_InvalidOperation_EnumOpCantHappen() { throw new InvalidOperationException(SR.InvalidOperation_EnumOpCantHappen); } + [DoesNotReturn] internal static void ThrowInvalidOperationException_InvalidOperation_NoValue() { throw new InvalidOperationException(SR.InvalidOperation_NoValue); } + [DoesNotReturn] internal static void ThrowInvalidOperationException_ConcurrentOperationsNotSupported() { throw new InvalidOperationException(SR.InvalidOperation_ConcurrentOperationsNotSupported); } + [DoesNotReturn] internal static void ThrowInvalidOperationException_HandleIsNotInitialized() { throw new InvalidOperationException(SR.InvalidOperation_HandleIsNotInitialized); } + [DoesNotReturn] internal static void ThrowInvalidOperationException_HandleIsNotPinned() { throw new InvalidOperationException(SR.InvalidOperation_HandleIsNotPinned); } + [DoesNotReturn] internal static void ThrowArraySegmentCtorValidationFailedExceptions(Array? array, int offset, int count) { throw GetArraySegmentCtorValidationFailedException(array, offset, count); } + [DoesNotReturn] internal static void ThrowFormatException_BadFormatSpecifier() { throw new FormatException(SR.Argument_BadFormatSpecifier); } + [DoesNotReturn] internal static void ThrowArgumentOutOfRangeException_PrecisionTooLarge() { throw new ArgumentOutOfRangeException("precision", SR.Format(SR.Argument_PrecisionTooLarge, StandardFormat.MaxPrecision)); } + [DoesNotReturn] internal static void ThrowArgumentOutOfRangeException_SymbolDoesNotFit() { throw new ArgumentOutOfRangeException("symbol", SR.Argument_BadFormatSpecifier); @@ -399,7 +453,7 @@ namespace System internal static void IfNullAndNullsAreIllegalThenThrow(object? value, ExceptionArgument argName) { // Note that default(T) is not equal to null for value types except when T is Nullable. - if (!(default(T)! == null) && value == null) // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/34757 + if (!(default(T)! == null) && value == null) // TODO-NULLABLE: default(T) == null warning (https://github.com/dotnet/roslyn/issues/34757) ThrowHelper.ThrowArgumentNullException(argName); } diff --git a/src/System.Private.CoreLib/shared/System/TimeZone.cs b/src/System.Private.CoreLib/shared/System/TimeZone.cs index b9dc233..0775e5b 100644 --- a/src/System.Private.CoreLib/shared/System/TimeZone.cs +++ b/src/System.Private.CoreLib/shared/System/TimeZone.cs @@ -42,7 +42,7 @@ namespace System object o = new object(); Interlocked.CompareExchange(ref s_InternalSyncObject, o, null); } - return s_InternalSyncObject!; // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 + return s_InternalSyncObject!; // TODO-NULLABLE: Remove ! when compiler specially-recognizes CompareExchange for nullability } } diff --git a/src/System.Private.CoreLib/shared/System/TimeZoneInfo.AdjustmentRule.cs b/src/System.Private.CoreLib/shared/System/TimeZoneInfo.AdjustmentRule.cs index 4ba7f28..a3ffb1c 100644 --- a/src/System.Private.CoreLib/shared/System/TimeZoneInfo.AdjustmentRule.cs +++ b/src/System.Private.CoreLib/shared/System/TimeZoneInfo.AdjustmentRule.cs @@ -9,7 +9,7 @@ namespace System public sealed partial class TimeZoneInfo { [Serializable] - public sealed class AdjustmentRule : IEquatable, ISerializable, IDeserializationCallback + public sealed class AdjustmentRule : IEquatable, ISerializable, IDeserializationCallback { private static readonly TimeSpan DaylightDeltaAdjustment = TimeSpan.FromHours(24.0); private static readonly TimeSpan MaxDaylightDelta = TimeSpan.FromHours(12.0); @@ -44,7 +44,9 @@ namespace System (DaylightTransitionStart != default && DaylightTransitionStart.TimeOfDay != DateTime.MinValue) || (DaylightTransitionEnd != default && DaylightTransitionEnd.TimeOfDay != DateTime.MinValue.AddMilliseconds(1)); +#pragma warning disable CS8614 // TODO-NULLABLE: Covariant interface arguments (https://github.com/dotnet/roslyn/issues/35817) public bool Equals(AdjustmentRule? other) => +#pragma warning restore CS8614 other != null && _dateStart == other._dateStart && _dateEnd == other._dateEnd && diff --git a/src/System.Private.CoreLib/shared/System/TimeZoneInfo.Unix.cs b/src/System.Private.CoreLib/shared/System/TimeZoneInfo.Unix.cs index bc6ac41..1187eb5 100644 --- a/src/System.Private.CoreLib/shared/System/TimeZoneInfo.Unix.cs +++ b/src/System.Private.CoreLib/shared/System/TimeZoneInfo.Unix.cs @@ -5,11 +5,13 @@ using System.Buffers; using System.Collections.Generic; using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.IO; using System.Text; using System.Threading; using System.Security; +using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using Internal.IO; @@ -307,7 +309,7 @@ namespace System /// 3. Look for the data in GetTimeZoneDirectory()/localtime. /// 4. Use UTC if all else fails. /// - private static bool TryGetLocalTzFile(out byte[]? rawData, out string? id) // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 + private static bool TryGetLocalTzFile([NotNullWhen(true)] out byte[]? rawData, [NotNullWhen(true)] out string? id) { rawData = null; id = null; @@ -357,7 +359,7 @@ namespace System return result; } - private static bool TryLoadTzFile(string tzFilePath, ref byte[]? rawData, ref string? id) // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 + private static bool TryLoadTzFile(string tzFilePath, [NotNullWhen(true)] ref byte[]? rawData, [NotNullWhen(true)] ref string? id) { if (File.Exists(tzFilePath)) { @@ -394,7 +396,7 @@ namespace System if (symlinkPath != null) { // symlinkPath can be relative path, use Path to get the full absolute path. - symlinkPath = Path.GetFullPath(symlinkPath, Path.GetDirectoryName(tzFilePath)!); // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 + symlinkPath = Path.GetFullPath(symlinkPath, Path.GetDirectoryName(tzFilePath)!); // TODO-NULLABLE: Remove ! when nullable attributes are respected string timeZoneDirectory = GetTimeZoneDirectory(); if (symlinkPath.StartsWith(timeZoneDirectory, StringComparison.Ordinal)) @@ -614,9 +616,9 @@ namespace System { byte[]? rawData; string? id; - if (TryGetLocalTzFile(out rawData, out id)) // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 + if (TryGetLocalTzFile(out rawData, out id)) { - TimeZoneInfo? result = GetTimeZoneFromTzData(rawData!, id!); + TimeZoneInfo? result = GetTimeZoneFromTzData(rawData!, id!); // TODO-NULLABLE: Remove ! when nullable attributes are respected if (result != null) { return result; @@ -991,7 +993,7 @@ namespace System { if (!IsValidAdjustmentRuleOffest(timeZoneBaseUtcOffset, r)) { - NormalizeAdjustmentRuleOffset(timeZoneBaseUtcOffset, ref r!); // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 + NormalizeAdjustmentRuleOffset(timeZoneBaseUtcOffset, ref r!); // TODO-NULLABLE: Remove ! when nullable attributes are respected } rulesList.Add(r); diff --git a/src/System.Private.CoreLib/shared/System/TimeZoneInfo.Win32.cs b/src/System.Private.CoreLib/shared/System/TimeZoneInfo.Win32.cs index a261b75..e1cfe4e 100644 --- a/src/System.Private.CoreLib/shared/System/TimeZoneInfo.Win32.cs +++ b/src/System.Private.CoreLib/shared/System/TimeZoneInfo.Win32.cs @@ -260,7 +260,7 @@ namespace System if (TryGetTimeZone(dynamicTimeZoneKeyName, dynamicTimeZoneInformation.DynamicDaylightTimeDisabled != 0, out TimeZoneInfo? zone, out _, cachedData) == TimeZoneInfoResult.Success) { // successfully loaded the time zone from the registry - return zone!; // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 + return zone!; } } @@ -274,7 +274,7 @@ namespace System if (TryGetTimeZone(id, dstDisabled, out TimeZoneInfo? zone, out _, cachedData) == TimeZoneInfoResult.Success) { // successfully loaded the time zone from the registry - return zone!; // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 + return zone!; } } @@ -352,7 +352,7 @@ namespace System if (result == TimeZoneInfoResult.Success) { - return value!; // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 + return value!; } else if (result == TimeZoneInfoResult.InvalidTimeZoneException) { @@ -563,8 +563,8 @@ namespace System // read LastEntry {(yearN, 1, 1) - MaxValue } // read the FirstEntry and LastEntry key values (ex: "1980", "2038") - int first = (int)dynamicKey.GetValue(FirstEntryValue, -1)!; // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/34976 - int last = (int)dynamicKey.GetValue(LastEntryValue, -1)!; // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/34976 + int first = (int)dynamicKey.GetValue(FirstEntryValue, -1)!; // TODO-NULLABLE: Remove ! when nullable attributes are respected + int last = (int)dynamicKey.GetValue(LastEntryValue, -1)!; // TODO-NULLABLE: Remove ! when nullable attributes are respected if (first == -1 || last == -1 || first > last) { diff --git a/src/System.Private.CoreLib/shared/System/TimeZoneInfo.cs b/src/System.Private.CoreLib/shared/System/TimeZoneInfo.cs index cef843f..768385c 100644 --- a/src/System.Private.CoreLib/shared/System/TimeZoneInfo.cs +++ b/src/System.Private.CoreLib/shared/System/TimeZoneInfo.cs @@ -5,6 +5,7 @@ using System.Collections.Generic; using System.Collections.ObjectModel; using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.Runtime.Serialization; using System.Threading; @@ -29,7 +30,7 @@ namespace System [Serializable] [System.Runtime.CompilerServices.TypeForwardedFrom("System.Core, Version=3.5.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")] - public sealed partial class TimeZoneInfo : IEquatable, ISerializable, IDeserializationCallback + public sealed partial class TimeZoneInfo : IEquatable, ISerializable, IDeserializationCallback { private enum TimeZoneInfoResult { @@ -764,7 +765,9 @@ namespace System /// Returns value equality. Equals does not compare any localizable /// String objects (DisplayName, StandardName, DaylightName). /// +#pragma warning disable CS8614 // TODO-NULLABLE: Covariant interface arguments (https://github.com/dotnet/roslyn/issues/35817) public bool Equals(TimeZoneInfo? other) => +#pragma warning restore CS8614 other != null && string.Equals(_id, other._id, StringComparison.OrdinalIgnoreCase) && HasSameRules(other); @@ -1902,17 +1905,17 @@ namespace System // uses reference equality with the Utc object. if (!id.Equals(UtcId, StringComparison.OrdinalIgnoreCase)) { - cachedData._systemTimeZones.Add(id, match!); // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 + cachedData._systemTimeZones.Add(id, match!); } - if (dstDisabled && match!._supportsDaylightSavingTime) // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 + if (dstDisabled && match!._supportsDaylightSavingTime) { // we found a cache hit but we want a time zone without DST and this one has DST data value = CreateCustomTimeZone(match._id, match._baseUtcOffset, match._displayName, match._standardDisplayName); } else { - value = new TimeZoneInfo(match!._id, match._baseUtcOffset, match._displayName, match._standardDisplayName, // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 + value = new TimeZoneInfo(match!._id, match._baseUtcOffset, match._displayName, match._standardDisplayName, match._daylightDisplayName, match._adjustmentRules, disableDaylightSavingTime: false); } } @@ -2017,7 +2020,7 @@ namespace System /// This method should not be called at all but is here in case something changes in the future /// or if really old time zones are present on the OS (no combination is known at the moment) /// - private static void NormalizeAdjustmentRuleOffset(TimeSpan baseUtcOffset, ref AdjustmentRule adjustmentRule) + private static void NormalizeAdjustmentRuleOffset(TimeSpan baseUtcOffset, [NotNull] ref AdjustmentRule adjustmentRule) { // Certain time zones such as: // Time Zone start date end date offset diff --git a/src/System.Private.CoreLib/shared/System/Tuple.cs b/src/System.Private.CoreLib/shared/System/Tuple.cs index 6439720..034264d 100644 --- a/src/System.Private.CoreLib/shared/System/Tuple.cs +++ b/src/System.Private.CoreLib/shared/System/Tuple.cs @@ -156,7 +156,7 @@ namespace System int IStructuralEquatable.GetHashCode(IEqualityComparer comparer) { - return comparer.GetHashCode(m_Item1!); // TODO-NULLABLE-GENERIC + return comparer.GetHashCode(m_Item1!); } int ITupleInternal.GetHashCode(IEqualityComparer comparer) @@ -261,7 +261,7 @@ namespace System int IStructuralEquatable.GetHashCode(IEqualityComparer comparer) { - return Tuple.CombineHashCodes(comparer.GetHashCode(m_Item1!), comparer.GetHashCode(m_Item2!)); // TODO-NULLABLE-GENERIC + return Tuple.CombineHashCodes(comparer.GetHashCode(m_Item1!), comparer.GetHashCode(m_Item2!)); } int ITupleInternal.GetHashCode(IEqualityComparer comparer) @@ -379,7 +379,7 @@ namespace System int IStructuralEquatable.GetHashCode(IEqualityComparer comparer) { - return Tuple.CombineHashCodes(comparer.GetHashCode(m_Item1!), comparer.GetHashCode(m_Item2!), comparer.GetHashCode(m_Item3!)); // TODO-NULLABLE-GENERIC + return Tuple.CombineHashCodes(comparer.GetHashCode(m_Item1!), comparer.GetHashCode(m_Item2!), comparer.GetHashCode(m_Item3!)); } int ITupleInternal.GetHashCode(IEqualityComparer comparer) @@ -508,7 +508,7 @@ namespace System int IStructuralEquatable.GetHashCode(IEqualityComparer comparer) { - return Tuple.CombineHashCodes(comparer.GetHashCode(m_Item1!), comparer.GetHashCode(m_Item2!), comparer.GetHashCode(m_Item3!), comparer.GetHashCode(m_Item4!)); // TODO-NULLABLE-GENERIC + return Tuple.CombineHashCodes(comparer.GetHashCode(m_Item1!), comparer.GetHashCode(m_Item2!), comparer.GetHashCode(m_Item3!), comparer.GetHashCode(m_Item4!)); } int ITupleInternal.GetHashCode(IEqualityComparer comparer) @@ -648,7 +648,7 @@ namespace System int IStructuralEquatable.GetHashCode(IEqualityComparer comparer) { - return Tuple.CombineHashCodes(comparer.GetHashCode(m_Item1!), comparer.GetHashCode(m_Item2!), comparer.GetHashCode(m_Item3!), comparer.GetHashCode(m_Item4!), comparer.GetHashCode(m_Item5!)); // TODO-NULLABLE-GENERIC + return Tuple.CombineHashCodes(comparer.GetHashCode(m_Item1!), comparer.GetHashCode(m_Item2!), comparer.GetHashCode(m_Item3!), comparer.GetHashCode(m_Item4!), comparer.GetHashCode(m_Item5!)); } int ITupleInternal.GetHashCode(IEqualityComparer comparer) @@ -799,7 +799,7 @@ namespace System int IStructuralEquatable.GetHashCode(IEqualityComparer comparer) { - return Tuple.CombineHashCodes(comparer.GetHashCode(m_Item1!), comparer.GetHashCode(m_Item2!), comparer.GetHashCode(m_Item3!), comparer.GetHashCode(m_Item4!), comparer.GetHashCode(m_Item5!), comparer.GetHashCode(m_Item6!)); // TODO-NULLABLE-GENERIC + return Tuple.CombineHashCodes(comparer.GetHashCode(m_Item1!), comparer.GetHashCode(m_Item2!), comparer.GetHashCode(m_Item3!), comparer.GetHashCode(m_Item4!), comparer.GetHashCode(m_Item5!), comparer.GetHashCode(m_Item6!)); } int ITupleInternal.GetHashCode(IEqualityComparer comparer) @@ -961,7 +961,7 @@ namespace System int IStructuralEquatable.GetHashCode(IEqualityComparer comparer) { - return Tuple.CombineHashCodes(comparer.GetHashCode(m_Item1!), comparer.GetHashCode(m_Item2!), comparer.GetHashCode(m_Item3!), comparer.GetHashCode(m_Item4!), comparer.GetHashCode(m_Item5!), comparer.GetHashCode(m_Item6!), comparer.GetHashCode(m_Item7!)); // TODO-NULLABLE-GENERIC + return Tuple.CombineHashCodes(comparer.GetHashCode(m_Item1!), comparer.GetHashCode(m_Item2!), comparer.GetHashCode(m_Item3!), comparer.GetHashCode(m_Item4!), comparer.GetHashCode(m_Item5!), comparer.GetHashCode(m_Item6!), comparer.GetHashCode(m_Item7!)); } int ITupleInternal.GetHashCode(IEqualityComparer comparer) @@ -1031,7 +1031,7 @@ namespace System [Serializable] [System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")] - public class Tuple : IStructuralEquatable, IStructuralComparable, IComparable, ITupleInternal, ITuple + public class Tuple : IStructuralEquatable, IStructuralComparable, IComparable, ITupleInternal, ITuple where TRest : object { private readonly T1 m_Item1; // Do not rename (binary serialization) private readonly T2 m_Item2; // Do not rename (binary serialization) @@ -1140,7 +1140,7 @@ namespace System int IStructuralEquatable.GetHashCode(IEqualityComparer comparer) { // We want to have a limited hash in this case. We'll use the last 8 elements of the tuple - ITupleInternal t = (ITupleInternal)m_Rest!; // TODO-NULLABLE-GENERIC + ITupleInternal t = (ITupleInternal)m_Rest; if (t.Length >= 8) { return t.GetHashCode(comparer); } // In this case, the rest memeber has less than 8 elements so we need to combine some our elements with the elements in rest @@ -1148,19 +1148,19 @@ namespace System switch (k) { case 1: - return Tuple.CombineHashCodes(comparer.GetHashCode(m_Item7!), t.GetHashCode(comparer)); // TODO-NULLABLE-GENERIC + return Tuple.CombineHashCodes(comparer.GetHashCode(m_Item7!), t.GetHashCode(comparer)); case 2: - return Tuple.CombineHashCodes(comparer.GetHashCode(m_Item6!), comparer.GetHashCode(m_Item7!), t.GetHashCode(comparer)); // TODO-NULLABLE-GENERIC + return Tuple.CombineHashCodes(comparer.GetHashCode(m_Item6!), comparer.GetHashCode(m_Item7!), t.GetHashCode(comparer)); case 3: - return Tuple.CombineHashCodes(comparer.GetHashCode(m_Item5!), comparer.GetHashCode(m_Item6!), comparer.GetHashCode(m_Item7!), t.GetHashCode(comparer)); // TODO-NULLABLE-GENERIC + return Tuple.CombineHashCodes(comparer.GetHashCode(m_Item5!), comparer.GetHashCode(m_Item6!), comparer.GetHashCode(m_Item7!), t.GetHashCode(comparer)); case 4: - return Tuple.CombineHashCodes(comparer.GetHashCode(m_Item4!), comparer.GetHashCode(m_Item5!), comparer.GetHashCode(m_Item6!), comparer.GetHashCode(m_Item7!), t.GetHashCode(comparer)); // TODO-NULLABLE-GENERIC + return Tuple.CombineHashCodes(comparer.GetHashCode(m_Item4!), comparer.GetHashCode(m_Item5!), comparer.GetHashCode(m_Item6!), comparer.GetHashCode(m_Item7!), t.GetHashCode(comparer)); case 5: - return Tuple.CombineHashCodes(comparer.GetHashCode(m_Item3!), comparer.GetHashCode(m_Item4!), comparer.GetHashCode(m_Item5!), comparer.GetHashCode(m_Item6!), comparer.GetHashCode(m_Item7!), t.GetHashCode(comparer)); // TODO-NULLABLE-GENERIC + return Tuple.CombineHashCodes(comparer.GetHashCode(m_Item3!), comparer.GetHashCode(m_Item4!), comparer.GetHashCode(m_Item5!), comparer.GetHashCode(m_Item6!), comparer.GetHashCode(m_Item7!), t.GetHashCode(comparer)); case 6: - return Tuple.CombineHashCodes(comparer.GetHashCode(m_Item2!), comparer.GetHashCode(m_Item3!), comparer.GetHashCode(m_Item4!), comparer.GetHashCode(m_Item5!), comparer.GetHashCode(m_Item6!), comparer.GetHashCode(m_Item7!), t.GetHashCode(comparer)); // TODO-NULLABLE-GENERIC + return Tuple.CombineHashCodes(comparer.GetHashCode(m_Item2!), comparer.GetHashCode(m_Item3!), comparer.GetHashCode(m_Item4!), comparer.GetHashCode(m_Item5!), comparer.GetHashCode(m_Item6!), comparer.GetHashCode(m_Item7!), t.GetHashCode(comparer)); case 7: - return Tuple.CombineHashCodes(comparer.GetHashCode(m_Item1!), comparer.GetHashCode(m_Item2!), comparer.GetHashCode(m_Item3!), comparer.GetHashCode(m_Item4!), comparer.GetHashCode(m_Item5!), comparer.GetHashCode(m_Item6!), comparer.GetHashCode(m_Item7!), t.GetHashCode(comparer)); // TODO-NULLABLE-GENERIC + return Tuple.CombineHashCodes(comparer.GetHashCode(m_Item1!), comparer.GetHashCode(m_Item2!), comparer.GetHashCode(m_Item3!), comparer.GetHashCode(m_Item4!), comparer.GetHashCode(m_Item5!), comparer.GetHashCode(m_Item6!), comparer.GetHashCode(m_Item7!), t.GetHashCode(comparer)); } Debug.Fail("Missed all cases for computing Tuple hash code"); return -1; @@ -1193,7 +1193,7 @@ namespace System sb.Append(", "); sb.Append(m_Item7); sb.Append(", "); - return ((ITupleInternal)m_Rest!).ToString(sb); // TODO-NULLABLE-GENERIC + return ((ITupleInternal)m_Rest).ToString(sb); } /// @@ -1203,7 +1203,7 @@ namespace System { get { - return 7 + ((ITupleInternal)Rest!).Length; // TODO-NULLABLE-GENERIC + return 7 + ((ITupleInternal)Rest).Length; } } @@ -1232,7 +1232,7 @@ namespace System return Item7; } - return ((ITupleInternal)Rest!)[index - 7]; // TODO-NULLABLE-GENERIC + return ((ITupleInternal)Rest)[index - 7]; } } } diff --git a/src/System.Private.CoreLib/shared/System/Type.Helpers.cs b/src/System.Private.CoreLib/shared/System/Type.Helpers.cs index 0e871c6..0f171ec 100644 --- a/src/System.Private.CoreLib/shared/System/Type.Helpers.cs +++ b/src/System.Private.CoreLib/shared/System/Type.Helpers.cs @@ -135,7 +135,7 @@ namespace System for (int i = 0; i < c.Length; i++) { if (c[i] != null) - ret[cnt++] = c[i]!; // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/34644 + ret[cnt++] = c[i]!; // TODO-NULLABLE: Indexer nullability tracked (https://github.com/dotnet/roslyn/issues/34644) } return ret; } @@ -270,7 +270,7 @@ namespace System { for (i = 0; i < m.Length; i++) if (m[i] != null) - ret[cnt++] = m[i]!; // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/34644 + ret[cnt++] = m[i]!; // TODO-NULLABLE: Indexer nullability tracked (https://github.com/dotnet/roslyn/issues/34644) } // Copy the Constructors @@ -278,7 +278,7 @@ namespace System { for (i = 0; i < c.Length; i++) if (c[i] != null) - ret[cnt++] = c[i]!; // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/34644 + ret[cnt++] = c[i]!; // TODO-NULLABLE: Indexer nullability tracked (https://github.com/dotnet/roslyn/issues/34644) } // Copy the Fields @@ -286,7 +286,7 @@ namespace System { for (i = 0; i < f.Length; i++) if (f[i] != null) - ret[cnt++] = f[i]!; // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/34644 + ret[cnt++] = f[i]!; // TODO-NULLABLE: Indexer nullability tracked (https://github.com/dotnet/roslyn/issues/34644) } // Copy the Properties @@ -294,7 +294,7 @@ namespace System { for (i = 0; i < p.Length; i++) if (p[i] != null) - ret[cnt++] = p[i]!; // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/34644 + ret[cnt++] = p[i]!; // TODO-NULLABLE: Indexer nullability tracked (https://github.com/dotnet/roslyn/issues/34644) } // Copy the Events @@ -302,7 +302,7 @@ namespace System { for (i = 0; i < e.Length; i++) if (e[i] != null) - ret[cnt++] = e[i]!; // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/34644 + ret[cnt++] = e[i]!; // TODO-NULLABLE: Indexer nullability tracked (https://github.com/dotnet/roslyn/issues/34644) } // Copy the Types @@ -310,7 +310,7 @@ namespace System { for (i = 0; i < t.Length; i++) if (t[i] != null) - ret[cnt++] = t[i]!; // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/34644 + ret[cnt++] = t[i]!; // TODO-NULLABLE: Indexer nullability tracked (https://github.com/dotnet/roslyn/issues/34644) } return ret; diff --git a/src/System.Private.CoreLib/shared/System/ValueTuple.cs b/src/System.Private.CoreLib/shared/System/ValueTuple.cs index 72c13b5..774f3e3 100644 --- a/src/System.Private.CoreLib/shared/System/ValueTuple.cs +++ b/src/System.Private.CoreLib/shared/System/ValueTuple.cs @@ -411,12 +411,12 @@ namespace System int IStructuralEquatable.GetHashCode(IEqualityComparer comparer) { - return comparer.GetHashCode(Item1!); // TODO-NULLABLE-GENERIC + return comparer.GetHashCode(Item1!); } int IValueTupleInternal.GetHashCode(IEqualityComparer comparer) { - return comparer.GetHashCode(Item1!); // TODO-NULLABLE-GENERIC + return comparer.GetHashCode(Item1!); } /// @@ -616,7 +616,7 @@ namespace System private int GetHashCodeCore(IEqualityComparer comparer) { return ValueTuple.CombineHashCodes(comparer.GetHashCode(Item1!), - comparer.GetHashCode(Item2!)); // TODO-NULLABLE-GENERIC + comparer.GetHashCode(Item2!)); } int IValueTupleInternal.GetHashCode(IEqualityComparer comparer) @@ -824,7 +824,7 @@ namespace System { return ValueTuple.CombineHashCodes(comparer.GetHashCode(Item1!), comparer.GetHashCode(Item2!), - comparer.GetHashCode(Item3!)); // TODO-NULLABLE-GENERIC + comparer.GetHashCode(Item3!)); } int IValueTupleInternal.GetHashCode(IEqualityComparer comparer) @@ -1049,7 +1049,7 @@ namespace System return ValueTuple.CombineHashCodes(comparer.GetHashCode(Item1!), comparer.GetHashCode(Item2!), comparer.GetHashCode(Item3!), - comparer.GetHashCode(Item4!)); // TODO-NULLABLE-GENERIC + comparer.GetHashCode(Item4!)); } int IValueTupleInternal.GetHashCode(IEqualityComparer comparer) @@ -1293,7 +1293,7 @@ namespace System comparer.GetHashCode(Item2!), comparer.GetHashCode(Item3!), comparer.GetHashCode(Item4!), - comparer.GetHashCode(Item5!)); // TODO-NULLABLE-GENERIC + comparer.GetHashCode(Item5!)); } int IValueTupleInternal.GetHashCode(IEqualityComparer comparer) @@ -1556,7 +1556,7 @@ namespace System comparer.GetHashCode(Item3!), comparer.GetHashCode(Item4!), comparer.GetHashCode(Item5!), - comparer.GetHashCode(Item6!)); // TODO-NULLABLE-GENERIC + comparer.GetHashCode(Item6!)); } int IValueTupleInternal.GetHashCode(IEqualityComparer comparer) @@ -1838,7 +1838,7 @@ namespace System comparer.GetHashCode(Item4!), comparer.GetHashCode(Item5!), comparer.GetHashCode(Item6!), - comparer.GetHashCode(Item7!)); // TODO-NULLABLE-GENERIC + comparer.GetHashCode(Item7!)); } int IValueTupleInternal.GetHashCode(IEqualityComparer comparer) @@ -2203,7 +2203,7 @@ namespace System { return ValueTuple.CombineHashCodes(comparer.GetHashCode(Item1!), comparer.GetHashCode(Item2!), comparer.GetHashCode(Item3!), comparer.GetHashCode(Item4!), comparer.GetHashCode(Item5!), comparer.GetHashCode(Item6!), - comparer.GetHashCode(Item7!)); // TODO-NULLABLE-GENERIC + comparer.GetHashCode(Item7!)); } int size = rest.Length; @@ -2214,27 +2214,27 @@ namespace System switch (k) { case 1: - return ValueTuple.CombineHashCodes(comparer.GetHashCode(Item7!), rest.GetHashCode(comparer)); // TODO-NULLABLE-GENERIC + return ValueTuple.CombineHashCodes(comparer.GetHashCode(Item7!), rest.GetHashCode(comparer)); case 2: - return ValueTuple.CombineHashCodes(comparer.GetHashCode(Item6!), comparer.GetHashCode(Item7!), rest.GetHashCode(comparer)); // TODO-NULLABLE-GENERIC + return ValueTuple.CombineHashCodes(comparer.GetHashCode(Item6!), comparer.GetHashCode(Item7!), rest.GetHashCode(comparer)); case 3: return ValueTuple.CombineHashCodes(comparer.GetHashCode(Item5!), comparer.GetHashCode(Item6!), comparer.GetHashCode(Item7!), - rest.GetHashCode(comparer)); // TODO-NULLABLE-GENERIC + rest.GetHashCode(comparer)); case 4: return ValueTuple.CombineHashCodes(comparer.GetHashCode(Item4!), comparer.GetHashCode(Item5!), comparer.GetHashCode(Item6!), - comparer.GetHashCode(Item7!), rest.GetHashCode(comparer)); // TODO-NULLABLE-GENERIC + comparer.GetHashCode(Item7!), rest.GetHashCode(comparer)); case 5: return ValueTuple.CombineHashCodes(comparer.GetHashCode(Item3!), comparer.GetHashCode(Item4!), comparer.GetHashCode(Item5!), - comparer.GetHashCode(Item6!), comparer.GetHashCode(Item7!), rest.GetHashCode(comparer)); // TODO-NULLABLE-GENERIC + comparer.GetHashCode(Item6!), comparer.GetHashCode(Item7!), rest.GetHashCode(comparer)); case 6: return ValueTuple.CombineHashCodes(comparer.GetHashCode(Item2!), comparer.GetHashCode(Item3!), comparer.GetHashCode(Item4!), comparer.GetHashCode(Item5!), comparer.GetHashCode(Item6!), comparer.GetHashCode(Item7!), - rest.GetHashCode(comparer)); // TODO-NULLABLE-GENERIC + rest.GetHashCode(comparer)); case 7: case 8: return ValueTuple.CombineHashCodes(comparer.GetHashCode(Item1!), comparer.GetHashCode(Item2!), comparer.GetHashCode(Item3!), comparer.GetHashCode(Item4!), comparer.GetHashCode(Item5!), comparer.GetHashCode(Item6!), - comparer.GetHashCode(Item7!), rest.GetHashCode(comparer)); // TODO-NULLABLE-GENERIC + comparer.GetHashCode(Item7!), rest.GetHashCode(comparer)); } Debug.Fail("Missed all cases for computing ValueTuple hash code"); diff --git a/src/System.Private.CoreLib/shared/System/Version.cs b/src/System.Private.CoreLib/shared/System/Version.cs index 3b8d1cb..b3e770c 100644 --- a/src/System.Private.CoreLib/shared/System/Version.cs +++ b/src/System.Private.CoreLib/shared/System/Version.cs @@ -6,6 +6,7 @@ using System.Globalization; using System.Diagnostics; using System.Text; using System.Runtime.CompilerServices; +using System.Diagnostics.CodeAnalysis; namespace System { @@ -17,7 +18,7 @@ namespace System [Serializable] [System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")] - public sealed class Version : ICloneable, IComparable, IComparable, IEquatable, ISpanFormattable + public sealed class Version : ICloneable, IComparable, IComparable, IEquatable, ISpanFormattable { // AssemblyName depends on the order staying the same private readonly int _Major; // Do not rename (binary serialization) @@ -167,7 +168,9 @@ namespace System return Equals(obj as Version); } +#pragma warning disable CS8614 // TODO-NULLABLE: Covariant interface arguments (https://github.com/dotnet/roslyn/issues/35817) public bool Equals(Version? obj) +#pragma warning restore CS8614 { return object.ReferenceEquals(obj, this) || (!(obj is null) && @@ -306,7 +309,7 @@ namespace System public static Version Parse(ReadOnlySpan input) => ParseVersion(input, throwOnFailure: true)!; - public static bool TryParse(string? input, out Version? result) // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 + public static bool TryParse(string? input, [NotNullWhen(true)] out Version? result) { if (input == null) { @@ -317,7 +320,7 @@ namespace System return (result = ParseVersion(input.AsSpan(), throwOnFailure: false)) != null; } - public static bool TryParse(ReadOnlySpan input, out Version? result) => + public static bool TryParse(ReadOnlySpan input, [NotNullWhen(true)] out Version? result) => (result = ParseVersion(input, throwOnFailure: false)) != null; private static Version? ParseVersion(ReadOnlySpan input, bool throwOnFailure) diff --git a/src/System.Private.CoreLib/shared/System/WinRTFolderPaths.cs b/src/System.Private.CoreLib/shared/System/WinRTFolderPaths.cs index a833f55..b0986da 100644 --- a/src/System.Private.CoreLib/shared/System/WinRTFolderPaths.cs +++ b/src/System.Private.CoreLib/shared/System/WinRTFolderPaths.cs @@ -130,7 +130,7 @@ namespace System case SpecialFolder.System: return SystemDirectory; case SpecialFolder.Windows: - return Path.GetDirectoryName(SystemDirectory)!; // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 + return Path.GetDirectoryName(SystemDirectory)!; // TODO-NULLABLE: Remove ! when nullable attributes are respected default: return string.Empty; } diff --git a/src/System.Private.CoreLib/src/System/Array.CoreCLR.cs b/src/System.Private.CoreLib/src/System/Array.CoreCLR.cs index ee4a481..14f6847 100644 --- a/src/System.Private.CoreLib/src/System/Array.CoreCLR.cs +++ b/src/System.Private.CoreLib/src/System/Array.CoreCLR.cs @@ -293,7 +293,7 @@ namespace System { if (indices == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.indices); - if (Rank != indices!.Length) // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 + if (Rank != indices!.Length) // TODO-NULLABLE: Remove ! when [DoesNotReturn] respected ThrowHelper.ThrowArgumentException(ExceptionResource.Arg_RankIndices); TypedReference elemref = new TypedReference(); diff --git a/src/System.Private.CoreLib/src/System/Attribute.CoreCLR.cs b/src/System.Private.CoreLib/src/System/Attribute.CoreCLR.cs index 75b9c4b..e17f430 100644 --- a/src/System.Private.CoreLib/src/System/Attribute.CoreCLR.cs +++ b/src/System.Private.CoreLib/src/System/Attribute.CoreCLR.cs @@ -294,7 +294,7 @@ namespace System { if (objAttr[i] != null) { - attributes[count] = (Attribute)objAttr[i]!; // TODO-NULLABLE https://github.com/dotnet/roslyn/issues/34644 + attributes[count] = (Attribute)objAttr[i]!; // TODO-NULLABLE Indexer nullability tracked (https://github.com/dotnet/roslyn/issues/34644) count++; } } diff --git a/src/System.Private.CoreLib/src/System/Collections/Generic/EqualityComparer.CoreCLR.cs b/src/System.Private.CoreLib/src/System/Collections/Generic/EqualityComparer.CoreCLR.cs index ef0a6ef..40e6790 100644 --- a/src/System.Private.CoreLib/src/System/Collections/Generic/EqualityComparer.CoreCLR.cs +++ b/src/System.Private.CoreLib/src/System/Collections/Generic/EqualityComparer.CoreCLR.cs @@ -138,7 +138,7 @@ namespace System.Collections.Generic { for (int i = startIndex; i < endIndex; i++) { - if (array[i] != null && array[i]!.Equals(value)) return i; // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/34644 + if (array[i] != null && array[i]!.Equals(value)) return i; // TODO-NULLABLE: Indexer nullability tracked (https://github.com/dotnet/roslyn/issues/34644) } } return -1; @@ -158,7 +158,7 @@ namespace System.Collections.Generic { for (int i = startIndex; i >= endIndex; i--) { - if (array[i] != null && array[i]!.Equals(value)) return i; // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/34644 + if (array[i] != null && array[i]!.Equals(value)) return i; // TODO-NULLABLE: Indexer nullability tracked (https://github.com/dotnet/roslyn/issues/34644) } } return -1; diff --git a/src/System.Private.CoreLib/src/System/Collections/ObjectModel/ReadOnlyDictionary.cs b/src/System.Private.CoreLib/src/System/Collections/ObjectModel/ReadOnlyDictionary.cs index a88fc2d..2a455a4 100644 --- a/src/System.Private.CoreLib/src/System/Collections/ObjectModel/ReadOnlyDictionary.cs +++ b/src/System.Private.CoreLib/src/System/Collections/ObjectModel/ReadOnlyDictionary.cs @@ -13,6 +13,7 @@ using System.Collections.Generic; using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.Threading; namespace System.Collections.ObjectModel @@ -79,7 +80,7 @@ namespace System.Collections.ObjectModel } } - public bool TryGetValue(TKey key, out TValue value) + public bool TryGetValue(TKey key, [MaybeNullWhen(false)] out TValue value) { return m_dictionary.TryGetValue(key, out value); } @@ -272,7 +273,7 @@ namespace System.Collections.ObjectModel ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array); } - if (array!.Rank != 1) // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 + if (array!.Rank != 1) // TODO-NULLABLE: Remove ! when [DoesNotReturn] respected { ThrowHelper.ThrowArgumentException(ExceptionResource.Arg_RankMultiDimNotSupported); } @@ -317,7 +318,7 @@ namespace System.Collections.ObjectModel { foreach (var item in m_dictionary) { - objects![index++] = new KeyValuePair(item.Key, item.Value); // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 + objects![index++] = new KeyValuePair(item.Key, item.Value); // TODO-NULLABLE: Remove ! when [DoesNotReturn] respected } } catch (ArrayTypeMismatchException) @@ -348,7 +349,7 @@ namespace System.Collections.ObjectModel Interlocked.CompareExchange(ref m_syncRoot, new object(), null); } } - return m_syncRoot!; // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/34901 + return m_syncRoot!; // TODO-NULLABLE: Remove ! when compiler specially-recognizes CompareExchange for nullability } } @@ -429,7 +430,7 @@ namespace System.Collections.ObjectModel { ThrowHelper.ThrowArgumentNullException(ExceptionArgument.collection); } - m_collection = collection!; // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 + m_collection = collection!; // TODO-NULLABLE: Remove ! when [DoesNotReturn] respected } #region ICollection Members @@ -514,10 +515,10 @@ namespace System.Collections.ObjectModel } else { - Interlocked.CompareExchange(ref m_syncRoot, new object(), null); // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/34901 + Interlocked.CompareExchange(ref m_syncRoot, new object(), null); } } - return m_syncRoot!; + return m_syncRoot!; // TODO-NULLABLE: Remove ! when compiler specially-recognizes CompareExchange for nullability } } @@ -537,7 +538,7 @@ namespace System.Collections.ObjectModel { ThrowHelper.ThrowArgumentNullException(ExceptionArgument.collection); } - m_collection = collection!; // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 + m_collection = collection!; // TODO-NULLABLE: Remove ! when [DoesNotReturn] respected } #region ICollection Members @@ -625,7 +626,7 @@ namespace System.Collections.ObjectModel Interlocked.CompareExchange(ref m_syncRoot, new object(), null); } } - return m_syncRoot!; // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/34901 + return m_syncRoot!; // TODO-NULLABLE: Remove ! when compiler specially-recognizes CompareExchange for nullability } } @@ -646,7 +647,7 @@ namespace System.Collections.ObjectModel ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array); } - if (array!.Rank != 1) // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 + if (array!.Rank != 1) // TODO-NULLABLE: Remove ! when [DoesNotReturn] respected { ThrowHelper.ThrowArgumentException(ExceptionResource.Arg_RankMultiDimNotSupported); } @@ -706,7 +707,7 @@ namespace System.Collections.ObjectModel { foreach (var item in collection) { - objects![index++] = item; // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 + objects![index++] = item; // TODO-NULLABLE: Remove ! when [DoesNotReturn] respected } } catch (ArrayTypeMismatchException) diff --git a/src/System.Private.CoreLib/src/System/Diagnostics/Eventing/XplatEventLogger.cs b/src/System.Private.CoreLib/src/System/Diagnostics/Eventing/XplatEventLogger.cs index 366afa6..ec58d55 100644 --- a/src/System.Private.CoreLib/src/System/Diagnostics/Eventing/XplatEventLogger.cs +++ b/src/System.Private.CoreLib/src/System/Diagnostics/Eventing/XplatEventLogger.cs @@ -132,7 +132,7 @@ namespace System.Diagnostics.Tracing { if(payload[i] != null) { - sb.Append(payload[i]!.ToString()); // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/34644 + sb.Append(payload[i]!.ToString()); // TODO-NULLABLE: Indexer nullability tracked (https://github.com/dotnet/roslyn/issues/34644) } break; } diff --git a/src/System.Private.CoreLib/src/System/Environment.CoreCLR.cs b/src/System.Private.CoreLib/src/System/Environment.CoreCLR.cs index 36ddf53..6904765 100644 --- a/src/System.Private.CoreLib/src/System/Environment.CoreCLR.cs +++ b/src/System.Private.CoreLib/src/System/Environment.CoreCLR.cs @@ -4,6 +4,7 @@ using System.Buffers; using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Threading; @@ -32,6 +33,7 @@ namespace System // Note: The CLR's Watson bucketization code looks at the caller of the FCALL method // to assign blame for crashes. Don't mess with this, such as by making it call // another managed helper method, unless you consult with some CLR Watson experts. + [DoesNotReturn] [MethodImpl(MethodImplOptions.InternalCall)] public static extern void FailFast(string? message); @@ -48,9 +50,11 @@ namespace System // if the exception object is preallocated, the runtime will use the callsite's // IP for bucketing. If the exception object is not preallocated, it will use the bucket // details contained in the object (if any). + [DoesNotReturn] [MethodImpl(MethodImplOptions.InternalCall)] public static extern void FailFast(string? message, Exception? exception); + [DoesNotReturn] [MethodImpl(MethodImplOptions.InternalCall)] public static extern void FailFast(string? message, Exception? exception, string? errorMessage); diff --git a/src/System.Private.CoreLib/src/System/IO/FileLoadException.CoreCLR.cs b/src/System.Private.CoreLib/src/System/IO/FileLoadException.CoreCLR.cs index 762cfb2..7ec8014 100644 --- a/src/System.Private.CoreLib/src/System/IO/FileLoadException.CoreCLR.cs +++ b/src/System.Private.CoreLib/src/System/IO/FileLoadException.CoreCLR.cs @@ -30,7 +30,7 @@ namespace System.IO else GetMessageForHR(hResult, JitHelpers.GetStringHandleOnStack(ref message)); - return string.Format(format!, fileName, message!); // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 GetStringHandleOnStack needs to be attributed + return string.Format(format!, fileName, message!); // TODO-NULLABLE: Remove ! when nullable attributes are respected } [DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode)] diff --git a/src/System.Private.CoreLib/src/System/MulticastDelegate.cs b/src/System.Private.CoreLib/src/System/MulticastDelegate.cs index daae0fd..311c162 100644 --- a/src/System.Private.CoreLib/src/System/MulticastDelegate.cs +++ b/src/System.Private.CoreLib/src/System/MulticastDelegate.cs @@ -3,6 +3,7 @@ // See the LICENSE file in the project root for more information. using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; @@ -164,7 +165,7 @@ namespace System if (a[index] != null) { MulticastDelegate d = (MulticastDelegate)o; - MulticastDelegate dd = (MulticastDelegate)a[index]!; // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/34644 + MulticastDelegate dd = (MulticastDelegate)a[index]!; // TODO-NULLABLE: Indexer nullability tracked (https://github.com/dotnet/roslyn/issues/34644) if (dd._methodPtr == d._methodPtr && dd._target == d._target && @@ -566,6 +567,7 @@ namespace System } // this should help inlining + [DoesNotReturn] [System.Diagnostics.DebuggerNonUserCode] private void ThrowNullThisInDelegateToInstance() { @@ -577,7 +579,7 @@ namespace System { if (target == null) ThrowNullThisInDelegateToInstance(); - this._target = target!; // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 + this._target = target!; // TODO-NULLABLE: Remove ! when [DoesNotReturn] respected this._methodPtr = methodPtr; } diff --git a/src/System.Private.CoreLib/src/System/Reflection/Assembly.CoreCLR.cs b/src/System.Private.CoreLib/src/System/Reflection/Assembly.CoreCLR.cs index 8b0237c..eae84bf 100644 --- a/src/System.Private.CoreLib/src/System/Reflection/Assembly.CoreCLR.cs +++ b/src/System.Private.CoreLib/src/System/Reflection/Assembly.CoreCLR.cs @@ -80,7 +80,7 @@ namespace System.Reflection { RuntimeAssembly? retAssembly = null; GetExecutingAssemblyNative(JitHelpers.GetStackCrawlMarkHandle(ref stackMark), JitHelpers.GetObjectHandleOnStack(ref retAssembly)); - return retAssembly!; // TODO-NULLABLE: Confirm this can never be null + return retAssembly!; // TODO-NULLABLE: Remove ! when nullable attributes are respected } // Get the assembly that the current code is running from. diff --git a/src/System.Private.CoreLib/src/System/Reflection/Emit/DynamicILGenerator.cs b/src/System.Private.CoreLib/src/System/Reflection/Emit/DynamicILGenerator.cs index 777ad2a..9c4e5ca 100644 --- a/src/System.Private.CoreLib/src/System/Reflection/Emit/DynamicILGenerator.cs +++ b/src/System.Private.CoreLib/src/System/Reflection/Emit/DynamicILGenerator.cs @@ -1038,7 +1038,7 @@ namespace System.Reflection.Emit public int GetTokenFor(RuntimeMethodHandle method) { IRuntimeMethodInfo methodReal = method.GetMethodInfo(); - if (methodReal != null) // TODO-NULLABLE: never null + if (methodReal != null) { RuntimeMethodHandleInternal rmhi = methodReal.Value; if (!RuntimeMethodHandle.IsDynamicMethod(rmhi)) diff --git a/src/System.Private.CoreLib/src/System/Reflection/Emit/DynamicMethod.cs b/src/System.Private.CoreLib/src/System/Reflection/Emit/DynamicMethod.cs index 978f234..6a8c340 100644 --- a/src/System.Private.CoreLib/src/System/Reflection/Emit/DynamicMethod.cs +++ b/src/System.Private.CoreLib/src/System/Reflection/Emit/DynamicMethod.cs @@ -706,7 +706,7 @@ namespace System.Reflection.Emit get { return m_owner.IsSecurityTransparent; } } -#pragma warning disable CS8608 // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/23268 +#pragma warning disable CS8608 // TODO-NULLABLE: Covariant return types (https://github.com/dotnet/roslyn/issues/23268) public override Type ReturnType { get @@ -721,7 +721,7 @@ namespace System.Reflection.Emit get { return null; } } -#pragma warning disable CS8608 // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/23268 +#pragma warning disable CS8608 // TODO-NULLABLE: Covariant return types (https://github.com/dotnet/roslyn/issues/23268) public override ICustomAttributeProvider ReturnTypeCustomAttributes { get { return GetEmptyCAHolder(); } diff --git a/src/System.Private.CoreLib/src/System/Reflection/Emit/ILGenerator.cs b/src/System.Private.CoreLib/src/System/Reflection/Emit/ILGenerator.cs index 6138e55..a363f46 100644 --- a/src/System.Private.CoreLib/src/System/Reflection/Emit/ILGenerator.cs +++ b/src/System.Private.CoreLib/src/System/Reflection/Emit/ILGenerator.cs @@ -1564,7 +1564,7 @@ namespace System.Reflection.Emit { m_localSymInfos[i] = new LocalSymInfo(); } - m_localSymInfos[i]!.AddLocalSymInfo(strName, signature, slot, startOffset, endOffset); // TODO-NULLABLE https://github.com/dotnet/roslyn/issues/34644 + m_localSymInfos[i]!.AddLocalSymInfo(strName, signature, slot, startOffset, endOffset); // TODO-NULLABLE Indexer nullability tracked (https://github.com/dotnet/roslyn/issues/34644) } internal void AddUsingNamespaceToCurrentScope( @@ -1575,7 +1575,7 @@ namespace System.Reflection.Emit { m_localSymInfos[i] = new LocalSymInfo(); } - m_localSymInfos[i]!.AddUsingNamespace(strNamespace); // TODO-NULLABLE https://github.com/dotnet/roslyn/issues/34644 + m_localSymInfos[i]!.AddUsingNamespace(strNamespace); // TODO-NULLABLE Indexer nullability tracked (https://github.com/dotnet/roslyn/issues/34644) } internal void AddScopeInfo(ScopeAction sa, int iOffset) @@ -1642,7 +1642,7 @@ namespace System.Reflection.Emit } if (m_localSymInfos[i] != null) { - m_localSymInfos[i]!.EmitLocalSymInfo(symWriter); // TODO-NULLABLE https://github.com/dotnet/roslyn/issues/34644 + m_localSymInfos[i]!.EmitLocalSymInfo(symWriter); // TODO-NULLABLE Indexer nullability tracked (https://github.com/dotnet/roslyn/issues/34644) } } } diff --git a/src/System.Private.CoreLib/src/System/Reflection/Emit/ISymWrapperCore.cs b/src/System.Private.CoreLib/src/System/Reflection/Emit/ISymWrapperCore.cs index e8c58b7..faa404b 100644 --- a/src/System.Private.CoreLib/src/System/Reflection/Emit/ISymWrapperCore.cs +++ b/src/System.Private.CoreLib/src/System/Reflection/Emit/ISymWrapperCore.cs @@ -57,7 +57,7 @@ namespace System.Reflection.Emit m_pDocumentWriterSafeHandle = pDocumentWriterSafeHandle; // The handle is actually a pointer to a native ISymUnmanagedDocumentWriter. m_pDocWriter = (ISymUnmanagedDocumentWriter*)m_pDocumentWriterSafeHandle.DangerousGetHandle(); - m_vtable = (ISymUnmanagedDocumentWriterVTable)(Marshal.PtrToStructure(m_pDocWriter->m_unmanagedVTable, typeof(ISymUnmanagedDocumentWriterVTable)))!; // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/34976 + m_vtable = (ISymUnmanagedDocumentWriterVTable)(Marshal.PtrToStructure(m_pDocWriter->m_unmanagedVTable, typeof(ISymUnmanagedDocumentWriterVTable)))!; } //------------------------------------------------------------------------------ @@ -358,7 +358,7 @@ namespace System.Reflection.Emit internal void InternalSetUnderlyingWriter(IntPtr ppUnderlyingWriter) { m_pWriter = *((ISymUnmanagedWriter**)ppUnderlyingWriter); - m_vtable = (ISymUnmanagedWriterVTable)(Marshal.PtrToStructure(m_pWriter->m_unmanagedVTable, typeof(ISymUnmanagedWriterVTable)))!; // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/34976 + m_vtable = (ISymUnmanagedWriterVTable)(Marshal.PtrToStructure(m_pWriter->m_unmanagedVTable, typeof(ISymUnmanagedWriterVTable)))!; } //------------------------------------------------------------------------------ diff --git a/src/System.Private.CoreLib/src/System/Reflection/Emit/MethodBuilder.cs b/src/System.Private.CoreLib/src/System/Reflection/Emit/MethodBuilder.cs index abf38ab..63e570c 100644 --- a/src/System.Private.CoreLib/src/System/Reflection/Emit/MethodBuilder.cs +++ b/src/System.Private.CoreLib/src/System/Reflection/Emit/MethodBuilder.cs @@ -270,7 +270,7 @@ namespace System.Reflection.Emit // if it is in a debug module // SymbolToken tk = new SymbolToken(MetadataTokenInternal); - ISymbolWriter symWriter = dynMod.GetSymWriter()!; // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/2388 + ISymbolWriter symWriter = dynMod.GetSymWriter()!; // call OpenMethod to make this method the current method symWriter.OpenMethod(tk); diff --git a/src/System.Private.CoreLib/src/System/Reflection/Emit/SymbolType.cs b/src/System.Private.CoreLib/src/System/Reflection/Emit/SymbolType.cs index b3390c0..9f99bad 100644 --- a/src/System.Private.CoreLib/src/System/Reflection/Emit/SymbolType.cs +++ b/src/System.Private.CoreLib/src/System/Reflection/Emit/SymbolType.cs @@ -391,7 +391,7 @@ namespace System.Reflection.Emit get { return m_baseType.Namespace; } } -#pragma warning disable CS8608 // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/23268 +#pragma warning disable CS8608 // TODO-NULLABLE: Covariant return types (https://github.com/dotnet/roslyn/issues/23268) public override Type BaseType { get { return typeof(System.Array); } diff --git a/src/System.Private.CoreLib/src/System/Reflection/RuntimeAssembly.cs b/src/System.Private.CoreLib/src/System/Reflection/RuntimeAssembly.cs index a9f8065..d5eda80 100644 --- a/src/System.Private.CoreLib/src/System/Reflection/RuntimeAssembly.cs +++ b/src/System.Private.CoreLib/src/System/Reflection/RuntimeAssembly.cs @@ -50,7 +50,7 @@ namespace System.Reflection { Interlocked.CompareExchange(ref m_syncRoot, new object(), null); } - return m_syncRoot!; // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 + return m_syncRoot!; // TODO-NULLABLE: Remove ! when compiler specially-recognizes CompareExchange for nullability } } @@ -728,7 +728,7 @@ namespace System.Reflection exception = e; } - Debug.Assert((type != null) != (exception != null)); // Exactly one of these must be non-null. // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/2388 + Debug.Assert((type != null) != (exception != null)); // Exactly one of these must be non-null. if (type != null) { diff --git a/src/System.Private.CoreLib/src/System/Reflection/RuntimeConstructorInfo.cs b/src/System.Private.CoreLib/src/System/Reflection/RuntimeConstructorInfo.cs index 768e4a7..5d8be5d 100644 --- a/src/System.Private.CoreLib/src/System/Reflection/RuntimeConstructorInfo.cs +++ b/src/System.Private.CoreLib/src/System/Reflection/RuntimeConstructorInfo.cs @@ -4,6 +4,7 @@ using System.Collections.Generic; using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.Text; using RuntimeTypeCache = System.RuntimeType.RuntimeTypeCache; @@ -328,6 +329,7 @@ namespace System.Reflection throw new MemberAccessException(SR.Access_Void); } + [DoesNotReturn] internal void ThrowNoInvokeException() { CheckCanCreateInstance(DeclaringType!, (CallingConvention & CallingConventions.VarArgs) == CallingConventions.VarArgs); diff --git a/src/System.Private.CoreLib/src/System/Reflection/RuntimeMethodInfo.cs b/src/System.Private.CoreLib/src/System/Reflection/RuntimeMethodInfo.cs index 7ba7576..f60779f 100644 --- a/src/System.Private.CoreLib/src/System/Reflection/RuntimeMethodInfo.cs +++ b/src/System.Private.CoreLib/src/System/Reflection/RuntimeMethodInfo.cs @@ -4,6 +4,7 @@ using System.Collections.Generic; using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.Security; using System.Text; @@ -418,6 +419,7 @@ namespace System.Reflection } } + [DoesNotReturn] private void ThrowNoInvokeException() { // method is on a class that contains stack pointers @@ -507,7 +509,7 @@ namespace System.Reflection #region MethodInfo Overrides -#pragma warning disable CS8608 // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/23268 +#pragma warning disable CS8608 // TODO-NULLABLE: Covariant return types (https://github.com/dotnet/roslyn/issues/23268) public override Type ReturnType { get { return Signature.ReturnType; } diff --git a/src/System.Private.CoreLib/src/System/RtType.cs b/src/System.Private.CoreLib/src/System/RtType.cs index 0bad3f6..c22229a 100644 --- a/src/System.Private.CoreLib/src/System/RtType.cs +++ b/src/System.Private.CoreLib/src/System/RtType.cs @@ -14,6 +14,7 @@ using System.Threading; using DebuggerStepThroughAttribute = System.Diagnostics.DebuggerStepThroughAttribute; using MdToken = System.Reflection.MetadataToken; using Internal.Runtime.CompilerServices; +using System.Diagnostics.CodeAnalysis; namespace System { @@ -135,7 +136,7 @@ namespace System _capacity = newCapacity; } - _items![_count] = item; // TODO-NULLABLE: https://github.com/dotnet/coreclr/pull/23708 + _items![_count] = item; // TODO-NULLABLE: Remove ! when nullable attributes are respected } _count++; } @@ -1434,7 +1435,7 @@ namespace System #endregion #region Private Members - private string ConstructName(ref string? name, TypeNameFormatFlags formatFlags) // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 + private string ConstructName([NotNull] ref string? name, TypeNameFormatFlags formatFlags) { if (name == null) { @@ -4195,7 +4196,7 @@ namespace System MethodBase? invokeMethod = null; - try { invokeMethod = binder.BindToMethod(bindingFlags, finalists, ref providedArgs!, modifiers, culture, namedParams, out state); } //TODO-NULLABLE https://github.com/dotnet/csharplang/issues/2388 + try { invokeMethod = binder.BindToMethod(bindingFlags, finalists, ref providedArgs!, modifiers, culture, namedParams, out state); } catch (MissingMethodException) { } if (invokeMethod == null) @@ -4204,7 +4205,7 @@ namespace System object? result = ((MethodInfo)invokeMethod).Invoke(target, bindingFlags, binder, providedArgs, culture); if (state != null) - binder.ReorderArgumentArray(ref providedArgs!, state); + binder.ReorderArgumentArray(ref providedArgs!, state); // TODO-NULLABLE: Pass non-null string? to string ref (https://github.com/dotnet/roslyn/issues/34874) return result; } @@ -4384,7 +4385,7 @@ namespace System { if (args[i] != null) { - argsType[i] = args[i]!.GetType(); // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/34644 + argsType[i] = args[i]!.GetType(); // TODO-NULLABLE: Indexer nullability tracked (https://github.com/dotnet/roslyn/issues/34644) } } @@ -4406,7 +4407,7 @@ namespace System try { - invokeMethod = binder.BindToMethod(bindingAttr, cons, ref args!, null, culture, null, out state); //TODO-NULLABLE https://github.com/dotnet/csharplang/issues/2388 + invokeMethod = binder.BindToMethod(bindingAttr, cons, ref args!, null, culture, null, out state); //TODO-NULLABLE: Pass non-null string? to string ref (https://github.com/dotnet/roslyn/issues/34874) } catch (MissingMethodException) { invokeMethod = null; } diff --git a/src/System.Private.CoreLib/src/System/Runtime/CompilerServices/ICastableHelpers.cs b/src/System.Private.CoreLib/src/System/Runtime/CompilerServices/ICastableHelpers.cs index 4b1b543..d996d44 100644 --- a/src/System.Private.CoreLib/src/System/Runtime/CompilerServices/ICastableHelpers.cs +++ b/src/System.Private.CoreLib/src/System/Runtime/CompilerServices/ICastableHelpers.cs @@ -2,9 +2,11 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +using System.Diagnostics.CodeAnalysis; + namespace System.Runtime.CompilerServices { - + /// /// Helpers that allows VM to call into ICastable methods without having to deal with RuntimeTypeHandle. /// RuntimeTypeHandle is a struct and is always passed in stack in x86, which our VM call helpers don't @@ -12,7 +14,7 @@ namespace System.Runtime.CompilerServices /// internal class ICastableHelpers { - internal static bool IsInstanceOfInterface(ICastable castable, RuntimeType type, out Exception? castError) // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 + internal static bool IsInstanceOfInterface(ICastable castable, RuntimeType type, [NotNullWhen(true)] out Exception? castError) { return castable.IsInstanceOfInterface(new RuntimeTypeHandle(type), out castError); } diff --git a/src/System.Private.CoreLib/src/System/Runtime/CompilerServices/jithelpers.cs b/src/System.Private.CoreLib/src/System/Runtime/CompilerServices/jithelpers.cs index bf792c3..81fae84 100644 --- a/src/System.Private.CoreLib/src/System/Runtime/CompilerServices/jithelpers.cs +++ b/src/System.Private.CoreLib/src/System/Runtime/CompilerServices/jithelpers.cs @@ -10,6 +10,7 @@ using System.Threading; using System.Diagnostics; using Internal.Runtime.CompilerServices; +using System.Diagnostics.CodeAnalysis; namespace System.Runtime.CompilerServices { @@ -107,14 +108,14 @@ namespace System.Runtime.CompilerServices // Wraps object variable into a handle. Used to return managed strings from QCalls. // s has to be a local variable on the stack. - internal static StringHandleOnStack GetStringHandleOnStack(ref string? s) + internal static StringHandleOnStack GetStringHandleOnStack([NotNull] ref string? s) { return new StringHandleOnStack((IntPtr)Unsafe.AsPointer(ref s)); } // Wraps object variable into a handle. Used to pass managed object references in and out of QCalls. // o has to be a local variable on the stack. - internal static ObjectHandleOnStack GetObjectHandleOnStack(ref T o) where T : class? + internal static ObjectHandleOnStack GetObjectHandleOnStack([NotNull] ref T o) where T : class? { return new ObjectHandleOnStack((IntPtr)Unsafe.AsPointer(ref o)); } diff --git a/src/System.Private.CoreLib/src/System/Runtime/InteropServices/ComEventsMethod.cs b/src/System.Private.CoreLib/src/System/Runtime/InteropServices/ComEventsMethod.cs index 20a4cc5..b8a6dd8 100644 --- a/src/System.Private.CoreLib/src/System/Runtime/InteropServices/ComEventsMethod.cs +++ b/src/System.Private.CoreLib/src/System/Runtime/InteropServices/ComEventsMethod.cs @@ -55,7 +55,7 @@ namespace System.Runtime.InteropServices { if (_cachedTargetTypes[i] != null) { - args[i] = Enum.ToObject(_cachedTargetTypes[i]!, args[i]); // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/34644 + args[i] = Enum.ToObject(_cachedTargetTypes[i]!, args[i]); // TODO-NULLABLE: Indexer nullability tracked (https://github.com/dotnet/roslyn/issues/34644) } } } @@ -173,7 +173,7 @@ namespace System.Runtime.InteropServices { if (wrapper.Delegate.GetType() == d.GetType()) { - wrapper.Delegate = Delegate.Combine(wrapper.Delegate, d)!; // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 + wrapper.Delegate = Delegate.Combine(wrapper.Delegate, d)!; // TODO-NULLABLE: Remove ! when nullable attributes are respected return; } } diff --git a/src/System.Private.CoreLib/src/System/Runtime/InteropServices/CustomMarshalers/EnumeratorViewOfEnumVariant.cs b/src/System.Private.CoreLib/src/System/Runtime/InteropServices/CustomMarshalers/EnumeratorViewOfEnumVariant.cs index 21116e4..6b1c418 100644 --- a/src/System.Private.CoreLib/src/System/Runtime/InteropServices/CustomMarshalers/EnumeratorViewOfEnumVariant.cs +++ b/src/System.Private.CoreLib/src/System/Runtime/InteropServices/CustomMarshalers/EnumeratorViewOfEnumVariant.cs @@ -21,7 +21,7 @@ namespace System.Runtime.InteropServices.CustomMarshalers _current = null; } - public object? Current => _current; // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/23268 + public object? Current => _current; public unsafe bool MoveNext() { diff --git a/src/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshal.CoreCLR.cs b/src/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshal.CoreCLR.cs index cecf880..6df19ae 100644 --- a/src/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshal.CoreCLR.cs +++ b/src/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshal.CoreCLR.cs @@ -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. +using System.Diagnostics.CodeAnalysis; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.ConstrainedExecution; @@ -349,8 +350,7 @@ namespace System.Runtime.InteropServices return GetComInterfaceForObjectNative(o, T, false, true); } - // TODO-NULLABLE-GENERIC: T cannot be null - public static IntPtr GetComInterfaceForObject(T o) => GetComInterfaceForObject(o!, typeof(TInterface)); + public static IntPtr GetComInterfaceForObject([DisallowNull] T o) => GetComInterfaceForObject(o!, typeof(TInterface)); /// /// Return the IUnknown* representing the interface for the Object. @@ -388,10 +388,9 @@ namespace System.Runtime.InteropServices [MethodImpl(MethodImplOptions.InternalCall)] public static extern IntPtr CreateAggregatedObject(IntPtr pOuter, object o); - public static IntPtr CreateAggregatedObject(IntPtr pOuter, T o) + public static IntPtr CreateAggregatedObject(IntPtr pOuter, T o) where T : object { - // TODO-NULLABLE-GENERIC: T cannot be null - return CreateAggregatedObject(pOuter, (object)o!); + return CreateAggregatedObject(pOuter, (object)o); } [MethodImpl(MethodImplOptions.InternalCall)] @@ -641,9 +640,8 @@ namespace System.Runtime.InteropServices return Wrapper; } - public static TWrapper CreateWrapperOfType(T o) + public static TWrapper CreateWrapperOfType([AllowNull] T o) { - // TODO-NULLABLE-GENERIC: T can be null return (TWrapper)CreateWrapperOfType(o, typeof(TWrapper))!; } @@ -668,25 +666,23 @@ namespace System.Runtime.InteropServices [MethodImpl(MethodImplOptions.InternalCall)] public static extern void GetNativeVariantForObject(object? obj, /* VARIANT * */ IntPtr pDstNativeVariant); - public static void GetNativeVariantForObject(T obj, IntPtr pDstNativeVariant) + public static void GetNativeVariantForObject([AllowNull] T obj, IntPtr pDstNativeVariant) { - // TODO-NULLABLE-GENERIC: T can be null - GetNativeVariantForObject((object)obj!, pDstNativeVariant); + GetNativeVariantForObject((object?)obj, pDstNativeVariant); } [MethodImpl(MethodImplOptions.InternalCall)] public static extern object? GetObjectForNativeVariant(/* VARIANT * */ IntPtr pSrcNativeVariant); + [return: MaybeNull] public static T GetObjectForNativeVariant(IntPtr pSrcNativeVariant) { - // TODO-NULLABLE-GENERIC: T can be null return (T)GetObjectForNativeVariant(pSrcNativeVariant)!; } [MethodImpl(MethodImplOptions.InternalCall)] public static extern object?[] GetObjectsForNativeVariants(/* VARIANT * */ IntPtr aSrcNativeVariant, int cVars); - // TODO-NULLABLE-GENERIC: T[] contents can be null public static T[] GetObjectsForNativeVariants(IntPtr aSrcNativeVariant, int cVars) { object?[] objects = GetObjectsForNativeVariants(aSrcNativeVariant, cVars); diff --git a/src/System.Private.CoreLib/src/System/Runtime/InteropServices/WindowsRuntime/CLRIReferenceImpl.cs b/src/System.Private.CoreLib/src/System/Runtime/InteropServices/WindowsRuntime/CLRIReferenceImpl.cs index dc4028a..8ee1ff7 100644 --- a/src/System.Private.CoreLib/src/System/Runtime/InteropServices/WindowsRuntime/CLRIReferenceImpl.cs +++ b/src/System.Private.CoreLib/src/System/Runtime/InteropServices/WindowsRuntime/CLRIReferenceImpl.cs @@ -37,7 +37,7 @@ namespace System.Runtime.InteropServices.WindowsRuntime object IGetProxyTarget.GetTarget() { - return _value!; // TODO-NULLABLE-GENERIC + return _value!; } // We have T in an IReference. Need to QI for IReference with the appropriate GUID, call @@ -50,7 +50,7 @@ namespace System.Runtime.InteropServices.WindowsRuntime Debug.Assert(wrapper != null); IReference reference = (IReference)wrapper; Debug.Assert(reference != null, "CLRIReferenceImpl::UnboxHelper - QI'ed for IReference<" + typeof(T) + ">, but that failed."); - return reference.Value!; // TODO-NULLABLE-GENERIC + return reference.Value!; } } diff --git a/src/System.Private.CoreLib/src/System/Runtime/InteropServices/WindowsRuntime/ConstantSplittableMap.cs b/src/System.Private.CoreLib/src/System/Runtime/InteropServices/WindowsRuntime/ConstantSplittableMap.cs index 5c4aaf7..9f5f99b 100644 --- a/src/System.Private.CoreLib/src/System/Runtime/InteropServices/WindowsRuntime/ConstantSplittableMap.cs +++ b/src/System.Private.CoreLib/src/System/Runtime/InteropServices/WindowsRuntime/ConstantSplittableMap.cs @@ -5,6 +5,7 @@ using System.Diagnostics; using System.Collections; using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; namespace System.Runtime.InteropServices.WindowsRuntime { @@ -145,14 +146,14 @@ namespace System.Runtime.InteropServices.WindowsRuntime #region IReadOnlyDictionary members - public bool TryGetValue(TKey key, out TValue value) + public bool TryGetValue(TKey key, [MaybeNullWhen(false)] out TValue value) { - KeyValuePair searchKey = new KeyValuePair(key, default!); // TODO-NULLABLE-GENERIC + KeyValuePair searchKey = new KeyValuePair(key, default!); int index = Array.BinarySearch(items, firstItemIndex, Count, searchKey, keyValuePairComparator); if (index < 0) { - value = default!; // TODO-NULLABLE-GENERIC + value = default!; return false; } @@ -205,7 +206,7 @@ namespace System.Runtime.InteropServices.WindowsRuntime } } - object? IEnumerator.Current // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/23268 + object? IEnumerator.Current { get { diff --git a/src/System.Private.CoreLib/src/System/Runtime/InteropServices/WindowsRuntime/EventRegistrationTokenTable.cs b/src/System.Private.CoreLib/src/System/Runtime/InteropServices/WindowsRuntime/EventRegistrationTokenTable.cs index 7fe627d..f9eb669 100644 --- a/src/System.Private.CoreLib/src/System/Runtime/InteropServices/WindowsRuntime/EventRegistrationTokenTable.cs +++ b/src/System.Private.CoreLib/src/System/Runtime/InteropServices/WindowsRuntime/EventRegistrationTokenTable.cs @@ -4,6 +4,7 @@ using System.Collections.Generic; using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.Threading; namespace System.Runtime.InteropServices.WindowsRuntime @@ -17,7 +18,7 @@ namespace System.Runtime.InteropServices.WindowsRuntime // Cached multicast delegate which will invoke all of the currently registered delegates. This // will be accessed frequently in common coding paterns, so we don't want to calculate it repeatedly. - private volatile T m_invokeList = null!; // TODO-NULLABLE-GENERIC + [AllowNull, MaybeNull] private volatile T m_invokeList = null!; // TODO-NULLABLE: Remove ! when nullable attributes are respected public EventRegistrationTokenTable() { @@ -31,20 +32,20 @@ namespace System.Runtime.InteropServices.WindowsRuntime // The InvocationList property provides access to a delegate which will invoke every registered event handler // in this table. If the property is set, the new value will replace any existing token registrations. + [MaybeNull] public T InvocationList { get { return m_invokeList; } - set { lock (m_tokens) { // The value being set replaces any of the existing values m_tokens.Clear(); - m_invokeList = null!; // TODO-NULLABLE-GENERIC + m_invokeList = null!; // TODO-NULLABLE: Remove ! when nullable attributes are respected if (value != null) { @@ -84,7 +85,7 @@ namespace System.Runtime.InteropServices.WindowsRuntime // Update the current invocation list to include the newly added delegate Delegate? invokeList = (Delegate?)(object?)m_invokeList; invokeList = MulticastDelegate.Combine(invokeList, (Delegate)(object)handler); - m_invokeList = (T)(object?)invokeList!; // TODO-NULLABLE-GENERIC + m_invokeList = (T)(object?)invokeList!; return token; } @@ -235,7 +236,7 @@ namespace System.Runtime.InteropServices.WindowsRuntime // Update the current invocation list to remove the delegate Delegate? invokeList = (Delegate?)(object?)m_invokeList; invokeList = MulticastDelegate.Remove(invokeList, (Delegate?)(object?)handler); - m_invokeList = (T)(object?)invokeList!; // TODO-NULLABLE-GENERIC + m_invokeList = (T)(object?)invokeList!; } } @@ -245,7 +246,7 @@ namespace System.Runtime.InteropServices.WindowsRuntime { Interlocked.CompareExchange(ref refEventTable, new EventRegistrationTokenTable(), null); } - return refEventTable!; // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 + return refEventTable!; // TODO-NULLABLE: Remove ! when compiler specially-recognizes CompareExchange for nullability } } } diff --git a/src/System.Private.CoreLib/src/System/Runtime/InteropServices/WindowsRuntime/IMapViewToIReadOnlyDictionaryAdapter.cs b/src/System.Private.CoreLib/src/System/Runtime/InteropServices/WindowsRuntime/IMapViewToIReadOnlyDictionaryAdapter.cs index 16ef392..7a8b11b 100644 --- a/src/System.Private.CoreLib/src/System/Runtime/InteropServices/WindowsRuntime/IMapViewToIReadOnlyDictionaryAdapter.cs +++ b/src/System.Private.CoreLib/src/System/Runtime/InteropServices/WindowsRuntime/IMapViewToIReadOnlyDictionaryAdapter.cs @@ -5,6 +5,7 @@ using System.Collections; using System.Collections.Generic; using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using Internal.Runtime.CompilerServices; namespace System.Runtime.InteropServices.WindowsRuntime @@ -62,7 +63,7 @@ namespace System.Runtime.InteropServices.WindowsRuntime } // bool TryGetValue(TKey key, out TValue value) - internal bool TryGetValue(K key, out V value) where K : object + internal bool TryGetValue(K key, [MaybeNullWhen(false)] out V value) where K : object { if (key == null) throw new ArgumentNullException(nameof(key)); @@ -73,7 +74,7 @@ namespace System.Runtime.InteropServices.WindowsRuntime // throw an exception from Lookup. if (!_this.HasKey(key)) { - value = default!; // TODO-NULLABLE-GENERIC + value = default!; return false; } @@ -86,7 +87,7 @@ namespace System.Runtime.InteropServices.WindowsRuntime { if (HResults.E_BOUNDS == ex.HResult) { - value = default!; // TODO-NULLABLE-GENERIC + value = default!; return false; } throw; diff --git a/src/System.Private.CoreLib/src/System/Runtime/InteropServices/WindowsRuntime/IteratorToEnumeratorAdapter.cs b/src/System.Private.CoreLib/src/System/Runtime/InteropServices/WindowsRuntime/IteratorToEnumeratorAdapter.cs index 756026b..9c9245e 100644 --- a/src/System.Private.CoreLib/src/System/Runtime/InteropServices/WindowsRuntime/IteratorToEnumeratorAdapter.cs +++ b/src/System.Private.CoreLib/src/System/Runtime/InteropServices/WindowsRuntime/IteratorToEnumeratorAdapter.cs @@ -98,7 +98,7 @@ namespace System.Runtime.InteropServices.WindowsRuntime { private IIterator m_iterator; private bool m_hadCurrent; - private T m_current = default!; // TODO-NULLABLE-GENERIC + private T m_current = default!; private bool m_isInitialized; internal IteratorToEnumeratorAdapter(IIterator iterator) diff --git a/src/System.Private.CoreLib/src/System/Runtime/InteropServices/WindowsRuntime/MapToDictionaryAdapter.cs b/src/System.Private.CoreLib/src/System/Runtime/InteropServices/WindowsRuntime/MapToDictionaryAdapter.cs index a5e5673..e0ad2d7 100644 --- a/src/System.Private.CoreLib/src/System/Runtime/InteropServices/WindowsRuntime/MapToDictionaryAdapter.cs +++ b/src/System.Private.CoreLib/src/System/Runtime/InteropServices/WindowsRuntime/MapToDictionaryAdapter.cs @@ -4,6 +4,7 @@ using System.Collections.Generic; using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using Internal.Runtime.CompilerServices; namespace System.Runtime.InteropServices.WindowsRuntime @@ -110,7 +111,7 @@ namespace System.Runtime.InteropServices.WindowsRuntime } // bool TryGetValue(TKey key, out TValue value) - internal bool TryGetValue(K key, out V value) where K : object + internal bool TryGetValue(K key, [MaybeNullWhen(false)] out V value) where K : object { if (key == null) throw new ArgumentNullException(nameof(key)); @@ -118,7 +119,7 @@ namespace System.Runtime.InteropServices.WindowsRuntime IMap _this = Unsafe.As>(this); if (!_this.HasKey(key)) { - value = default!; // TODO-NULLABLE-GENERIC + value = default!; return false; } @@ -129,7 +130,7 @@ namespace System.Runtime.InteropServices.WindowsRuntime } catch (KeyNotFoundException) { - value = default!; // TODO-NULLABLE-GENERIC + value = default!; return false; } } diff --git a/src/System.Private.CoreLib/src/System/Runtime/InteropServices/WindowsRuntime/WindowsRuntimeMarshal.cs b/src/System.Private.CoreLib/src/System/Runtime/InteropServices/WindowsRuntime/WindowsRuntimeMarshal.cs index d879f89..7f5fef2 100644 --- a/src/System.Private.CoreLib/src/System/Runtime/InteropServices/WindowsRuntime/WindowsRuntimeMarshal.cs +++ b/src/System.Private.CoreLib/src/System/Runtime/InteropServices/WindowsRuntime/WindowsRuntimeMarshal.cs @@ -531,7 +531,7 @@ namespace System.Runtime.InteropServices.WindowsRuntime return (object)Marshal.GetRawIUnknownForComObjectNoAddRef(target); } - private static object? FindEquivalentKeyUnsafe(ConditionalWeakTable registrationTable, object handler, out EventRegistrationTokenListWithCount? tokens) // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 + private static object? FindEquivalentKeyUnsafe(ConditionalWeakTable registrationTable, object handler, out EventRegistrationTokenListWithCount? tokens) { foreach (KeyValuePair item in registrationTable) { @@ -599,7 +599,7 @@ namespace System.Runtime.InteropServices.WindowsRuntime } else { - tokens!.Push(token); // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 + tokens!.Push(token); } tokenAdded = true; @@ -742,7 +742,7 @@ namespace System.Runtime.InteropServices.WindowsRuntime // NOTE: We should not check whether registrationTokens has 0 entries and remove it from the cache // (just like managed event implementation), because this might have raced with the finalizer of // EventRegistrationTokenList - registrationTokens.Remove(key!); // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/2388 + registrationTokens.Remove(key!); } Log("[WinRT_Eventing] Event unsubscribed for managed instance = " + instanceKey + ", handler = " + handler + ", token = " + token.Value + "\n"); diff --git a/src/System.Private.CoreLib/src/System/Runtime/Loader/AssemblyDependencyResolver.cs b/src/System.Private.CoreLib/src/System/Runtime/Loader/AssemblyDependencyResolver.cs index 6fdb5da..ad9f585 100644 --- a/src/System.Private.CoreLib/src/System/Runtime/Loader/AssemblyDependencyResolver.cs +++ b/src/System.Private.CoreLib/src/System/Runtime/Loader/AssemblyDependencyResolver.cs @@ -99,13 +99,13 @@ namespace System.Runtime.Loader _assemblyPaths = new Dictionary(StringComparer.OrdinalIgnoreCase); foreach (string assemblyPath in assemblyPaths) { - _assemblyPaths.Add(Path.GetFileNameWithoutExtension(assemblyPath)!, assemblyPath); // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 + _assemblyPaths.Add(Path.GetFileNameWithoutExtension(assemblyPath)!, assemblyPath); // TODO-NULLABLE: Remove ! when nullable attributes are respected } _nativeSearchPaths = SplitPathsList(nativeSearchPathsList); _resourceSearchPaths = SplitPathsList(resourceSearchPathsList); - _assemblyDirectorySearchPaths = new string[1] { Path.GetDirectoryName(componentAssemblyPath)! }; // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 + _assemblyDirectorySearchPaths = new string[1] { Path.GetDirectoryName(componentAssemblyPath)! }; } public string? ResolveAssemblyToPath(AssemblyName assemblyName) diff --git a/src/System.Private.CoreLib/src/System/StubHelpers.cs b/src/System.Private.CoreLib/src/System/StubHelpers.cs index 94d7ba9..0f9ee4e 100644 --- a/src/System.Private.CoreLib/src/System/StubHelpers.cs +++ b/src/System.Private.CoreLib/src/System/StubHelpers.cs @@ -1622,7 +1622,7 @@ namespace System.StubHelpers ThrowHelper.ThrowArgumentNullException(ExceptionArgument.pHandle, ExceptionResource.ArgumentNull_SafeHandle); } - pHandle!.DangerousAddRef(ref success); // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 + pHandle!.DangerousAddRef(ref success); // TODO-NULLABLE: Remove ! when [DoesNotReturn] respected return pHandle.DangerousGetHandle(); } @@ -1636,7 +1636,7 @@ namespace System.StubHelpers try { - pHandle!.DangerousRelease(); // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 + pHandle!.DangerousRelease(); // TODO-NULLABLE: Remove ! when [DoesNotReturn] respected } catch { diff --git a/src/System.Private.CoreLib/src/System/Threading/Interlocked.cs b/src/System.Private.CoreLib/src/System/Threading/Interlocked.cs index ed6829e..f23942e 100644 --- a/src/System.Private.CoreLib/src/System/Threading/Interlocked.cs +++ b/src/System.Private.CoreLib/src/System/Threading/Interlocked.cs @@ -5,6 +5,7 @@ using System.Runtime.CompilerServices; using Internal.Runtime.CompilerServices; using System.Runtime.InteropServices; +using System.Diagnostics.CodeAnalysis; namespace System.Threading { @@ -59,7 +60,8 @@ 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); + [return: NotNullIfNotNull("value")] + public static extern object? Exchange([NotNullIfNotNull("value")] ref object? location1, object? value); [MethodImplAttribute(MethodImplOptions.InternalCall)] public static extern IntPtr Exchange(ref IntPtr location1, IntPtr value); @@ -67,7 +69,8 @@ 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(ref T location1, T value) where T : class? + [return: NotNullIfNotNull("value")] + public static T Exchange([NotNullIfNotNull("value")] ref T location1, T value) where T : class? { return Unsafe.As(Exchange(ref Unsafe.As(ref location1), value)); } diff --git a/src/System.Private.CoreLib/src/System/Threading/Monitor.cs b/src/System.Private.CoreLib/src/System/Threading/Monitor.cs index 4385bf9..1783d4d 100644 --- a/src/System.Private.CoreLib/src/System/Threading/Monitor.cs +++ b/src/System.Private.CoreLib/src/System/Threading/Monitor.cs @@ -21,6 +21,7 @@ using System.Runtime.ConstrainedExecution; using System.Runtime.Versioning; using System.Diagnostics; using System.Runtime.InteropServices; +using System.Diagnostics.CodeAnalysis; namespace System.Threading { @@ -52,6 +53,7 @@ namespace System.Threading Debug.Assert(lockTaken); } + [DoesNotReturn] private static void ThrowLockTakenException() { throw new ArgumentException(SR.Argument_MustBeFalse, "lockTaken"); diff --git a/src/System.Private.CoreLib/src/System/Threading/ThreadPool.CoreCLR.cs b/src/System.Private.CoreLib/src/System/Threading/ThreadPool.CoreCLR.cs index 53d47b9..ec82665 100644 --- a/src/System.Private.CoreLib/src/System/Threading/ThreadPool.CoreCLR.cs +++ b/src/System.Private.CoreLib/src/System/Threading/ThreadPool.CoreCLR.cs @@ -52,7 +52,7 @@ namespace System.Threading m_internalWaitObject = waitObject; if (waitObject != null) { - m_internalWaitObject.SafeWaitHandle!.DangerousAddRef(ref bReleaseNeeded); // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/2384 + m_internalWaitObject.SafeWaitHandle.DangerousAddRef(ref bReleaseNeeded); } } @@ -82,7 +82,7 @@ namespace System.Threading if (bReleaseNeeded) { Debug.Assert(m_internalWaitObject != null, "Must be non-null for bReleaseNeeded to be true"); - m_internalWaitObject.SafeWaitHandle!.DangerousRelease(); // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/2384 + m_internalWaitObject.SafeWaitHandle.DangerousRelease(); bReleaseNeeded = false; } // if result not true don't release/suppress here so finalizer can make another attempt @@ -144,7 +144,7 @@ namespace System.Threading if (bReleaseNeeded) { Debug.Assert(m_internalWaitObject != null, "Must be non-null for bReleaseNeeded to be true"); - m_internalWaitObject.SafeWaitHandle!.DangerousRelease(); // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/2384 + m_internalWaitObject.SafeWaitHandle.DangerousRelease(); bReleaseNeeded = false; } SetHandle(InvalidHandle); diff --git a/src/System.Private.CoreLib/src/System/Utf8String.Construction.cs b/src/System.Private.CoreLib/src/System/Utf8String.Construction.cs index 4705216..c448b5b 100644 --- a/src/System.Private.CoreLib/src/System/Utf8String.Construction.cs +++ b/src/System.Private.CoreLib/src/System/Utf8String.Construction.cs @@ -49,7 +49,7 @@ namespace System Utf8String newString = FastAllocate(value.Length); Buffer.Memmove(ref newString.DangerousGetMutableReference(), ref MemoryMarshal.GetReference(value), (uint)value.Length); - return Utf8Utility.ValidateAndFixupUtf8String(newString)!; // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 + return Utf8Utility.ValidateAndFixupUtf8String(newString)!; // TODO-NULLABLE: Remove ! when nullable attributes are respected } /// diff --git a/src/System.Private.CoreLib/src/System/Utf8String.cs b/src/System.Private.CoreLib/src/System/Utf8String.cs index 7a1a17c..83a4b39 100644 --- a/src/System.Private.CoreLib/src/System/Utf8String.cs +++ b/src/System.Private.CoreLib/src/System/Utf8String.cs @@ -4,6 +4,7 @@ using System.ComponentModel; using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.Runtime.CompilerServices; using System.Text; using Internal.Runtime.CompilerServices; @@ -13,7 +14,7 @@ namespace System /// /// Represents an immutable string of UTF-8 code units. /// - public sealed partial class Utf8String : IEquatable + public sealed partial class Utf8String : IEquatable { /* * STATIC FIELDS @@ -118,7 +119,9 @@ namespace System /// /// Performs an equality comparison using a comparer. /// +#pragma warning disable CS8614 // TODO-NULLABLE: Covariant interface arguments (https://github.com/dotnet/roslyn/issues/35817) public bool Equals(Utf8String? value) +#pragma warning restore CS8614 { // First, a very quick check for referential equality. @@ -179,7 +182,7 @@ namespace System /// Returns if is or zero length; /// otherwise. /// - public static bool IsNullOrEmpty(Utf8String? value) + public static bool IsNullOrEmpty([NotNullWhen(false)] Utf8String? value) { // Copied from String.IsNullOrEmpty. See that method for detailed comments on why this pattern is used. return (value is null || 0u >= (uint)value.Length) ? true : false; diff --git a/src/System.Private.CoreLib/src/System/WeakReferenceOfT.cs b/src/System.Private.CoreLib/src/System/WeakReferenceOfT.cs index 7b89b05..1413a35 100644 --- a/src/System.Private.CoreLib/src/System/WeakReferenceOfT.cs +++ b/src/System.Private.CoreLib/src/System/WeakReferenceOfT.cs @@ -15,6 +15,7 @@ using System.Security; using System.Runtime; using System.Runtime.CompilerServices; using System.Runtime.Versioning; +using System.Diagnostics.CodeAnalysis; namespace System { @@ -51,7 +52,7 @@ namespace System throw new ArgumentNullException(nameof(info)); } - T target = (T)info.GetValue("TrackedObject", typeof(T))!; // Do not rename (binary serialization) // TODO-NULLABLE-GENERIC + T target = (T)info.GetValue("TrackedObject", typeof(T))!; // Do not rename (binary serialization) bool trackResurrection = info.GetBoolean("TrackResurrection"); // Do not rename (binary serialization) Create(target, trackResurrection); @@ -65,7 +66,7 @@ namespace System // DoSomething(ref.Target) // [MethodImplAttribute(MethodImplOptions.AggressiveInlining)] - public bool TryGetTarget(out T target) + public bool TryGetTarget([NotNullWhen(true)] out T target) { // Call the worker method that has more performant but less user friendly signature. T o = this.Target; -- 2.7.4