Nullable: System.Collections.Concurrent.dll
authorStephen Toub <stoub@microsoft.com>
Thu, 18 Apr 2019 02:42:16 +0000 (22:42 -0400)
committerStephen Toub <stoub@microsoft.com>
Thu, 9 May 2019 10:42:58 +0000 (06:42 -0400)
Commit migrated from https://github.com/dotnet/corefx/commit/9cf92cbef7cf5fcf46a1b556f9c6250e67d421ab

src/libraries/System.Collections.Concurrent/src/System.Collections.Concurrent.csproj
src/libraries/System.Collections.Concurrent/src/System/Collections/Concurrent/BlockingCollection.cs
src/libraries/System.Collections.Concurrent/src/System/Collections/Concurrent/ConcurrentBag.cs
src/libraries/System.Collections.Concurrent/src/System/Collections/Concurrent/ConcurrentDictionary.cs
src/libraries/System.Collections.Concurrent/src/System/Collections/Concurrent/ConcurrentStack.cs
src/libraries/System.Collections.Concurrent/src/System/Collections/Concurrent/OrderablePartitioner.cs
src/libraries/System.Collections.Concurrent/src/System/Collections/Concurrent/PartitionerStatic.cs

index 5abdb75..af4c27e 100644 (file)
@@ -4,6 +4,7 @@
     <AssemblyName>System.Collections.Concurrent</AssemblyName>
     <RootNamespace>System.Collections.Concurrent</RootNamespace>
     <IsPartialFacadeAssembly>true</IsPartialFacadeAssembly>
+    <NullableContextOptions>enable</NullableContextOptions>
     <Configurations>netcoreapp-Unix-Debug;netcoreapp-Unix-Release;netcoreapp-Windows_NT-Debug;netcoreapp-Windows_NT-Release;uap-Windows_NT-Debug;uap-Windows_NT-Release;uapaot-Windows_NT-Debug;uapaot-Windows_NT-Release</Configurations>
   </PropertyGroup>
   <ItemGroup>
index e29f1f6..ba0cf8b 100644 (file)
@@ -15,7 +15,6 @@
 using System.Collections.Generic;
 using System.Diagnostics;
 using System.Globalization;
-using System.Runtime.InteropServices;
 using System.Threading;
 
 namespace System.Collections.Concurrent
@@ -43,14 +42,14 @@ namespace System.Collections.Concurrent
     [DebuggerDisplay("Count = {Count}, Type = {_collection}")]
     public class BlockingCollection<T> : IEnumerable<T>, ICollection, IDisposable, IReadOnlyCollection<T>
     {
-        private IProducerConsumerCollection<T> _collection;
+        private IProducerConsumerCollection<T> _collection = null!;
         private int _boundedCapacity;
         private const int NON_BOUNDED = -1;
-        private SemaphoreSlim _freeNodes;
-        private SemaphoreSlim _occupiedNodes;
+        private SemaphoreSlim? _freeNodes;
+        private SemaphoreSlim _occupiedNodes = null!;
         private bool _isDisposed;
-        private CancellationTokenSource _consumersCancellationTokenSource;
-        private CancellationTokenSource _producersCancellationTokenSource;
+        private CancellationTokenSource _consumersCancellationTokenSource = null!;
+        private CancellationTokenSource _producersCancellationTokenSource = null!;
 
         private volatile int _currentAdders;
         private const int COMPLETE_ADDING_ON_MASK = unchecked((int)0x80000000);
@@ -413,7 +412,7 @@ nameof(boundedCapacity), boundedCapacity,
             {
                 //If the _freeNodes semaphore threw OperationCanceledException then this means that CompleteAdding()
                 //was called concurrently with Adding which is not supported by BlockingCollection.
-                CancellationTokenSource linkedTokenSource = null;
+                CancellationTokenSource? linkedTokenSource = null;
                 try
                 {
                     waitForSemaphoreWasSuccessful = _freeNodes.Wait(0);
@@ -579,7 +578,7 @@ nameof(boundedCapacity), boundedCapacity,
         /// <exception cref="T:System.InvalidOperationException">The underlying collection was modified
         /// outside of this <see
         /// cref="T:System.Collections.Concurrent.BlockingCollection{T}"/> instance.</exception>
-        public bool TryTake(out T item)
+        public bool TryTake(out T item) // TODO-NULLABLE-GENERIC
         {
             return TryTake(out item, 0, CancellationToken.None);
         }
@@ -601,7 +600,7 @@ nameof(boundedCapacity), boundedCapacity,
         /// <exception cref="T:System.InvalidOperationException">The underlying collection was modified
         /// outside of this <see
         /// cref="T:System.Collections.Concurrent.BlockingCollection{T}"/> instance.</exception>
-        public bool TryTake(out T item, TimeSpan timeout)
+        public bool TryTake(out T item, TimeSpan timeout) // TODO-NULLABLE-GENERIC
         {
             ValidateTimeout(timeout);
             return TryTakeWithNoTimeValidation(out item, (int)timeout.TotalMilliseconds, CancellationToken.None, null);
@@ -622,7 +621,7 @@ nameof(boundedCapacity), boundedCapacity,
         /// <exception cref="T:System.InvalidOperationException">The underlying collection was modified
         /// outside of this <see
         /// cref="T:System.Collections.Concurrent.BlockingCollection{T}"/> instance.</exception>
-        public bool TryTake(out T item, int millisecondsTimeout)
+        public bool TryTake(out T item, int millisecondsTimeout) // TODO-NULLABLE-GENERIC
         {
             ValidateMillisecondsTimeout(millisecondsTimeout);
             return TryTakeWithNoTimeValidation(out item, millisecondsTimeout, CancellationToken.None, null);
@@ -647,7 +646,7 @@ nameof(boundedCapacity), boundedCapacity,
         /// <exception cref="T:System.InvalidOperationException">The underlying collection was modified
         /// outside of this <see
         /// cref="T:System.Collections.Concurrent.BlockingCollection{T}"/> instance.</exception>
-        public bool TryTake(out T item, int millisecondsTimeout, CancellationToken cancellationToken)
+        public bool TryTake(out T item, int millisecondsTimeout, CancellationToken cancellationToken) // TODO-NULLABLE-GENERIC
         {
             ValidateMillisecondsTimeout(millisecondsTimeout);
             return TryTakeWithNoTimeValidation(out item, millisecondsTimeout, cancellationToken, null);
@@ -669,10 +668,10 @@ nameof(boundedCapacity), boundedCapacity,
         /// <returns>False if the collection remained empty till the timeout period was exhausted. True otherwise.</returns>
         /// <exception cref="OperationCanceledException">If the <see cref="CancellationToken"/> is canceled.</exception>
         /// <exception cref="System.ObjectDisposedException">If the collection has been disposed.</exception>
-        private bool TryTakeWithNoTimeValidation(out T item, int millisecondsTimeout, CancellationToken cancellationToken, CancellationTokenSource combinedTokenSource)
+        private bool TryTakeWithNoTimeValidation(out T item, int millisecondsTimeout, CancellationToken cancellationToken, CancellationTokenSource? combinedTokenSource) // TODO-NULLABLE-GENERIC
         {
             CheckDisposed();
-            item = default(T);
+            item = default(T)!; // TODO-NULLABLE-GENERIC
 
             if (cancellationToken.IsCancellationRequested)
                 throw new OperationCanceledException(SR.Common_OperationCanceled, cancellationToken);
@@ -685,14 +684,14 @@ nameof(boundedCapacity), boundedCapacity,
             bool waitForSemaphoreWasSuccessful = false;
 
             // set the combined token source to the combinedToken parameter if it is not null (came from GetConsumingEnumerable)
-            CancellationTokenSource linkedTokenSource = combinedTokenSource;
+            CancellationTokenSource? linkedTokenSource = combinedTokenSource;
             try
             {
                 waitForSemaphoreWasSuccessful = _occupiedNodes.Wait(0);
                 if (waitForSemaphoreWasSuccessful == false && millisecondsTimeout != 0)
                 {
                     // create the linked token if it is not created yet
-                    if (combinedTokenSource == null)
+                    if (linkedTokenSource == null)
                         linkedTokenSource = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken,
                                                                                           _consumersCancellationTokenSource.Token);
                     waitForSemaphoreWasSuccessful = _occupiedNodes.Wait(millisecondsTimeout, linkedTokenSource.Token);
@@ -795,7 +794,7 @@ nameof(boundedCapacity), boundedCapacity,
 #else
             return
 #endif
- TryAddToAny(collections, item, Timeout.Infinite, CancellationToken.None);
               TryAddToAny(collections, item, Timeout.Infinite, CancellationToken.None);
 #if DEBUG
             Debug.Assert((tryAddAnyReturnValue >= 0 && tryAddAnyReturnValue < collections.Length)
                                 , "TryAddToAny() was expected to return an index within the bounds of the collections array.");
@@ -837,7 +836,7 @@ nameof(boundedCapacity), boundedCapacity,
 #else
             return
 #endif
- TryAddToAny(collections, item, Timeout.Infinite, cancellationToken);
               TryAddToAny(collections, item, Timeout.Infinite, cancellationToken);
 #if DEBUG
             Debug.Assert((tryAddAnyReturnValue >= 0 && tryAddAnyReturnValue < collections.Length)
                                 , "TryAddToAny() was expected to return an index within the bounds of the collections array.");
@@ -1094,7 +1093,7 @@ nameof(boundedCapacity), boundedCapacity,
                 {
                     if (collections[i]._freeNodes != null)
                     {
-                        handlesList.Add(collections[i]._freeNodes.AvailableWaitHandle);
+                        handlesList.Add(collections[i]._freeNodes!.AvailableWaitHandle); // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/34644
                         tokensList.Add(collections[i]._producersCancellationTokenSource.Token);
                     }
                 }
@@ -1167,7 +1166,7 @@ nameof(boundedCapacity), boundedCapacity,
         /// <exception cref="T:System.ArgumentOutOfRangeException">The count of <paramref name="collections"/> is greater than the maximum size of
         /// 62 for STA and 63 for MTA.</exception>
         /// <remarks>A call to TakeFromAny may block until an item is available to be removed.</remarks>
-        public static int TakeFromAny(BlockingCollection<T>[] collections, out T item)
+        public static int TakeFromAny(BlockingCollection<T>[] collections, out T item) // TODO-NULLABLE-GENERIC
         {
             return TakeFromAny(collections, out item, CancellationToken.None);
         }
@@ -1196,7 +1195,7 @@ nameof(boundedCapacity), boundedCapacity,
         /// <exception cref="T:System.ArgumentOutOfRangeException">The count of <paramref name="collections"/> is greater than the maximum size of 
         /// 62 for STA and 63 for MTA.</exception>
         /// <remarks>A call to TakeFromAny may block until an item is available to be removed.</remarks>
-        public static int TakeFromAny(BlockingCollection<T>[] collections, out T item, CancellationToken cancellationToken)
+        public static int TakeFromAny(BlockingCollection<T>[] collections, out T item, CancellationToken cancellationToken) // TODO-NULLABLE-GENERIC
         {
             int returnValue = TryTakeFromAnyCore(collections, out item, Timeout.Infinite, true, cancellationToken);
             Debug.Assert((returnValue >= 0 && returnValue < collections.Length)
@@ -1224,7 +1223,7 @@ nameof(boundedCapacity), boundedCapacity,
         /// <exception cref="T:System.ArgumentOutOfRangeException">The count of <paramref name="collections"/> is greater than the maximum size of
         /// 62 for STA and 63 for MTA.</exception>
         /// <remarks>A call to TryTakeFromAny may block until an item is available to be removed.</remarks>
-        public static int TryTakeFromAny(BlockingCollection<T>[] collections, out T item)
+        public static int TryTakeFromAny(BlockingCollection<T>[] collections, out T item) // TODO-NULLABLE-GENERIC
         {
             return TryTakeFromAny(collections, out item, 0);
         }
@@ -1255,7 +1254,7 @@ nameof(boundedCapacity), boundedCapacity,
         /// <exception cref="T:System.ArgumentOutOfRangeException">The count of <paramref name="collections"/> is greater than the maximum size of
         /// 62 for STA and 63 for MTA.</exception>
         /// <remarks>A call to TryTakeFromAny may block until an item is available to be removed.</remarks>
-        public static int TryTakeFromAny(BlockingCollection<T>[] collections, out T item, TimeSpan timeout)
+        public static int TryTakeFromAny(BlockingCollection<T>[] collections, out T item, TimeSpan timeout) // TODO-NULLABLE-GENERIC
         {
             ValidateTimeout(timeout);
             return TryTakeFromAnyCore(collections, out item, (int)timeout.TotalMilliseconds, false, CancellationToken.None);
@@ -1285,7 +1284,7 @@ nameof(boundedCapacity), boundedCapacity,
         /// <exception cref="T:System.ArgumentOutOfRangeException">The count of <paramref name="collections"/> is greater than the maximum size of
         /// 62 for STA and 63 for MTA.</exception>
         /// <remarks>A call to TryTakeFromAny may block until an item is available to be removed.</remarks>
-        public static int TryTakeFromAny(BlockingCollection<T>[] collections, out T item, int millisecondsTimeout)
+        public static int TryTakeFromAny(BlockingCollection<T>[] collections, out T item, int millisecondsTimeout) // TODO-NULLABLE-GENERIC
         {
             ValidateMillisecondsTimeout(millisecondsTimeout);
             return TryTakeFromAnyCore(collections, out item, millisecondsTimeout, false, CancellationToken.None);
@@ -1319,7 +1318,7 @@ nameof(boundedCapacity), boundedCapacity,
         /// <exception cref="T:System.ArgumentOutOfRangeException">The count of <paramref name="collections"/> is greater than the maximum size of
         /// 62 for STA and 63 for MTA.</exception>
         /// <remarks>A call to TryTakeFromAny may block until an item is available to be removed.</remarks>
-        public static int TryTakeFromAny(BlockingCollection<T>[] collections, out T item, int millisecondsTimeout, CancellationToken cancellationToken)
+        public static int TryTakeFromAny(BlockingCollection<T>[] collections, out T item, int millisecondsTimeout, CancellationToken cancellationToken) // TODO-NULLABLE-GENERIC
         {
             ValidateMillisecondsTimeout(millisecondsTimeout);
             return TryTakeFromAnyCore(collections, out item, millisecondsTimeout, false, cancellationToken);
@@ -1342,7 +1341,7 @@ nameof(boundedCapacity), boundedCapacity,
         /// <exception cref="System.ArgumentException">If the collections argument is a 0-length array or contains a 
         /// null element. Also, if at least one of the collections has been marked complete for adds.</exception>
         /// <exception cref="System.ObjectDisposedException">If at least one of the collections has been disposed.</exception>
-        private static int TryTakeFromAnyCore(BlockingCollection<T>[] collections, out T item, int millisecondsTimeout, bool isTakeOperation, CancellationToken externalCancellationToken)
+        private static int TryTakeFromAnyCore(BlockingCollection<T>[] collections, out T item, int millisecondsTimeout, bool isTakeOperation, CancellationToken externalCancellationToken) // TODO-NULLABLE-GENERIC
         {
             ValidateCollectionsArray(collections, false);
 
@@ -1376,7 +1375,7 @@ nameof(boundedCapacity), boundedCapacity,
         /// <exception cref="System.ArgumentException">If the collections argument is a 0-length array or contains a 
         /// null element. Also, if at least one of the collections has been marked complete for adds.</exception>
         /// <exception cref="System.ObjectDisposedException">If at least one of the collections has been disposed.</exception>
-        private static int TryTakeFromAnyCoreSlow(BlockingCollection<T>[] collections, out T item, int millisecondsTimeout, bool isTakeOperation, CancellationToken externalCancellationToken)
+        private static int TryTakeFromAnyCoreSlow(BlockingCollection<T>[] collections, out T item, int millisecondsTimeout, bool isTakeOperation, CancellationToken externalCancellationToken) // TODO-NULLABLE-GENERIC
         {
             const int OPERATION_FAILED = -1;
 
@@ -1454,7 +1453,7 @@ nameof(boundedCapacity), boundedCapacity,
                     timeout = UpdateTimeOut(startTime, millisecondsTimeout);
             }
 
-            item = default(T); //case#2
+            item = default(T)!; //case#2  // TODO-NULLABLE-GENERIC
             return OPERATION_FAILED;
         }
 
@@ -1649,7 +1648,7 @@ nameof(boundedCapacity), boundedCapacity,
         /// <exception cref="OperationCanceledException">If the <see cref="CancellationToken"/> is canceled.</exception>
         public IEnumerable<T> GetConsumingEnumerable(CancellationToken cancellationToken)
         {
-            CancellationTokenSource linkedTokenSource = null;
+            CancellationTokenSource? linkedTokenSource = null;
             try
             {
                 linkedTokenSource = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, _consumersCancellationTokenSource.Token);
index 59f9757..7a18348 100644 (file)
@@ -34,7 +34,7 @@ namespace System.Collections.Concurrent
         /// <summary>The per-bag, per-thread work-stealing queues.</summary>
         private readonly ThreadLocal<WorkStealingQueue> _locals;
         /// <summary>The head work stealing queue in a linked list of queues.</summary>
-        private volatile WorkStealingQueue _workStealingQueues;
+        private volatile WorkStealingQueue? _workStealingQueues;
         /// <summary>Number of times any list transitions from empty to non-empty.</summary>
         private long _emptyToNonEmptyListTransitionCount;
 
@@ -61,7 +61,7 @@ namespace System.Collections.Concurrent
 
             _locals = new ThreadLocal<WorkStealingQueue>();
 
-            WorkStealingQueue queue = GetCurrentThreadWorkStealingQueue(forceCreate: true);
+            WorkStealingQueue queue = GetCurrentThreadWorkStealingQueue(forceCreate: true)!;
             foreach (T item in collection)
             {
                 queue.LocalPush(item, ref _emptyToNonEmptyListTransitionCount);
@@ -75,7 +75,7 @@ namespace System.Collections.Concurrent
         /// <see cref="ConcurrentBag{T}"/>. The value can be a null reference
         /// (Nothing in Visual Basic) for reference types.</param>
         public void Add(T item) =>
-            GetCurrentThreadWorkStealingQueue(forceCreate: true)
+            GetCurrentThreadWorkStealingQueue(forceCreate: true)!
             .LocalPush(item, ref _emptyToNonEmptyListTransitionCount);
 
         /// <summary>
@@ -98,9 +98,9 @@ namespace System.Collections.Concurrent
         /// removed from the <see cref="ConcurrentBag{T}"/> or the default value
         /// of <typeparamref name="T"/> if the operation failed.</param>
         /// <returns>true if an object was removed successfully; otherwise, false.</returns>
-        public bool TryTake(out T result)
+        public bool TryTake(out T result) // TODO-NULLABLE-GENERIC
         {
-            WorkStealingQueue queue = GetCurrentThreadWorkStealingQueue(forceCreate: false);
+            WorkStealingQueue? queue = GetCurrentThreadWorkStealingQueue(forceCreate: false);
             return (queue != null && queue.TryLocalPop(out result)) || TrySteal(out result, take: true);
         }
 
@@ -111,16 +111,16 @@ namespace System.Collections.Concurrent
         /// the <see cref="ConcurrentBag{T}"/> or the default value of
         /// <typeparamref name="T"/> if the operation failed.</param>
         /// <returns>true if and object was returned successfully; otherwise, false.</returns>
-        public bool TryPeek(out T result)
+        public bool TryPeek(out T result) // TODO-NULLABLE-GENERIC
         {
-            WorkStealingQueue queue = GetCurrentThreadWorkStealingQueue(forceCreate: false);
+            WorkStealingQueue? queue = GetCurrentThreadWorkStealingQueue(forceCreate: false);
             return (queue != null && queue.TryLocalPeek(out result)) || TrySteal(out result, take: false);
         }
 
         /// <summary>Gets the work-stealing queue data structure for the current thread.</summary>
         /// <param name="forceCreate">Whether to create a new queue if this thread doesn't have one.</param>
         /// <returns>The local queue object, or null if the thread doesn't have one.</returns>
-        private WorkStealingQueue GetCurrentThreadWorkStealingQueue(bool forceCreate) =>
+        private WorkStealingQueue? GetCurrentThreadWorkStealingQueue(bool forceCreate) => // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761
             _locals.Value ??
             (forceCreate ? CreateWorkStealingQueueForCurrentThread() : null);
 
@@ -128,9 +128,9 @@ namespace System.Collections.Concurrent
         {
             lock (GlobalQueuesLock) // necessary to update _workStealingQueues, so as to synchronize with freezing operations
             {
-                WorkStealingQueue head = _workStealingQueues;
+                WorkStealingQueue? head = _workStealingQueues;
 
-                WorkStealingQueue queue = head != null ? GetUnownedWorkStealingQueue() : null;
+                WorkStealingQueue? queue = head != null ? GetUnownedWorkStealingQueue() : null;
                 if (queue == null)
                 {
                     _workStealingQueues = queue = new WorkStealingQueue(head);
@@ -146,7 +146,7 @@ namespace System.Collections.Concurrent
         /// the bag purposefully retains its queue, as it contains data associated with the bag.
         /// </summary>
         /// <returns>The queue object, or null if no unowned queue could be gathered.</returns>
-        private WorkStealingQueue GetUnownedWorkStealingQueue()
+        private WorkStealingQueue? GetUnownedWorkStealingQueue()
         {
             Debug.Assert(Monitor.IsEntered(GlobalQueuesLock));
 
@@ -154,7 +154,7 @@ namespace System.Collections.Concurrent
             // but if our thread ID is reused, we know that no other thread can have the same ID and thus
             // no other thread can be using this queue.
             int currentThreadId = Environment.CurrentManagedThreadId;
-            for (WorkStealingQueue queue = _workStealingQueues; queue != null; queue = queue._nextQueue)
+            for (WorkStealingQueue? queue = _workStealingQueues; queue != null; queue = queue._nextQueue)
             {
                 if (queue._ownerThreadId == currentThreadId)
                 {
@@ -209,7 +209,7 @@ namespace System.Collections.Concurrent
                 // and try to steal from each queue until we get a result. If there is a local queue from this thread,
                 // then start from the next queue after it, and then iterate around back from the head to this queue,
                 // not including it.
-                WorkStealingQueue localQueue = GetCurrentThreadWorkStealingQueue(forceCreate: false);
+                WorkStealingQueue? localQueue = GetCurrentThreadWorkStealingQueue(forceCreate: false);
                 bool gotItem = localQueue == null ?
                     TryStealFromTo(_workStealingQueues, null, out result, take) :
                     (TryStealFromTo(localQueue._nextQueue, null, out result, take) || TryStealFromTo(_workStealingQueues, localQueue, out result, take));
@@ -234,17 +234,17 @@ namespace System.Collections.Concurrent
         /// <summary>
         /// Attempts to steal from each queue starting from <paramref name="startInclusive"/> to <paramref name="endExclusive"/>.
         /// </summary>
-        private bool TryStealFromTo(WorkStealingQueue startInclusive, WorkStealingQueue endExclusive, out T result, bool take)
+        private bool TryStealFromTo(WorkStealingQueue? startInclusive, WorkStealingQueue? endExclusive, out T result, bool take) // TODO-NULLABLE-GENERIC
         {
-            for (WorkStealingQueue queue = startInclusive; queue != endExclusive; queue = queue._nextQueue)
+            for (WorkStealingQueue? queue = startInclusive; queue != endExclusive; queue = queue._nextQueue)
             {
-                if (queue.TrySteal(out result, take))
+                if (queue!.TrySteal(out result, take))
                 {
                     return true;
                 }
             }
 
-            result = default(T);
+            result = default(T)!; // TODO-NULLABLE-GENERIC
             return false;
         }
 
@@ -321,7 +321,7 @@ namespace System.Collections.Concurrent
             Debug.Assert(Monitor.IsEntered(GlobalQueuesLock));
 
             int i = index;
-            for (WorkStealingQueue queue = _workStealingQueues; queue != null; queue = queue._nextQueue)
+            for (WorkStealingQueue? queue = _workStealingQueues; queue != null; queue = queue._nextQueue)
             {
                 i += queue.DangerousCopyTo(array, i);
             }
@@ -357,7 +357,7 @@ namespace System.Collections.Concurrent
         {
             // If the destination is actually a T[], use the strongly-typed
             // overload that doesn't allocate/copy an extra array.
-            T[] szArray = array as T[];
+            T[]? szArray = array as T[];
             if (szArray != null)
             {
                 CopyTo(szArray, index);
@@ -418,7 +418,7 @@ namespace System.Collections.Concurrent
             }
 
             // Clear the local queue.
-            WorkStealingQueue local = GetCurrentThreadWorkStealingQueue(forceCreate: false);
+            WorkStealingQueue? local = GetCurrentThreadWorkStealingQueue(forceCreate: false);
             if (local != null)
             {
                 local.LocalClear();
@@ -438,7 +438,7 @@ namespace System.Collections.Concurrent
             try
             {
                 FreezeBag(ref lockTaken);
-                for (WorkStealingQueue queue = _workStealingQueues; queue != null; queue = queue._nextQueue)
+                for (WorkStealingQueue? queue = _workStealingQueues; queue != null; queue = queue._nextQueue)
                 {
                     T ignored;
                     while (queue.TrySteal(out ignored, take: true));
@@ -516,7 +516,7 @@ namespace System.Collections.Concurrent
             get
             {
                 int count = 0;
-                for (WorkStealingQueue queue = _workStealingQueues; queue != null; queue = queue._nextQueue)
+                for (WorkStealingQueue? queue = _workStealingQueues; queue != null; queue = queue._nextQueue)
                 {
                     checked { count += queue.DangerousCount; }
                 }
@@ -535,7 +535,7 @@ namespace System.Collections.Concurrent
             get
             {
                 // Fast-path based on the current thread's local queue.
-                WorkStealingQueue local = GetCurrentThreadWorkStealingQueue(forceCreate: false);
+                WorkStealingQueue? local = GetCurrentThreadWorkStealingQueue(forceCreate: false);
                 if (local != null)
                 {
                     // We don't need the lock to check the local queue, as no other thread
@@ -563,7 +563,7 @@ namespace System.Collections.Concurrent
                 try
                 {
                     FreezeBag(ref lockTaken);
-                    for (WorkStealingQueue queue = _workStealingQueues; queue != null; queue = queue._nextQueue)
+                    for (WorkStealingQueue? queue = _workStealingQueues; queue != null; queue = queue._nextQueue)
                     {
                         if (!queue.IsEmpty)
                         {
@@ -619,17 +619,17 @@ namespace System.Collections.Concurrent
             // while a global operation is in progress.
             Debug.Assert(!Monitor.IsEntered(GlobalQueuesLock));
             Monitor.Enter(GlobalQueuesLock, ref lockTaken);
-            WorkStealingQueue head = _workStealingQueues; // stable at least until GlobalQueuesLock is released in UnfreezeBag
+            WorkStealingQueue? head = _workStealingQueues; // stable at least until GlobalQueuesLock is released in UnfreezeBag
 
             // Then acquire all local queue locks, noting on each that it's been taken.
-            for (WorkStealingQueue queue = head; queue != null; queue = queue._nextQueue)
+            for (WorkStealingQueue? queue = head; queue != null; queue = queue._nextQueue)
             {
                 Monitor.Enter(queue, ref queue._frozen);
             }
             Interlocked.MemoryBarrier(); // prevent reads of _currentOp from moving before writes to _frozen
 
             // Finally, wait for all unsynchronized operations on each queue to be done.
-            for (WorkStealingQueue queue = head; queue != null; queue = queue._nextQueue)
+            for (WorkStealingQueue? queue = head; queue != null; queue = queue._nextQueue)
             {
                 if (queue._currentOp != (int)Operation.None)
                 {
@@ -648,7 +648,7 @@ namespace System.Collections.Concurrent
             if (lockTaken)
             {
                 // Release all of the individual queue locks.
-                for (WorkStealingQueue queue = _workStealingQueues; queue != null; queue = queue._nextQueue)
+                for (WorkStealingQueue? queue = _workStealingQueues; queue != null; queue = queue._nextQueue)
                 {
                     if (queue._frozen)
                     {
@@ -691,13 +691,13 @@ namespace System.Collections.Concurrent
             /// <summary>true if this queue's lock is held as part of a global freeze.</summary>
             internal bool _frozen;
             /// <summary>Next queue in the <see cref="ConcurrentBag{T}"/>'s set of thread-local queues.</summary>
-            internal readonly WorkStealingQueue _nextQueue;
+            internal readonly WorkStealingQueue? _nextQueue;
             /// <summary>Thread ID that owns this queue.</summary>
             internal readonly int _ownerThreadId;
 
             /// <summary>Initialize the WorkStealingQueue.</summary>
             /// <param name="nextQueue">The next queue in the linked list of work-stealing queues.</param>
-            internal WorkStealingQueue(WorkStealingQueue nextQueue)
+            internal WorkStealingQueue(WorkStealingQueue? nextQueue)
             {
                 _ownerThreadId = Environment.CurrentManagedThreadId;
                 _nextQueue = nextQueue;
@@ -859,14 +859,14 @@ namespace System.Collections.Concurrent
 
             /// <summary>Remove an item from the tail of the queue.</summary>
             /// <param name="result">The removed item</param>
-            internal bool TryLocalPop(out T result)
+            internal bool TryLocalPop(out T result) // TODO-NULLABLE-GENERIC
             {
                 Debug.Assert(Environment.CurrentManagedThreadId == _ownerThreadId);
 
                 int tail = _tailIndex;
                 if (_headIndex >= tail)
                 {
-                    result = default(T);
+                    result = default(T)!;
                     return false;
                 }
 
@@ -888,7 +888,7 @@ namespace System.Collections.Concurrent
                     {
                         int idx = tail & _mask;
                         result = _array[idx];
-                        _array[idx] = default(T);
+                        _array[idx] = default(T)!; // TODO-NULLABLE-GENERIC
                         _addTakeCount--;
                         return true;
                     }
@@ -902,7 +902,7 @@ namespace System.Collections.Concurrent
                             // Element still available. Take it.
                             int idx = tail & _mask;
                             result = _array[idx];
-                            _array[idx] = default(T);
+                            _array[idx] = default(T)!;
                             _addTakeCount--;
                             return true;
                         }
@@ -910,7 +910,7 @@ namespace System.Collections.Concurrent
                         {
                             // We encountered a race condition and the element was stolen, restore the tail.
                             _tailIndex = tail + 1;
-                            result = default(T);
+                            result = default(T)!; // TODO-NULLABLE-GENERIC
                             return false;
                         }
                     }
@@ -928,7 +928,7 @@ namespace System.Collections.Concurrent
             /// <summary>Peek an item from the tail of the queue.</summary>
             /// <param name="result">the peeked item</param>
             /// <returns>True if succeeded, false otherwise</returns>
-            internal bool TryLocalPeek(out T result)
+            internal bool TryLocalPeek(out T result) // TODO-NULLABLE-GENERIC
             {
                 Debug.Assert(Environment.CurrentManagedThreadId == _ownerThreadId);
 
@@ -954,14 +954,14 @@ namespace System.Collections.Concurrent
                     }
                 }
 
-                result = default(T);
+                result = default(T)!; // TODO-NULLABLE-GENERIC
                 return false;
             }
 
             /// <summary>Steal an item from the head of the queue.</summary>
             /// <param name="result">the removed item</param>
             /// <param name="take">true to take the item; false to simply peek at it</param>
-            internal bool TrySteal(out T result, bool take)
+            internal bool TrySteal(out T result, bool take) // TODO-NULLABLE-GENERIC
             {
                 lock (this)
                 {
@@ -992,7 +992,7 @@ namespace System.Collections.Concurrent
                         {
                             int idx = head & _mask;
                             result = _array[idx];
-                            _array[idx] = default(T);
+                            _array[idx] = default(T)!; // TODO-NULLABLE-GENERIC
                             _stealCount++;
                             return true;
                         }
@@ -1011,7 +1011,7 @@ namespace System.Collections.Concurrent
                 }
 
                 // The queue was empty.
-                result = default(T);
+                result = default(T)!; // TODO-NULLABLE-GENERIC
                 return false;
             }
 
@@ -1079,7 +1079,7 @@ namespace System.Collections.Concurrent
         private sealed class Enumerator : IEnumerator<T>
         {
             private readonly T[] _array;
-            private T _current;
+            private T _current = default!;
             private int _index;
 
             public Enumerator(T[] array)
@@ -1102,7 +1102,7 @@ namespace System.Collections.Concurrent
 
             public T Current => _current;
 
-            object IEnumerator.Current
+            object? IEnumerator.Current
             {
                 get
                 {
@@ -1117,7 +1117,7 @@ namespace System.Collections.Concurrent
             public void Reset()
             {
                 _index = 0;
-                _current = default(T);
+                _current = default(T)!; // TODO-NULLABLE-GENERIC
             }
 
             public void Dispose() { }
index 528eaa1..71fb8b6 100644 (file)
@@ -15,7 +15,6 @@
 using System.Collections.Generic;
 using System.Collections.ObjectModel;
 using System.Diagnostics;
-using System.Reflection;
 using System.Runtime.CompilerServices;
 using System.Threading;
 
@@ -32,7 +31,7 @@ namespace System.Collections.Concurrent
     /// </remarks>
     [DebuggerTypeProxy(typeof(IDictionaryDebugView<,>))]
     [DebuggerDisplay("Count = {Count}")]
-    public class ConcurrentDictionary<TKey, TValue> : IDictionary<TKey, TValue>, IDictionary, IReadOnlyDictionary<TKey, TValue>
+    public class ConcurrentDictionary<TKey, TValue> : IDictionary<TKey, TValue>, IDictionary, IReadOnlyDictionary<TKey, TValue> where TKey : object
     {
         /// <summary>
         /// Tables that hold the internal state of the ConcurrentDictionary
@@ -158,7 +157,7 @@ namespace System.Collections.Concurrent
         /// </summary>
         /// <param name="comparer">The <see cref="T:System.Collections.Generic.IEqualityComparer{TKey}"/>
         /// implementation to use when comparing keys.</param>
-        public ConcurrentDictionary(IEqualityComparer<TKey> comparer) : this(DefaultConcurrencyLevel, DefaultCapacity, true, comparer) { }
+        public ConcurrentDictionary(IEqualityComparer<TKey>? comparer) : this(DefaultConcurrencyLevel, DefaultCapacity, true, comparer) { }
 
         /// <summary>
         /// Initializes a new instance of the <see cref="ConcurrentDictionary{TKey,TValue}"/>
@@ -175,7 +174,7 @@ namespace System.Collections.Concurrent
         /// implementation to use when comparing keys.</param>
         /// <exception cref="T:System.ArgumentNullException"><paramref name="collection"/> is a null reference
         /// (Nothing in Visual Basic).</exception>
-        public ConcurrentDictionary(IEnumerable<KeyValuePair<TKey, TValue>> collection, IEqualityComparer<TKey> comparer)
+        public ConcurrentDictionary(IEnumerable<KeyValuePair<TKey, TValue>> collection, IEqualityComparer<TKey>? comparer)
             : this(comparer)
         {
             if (collection == null) throw new ArgumentNullException(nameof(collection));
@@ -203,7 +202,7 @@ namespace System.Collections.Concurrent
         /// </exception>
         /// <exception cref="T:System.ArgumentException"><paramref name="collection"/> contains one or more duplicate keys.</exception>
         public ConcurrentDictionary(
-            int concurrencyLevel, IEnumerable<KeyValuePair<TKey, TValue>> collection, IEqualityComparer<TKey> comparer)
+            int concurrencyLevel, IEnumerable<KeyValuePair<TKey, TValue>> collection, IEqualityComparer<TKey>? comparer)
             : this(concurrencyLevel, DefaultCapacity, false, comparer)
         {
             if (collection == null) throw new ArgumentNullException(nameof(collection));
@@ -246,12 +245,12 @@ namespace System.Collections.Concurrent
         /// <paramref name="concurrencyLevel"/> is less than 1. -or-
         /// <paramref name="capacity"/> is less than 0.
         /// </exception>
-        public ConcurrentDictionary(int concurrencyLevel, int capacity, IEqualityComparer<TKey> comparer)
+        public ConcurrentDictionary(int concurrencyLevel, int capacity, IEqualityComparer<TKey>? comparer)
             : this(concurrencyLevel, capacity, false, comparer)
         {
         }
 
-        internal ConcurrentDictionary(int concurrencyLevel, int capacity, bool growLockArray, IEqualityComparer<TKey> comparer)
+        internal ConcurrentDictionary(int concurrencyLevel, int capacity, bool growLockArray, IEqualityComparer<TKey>? comparer)
         {
             if (concurrencyLevel < 1)
             {
@@ -335,11 +334,11 @@ namespace System.Collections.Concurrent
         /// <returns>true if an object was removed successfully; otherwise, false.</returns>
         /// <exception cref="T:System.ArgumentNullException"><paramref name="key"/> is a null reference
         /// (Nothing in Visual Basic).</exception>
-        public bool TryRemove(TKey key, out TValue value)
+        public bool TryRemove(TKey key, out TValue value) // TODO-NULLABLE-GENERIC
         {
             if (key == null) ThrowKeyNullException();
 
-            return TryRemoveInternal(key, out value, false, default(TValue));
+            return TryRemoveInternal(key, out value, false, default(TValue)!); // TODO-NULLABLE-GENERIC
         }
 
         /// <summary>
@@ -352,7 +351,7 @@ namespace System.Collections.Concurrent
         /// <param name="matchValue">Whether removal of the key is conditional on its value.</param>
         /// <param name="oldValue">The conditional value to compare against if <paramref name="matchValue"/> is true</param>
         /// <returns></returns>
-        private bool TryRemoveInternal(TKey key, out TValue value, bool matchValue, TValue oldValue)
+        private bool TryRemoveInternal(TKey key, out TValue value, bool matchValue, TValue oldValue) // TODO-NULLABLE-GENERIC
         {
             int hashcode = _comparer.GetHashCode(key);
             while (true)
@@ -371,10 +370,10 @@ namespace System.Collections.Concurrent
                         continue;
                     }
 
-                    Node prev = null;
+                    Node? prev = null;
                     for (Node curr = tables._buckets[bucketNo]; curr != null; curr = curr._next)
                     {
-                        Debug.Assert((prev == null && curr == tables._buckets[bucketNo]) || prev._next == curr);
+                        Debug.Assert((prev == null && curr == tables._buckets[bucketNo]) || prev!._next == curr);
 
                         if (hashcode == curr._hashcode && _comparer.Equals(curr._key, key))
                         {
@@ -383,7 +382,7 @@ namespace System.Collections.Concurrent
                                 bool valuesMatch = EqualityComparer<TValue>.Default.Equals(oldValue, curr._value);
                                 if (!valuesMatch)
                                 {
-                                    value = default(TValue);
+                                    value = default(TValue)!; // TODO-NULLABLE-GENERIC
                                     return false;
                                 }
                             }
@@ -405,7 +404,7 @@ namespace System.Collections.Concurrent
                     }
                 }
 
-                value = default(TValue);
+                value = default(TValue)!; // TODO-NULLABLE-GENERIC
                 return false;
             }
         }
@@ -423,13 +422,13 @@ namespace System.Collections.Concurrent
         /// otherwise, false.</returns>
         /// <exception cref="T:System.ArgumentNullException"><paramref name="key"/> is a null reference
         /// (Nothing in Visual Basic).</exception>
-        public bool TryGetValue(TKey key, out TValue value)
+        public bool TryGetValue(TKey key, out TValue value) // TODO-NULLABLE-GENERIC
         {
             if (key == null) ThrowKeyNullException();
             return TryGetValueInternal(key, _comparer.GetHashCode(key), out value);
         }
 
-        private bool TryGetValueInternal(TKey key, int hashcode, out TValue value)
+        private bool TryGetValueInternal(TKey key, int hashcode, out TValue value) // TODO-NULLABLE-GENERIC
         {
             Debug.Assert(_comparer.GetHashCode(key) == hashcode);
 
@@ -453,7 +452,7 @@ namespace System.Collections.Concurrent
                 n = n._next;
             }
 
-            value = default(TValue);
+            value = default(TValue)!; // TODO-NULLABLE-GENERIC
             return false;
         }
 
@@ -518,10 +517,10 @@ namespace System.Collections.Concurrent
                     }
 
                     // Try to find this key in the bucket
-                    Node prev = null;
+                    Node? prev = null;
                     for (Node node = tables._buckets[bucketNo]; node != null; node = node._next)
                     {
-                        Debug.Assert((prev == null && node == tables._buckets[bucketNo]) || prev._next == node);
+                        Debug.Assert((prev == null && node == tables._buckets[bucketNo]) || prev!._next == node);
                         if (hashcode == node._hashcode && _comparer.Equals(node._key, key))
                         {
                             if (valueComparer.Equals(node._value, comparisonValue))
@@ -778,10 +777,10 @@ namespace System.Collections.Concurrent
                     }
 
                     // Try to find this key in the bucket
-                    Node prev = null;
+                    Node? prev = null;
                     for (Node node = tables._buckets[bucketNo]; node != null; node = node._next)
                     {
-                        Debug.Assert((prev == null && node == tables._buckets[bucketNo]) || prev._next == node);
+                        Debug.Assert((prev == null && node == tables._buckets[bucketNo]) || prev!._next == node);
                         if (hashcode == node._hashcode && _comparer.Equals(node._key, key))
                         {
                             // The key was found in the dictionary. If updates are allowed, update the value for that key.
@@ -905,7 +904,7 @@ namespace System.Collections.Concurrent
 
 
         [MethodImpl(MethodImplOptions.AggressiveInlining)]
-        private static void ThrowIfInvalidObjectValue(object value)
+        private static void ThrowIfInvalidObjectValue(object? value)
         {
             if (value != null)
             {
@@ -914,7 +913,7 @@ namespace System.Collections.Concurrent
                     ThrowValueNullException();
                 }
             }
-            else if (default(TValue) != null)
+            else if (default(TValue)! != null) // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/34757
             {
                 ThrowValueNullException();
             }
@@ -1468,13 +1467,13 @@ namespace System.Collections.Concurrent
         /// -or- A value with the same key already exists in the <see
         /// cref="T:System.Collections.Generic.Dictionary{TKey,TValue}"/>.
         /// </exception>
-        void IDictionary.Add(object key, object value)
+        void IDictionary.Add(object key, object? value)
         {
             if (key == null) ThrowKeyNullException();
             if (!(key is TKey)) throw new ArgumentException(SR.ConcurrentDictionary_TypeOfKeyIncorrect);
             ThrowIfInvalidObjectValue(value);
 
-            ((IDictionary<TKey, TValue>)this).Add((TKey)key, (TValue)value);
+            ((IDictionary<TKey, TValue>)this).Add((TKey)key, (TValue)value!);
         }
 
         /// <summary>
@@ -1587,7 +1586,7 @@ namespace System.Collections.Concurrent
         /// <typeparamref name="TValue"/> of the <see
         /// cref="T:System.Collections.Generic.ConcurrentDictionary{TKey,TValue}"/>
         /// </exception>
-        object IDictionary.this[object key]
+        object? IDictionary.this[object key]
         {
             get
             {
@@ -1608,7 +1607,7 @@ namespace System.Collections.Concurrent
                 if (!(key is TKey)) throw new ArgumentException(SR.ConcurrentDictionary_TypeOfKeyIncorrect);
                 ThrowIfInvalidObjectValue(value);
 
-                ((ConcurrentDictionary<TKey, TValue>)this)[(TKey)key] = (TValue)value;
+                ((ConcurrentDictionary<TKey, TValue>)this)[(TKey)key] = (TValue)value!; // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538
             }
         }
 
@@ -1663,21 +1662,21 @@ namespace System.Collections.Concurrent
                 //    - an array of DictionaryEntry structs
                 //    - an array of objects
 
-                KeyValuePair<TKey, TValue>[] pairs = array as KeyValuePair<TKey, TValue>[];
+                KeyValuePair<TKey, TValue>[]? pairs = array as KeyValuePair<TKey, TValue>[];
                 if (pairs != null)
                 {
                     CopyToPairs(pairs, index);
                     return;
                 }
 
-                DictionaryEntry[] entries = array as DictionaryEntry[];
+                DictionaryEntry[]? entries = array as DictionaryEntry[];
                 if (entries != null)
                 {
                     CopyToEntries(entries, index);
                     return;
                 }
 
-                object[] objects = array as object[];
+                object[]? objects = array as object[];
                 if (objects != null)
                 {
                     CopyToObjects(objects, index);
@@ -2058,12 +2057,14 @@ namespace System.Collections.Concurrent
                 get { return _enumerator.Current.Key; }
             }
 
-            public object Value
+            public object? Value
             {
                 get { return _enumerator.Current.Value; }
             }
 
+#pragma warning disable CS8612 // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/23268
             public object Current
+#pragma warning restore CS8612
             {
                 get { return Entry; }
             }
index cd5d921..afe9725 100644 (file)
@@ -44,7 +44,7 @@ namespace System.Collections.Concurrent
         private class Node
         {
             internal readonly T _value; // Value of the node.
-            internal Node _next; // Next pointer.
+            internal Node? _next; // Next pointer.
 
             /// <summary>
             /// Constructs a new node with the specified value and no next node.
@@ -57,7 +57,7 @@ namespace System.Collections.Concurrent
             }
         }
 
-        private volatile Node _head; // The stack is a singly linked list, and only remembers the head.
+        private volatile Node? _head; // The stack is a singly linked list, and only remembers the head.
         private const int BACKOFF_MAX_YIELDS = 8; // Arbitrary number to cap backoff.
 
         /// <summary>
@@ -92,7 +92,7 @@ namespace System.Collections.Concurrent
         private void InitializeFromCollection(IEnumerable<T> collection)
         {
             // We just copy the contents of the collection to our stack.
-            Node lastNode = null;
+            Node? lastNode = null;
             foreach (T element in collection)
             {
                 Node newNode = new Node(element);
@@ -148,7 +148,7 @@ namespace System.Collections.Concurrent
                 // they are being dequeued. If we ever changed this (e.g. to pool nodes somehow),
                 // we'd need to revisit this implementation.
 
-                for (Node curr = _head; curr != null; curr = curr._next)
+                for (Node? curr = _head; curr != null; curr = curr._next)
                 {
                     count++; //we don't handle overflow, to be consistent with existing generic collection types in CLR
                 }
@@ -446,14 +446,14 @@ namespace System.Collections.Concurrent
         /// the top of the <see cref="T:System.Collections.Concurrent.ConcurrentStack{T}"/> or an
         /// unspecified value if the operation failed.</param>
         /// <returns>true if and object was returned successfully; otherwise, false.</returns>
-        public bool TryPeek(out T result)
+        public bool TryPeek(out T result) // TODO-NULLABLE-GENERIC
         {
-            Node head = _head;
+            Node? head = _head;
 
             // If the stack is empty, return false; else return the element and true.
             if (head == null)
             {
-                result = default(T);
+                result = default(T)!; // TODO-NULLABLE-GENERIC
                 return false;
             }
             else
@@ -473,13 +473,13 @@ namespace System.Collections.Concurrent
         /// <returns>true if an element was removed and returned from the top of the <see
         /// cref="ConcurrentStack{T}"/>
         /// successfully; otherwise, false.</returns>
-        public bool TryPop(out T result)
+        public bool TryPop(out T result) // TODO-NULLABLE-GENERIC
         {
-            Node head = _head;
+            Node? head = _head;
             //stack is empty
             if (head == null)
             {
-                result = default(T);
+                result = default(T)!; // TODO-NULLABLE-GENERIC
                 return false;
             }
             if (Interlocked.CompareExchange(ref _head, head._next, head) == head)
@@ -558,11 +558,11 @@ namespace System.Collections.Concurrent
             if (count == 0)
                 return 0;
 
-            Node poppedHead;
+            Node? poppedHead;
             int nodesCount = TryPopCore(count, out poppedHead);
             if (nodesCount > 0)
             {
-                CopyRemovedItems(poppedHead, items, startIndex, nodesCount);
+                CopyRemovedItems(poppedHead!, items, startIndex, nodesCount);
             }
             return nodesCount;
         }
@@ -572,17 +572,17 @@ namespace System.Collections.Concurrent
         /// </summary>
         /// <param name="result">The popped item</param>
         /// <returns>True if succeeded, false otherwise</returns>
-        private bool TryPopCore(out T result)
+        private bool TryPopCore(out T result) // TODO-NULLABLE-GENERIC
         {
-            Node poppedNode;
+            Node? poppedNode;
 
             if (TryPopCore(1, out poppedNode) == 1)
             {
-                result = poppedNode._value;
+                result = poppedNode!._value; // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761
                 return true;
             }
 
-            result = default(T);
+            result = default(T)!; // TODO-NULLABLE-GENERIC
             return false;
         }
 
@@ -597,16 +597,16 @@ namespace System.Collections.Concurrent
         /// </param>
         /// <returns>The number of objects successfully popped from the top of
         /// the <see cref="ConcurrentStack{T}"/>.</returns>
-        private int TryPopCore(int count, out Node poppedHead)
+        private int TryPopCore(int count, out Node? poppedHead) // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761
         {
             SpinWait spin = new SpinWait();
 
             // Try to CAS the head with its current next.  We stop when we succeed or
             // when we notice that the stack is empty, whichever comes first.
-            Node head;
+            Node? head;
             Node next;
             int backoff = 1;
-            Random r = null;
+            Random? r = null;
             while (true)
             {
                 head = _head;
@@ -671,10 +671,10 @@ namespace System.Collections.Concurrent
         /// <param name="nodesCount">The number of nodes.</param>
         private static void CopyRemovedItems(Node head, T[] collection, int startIndex, int nodesCount)
         {
-            Node current = head;
+            Node? current = head;
             for (int i = startIndex; i < startIndex + nodesCount; i++)
             {
-                collection[i] = current._value;
+                collection[i] = current!._value;
                 current = current._next;
             }
         }
@@ -703,7 +703,7 @@ namespace System.Collections.Concurrent
         /// cref="ConcurrentStack{T}"/>.</returns>
         public T[] ToArray()
         {
-            Node curr = _head;
+            Node? curr = _head;
             return curr == null ?
                 Array.Empty<T>() :
                 ToList(curr).ToArray();
@@ -723,7 +723,7 @@ namespace System.Collections.Concurrent
         /// Returns an array containing a snapshot of the list's contents starting at the specified node.
         /// </summary>
         /// <returns>A list of the stack's contents starting at the specified node.</returns>
-        private List<T> ToList(Node curr)
+        private List<T> ToList(Node? curr)
         {
             List<T> list = new List<T>();
 
@@ -759,9 +759,9 @@ namespace System.Collections.Concurrent
             return GetEnumerator(_head);
         }
 
-        private IEnumerator<T> GetEnumerator(Node head)
+        private IEnumerator<T> GetEnumerator(Node? head)
         {
-            Node current = head;
+            Node? current = head;
             while (current != null)
             {
                 yield return current._value;
index 1fa639f..7135dcf 100644 (file)
@@ -230,7 +230,7 @@ namespace System.Collections.Concurrent
             }
             public void Dispose()
             {
-                IDisposable d = _source as IDisposable;
+                IDisposable? d = _source as IDisposable;
                 if (d != null)
                 {
                     d.Dispose();
@@ -256,7 +256,7 @@ namespace System.Collections.Concurrent
                     return _source.Current.Value;
                 }
             }
-            object IEnumerator.Current
+            object? IEnumerator.Current
             {
                 get
                 {
index 4c8162a..952207c 100644 (file)
@@ -321,10 +321,10 @@ namespace System.Collections.Concurrent
 
             //deferred allocating in MoveNext() with initial value 0, to avoid false sharing
             //we also use the fact that: (_currentChunkSize==null) means MoveNext is never called on this enumerator 
-            protected SharedInt _currentChunkSize;
+            protected SharedInt? _currentChunkSize;
 
             //deferring allocation in MoveNext() with initial value -1, to avoid false sharing
-            protected SharedInt _localOffset;
+            protected SharedInt? _localOffset;
 
             private const int CHUNK_DOUBLING_RATE = 3; // Double the chunk size every this many grabs
             private int _doublingCountdown; // Number of grabs remaining until chunk size doubles
@@ -401,7 +401,7 @@ namespace System.Collections.Concurrent
             /// <summary>
             /// Get the current element in the current partition. Property required by IEnumerator interface
             /// </summary>
-            object IEnumerator.Current
+            object? IEnumerator.Current
             {
                 get
                 {
@@ -429,6 +429,7 @@ namespace System.Collections.Concurrent
                     _currentChunkSize = new SharedInt(0);
                     _doublingCountdown = CHUNK_DOUBLING_RATE;
                 }
+                Debug.Assert(_currentChunkSize != null);
 
                 if (_localOffset.Value < _currentChunkSize.Value - 1)
                 //attempt to grab the next element from the local chunk
@@ -553,7 +554,7 @@ namespace System.Collections.Concurrent
                 private readonly IEnumerator<TSource> _sharedReader;
                 private SharedLong _sharedIndex;//initial value -1
 
-                private volatile KeyValuePair<long, TSource>[] _fillBuffer;  // intermediate buffer to reduce locking
+                private volatile KeyValuePair<long, TSource>[]? _fillBuffer;  // intermediate buffer to reduce locking
                 private volatile int _fillBufferSize;               // actual number of elements in _FillBuffer. Will start
                                                                      // at _FillBuffer.Length, and might be reduced during the last refill
                 private volatile int _fillBufferCurrentPosition;    //shared value to be accessed by Interlock.Increment only
@@ -570,7 +571,7 @@ namespace System.Collections.Concurrent
 
                 // If dynamic partitioning, then _activePartitionCount == null
                 // If static partitioning, then it keeps track of active partition count
-                private SharedInt _activePartitionCount;
+                private SharedInt? _activePartitionCount;
 
                 // records whether or not the user has requested single-chunking behavior
                 private readonly bool _useSingleChunking;
@@ -641,7 +642,7 @@ namespace System.Collections.Concurrent
 
 
                     // making a local defensive copy of the fill buffer reference, just in case it gets nulled out
-                    KeyValuePair<long, TSource>[] fillBufferLocalRef = _fillBuffer;
+                    KeyValuePair<long, TSource>[]? fillBufferLocalRef = _fillBuffer;
                     if (fillBufferLocalRef == null) return;
 
                     // first do a quick check, and give up if the current position is at the end
@@ -885,12 +886,12 @@ namespace System.Collections.Concurrent
             {
                 //---- fields ----
                 //cached local copy of the current chunk
-                private KeyValuePair<long, TSource>[] _localList; //defer allocating to avoid false sharing
+                private KeyValuePair<long, TSource>[]? _localList; //defer allocating to avoid false sharing
 
                 // the values of the following two fields are passed in from
                 // outside(already initialized) by the constructor, 
                 private readonly SharedBool _hasNoElementsLeft;
-                private readonly SharedInt _activePartitionCount;
+                private readonly SharedInt? _activePartitionCount;
                 private InternalPartitionEnumerable _enumerable;
 
                 //constructor
@@ -898,7 +899,7 @@ namespace System.Collections.Concurrent
                     IEnumerator<TSource> sharedReader,
                     SharedLong sharedIndex,
                     SharedBool hasNoElementsLeft,
-                    SharedInt activePartitionCount,
+                    SharedInt? activePartitionCount,
                     InternalPartitionEnumerable enumerable,
                     bool useSingleChunking)
                     : base(sharedReader, sharedIndex, useSingleChunking)
@@ -941,7 +942,7 @@ namespace System.Collections.Concurrent
 
 #pragma warning disable 0420 // TODO: https://github.com/dotnet/corefx/issues/35022
                     // make the actual call to the enumerable that grabs a chunk
-                    return _enumerable.GrabChunk(_localList, requestedChunkSize, ref _currentChunkSize.Value);
+                    return _enumerable.GrabChunk(_localList, requestedChunkSize, ref _currentChunkSize!.Value);
 #pragma warning restore 0420
                 }
 
@@ -969,7 +970,7 @@ namespace System.Collections.Concurrent
                             throw new InvalidOperationException(SR.PartitionerStatic_CurrentCalledBeforeMoveNext);
                         }
                         Debug.Assert(_localList != null);
-                        Debug.Assert(_localOffset.Value >= 0 && _localOffset.Value < _currentChunkSize.Value);
+                        Debug.Assert(_localOffset!.Value >= 0 && _localOffset.Value < _currentChunkSize.Value);
                         return (_localList[_localOffset.Value]);
                     }
                 }
@@ -1133,8 +1134,8 @@ namespace System.Collections.Concurrent
                         //set up local indexes.
                         //_currentChunkSize is always set to requestedChunkSize when source data had 
                         //enough elements of what we requested
-                        _currentChunkSize.Value = (int)(newSharedIndex - oldSharedIndex);
-                        _localOffset.Value = -1;
+                        _currentChunkSize!.Value = (int)(newSharedIndex - oldSharedIndex);
+                        _localOffset!.Value = -1;
                         _startIndex = (int)(oldSharedIndex + 1);
                         return true;
                     }
@@ -1242,7 +1243,7 @@ namespace System.Collections.Concurrent
                             throw new InvalidOperationException(SR.PartitionerStatic_CurrentCalledBeforeMoveNext);
                         }
 
-                        Debug.Assert(_localOffset.Value >= 0 && _localOffset.Value < _currentChunkSize.Value);
+                        Debug.Assert(_localOffset!.Value >= 0 && _localOffset.Value < _currentChunkSize.Value);
                         return new KeyValuePair<long, TSource>(_startIndex + _localOffset.Value,
                             _sharedReader[_startIndex + _localOffset.Value]);
                     }
@@ -1326,7 +1327,7 @@ namespace System.Collections.Concurrent
                             throw new InvalidOperationException(SR.PartitionerStatic_CurrentCalledBeforeMoveNext);
                         }
 
-                        Debug.Assert(_localOffset.Value >= 0 && _localOffset.Value < _currentChunkSize.Value);
+                        Debug.Assert(_localOffset!.Value >= 0 && _localOffset.Value < _currentChunkSize.Value);
                         return new KeyValuePair<long, TSource>(_startIndex + _localOffset.Value,
                             _sharedReader[_startIndex + _localOffset.Value]);
                     }
@@ -1492,7 +1493,7 @@ namespace System.Collections.Concurrent
                 }
             }
 
-            object IEnumerator.Current
+            object? IEnumerator.Current
             {
                 get
                 {
@@ -1676,7 +1677,7 @@ namespace System.Collections.Concurrent
             // Because of the lack of typeof(T).IsValueType we need two pieces of information
             // to determine this. default(T) will return a non null for Value Types, except those
             // using Nullable<>, that is why we need a second condition.
-            if (default(TSource) != null || Nullable.GetUnderlyingType(typeof(TSource)) != null)
+            if (default(TSource)! != null || Nullable.GetUnderlyingType(typeof(TSource)) != null) // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/34757
             {
                 // Marshal.SizeOf fails for value types that don't have explicit layouts. We
                 // just fall back to some arbitrary constant in that case. Is there a better way?