Annotate System.Threading.Tasks.Dataflow for nullable reference types (#33644)
authorStephen Toub <stoub@microsoft.com>
Tue, 17 Mar 2020 23:37:48 +0000 (19:37 -0400)
committerGitHub <noreply@github.com>
Tue, 17 Mar 2020 23:37:48 +0000 (19:37 -0400)
30 files changed:
src/libraries/System.Threading.Tasks.Dataflow/ref/System.Threading.Tasks.Dataflow.cs
src/libraries/System.Threading.Tasks.Dataflow/ref/System.Threading.Tasks.Dataflow.csproj
src/libraries/System.Threading.Tasks.Dataflow/src/Base/DataflowBlock.cs
src/libraries/System.Threading.Tasks.Dataflow/src/Base/DataflowMessageHeader.cs
src/libraries/System.Threading.Tasks.Dataflow/src/Base/IReceivableSourceBlock.cs
src/libraries/System.Threading.Tasks.Dataflow/src/Base/ISourceBlock.cs
src/libraries/System.Threading.Tasks.Dataflow/src/Base/ITargetBlock.cs
src/libraries/System.Threading.Tasks.Dataflow/src/Blocks/ActionBlock.cs
src/libraries/System.Threading.Tasks.Dataflow/src/Blocks/BatchBlock.cs
src/libraries/System.Threading.Tasks.Dataflow/src/Blocks/BatchedJoinBlock.cs
src/libraries/System.Threading.Tasks.Dataflow/src/Blocks/BroadcastBlock.cs
src/libraries/System.Threading.Tasks.Dataflow/src/Blocks/BufferBlock.cs
src/libraries/System.Threading.Tasks.Dataflow/src/Blocks/JoinBlock.cs
src/libraries/System.Threading.Tasks.Dataflow/src/Blocks/TransformBlock.cs
src/libraries/System.Threading.Tasks.Dataflow/src/Blocks/TransformManyBlock.cs
src/libraries/System.Threading.Tasks.Dataflow/src/Blocks/WriteOnceBlock.cs
src/libraries/System.Threading.Tasks.Dataflow/src/Internal/ActionOnDispose.cs
src/libraries/System.Threading.Tasks.Dataflow/src/Internal/Common.cs
src/libraries/System.Threading.Tasks.Dataflow/src/Internal/ConcurrentQueue.cs
src/libraries/System.Threading.Tasks.Dataflow/src/Internal/IProducerConsumerCollection.cs
src/libraries/System.Threading.Tasks.Dataflow/src/Internal/ProducerConsumerQueues.cs
src/libraries/System.Threading.Tasks.Dataflow/src/Internal/QueuedMap.cs
src/libraries/System.Threading.Tasks.Dataflow/src/Internal/ReorderingBuffer.cs
src/libraries/System.Threading.Tasks.Dataflow/src/Internal/SourceCore.cs
src/libraries/System.Threading.Tasks.Dataflow/src/Internal/SpscTargetCore.cs
src/libraries/System.Threading.Tasks.Dataflow/src/Internal/TargetCore.cs
src/libraries/System.Threading.Tasks.Dataflow/src/Internal/TargetRegistry.cs
src/libraries/System.Threading.Tasks.Dataflow/src/Internal/Threading.cs
src/libraries/System.Threading.Tasks.Dataflow/src/System.Threading.Tasks.Dataflow.csproj
src/libraries/System.Threading.Tasks.Dataflow/tests/Dataflow/DataflowBlockExtensionTests.cs

index 3fee580..b4ffb87 100644 (file)
@@ -18,7 +18,7 @@ namespace System.Threading.Tasks.Dataflow
         public void Complete() { }
         public bool Post(TInput item) { throw null; }
         void System.Threading.Tasks.Dataflow.IDataflowBlock.Fault(System.Exception exception) { }
-        System.Threading.Tasks.Dataflow.DataflowMessageStatus System.Threading.Tasks.Dataflow.ITargetBlock<TInput>.OfferMessage(System.Threading.Tasks.Dataflow.DataflowMessageHeader messageHeader, TInput messageValue, System.Threading.Tasks.Dataflow.ISourceBlock<TInput> source, bool consumeToAccept) { throw null; }
+        System.Threading.Tasks.Dataflow.DataflowMessageStatus System.Threading.Tasks.Dataflow.ITargetBlock<TInput>.OfferMessage(System.Threading.Tasks.Dataflow.DataflowMessageHeader messageHeader, TInput messageValue, System.Threading.Tasks.Dataflow.ISourceBlock<TInput>? source, bool consumeToAccept) { throw null; }
         public override string ToString() { throw null; }
     }
     public sealed partial class BatchBlock<T> : System.Threading.Tasks.Dataflow.IDataflowBlock, System.Threading.Tasks.Dataflow.IPropagatorBlock<T, T[]>, System.Threading.Tasks.Dataflow.IReceivableSourceBlock<T[]>, System.Threading.Tasks.Dataflow.ISourceBlock<T[]>, System.Threading.Tasks.Dataflow.ITargetBlock<T>
@@ -31,14 +31,15 @@ namespace System.Threading.Tasks.Dataflow
         public void Complete() { }
         public System.IDisposable LinkTo(System.Threading.Tasks.Dataflow.ITargetBlock<T[]> target, System.Threading.Tasks.Dataflow.DataflowLinkOptions linkOptions) { throw null; }
         void System.Threading.Tasks.Dataflow.IDataflowBlock.Fault(System.Exception exception) { }
+        [return: System.Diagnostics.CodeAnalysis.MaybeNull]
         T[] System.Threading.Tasks.Dataflow.ISourceBlock<T[]>.ConsumeMessage(System.Threading.Tasks.Dataflow.DataflowMessageHeader messageHeader, System.Threading.Tasks.Dataflow.ITargetBlock<T[]> target, out bool messageConsumed) { throw null; }
         void System.Threading.Tasks.Dataflow.ISourceBlock<T[]>.ReleaseReservation(System.Threading.Tasks.Dataflow.DataflowMessageHeader messageHeader, System.Threading.Tasks.Dataflow.ITargetBlock<T[]> target) { }
         bool System.Threading.Tasks.Dataflow.ISourceBlock<T[]>.ReserveMessage(System.Threading.Tasks.Dataflow.DataflowMessageHeader messageHeader, System.Threading.Tasks.Dataflow.ITargetBlock<T[]> target) { throw null; }
-        System.Threading.Tasks.Dataflow.DataflowMessageStatus System.Threading.Tasks.Dataflow.ITargetBlock<T>.OfferMessage(System.Threading.Tasks.Dataflow.DataflowMessageHeader messageHeader, T messageValue, System.Threading.Tasks.Dataflow.ISourceBlock<T> source, bool consumeToAccept) { throw null; }
+        System.Threading.Tasks.Dataflow.DataflowMessageStatus System.Threading.Tasks.Dataflow.ITargetBlock<T>.OfferMessage(System.Threading.Tasks.Dataflow.DataflowMessageHeader messageHeader, T messageValue, System.Threading.Tasks.Dataflow.ISourceBlock<T>? source, bool consumeToAccept) { throw null; }
         public override string ToString() { throw null; }
         public void TriggerBatch() { }
-        public bool TryReceive(System.Predicate<T[]> filter, out T[] item) { throw null; }
-        public bool TryReceiveAll(out System.Collections.Generic.IList<T[]> items) { throw null; }
+        public bool TryReceive(System.Predicate<T[]>? filter, [System.Diagnostics.CodeAnalysis.NotNullWhen(true)] out T[]? item) { throw null; }
+        public bool TryReceiveAll([System.Diagnostics.CodeAnalysis.NotNullWhen(true)] out System.Collections.Generic.IList<T[]>? items) { throw null; }
     }
     public sealed partial class BatchedJoinBlock<T1, T2> : System.Threading.Tasks.Dataflow.IDataflowBlock, System.Threading.Tasks.Dataflow.IReceivableSourceBlock<System.Tuple<System.Collections.Generic.IList<T1>, System.Collections.Generic.IList<T2>>>, System.Threading.Tasks.Dataflow.ISourceBlock<System.Tuple<System.Collections.Generic.IList<T1>, System.Collections.Generic.IList<T2>>>
     {
@@ -56,8 +57,8 @@ namespace System.Threading.Tasks.Dataflow
         void System.Threading.Tasks.Dataflow.ISourceBlock<System.Tuple<System.Collections.Generic.IList<T1>,System.Collections.Generic.IList<T2>>>.ReleaseReservation(System.Threading.Tasks.Dataflow.DataflowMessageHeader messageHeader, System.Threading.Tasks.Dataflow.ITargetBlock<System.Tuple<System.Collections.Generic.IList<T1>, System.Collections.Generic.IList<T2>>> target) { }
         bool System.Threading.Tasks.Dataflow.ISourceBlock<System.Tuple<System.Collections.Generic.IList<T1>,System.Collections.Generic.IList<T2>>>.ReserveMessage(System.Threading.Tasks.Dataflow.DataflowMessageHeader messageHeader, System.Threading.Tasks.Dataflow.ITargetBlock<System.Tuple<System.Collections.Generic.IList<T1>, System.Collections.Generic.IList<T2>>> target) { throw null; }
         public override string ToString() { throw null; }
-        public bool TryReceive(System.Predicate<System.Tuple<System.Collections.Generic.IList<T1>, System.Collections.Generic.IList<T2>>> filter, out System.Tuple<System.Collections.Generic.IList<T1>, System.Collections.Generic.IList<T2>> item) { throw null; }
-        public bool TryReceiveAll(out System.Collections.Generic.IList<System.Tuple<System.Collections.Generic.IList<T1>, System.Collections.Generic.IList<T2>>> items) { throw null; }
+        public bool TryReceive(System.Predicate<System.Tuple<System.Collections.Generic.IList<T1>, System.Collections.Generic.IList<T2>>>? filter, [System.Diagnostics.CodeAnalysis.NotNullWhen(true)] out System.Tuple<System.Collections.Generic.IList<T1>, System.Collections.Generic.IList<T2>>? item) { throw null; }
+        public bool TryReceiveAll([System.Diagnostics.CodeAnalysis.NotNullWhen(true)] out System.Collections.Generic.IList<System.Tuple<System.Collections.Generic.IList<T1>, System.Collections.Generic.IList<T2>>>? items) { throw null; }
     }
     public sealed partial class BatchedJoinBlock<T1, T2, T3> : System.Threading.Tasks.Dataflow.IDataflowBlock, System.Threading.Tasks.Dataflow.IReceivableSourceBlock<System.Tuple<System.Collections.Generic.IList<T1>, System.Collections.Generic.IList<T2>, System.Collections.Generic.IList<T3>>>, System.Threading.Tasks.Dataflow.ISourceBlock<System.Tuple<System.Collections.Generic.IList<T1>, System.Collections.Generic.IList<T2>, System.Collections.Generic.IList<T3>>>
     {
@@ -76,24 +77,25 @@ namespace System.Threading.Tasks.Dataflow
         void System.Threading.Tasks.Dataflow.ISourceBlock<System.Tuple<System.Collections.Generic.IList<T1>,System.Collections.Generic.IList<T2>,System.Collections.Generic.IList<T3>>>.ReleaseReservation(System.Threading.Tasks.Dataflow.DataflowMessageHeader messageHeader, System.Threading.Tasks.Dataflow.ITargetBlock<System.Tuple<System.Collections.Generic.IList<T1>, System.Collections.Generic.IList<T2>, System.Collections.Generic.IList<T3>>> target) { }
         bool System.Threading.Tasks.Dataflow.ISourceBlock<System.Tuple<System.Collections.Generic.IList<T1>,System.Collections.Generic.IList<T2>,System.Collections.Generic.IList<T3>>>.ReserveMessage(System.Threading.Tasks.Dataflow.DataflowMessageHeader messageHeader, System.Threading.Tasks.Dataflow.ITargetBlock<System.Tuple<System.Collections.Generic.IList<T1>, System.Collections.Generic.IList<T2>, System.Collections.Generic.IList<T3>>> target) { throw null; }
         public override string ToString() { throw null; }
-        public bool TryReceive(System.Predicate<System.Tuple<System.Collections.Generic.IList<T1>, System.Collections.Generic.IList<T2>, System.Collections.Generic.IList<T3>>> filter, out System.Tuple<System.Collections.Generic.IList<T1>, System.Collections.Generic.IList<T2>, System.Collections.Generic.IList<T3>> item) { throw null; }
-        public bool TryReceiveAll(out System.Collections.Generic.IList<System.Tuple<System.Collections.Generic.IList<T1>, System.Collections.Generic.IList<T2>, System.Collections.Generic.IList<T3>>> items) { throw null; }
+        public bool TryReceive(System.Predicate<System.Tuple<System.Collections.Generic.IList<T1>, System.Collections.Generic.IList<T2>, System.Collections.Generic.IList<T3>>>? filter, [System.Diagnostics.CodeAnalysis.NotNullWhen(true)] out System.Tuple<System.Collections.Generic.IList<T1>, System.Collections.Generic.IList<T2>, System.Collections.Generic.IList<T3>>? item) { throw null; }
+        public bool TryReceiveAll([System.Diagnostics.CodeAnalysis.NotNullWhen(true)] out System.Collections.Generic.IList<System.Tuple<System.Collections.Generic.IList<T1>, System.Collections.Generic.IList<T2>, System.Collections.Generic.IList<T3>>>? items) { throw null; }
     }
     public sealed partial class BroadcastBlock<T> : System.Threading.Tasks.Dataflow.IDataflowBlock, System.Threading.Tasks.Dataflow.IPropagatorBlock<T, T>, System.Threading.Tasks.Dataflow.IReceivableSourceBlock<T>, System.Threading.Tasks.Dataflow.ISourceBlock<T>, System.Threading.Tasks.Dataflow.ITargetBlock<T>
     {
-        public BroadcastBlock(System.Func<T, T> cloningFunction) { }
-        public BroadcastBlock(System.Func<T, T> cloningFunction, System.Threading.Tasks.Dataflow.DataflowBlockOptions dataflowBlockOptions) { }
+        public BroadcastBlock(System.Func<T, T>? cloningFunction) { }
+        public BroadcastBlock(System.Func<T, T>? cloningFunction, System.Threading.Tasks.Dataflow.DataflowBlockOptions dataflowBlockOptions) { }
         public System.Threading.Tasks.Task Completion { get { throw null; } }
         public void Complete() { }
         public System.IDisposable LinkTo(System.Threading.Tasks.Dataflow.ITargetBlock<T> target, System.Threading.Tasks.Dataflow.DataflowLinkOptions linkOptions) { throw null; }
         void System.Threading.Tasks.Dataflow.IDataflowBlock.Fault(System.Exception exception) { }
-        bool System.Threading.Tasks.Dataflow.IReceivableSourceBlock<T>.TryReceiveAll(out System.Collections.Generic.IList<T> items) { throw null; }
+        bool System.Threading.Tasks.Dataflow.IReceivableSourceBlock<T>.TryReceiveAll([System.Diagnostics.CodeAnalysis.NotNullWhen(true)] out System.Collections.Generic.IList<T>? items) { throw null; }
+        [return: System.Diagnostics.CodeAnalysis.MaybeNull]
         T System.Threading.Tasks.Dataflow.ISourceBlock<T>.ConsumeMessage(System.Threading.Tasks.Dataflow.DataflowMessageHeader messageHeader, System.Threading.Tasks.Dataflow.ITargetBlock<T> target, out bool messageConsumed) { throw null; }
         void System.Threading.Tasks.Dataflow.ISourceBlock<T>.ReleaseReservation(System.Threading.Tasks.Dataflow.DataflowMessageHeader messageHeader, System.Threading.Tasks.Dataflow.ITargetBlock<T> target) { }
         bool System.Threading.Tasks.Dataflow.ISourceBlock<T>.ReserveMessage(System.Threading.Tasks.Dataflow.DataflowMessageHeader messageHeader, System.Threading.Tasks.Dataflow.ITargetBlock<T> target) { throw null; }
-        System.Threading.Tasks.Dataflow.DataflowMessageStatus System.Threading.Tasks.Dataflow.ITargetBlock<T>.OfferMessage(System.Threading.Tasks.Dataflow.DataflowMessageHeader messageHeader, T messageValue, System.Threading.Tasks.Dataflow.ISourceBlock<T> source, bool consumeToAccept) { throw null; }
+        System.Threading.Tasks.Dataflow.DataflowMessageStatus System.Threading.Tasks.Dataflow.ITargetBlock<T>.OfferMessage(System.Threading.Tasks.Dataflow.DataflowMessageHeader messageHeader, T messageValue, System.Threading.Tasks.Dataflow.ISourceBlock<T>? source, bool consumeToAccept) { throw null; }
         public override string ToString() { throw null; }
-        public bool TryReceive(System.Predicate<T> filter, out T item) { throw null; }
+        public bool TryReceive(System.Predicate<T>? filter, [System.Diagnostics.CodeAnalysis.MaybeNullWhen(false)] out T item) { throw null; }
     }
     public sealed partial class BufferBlock<T> : System.Threading.Tasks.Dataflow.IDataflowBlock, System.Threading.Tasks.Dataflow.IPropagatorBlock<T, T>, System.Threading.Tasks.Dataflow.IReceivableSourceBlock<T>, System.Threading.Tasks.Dataflow.ISourceBlock<T>, System.Threading.Tasks.Dataflow.ITargetBlock<T>
     {
@@ -104,13 +106,14 @@ namespace System.Threading.Tasks.Dataflow
         public void Complete() { }
         public System.IDisposable LinkTo(System.Threading.Tasks.Dataflow.ITargetBlock<T> target, System.Threading.Tasks.Dataflow.DataflowLinkOptions linkOptions) { throw null; }
         void System.Threading.Tasks.Dataflow.IDataflowBlock.Fault(System.Exception exception) { }
+        [return: System.Diagnostics.CodeAnalysis.MaybeNull]
         T System.Threading.Tasks.Dataflow.ISourceBlock<T>.ConsumeMessage(System.Threading.Tasks.Dataflow.DataflowMessageHeader messageHeader, System.Threading.Tasks.Dataflow.ITargetBlock<T> target, out bool messageConsumed) { throw null; }
         void System.Threading.Tasks.Dataflow.ISourceBlock<T>.ReleaseReservation(System.Threading.Tasks.Dataflow.DataflowMessageHeader messageHeader, System.Threading.Tasks.Dataflow.ITargetBlock<T> target) { }
         bool System.Threading.Tasks.Dataflow.ISourceBlock<T>.ReserveMessage(System.Threading.Tasks.Dataflow.DataflowMessageHeader messageHeader, System.Threading.Tasks.Dataflow.ITargetBlock<T> target) { throw null; }
-        System.Threading.Tasks.Dataflow.DataflowMessageStatus System.Threading.Tasks.Dataflow.ITargetBlock<T>.OfferMessage(System.Threading.Tasks.Dataflow.DataflowMessageHeader messageHeader, T messageValue, System.Threading.Tasks.Dataflow.ISourceBlock<T> source, bool consumeToAccept) { throw null; }
+        System.Threading.Tasks.Dataflow.DataflowMessageStatus System.Threading.Tasks.Dataflow.ITargetBlock<T>.OfferMessage(System.Threading.Tasks.Dataflow.DataflowMessageHeader messageHeader, T messageValue, System.Threading.Tasks.Dataflow.ISourceBlock<T>? source, bool consumeToAccept) { throw null; }
         public override string ToString() { throw null; }
-        public bool TryReceive(System.Predicate<T> filter, out T item) { throw null; }
-        public bool TryReceiveAll(out System.Collections.Generic.IList<T> items) { throw null; }
+        public bool TryReceive(System.Predicate<T>? filter, [System.Diagnostics.CodeAnalysis.MaybeNullWhen(false)] out T item) { throw null; }
+        public bool TryReceiveAll([System.Diagnostics.CodeAnalysis.NotNullWhen(true)] out System.Collections.Generic.IList<T>? items) { throw null; }
     }
     public static partial class DataflowBlock
     {
@@ -138,7 +141,7 @@ namespace System.Threading.Tasks.Dataflow
         public static TOutput Receive<TOutput>(this System.Threading.Tasks.Dataflow.ISourceBlock<TOutput> source, System.TimeSpan timeout, System.Threading.CancellationToken cancellationToken) { throw null; }
         public static System.Threading.Tasks.Task<bool> SendAsync<TInput>(this System.Threading.Tasks.Dataflow.ITargetBlock<TInput> target, TInput item) { throw null; }
         public static System.Threading.Tasks.Task<bool> SendAsync<TInput>(this System.Threading.Tasks.Dataflow.ITargetBlock<TInput> target, TInput item, System.Threading.CancellationToken cancellationToken) { throw null; }
-        public static bool TryReceive<TOutput>(this System.Threading.Tasks.Dataflow.IReceivableSourceBlock<TOutput> source, out TOutput item) { throw null; }
+        public static bool TryReceive<TOutput>(this System.Threading.Tasks.Dataflow.IReceivableSourceBlock<TOutput> source, [System.Diagnostics.CodeAnalysis.MaybeNullWhen(false)] out TOutput item) { throw null; }
     }
     public partial class DataflowBlockOptions
     {
@@ -164,7 +167,7 @@ namespace System.Threading.Tasks.Dataflow
         public DataflowMessageHeader(long id) { throw null; }
         public long Id { get { throw null; } }
         public bool IsValid { get { throw null; } }
-        public override bool Equals(object obj) { throw null; }
+        public override bool Equals(object? obj) { throw null; }
         public bool Equals(System.Threading.Tasks.Dataflow.DataflowMessageHeader other) { throw null; }
         public override int GetHashCode() { throw null; }
         public static bool operator ==(System.Threading.Tasks.Dataflow.DataflowMessageHeader left, System.Threading.Tasks.Dataflow.DataflowMessageHeader right) { throw null; }
@@ -201,11 +204,12 @@ namespace System.Threading.Tasks.Dataflow
     }
     public partial interface IReceivableSourceBlock<TOutput> : System.Threading.Tasks.Dataflow.IDataflowBlock, System.Threading.Tasks.Dataflow.ISourceBlock<TOutput>
     {
-        bool TryReceive(System.Predicate<TOutput> filter, out TOutput item);
-        bool TryReceiveAll(out System.Collections.Generic.IList<TOutput> items);
+        bool TryReceive(System.Predicate<TOutput>? filter, [System.Diagnostics.CodeAnalysis.MaybeNullWhen(false)] out TOutput item);
+        bool TryReceiveAll([System.Diagnostics.CodeAnalysis.NotNullWhen(true)] out System.Collections.Generic.IList<TOutput>? items);
     }
     public partial interface ISourceBlock<out TOutput> : System.Threading.Tasks.Dataflow.IDataflowBlock
     {
+        [return: System.Diagnostics.CodeAnalysis.MaybeNull]
         TOutput ConsumeMessage(System.Threading.Tasks.Dataflow.DataflowMessageHeader messageHeader, System.Threading.Tasks.Dataflow.ITargetBlock<TOutput> target, out bool messageConsumed);
         System.IDisposable LinkTo(System.Threading.Tasks.Dataflow.ITargetBlock<TOutput> target, System.Threading.Tasks.Dataflow.DataflowLinkOptions linkOptions);
         void ReleaseReservation(System.Threading.Tasks.Dataflow.DataflowMessageHeader messageHeader, System.Threading.Tasks.Dataflow.ITargetBlock<TOutput> target);
@@ -213,7 +217,7 @@ namespace System.Threading.Tasks.Dataflow
     }
     public partial interface ITargetBlock<in TInput> : System.Threading.Tasks.Dataflow.IDataflowBlock
     {
-        System.Threading.Tasks.Dataflow.DataflowMessageStatus OfferMessage(System.Threading.Tasks.Dataflow.DataflowMessageHeader messageHeader, TInput messageValue, System.Threading.Tasks.Dataflow.ISourceBlock<TInput> source, bool consumeToAccept);
+        System.Threading.Tasks.Dataflow.DataflowMessageStatus OfferMessage(System.Threading.Tasks.Dataflow.DataflowMessageHeader messageHeader, TInput messageValue, System.Threading.Tasks.Dataflow.ISourceBlock<TInput>? source, bool consumeToAccept);
     }
     public sealed partial class JoinBlock<T1, T2> : System.Threading.Tasks.Dataflow.IDataflowBlock, System.Threading.Tasks.Dataflow.IReceivableSourceBlock<System.Tuple<T1, T2>>, System.Threading.Tasks.Dataflow.ISourceBlock<System.Tuple<T1, T2>>
     {
@@ -226,12 +230,12 @@ namespace System.Threading.Tasks.Dataflow
         public void Complete() { }
         public System.IDisposable LinkTo(System.Threading.Tasks.Dataflow.ITargetBlock<System.Tuple<T1, T2>> target, System.Threading.Tasks.Dataflow.DataflowLinkOptions linkOptions) { throw null; }
         void System.Threading.Tasks.Dataflow.IDataflowBlock.Fault(System.Exception exception) { }
-        System.Tuple<T1, T2> System.Threading.Tasks.Dataflow.ISourceBlock<System.Tuple<T1,T2>>.ConsumeMessage(System.Threading.Tasks.Dataflow.DataflowMessageHeader messageHeader, System.Threading.Tasks.Dataflow.ITargetBlock<System.Tuple<T1, T2>> target, out bool messageConsumed) { throw null; }
+        System.Tuple<T1, T2>? System.Threading.Tasks.Dataflow.ISourceBlock<System.Tuple<T1,T2>>.ConsumeMessage(System.Threading.Tasks.Dataflow.DataflowMessageHeader messageHeader, System.Threading.Tasks.Dataflow.ITargetBlock<System.Tuple<T1, T2>> target, out bool messageConsumed) { throw null; }
         void System.Threading.Tasks.Dataflow.ISourceBlock<System.Tuple<T1,T2>>.ReleaseReservation(System.Threading.Tasks.Dataflow.DataflowMessageHeader messageHeader, System.Threading.Tasks.Dataflow.ITargetBlock<System.Tuple<T1, T2>> target) { }
         bool System.Threading.Tasks.Dataflow.ISourceBlock<System.Tuple<T1,T2>>.ReserveMessage(System.Threading.Tasks.Dataflow.DataflowMessageHeader messageHeader, System.Threading.Tasks.Dataflow.ITargetBlock<System.Tuple<T1, T2>> target) { throw null; }
         public override string ToString() { throw null; }
-        public bool TryReceive(System.Predicate<System.Tuple<T1, T2>> filter, out System.Tuple<T1, T2> item) { throw null; }
-        public bool TryReceiveAll(out System.Collections.Generic.IList<System.Tuple<T1, T2>> items) { throw null; }
+        public bool TryReceive(System.Predicate<System.Tuple<T1, T2>>? filter, [System.Diagnostics.CodeAnalysis.NotNullWhen(true)] out System.Tuple<T1, T2>? item) { throw null; }
+        public bool TryReceiveAll([System.Diagnostics.CodeAnalysis.NotNullWhen(true)] out System.Collections.Generic.IList<System.Tuple<T1, T2>>? items) { throw null; }
     }
     public sealed partial class JoinBlock<T1, T2, T3> : System.Threading.Tasks.Dataflow.IDataflowBlock, System.Threading.Tasks.Dataflow.IReceivableSourceBlock<System.Tuple<T1, T2, T3>>, System.Threading.Tasks.Dataflow.ISourceBlock<System.Tuple<T1, T2, T3>>
     {
@@ -245,12 +249,12 @@ namespace System.Threading.Tasks.Dataflow
         public void Complete() { }
         public System.IDisposable LinkTo(System.Threading.Tasks.Dataflow.ITargetBlock<System.Tuple<T1, T2, T3>> target, System.Threading.Tasks.Dataflow.DataflowLinkOptions linkOptions) { throw null; }
         void System.Threading.Tasks.Dataflow.IDataflowBlock.Fault(System.Exception exception) { }
-        System.Tuple<T1, T2, T3> System.Threading.Tasks.Dataflow.ISourceBlock<System.Tuple<T1,T2,T3>>.ConsumeMessage(System.Threading.Tasks.Dataflow.DataflowMessageHeader messageHeader, System.Threading.Tasks.Dataflow.ITargetBlock<System.Tuple<T1, T2, T3>> target, out bool messageConsumed) { throw null; }
+        System.Tuple<T1, T2, T3>? System.Threading.Tasks.Dataflow.ISourceBlock<System.Tuple<T1,T2,T3>>.ConsumeMessage(System.Threading.Tasks.Dataflow.DataflowMessageHeader messageHeader, System.Threading.Tasks.Dataflow.ITargetBlock<System.Tuple<T1, T2, T3>> target, out bool messageConsumed) { throw null; }
         void System.Threading.Tasks.Dataflow.ISourceBlock<System.Tuple<T1,T2,T3>>.ReleaseReservation(System.Threading.Tasks.Dataflow.DataflowMessageHeader messageHeader, System.Threading.Tasks.Dataflow.ITargetBlock<System.Tuple<T1, T2, T3>> target) { }
         bool System.Threading.Tasks.Dataflow.ISourceBlock<System.Tuple<T1,T2,T3>>.ReserveMessage(System.Threading.Tasks.Dataflow.DataflowMessageHeader messageHeader, System.Threading.Tasks.Dataflow.ITargetBlock<System.Tuple<T1, T2, T3>> target) { throw null; }
         public override string ToString() { throw null; }
-        public bool TryReceive(System.Predicate<System.Tuple<T1, T2, T3>> filter, out System.Tuple<T1, T2, T3> item) { throw null; }
-        public bool TryReceiveAll(out System.Collections.Generic.IList<System.Tuple<T1, T2, T3>> items) { throw null; }
+        public bool TryReceive(System.Predicate<System.Tuple<T1, T2, T3>>? filter, [System.Diagnostics.CodeAnalysis.NotNullWhen(true)] out System.Tuple<T1, T2, T3>? item) { throw null; }
+        public bool TryReceiveAll([System.Diagnostics.CodeAnalysis.NotNullWhen(true)] out System.Collections.Generic.IList<System.Tuple<T1, T2, T3>>? items) { throw null; }
     }
     public sealed partial class TransformBlock<TInput, TOutput> : System.Threading.Tasks.Dataflow.IDataflowBlock, System.Threading.Tasks.Dataflow.IPropagatorBlock<TInput, TOutput>, System.Threading.Tasks.Dataflow.IReceivableSourceBlock<TOutput>, System.Threading.Tasks.Dataflow.ISourceBlock<TOutput>, System.Threading.Tasks.Dataflow.ITargetBlock<TInput>
     {
@@ -264,13 +268,14 @@ namespace System.Threading.Tasks.Dataflow
         public void Complete() { }
         public System.IDisposable LinkTo(System.Threading.Tasks.Dataflow.ITargetBlock<TOutput> target, System.Threading.Tasks.Dataflow.DataflowLinkOptions linkOptions) { throw null; }
         void System.Threading.Tasks.Dataflow.IDataflowBlock.Fault(System.Exception exception) { }
+        [return: System.Diagnostics.CodeAnalysis.MaybeNull]
         TOutput System.Threading.Tasks.Dataflow.ISourceBlock<TOutput>.ConsumeMessage(System.Threading.Tasks.Dataflow.DataflowMessageHeader messageHeader, System.Threading.Tasks.Dataflow.ITargetBlock<TOutput> target, out bool messageConsumed) { throw null; }
         void System.Threading.Tasks.Dataflow.ISourceBlock<TOutput>.ReleaseReservation(System.Threading.Tasks.Dataflow.DataflowMessageHeader messageHeader, System.Threading.Tasks.Dataflow.ITargetBlock<TOutput> target) { }
         bool System.Threading.Tasks.Dataflow.ISourceBlock<TOutput>.ReserveMessage(System.Threading.Tasks.Dataflow.DataflowMessageHeader messageHeader, System.Threading.Tasks.Dataflow.ITargetBlock<TOutput> target) { throw null; }
-        System.Threading.Tasks.Dataflow.DataflowMessageStatus System.Threading.Tasks.Dataflow.ITargetBlock<TInput>.OfferMessage(System.Threading.Tasks.Dataflow.DataflowMessageHeader messageHeader, TInput messageValue, System.Threading.Tasks.Dataflow.ISourceBlock<TInput> source, bool consumeToAccept) { throw null; }
+        System.Threading.Tasks.Dataflow.DataflowMessageStatus System.Threading.Tasks.Dataflow.ITargetBlock<TInput>.OfferMessage(System.Threading.Tasks.Dataflow.DataflowMessageHeader messageHeader, TInput messageValue, System.Threading.Tasks.Dataflow.ISourceBlock<TInput>? source, bool consumeToAccept) { throw null; }
         public override string ToString() { throw null; }
-        public bool TryReceive(System.Predicate<TOutput> filter, out TOutput item) { throw null; }
-        public bool TryReceiveAll(out System.Collections.Generic.IList<TOutput> items) { throw null; }
+        public bool TryReceive(System.Predicate<TOutput>? filter, [System.Diagnostics.CodeAnalysis.MaybeNullWhen(false)] out TOutput item) { throw null; }
+        public bool TryReceiveAll([System.Diagnostics.CodeAnalysis.NotNullWhen(true)] out System.Collections.Generic.IList<TOutput>? items) { throw null; }
     }
     public sealed partial class TransformManyBlock<TInput, TOutput> : System.Threading.Tasks.Dataflow.IDataflowBlock, System.Threading.Tasks.Dataflow.IPropagatorBlock<TInput, TOutput>, System.Threading.Tasks.Dataflow.IReceivableSourceBlock<TOutput>, System.Threading.Tasks.Dataflow.ISourceBlock<TOutput>, System.Threading.Tasks.Dataflow.ITargetBlock<TInput>
     {
@@ -284,28 +289,30 @@ namespace System.Threading.Tasks.Dataflow
         public void Complete() { }
         public System.IDisposable LinkTo(System.Threading.Tasks.Dataflow.ITargetBlock<TOutput> target, System.Threading.Tasks.Dataflow.DataflowLinkOptions linkOptions) { throw null; }
         void System.Threading.Tasks.Dataflow.IDataflowBlock.Fault(System.Exception exception) { }
+        [return: System.Diagnostics.CodeAnalysis.MaybeNull]
         TOutput System.Threading.Tasks.Dataflow.ISourceBlock<TOutput>.ConsumeMessage(System.Threading.Tasks.Dataflow.DataflowMessageHeader messageHeader, System.Threading.Tasks.Dataflow.ITargetBlock<TOutput> target, out bool messageConsumed) { throw null; }
         void System.Threading.Tasks.Dataflow.ISourceBlock<TOutput>.ReleaseReservation(System.Threading.Tasks.Dataflow.DataflowMessageHeader messageHeader, System.Threading.Tasks.Dataflow.ITargetBlock<TOutput> target) { }
         bool System.Threading.Tasks.Dataflow.ISourceBlock<TOutput>.ReserveMessage(System.Threading.Tasks.Dataflow.DataflowMessageHeader messageHeader, System.Threading.Tasks.Dataflow.ITargetBlock<TOutput> target) { throw null; }
-        System.Threading.Tasks.Dataflow.DataflowMessageStatus System.Threading.Tasks.Dataflow.ITargetBlock<TInput>.OfferMessage(System.Threading.Tasks.Dataflow.DataflowMessageHeader messageHeader, TInput messageValue, System.Threading.Tasks.Dataflow.ISourceBlock<TInput> source, bool consumeToAccept) { throw null; }
+        System.Threading.Tasks.Dataflow.DataflowMessageStatus System.Threading.Tasks.Dataflow.ITargetBlock<TInput>.OfferMessage(System.Threading.Tasks.Dataflow.DataflowMessageHeader messageHeader, TInput messageValue, System.Threading.Tasks.Dataflow.ISourceBlock<TInput>? source, bool consumeToAccept) { throw null; }
         public override string ToString() { throw null; }
-        public bool TryReceive(System.Predicate<TOutput> filter, out TOutput item) { throw null; }
-        public bool TryReceiveAll(out System.Collections.Generic.IList<TOutput> items) { throw null; }
+        public bool TryReceive(System.Predicate<TOutput>? filter, [System.Diagnostics.CodeAnalysis.MaybeNullWhen(false)] out TOutput item) { throw null; }
+        public bool TryReceiveAll([System.Diagnostics.CodeAnalysis.NotNullWhen(true)] out System.Collections.Generic.IList<TOutput>? items) { throw null; }
     }
     public sealed partial class WriteOnceBlock<T> : System.Threading.Tasks.Dataflow.IDataflowBlock, System.Threading.Tasks.Dataflow.IPropagatorBlock<T, T>, System.Threading.Tasks.Dataflow.IReceivableSourceBlock<T>, System.Threading.Tasks.Dataflow.ISourceBlock<T>, System.Threading.Tasks.Dataflow.ITargetBlock<T>
     {
-        public WriteOnceBlock(System.Func<T, T> cloningFunction) { }
-        public WriteOnceBlock(System.Func<T, T> cloningFunction, System.Threading.Tasks.Dataflow.DataflowBlockOptions dataflowBlockOptions) { }
+        public WriteOnceBlock(System.Func<T, T>? cloningFunction) { }
+        public WriteOnceBlock(System.Func<T, T>? cloningFunction, System.Threading.Tasks.Dataflow.DataflowBlockOptions dataflowBlockOptions) { }
         public System.Threading.Tasks.Task Completion { get { throw null; } }
         public void Complete() { }
         public System.IDisposable LinkTo(System.Threading.Tasks.Dataflow.ITargetBlock<T> target, System.Threading.Tasks.Dataflow.DataflowLinkOptions linkOptions) { throw null; }
         void System.Threading.Tasks.Dataflow.IDataflowBlock.Fault(System.Exception exception) { }
-        bool System.Threading.Tasks.Dataflow.IReceivableSourceBlock<T>.TryReceiveAll(out System.Collections.Generic.IList<T> items) { throw null; }
+        bool System.Threading.Tasks.Dataflow.IReceivableSourceBlock<T>.TryReceiveAll([System.Diagnostics.CodeAnalysis.NotNullWhen(true)] out System.Collections.Generic.IList<T>? items) { throw null; }
+        [return: System.Diagnostics.CodeAnalysis.MaybeNull]
         T System.Threading.Tasks.Dataflow.ISourceBlock<T>.ConsumeMessage(System.Threading.Tasks.Dataflow.DataflowMessageHeader messageHeader, System.Threading.Tasks.Dataflow.ITargetBlock<T> target, out bool messageConsumed) { throw null; }
         void System.Threading.Tasks.Dataflow.ISourceBlock<T>.ReleaseReservation(System.Threading.Tasks.Dataflow.DataflowMessageHeader messageHeader, System.Threading.Tasks.Dataflow.ITargetBlock<T> target) { }
         bool System.Threading.Tasks.Dataflow.ISourceBlock<T>.ReserveMessage(System.Threading.Tasks.Dataflow.DataflowMessageHeader messageHeader, System.Threading.Tasks.Dataflow.ITargetBlock<T> target) { throw null; }
-        System.Threading.Tasks.Dataflow.DataflowMessageStatus System.Threading.Tasks.Dataflow.ITargetBlock<T>.OfferMessage(System.Threading.Tasks.Dataflow.DataflowMessageHeader messageHeader, T messageValue, System.Threading.Tasks.Dataflow.ISourceBlock<T> source, bool consumeToAccept) { throw null; }
+        System.Threading.Tasks.Dataflow.DataflowMessageStatus System.Threading.Tasks.Dataflow.ITargetBlock<T>.OfferMessage(System.Threading.Tasks.Dataflow.DataflowMessageHeader messageHeader, T messageValue, System.Threading.Tasks.Dataflow.ISourceBlock<T>? source, bool consumeToAccept) { throw null; }
         public override string ToString() { throw null; }
-        public bool TryReceive(System.Predicate<T> filter, out T item) { throw null; }
+        public bool TryReceive(System.Predicate<T>? filter, [System.Diagnostics.CodeAnalysis.MaybeNullWhen(false)] out T item) { throw null; }
     }
 }
index 9a09a94..915b6a2 100644 (file)
@@ -1,6 +1,7 @@
 <Project Sdk="Microsoft.NET.Sdk">
   <PropertyGroup>
     <TargetFrameworks>netstandard2.0;netstandard1.0;netstandard1.1</TargetFrameworks>
+    <Nullable>enable</Nullable>
   </PropertyGroup>
   <ItemGroup>
     <Compile Include="System.Threading.Tasks.Dataflow.cs" />
index 73dd608..1753d40 100644 (file)
@@ -133,7 +133,9 @@ namespace System.Threading.Tasks.Dataflow
             }
 
             /// <include file='XmlDocs/CommonXmlDocComments.xml' path='CommonXmlDocComments/Targets/Member[@name="OfferMessage"]/*' />
+#pragma warning disable 8617
             DataflowMessageStatus ITargetBlock<T>.OfferMessage(DataflowMessageHeader messageHeader, T messageValue, ISourceBlock<T> source, bool consumeToAccept)
+#pragma warning restore 8617
             {
                 // Validate arguments.  Some targets may have a null source, but FilteredLinkPropagator
                 // is an internal target that should only ever have source non-null.
@@ -153,6 +155,7 @@ namespace System.Threading.Tasks.Dataflow
             }
 
             /// <include file='XmlDocs/CommonXmlDocComments.xml' path='CommonXmlDocComments/Sources/Member[@name="ConsumeMessage"]/*' />
+            [return: MaybeNull]
             T ISourceBlock<T>.ConsumeMessage(DataflowMessageHeader messageHeader, ITargetBlock<T> target, out bool messageConsumed)
             {
                 // This message should have only made it to the target if it passes the filter, so we shouldn't need to check again.
@@ -442,7 +445,7 @@ namespace System.Threading.Tasks.Dataflow
             {
                 RunCompletionAction(state =>
                 {
-                    try { ((SendAsyncSource<TOutput>)state).TrySetResult(true); }
+                    try { ((SendAsyncSource<TOutput>)state!).TrySetResult(true); }
                     catch (ObjectDisposedException) { }
                 }, this, runAsync);
             }
@@ -455,7 +458,7 @@ namespace System.Threading.Tasks.Dataflow
                 {
                     // The try/catch for ObjectDisposedException handles the case where the
                     // user disposes of the returned task before we're done with it.
-                    try { ((SendAsyncSource<TOutput>)state).TrySetResult(false); }
+                    try { ((SendAsyncSource<TOutput>)state!).TrySetResult(false); }
                     catch (ObjectDisposedException) { }
                 }, this, runAsync);
             }
@@ -467,7 +470,7 @@ namespace System.Threading.Tasks.Dataflow
             {
                 RunCompletionAction(state =>
                 {
-                    var tuple = (Tuple<SendAsyncSource<TOutput>, Exception>)state;
+                    var tuple = (Tuple<SendAsyncSource<TOutput>, Exception>)state!;
                     try { tuple.Item1.TrySetException(tuple.Item2); }
                     catch (ObjectDisposedException) { }
                 }, Tuple.Create<SendAsyncSource<TOutput>, Exception>(this, exception), runAsync);
@@ -479,7 +482,7 @@ namespace System.Threading.Tasks.Dataflow
             {
                 RunCompletionAction(state =>
                 {
-                    try { ((SendAsyncSource<TOutput>)state).TrySetCanceled(); }
+                    try { ((SendAsyncSource<TOutput>)state!).TrySetCanceled(); }
                     catch (ObjectDisposedException) { }
                 }, this, runAsync);
             }
@@ -493,7 +496,7 @@ namespace System.Threading.Tasks.Dataflow
             /// the target is calling to ConsumeMessage.  We don't want to block the target indefinitely
             /// with any synchronous continuations off of the returned send async task.
             /// </remarks>
-            private void RunCompletionAction(Action<object> completionAction, object completionActionState, bool runAsync)
+            private void RunCompletionAction(Action<object?> completionAction, object completionActionState, bool runAsync)
             {
                 Debug.Assert(completionAction != null, "Completion action to run is required.");
 
@@ -527,21 +530,21 @@ namespace System.Threading.Tasks.Dataflow
             private void OfferToTargetAsync()
             {
                 System.Threading.Tasks.Task.Factory.StartNew(
-                    state => ((SendAsyncSource<TOutput>)state).OfferToTarget(), this,
+                    state => ((SendAsyncSource<TOutput>)state!).OfferToTarget(), this,
                     CancellationToken.None, Common.GetCreationOptionsForTask(), TaskScheduler.Default);
             }
 
             /// <summary>Cached delegate used to cancel a send in response to a cancellation request.</summary>
-            private static readonly Action<object> _cancellationCallback = CancellationHandler;
+            private static readonly Action<object?> _cancellationCallback = CancellationHandler;
 
             /// <summary>Attempts to cancel the source passed as state in response to a cancellation request.</summary>
             /// <param name="state">
             /// A weak reference to the SendAsyncSource.  A weak reference is used to prevent the source
             /// from being rooted in a long-lived token.
             /// </param>
-            private static void CancellationHandler(object state)
+            private static void CancellationHandler(object? state)
             {
-                SendAsyncSource<TOutput> source = Common.UnwrapWeakReference<SendAsyncSource<TOutput>>(state);
+                SendAsyncSource<TOutput>? source = Common.UnwrapWeakReference<SendAsyncSource<TOutput>>(state!);
                 if (source != null)
                 {
                     Debug.Assert(source._cancellationState != CANCELLATION_STATE_NONE,
@@ -619,6 +622,7 @@ namespace System.Threading.Tasks.Dataflow
             }
 
             /// <summary>Called by the target to consume the buffered message.</summary>
+            [return: MaybeNull]
             TOutput ISourceBlock<TOutput>.ConsumeMessage(DataflowMessageHeader messageHeader, ITargetBlock<TOutput> target, out bool messageConsumed)
             {
                 // Validate arguments
@@ -770,7 +774,7 @@ namespace System.Threading.Tasks.Dataflow
         /// This method does not wait until the source has an item to provide.
         /// It will return whether or not an element was available.
         /// </remarks>
-        public static bool TryReceive<TOutput>(this IReceivableSourceBlock<TOutput> source, out TOutput item)
+        public static bool TryReceive<TOutput>(this IReceivableSourceBlock<TOutput> source, [MaybeNullWhen(false)] out TOutput item)
         {
             if (source == null) throw new ArgumentNullException(nameof(source));
 
@@ -1034,7 +1038,7 @@ namespace System.Threading.Tasks.Dataflow
         }
 
         /// <summary>Cancels a CancellationTokenSource passed as the object state argument.</summary>
-        private static readonly Action<object> _cancelCts = state => ((CancellationTokenSource)state).Cancel();
+        private static readonly Action<object?> _cancelCts = state => ((CancellationTokenSource)state!).Cancel();
 
         /// <summary>Receives an item from the source by linking a temporary target from it.</summary>
         /// <typeparam name="TOutput">Specifies the type of data contained in the source.</typeparam>
@@ -1113,20 +1117,21 @@ namespace System.Threading.Tasks.Dataflow
             /// <remarks>The C# compiler will not cache this delegate by default due to it being a generic method on a non-generic class.</remarks>
             internal static readonly TimerCallback CachedLinkingTimerCallback = state =>
             {
-                var receiveTarget = (ReceiveTarget<T>)state;
+                var receiveTarget = (ReceiveTarget<T>)state!;
                 receiveTarget.TryCleanupAndComplete(ReceiveCoreByLinkingCleanupReason.Timer);
             };
 
             /// <summary>Cached delegate used in ReceiveCoreByLinking on the cancellation token. Passed the ReceiveTarget as the state argument.</summary>
             /// <remarks>The C# compiler will not cache this delegate by default due to it being a generic method on a non-generic class.</remarks>
-            internal static readonly Action<object> CachedLinkingCancellationCallback = state =>
+            internal static readonly Action<object?> CachedLinkingCancellationCallback = state =>
             {
-                var receiveTarget = (ReceiveTarget<T>)state;
+                var receiveTarget = (ReceiveTarget<T>)state!;
                 receiveTarget.TryCleanupAndComplete(ReceiveCoreByLinkingCleanupReason.Cancellation);
             };
 
             /// <summary>The received value if we accepted a value from the source.</summary>
-            private T _receivedValue;
+            [AllowNull, MaybeNull]
+            private T _receivedValue = default!;
 
             /// <summary>The cancellation token source representing both external and internal cancellation.</summary>
             internal readonly CancellationTokenSource _cts = new CancellationTokenSource();
@@ -1137,11 +1142,11 @@ namespace System.Threading.Tasks.Dataflow
             /// <summary>The registration on the external token that cancels the internal token.</summary>
             internal CancellationTokenRegistration _regFromExternalCancellationToken;
             /// <summary>The timer that fires when the timeout has been exceeded.</summary>
-            internal Timer _timer;
+            internal Timer? _timer;
             /// <summary>The unlinker from removing this target from the source from which we're receiving.</summary>
-            internal IDisposable _unlink;
+            internal IDisposable? _unlink;
             /// <summary>The received exception if an error occurred.</summary>
-            internal Exception _receivedException;
+            internal Exception? _receivedException;
 
             /// <summary>Gets the sync obj used to synchronize all activity on this target.</summary>
             internal object IncomingLock { get { return _cts; } }
@@ -1150,7 +1155,7 @@ namespace System.Threading.Tasks.Dataflow
             internal ReceiveTarget() { }
 
             /// <summary>Offers a message to be used to complete the TaskCompletionSource.</summary>
-            DataflowMessageStatus ITargetBlock<T>.OfferMessage(DataflowMessageHeader messageHeader, T messageValue, ISourceBlock<T> source, bool consumeToAccept)
+            DataflowMessageStatus ITargetBlock<T>.OfferMessage(DataflowMessageHeader messageHeader, T messageValue, ISourceBlock<T>? source, bool consumeToAccept)
             {
                 // Validate arguments
                 if (!messageHeader.IsValid) throw new ArgumentException(SR.Argument_InvalidMessageHeader, nameof(messageHeader));
@@ -1172,7 +1177,7 @@ namespace System.Threading.Tasks.Dataflow
                     {
                         // Accept the message if possible and complete this task with the message's value.
                         bool consumed = true;
-                        T acceptedValue = consumeToAccept ? source.ConsumeMessage(messageHeader, this, out consumed) : messageValue;
+                        T acceptedValue = consumeToAccept ? source!.ConsumeMessage(messageHeader, this, out consumed) : messageValue;
                         if (consumed)
                         {
                             status = DataflowMessageStatus.Accepted;
@@ -1238,10 +1243,10 @@ namespace System.Threading.Tasks.Dataflow
                 // completed, this is unnecessary, as the source should have already
                 // emptied out its target registry, or at least be in the process of doing so.
                 // We are racing with the linking code - only one can dispose of the unlinker.
-                IDisposable unlink = _unlink;
+                IDisposable? unlink = _unlink;
                 if (reason != ReceiveCoreByLinkingCleanupReason.SourceCompletion && unlink != null)
                 {
-                    IDisposable disposableUnlink = Interlocked.CompareExchange(ref _unlink, null, unlink);
+                    IDisposable? disposableUnlink = Interlocked.CompareExchange(ref _unlink, null, unlink);
                     if (disposableUnlink != null)
                     {
                         // If an error occurs, fault the target and override the reason to
@@ -1297,8 +1302,8 @@ namespace System.Threading.Tasks.Dataflow
                         System.Threading.Tasks.Task.Factory.StartNew(state =>
                         {
                             // Complete with the received value
-                            var target = (ReceiveTarget<T>)state;
-                            try { target.TrySetResult(target._receivedValue); }
+                            var target = (ReceiveTarget<T>)state!;
+                            try { target.TrySetResult(target._receivedValue!); }
                             catch (ObjectDisposedException) { /* benign race if returned task is already disposed */ }
                         }, this, CancellationToken.None, TaskCreationOptions.None, TaskScheduler.Default);
                         break;
@@ -1308,7 +1313,7 @@ namespace System.Threading.Tasks.Dataflow
                         System.Threading.Tasks.Task.Factory.StartNew(state =>
                         {
                             // Complete as canceled
-                            var target = (ReceiveTarget<T>)state;
+                            var target = (ReceiveTarget<T>)state!;
                             try { target.TrySetCanceled(); }
                             catch (ObjectDisposedException) { /* benign race if returned task is already disposed */ }
                         }, this, CancellationToken.None, TaskCreationOptions.None, TaskScheduler.Default);
@@ -1329,7 +1334,7 @@ namespace System.Threading.Tasks.Dataflow
                         System.Threading.Tasks.Task.Factory.StartNew(state =>
                         {
                             // Complete with the received exception
-                            var target = (ReceiveTarget<T>)state;
+                            var target = (ReceiveTarget<T>)state!;
                             try { target.TrySetException(target._receivedException ?? new InvalidOperationException(SR.InvalidOperation_ErrorDuringCleanup)); }
                             catch (ObjectDisposedException) { /* benign race if returned task is already disposed */ }
                         }, this, CancellationToken.None, TaskCreationOptions.None, TaskScheduler.Default);
@@ -1482,7 +1487,7 @@ namespace System.Threading.Tasks.Dataflow
             /// Cached continuation delegate that unregisters from cancellation and
             /// marshals the antecedent's result to the return value.
             /// </summary>
-            internal static readonly Func<Task<bool>, object, bool> s_handleCompletion = (antecedent, state) =>
+            internal static readonly Func<Task<bool>, object?, bool> s_handleCompletion = (antecedent, state) =>
             {
                 var target = state as OutputAvailableAsyncTarget<T>;
                 Debug.Assert(target != null, "Expected non-null target");
@@ -1494,11 +1499,11 @@ namespace System.Threading.Tasks.Dataflow
             /// Cached delegate that cancels the target and unlinks the target from the source.
             /// Expects an OutputAvailableAsyncTarget as the state argument.
             /// </summary>
-            internal static readonly Action<object> s_cancelAndUnlink = CancelAndUnlink;
+            internal static readonly Action<object?> s_cancelAndUnlink = CancelAndUnlink;
 
             /// <summary>Cancels the target and unlinks the target from the source.</summary>
             /// <param name="state">An OutputAvailableAsyncTarget.</param>
-            private static void CancelAndUnlink(object state)
+            private static void CancelAndUnlink(object? state)
             {
                 var target = state as OutputAvailableAsyncTarget<T>;
                 Debug.Assert(target != null, "Expected a non-null target");
@@ -1508,7 +1513,7 @@ namespace System.Threading.Tasks.Dataflow
                 // Take advantage of this task and unlink from there to avoid doing the interlocked operation synchronously.
                 System.Threading.Tasks.Task.Factory.StartNew(tgt =>
                                                             {
-                                                                var thisTarget = (OutputAvailableAsyncTarget<T>)tgt;
+                                                                var thisTarget = (OutputAvailableAsyncTarget<T>)tgt!;
                                                                 thisTarget.TrySetCanceled();
                                                                 thisTarget.AttemptThreadSafeUnlink();
                                                             },
@@ -1519,7 +1524,7 @@ namespace System.Threading.Tasks.Dataflow
             internal void AttemptThreadSafeUnlink()
             {
                 // A race is possible. Therefore use an interlocked operation.
-                IDisposable cachedUnlinker = _unlinker;
+                IDisposable? cachedUnlinker = _unlinker;
                 if (cachedUnlinker != null && Interlocked.CompareExchange(ref _unlinker, null, cachedUnlinker) == cachedUnlinker)
                 {
                     cachedUnlinker.Dispose();
@@ -1527,12 +1532,12 @@ namespace System.Threading.Tasks.Dataflow
             }
 
             /// <summary>The IDisposable used to unlink this target from its source.</summary>
-            internal IDisposable _unlinker;
+            internal IDisposable? _unlinker;
             /// <summary>The registration used to unregister this target from the cancellation token.</summary>
             internal CancellationTokenRegistration _ctr;
 
             /// <summary>Completes the task when offered a message (but doesn't consume the message).</summary>
-            DataflowMessageStatus ITargetBlock<T>.OfferMessage(DataflowMessageHeader messageHeader, T messageValue, ISourceBlock<T> source, bool consumeToAccept)
+            DataflowMessageStatus ITargetBlock<T>.OfferMessage(DataflowMessageHeader messageHeader, T messageValue, ISourceBlock<T>? source, bool consumeToAccept)
             {
                 if (!messageHeader.IsValid) throw new ArgumentException(SR.Argument_InvalidMessageHeader, nameof(messageHeader));
                 if (source == null) throw new ArgumentNullException(nameof(source));
@@ -1625,7 +1630,7 @@ namespace System.Threading.Tasks.Dataflow
                 _target.Fault(exception);
             }
             /// <include file='XmlDocs/CommonXmlDocComments.xml' path='CommonXmlDocComments/Targets/Member[@name="OfferMessage"]/*' />
-            public DataflowMessageStatus OfferMessage(DataflowMessageHeader messageHeader, TInput messageValue, ISourceBlock<TInput> source, bool consumeToAccept)
+            public DataflowMessageStatus OfferMessage(DataflowMessageHeader messageHeader, TInput messageValue, ISourceBlock<TInput>? source, bool consumeToAccept)
             {
                 return _target.OfferMessage(messageHeader, messageValue, source, consumeToAccept);
             }
@@ -1640,7 +1645,7 @@ namespace System.Threading.Tasks.Dataflow
             }
 
             /// <include file='XmlDocs/CommonXmlDocComments.xml' path='CommonXmlDocComments/Sources/Member[@name="TryReceive"]/*' />
-            public bool TryReceive(Predicate<TOutput> filter, out TOutput item)
+            public bool TryReceive(Predicate<TOutput>? filter, [MaybeNullWhen(false)] out TOutput item)
             {
                 var receivableSource = _source as IReceivableSourceBlock<TOutput>;
                 if (receivableSource != null) return receivableSource.TryReceive(filter, out item);
@@ -1650,7 +1655,7 @@ namespace System.Threading.Tasks.Dataflow
             }
 
             /// <include file='XmlDocs/CommonXmlDocComments.xml' path='CommonXmlDocComments/Sources/Member[@name="TryReceiveAll"]/*' />
-            public bool TryReceiveAll(out IList<TOutput> items)
+            public bool TryReceiveAll([NotNullWhen(true)] out IList<TOutput>? items)
             {
                 var receivableSource = _source as IReceivableSourceBlock<TOutput>;
                 if (receivableSource != null) return receivableSource.TryReceiveAll(out items);
@@ -1660,6 +1665,7 @@ namespace System.Threading.Tasks.Dataflow
             }
 
             /// <include file='XmlDocs/CommonXmlDocComments.xml' path='CommonXmlDocComments/Sources/Member[@name="ConsumeMessage"]/*' />
+            [return: MaybeNull]
             public TOutput ConsumeMessage(DataflowMessageHeader messageHeader, ITargetBlock<TOutput> target, out bool messageConsumed)
             {
                 return _source.ConsumeMessage(messageHeader, target, out messageConsumed);
@@ -1905,7 +1911,7 @@ namespace System.Threading.Tasks.Dataflow
         private static Task<int> ChooseCore<T1, T2, T3>(
             ISourceBlock<T1> source1, Action<T1> action1,
             ISourceBlock<T2> source2, Action<T2> action2,
-            ISourceBlock<T3> source3, Action<T3> action3,
+            ISourceBlock<T3>? source3, Action<T3>? action3,
             DataflowBlockOptions dataflowBlockOptions)
         {
             Debug.Assert(source1 != null && action1 != null, "The first source and action should not be null.");
@@ -1919,13 +1925,13 @@ namespace System.Threading.Tasks.Dataflow
                 return Common.CreateTaskFromCancellation<int>(dataflowBlockOptions.CancellationToken);
 
             // Fast path: if any of the sources already has data available that can be received immediately.
-            Task<int> resultTask;
+            Task<int>? resultTask;
             try
             {
                 TaskScheduler scheduler = dataflowBlockOptions.TaskScheduler;
                 if (TryChooseFromSource(source1, action1, 0, scheduler, out resultTask) ||
                     TryChooseFromSource(source2, action2, 1, scheduler, out resultTask) ||
-                    (hasThirdSource && TryChooseFromSource(source3, action3, 2, scheduler, out resultTask)))
+                    (hasThirdSource && TryChooseFromSource(source3!, action3!, 2, scheduler, out resultTask)))
                 {
                     return resultTask;
                 }
@@ -1952,7 +1958,7 @@ namespace System.Threading.Tasks.Dataflow
         /// <returns>true if this try attempt satisfies the choose operation; otherwise, false.</returns>
         private static bool TryChooseFromSource<T>(
             ISourceBlock<T> source, Action<T> action, int branchId, TaskScheduler scheduler,
-            out Task<int> task)
+            [NotNullWhen(true)] out Task<int>? task)
         {
             // Validate arguments
             Debug.Assert(source != null, "Expected a non-null source");
@@ -1990,7 +1996,7 @@ namespace System.Threading.Tasks.Dataflow
         private static Task<int> ChooseCoreByLinking<T1, T2, T3>(
             ISourceBlock<T1> source1, Action<T1> action1,
             ISourceBlock<T2> source2, Action<T2> action2,
-            ISourceBlock<T3> source3, Action<T3> action3,
+            ISourceBlock<T3>? source3, Action<T3>? action3,
             DataflowBlockOptions dataflowBlockOptions)
         {
             Debug.Assert(source1 != null && action1 != null, "The first source and action should not be null.");
@@ -2015,7 +2021,7 @@ namespace System.Threading.Tasks.Dataflow
             branchTasks[1] = CreateChooseBranch(boxedCompleted, cts, scheduler, 1, source2, action2);
             if (hasThirdSource)
             {
-                branchTasks[2] = CreateChooseBranch(boxedCompleted, cts, scheduler, 2, source3, action3);
+                branchTasks[2] = CreateChooseBranch(boxedCompleted, cts, scheduler, 2, source3!, action3!);
             }
 
             // Asynchronously wait for all branches to complete, then complete
@@ -2029,14 +2035,14 @@ namespace System.Threading.Tasks.Dataflow
                 // of whether a branch completed successfully.  Others may have been
                 // canceled (or run but found they were not needed), and those
                 // we just ignore.
-                List<Exception> exceptions = null;
+                List<Exception>? exceptions = null;
                 int successfulBranchId = -1;
                 foreach (Task<int> task in tasks)
                 {
                     switch (task.Status)
                     {
                         case TaskStatus.Faulted:
-                            Common.AddException(ref exceptions, task.Exception, unwrapInnerExceptions: true);
+                            Common.AddException(ref exceptions, task.Exception!, unwrapInnerExceptions: true);
                             break;
                         case TaskStatus.RanToCompletion:
                             int resultBranchId = task.Result;
@@ -2150,9 +2156,9 @@ namespace System.Threading.Tasks.Dataflow
             /// Delegate used to invoke the action for a branch when that branch is activated
             /// on the fast path.
             /// </summary>
-            internal static readonly Func<object, int> s_processBranchFunction = state =>
+            internal static readonly Func<object?, int> s_processBranchFunction = state =>
             {
-                Tuple<Action<T>, T, int> actionResultBranch = (Tuple<Action<T>, T, int>)state;
+                Tuple<Action<T>, T, int> actionResultBranch = (Tuple<Action<T>, T, int>)state!;
                 actionResultBranch.Item1(actionResultBranch.Item2);
                 return actionResultBranch.Item3;
             };
@@ -2176,13 +2182,13 @@ namespace System.Threading.Tasks.Dataflow
                 Common.WireCancellationToComplete(cancellationToken, base.Task,
                     state =>
                     {
-                        var thisChooseTarget = (ChooseTarget<T>)state;
+                        var thisChooseTarget = (ChooseTarget<T>)state!;
                         lock (thisChooseTarget._completed) thisChooseTarget.TrySetCanceled();
                     }, this);
             }
 
             /// <summary>Called when this choice branch is being offered a message.</summary>
-            public DataflowMessageStatus OfferMessage(DataflowMessageHeader messageHeader, T messageValue, ISourceBlock<T> source, bool consumeToAccept)
+            public DataflowMessageStatus OfferMessage(DataflowMessageHeader messageHeader, T messageValue, ISourceBlock<T>? source, bool consumeToAccept)
             {
                 // Validate arguments
                 if (!messageHeader.IsValid) throw new ArgumentException(SR.Argument_InvalidMessageHeader, nameof(messageHeader));
@@ -2197,12 +2203,12 @@ namespace System.Threading.Tasks.Dataflow
                     if (consumeToAccept)
                     {
                         bool consumed;
-                        messageValue = source.ConsumeMessage(messageHeader, this, out consumed);
+                        messageValue = source!.ConsumeMessage(messageHeader, this, out consumed);
                         if (!consumed) return DataflowMessageStatus.NotAvailable;
                     }
 
                     // Store the result and signal our success
-                    TrySetResult(messageValue);
+                    TrySetResult(messageValue!);
                     _completed.Value = Task;
                     return DataflowMessageStatus.Accepted;
                 }
@@ -2295,9 +2301,9 @@ namespace System.Threading.Tasks.Dataflow
 
             /// <summary>Gets any exceptions from the source block.</summary>
             /// <returns>The aggregate exception of all errors, or null if everything completed successfully.</returns>
-            private AggregateException GetCompletionError()
+            private AggregateException? GetCompletionError()
             {
-                Task sourceCompletionTask = Common.GetPotentiallyNotSupportedCompletionTask(_source);
+                Task? sourceCompletionTask = Common.GetPotentiallyNotSupportedCompletionTask(_source);
                 return sourceCompletionTask != null && sourceCompletionTask.IsFaulted ?
                     sourceCompletionTask.Exception : null;
             }
@@ -2311,10 +2317,10 @@ namespace System.Threading.Tasks.Dataflow
                 if (observer == null) throw new ArgumentNullException(nameof(observer));
                 Common.ContractAssertMonitorStatus(_SubscriptionLock, held: false);
 
-                Task sourceCompletionTask = Common.GetPotentiallyNotSupportedCompletionTask(_source);
+                Task? sourceCompletionTask = Common.GetPotentiallyNotSupportedCompletionTask(_source);
 
                 // Synchronize all observers for this source.
-                Exception error = null;
+                Exception? error = null;
                 lock (_SubscriptionLock)
                 {
                     // Fast path for if everything is already done.  We need to ensure that both
@@ -2338,7 +2344,7 @@ namespace System.Threading.Tasks.Dataflow
                             if (_observersState.Unlinker == null)
                             {
                                 _observersState.Observers = ImmutableArray<IObserver<TOutput>>.Empty;
-                                return null;
+                                return Disposables.Nop;
                             }
                         }
 
@@ -2452,12 +2458,12 @@ namespace System.Threading.Tasks.Dataflow
                 /// </summary>
                 internal ImmutableArray<IObserver<TOutput>> Observers = ImmutableArray<IObserver<TOutput>>.Empty;
                 /// <summary>Used to unlink the source from this target when the last observer is unsubscribed.</summary>
-                internal IDisposable Unlinker;
+                internal IDisposable? Unlinker;
                 /// <summary>
                 /// Temporary list to keep track of SendAsync tasks to TargetObservers with back pressure.
                 /// This field gets instantiated on demand. It gets populated and cleared within an offering cycle.
                 /// </summary>
-                private List<Task<bool>> _tempSendAsyncTaskList;
+                private List<Task<bool>>? _tempSendAsyncTaskList;
 
                 /// <summary>Initializes the target instance.</summary>
                 /// <param name="observable">The owning observable.</param>
@@ -2472,22 +2478,22 @@ namespace System.Threading.Tasks.Dataflow
                     // If the target block fails due to an unexpected exception (e.g. it calls back to the source and the source throws an error),
                     // we fault currently registered observers and reset the observable.
                     Target.Completion.ContinueWith(
-                        (t, state) => ((ObserversState)state).NotifyObserversOfCompletion(t.Exception), this,
+                        (t, state) => ((ObserversState)state!).NotifyObserversOfCompletion(t.Exception!), this,
                         CancellationToken.None,
                         Common.GetContinuationOptions(TaskContinuationOptions.OnlyOnFaulted | TaskContinuationOptions.ExecuteSynchronously),
                         TaskScheduler.Default);
 
                     // When the source completes, complete the target. Then when the target completes,
                     // send completion messages to any observers still registered.
-                    Task sourceCompletionTask = Common.GetPotentiallyNotSupportedCompletionTask(Observable._source);
+                    Task? sourceCompletionTask = Common.GetPotentiallyNotSupportedCompletionTask(Observable._source);
                     if (sourceCompletionTask != null)
                     {
                         sourceCompletionTask.ContinueWith((_1, state1) =>
                         {
-                            var ti = (ObserversState)state1;
+                            var ti = (ObserversState)state1!;
                             ti.Target.Complete();
                             ti.Target.Completion.ContinueWith(
-                                (_2, state2) => ((ObserversState)state2).NotifyObserversOfCompletion(), state1,
+                                (_2, state2) => ((ObserversState)state2!).NotifyObserversOfCompletion(), state1,
                                 CancellationToken.None,
                                 Common.GetContinuationOptions(TaskContinuationOptions.NotOnFaulted | TaskContinuationOptions.ExecuteSynchronously),
                                 TaskScheduler.Default);
@@ -2558,7 +2564,7 @@ namespace System.Threading.Tasks.Dataflow
                 /// Non-null when an unexpected exception occurs during processing.  Faults
                 /// all subscribed observers and resets the observable back to its original condition.
                 /// </param>
-                private void NotifyObserversOfCompletion(Exception targetException = null)
+                private void NotifyObserversOfCompletion(Exception? targetException = null)
                 {
                     Debug.Assert(Target.Completion.IsCompleted, "The target must have already completed in order to notify of completion.");
                     Common.ContractAssertMonitorStatus(Observable._SubscriptionLock, held: false);
@@ -2579,7 +2585,7 @@ namespace System.Threading.Tasks.Dataflow
                     if (currentObservers.Count > 0)
                     {
                         // Determine if we should fault or complete the observers
-                        Exception error = targetException ?? Observable.GetCompletionError();
+                        Exception? error = targetException ?? Observable.GetCompletionError();
                         try
                         {
                             // Do it.
@@ -2696,10 +2702,10 @@ namespace System.Threading.Tasks.Dataflow
         /// <typeparam name="TInput">The type of the messages this block can accept.</typeparam>
         private class NullTargetBlock<TInput> : ITargetBlock<TInput>
         {
-            private Task _completion;
+            private Task? _completion;
 
             /// <include file='XmlDocs/CommonXmlDocComments.xml' path='CommonXmlDocComments/Targets/Member[@name="OfferMessage"]/*' />
-            DataflowMessageStatus ITargetBlock<TInput>.OfferMessage(DataflowMessageHeader messageHeader, TInput messageValue, ISourceBlock<TInput> source, bool consumeToAccept)
+            DataflowMessageStatus ITargetBlock<TInput>.OfferMessage(DataflowMessageHeader messageHeader, TInput messageValue, ISourceBlock<TInput>? source, bool consumeToAccept)
             {
                 if (!messageHeader.IsValid) throw new ArgumentException(SR.Argument_InvalidMessageHeader, nameof(messageHeader));
 
index fcf8b45..25cd92f 100644 (file)
@@ -57,7 +57,7 @@ namespace System.Threading.Tasks.Dataflow
         /// <summary>Checks boxed <see cref="DataflowMessageHeader"/> instances for equality by ID.</summary>
         /// <param name="obj">A boxed <see cref="DataflowMessageHeader"/> instance.</param>
         /// <returns>True if the instances are equal. False otherwise.</returns>
-        public override bool Equals(object obj)
+        public override bool Equals(object? obj)
         {
             return obj is DataflowMessageHeader && this == (DataflowMessageHeader)obj;
         }
index 3bb2f54..9dc8439 100644 (file)
@@ -12,6 +12,7 @@
 // =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
 
 using System.Collections.Generic;
+using System.Diagnostics.CodeAnalysis;
 
 namespace System.Threading.Tasks.Dataflow
 {
@@ -22,11 +23,11 @@ namespace System.Threading.Tasks.Dataflow
         // IMPLEMENT IMPLICITLY
 
         /// <include file='XmlDocs/CommonXmlDocComments.xml' path='CommonXmlDocComments/Sources/Member[@name="TryReceive"]/*' />
-        bool TryReceive(Predicate<TOutput> filter, out TOutput item);
+        bool TryReceive(Predicate<TOutput>? filter, [MaybeNullWhen(false)] out TOutput item);
 
         // IMPLEMENT IMPLICITLY IF BLOCK SUPPORTS RECEIVING MORE THAN ONE ITEM, OTHERWISE EXPLICITLY
 
         /// <include file='XmlDocs/CommonXmlDocComments.xml' path='CommonXmlDocComments/Sources/Member[@name="TryReceiveAll"]/*' />
-        bool TryReceiveAll(out IList<TOutput> items);
+        bool TryReceiveAll([NotNullWhen(true)] out IList<TOutput>? items);
     }
 }
index 8b54066..8b2f9bc 100644 (file)
@@ -28,6 +28,7 @@ namespace System.Threading.Tasks.Dataflow
         // IMPLEMENT EXPLICITLY
 
         /// <include file='XmlDocs/CommonXmlDocComments.xml' path='CommonXmlDocComments/Sources/Member[@name="ConsumeMessage"]/*' />
+        [return: MaybeNull]
         TOutput ConsumeMessage(DataflowMessageHeader messageHeader, ITargetBlock<TOutput> target, out bool messageConsumed);
 
         /// <include file='XmlDocs/CommonXmlDocComments.xml' path='CommonXmlDocComments/Sources/Member[@name="ReserveMessage"]/*' />
index 1728d58..67eed5c 100644 (file)
@@ -20,6 +20,6 @@ namespace System.Threading.Tasks.Dataflow
         // IMPLEMENT EXPLICITLY
 
         /// <include file='XmlDocs/CommonXmlDocComments.xml' path='CommonXmlDocComments/Targets/Member[@name="OfferMessage"]/*' />
-        DataflowMessageStatus OfferMessage(DataflowMessageHeader messageHeader, TInput messageValue, ISourceBlock<TInput> source, bool consumeToAccept);
+        DataflowMessageStatus OfferMessage(DataflowMessageHeader messageHeader, TInput messageValue, ISourceBlock<TInput>? source, bool consumeToAccept);
     }
 }
index f687532..e81e34c 100644 (file)
@@ -26,9 +26,9 @@ namespace System.Threading.Tasks.Dataflow
     public sealed class ActionBlock<TInput> : ITargetBlock<TInput>, IDebuggerDisplay
     {
         /// <summary>The core implementation of this message block when in default mode.</summary>
-        private readonly TargetCore<TInput> _defaultTarget;
+        private readonly TargetCore<TInput>? _defaultTarget;
         /// <summary>The core implementation of this message block when in SPSC mode.</summary>
-        private readonly SpscTargetCore<TInput> _spscTarget;
+        private readonly SpscTargetCore<TInput>? _spscTarget;
 
         /// <summary>Initializes the <see cref="ActionBlock{T}"/> with the specified <see cref="System.Action{T}"/>.</summary>
         /// <param name="action">The action to invoke with each data element received.</param>
@@ -113,7 +113,7 @@ namespace System.Threading.Tasks.Dataflow
 
                 // Handle async cancellation requests by declining on the target
                 Common.WireCancellationToComplete(
-                    dataflowBlockOptions.CancellationToken, Completion, state => ((TargetCore<TInput>)state).Complete(exception: null, dropPendingMessages: true), _defaultTarget);
+                    dataflowBlockOptions.CancellationToken, Completion, state => ((TargetCore<TInput>)state!).Complete(exception: null, dropPendingMessages: true), _defaultTarget);
             }
 #if FEATURE_TRACING
             DataflowEtwProvider etwLog = DataflowEtwProvider.Log;
@@ -131,6 +131,7 @@ namespace System.Threading.Tasks.Dataflow
         /// <param name="messageWithId">The message to be processed.</param>
         private void ProcessMessage(Action<TInput> action, KeyValuePair<TInput, long> messageWithId)
         {
+            Debug.Assert(_defaultTarget != null);
             try
             {
                 action(messageWithId.Key);
@@ -154,10 +155,11 @@ namespace System.Threading.Tasks.Dataflow
         private void ProcessMessageWithTask(Func<TInput, Task> action, KeyValuePair<TInput, long> messageWithId)
         {
             Debug.Assert(action != null, "action needed for processing");
+            Debug.Assert(_defaultTarget != null);
 
             // Run the action to get the task that represents the operation's completion
-            Task task = null;
-            Exception caughtException = null;
+            Task? task = null;
+            Exception? caughtException = null;
             try
             {
                 task = action(messageWithId.Key);
@@ -188,7 +190,7 @@ namespace System.Threading.Tasks.Dataflow
                 // Otherwise, join with the asynchronous operation when it completes.
                 task.ContinueWith((completed, state) =>
                 {
-                    ((ActionBlock<TInput>)state).AsyncCompleteProcessMessageWithTask(completed);
+                    ((ActionBlock<TInput>)state!).AsyncCompleteProcessMessageWithTask(completed);
                 }, this, CancellationToken.None, Common.GetContinuationOptions(TaskContinuationOptions.ExecuteSynchronously), TaskScheduler.Default);
             }
         }
@@ -199,6 +201,7 @@ namespace System.Threading.Tasks.Dataflow
         {
             Debug.Assert(completed != null, "Need completed task for processing");
             Debug.Assert(completed.IsCompleted, "The task to be processed must be completed by now.");
+            Debug.Assert(_defaultTarget != null);
 
             // If the task faulted, store its errors. We must add the exception before declining
             // and signaling completion, as the exception is part of the operation, and the completion conditions
@@ -224,6 +227,7 @@ namespace System.Threading.Tasks.Dataflow
             }
             else
             {
+                Debug.Assert(_spscTarget != null);
                 _spscTarget.Complete(exception: null);
             }
         }
@@ -239,6 +243,7 @@ namespace System.Threading.Tasks.Dataflow
             }
             else
             {
+                Debug.Assert(_spscTarget != null);
                 _spscTarget.Complete(exception);
             }
         }
@@ -246,7 +251,7 @@ namespace System.Threading.Tasks.Dataflow
         /// <include file='XmlDocs/CommonXmlDocComments.xml' path='CommonXmlDocComments/Blocks/Member[@name="Completion"]/*' />
         public Task Completion
         {
-            get { return _defaultTarget != null ? _defaultTarget.Completion : _spscTarget.Completion; }
+            get { return _defaultTarget != null ? _defaultTarget.Completion : _spscTarget!.Completion; }
         }
 
         /// <summary>Posts an item to the <see cref="System.Threading.Tasks.Dataflow.ITargetBlock{T}"/>.</summary>
@@ -273,33 +278,33 @@ namespace System.Threading.Tasks.Dataflow
 
             return _defaultTarget != null ?
                 _defaultTarget.OfferMessage(Common.SingleMessageHeader, item, null, false) == DataflowMessageStatus.Accepted :
-                _spscTarget.Post(item);
+                _spscTarget!.Post(item);
         }
 
         /// <include file='XmlDocs/CommonXmlDocComments.xml' path='CommonXmlDocComments/Targets/Member[@name="OfferMessage"]/*' />
-        DataflowMessageStatus ITargetBlock<TInput>.OfferMessage(DataflowMessageHeader messageHeader, TInput messageValue, ISourceBlock<TInput> source, bool consumeToAccept)
+        DataflowMessageStatus ITargetBlock<TInput>.OfferMessage(DataflowMessageHeader messageHeader, TInput messageValue, ISourceBlock<TInput>? source, bool consumeToAccept)
         {
             return _defaultTarget != null ?
                 _defaultTarget.OfferMessage(messageHeader, messageValue, source, consumeToAccept) :
-                _spscTarget.OfferMessage(messageHeader, messageValue, source, consumeToAccept);
+                _spscTarget!.OfferMessage(messageHeader, messageValue, source, consumeToAccept);
         }
 
         /// <include file='XmlDocs/CommonXmlDocComments.xml' path='CommonXmlDocComments/Targets/Member[@name="InputCount"]/*' />
         public int InputCount
         {
-            get { return _defaultTarget != null ? _defaultTarget.InputCount : _spscTarget.InputCount; }
+            get { return _defaultTarget != null ? _defaultTarget.InputCount : _spscTarget!.InputCount; }
         }
 
         /// <summary>Gets the number of messages waiting to be processed. This must only be used from the debugger.</summary>
         private int InputCountForDebugger
         {
-            get { return _defaultTarget != null ? _defaultTarget.GetDebuggingInformation().InputCount : _spscTarget.InputCount; }
+            get { return _defaultTarget != null ? _defaultTarget.GetDebuggingInformation().InputCount : _spscTarget!.InputCount; }
         }
 
         /// <include file='XmlDocs/CommonXmlDocComments.xml' path='CommonXmlDocComments/Blocks/Member[@name="ToString"]/*' />
         public override string ToString()
         {
-            return Common.GetNameForDebugger(this, _defaultTarget != null ? _defaultTarget.DataflowBlockOptions : _spscTarget.DataflowBlockOptions);
+            return Common.GetNameForDebugger(this, _defaultTarget != null ? _defaultTarget.DataflowBlockOptions : _spscTarget!.DataflowBlockOptions);
         }
 
         /// <summary>The data to display in the debugger display attribute.</summary>
@@ -308,7 +313,7 @@ namespace System.Threading.Tasks.Dataflow
             get
             {
                 return string.Format("{0}, InputCount={1}",
-                    Common.GetNameForDebugger(this, _defaultTarget != null ? _defaultTarget.DataflowBlockOptions : _spscTarget.DataflowBlockOptions),
+                    Common.GetNameForDebugger(this, _defaultTarget != null ? _defaultTarget.DataflowBlockOptions : _spscTarget!.DataflowBlockOptions),
                     InputCountForDebugger);
             }
         }
@@ -321,9 +326,9 @@ namespace System.Threading.Tasks.Dataflow
             /// <summary>The action block being viewed.</summary>
             private readonly ActionBlock<TInput> _actionBlock;
             /// <summary>The action block's default target being viewed.</summary>
-            private readonly TargetCore<TInput>.DebuggingInformation _defaultDebugInfo;
+            private readonly TargetCore<TInput>.DebuggingInformation? _defaultDebugInfo;
             /// <summary>The action block's SPSC target being viewed.</summary>
-            private readonly SpscTargetCore<TInput>.DebuggingInformation _spscDebugInfo;
+            private readonly SpscTargetCore<TInput>.DebuggingInformation? _spscDebugInfo;
 
             /// <summary>Initializes the debug view.</summary>
             /// <param name="actionBlock">The target being debugged.</param>
@@ -333,21 +338,21 @@ namespace System.Threading.Tasks.Dataflow
                 _actionBlock = actionBlock;
                 if (_actionBlock._defaultTarget != null)
                 {
-                    _defaultDebugInfo = actionBlock._defaultTarget.GetDebuggingInformation();
+                    _defaultDebugInfo = actionBlock._defaultTarget!.GetDebuggingInformation();
                 }
                 else
                 {
-                    _spscDebugInfo = actionBlock._spscTarget.GetDebuggingInformation();
+                    _spscDebugInfo = actionBlock._spscTarget!.GetDebuggingInformation();
                 }
             }
 
             /// <summary>Gets the messages waiting to be processed.</summary>
             public IEnumerable<TInput> InputQueue
             {
-                get { return _defaultDebugInfo != null ? _defaultDebugInfo.InputQueue : _spscDebugInfo.InputQueue; }
+                get { return _defaultDebugInfo != null ? _defaultDebugInfo.InputQueue : _spscDebugInfo!.InputQueue; }
             }
             /// <summary>Gets any postponed messages.</summary>
-            public QueuedMap<ISourceBlock<TInput>, DataflowMessageHeader> PostponedMessages
+            public QueuedMap<ISourceBlock<TInput>, DataflowMessageHeader>? PostponedMessages
             {
                 get { return _defaultDebugInfo != null ? _defaultDebugInfo.PostponedMessages : null; }
             }
@@ -355,23 +360,23 @@ namespace System.Threading.Tasks.Dataflow
             /// <summary>Gets the number of outstanding input operations.</summary>
             public int CurrentDegreeOfParallelism
             {
-                get { return _defaultDebugInfo != null ? _defaultDebugInfo.CurrentDegreeOfParallelism : _spscDebugInfo.CurrentDegreeOfParallelism; }
+                get { return _defaultDebugInfo != null ? _defaultDebugInfo.CurrentDegreeOfParallelism : _spscDebugInfo!.CurrentDegreeOfParallelism; }
             }
 
             /// <summary>Gets the ExecutionDataflowBlockOptions used to configure this block.</summary>
             public ExecutionDataflowBlockOptions DataflowBlockOptions
             {
-                get { return _defaultDebugInfo != null ? _defaultDebugInfo.DataflowBlockOptions : _spscDebugInfo.DataflowBlockOptions; }
+                get { return _defaultDebugInfo != null ? _defaultDebugInfo.DataflowBlockOptions : _spscDebugInfo!.DataflowBlockOptions; }
             }
             /// <summary>Gets whether the block is declining further messages.</summary>
             public bool IsDecliningPermanently
             {
-                get { return _defaultDebugInfo != null ? _defaultDebugInfo.IsDecliningPermanently : _spscDebugInfo.IsDecliningPermanently; }
+                get { return _defaultDebugInfo != null ? _defaultDebugInfo.IsDecliningPermanently : _spscDebugInfo!.IsDecliningPermanently; }
             }
             /// <summary>Gets whether the block is completed.</summary>
             public bool IsCompleted
             {
-                get { return _defaultDebugInfo != null ? _defaultDebugInfo.IsCompleted : _spscDebugInfo.IsCompleted; }
+                get { return _defaultDebugInfo != null ? _defaultDebugInfo.IsCompleted : _spscDebugInfo!.IsCompleted; }
             }
             /// <summary>Gets the block's Id.</summary>
             public int Id { get { return Common.GetBlockId(_actionBlock); } }
index 8c18c71..48976ab 100644 (file)
@@ -55,8 +55,8 @@ namespace System.Threading.Tasks.Dataflow
             dataflowBlockOptions = dataflowBlockOptions.DefaultOrClone();
 
             // Initialize bounding actions
-            Action<ISourceBlock<T[]>, int> onItemsRemoved = null;
-            Func<ISourceBlock<T[]>, T[], IList<T[]>, int> itemCountingFunc = null;
+            Action<ISourceBlock<T[]>, int>? onItemsRemoved = null;
+            Func<ISourceBlock<T[]>, T[], IList<T[]>?, int>? itemCountingFunc = null;
             if (dataflowBlockOptions.BoundedCapacity > 0)
             {
                 onItemsRemoved = (owningSource, count) => ((BatchBlock<T>)owningSource)._target.OnItemsRemoved(count);
@@ -81,14 +81,14 @@ namespace System.Threading.Tasks.Dataflow
             // to handle multiple completion requests and to carry over only one.
             _source.Completion.ContinueWith((completed, state) =>
             {
-                var thisBlock = ((BatchBlock<T>)state) as IDataflowBlock;
+                var thisBlock = ((BatchBlock<T>)state!) as IDataflowBlock;
                 Debug.Assert(completed.IsFaulted, "The source must be faulted in order to trigger a target completion.");
-                thisBlock.Fault(completed.Exception);
+                thisBlock.Fault(completed.Exception!);
             }, this, CancellationToken.None, Common.GetContinuationOptions() | TaskContinuationOptions.OnlyOnFaulted, TaskScheduler.Default);
 
             // Handle async cancellation requests by declining on the target
             Common.WireCancellationToComplete(
-                dataflowBlockOptions.CancellationToken, _source.Completion, state => ((BatchBlockTargetCore)state).Complete(exception: null, dropPendingMessages: true, releaseReservedMessages: false), _target);
+                dataflowBlockOptions.CancellationToken, _source.Completion, state => ((BatchBlockTargetCore)state!).Complete(exception: null, dropPendingMessages: true, releaseReservedMessages: false), _target);
 #if FEATURE_TRACING
             DataflowEtwProvider etwLog = DataflowEtwProvider.Log;
             if (etwLog.IsEnabled())
@@ -127,13 +127,15 @@ namespace System.Threading.Tasks.Dataflow
         }
 
         /// <include file='XmlDocs/CommonXmlDocComments.xml' path='CommonXmlDocComments/Sources/Member[@name="TryReceive"]/*' />
-        public bool TryReceive(Predicate<T[]> filter, out T[] item)
+#pragma warning disable CS8614 // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/42470
+        public bool TryReceive(Predicate<T[]>? filter, [NotNullWhen(true)] out T[]? item)
+#pragma warning restore CS8614
         {
             return _source.TryReceive(filter, out item);
         }
 
         /// <include file='XmlDocs/CommonXmlDocComments.xml' path='CommonXmlDocComments/Sources/Member[@name="TryReceiveAll"]/*' />
-        public bool TryReceiveAll(out IList<T[]> items) { return _source.TryReceiveAll(out items); }
+        public bool TryReceiveAll([NotNullWhen(true)] out IList<T[]>? items) { return _source.TryReceiveAll(out items); }
 
         /// <include file='XmlDocs/CommonXmlDocComments.xml' path='CommonXmlDocComments/Sources/Member[@name="OutputCount"]/*' />
         public int OutputCount { get { return _source.OutputCount; } }
@@ -149,12 +151,13 @@ namespace System.Threading.Tasks.Dataflow
         public int BatchSize { get { return _target.BatchSize; } }
 
         /// <include file='XmlDocs/CommonXmlDocComments.xml' path='CommonXmlDocComments/Targets/Member[@name="OfferMessage"]/*' />
-        DataflowMessageStatus ITargetBlock<T>.OfferMessage(DataflowMessageHeader messageHeader, T messageValue, ISourceBlock<T> source, bool consumeToAccept)
+        DataflowMessageStatus ITargetBlock<T>.OfferMessage(DataflowMessageHeader messageHeader, T messageValue, ISourceBlock<T>? source, bool consumeToAccept)
         {
             return _target.OfferMessage(messageHeader, messageValue, source, consumeToAccept);
         }
 
         /// <include file='XmlDocs/CommonXmlDocComments.xml' path='CommonXmlDocComments/Sources/Member[@name="ConsumeMessage"]/*' />
+        [return: MaybeNull]
         T[] ISourceBlock<T[]>.ConsumeMessage(DataflowMessageHeader messageHeader, ITargetBlock<T[]> target, out bool messageConsumed)
         {
             return _source.ConsumeMessage(messageHeader, target, out messageConsumed);
@@ -220,9 +223,9 @@ namespace System.Threading.Tasks.Dataflow
             public long BatchesCompleted { get { return _targetDebuggingInformation.NumberOfBatchesCompleted; } }
 
             /// <summary>Gets the task being used for input processing.</summary>
-            public Task TaskForInputProcessing { get { return _targetDebuggingInformation.TaskForInputProcessing; } }
+            public Task? TaskForInputProcessing { get { return _targetDebuggingInformation.TaskForInputProcessing; } }
             /// <summary>Gets the task being used for output processing.</summary>
-            public Task TaskForOutputProcessing { get { return _sourceDebuggingInformation.TaskForOutputProcessing; } }
+            public Task? TaskForOutputProcessing { get { return _sourceDebuggingInformation.TaskForOutputProcessing; } }
 
             /// <summary>Gets the DataflowBlockOptions used to configure this block.</summary>
             public GroupingDataflowBlockOptions DataflowBlockOptions { get { return _targetDebuggingInformation.DataflowBlockOptions; } }
@@ -236,11 +239,11 @@ namespace System.Threading.Tasks.Dataflow
             public int Id { get { return Common.GetBlockId(_batchBlock); } }
 
             /// <summary>Gets the messages postponed by this batch.</summary>
-            public QueuedMap<ISourceBlock<T>, DataflowMessageHeader> PostponedMessages { get { return _targetDebuggingInformation.PostponedMessages; } }
+            public QueuedMap<ISourceBlock<T>, DataflowMessageHeader>? PostponedMessages { get { return _targetDebuggingInformation.PostponedMessages; } }
             /// <summary>Gets the set of all targets linked from this block.</summary>
             public TargetRegistry<T[]> LinkedTargets { get { return _sourceDebuggingInformation.LinkedTargets; } }
             /// <summary>Gets the set of all targets linked from this block.</summary>
-            public ITargetBlock<T[]> NextMessageReservedFor { get { return _sourceDebuggingInformation.NextMessageReservedFor; } }
+            public ITargetBlock<T[]>? NextMessageReservedFor { get { return _sourceDebuggingInformation.NextMessageReservedFor; } }
         }
 
         /// <summary>Provides the core target implementation for a Batch.</summary>
@@ -260,9 +263,9 @@ namespace System.Threading.Tasks.Dataflow
             /// <summary>The batch size.</summary>
             private readonly int _batchSize;
             /// <summary>State used when in non-greedy mode.</summary>
-            private readonly NonGreedyState _nonGreedyState;
+            private readonly NonGreedyState? _nonGreedyState;
             /// <summary>Bounding state for when the block is executing in bounded mode.</summary>
-            private readonly BoundingState _boundingState;
+            private readonly BoundingState? _boundingState;
             /// <summary>The options associated with this block.</summary>
             private readonly GroupingDataflowBlockOptions _dataflowBlockOptions;
             /// <summary>The action invoked with a completed batch.</summary>
@@ -288,7 +291,7 @@ namespace System.Threading.Tasks.Dataflow
                 /// <remarks>This value may be read not under a lock, but it must only be written to protected by the IncomingLock.</remarks>
                 internal bool AcceptFewerThanBatchSize;
                 /// <summary>The task used to process messages.</summary>
-                internal Task TaskForInputProcessing;
+                internal Task? TaskForInputProcessing;
 
                 /// <summary>Initializes the NonGreedyState.</summary>
                 /// <param name="batchSize">The batch size used by the BatchBlock.</param>
@@ -356,7 +359,7 @@ namespace System.Threading.Tasks.Dataflow
             }
 
             /// <include file='XmlDocs/CommonXmlDocComments.xml' path='CommonXmlDocComments/Targets/Member[@name="OfferMessage"]/*' />
-            internal DataflowMessageStatus OfferMessage(DataflowMessageHeader messageHeader, T messageValue, ISourceBlock<T> source, bool consumeToAccept)
+            internal DataflowMessageStatus OfferMessage(DataflowMessageHeader messageHeader, T messageValue, ISourceBlock<T>? source, bool consumeToAccept)
             {
                 // Validate arguments
                 if (!messageHeader.IsValid) throw new ArgumentException(SR.Argument_InvalidMessageHeader, nameof(messageHeader));
@@ -380,7 +383,7 @@ namespace System.Threading.Tasks.Dataflow
                     if (_dataflowBlockOptions.Greedy &&
                             (_boundingState == null
                                 ||
-                             (_boundingState.CountIsLessThanBound && _nonGreedyState.PostponedMessages.Count == 0 && _nonGreedyState.TaskForInputProcessing == null)))
+                             (_boundingState.CountIsLessThanBound && _nonGreedyState!.PostponedMessages.Count == 0 && _nonGreedyState.TaskForInputProcessing == null)))
                     {
                         // Consume the message from the source if necessary
                         if (consumeToAccept)
@@ -393,7 +396,7 @@ namespace System.Threading.Tasks.Dataflow
                         }
 
                         // Once consumed, enqueue it.
-                        _messages.Enqueue(messageValue);
+                        _messages.Enqueue(messageValue!);
                         if (_boundingState != null) _boundingState.CurrentCount += 1; // track this new item against our bound
 
                         // Now start declining if the number of batches we've already made plus
@@ -432,7 +435,7 @@ namespace System.Threading.Tasks.Dataflow
             /// In general, it is not safe to pass releaseReservedMessages:true, because releasing of reserved messages
             /// is done without taking a lock. We pass releaseReservedMessages:true only when an exception has been
             /// caught inside the message processing loop which is a single instance at any given moment.</summary>
-            internal void Complete(Exception exception, bool dropPendingMessages, bool releaseReservedMessages, bool revertProcessingState = false)
+            internal void Complete(Exception? exception, bool dropPendingMessages, bool releaseReservedMessages, bool revertProcessingState = false)
             {
                 // Ensure that no new messages may be added
                 lock (IncomingLock)
@@ -531,10 +534,10 @@ namespace System.Threading.Tasks.Dataflow
                         // completion task continuations in that case, do it in a separate task.
                         Task.Factory.StartNew(thisTargetCore =>
                         {
-                            var targetCore = (BatchBlockTargetCore)thisTargetCore;
+                            var targetCore = (BatchBlockTargetCore)thisTargetCore!;
 
                             // Release any postponed messages
-                            List<Exception> exceptions = null;
+                            List<Exception>? exceptions = null;
                             if (targetCore._nonGreedyState != null)
                             {
                                 // Note: No locks should be held at this point
@@ -637,7 +640,7 @@ namespace System.Threading.Tasks.Dataflow
 
                 // Create task and store into _taskForInputProcessing prior to scheduling the task
                 // so that _taskForInputProcessing will be visibly set in the task loop.
-                _nonGreedyState.TaskForInputProcessing = new Task(thisBatchTarget => ((BatchBlockTargetCore)thisBatchTarget).ProcessMessagesLoopCore(), this,
+                _nonGreedyState!.TaskForInputProcessing = new Task(thisBatchTarget => ((BatchBlockTargetCore)thisBatchTarget!).ProcessMessagesLoopCore(), this,
                                                     Common.GetCreationOptionsForTask(isReplacementReplica));
 
 #if FEATURE_TRACING
@@ -651,11 +654,11 @@ namespace System.Threading.Tasks.Dataflow
 #endif
 
                 // Start the task handling scheduling exceptions
-                Exception exception = Common.StartTaskSafe(_nonGreedyState.TaskForInputProcessing, _dataflowBlockOptions.TaskScheduler);
+                Exception? exception = Common.StartTaskSafe(_nonGreedyState.TaskForInputProcessing, _dataflowBlockOptions.TaskScheduler);
                 if (exception != null)
                 {
                     // Get out from under currently held locks. Complete re-acquires the locks it needs.
-                    Task.Factory.StartNew(exc => Complete(exception: (Exception)exc, dropPendingMessages: true, releaseReservedMessages: true, revertProcessingState: true),
+                    Task.Factory.StartNew(exc => Complete(exception: (Exception)exc!, dropPendingMessages: true, releaseReservedMessages: true, revertProcessingState: true),
                                         exception, CancellationToken.None, Common.GetCreationOptionsForTask(), TaskScheduler.Default);
                 }
             }
@@ -793,7 +796,7 @@ namespace System.Threading.Tasks.Dataflow
                     KeyValuePair<ISourceBlock<T>, DataflowMessageHeader> sourceAndMessage = postponedTemp[i];
                     if (sourceAndMessage.Key.ReserveMessage(sourceAndMessage.Value, _owningBatch))
                     {
-                        var reservedMessage = new KeyValuePair<DataflowMessageHeader, T>(sourceAndMessage.Value, default(T));
+                        var reservedMessage = new KeyValuePair<DataflowMessageHeader, T>(sourceAndMessage.Value, default(T)!);
                         var reservedSourceAndMessage = new KeyValuePair<ISourceBlock<T>, KeyValuePair<DataflowMessageHeader, T>>(sourceAndMessage.Key, reservedMessage);
                         reserved.Add(reservedSourceAndMessage);
                     }
@@ -811,7 +814,7 @@ namespace System.Threading.Tasks.Dataflow
                     } // Release the lock.  We must not hold it while calling Reserve/Consume/Release.
                     if (sourceAndMessage.Key.ReserveMessage(sourceAndMessage.Value, _owningBatch))
                     {
-                        var reservedMessage = new KeyValuePair<DataflowMessageHeader, T>(sourceAndMessage.Value, default(T));
+                        var reservedMessage = new KeyValuePair<DataflowMessageHeader, T>(sourceAndMessage.Value, default(T)!);
                         var reservedSourceAndMessage = new KeyValuePair<ISourceBlock<T>, KeyValuePair<DataflowMessageHeader, T>>(sourceAndMessage.Key, reservedMessage);
                         reserved.Add(reservedSourceAndMessage);
                     }
@@ -908,7 +911,7 @@ namespace System.Threading.Tasks.Dataflow
                 for (int i = 0; i < poppedInitially; i++)
                 {
                     KeyValuePair<ISourceBlock<T>, DataflowMessageHeader> sourceAndMessage = postponedTemp[i];
-                    var reservedMessage = new KeyValuePair<DataflowMessageHeader, T>(sourceAndMessage.Value, default(T));
+                    var reservedMessage = new KeyValuePair<DataflowMessageHeader, T>(sourceAndMessage.Value, default(T)!);
                     var reservedSourceAndMessage = new KeyValuePair<ISourceBlock<T>, KeyValuePair<DataflowMessageHeader, T>>(sourceAndMessage.Key, reservedMessage);
                     reserved.Add(reservedSourceAndMessage);
                 }
@@ -924,7 +927,7 @@ namespace System.Threading.Tasks.Dataflow
                         if (!postponed.TryPop(out sourceAndMessage)) break;
                     } // Release the lock.  We must not hold it while calling Reserve/Consume/Release.
 
-                    var reservedMessage = new KeyValuePair<DataflowMessageHeader, T>(sourceAndMessage.Value, default(T));
+                    var reservedMessage = new KeyValuePair<DataflowMessageHeader, T>(sourceAndMessage.Value, default(T)!);
                     var reservedSourceAndMessage = new KeyValuePair<ISourceBlock<T>, KeyValuePair<DataflowMessageHeader, T>>(sourceAndMessage.Key, reservedMessage);
                     reserved.Add(reservedSourceAndMessage);
                 }
@@ -1007,7 +1010,7 @@ namespace System.Threading.Tasks.Dataflow
                         throw new InvalidOperationException(SR.InvalidOperation_FailedToConsumeReservedMessage);
                     }
 
-                    var consumedMessage = new KeyValuePair<DataflowMessageHeader, T>(sourceAndMessage.Value.Key, consumedValue);
+                    var consumedMessage = new KeyValuePair<DataflowMessageHeader, T>(sourceAndMessage.Value.Key, consumedValue!);
                     var consumedSourceAndMessage = new KeyValuePair<ISourceBlock<T>, KeyValuePair<DataflowMessageHeader, T>>(sourceAndMessage.Key, consumedMessage);
                     reserved[i] = consumedSourceAndMessage;
                 }
@@ -1052,7 +1055,7 @@ namespace System.Threading.Tasks.Dataflow
                     T consumedValue = sourceAndMessage.Key.ConsumeMessage(sourceAndMessage.Value.Key, _owningBatch, out consumed);
                     if (consumed)
                     {
-                        var consumedMessage = new KeyValuePair<DataflowMessageHeader, T>(sourceAndMessage.Value.Key, consumedValue);
+                        var consumedMessage = new KeyValuePair<DataflowMessageHeader, T>(sourceAndMessage.Value.Key, consumedValue!);
                         var consumedSourceAndMessage = new KeyValuePair<ISourceBlock<T>, KeyValuePair<DataflowMessageHeader, T>>(sourceAndMessage.Key, consumedMessage);
                         reserved[i] = consumedSourceAndMessage;
 
@@ -1087,7 +1090,7 @@ namespace System.Threading.Tasks.Dataflow
                 Debug.Assert(_nonGreedyState != null, "Non-greedy state is required for non-greedy mode.");
                 Debug.Assert(_nonGreedyState.ReservedSourcesTemp != null, "Should have been initialized");
 
-                List<Exception> exceptions = null;
+                List<Exception>? exceptions = null;
 
                 List<KeyValuePair<ISourceBlock<T>, KeyValuePair<DataflowMessageHeader, T>>> reserved = _nonGreedyState.ReservedSourcesTemp;
                 for (int i = 0; i < reserved.Count; i++)
@@ -1139,7 +1142,7 @@ namespace System.Threading.Tasks.Dataflow
             /// <summary>Counts the input items in a single output item or in a list of output items.</summary>
             /// <param name="singleOutputItem">A single output item. Only considered if multipleOutputItems == null.</param>
             /// <param name="multipleOutputItems">A list of output items. May be null.</param>
-            internal static int CountItems(T[] singleOutputItem, IList<T[]> multipleOutputItems)
+            internal static int CountItems(T[] singleOutputItem, IList<T[]>? multipleOutputItems)
             {
                 // If multipleOutputItems == null, then singleOutputItem is the subject of counting
                 if (multipleOutputItems == null) return singleOutputItem.Length;
@@ -1181,9 +1184,9 @@ namespace System.Threading.Tasks.Dataflow
                 /// <summary>Gets the messages waiting to be processed.</summary>
                 public IEnumerable<T> InputQueue { get { return _target._messages.ToList(); } }
                 /// <summary>Gets the task being used for input processing.</summary>
-                public Task TaskForInputProcessing { get { return _target._nonGreedyState != null ? _target._nonGreedyState.TaskForInputProcessing : null; } }
+                public Task? TaskForInputProcessing { get { return _target._nonGreedyState != null ? _target._nonGreedyState.TaskForInputProcessing : null; } }
                 /// <summary>Gets the collection of postponed messages.</summary>
-                public QueuedMap<ISourceBlock<T>, DataflowMessageHeader> PostponedMessages { get { return _target._nonGreedyState != null ? _target._nonGreedyState.PostponedMessages : null; } }
+                public QueuedMap<ISourceBlock<T>, DataflowMessageHeader>? PostponedMessages { get { return _target._nonGreedyState != null ? _target._nonGreedyState.PostponedMessages : null; } }
                 /// <summary>Gets whether the block is declining further messages.</summary>
                 public bool IsDecliningPermanently { get { return _target._decliningPermanently; } }
                 /// <summary>Gets the DataflowBlockOptions used to configure this block.</summary>
index 4b961f5..4e4f576 100644 (file)
@@ -99,14 +99,14 @@ namespace System.Threading.Tasks.Dataflow
             // to handle multiple completion requests and to carry over only one.
             _source.Completion.ContinueWith((completed, state) =>
             {
-                var thisBlock = ((BatchedJoinBlock<T1, T2>)state) as IDataflowBlock;
+                var thisBlock = ((BatchedJoinBlock<T1, T2>)state!) as IDataflowBlock;
                 Debug.Assert(completed.IsFaulted, "The source must be faulted in order to trigger a target completion.");
-                thisBlock.Fault(completed.Exception);
+                thisBlock.Fault(completed.Exception!);
             }, this, CancellationToken.None, Common.GetContinuationOptions() | TaskContinuationOptions.OnlyOnFaulted, TaskScheduler.Default);
 
             // Handle async cancellation requests by declining on the target
             Common.WireCancellationToComplete(
-                dataflowBlockOptions.CancellationToken, _source.Completion, state => ((BatchedJoinBlock<T1, T2>)state).CompleteEachTarget(), this);
+                dataflowBlockOptions.CancellationToken, _source.Completion, state => ((BatchedJoinBlock<T1, T2>)state!).CompleteEachTarget(), this);
 #if FEATURE_TRACING
             DataflowEtwProvider etwLog = DataflowEtwProvider.Log;
             if (etwLog.IsEnabled())
@@ -132,13 +132,15 @@ namespace System.Threading.Tasks.Dataflow
         }
 
         /// <include file='XmlDocs/CommonXmlDocComments.xml' path='CommonXmlDocComments/Sources/Member[@name="TryReceive"]/*' />
-        public bool TryReceive(Predicate<Tuple<IList<T1>, IList<T2>>> filter, out Tuple<IList<T1>, IList<T2>> item)
+#pragma warning disable CS8614 // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/42470
+        public bool TryReceive(Predicate<Tuple<IList<T1>, IList<T2>>>? filter, [NotNullWhen(true)] out Tuple<IList<T1>, IList<T2>>? item)
+#pragma warning restore CS8614
         {
             return _source.TryReceive(filter, out item);
         }
 
         /// <include file='XmlDocs/CommonXmlDocComments.xml' path='CommonXmlDocComments/Sources/Member[@name="TryReceiveAll"]/*' />
-        public bool TryReceiveAll(out IList<Tuple<IList<T1>, IList<T2>>> items) { return _source.TryReceiveAll(out items); }
+        public bool TryReceiveAll([NotNullWhen(true)] out IList<Tuple<IList<T1>, IList<T2>>>? items) { return _source.TryReceiveAll(out items); }
 
         /// <include file='XmlDocs/CommonXmlDocComments.xml' path='CommonXmlDocComments/Sources/Member[@name="OutputCount"]/*' />
         public int OutputCount { get { return _source.OutputCount; } }
@@ -173,6 +175,7 @@ namespace System.Threading.Tasks.Dataflow
         }
 
         /// <include file='XmlDocs/CommonXmlDocComments.xml' path='CommonXmlDocComments/Sources/Member[@name="ConsumeMessage"]/*' />
+        [return: MaybeNull]
         Tuple<IList<T1>, IList<T2>> ISourceBlock<Tuple<IList<T1>, IList<T2>>>.ConsumeMessage(
             DataflowMessageHeader messageHeader, ITargetBlock<Tuple<IList<T1>, IList<T2>>> target, out bool messageConsumed)
         {
@@ -254,7 +257,7 @@ namespace System.Threading.Tasks.Dataflow
             public ITargetBlock<T2> Target2 { get { return _batchedJoinBlock._target2; } }
 
             /// <summary>Gets the task being used for output processing.</summary>
-            public Task TaskForOutputProcessing { get { return _sourceDebuggingInformation.TaskForOutputProcessing; } }
+            public Task? TaskForOutputProcessing { get { return _sourceDebuggingInformation.TaskForOutputProcessing; } }
 
             /// <summary>Gets the DataflowBlockOptions used to configure this block.</summary>
             public GroupingDataflowBlockOptions DataflowBlockOptions { get { return (GroupingDataflowBlockOptions)_sourceDebuggingInformation.DataflowBlockOptions; } }
@@ -266,7 +269,7 @@ namespace System.Threading.Tasks.Dataflow
             /// <summary>Gets the set of all targets linked from this block.</summary>
             public TargetRegistry<Tuple<IList<T1>, IList<T2>>> LinkedTargets { get { return _sourceDebuggingInformation.LinkedTargets; } }
             /// <summary>Gets the target that holds a reservation on the next message, if any.</summary>
-            public ITargetBlock<Tuple<IList<T1>, IList<T2>>> NextMessageReservedFor { get { return _sourceDebuggingInformation.NextMessageReservedFor; } }
+            public ITargetBlock<Tuple<IList<T1>, IList<T2>>>? NextMessageReservedFor { get { return _sourceDebuggingInformation.NextMessageReservedFor; } }
         }
     }
 
@@ -357,14 +360,14 @@ namespace System.Threading.Tasks.Dataflow
             // to handle multiple completion requests and to carry over only one.
             _source.Completion.ContinueWith((completed, state) =>
             {
-                var thisBlock = ((BatchedJoinBlock<T1, T2, T3>)state) as IDataflowBlock;
+                var thisBlock = ((BatchedJoinBlock<T1, T2, T3>)state!) as IDataflowBlock;
                 Debug.Assert(completed.IsFaulted, "The source must be faulted in order to trigger a target completion.");
-                thisBlock.Fault(completed.Exception);
+                thisBlock.Fault(completed.Exception!);
             }, this, CancellationToken.None, Common.GetContinuationOptions() | TaskContinuationOptions.OnlyOnFaulted, TaskScheduler.Default);
 
             // Handle async cancellation requests by declining on the target
             Common.WireCancellationToComplete(
-                dataflowBlockOptions.CancellationToken, _source.Completion, state => ((BatchedJoinBlock<T1, T2, T3>)state).CompleteEachTarget(), this);
+                dataflowBlockOptions.CancellationToken, _source.Completion, state => ((BatchedJoinBlock<T1, T2, T3>)state!).CompleteEachTarget(), this);
 #if FEATURE_TRACING
             DataflowEtwProvider etwLog = DataflowEtwProvider.Log;
             if (etwLog.IsEnabled())
@@ -393,13 +396,15 @@ namespace System.Threading.Tasks.Dataflow
         }
 
         /// <include file='XmlDocs/CommonXmlDocComments.xml' path='CommonXmlDocComments/Sources/Member[@name="TryReceive"]/*' />
-        public bool TryReceive(Predicate<Tuple<IList<T1>, IList<T2>, IList<T3>>> filter, out Tuple<IList<T1>, IList<T2>, IList<T3>> item)
+#pragma warning disable CS8614 // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/42470
+        public bool TryReceive(Predicate<Tuple<IList<T1>, IList<T2>, IList<T3>>>? filter, [NotNullWhen(true)] out Tuple<IList<T1>, IList<T2>, IList<T3>>? item)
+#pragma warning restore CS8614
         {
             return _source.TryReceive(filter, out item);
         }
 
         /// <include file='XmlDocs/CommonXmlDocComments.xml' path='CommonXmlDocComments/Sources/Member[@name="TryReceiveAll"]/*' />
-        public bool TryReceiveAll(out IList<Tuple<IList<T1>, IList<T2>, IList<T3>>> items) { return _source.TryReceiveAll(out items); }
+        public bool TryReceiveAll([NotNullWhen(true)] out IList<Tuple<IList<T1>, IList<T2>, IList<T3>>>? items) { return _source.TryReceiveAll(out items); }
 
         /// <include file='XmlDocs/CommonXmlDocComments.xml' path='CommonXmlDocComments/Sources/Member[@name="OutputCount"]/*' />
         public int OutputCount { get { return _source.OutputCount; } }
@@ -436,6 +441,7 @@ namespace System.Threading.Tasks.Dataflow
         }
 
         /// <include file='XmlDocs/CommonXmlDocComments.xml' path='CommonXmlDocComments/Sources/Member[@name="ConsumeMessage"]/*' />
+        [return: MaybeNull]
         Tuple<IList<T1>, IList<T2>, IList<T3>> ISourceBlock<Tuple<IList<T1>, IList<T2>, IList<T3>>>.ConsumeMessage(
             DataflowMessageHeader messageHeader, ITargetBlock<Tuple<IList<T1>, IList<T2>, IList<T3>>> target, out bool messageConsumed)
         {
@@ -520,7 +526,7 @@ namespace System.Threading.Tasks.Dataflow
             public ITargetBlock<T3> Target3 { get { return _batchedJoinBlock._target3; } }
 
             /// <summary>Gets the task being used for output processing.</summary>
-            public Task TaskForOutputProcessing { get { return _sourceDebuggingInformation.TaskForOutputProcessing; } }
+            public Task? TaskForOutputProcessing { get { return _sourceDebuggingInformation.TaskForOutputProcessing; } }
 
             /// <summary>Gets the DataflowBlockOptions used to configure this block.</summary>
             public GroupingDataflowBlockOptions DataflowBlockOptions { get { return (GroupingDataflowBlockOptions)_sourceDebuggingInformation.DataflowBlockOptions; } }
@@ -532,7 +538,7 @@ namespace System.Threading.Tasks.Dataflow
             /// <summary>Gets the set of all targets linked from this block.</summary>
             public TargetRegistry<Tuple<IList<T1>, IList<T2>, IList<T3>>> LinkedTargets { get { return _sourceDebuggingInformation.LinkedTargets; } }
             /// <summary>Gets the target that holds a reservation on the next message, if any.</summary>
-            public ITargetBlock<Tuple<IList<T1>, IList<T2>, IList<T3>>> NextMessageReservedFor { get { return _sourceDebuggingInformation.NextMessageReservedFor; } }
+            public ITargetBlock<Tuple<IList<T1>, IList<T2>, IList<T3>>>? NextMessageReservedFor { get { return _sourceDebuggingInformation.NextMessageReservedFor; } }
         }
     }
 }
@@ -580,7 +586,7 @@ namespace System.Threading.Tasks.Dataflow.Internal
         }
 
         /// <include file='XmlDocs/CommonXmlDocComments.xml' path='CommonXmlDocComments/Targets/Member[@name="OfferMessage"]/*' />
-        public DataflowMessageStatus OfferMessage(DataflowMessageHeader messageHeader, T messageValue, ISourceBlock<T> source, bool consumeToAccept)
+        public DataflowMessageStatus OfferMessage(DataflowMessageHeader messageHeader, T messageValue, ISourceBlock<T>? source, bool consumeToAccept)
         {
             // Validate arguments
             if (!messageHeader.IsValid) throw new ArgumentException(SR.Argument_InvalidMessageHeader, nameof(messageHeader));
@@ -602,7 +608,7 @@ namespace System.Threading.Tasks.Dataflow.Internal
                     messageValue = source.ConsumeMessage(messageHeader, this, out consumed);
                     if (!consumed) return DataflowMessageStatus.NotAvailable;
                 }
-                _messages.Add(messageValue);
+                _messages.Add(messageValue!);
 
                 // If this message makes a batch, notify the shared resources that a batch has been completed
                 if (--_sharedResources._remainingItemsInBatch == 0) _sharedResources._batchSizeReachedAction();
index ab47133..103a124 100644 (file)
@@ -39,7 +39,7 @@ namespace System.Threading.Tasks.Dataflow
         /// <summary>The source side.</summary>
         private readonly BroadcastingSourceCore<T> _source;
         /// <summary>Bounding state for when the block is executing in bounded mode.</summary>
-        private readonly BoundingStateWithPostponedAndTask<T> _boundingState;
+        private readonly BoundingStateWithPostponedAndTask<T>? _boundingState;
         /// <summary>Whether all future messages should be declined.</summary>
         private bool _decliningPermanently;
         /// <summary>A task has reserved the right to run the completion routine.</summary>
@@ -52,7 +52,7 @@ namespace System.Threading.Tasks.Dataflow
         /// The function to use to clone the data when offered to other blocks.
         /// This may be null to indicate that no cloning need be performed.
         /// </param>
-        public BroadcastBlock(Func<T, T> cloningFunction) :
+        public BroadcastBlock(Func<T, T>? cloningFunction) :
             this(cloningFunction, DataflowBlockOptions.Default)
         { }
 
@@ -63,7 +63,7 @@ namespace System.Threading.Tasks.Dataflow
         /// </param>
         /// <param name="dataflowBlockOptions">The options with which to configure this <see cref="BroadcastBlock{T}"/>.</param>
         /// <exception cref="System.ArgumentNullException">The <paramref name="dataflowBlockOptions"/> is null (Nothing in Visual Basic).</exception>
-        public BroadcastBlock(Func<T, T> cloningFunction, DataflowBlockOptions dataflowBlockOptions)
+        public BroadcastBlock(Func<T, T>? cloningFunction, DataflowBlockOptions dataflowBlockOptions)
         {
             // Validate arguments
             if (dataflowBlockOptions == null) throw new ArgumentNullException(nameof(dataflowBlockOptions));
@@ -72,7 +72,7 @@ namespace System.Threading.Tasks.Dataflow
             dataflowBlockOptions = dataflowBlockOptions.DefaultOrClone();
 
             // Initialize bounding state if necessary
-            Action<int> onItemsRemoved = null;
+            Action<int>? onItemsRemoved = null;
             if (dataflowBlockOptions.BoundedCapacity > 0)
             {
                 Debug.Assert(dataflowBlockOptions.BoundedCapacity > 0, "Positive bounding count expected; should have been verified by options ctor");
@@ -89,14 +89,14 @@ namespace System.Threading.Tasks.Dataflow
             // to handle multiple completion requests and to carry over only one.
             _source.Completion.ContinueWith((completed, state) =>
             {
-                var thisBlock = ((BroadcastBlock<T>)state) as IDataflowBlock;
+                var thisBlock = ((BroadcastBlock<T>)state!) as IDataflowBlock;
                 Debug.Assert(completed.IsFaulted, "The source must be faulted in order to trigger a target completion.");
-                thisBlock.Fault(completed.Exception);
+                thisBlock.Fault(completed.Exception!);
             }, this, CancellationToken.None, Common.GetContinuationOptions() | TaskContinuationOptions.OnlyOnFaulted, TaskScheduler.Default);
 
             // Handle async cancellation requests by declining on the target
             Common.WireCancellationToComplete(
-                dataflowBlockOptions.CancellationToken, _source.Completion, state => ((BroadcastBlock<T>)state).Complete(), this);
+                dataflowBlockOptions.CancellationToken, _source.Completion, state => ((BroadcastBlock<T>)state!).Complete(), this);
 #if FEATURE_TRACING
             DataflowEtwProvider etwLog = DataflowEtwProvider.Log;
             if (etwLog.IsEnabled())
@@ -120,7 +120,7 @@ namespace System.Threading.Tasks.Dataflow
             CompleteCore(exception, storeExceptionEvenIfAlreadyCompleting: false);
         }
 
-        internal void CompleteCore(Exception exception, bool storeExceptionEvenIfAlreadyCompleting, bool revertProcessingState = false)
+        internal void CompleteCore(Exception? exception, bool storeExceptionEvenIfAlreadyCompleting, bool revertProcessingState = false)
         {
             Debug.Assert(storeExceptionEvenIfAlreadyCompleting || !revertProcessingState,
                             "Indicating dirty processing state may only come with storeExceptionEvenIfAlreadyCompleting==true.");
@@ -152,16 +152,16 @@ namespace System.Threading.Tasks.Dataflow
         public IDisposable LinkTo(ITargetBlock<T> target, DataflowLinkOptions linkOptions) { return _source.LinkTo(target, linkOptions); }
 
         /// <include file='XmlDocs/CommonXmlDocComments.xml' path='CommonXmlDocComments/Sources/Member[@name="TryReceive"]/*' />
-        public bool TryReceive(Predicate<T> filter, out T item) { return _source.TryReceive(filter, out item); }
+        public bool TryReceive(Predicate<T>? filter, [MaybeNullWhen(false)] out T item) { return _source.TryReceive(filter, out item); }
 
         /// <include file='XmlDocs/CommonXmlDocComments.xml' path='CommonXmlDocComments/Sources/Member[@name="TryReceiveAll"]/*' />
-        bool IReceivableSourceBlock<T>.TryReceiveAll(out IList<T> items) { return _source.TryReceiveAll(out items); }
+        bool IReceivableSourceBlock<T>.TryReceiveAll([NotNullWhen(true)] out IList<T>? items) { return _source.TryReceiveAll(out items); }
 
         /// <include file='XmlDocs/CommonXmlDocComments.xml' path='CommonXmlDocComments/Blocks/Member[@name="Completion"]/*' />
         public Task Completion { get { return _source.Completion; } }
 
         /// <include file='XmlDocs/CommonXmlDocComments.xml' path='CommonXmlDocComments/Targets/Member[@name="OfferMessage"]/*' />
-        DataflowMessageStatus ITargetBlock<T>.OfferMessage(DataflowMessageHeader messageHeader, T messageValue, ISourceBlock<T> source, bool consumeToAccept)
+        DataflowMessageStatus ITargetBlock<T>.OfferMessage(DataflowMessageHeader messageHeader, T messageValue, ISourceBlock<T>? source, bool consumeToAccept)
         {
             // Validate arguments
             if (!messageHeader.IsValid) throw new ArgumentException(SR.Argument_InvalidMessageHeader, nameof(messageHeader));
@@ -197,7 +197,7 @@ namespace System.Threading.Tasks.Dataflow
                     }
 
                     // Once consumed, pass it to the delegate
-                    _source.AddMessage(messageValue);
+                    _source.AddMessage(messageValue!);
                     if (_boundingState != null) _boundingState.CurrentCount += 1; // track this new item against our bound
                     return DataflowMessageStatus.Accepted;
                 }
@@ -255,7 +255,7 @@ namespace System.Threading.Tasks.Dataflow
                 // Create task and store into _taskForInputProcessing prior to scheduling the task
                 // so that _taskForInputProcessing will be visibly set in the task loop.
                 _boundingState.TaskForInputProcessing =
-                    new Task(state => ((BroadcastBlock<T>)state).ConsumeMessagesLoopCore(), this,
+                    new Task(state => ((BroadcastBlock<T>)state!).ConsumeMessagesLoopCore(), this,
                         Common.GetCreationOptionsForTask(isReplacementReplica));
 
 #if FEATURE_TRACING
@@ -269,11 +269,11 @@ namespace System.Threading.Tasks.Dataflow
 #endif
 
                 // Start the task handling scheduling exceptions
-                Exception exception = Common.StartTaskSafe(_boundingState.TaskForInputProcessing, _source.DataflowBlockOptions.TaskScheduler);
+                Exception? exception = Common.StartTaskSafe(_boundingState.TaskForInputProcessing, _source.DataflowBlockOptions.TaskScheduler);
                 if (exception != null)
                 {
                     // Get out from under currently held locks. Complete re-acquires the locks it needs.
-                    Task.Factory.StartNew(exc => CompleteCore(exception: (Exception)exc, storeExceptionEvenIfAlreadyCompleting: true, revertProcessingState: true),
+                    Task.Factory.StartNew(exc => CompleteCore(exception: (Exception)exc!, storeExceptionEvenIfAlreadyCompleting: true, revertProcessingState: true),
                                         exception, CancellationToken.None, Common.GetCreationOptionsForTask(), TaskScheduler.Default);
                 }
             }
@@ -356,7 +356,7 @@ namespace System.Threading.Tasks.Dataflow
                     T consumedValue = sourceAndMessage.Key.ConsumeMessage(sourceAndMessage.Value, this, out consumed);
                     if (consumed)
                     {
-                        _source.AddMessage(consumedValue);
+                        _source.AddMessage(consumedValue!);
                         return true;
                     }
                 }
@@ -387,10 +387,10 @@ namespace System.Threading.Tasks.Dataflow
                 {
                     Task.Factory.StartNew(state =>
                     {
-                        var thisBroadcastBlock = (BroadcastBlock<T>)state;
+                        var thisBroadcastBlock = (BroadcastBlock<T>)state!;
 
                         // Release any postponed messages
-                        List<Exception> exceptions = null;
+                        List<Exception>? exceptions = null;
                         if (thisBroadcastBlock._boundingState != null)
                         {
                             // Note: No locks should be held at this point
@@ -418,6 +418,7 @@ namespace System.Threading.Tasks.Dataflow
         }
 
         /// <include file='XmlDocs/CommonXmlDocComments.xml' path='CommonXmlDocComments/Sources/Member[@name="ConsumeMessage"]/*' />
+        [return: MaybeNull]
         T ISourceBlock<T>.ConsumeMessage(DataflowMessageHeader messageHeader, ITargetBlock<T> target, out bool messageConsumed)
         {
             return _source.ConsumeMessage(messageHeader, target, out messageConsumed);
@@ -482,7 +483,7 @@ namespace System.Threading.Tasks.Dataflow
             public T Value { get { return _broadcastBlock.ValueForDebugger; } }
 
             /// <summary>Gets the task being used for output processing.</summary>
-            public Task TaskForOutputProcessing { get { return _sourceDebuggingInformation.TaskForOutputProcessing; } }
+            public Task? TaskForOutputProcessing { get { return _sourceDebuggingInformation.TaskForOutputProcessing; } }
 
             /// <summary>Gets the DataflowBlockOptions used to configure this block.</summary>
             public DataflowBlockOptions DataflowBlockOptions { get { return _sourceDebuggingInformation.DataflowBlockOptions; } }
@@ -496,7 +497,7 @@ namespace System.Threading.Tasks.Dataflow
             /// <summary>Gets the set of all targets linked from this block.</summary>
             public TargetRegistry<T> LinkedTargets { get { return _sourceDebuggingInformation.LinkedTargets; } }
             /// <summary>Gets the set of all targets linked from this block.</summary>
-            public ITargetBlock<T> NextMessageReservedFor { get { return _sourceDebuggingInformation.NextMessageReservedFor; } }
+            public ITargetBlock<T>? NextMessageReservedFor { get { return _sourceDebuggingInformation.NextMessageReservedFor; } }
         }
 
         /// <summary>Provides a core implementation for blocks that implement <see cref="ISourceBlock{TOutput}"/>.</summary>
@@ -514,7 +515,7 @@ namespace System.Threading.Tasks.Dataflow
             /// An action to be invoked on the owner block when an item is removed.
             /// This may be null if the owner block doesn't need to be notified.
             /// </summary>
-            private readonly Action<int> _itemsRemovedAction;
+            private readonly Action<int>? _itemsRemovedAction;
 
             /// <summary>Gets the object to use as the outgoing lock.</summary>
             private object OutgoingLock { get { return _completionTask; } }
@@ -526,22 +527,23 @@ namespace System.Threading.Tasks.Dataflow
             /// <summary>The options used to configure this block's execution.</summary>
             private readonly DataflowBlockOptions _dataflowBlockOptions;
             /// <summary>The cloning function to use.</summary>
-            private readonly Func<TOutput, TOutput> _cloningFunction;
+            private readonly Func<TOutput, TOutput>? _cloningFunction;
 
             /// <summary>An indicator whether _currentMessage has a value.</summary>
             private bool _currentMessageIsValid;
             /// <summary>The message currently being broadcast.</summary>
-            private TOutput _currentMessage;
+            [AllowNull, MaybeNull]
+            private TOutput _currentMessage = default;
             /// <summary>The target that the next message is reserved for, or null if nothing is reserved.</summary>
-            private ITargetBlock<TOutput> _nextMessageReservedFor;
+            private ITargetBlock<TOutput>? _nextMessageReservedFor;
             /// <summary>Whether this block should again attempt to offer messages to targets.</summary>
             private bool _enableOffering;
             /// <summary>Whether all future messages should be declined.</summary>
             private bool _decliningPermanently;
             /// <summary>The task used to process the output and offer it to targets.</summary>
-            private Task _taskForOutputProcessing;
+            private Task? _taskForOutputProcessing;
             /// <summary>Exceptions that may have occurred and gone unhandled during processing.</summary>
-            private List<Exception> _exceptions;
+            private List<Exception>? _exceptions;
             /// <summary>Counter for message IDs unique within this source block.</summary>
             private long _nextMessageId = 1; // We are going to use this value before incrementing.
             /// <summary>Whether someone has reserved the right to call CompleteBlockOncePossible.</summary>
@@ -554,9 +556,9 @@ namespace System.Threading.Tasks.Dataflow
             /// <param name="itemsRemovedAction">Action to invoke when an item is removed.</param>
             internal BroadcastingSourceCore(
                 BroadcastBlock<TOutput> owningSource,
-                Func<TOutput, TOutput> cloningFunction,
+                Func<TOutput, TOutput>? cloningFunction,
                 DataflowBlockOptions dataflowBlockOptions,
-                Action<int> itemsRemovedAction)
+                Action<int>? itemsRemovedAction)
             {
                 Debug.Assert(owningSource != null, "Must be associated with a broadcast block.");
                 Debug.Assert(dataflowBlockOptions != null, "Options are required to configure this block.");
@@ -572,7 +574,7 @@ namespace System.Threading.Tasks.Dataflow
             }
 
             /// <include file='XmlDocs/CommonXmlDocComments.xml' path='CommonXmlDocComments/Sources/Member[@name="TryReceive"]/*' />
-            internal bool TryReceive(Predicate<TOutput> filter, out TOutput item)
+            internal bool TryReceive(Predicate<TOutput>? filter, [MaybeNullWhen(false)] out TOutput item)
             {
                 // Take the lock only long enough to get the message,
                 // synchronizing with other activities on the block.
@@ -591,9 +593,9 @@ namespace System.Threading.Tasks.Dataflow
 
                 // Clone and hand back a message if we have one and if it passes the filter.
                 // (A null filter means all messages pass.)
-                if (isValid && (filter == null || filter(message)))
+                if (isValid && (filter == null || filter(message!)))
                 {
-                    item = CloneItem(message);
+                    item = CloneItem(message!);
                     return true;
                 }
                 else
@@ -604,7 +606,7 @@ namespace System.Threading.Tasks.Dataflow
             }
 
             /// <include file='XmlDocs/CommonXmlDocComments.xml' path='CommonXmlDocComments/Sources/Member[@name="TryReceiveAll"]/*' />
-            internal bool TryReceiveAll(out IList<TOutput> items)
+            internal bool TryReceiveAll([NotNullWhen(true)] out IList<TOutput>? items)
             {
                 // Try to receive the one item this block may have.
                 // If we can, give back an array of one item. Otherwise, give back null.
@@ -653,7 +655,7 @@ namespace System.Threading.Tasks.Dataflow
                     // and take the necessary locks in a situation where we're sure it won't cause a problem.
                     Task.Factory.StartNew(state =>
                     {
-                        var thisSourceCore = (BroadcastingSourceCore<TOutput>)state;
+                        var thisSourceCore = (BroadcastingSourceCore<TOutput>)state!;
                         lock (thisSourceCore.OutgoingLock)
                         {
                             lock (thisSourceCore.ValueLock)
@@ -698,7 +700,7 @@ namespace System.Threading.Tasks.Dataflow
                 // Offer it to the target.
                 // We must not increment the message ID here. We only do that when we populate _currentMessage, i.e. when we dequeue.
                 bool useCloning = _cloningFunction != null;
-                DataflowMessageStatus result = target.OfferMessage(new DataflowMessageHeader(_nextMessageId), currentMessage, _owningSource, consumeToAccept: useCloning);
+                DataflowMessageStatus result = target.OfferMessage(new DataflowMessageHeader(_nextMessageId), currentMessage!, _owningSource, consumeToAccept: useCloning);
 
                 // If accepted and the target was linked as "unlinkAfterOne", remove it
                 if (result == DataflowMessageStatus.Accepted)
@@ -770,14 +772,14 @@ namespace System.Threading.Tasks.Dataflow
                     if (_itemsRemovedAction != null) _itemsRemovedAction(numDequeuedMessages);
 
                     // Offer it to each target, unless a soleTarget was provided, which case just offer it to that one.
-                    TargetRegistry<TOutput>.LinkedTargetInfo cur = _targetRegistry.FirstTargetNode;
+                    TargetRegistry<TOutput>.LinkedTargetInfo? cur = _targetRegistry.FirstTargetNode;
                     while (cur != null)
                     {
                         // Note that during OfferMessage, a target may call ConsumeMessage, which may unlink the target
                         // if the target is registered as "once".  Doing so will remove the target from the targets list.
                         // As such, we avoid using an enumerator over _targetRegistry and instead walk from back to front,
                         // so that if an element is removed, it won't affect the rest of our walk.
-                        TargetRegistry<TOutput>.LinkedTargetInfo next = cur.Next;
+                        TargetRegistry<TOutput>.LinkedTargetInfo? next = cur.Next;
                         ITargetBlock<TOutput> target = cur.Target;
                         OfferMessageToTarget(header, message, target);
                         cur = next;
@@ -842,7 +844,7 @@ namespace System.Threading.Tasks.Dataflow
                 {
                     // Create task and store into _taskForOutputProcessing prior to scheduling the task
                     // so that _taskForOutputProcessing will be visibly set in the task loop.
-                    _taskForOutputProcessing = new Task(thisSourceCore => ((BroadcastingSourceCore<TOutput>)thisSourceCore).OfferMessagesLoopCore(), this,
+                    _taskForOutputProcessing = new Task(thisSourceCore => ((BroadcastingSourceCore<TOutput>)thisSourceCore!).OfferMessagesLoopCore(), this,
                                                         Common.GetCreationOptionsForTask(isReplacementReplica));
 
 #if FEATURE_TRACING
@@ -855,7 +857,7 @@ namespace System.Threading.Tasks.Dataflow
 #endif
 
                     // Start the task handling scheduling exceptions
-                    Exception exception = Common.StartTaskSafe(_taskForOutputProcessing, _dataflowBlockOptions.TaskScheduler);
+                    Exception? exception = Common.StartTaskSafe(_taskForOutputProcessing, _dataflowBlockOptions.TaskScheduler);
                     if (exception != null)
                     {
                         // First, log the exception while the processing state is dirty which is preventing the block from completing.
@@ -869,7 +871,7 @@ namespace System.Threading.Tasks.Dataflow
                         // Re-take the locks on a separate thread.
                         Task.Factory.StartNew(state =>
                         {
-                            var thisSourceCore = (BroadcastingSourceCore<TOutput>)state;
+                            var thisSourceCore = (BroadcastingSourceCore<TOutput>)state!;
                             lock (thisSourceCore.OutgoingLock)
                             {
                                 lock (thisSourceCore.ValueLock)
@@ -959,7 +961,7 @@ namespace System.Threading.Tasks.Dataflow
                 _completionReserved = true;
 
                 // Run asynchronously to get out of the currently held locks
-                Task.Factory.StartNew(thisSourceCore => ((BroadcastingSourceCore<TOutput>)thisSourceCore).CompleteBlockOncePossible(),
+                Task.Factory.StartNew(thisSourceCore => ((BroadcastingSourceCore<TOutput>)thisSourceCore!).CompleteBlockOncePossible(),
                     this, CancellationToken.None, Common.GetCreationOptionsForTask(), TaskScheduler.Default);
             }
 
@@ -969,8 +971,8 @@ namespace System.Threading.Tasks.Dataflow
             /// </summary>
             private void CompleteBlockOncePossible()
             {
-                TargetRegistry<TOutput>.LinkedTargetInfo linkedTargets;
-                List<Exception> exceptions;
+                TargetRegistry<TOutput>.LinkedTargetInfo? linkedTargets;
+                List<Exception>? exceptions;
 
                 // Clear out the target registry and buffers to help avoid memory leaks.
                 // We do not clear _currentMessage, which should remain as that message forever.
@@ -1048,6 +1050,7 @@ namespace System.Threading.Tasks.Dataflow
             }
 
             /// <include file='XmlDocs/CommonXmlDocComments.xml' path='CommonXmlDocComments/Sources/Member[@name="ConsumeMessage"]/*' />
+            [return: MaybeNull]
             internal TOutput ConsumeMessage(DataflowMessageHeader messageHeader, ITargetBlock<TOutput> target, out bool messageConsumed)
             {
                 // Validate arguments
@@ -1084,7 +1087,7 @@ namespace System.Threading.Tasks.Dataflow
                 }
 
                 messageConsumed = true;
-                return CloneItem(valueToClone);
+                return CloneItem(valueToClone!);
             }
 
             /// <include file='XmlDocs/CommonXmlDocComments.xml' path='CommonXmlDocComments/Sources/Member[@name="ReserveMessage"]/*' />
@@ -1145,7 +1148,7 @@ namespace System.Threading.Tasks.Dataflow
                     // do this if _messages.Count == 0, as if it's > 0 the message will get overwritten
                     // as part of the asynchronous offering, but for consistency we should always reoffer
                     // the current message.
-                    OfferMessageToTarget(messageHeader, messageToReoffer, target);
+                    OfferMessageToTarget(messageHeader, messageToReoffer!, target);
                 }
             }
 
@@ -1223,11 +1226,11 @@ namespace System.Threading.Tasks.Dataflow
                 /// <summary>Gets whether the source contains a current message.</summary>
                 public bool HasValue { get { return _source._currentMessageIsValid; } }
                 /// <summary>Gets the value of the source's current message.</summary>
-                public TOutput Value { get { return _source._currentMessage; } }
+                public TOutput Value { get { return _source._currentMessage!; } }
                 /// <summary>Gets the messages available for receiving.</summary>
                 public IEnumerable<TOutput> InputQueue { get { return _source._messages.ToList(); } }
                 /// <summary>Gets the task being used for output processing.</summary>
-                public Task TaskForOutputProcessing { get { return _source._taskForOutputProcessing; } }
+                public Task? TaskForOutputProcessing { get { return _source._taskForOutputProcessing; } }
 
                 /// <summary>Gets the DataflowBlockOptions used to configure this block.</summary>
                 public DataflowBlockOptions DataflowBlockOptions { get { return _source._dataflowBlockOptions; } }
@@ -1237,7 +1240,7 @@ namespace System.Threading.Tasks.Dataflow
                 /// <summary>Gets the set of all targets linked from this block.</summary>
                 public TargetRegistry<TOutput> LinkedTargets { get { return _source._targetRegistry; } }
                 /// <summary>Gets the target that holds a reservation on the next message, if any.</summary>
-                public ITargetBlock<TOutput> NextMessageReservedFor { get { return _source._nextMessageReservedFor; } }
+                public ITargetBlock<TOutput>? NextMessageReservedFor { get { return _source._nextMessageReservedFor; } }
             }
         }
     }
index d9dce57..806ee15 100644 (file)
@@ -28,7 +28,7 @@ namespace System.Threading.Tasks.Dataflow
         /// <summary>The core logic for the buffer block.</summary>
         private readonly SourceCore<T> _source;
         /// <summary>The bounding state for when in bounding mode; null if not bounding.</summary>
-        private readonly BoundingStateWithPostponedAndTask<T> _boundingState;
+        private readonly BoundingStateWithPostponedAndTask<T>? _boundingState;
         /// <summary>Whether all future messages should be declined on the target.</summary>
         private bool _targetDecliningPermanently;
         /// <summary>A task has reserved the right to run the target's completion routine.</summary>
@@ -52,7 +52,7 @@ namespace System.Threading.Tasks.Dataflow
             dataflowBlockOptions = dataflowBlockOptions.DefaultOrClone();
 
             // Initialize bounding state if necessary
-            Action<ISourceBlock<T>, int> onItemsRemoved = null;
+            Action<ISourceBlock<T>, int>? onItemsRemoved = null;
             if (dataflowBlockOptions.BoundedCapacity > 0)
             {
                 onItemsRemoved = (owningSource, count) => ((BufferBlock<T>)owningSource).OnItemsRemoved(count);
@@ -70,14 +70,14 @@ namespace System.Threading.Tasks.Dataflow
             // to handle multiple completion requests and to carry over only one.
             _source.Completion.ContinueWith((completed, state) =>
             {
-                var thisBlock = ((BufferBlock<T>)state) as IDataflowBlock;
+                var thisBlock = ((BufferBlock<T>)state!) as IDataflowBlock;
                 Debug.Assert(completed.IsFaulted, "The source must be faulted in order to trigger a target completion.");
-                thisBlock.Fault(completed.Exception);
+                thisBlock.Fault(completed.Exception!);
             }, this, CancellationToken.None, Common.GetContinuationOptions() | TaskContinuationOptions.OnlyOnFaulted, TaskScheduler.Default);
 
             // Handle async cancellation requests by declining on the target
             Common.WireCancellationToComplete(
-                dataflowBlockOptions.CancellationToken, _source.Completion, owningSource => ((BufferBlock<T>)owningSource).Complete(), this);
+                dataflowBlockOptions.CancellationToken, _source.Completion, owningSource => ((BufferBlock<T>)owningSource!).Complete(), this);
 #if FEATURE_TRACING
             DataflowEtwProvider etwLog = DataflowEtwProvider.Log;
             if (etwLog.IsEnabled())
@@ -88,7 +88,7 @@ namespace System.Threading.Tasks.Dataflow
         }
 
         /// <include file='XmlDocs/CommonXmlDocComments.xml' path='CommonXmlDocComments/Targets/Member[@name="OfferMessage"]/*' />
-        DataflowMessageStatus ITargetBlock<T>.OfferMessage(DataflowMessageHeader messageHeader, T messageValue, ISourceBlock<T> source, bool consumeToAccept)
+        DataflowMessageStatus ITargetBlock<T>.OfferMessage(DataflowMessageHeader messageHeader, T messageValue, ISourceBlock<T>? source, bool consumeToAccept)
         {
             // Validate arguments
             if (!messageHeader.IsValid) throw new ArgumentException(SR.Argument_InvalidMessageHeader, nameof(messageHeader));
@@ -124,7 +124,7 @@ namespace System.Threading.Tasks.Dataflow
                     }
 
                     // Once consumed, pass it to the source
-                    _source.AddMessage(messageValue);
+                    _source.AddMessage(messageValue!);
                     if (_boundingState != null) _boundingState.CurrentCount++;
 
                     return DataflowMessageStatus.Accepted;
@@ -154,7 +154,7 @@ namespace System.Threading.Tasks.Dataflow
             CompleteCore(exception, storeExceptionEvenIfAlreadyCompleting: false);
         }
 
-        private void CompleteCore(Exception exception, bool storeExceptionEvenIfAlreadyCompleting, bool revertProcessingState = false)
+        private void CompleteCore(Exception? exception, bool storeExceptionEvenIfAlreadyCompleting, bool revertProcessingState = false)
         {
             Debug.Assert(storeExceptionEvenIfAlreadyCompleting || !revertProcessingState,
                             "Indicating dirty processing state may only come with storeExceptionEvenIfAlreadyCompleting==true.");
@@ -186,10 +186,10 @@ namespace System.Threading.Tasks.Dataflow
         public IDisposable LinkTo(ITargetBlock<T> target, DataflowLinkOptions linkOptions) { return _source.LinkTo(target, linkOptions); }
 
         /// <include file='XmlDocs/CommonXmlDocComments.xml' path='CommonXmlDocComments/Sources/Member[@name="TryReceive"]/*' />
-        public bool TryReceive(Predicate<T> filter, out T item) { return _source.TryReceive(filter, out item); }
+        public bool TryReceive(Predicate<T>? filter, [MaybeNullWhen(false)] out T item) { return _source.TryReceive(filter, out item); }
 
         /// <include file='XmlDocs/CommonXmlDocComments.xml' path='CommonXmlDocComments/Sources/Member[@name="TryReceiveAll"]/*' />
-        public bool TryReceiveAll(out IList<T> items) { return _source.TryReceiveAll(out items); }
+        public bool TryReceiveAll([NotNullWhen(true)] out IList<T>? items) { return _source.TryReceiveAll(out items); }
 
         /// <summary>Gets the number of items currently stored in the buffer.</summary>
         public int Count { get { return _source.OutputCount; } }
@@ -198,6 +198,7 @@ namespace System.Threading.Tasks.Dataflow
         public Task Completion { get { return _source.Completion; } }
 
         /// <include file='XmlDocs/CommonXmlDocComments.xml' path='CommonXmlDocComments/Sources/Member[@name="ConsumeMessage"]/*' />
+        [return: MaybeNull]
         T ISourceBlock<T>.ConsumeMessage(DataflowMessageHeader messageHeader, ITargetBlock<T> target, out bool messageConsumed)
         {
             return _source.ConsumeMessage(messageHeader, target, out messageConsumed);
@@ -255,7 +256,7 @@ namespace System.Threading.Tasks.Dataflow
                 // Create task and store into _taskForInputProcessing prior to scheduling the task
                 // so that _taskForInputProcessing will be visibly set in the task loop.
                 _boundingState.TaskForInputProcessing =
-                    new Task(state => ((BufferBlock<T>)state).ConsumeMessagesLoopCore(), this,
+                    new Task(state => ((BufferBlock<T>)state!).ConsumeMessagesLoopCore(), this,
                         Common.GetCreationOptionsForTask(isReplacementReplica));
 
 #if FEATURE_TRACING
@@ -269,11 +270,11 @@ namespace System.Threading.Tasks.Dataflow
 #endif
 
                 // Start the task handling scheduling exceptions
-                Exception exception = Common.StartTaskSafe(_boundingState.TaskForInputProcessing, _source.DataflowBlockOptions.TaskScheduler);
+                Exception? exception = Common.StartTaskSafe(_boundingState.TaskForInputProcessing, _source.DataflowBlockOptions.TaskScheduler);
                 if (exception != null)
                 {
                     // Get out from under currently held locks. CompleteCore re-acquires the locks it needs.
-                    Task.Factory.StartNew(exc => CompleteCore(exception: (Exception)exc, storeExceptionEvenIfAlreadyCompleting: true, revertProcessingState: true),
+                    Task.Factory.StartNew(exc => CompleteCore(exception: (Exception)exc!, storeExceptionEvenIfAlreadyCompleting: true, revertProcessingState: true),
                                         exception, CancellationToken.None, Common.GetCreationOptionsForTask(), TaskScheduler.Default);
                 }
             }
@@ -358,7 +359,7 @@ namespace System.Threading.Tasks.Dataflow
                     T consumedValue = sourceAndMessage.Key.ConsumeMessage(sourceAndMessage.Value, this, out consumed);
                     if (consumed)
                     {
-                        _source.AddMessage(consumedValue);
+                        _source.AddMessage(consumedValue!);
                         return true;
                     }
                 }
@@ -389,10 +390,10 @@ namespace System.Threading.Tasks.Dataflow
                 {
                     Task.Factory.StartNew(state =>
                     {
-                        var thisBufferBlock = (BufferBlock<T>)state;
+                        var thisBufferBlock = (BufferBlock<T>)state!;
 
                         // Release any postponed messages
-                        List<Exception> exceptions = null;
+                        List<Exception>? exceptions = null;
                         if (thisBufferBlock._boundingState != null)
                         {
                             // Note: No locks should be held at this point
@@ -456,7 +457,7 @@ namespace System.Threading.Tasks.Dataflow
             }
 
             /// <summary>Gets the collection of postponed message headers.</summary>
-            public QueuedMap<ISourceBlock<T>, DataflowMessageHeader> PostponedMessages
+            public QueuedMap<ISourceBlock<T>, DataflowMessageHeader>? PostponedMessages
             {
                 get { return _bufferBlock._boundingState != null ? _bufferBlock._boundingState.PostponedMessages : null; }
             }
@@ -464,9 +465,9 @@ namespace System.Threading.Tasks.Dataflow
             public IEnumerable<T> Queue { get { return _sourceDebuggingInformation.OutputQueue; } }
 
             /// <summary>The task used to process messages.</summary>
-            public Task TaskForInputProcessing { get { return _bufferBlock._boundingState != null ? _bufferBlock._boundingState.TaskForInputProcessing : null; } }
+            public Task? TaskForInputProcessing { get { return _bufferBlock._boundingState != null ? _bufferBlock._boundingState.TaskForInputProcessing : null; } }
             /// <summary>Gets the task being used for output processing.</summary>
-            public Task TaskForOutputProcessing { get { return _sourceDebuggingInformation.TaskForOutputProcessing; } }
+            public Task? TaskForOutputProcessing { get { return _sourceDebuggingInformation.TaskForOutputProcessing; } }
 
             /// <summary>Gets the DataflowBlockOptions used to configure this block.</summary>
             public DataflowBlockOptions DataflowBlockOptions { get { return _sourceDebuggingInformation.DataflowBlockOptions; } }
@@ -481,7 +482,7 @@ namespace System.Threading.Tasks.Dataflow
             /// <summary>Gets the set of all targets linked from this block.</summary>
             public TargetRegistry<T> LinkedTargets { get { return _sourceDebuggingInformation.LinkedTargets; } }
             /// <summary>Gets the set of all targets linked from this block.</summary>
-            public ITargetBlock<T> NextMessageReservedFor { get { return _sourceDebuggingInformation.NextMessageReservedFor; } }
+            public ITargetBlock<T>? NextMessageReservedFor { get { return _sourceDebuggingInformation.NextMessageReservedFor; } }
         }
     }
 }
index b5d4052..9d8b1ad 100644 (file)
@@ -57,7 +57,7 @@ namespace System.Threading.Tasks.Dataflow
             dataflowBlockOptions = dataflowBlockOptions.DefaultOrClone();
 
             // Initialize bounding state if necessary
-            Action<ISourceBlock<Tuple<T1, T2>>, int> onItemsRemoved = null;
+            Action<ISourceBlock<Tuple<T1, T2>>, int>? onItemsRemoved = null;
             if (dataflowBlockOptions.BoundedCapacity > 0) onItemsRemoved = (owningSource, count) => ((JoinBlock<T1, T2>)owningSource)._sharedResources.OnItemsRemoved(count);
 
             // Configure the source
@@ -93,14 +93,14 @@ namespace System.Threading.Tasks.Dataflow
             // to handle multiple completion requests and to carry over only one.
             _source.Completion.ContinueWith((completed, state) =>
             {
-                var thisBlock = ((JoinBlock<T1, T2>)state) as IDataflowBlock;
+                var thisBlock = ((JoinBlock<T1, T2>)state!) as IDataflowBlock;
                 Debug.Assert(completed.IsFaulted, "The source must be faulted in order to trigger a target completion.");
-                thisBlock.Fault(completed.Exception);
+                thisBlock.Fault(completed.Exception!);
             }, this, CancellationToken.None, Common.GetContinuationOptions() | TaskContinuationOptions.OnlyOnFaulted, TaskScheduler.Default);
 
             // Handle async cancellation requests by declining on the target
             Common.WireCancellationToComplete(
-                dataflowBlockOptions.CancellationToken, _source.Completion, state => ((JoinBlock<T1, T2>)state)._sharedResources.CompleteEachTarget(), this);
+                dataflowBlockOptions.CancellationToken, _source.Completion, state => ((JoinBlock<T1, T2>)state!)._sharedResources.CompleteEachTarget(), this);
 #if FEATURE_TRACING
             DataflowEtwProvider etwLog = DataflowEtwProvider.Log;
             if (etwLog.IsEnabled())
@@ -117,13 +117,15 @@ namespace System.Threading.Tasks.Dataflow
         }
 
         /// <include file='XmlDocs/CommonXmlDocComments.xml' path='CommonXmlDocComments/Sources/Member[@name="TryReceive"]/*' />
-        public bool TryReceive(Predicate<Tuple<T1, T2>> filter, out Tuple<T1, T2> item)
+#pragma warning disable CS8614 // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/42470
+        public bool TryReceive(Predicate<Tuple<T1, T2>>? filter, [NotNullWhen(true)] out Tuple<T1, T2>? item)
+#pragma warning restore CS8614
         {
             return _source.TryReceive(filter, out item);
         }
 
         /// <include file='XmlDocs/CommonXmlDocComments.xml' path='CommonXmlDocComments/Sources/Member[@name="TryReceiveAll"]/*' />
-        public bool TryReceiveAll(out IList<Tuple<T1, T2>> items) { return _source.TryReceiveAll(out items); }
+        public bool TryReceiveAll([NotNullWhen(true)] out IList<Tuple<T1, T2>>? items) { return _source.TryReceiveAll(out items); }
 
         /// <include file='XmlDocs/CommonXmlDocComments.xml' path='CommonXmlDocComments/Sources/Member[@name="OutputCount"]/*' />
         public int OutputCount { get { return _source.OutputCount; } }
@@ -164,7 +166,9 @@ namespace System.Threading.Tasks.Dataflow
         public ITargetBlock<T2> Target2 { get { return _target2; } }
 
         /// <include file='XmlDocs/CommonXmlDocComments.xml' path='CommonXmlDocComments/Sources/Member[@name="ConsumeMessage"]/*' />
-        Tuple<T1, T2> ISourceBlock<Tuple<T1, T2>>.ConsumeMessage(DataflowMessageHeader messageHeader, ITargetBlock<Tuple<T1, T2>> target, out bool messageConsumed)
+#pragma warning disable CS8616 // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/42470
+        Tuple<T1, T2>? ISourceBlock<Tuple<T1, T2>>.ConsumeMessage(DataflowMessageHeader messageHeader, ITargetBlock<Tuple<T1, T2>> target, out bool messageConsumed)
+#pragma warning restore CS8616
         {
             return _source.ConsumeMessage(messageHeader, target, out messageConsumed);
         }
@@ -223,9 +227,9 @@ namespace System.Threading.Tasks.Dataflow
             public long JoinsCreated { get { return _joinBlock._sharedResources._joinsCreated; } }
 
             /// <summary>Gets the task being used for input processing.</summary>
-            public Task TaskForInputProcessing { get { return _joinBlock._sharedResources._taskForInputProcessing; } }
+            public Task? TaskForInputProcessing { get { return _joinBlock._sharedResources._taskForInputProcessing; } }
             /// <summary>Gets the task being used for output processing.</summary>
-            public Task TaskForOutputProcessing { get { return _sourceDebuggingInformation.TaskForOutputProcessing; } }
+            public Task? TaskForOutputProcessing { get { return _sourceDebuggingInformation.TaskForOutputProcessing; } }
 
             /// <summary>Gets the GroupingDataflowBlockOptions used to configure this block.</summary>
             public GroupingDataflowBlockOptions DataflowBlockOptions { get { return (GroupingDataflowBlockOptions)_sourceDebuggingInformation.DataflowBlockOptions; } }
@@ -244,7 +248,7 @@ namespace System.Threading.Tasks.Dataflow
             /// <summary>Gets the set of all targets linked from this block.</summary>
             public TargetRegistry<Tuple<T1, T2>> LinkedTargets { get { return _sourceDebuggingInformation.LinkedTargets; } }
             /// <summary>Gets the set of all targets linked from this block.</summary>
-            public ITargetBlock<Tuple<T1, T2>> NextMessageReservedFor { get { return _sourceDebuggingInformation.NextMessageReservedFor; } }
+            public ITargetBlock<Tuple<T1, T2>>? NextMessageReservedFor { get { return _sourceDebuggingInformation.NextMessageReservedFor; } }
         }
     }
 
@@ -287,7 +291,7 @@ namespace System.Threading.Tasks.Dataflow
             dataflowBlockOptions = dataflowBlockOptions.DefaultOrClone();
 
             // Initialize bounding state if necessary
-            Action<ISourceBlock<Tuple<T1, T2, T3>>, int> onItemsRemoved = null;
+            Action<ISourceBlock<Tuple<T1, T2, T3>>, int>? onItemsRemoved = null;
             if (dataflowBlockOptions.BoundedCapacity > 0) onItemsRemoved = (owningSource, count) => ((JoinBlock<T1, T2, T3>)owningSource)._sharedResources.OnItemsRemoved(count);
 
             // Configure the source
@@ -321,14 +325,14 @@ namespace System.Threading.Tasks.Dataflow
             // to handle multiple completion requests and to carry over only one.
             _source.Completion.ContinueWith((completed, state) =>
             {
-                var thisBlock = ((JoinBlock<T1, T2, T3>)state) as IDataflowBlock;
+                var thisBlock = ((JoinBlock<T1, T2, T3>)state!) as IDataflowBlock;
                 Debug.Assert(completed.IsFaulted, "The source must be faulted in order to trigger a target completion.");
-                thisBlock.Fault(completed.Exception);
+                thisBlock.Fault(completed.Exception!);
             }, this, CancellationToken.None, Common.GetContinuationOptions() | TaskContinuationOptions.OnlyOnFaulted, TaskScheduler.Default);
 
             // Handle async cancellation requests by declining on the target
             Common.WireCancellationToComplete(
-                dataflowBlockOptions.CancellationToken, _source.Completion, state => ((JoinBlock<T1, T2, T3>)state)._sharedResources.CompleteEachTarget(), this);
+                dataflowBlockOptions.CancellationToken, _source.Completion, state => ((JoinBlock<T1, T2, T3>)state!)._sharedResources.CompleteEachTarget(), this);
 #if FEATURE_TRACING
             DataflowEtwProvider etwLog = DataflowEtwProvider.Log;
             if (etwLog.IsEnabled())
@@ -345,13 +349,15 @@ namespace System.Threading.Tasks.Dataflow
         }
 
         /// <include file='XmlDocs/CommonXmlDocComments.xml' path='CommonXmlDocComments/Sources/Member[@name="TryReceive"]/*' />
-        public bool TryReceive(Predicate<Tuple<T1, T2, T3>> filter, out Tuple<T1, T2, T3> item)
+#pragma warning disable CS8614 // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/42470
+        public bool TryReceive(Predicate<Tuple<T1, T2, T3>>? filter, [NotNullWhen(true)] out Tuple<T1, T2, T3>? item)
+#pragma warning restore CS8614
         {
             return _source.TryReceive(filter, out item);
         }
 
         /// <include file='XmlDocs/CommonXmlDocComments.xml' path='CommonXmlDocComments/Sources/Member[@name="TryReceiveAll"]/*' />
-        public bool TryReceiveAll(out IList<Tuple<T1, T2, T3>> items) { return _source.TryReceiveAll(out items); }
+        public bool TryReceiveAll([NotNullWhen(true)] out IList<Tuple<T1, T2, T3>>? items) { return _source.TryReceiveAll(out items); }
 
         /// <include file='XmlDocs/CommonXmlDocComments.xml' path='CommonXmlDocComments/Sources/Member[@name="OutputCount"]/*' />
         public int OutputCount { get { return _source.OutputCount; } }
@@ -397,7 +403,9 @@ namespace System.Threading.Tasks.Dataflow
         public ITargetBlock<T3> Target3 { get { return _target3; } }
 
         /// <include file='XmlDocs/CommonXmlDocComments.xml' path='CommonXmlDocComments/Sources/Member[@name="ConsumeMessage"]/*' />
-        Tuple<T1, T2, T3> ISourceBlock<Tuple<T1, T2, T3>>.ConsumeMessage(DataflowMessageHeader messageHeader, ITargetBlock<Tuple<T1, T2, T3>> target, out bool messageConsumed)
+#pragma warning disable CS8616 // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/42470
+        Tuple<T1, T2, T3>? ISourceBlock<Tuple<T1, T2, T3>>.ConsumeMessage(DataflowMessageHeader messageHeader, ITargetBlock<Tuple<T1, T2, T3>> target, out bool messageConsumed)
+#pragma warning restore CS8616
         {
             return _source.ConsumeMessage(messageHeader, target, out messageConsumed);
         }
@@ -456,9 +464,9 @@ namespace System.Threading.Tasks.Dataflow
             public long JoinsCreated { get { return _joinBlock._sharedResources._joinsCreated; } }
 
             /// <summary>Gets the task being used for input processing.</summary>
-            public Task TaskForInputProcessing { get { return _joinBlock._sharedResources._taskForInputProcessing; } }
+            public Task? TaskForInputProcessing { get { return _joinBlock._sharedResources._taskForInputProcessing; } }
             /// <summary>Gets the task being used for output processing.</summary>
-            public Task TaskForOutputProcessing { get { return _sourceDebuggingInformation.TaskForOutputProcessing; } }
+            public Task? TaskForOutputProcessing { get { return _sourceDebuggingInformation.TaskForOutputProcessing; } }
 
             /// <summary>Gets the GroupingDataflowBlockOptions used to configure this block.</summary>
             public GroupingDataflowBlockOptions DataflowBlockOptions { get { return (GroupingDataflowBlockOptions)_sourceDebuggingInformation.DataflowBlockOptions; } }
@@ -479,7 +487,7 @@ namespace System.Threading.Tasks.Dataflow
             /// <summary>Gets the set of all targets linked from this block.</summary>
             public TargetRegistry<Tuple<T1, T2, T3>> LinkedTargets { get { return _sourceDebuggingInformation.LinkedTargets; } }
             /// <summary>Gets the set of all targets linked from this block.</summary>
-            public ITargetBlock<Tuple<T1, T2, T3>> NextMessageReservedFor { get { return _sourceDebuggingInformation.NextMessageReservedFor; } }
+            public ITargetBlock<Tuple<T1, T2, T3>>? NextMessageReservedFor { get { return _sourceDebuggingInformation.NextMessageReservedFor; } }
         }
     }
 }
@@ -497,9 +505,9 @@ namespace System.Threading.Tasks.Dataflow.Internal
         /// <summary>A task representing the completion of the block.</summary>
         private readonly TaskCompletionSource<VoidResult> _completionTask = new TaskCompletionSource<VoidResult>();
         /// <summary>Input messages for the next batch.</summary>
-        private readonly Queue<T> _messages;
+        private readonly Queue<T>? _messages;
         /// <summary>State used when in non-greedy mode.</summary>
-        private readonly NonGreedyState _nonGreedy;
+        private readonly NonGreedyState? _nonGreedy;
         /// <summary>Whether this target is declining future messages.</summary>
         private bool _decliningPermanently;
 
@@ -540,9 +548,9 @@ namespace System.Threading.Tasks.Dataflow.Internal
             }
             else
             {
-                Debug.Assert(_nonGreedy.ConsumedMessage.Key, "A message must have been consumed by this point.");
+                Debug.Assert(_nonGreedy!.ConsumedMessage.Key, "A message must have been consumed by this point.");
                 T value = _nonGreedy.ConsumedMessage.Value;
-                _nonGreedy.ConsumedMessage = new KeyValuePair<bool, T>(false, default(T));
+                _nonGreedy.ConsumedMessage = new KeyValuePair<bool, T>(false, default(T)!);
                 return value;
             }
         }
@@ -570,7 +578,7 @@ namespace System.Threading.Tasks.Dataflow.Internal
                 }
                 else
                 {
-                    return _nonGreedy.ConsumedMessage.Key;
+                    return _nonGreedy!.ConsumedMessage.Key;
                 }
             }
         }
@@ -591,7 +599,7 @@ namespace System.Threading.Tasks.Dataflow.Internal
             get
             {
                 Common.ContractAssertMonitorStatus(_sharedResources.IncomingLock, held: true);
-                return !_sharedResources._dataflowBlockOptions.Greedy ? _nonGreedy.PostponedMessages.Count : _messages.Count;
+                return !_sharedResources._dataflowBlockOptions.Greedy ? _nonGreedy!.PostponedMessages.Count : _messages!.Count;
             }
         }
 
@@ -604,7 +612,7 @@ namespace System.Threading.Tasks.Dataflow.Internal
                 Common.ContractAssertMonitorStatus(_sharedResources.IncomingLock, held: true);
 
                 // Note: If there is a tie, we must return true
-                int count = _messages.Count;
+                int count = _messages!.Count;
                 foreach (JoinBlockTargetBase target in _sharedResources._targets)
                     if (target != this && target.NumberOfMessagesAvailableOrPostponed > count)
                         return false; // Strictly bigger!
@@ -628,7 +636,7 @@ namespace System.Threading.Tasks.Dataflow.Internal
 
                 // While we are holding the lock, try to pop a postponed message.
                 // If there are no postponed messages, we can't do anything.
-                if (!_nonGreedy.PostponedMessages.TryPop(out next)) return false;
+                if (!_nonGreedy!.PostponedMessages.TryPop(out next)) return false;
             }
 
             // We'll bail out of this loop either when we have reserved a message (true)
@@ -658,7 +666,7 @@ namespace System.Threading.Tasks.Dataflow.Internal
         {
             Common.ContractAssertMonitorStatus(_sharedResources.IncomingLock, held: false);
             Debug.Assert(!_sharedResources._dataflowBlockOptions.Greedy, "This is only used in non-greedy mode");
-            Debug.Assert(_nonGreedy.ReservedMessage.Key != null, "This target must have a reserved message");
+            Debug.Assert(_nonGreedy!.ReservedMessage.Key != null, "This target must have a reserved message");
 
             bool consumed;
             T consumedValue = _nonGreedy.ReservedMessage.Key.ConsumeMessage(_nonGreedy.ReservedMessage.Value, this, out consumed);
@@ -685,7 +693,7 @@ namespace System.Threading.Tasks.Dataflow.Internal
                 {
                     // Now that we've consumed it, store its data.
                     Debug.Assert(!_nonGreedy.ConsumedMessage.Key, "There must be no other consumed message");
-                    _nonGreedy.ConsumedMessage = new KeyValuePair<bool, T>(true, consumedValue);
+                    _nonGreedy.ConsumedMessage = new KeyValuePair<bool, T>(true, consumedValue!);
                     // We don't account bounding per target in non-greedy mode. We do it once per batch (in the loop).
 
                     CompleteIfLastJoinIsFeasible();
@@ -716,7 +724,7 @@ namespace System.Threading.Tasks.Dataflow.Internal
                     hasTheHighestNumberOfMessagesAvailable = HasTheHighestNumberOfMessagesAvailable;
                     bool boundingCapacityAvailable = _sharedResources._boundingState.CountIsLessThanBound || !hasTheHighestNumberOfMessagesAvailable;
                     if (_decliningPermanently || _sharedResources._decliningPermanently ||
-                        !boundingCapacityAvailable || !_nonGreedy.PostponedMessages.TryPop(out next))
+                        !boundingCapacityAvailable || !_nonGreedy!.PostponedMessages.TryPop(out next))
                         return false;
                 }
 
@@ -729,7 +737,7 @@ namespace System.Threading.Tasks.Dataflow.Internal
                     {
                         // The ranking in highest number of available messages cannot have changed because this task is causing OfferMessage to postpone
                         if (hasTheHighestNumberOfMessagesAvailable) _sharedResources._boundingState.CurrentCount += 1; // track this new item against our bound
-                        _messages.Enqueue(consumedValue);
+                        _messages!.Enqueue(consumedValue!);
 
                         CompleteIfLastJoinIsFeasible();
                         return true;
@@ -746,8 +754,8 @@ namespace System.Threading.Tasks.Dataflow.Internal
         {
             Common.ContractAssertMonitorStatus(_sharedResources.IncomingLock, held: true);
             int messageCount = _sharedResources._dataflowBlockOptions.Greedy ?
-                                    _messages.Count :
-                                    _nonGreedy.ConsumedMessage.Key ? 1 : 0;
+                                    _messages!.Count :
+                                    _nonGreedy!.ConsumedMessage.Key ? 1 : 0;
             if ((_sharedResources._joinsCreated + messageCount) >= _sharedResources._dataflowBlockOptions.ActualMaxNumberOfGroups)
             {
                 _decliningPermanently = true;
@@ -806,7 +814,7 @@ namespace System.Threading.Tasks.Dataflow.Internal
             }
 
             // Release any postponed messages
-            List<Exception> exceptions = null;
+            List<Exception>? exceptions = null;
             if (_nonGreedy != null)
             {
                 // Note: No locks should be held at this point
@@ -830,7 +838,7 @@ namespace System.Threading.Tasks.Dataflow.Internal
         }
 
         /// <include file='XmlDocs/CommonXmlDocComments.xml' path='CommonXmlDocComments/Targets/Member[@name="OfferMessage"]/*' />
-        DataflowMessageStatus ITargetBlock<T>.OfferMessage(DataflowMessageHeader messageHeader, T messageValue, ISourceBlock<T> source, bool consumeToAccept)
+        DataflowMessageStatus ITargetBlock<T>.OfferMessage(DataflowMessageHeader messageHeader, T messageValue, ISourceBlock<T>? source, bool consumeToAccept)
         {
             // Validate arguments
             if (!messageHeader.IsValid) throw new ArgumentException(SR.Argument_InvalidMessageHeader, nameof(messageHeader));
@@ -855,7 +863,7 @@ namespace System.Threading.Tasks.Dataflow.Internal
                         (_sharedResources._boundingState == null
                             ||
                          ((_sharedResources._boundingState.CountIsLessThanBound || !HasTheHighestNumberOfMessagesAvailable) &&
-                          _nonGreedy.PostponedMessages.Count == 0 && _sharedResources._taskForInputProcessing == null)))
+                          _nonGreedy!.PostponedMessages.Count == 0 && _sharedResources._taskForInputProcessing == null)))
                 {
                     if (consumeToAccept)
                     {
@@ -866,7 +874,7 @@ namespace System.Threading.Tasks.Dataflow.Internal
                         if (!consumed) return DataflowMessageStatus.NotAvailable;
                     }
                     if (_sharedResources._boundingState != null && HasTheHighestNumberOfMessagesAvailable) _sharedResources._boundingState.CurrentCount += 1; // track this new item against our bound
-                    _messages.Enqueue(messageValue);
+                    _messages!.Enqueue(messageValue!);
                     CompleteIfLastJoinIsFeasible();
 
                     // Since we're in greedy mode, we can skip asynchronous processing and
@@ -899,7 +907,7 @@ namespace System.Threading.Tasks.Dataflow.Internal
         /// In general, it is not safe to pass releaseReservedMessages:true, because releasing of reserved messages
         /// is done without taking a lock. We pass releaseReservedMessages:true only when an exception has been
         /// caught inside the message processing loop which is a single instance at any given moment.</summary>
-        internal override void CompleteCore(Exception exception, bool dropPendingMessages, bool releaseReservedMessages)
+        internal override void CompleteCore(Exception? exception, bool dropPendingMessages, bool releaseReservedMessages)
         {
             bool greedy = _sharedResources._dataflowBlockOptions.Greedy;
             lock (_sharedResources.IncomingLock)
@@ -954,7 +962,7 @@ namespace System.Threading.Tasks.Dataflow.Internal
         internal Task CompletionTaskInternal { get { return _completionTask.Task; } }
 
         /// <summary>Gets the number of messages waiting to be processed.  This must only be used from the debugger as it avoids taking necessary locks.</summary>
-        private int InputCountForDebugger { get { return _messages != null ? _messages.Count : _nonGreedy.ConsumedMessage.Key ? 1 : 0; } }
+        private int InputCountForDebugger { get { return _messages != null ? _messages.Count : _nonGreedy!.ConsumedMessage.Key ? 1 : 0; } }
 
         /// <summary>The data to display in the debugger display attribute.</summary>
         private object DebuggerDisplayContent
@@ -986,7 +994,7 @@ namespace System.Threading.Tasks.Dataflow.Internal
             }
 
             /// <summary>Gets the messages waiting to be processed.</summary>
-            public IEnumerable<T> InputQueue { get { return _joinBlockTarget._messages; } }
+            public IEnumerable<T>? InputQueue { get { return _joinBlockTarget._messages; } }
             /// <summary>Gets whether the block is declining further messages.</summary>
             public bool IsDecliningPermanently { get { return _joinBlockTarget._decliningPermanently || _joinBlockTarget._sharedResources._decliningPermanently; } }
         }
@@ -1023,7 +1031,7 @@ namespace System.Threading.Tasks.Dataflow.Internal
         /// <summary>Access point to the corresponding API method.</summary>
         public void Complete() { CompleteCore(exception: null, dropPendingMessages: false, releaseReservedMessages: false); }
         /// <summary>Internal implementation of the corresponding API method.</summary>
-        internal abstract void CompleteCore(Exception exception, bool dropPendingMessages, bool releaseReservedMessages);
+        internal abstract void CompleteCore(Exception? exception, bool dropPendingMessages, bool releaseReservedMessages);
         /// <summary>Completes the target.</summary>
         internal abstract void CompleteOncePossible();
     }
@@ -1075,11 +1083,11 @@ namespace System.Threading.Tasks.Dataflow.Internal
         /// <summary>The options for the join.</summary>
         internal readonly GroupingDataflowBlockOptions _dataflowBlockOptions;
         /// <summary>Bounding state for when the block is executing in bounded mode.</summary>
-        internal readonly BoundingState _boundingState;
+        internal readonly BoundingState? _boundingState;
         /// <summary>Whether all targets should decline all further messages.</summary>
         internal bool _decliningPermanently;
         /// <summary>The task used to process messages.</summary>
-        internal Task _taskForInputProcessing;
+        internal Task? _taskForInputProcessing;
         /// <summary>Whether any exceptions have been generated and stored into the source core.</summary>
         internal bool _hasExceptions;
         /// <summary>The number of joins this block has created.</summary>
@@ -1286,7 +1294,7 @@ namespace System.Threading.Tasks.Dataflow.Internal
 
             // Create task and store into _taskForInputProcessing prior to scheduling the task
             // so that _taskForInputProcessing will be visibly set in the task loop.
-            _taskForInputProcessing = new Task(thisSharedResources => ((JoinBlockTargetSharedResources)thisSharedResources).ProcessMessagesLoopCore(), this,
+            _taskForInputProcessing = new Task(thisSharedResources => ((JoinBlockTargetSharedResources)thisSharedResources!).ProcessMessagesLoopCore(), this,
                                                 Common.GetCreationOptionsForTask(isReplacementReplica));
 
 #if FEATURE_TRACING
@@ -1300,7 +1308,7 @@ namespace System.Threading.Tasks.Dataflow.Internal
 #endif
 
             // Start the task handling scheduling exceptions
-            Exception exception = Common.StartTaskSafe(_taskForInputProcessing, _dataflowBlockOptions.TaskScheduler);
+            Exception? exception = Common.StartTaskSafe(_taskForInputProcessing, _dataflowBlockOptions.TaskScheduler);
             if (exception != null)
             {
                 // All of the following actions must be performed under the lock.
@@ -1354,7 +1362,7 @@ namespace System.Threading.Tasks.Dataflow.Internal
                     // Complete each target asynchronously so as not to invoke synchronous continuations under a lock
                     Task.Factory.StartNew(state =>
                     {
-                        var sharedResources = (JoinBlockTargetSharedResources)state;
+                        var sharedResources = (JoinBlockTargetSharedResources)state!;
                         foreach (JoinBlockTargetBase target in sharedResources._targets) target.CompleteOncePossible();
                     }, this, CancellationToken.None, Common.GetCreationOptionsForTask(), TaskScheduler.Default);
                 }
index 1dacf7e..c79e9db 100644 (file)
@@ -28,7 +28,7 @@ namespace System.Threading.Tasks.Dataflow
         /// <summary>The target side.</summary>
         private readonly TargetCore<TInput> _target;
         /// <summary>Buffer used to reorder outputs that may have completed out-of-order between the target half and the source half.</summary>
-        private readonly ReorderingBuffer<TOutput> _reorderingBuffer;
+        private readonly ReorderingBuffer<TOutput>? _reorderingBuffer;
         /// <summary>The source side.</summary>
         private readonly SourceCore<TOutput> _source;
 
@@ -89,7 +89,7 @@ namespace System.Threading.Tasks.Dataflow
         /// <param name="dataflowBlockOptions">The options with which to configure this <see cref="TransformBlock{TInput,TOutput}"/>.</param>
         /// <exception cref="System.ArgumentNullException">The <paramref name="transformSync"/> and <paramref name="transformAsync"/> are both null (Nothing in Visual Basic).</exception>
         /// <exception cref="System.ArgumentNullException">The <paramref name="dataflowBlockOptions"/> is null (Nothing in Visual Basic).</exception>
-        private TransformBlock(Func<TInput, TOutput> transformSync, Func<TInput, Task<TOutput>> transformAsync, ExecutionDataflowBlockOptions dataflowBlockOptions)
+        private TransformBlock(Func<TInput, TOutput>? transformSync, Func<TInput, Task<TOutput>>? transformAsync, ExecutionDataflowBlockOptions dataflowBlockOptions)
         {
             if (transformSync == null && transformAsync == null) throw new ArgumentNullException("transform");
             if (dataflowBlockOptions == null) throw new ArgumentNullException(nameof(dataflowBlockOptions));
@@ -100,7 +100,7 @@ namespace System.Threading.Tasks.Dataflow
             dataflowBlockOptions = dataflowBlockOptions.DefaultOrClone();
 
             // Initialize onItemsRemoved delegate if necessary
-            Action<ISourceBlock<TOutput>, int> onItemsRemoved = null;
+            Action<ISourceBlock<TOutput>, int>? onItemsRemoved = null;
             if (dataflowBlockOptions.BoundedCapacity > 0)
                 onItemsRemoved = (owningSource, count) => ((TransformBlock<TInput, TOutput>)owningSource)._target.ChangeBoundingCount(-count);
 
@@ -138,8 +138,8 @@ namespace System.Threading.Tasks.Dataflow
             // we know for certain that no more messages will need to be sent to the source.
             _target.Completion.ContinueWith((completed, state) =>
             {
-                var sourceCore = (SourceCore<TOutput>)state;
-                if (completed.IsFaulted) sourceCore.AddAndUnwrapAggregateException(completed.Exception);
+                var sourceCore = (SourceCore<TOutput>)state!;
+                if (completed.IsFaulted) sourceCore.AddAndUnwrapAggregateException(completed.Exception!);
                 sourceCore.Complete();
             }, _source, CancellationToken.None, Common.GetContinuationOptions(), TaskScheduler.Default);
 
@@ -149,14 +149,14 @@ namespace System.Threading.Tasks.Dataflow
             // to handle multiple completion requests and to carry over only one.
             _source.Completion.ContinueWith((completed, state) =>
             {
-                var thisBlock = ((TransformBlock<TInput, TOutput>)state) as IDataflowBlock;
+                var thisBlock = ((TransformBlock<TInput, TOutput>)state!) as IDataflowBlock;
                 Debug.Assert(completed.IsFaulted, "The source must be faulted in order to trigger a target completion.");
-                thisBlock.Fault(completed.Exception);
+                thisBlock.Fault(completed.Exception!);
             }, this, CancellationToken.None, Common.GetContinuationOptions() | TaskContinuationOptions.OnlyOnFaulted, TaskScheduler.Default);
 
             // Handle async cancellation requests by declining on the target
             Common.WireCancellationToComplete(
-                dataflowBlockOptions.CancellationToken, Completion, state => ((TargetCore<TInput>)state).Complete(exception: null, dropPendingMessages: true), _target);
+                dataflowBlockOptions.CancellationToken, Completion, state => ((TargetCore<TInput>)state!).Complete(exception: null, dropPendingMessages: true), _target);
 #if FEATURE_TRACING
             DataflowEtwProvider etwLog = DataflowEtwProvider.Log;
             if (etwLog.IsEnabled())
@@ -203,18 +203,18 @@ namespace System.Threading.Tasks.Dataflow
                     {
                         if (_target.DataflowBlockOptions.MaxDegreeOfParallelism == 1)
                         {
-                            _source.AddMessage(outputItem);
+                            _source.AddMessage(outputItem!);
                         }
                         else
                         {
                             lock (ParallelSourceLock)
                             {
-                                _source.AddMessage(outputItem);
+                                _source.AddMessage(outputItem!);
                             }
                         }
                     }
                 }
-                else _reorderingBuffer.AddItem(messageWithId.Value, outputItem, itemIsValid);
+                else _reorderingBuffer.AddItem(messageWithId.Value, outputItem!, itemIsValid);
             }
         }
 
@@ -226,8 +226,8 @@ namespace System.Threading.Tasks.Dataflow
             Debug.Assert(transform != null, "Function to invoke is required.");
 
             // Run the transform function to get the task that represents the operation's completion
-            Task<TOutput> task = null;
-            Exception caughtException = null;
+            Task<TOutput>? task = null;
+            Exception? caughtException = null;
             try
             {
                 task = transform(messageWithId.Key);
@@ -257,7 +257,7 @@ namespace System.Threading.Tasks.Dataflow
             // Otherwise, join with the asynchronous operation when it completes.
             task.ContinueWith((completed, state) =>
             {
-                var tuple = (Tuple<TransformBlock<TInput, TOutput>, KeyValuePair<TInput, long>>)state;
+                var tuple = (Tuple<TransformBlock<TInput, TOutput>, KeyValuePair<TInput, long>>)state!;
                 tuple.Item1.AsyncCompleteProcessMessageWithTask(completed, tuple.Item2);
             }, Tuple.Create(this, messageWithId), CancellationToken.None,
             Common.GetContinuationOptions(TaskContinuationOptions.ExecuteSynchronously), TaskScheduler.Default);
@@ -285,7 +285,7 @@ namespace System.Threading.Tasks.Dataflow
                 case TaskStatus.Faulted:
                     // We must add the exception before declining and signaling completion, as the exception
                     // is part of the operation, and the completion conditions depend on this.
-                    AggregateException aggregate = completed.Exception;
+                    AggregateException aggregate = completed.Exception!;
                     Common.StoreDataflowMessageValueIntoExceptionData(aggregate, messageWithId.Key, targetInnerExceptions: true);
                     _target.Complete(aggregate, dropPendingMessages: true, storeExceptionEvenIfAlreadyCompleting: true, unwrapInnerExceptions: true);
                     break;
@@ -307,13 +307,13 @@ namespace System.Threading.Tasks.Dataflow
                 {
                     if (_target.DataflowBlockOptions.MaxDegreeOfParallelism == 1)
                     {
-                        _source.AddMessage(outputItem);
+                        _source.AddMessage(outputItem!);
                     }
                     else
                     {
                         lock (ParallelSourceLock)
                         {
-                            _source.AddMessage(outputItem);
+                            _source.AddMessage(outputItem!);
                         }
                     }
                 }
@@ -321,7 +321,7 @@ namespace System.Threading.Tasks.Dataflow
             // Otherwise, there's a reordering buffer, so add to it instead.
             // Even if something goes wrong, we need to update the
             // reordering buffer, so it knows that an item isn't missing.
-            else _reorderingBuffer.AddItem(messageWithId.Value, outputItem, itemIsValid: gotOutputItem);
+            else _reorderingBuffer.AddItem(messageWithId.Value, outputItem!, itemIsValid: gotOutputItem);
 
             // Let the target know that one of the asynchronous operations it launched has completed.
             _target.SignalOneAsyncMessageCompleted();
@@ -345,13 +345,13 @@ namespace System.Threading.Tasks.Dataflow
         }
 
         /// <include file='XmlDocs/CommonXmlDocComments.xml' path='CommonXmlDocComments/Sources/Member[@name="TryReceive"]/*' />
-        public bool TryReceive(Predicate<TOutput> filter, out TOutput item)
+        public bool TryReceive(Predicate<TOutput>? filter, [MaybeNullWhen(false)] out TOutput item)
         {
             return _source.TryReceive(filter, out item);
         }
 
         /// <include file='XmlDocs/CommonXmlDocComments.xml' path='CommonXmlDocComments/Sources/Member[@name="TryReceiveAll"]/*' />
-        public bool TryReceiveAll(out IList<TOutput> items) { return _source.TryReceiveAll(out items); }
+        public bool TryReceiveAll([NotNullWhen(true)] out IList<TOutput>? items) { return _source.TryReceiveAll(out items); }
 
         /// <include file='XmlDocs/CommonXmlDocComments.xml' path='CommonXmlDocComments/Blocks/Member[@name="Completion"]/*' />
         public Task Completion { get { return _source.Completion; } }
@@ -363,12 +363,13 @@ namespace System.Threading.Tasks.Dataflow
         public int OutputCount { get { return _source.OutputCount; } }
 
         /// <include file='XmlDocs/CommonXmlDocComments.xml' path='CommonXmlDocComments/Targets/Member[@name="OfferMessage"]/*' />
-        DataflowMessageStatus ITargetBlock<TInput>.OfferMessage(DataflowMessageHeader messageHeader, TInput messageValue, ISourceBlock<TInput> source, bool consumeToAccept)
+        DataflowMessageStatus ITargetBlock<TInput>.OfferMessage(DataflowMessageHeader messageHeader, TInput messageValue, ISourceBlock<TInput>? source, bool consumeToAccept)
         {
             return _target.OfferMessage(messageHeader, messageValue, source, consumeToAccept);
         }
 
         /// <include file='XmlDocs/CommonXmlDocComments.xml' path='CommonXmlDocComments/Sources/Member[@name="ConsumeMessage"]/*' />
+        [return: MaybeNull]
         TOutput ISourceBlock<TOutput>.ConsumeMessage(DataflowMessageHeader messageHeader, ITargetBlock<TOutput> target, out bool messageConsumed)
         {
             return _source.ConsumeMessage(messageHeader, target, out messageConsumed);
@@ -431,14 +432,14 @@ namespace System.Threading.Tasks.Dataflow
             /// <summary>Gets the messages waiting to be processed.</summary>
             public IEnumerable<TInput> InputQueue { get { return _targetDebuggingInformation.InputQueue; } }
             /// <summary>Gets any postponed messages.</summary>
-            public QueuedMap<ISourceBlock<TInput>, DataflowMessageHeader> PostponedMessages { get { return _targetDebuggingInformation.PostponedMessages; } }
+            public QueuedMap<ISourceBlock<TInput>, DataflowMessageHeader>? PostponedMessages { get { return _targetDebuggingInformation.PostponedMessages; } }
             /// <summary>Gets the messages waiting to be received.</summary>
             public IEnumerable<TOutput> OutputQueue { get { return _sourceDebuggingInformation.OutputQueue; } }
 
             /// <summary>Gets the number of outstanding input operations.</summary>
             public int CurrentDegreeOfParallelism { get { return _targetDebuggingInformation.CurrentDegreeOfParallelism; } }
             /// <summary>Gets the task being used for output processing.</summary>
-            public Task TaskForOutputProcessing { get { return _sourceDebuggingInformation.TaskForOutputProcessing; } }
+            public Task? TaskForOutputProcessing { get { return _sourceDebuggingInformation.TaskForOutputProcessing; } }
 
             /// <summary>Gets the DataflowBlockOptions used to configure this block.</summary>
             public ExecutionDataflowBlockOptions DataflowBlockOptions { get { return _targetDebuggingInformation.DataflowBlockOptions; } }
@@ -452,7 +453,7 @@ namespace System.Threading.Tasks.Dataflow
             /// <summary>Gets the set of all targets linked from this block.</summary>
             public TargetRegistry<TOutput> LinkedTargets { get { return _sourceDebuggingInformation.LinkedTargets; } }
             /// <summary>Gets the target that holds a reservation on the next message, if any.</summary>
-            public ITargetBlock<TOutput> NextMessageReservedFor { get { return _sourceDebuggingInformation.NextMessageReservedFor; } }
+            public ITargetBlock<TOutput>? NextMessageReservedFor { get { return _sourceDebuggingInformation.NextMessageReservedFor; } }
         }
     }
 }
index 612ac2d..ef4b5df 100644 (file)
@@ -33,7 +33,7 @@ namespace System.Threading.Tasks.Dataflow
         /// Buffer used to reorder output sets that may have completed out-of-order between the target half and the source half.
         /// This specialized reordering buffer supports streaming out enumerables if the message is the next in line.
         /// </summary>
-        private readonly ReorderingBuffer<IEnumerable<TOutput>> _reorderingBuffer;
+        private readonly ReorderingBuffer<IEnumerable<TOutput>>? _reorderingBuffer;
         /// <summary>The source side.</summary>
         private readonly SourceCore<TOutput> _source;
 
@@ -97,7 +97,7 @@ namespace System.Threading.Tasks.Dataflow
         /// <param name="dataflowBlockOptions">The options with which to configure this <see cref="TransformManyBlock{TInput,TOutput}"/>.</param>
         /// <exception cref="System.ArgumentNullException">The <paramref name="transformSync"/> and <paramref name="transformAsync"/> are both null (Nothing in Visual Basic).</exception>
         /// <exception cref="System.ArgumentNullException">The <paramref name="dataflowBlockOptions"/> is null (Nothing in Visual Basic).</exception>
-        private TransformManyBlock(Func<TInput, IEnumerable<TOutput>> transformSync, Func<TInput, Task<IEnumerable<TOutput>>> transformAsync, ExecutionDataflowBlockOptions dataflowBlockOptions)
+        private TransformManyBlock(Func<TInput, IEnumerable<TOutput>>? transformSync, Func<TInput, Task<IEnumerable<TOutput>>>? transformAsync, ExecutionDataflowBlockOptions dataflowBlockOptions)
         {
             // Validate arguments.  It's ok for the filterFunction to be null, but not the other parameters.
             if (transformSync == null && transformAsync == null) throw new ArgumentNullException("transform");
@@ -109,7 +109,7 @@ namespace System.Threading.Tasks.Dataflow
             dataflowBlockOptions = dataflowBlockOptions.DefaultOrClone();
 
             // Initialize onItemsRemoved delegate if necessary
-            Action<ISourceBlock<TOutput>, int> onItemsRemoved = null;
+            Action<ISourceBlock<TOutput>, int>? onItemsRemoved = null;
             if (dataflowBlockOptions.BoundedCapacity > 0)
                 onItemsRemoved = (owningSource, count) => ((TransformManyBlock<TInput, TOutput>)owningSource)._target.ChangeBoundingCount(-count);
 
@@ -155,8 +155,8 @@ namespace System.Threading.Tasks.Dataflow
             // we know for certain that no more messages will need to be sent to the source.
             _target.Completion.ContinueWith((completed, state) =>
             {
-                var sourceCore = (SourceCore<TOutput>)state;
-                if (completed.IsFaulted) sourceCore.AddAndUnwrapAggregateException(completed.Exception);
+                var sourceCore = (SourceCore<TOutput>)state!;
+                if (completed.IsFaulted) sourceCore.AddAndUnwrapAggregateException(completed.Exception!);
                 sourceCore.Complete();
             }, _source, CancellationToken.None, Common.GetContinuationOptions(), TaskScheduler.Default);
 
@@ -166,14 +166,14 @@ namespace System.Threading.Tasks.Dataflow
             // to handle multiple completion requests and to carry over only one.
             _source.Completion.ContinueWith((completed, state) =>
             {
-                var thisBlock = ((TransformManyBlock<TInput, TOutput>)state) as IDataflowBlock;
+                var thisBlock = ((TransformManyBlock<TInput, TOutput>)state!) as IDataflowBlock;
                 Debug.Assert(completed.IsFaulted, "The source must be faulted in order to trigger a target completion.");
-                thisBlock.Fault(completed.Exception);
+                thisBlock.Fault(completed.Exception!);
             }, this, CancellationToken.None, Common.GetContinuationOptions() | TaskContinuationOptions.OnlyOnFaulted, TaskScheduler.Default);
 
             // Handle async cancellation requests by declining on the target
             Common.WireCancellationToComplete(
-                dataflowBlockOptions.CancellationToken, Completion, state => ((TargetCore<TInput>)state).Complete(exception: null, dropPendingMessages: true), _target);
+                dataflowBlockOptions.CancellationToken, Completion, state => ((TargetCore<TInput>)state!).Complete(exception: null, dropPendingMessages: true), _target);
 #if FEATURE_TRACING
             DataflowEtwProvider etwLog = DataflowEtwProvider.Log;
             if (etwLog.IsEnabled())
@@ -219,8 +219,8 @@ namespace System.Threading.Tasks.Dataflow
             Debug.Assert(function != null, "Function to invoke is required.");
 
             // Run the transform function to get the resulting task
-            Task<IEnumerable<TOutput>> task = null;
-            Exception caughtException = null;
+            Task<IEnumerable<TOutput>>? task = null;
+            Exception? caughtException = null;
             try
             {
                 task = function(messageWithId.Key);
@@ -263,7 +263,7 @@ namespace System.Threading.Tasks.Dataflow
             // scheduler as we'll be running user code through enumerating the returned enumerable.
             task.ContinueWith((completed, state) =>
             {
-                var tuple = (Tuple<TransformManyBlock<TInput, TOutput>, KeyValuePair<TInput, long>>)state;
+                var tuple = (Tuple<TransformManyBlock<TInput, TOutput>, KeyValuePair<TInput, long>>)state!;
                 tuple.Item1.AsyncCompleteProcessMessageWithTask(completed, tuple.Item2);
             }, Tuple.Create(this, messageWithId),
             CancellationToken.None,
@@ -307,7 +307,7 @@ namespace System.Threading.Tasks.Dataflow
                 case TaskStatus.Faulted:
                     // We must add the exception before declining and signaling completion, as the exception
                     // is part of the operation, and the completion conditions depend on this.
-                    AggregateException aggregate = completed.Exception;
+                    AggregateException aggregate = completed.Exception!;
                     Common.StoreDataflowMessageValueIntoExceptionData(aggregate, messageWithId.Key, targetInnerExceptions: true);
                     _target.Complete(aggregate, dropPendingMessages: true, storeExceptionEvenIfAlreadyCompleting: true, unwrapInnerExceptions: true);
                     goto case TaskStatus.Canceled;
@@ -331,7 +331,7 @@ namespace System.Threading.Tasks.Dataflow
         /// <param name="messageWithId">The message with id.</param>
         /// <param name="outputItems">The output items to be persisted.</param>
         private void StoreOutputItems(
-            KeyValuePair<TInput, long> messageWithId, IEnumerable<TOutput> outputItems)
+            KeyValuePair<TInput, long> messageWithId, IEnumerable<TOutput>? outputItems)
         {
             // If there's a reordering buffer, pass the data along to it.
             // The reordering buffer will handle all details, including bounding.
@@ -369,7 +369,7 @@ namespace System.Threading.Tasks.Dataflow
         /// <summary>Stores the next item using the reordering buffer.</summary>
         /// <param name="id">The ID of the item.</param>
         /// <param name="item">The completed item.</param>
-        private void StoreOutputItemsReordered(long id, IEnumerable<TOutput> item)
+        private void StoreOutputItemsReordered(long id, IEnumerable<TOutput>? item)
         {
             Debug.Assert(_reorderingBuffer != null, "Expected a reordering buffer");
             Debug.Assert(id != Common.INVALID_REORDERING_ID, "This ID should never have been handed out.");
@@ -381,7 +381,7 @@ namespace System.Threading.Tasks.Dataflow
             // Handle invalid items (null enumerables) by delegating to the base
             if (item == null)
             {
-                _reorderingBuffer.AddItem(id, null, false);
+                _reorderingBuffer.AddItem(id, null!, false);
                 if (isBounded) target.ChangeBoundingCount(count: -1);
                 return;
             }
@@ -390,7 +390,7 @@ namespace System.Threading.Tasks.Dataflow
             // This avoids the cost of updating it once per output item (since each update requires synchronization).
             // Even if we're not bounding, we still want to determine whether the item is trusted so that we
             // can immediately dump it out once we take the lock if we're the next item.
-            IList<TOutput> itemAsTrustedList = item as TOutput[];
+            IList<TOutput>? itemAsTrustedList = item as TOutput[];
             if (itemAsTrustedList == null) itemAsTrustedList = item as List<TOutput>;
             if (itemAsTrustedList != null && isBounded)
             {
@@ -407,7 +407,7 @@ namespace System.Threading.Tasks.Dataflow
             // By this point, either we're not the next item, in which case we need to make a copy of the
             // data and store it, or we are the next item and can store it immediately but we need to enumerate
             // the items and store them individually because we don't want to enumerate while holding a lock.
-            List<TOutput> itemCopy = null;
+            List<TOutput>? itemCopy = null;
             try
             {
                 // If this is the next item, we can output it now.
@@ -581,10 +581,10 @@ namespace System.Threading.Tasks.Dataflow
         public IDisposable LinkTo(ITargetBlock<TOutput> target, DataflowLinkOptions linkOptions) { return _source.LinkTo(target, linkOptions); }
 
         /// <include file='XmlDocs/CommonXmlDocComments.xml' path='CommonXmlDocComments/Sources/Member[@name="TryReceive"]/*' />
-        public bool TryReceive(Predicate<TOutput> filter, out TOutput item) { return _source.TryReceive(filter, out item); }
+        public bool TryReceive(Predicate<TOutput>? filter, [MaybeNullWhen(false)] out TOutput item) { return _source.TryReceive(filter, out item); }
 
         /// <include file='XmlDocs/CommonXmlDocComments.xml' path='CommonXmlDocComments/Sources/Member[@name="TryReceiveAll"]/*' />
-        public bool TryReceiveAll(out IList<TOutput> items) { return _source.TryReceiveAll(out items); }
+        public bool TryReceiveAll([NotNullWhen(true)] out IList<TOutput>? items) { return _source.TryReceiveAll(out items); }
 
         /// <include file='XmlDocs/CommonXmlDocComments.xml' path='CommonXmlDocComments/Blocks/Member[@name="Completion"]/*' />
         public Task Completion { get { return _source.Completion; } }
@@ -596,12 +596,13 @@ namespace System.Threading.Tasks.Dataflow
         public int OutputCount { get { return _source.OutputCount; } }
 
         /// <include file='XmlDocs/CommonXmlDocComments.xml' path='CommonXmlDocComments/Targets/Member[@name="OfferMessage"]/*' />
-        DataflowMessageStatus ITargetBlock<TInput>.OfferMessage(DataflowMessageHeader messageHeader, TInput messageValue, ISourceBlock<TInput> source, bool consumeToAccept)
+        DataflowMessageStatus ITargetBlock<TInput>.OfferMessage(DataflowMessageHeader messageHeader, TInput messageValue, ISourceBlock<TInput>? source, bool consumeToAccept)
         {
             return _target.OfferMessage(messageHeader, messageValue, source, consumeToAccept);
         }
 
         /// <include file='XmlDocs/CommonXmlDocComments.xml' path='CommonXmlDocComments/Sources/Member[@name="ConsumeMessage"]/*' />
+        [return: MaybeNull]
         TOutput ISourceBlock<TOutput>.ConsumeMessage(DataflowMessageHeader messageHeader, ITargetBlock<TOutput> target, out bool messageConsumed)
         {
             return _source.ConsumeMessage(messageHeader, target, out messageConsumed);
@@ -664,14 +665,14 @@ namespace System.Threading.Tasks.Dataflow
             /// <summary>Gets the messages waiting to be processed.</summary>
             public IEnumerable<TInput> InputQueue { get { return _targetDebuggingInformation.InputQueue; } }
             /// <summary>Gets any postponed messages.</summary>
-            public QueuedMap<ISourceBlock<TInput>, DataflowMessageHeader> PostponedMessages { get { return _targetDebuggingInformation.PostponedMessages; } }
+            public QueuedMap<ISourceBlock<TInput>, DataflowMessageHeader>? PostponedMessages { get { return _targetDebuggingInformation.PostponedMessages; } }
             /// <summary>Gets the messages waiting to be received.</summary>
             public IEnumerable<TOutput> OutputQueue { get { return _sourceDebuggingInformation.OutputQueue; } }
 
             /// <summary>Gets the number of input operations currently in flight.</summary>
             public int CurrentDegreeOfParallelism { get { return _targetDebuggingInformation.CurrentDegreeOfParallelism; } }
             /// <summary>Gets the task being used for output processing.</summary>
-            public Task TaskForOutputProcessing { get { return _sourceDebuggingInformation.TaskForOutputProcessing; } }
+            public Task? TaskForOutputProcessing { get { return _sourceDebuggingInformation.TaskForOutputProcessing; } }
 
             /// <summary>Gets the DataflowBlockOptions used to configure this block.</summary>
             public ExecutionDataflowBlockOptions DataflowBlockOptions { get { return _targetDebuggingInformation.DataflowBlockOptions; } }
@@ -685,7 +686,7 @@ namespace System.Threading.Tasks.Dataflow
             /// <summary>Gets the set of all targets linked from this block.</summary>
             public TargetRegistry<TOutput> LinkedTargets { get { return _sourceDebuggingInformation.LinkedTargets; } }
             /// <summary>Gets the set of all targets linked from this block.</summary>
-            public ITargetBlock<TOutput> NextMessageReservedFor { get { return _sourceDebuggingInformation.NextMessageReservedFor; } }
+            public ITargetBlock<TOutput>? NextMessageReservedFor { get { return _sourceDebuggingInformation.NextMessageReservedFor; } }
         }
     }
 }
index 8a0b29d..b588a7d 100644 (file)
@@ -28,11 +28,11 @@ namespace System.Threading.Tasks.Dataflow
         /// <summary>A registry used to store all linked targets and information about them.</summary>
         private readonly TargetRegistry<T> _targetRegistry;
         /// <summary>The cloning function.</summary>
-        private readonly Func<T, T> _cloningFunction;
+        private readonly Func<T, T>? _cloningFunction;
         /// <summary>The options used to configure this block's execution.</summary>
         private readonly DataflowBlockOptions _dataflowBlockOptions;
         /// <summary>Lazily initialized task completion source that produces the actual completion task when needed.</summary>
-        private TaskCompletionSource<VoidResult> _lazyCompletionTaskSource;
+        private TaskCompletionSource<VoidResult>? _lazyCompletionTaskSource;
         /// <summary>Whether all future messages should be declined.</summary>
         private bool _decliningPermanently;
         /// <summary>Whether block completion is disallowed.</summary>
@@ -40,7 +40,8 @@ namespace System.Threading.Tasks.Dataflow
         /// <summary>The header of the singly-assigned value.</summary>
         private DataflowMessageHeader _header;
         /// <summary>The singly-assigned value.</summary>
-        private T _value;
+        [AllowNull, MaybeNull]
+        private T _value = default;
 
         /// <summary>Gets the object used as the value lock.</summary>
         private object ValueLock { get { return _targetRegistry; } }
@@ -50,7 +51,7 @@ namespace System.Threading.Tasks.Dataflow
         /// The function to use to clone the data when offered to other blocks.
         /// This may be null to indicate that no cloning need be performed.
         /// </param>
-        public WriteOnceBlock(Func<T, T> cloningFunction) :
+        public WriteOnceBlock(Func<T, T>? cloningFunction) :
             this(cloningFunction, DataflowBlockOptions.Default)
         { }
 
@@ -61,7 +62,7 @@ namespace System.Threading.Tasks.Dataflow
         /// </param>
         /// <param name="dataflowBlockOptions">The options with which to configure this <see cref="WriteOnceBlock{T}"/>.</param>
         /// <exception cref="System.ArgumentNullException">The <paramref name="dataflowBlockOptions"/> is null (Nothing in Visual Basic).</exception>
-        public WriteOnceBlock(Func<T, T> cloningFunction, DataflowBlockOptions dataflowBlockOptions)
+        public WriteOnceBlock(Func<T, T>? cloningFunction, DataflowBlockOptions dataflowBlockOptions)
         {
             // Validate arguments
             if (dataflowBlockOptions == null) throw new ArgumentNullException(nameof(dataflowBlockOptions));
@@ -94,7 +95,7 @@ namespace System.Threading.Tasks.Dataflow
                 {
                     // Handle async cancellation requests by declining on the target
                     Common.WireCancellationToComplete(
-                        dataflowBlockOptions.CancellationToken, _lazyCompletionTaskSource.Task, state => ((WriteOnceBlock<T>)state).Complete(), this);
+                        dataflowBlockOptions.CancellationToken, _lazyCompletionTaskSource.Task, state => ((WriteOnceBlock<T>)state!).Complete(), this);
                 }
             }
 #if FEATURE_TRACING
@@ -110,7 +111,7 @@ namespace System.Threading.Tasks.Dataflow
         /// <remarks>
         /// This must only be called once all of the completion conditions are met.
         /// </remarks>
-        private void CompleteBlockAsync(IList<Exception> exceptions)
+        private void CompleteBlockAsync(IList<Exception>? exceptions)
         {
             Debug.Assert(_decliningPermanently, "We may get here only after we have started to decline permanently.");
             Debug.Assert(_completionReserved, "We may get here only after we have reserved completion.");
@@ -121,7 +122,7 @@ namespace System.Threading.Tasks.Dataflow
             if (exceptions == null)
             {
                 // Offer the message to any linked targets and complete the block asynchronously to avoid blocking the caller
-                var taskForOutputProcessing = new Task(state => ((WriteOnceBlock<T>)state).OfferToTargetsAndCompleteBlock(), this,
+                var taskForOutputProcessing = new Task(state => ((WriteOnceBlock<T>)state!).OfferToTargetsAndCompleteBlock(), this,
                                                         Common.GetCreationOptionsForTask());
 
 #if FEATURE_TRACING
@@ -134,7 +135,7 @@ namespace System.Threading.Tasks.Dataflow
 #endif
 
                 // Start the task handling scheduling exceptions
-                Exception exception = Common.StartTaskSafe(taskForOutputProcessing, _dataflowBlockOptions.TaskScheduler);
+                Exception? exception = Common.StartTaskSafe(taskForOutputProcessing, _dataflowBlockOptions.TaskScheduler);
                 if (exception != null) CompleteCore(exception, storeExceptionEvenIfAlreadyCompleting: true);
             }
             else
@@ -142,7 +143,7 @@ namespace System.Threading.Tasks.Dataflow
                 // Complete the block asynchronously to avoid blocking the caller
                 Task.Factory.StartNew(state =>
                 {
-                    Tuple<WriteOnceBlock<T>, IList<Exception>> blockAndList = (Tuple<WriteOnceBlock<T>, IList<Exception>>)state;
+                    Tuple<WriteOnceBlock<T>, IList<Exception>> blockAndList = (Tuple<WriteOnceBlock<T>, IList<Exception>>)state!;
                     blockAndList.Item1.CompleteBlock(blockAndList.Item2);
                 },
                 Tuple.Create(this, exceptions), CancellationToken.None, Common.GetCreationOptionsForTask(), TaskScheduler.Default);
@@ -159,7 +160,7 @@ namespace System.Threading.Tasks.Dataflow
             // could be faulty and throw an exception.  OfferToTargets creates a
             // list of all such exceptions and returns it.
             // If _value is null, OfferToTargets does nothing.
-            List<Exception> exceptions = OfferToTargets();
+            List<Exception>? exceptions = OfferToTargets();
             CompleteBlock(exceptions);
         }
 
@@ -167,7 +168,7 @@ namespace System.Threading.Tasks.Dataflow
         /// <remarks>
         /// This is called only once.
         /// </remarks>
-        private void CompleteBlock(IList<Exception> exceptions)
+        private void CompleteBlock(IList<Exception>? exceptions)
         {
             // Do not invoke the CompletionTaskSource property if there is a chance that _lazyCompletionTaskSource
             // has not been initialized yet and we may have to complete normally, because that would defeat the
@@ -176,7 +177,7 @@ namespace System.Threading.Tasks.Dataflow
             Debug.Assert(_lazyCompletionTaskSource == null || !_lazyCompletionTaskSource.Task.IsCompleted, "The task completion source must not be completed. This must be the only thread that ever completes the block.");
 
             // Save the linked list of targets so that it could be traversed later to propagate completion
-            TargetRegistry<T>.LinkedTargetInfo linkedTargets = _targetRegistry.ClearEntryPoints();
+            TargetRegistry<T>.LinkedTargetInfo? linkedTargets = _targetRegistry.ClearEntryPoints();
 
             // Complete the block's completion task
             if (exceptions != null && exceptions.Count > 0)
@@ -224,7 +225,7 @@ namespace System.Threading.Tasks.Dataflow
             CompleteCore(exception: null, storeExceptionEvenIfAlreadyCompleting: false);
         }
 
-        private void CompleteCore(Exception exception, bool storeExceptionEvenIfAlreadyCompleting)
+        private void CompleteCore(Exception? exception, bool storeExceptionEvenIfAlreadyCompleting)
         {
             Debug.Assert(exception != null || !storeExceptionEvenIfAlreadyCompleting,
                             "When storeExceptionEvenIfAlreadyCompleting is set to true, an exception must be provided.");
@@ -249,7 +250,7 @@ namespace System.Threading.Tasks.Dataflow
             // there's nothing more this block needs to do... complete it if we just reserved completion.
             if (thisThreadReservedCompletion)
             {
-                List<Exception> exceptions = null;
+                List<Exception>? exceptions = null;
                 if (exception != null)
                 {
                     exceptions = new List<Exception>();
@@ -261,7 +262,7 @@ namespace System.Threading.Tasks.Dataflow
         }
 
         /// <include file='XmlDocs/CommonXmlDocComments.xml' path='CommonXmlDocComments/Sources/Member[@name="TryReceive"]/*' />
-        public bool TryReceive(Predicate<T> filter, out T item)
+        public bool TryReceive(Predicate<T>? filter, [MaybeNullWhen(false)] out T item)
         {
             // No need to take the outgoing lock, as we don't need to synchronize with other
             // targets, and _value only ever goes from null to non-null, not the other way around.
@@ -269,9 +270,9 @@ namespace System.Threading.Tasks.Dataflow
             // If we have a value, give it up.  All receives on a successfully
             // completed WriteOnceBlock will return true, as long as the message
             // passes the filter (all messages pass a null filter).
-            if (_header.IsValid && (filter == null || filter(_value)))
+            if (_header.IsValid && (filter == null || filter(_value!)))
             {
-                item = CloneItem(_value);
+                item = CloneItem(_value!);
                 return true;
             }
             // Otherwise, nothing to receive
@@ -283,7 +284,7 @@ namespace System.Threading.Tasks.Dataflow
         }
 
         /// <include file='XmlDocs/CommonXmlDocComments.xml' path='CommonXmlDocComments/Sources/Member[@name="TryReceiveAll"]/*' />
-        bool IReceivableSourceBlock<T>.TryReceiveAll(out IList<T> items)
+        bool IReceivableSourceBlock<T>.TryReceiveAll([NotNullWhen(true)] out IList<T>? items)
         {
             // Try to receive the one item this block may have.
             // If we can, give back an array of one item. Otherwise,
@@ -327,7 +328,7 @@ namespace System.Threading.Tasks.Dataflow
             if (hasValue)
             {
                 bool useCloning = _cloningFunction != null;
-                target.OfferMessage(_header, _value, this, consumeToAccept: useCloning);
+                target.OfferMessage(_header, _value!, this, consumeToAccept: useCloning);
             }
 
             // If completion propagation has been requested, do it safely.
@@ -341,7 +342,7 @@ namespace System.Threading.Tasks.Dataflow
         public Task Completion { get { return CompletionTaskSource.Task; } }
 
         /// <include file='XmlDocs/CommonXmlDocComments.xml' path='CommonXmlDocComments/Targets/Member[@name="OfferMessage"]/*' />
-        DataflowMessageStatus ITargetBlock<T>.OfferMessage(DataflowMessageHeader messageHeader, T messageValue, ISourceBlock<T> source, bool consumeToAccept)
+        DataflowMessageStatus ITargetBlock<T>.OfferMessage(DataflowMessageHeader messageHeader, T messageValue, ISourceBlock<T>? source, bool consumeToAccept)
         {
             // Validate arguments
             if (!messageHeader.IsValid) throw new ArgumentException(SR.Argument_InvalidMessageHeader, nameof(messageHeader));
@@ -358,7 +359,7 @@ namespace System.Threading.Tasks.Dataflow
                 if (consumeToAccept)
                 {
                     bool consumed;
-                    messageValue = source.ConsumeMessage(messageHeader, this, out consumed);
+                    messageValue = source!.ConsumeMessage(messageHeader, this, out consumed);
                     if (!consumed) return DataflowMessageStatus.NotAvailable;
                 }
 
@@ -392,12 +393,12 @@ namespace System.Threading.Tasks.Dataflow
             if (_header.Id == messageHeader.Id)
             {
                 messageConsumed = true;
-                return CloneItem(_value);
+                return CloneItem(_value!);
             }
             else
             {
                 messageConsumed = false;
-                return default(T);
+                return default(T)!;
             }
         }
 
@@ -433,7 +434,7 @@ namespace System.Threading.Tasks.Dataflow
             // or not, nor do we care about any exceptions which may emerge (they should just propagate).
             Debug.Assert(_header.IsValid, "A valid header is required.");
             bool useCloning = _cloningFunction != null;
-            target.OfferMessage(_header, _value, this, consumeToAccept: useCloning);
+            target.OfferMessage(_header, _value!, this, consumeToAccept: useCloning);
         }
 
         /// <summary>Clones the item.</summary>
@@ -447,20 +448,20 @@ namespace System.Threading.Tasks.Dataflow
         }
 
         /// <summary>Offers the WriteOnceBlock's message to all targets.</summary>
-        private List<Exception> OfferToTargets()
+        private List<Exception>? OfferToTargets()
         {
             Common.ContractAssertMonitorStatus(ValueLock, held: false);
 
             // If there is a message, offer it to everyone.  Return values
             // don't matter, because we only get one message and then complete,
             // and everyone who wants a copy can get a copy.
-            List<Exception> exceptions = null;
+            List<Exception>? exceptions = null;
             if (HasValue)
             {
-                TargetRegistry<T>.LinkedTargetInfo cur = _targetRegistry.FirstTargetNode;
+                TargetRegistry<T>.LinkedTargetInfo? cur = _targetRegistry.FirstTargetNode;
                 while (cur != null)
                 {
-                    TargetRegistry<T>.LinkedTargetInfo next = cur.Next;
+                    TargetRegistry<T>.LinkedTargetInfo? next = cur.Next;
                     ITargetBlock<T> target = cur.Target;
                     try
                     {
@@ -469,14 +470,14 @@ namespace System.Threading.Tasks.Dataflow
                         // the cloning function once we know they want the data.  If there is no cloning
                         // function, there's no reason for them to call back here.
                         bool useCloning = _cloningFunction != null;
-                        target.OfferMessage(_header, _value, this, consumeToAccept: useCloning);
+                        target.OfferMessage(_header, _value!, this, consumeToAccept: useCloning);
                     }
                     catch (Exception exc)
                     {
                         // Track any erroneous exceptions that may occur
                         // and return them to the caller so that they may
                         // be logged in the completion task.
-                        Common.StoreDataflowMessageValueIntoExceptionData(exc, _value);
+                        Common.StoreDataflowMessageValueIntoExceptionData(exc, _value!);
                         Common.AddException(ref exceptions, exc);
                     }
                     cur = next;
@@ -506,6 +507,7 @@ namespace System.Threading.Tasks.Dataflow
         /// <summary>Gets whether the block is storing a value.</summary>
         private bool HasValue { get { return _header.IsValid; } }
         /// <summary>Gets the value being stored by the block.</summary>
+        [MaybeNull]
         private T Value { get { return _header.IsValid ? _value : default(T); } }
 
         /// <include file='XmlDocs/CommonXmlDocComments.xml' path='CommonXmlDocComments/Blocks/Member[@name="ToString"]/*' />
@@ -545,6 +547,7 @@ namespace System.Threading.Tasks.Dataflow
             /// <summary>Gets whether the WriteOnceBlock has a value.</summary>
             public bool HasValue { get { return _writeOnceBlock.HasValue; } }
             /// <summary>Gets the WriteOnceBlock's value if it has one, or default(T) if it doesn't.</summary>
+            [MaybeNull]
             public T Value { get { return _writeOnceBlock.Value; } }
 
             /// <summary>Gets the DataflowBlockOptions used to configure this block.</summary>
index bb87f43..a3d0047 100644 (file)
@@ -66,7 +66,7 @@ namespace System.Threading.Tasks.Dataflow.Internal
             /// <summary>Second state argument.</summary>
             private readonly T2 _arg2;
             /// <summary>The action to run when disposed. Null if disposed.</summary>
-            private Action<T1, T2> _action;
+            private Action<T1, T2>? _action;
 
             /// <summary>Initializes the ActionOnDispose.</summary>
             /// <param name="action">The action to run when disposed.</param>
@@ -86,7 +86,7 @@ namespace System.Threading.Tasks.Dataflow.Internal
             /// <summary>Invoke the action.</summary>
             void IDisposable.Dispose()
             {
-                Action<T1, T2> toRun = _action;
+                Action<T1, T2>? toRun = _action;
                 if (toRun != null &&
                     Interlocked.CompareExchange(ref _action, null, toRun) == toRun)
                 {
@@ -106,7 +106,7 @@ namespace System.Threading.Tasks.Dataflow.Internal
             /// <summary>Third state argument.</summary>
             private readonly T3 _arg3;
             /// <summary>The action to run when disposed. Null if disposed.</summary>
-            private Action<T1, T2, T3> _action;
+            private Action<T1, T2, T3>? _action;
 
             /// <summary>Initializes the ActionOnDispose.</summary>
             /// <param name="action">The action to run when disposed.</param>
@@ -128,7 +128,7 @@ namespace System.Threading.Tasks.Dataflow.Internal
             /// <summary>Invoke the action.</summary>
             void IDisposable.Dispose()
             {
-                Action<T1, T2, T3> toRun = _action;
+                Action<T1, T2, T3>? toRun = _action;
                 if (toRun != null &&
                     Interlocked.CompareExchange(ref _action, null, toRun) == toRun)
                 {
index b915ca1..61bd0e8 100644 (file)
@@ -71,7 +71,7 @@ namespace System.Threading.Tasks.Dataflow.Internal
         /// <param name="stateOut">Output state for the predicate in order to avoid closure allocations.</param>
         /// <returns>True if the predicate was evaluated and it returned true. False otherwise.</returns>
         internal static bool TryKeepAliveUntil<TStateIn, TStateOut>(KeepAlivePredicate<TStateIn, TStateOut> predicate,
-                                                                    TStateIn stateIn, out TStateOut stateOut)
+                                                                    TStateIn stateIn, [MaybeNullWhen(false)] out TStateOut stateOut)
         {
             Debug.Assert(predicate != null, "Non-null predicate to execute is required.");
             const int ITERATION_LIMIT = 16;
@@ -94,12 +94,12 @@ namespace System.Threading.Tasks.Dataflow.Internal
         /// <typeparam name="T">The type of the data to be unwrapped.</typeparam>
         /// <param name="state">The weak reference.</param>
         /// <returns>The T instance.</returns>
+        [return: MaybeNull]
         internal static T UnwrapWeakReference<T>(object state) where T : class
         {
             var wr = state as WeakReference<T>;
             Debug.Assert(wr != null, "Expected a WeakReference<T> as the state argument");
-            T item;
-            return wr.TryGetTarget(out item) ? item : null;
+            return wr.TryGetTarget(out T? item) ? item : null;
         }
 
         /// <summary>Gets an ID for the dataflow block.</summary>
@@ -109,7 +109,7 @@ namespace System.Threading.Tasks.Dataflow.Internal
         {
             Debug.Assert(block != null, "Block required to extract an Id.");
             const int NOTASKID = 0; // tasks don't have 0 as ids
-            Task t = Common.GetPotentiallyNotSupportedCompletionTask(block);
+            Task? t = Common.GetPotentiallyNotSupportedCompletionTask(block);
             return t != null ? t.Id : NOTASKID;
         }
 
@@ -121,7 +121,7 @@ namespace System.Threading.Tasks.Dataflow.Internal
         /// <returns>The name of the object.</returns>
         /// <remarks>This is used from DebuggerDisplay attributes.</remarks>
         internal static string GetNameForDebugger(
-            IDataflowBlock block, DataflowBlockOptions options = null)
+            IDataflowBlock block, DataflowBlockOptions? options = null)
         {
             Debug.Assert(block != null, "Should only be used with valid objects being displayed in the debugger.");
             Debug.Assert(options == null || options.NameFormat != null, "If options are provided, NameFormat must be valid.");
@@ -179,7 +179,7 @@ namespace System.Threading.Tasks.Dataflow.Internal
         /// <param name="completeAction">An action that will decline permanently on the state passed to it.</param>
         /// <param name="completeState">The block on which to decline permanently.</param>
         internal static void WireCancellationToComplete(
-            CancellationToken cancellationToken, Task completionTask, Action<object> completeAction, object completeState)
+            CancellationToken cancellationToken, Task completionTask, Action<object?> completeAction, object completeState)
         {
             Debug.Assert(completionTask != null, "A task to wire up for completion is needed.");
             Debug.Assert(completeAction != null, "An action to invoke upon cancellation is required.");
@@ -196,7 +196,7 @@ namespace System.Threading.Tasks.Dataflow.Internal
             else if (cancellationToken.CanBeCanceled)
             {
                 CancellationTokenRegistration reg = cancellationToken.Register(completeAction, completeState);
-                completionTask.ContinueWith((completed, state) => ((CancellationTokenRegistration)state).Dispose(),
+                completionTask.ContinueWith((completed, state) => ((CancellationTokenRegistration)state!).Dispose(),
                     reg, cancellationToken, Common.GetContinuationOptions(), TaskScheduler.Default);
             }
         }
@@ -225,7 +225,7 @@ namespace System.Threading.Tasks.Dataflow.Internal
             Debug.Assert(exc != null, "The exception into which data should be stored must be provided.");
 
             // Get the string value to store
-            string strValue = messageValue as string;
+            string? strValue = messageValue as string;
             if (strValue == null && messageValue != null)
             {
                 try
@@ -295,7 +295,7 @@ namespace System.Threading.Tasks.Dataflow.Internal
         internal static void ThrowAsync(Exception error)
         {
             ExceptionDispatchInfo edi = ExceptionDispatchInfo.Capture(error);
-            ThreadPool.QueueUserWorkItem(state => { ((ExceptionDispatchInfo)state).Throw(); }, edi);
+            ThreadPool.QueueUserWorkItem(state => { ((ExceptionDispatchInfo)state!).Throw(); }, edi);
         }
 
         /// <summary>Adds the exception to the list, first initializing the list if the list is null.</summary>
@@ -303,25 +303,25 @@ namespace System.Threading.Tasks.Dataflow.Internal
         /// <param name="exception">The exception to add or whose inner exception(s) should be added.</param>
         /// <param name="unwrapInnerExceptions">Unwrap and add the inner exception(s) rather than the specified exception directly.</param>
         /// <remarks>This method is not thread-safe, in that it manipulates <paramref name="list"/> without any synchronization.</remarks>
-        internal static void AddException(ref List<Exception> list, Exception exception, bool unwrapInnerExceptions = false)
+        internal static void AddException([NotNull] ref List<Exception>? list, Exception exception, bool unwrapInnerExceptions = false)
         {
             Debug.Assert(exception != null, "An exception to add is required.");
             Debug.Assert(!unwrapInnerExceptions || exception.InnerException != null,
                 "If unwrapping is requested, an inner exception is required.");
 
             // Make sure the list of exceptions is initialized (lazily).
-            if (list == null) list = new List<Exception>();
+            list ??= new List<Exception>();
 
             if (unwrapInnerExceptions)
             {
-                AggregateException aggregate = exception as AggregateException;
+                AggregateException? aggregate = exception as AggregateException;
                 if (aggregate != null)
                 {
                     list.AddRange(aggregate.InnerExceptions);
                 }
                 else
                 {
-                    list.Add(exception.InnerException);
+                    list.Add(exception.InnerException!);
                 }
             }
             else list.Add(exception);
@@ -346,7 +346,7 @@ namespace System.Threading.Tasks.Dataflow.Internal
         private static TaskCompletionSource<T> CreateCachedTaskCompletionSource<T>()
         {
             var tcs = new TaskCompletionSource<T>();
-            tcs.SetResult(default(T));
+            tcs.SetResult(default(T)!);
             return tcs;
         }
 
@@ -376,7 +376,7 @@ namespace System.Threading.Tasks.Dataflow.Internal
         /// <summary>Gets the completion task of a block, and protects against common cases of the completion task not being implemented or supported.</summary>
         /// <param name="block">The block.</param>
         /// <returns>The completion task, or null if the block's completion task is not implemented or supported.</returns>
-        internal static Task GetPotentiallyNotSupportedCompletionTask(IDataflowBlock block)
+        internal static Task? GetPotentiallyNotSupportedCompletionTask(IDataflowBlock block)
         {
             Debug.Assert(block != null, "We need a block from which to retrieve a cancellation task.");
             try
@@ -444,7 +444,7 @@ namespace System.Threading.Tasks.Dataflow.Internal
         /// <param name="task">Task to be started.</param>
         /// <param name="scheduler">TaskScheduler to schedule the task on.</param>
         /// <returns>null on success, an exception reference on scheduling error. In the latter case, the task reference is nulled out.</returns>
-        internal static Exception StartTaskSafe(Task task, TaskScheduler scheduler)
+        internal static Exception? StartTaskSafe(Task task, TaskScheduler scheduler)
         {
             Debug.Assert(task != null, "Task to start is required.");
             Debug.Assert(scheduler != null, "Scheduler on which to start the task is required.");
@@ -462,12 +462,12 @@ namespace System.Threading.Tasks.Dataflow.Internal
         /// <param name="task">Task to be started.</param>
         /// <param name="scheduler">TaskScheduler to schedule the task on.</param>
         /// <returns>null on success, an exception reference on scheduling error. In the latter case, the task reference is nulled out.</returns>
-        private static Exception StartTaskSafeCore(Task task, TaskScheduler scheduler)
+        private static Exception? StartTaskSafeCore(Task task, TaskScheduler scheduler)
         {
             Debug.Assert(task != null, "Task to start is needed.");
             Debug.Assert(scheduler != null, "Scheduler on which to start the task is required.");
 
-            Exception schedulingException = null;
+            Exception? schedulingException = null;
 
             try
             {
@@ -479,7 +479,7 @@ namespace System.Threading.Tasks.Dataflow.Internal
                 Debug.Assert(task.IsFaulted, "The task should have been faulted if it failed to start.");
 
                 // Observe the task's exception
-                AggregateException ignoredTaskException = task.Exception;
+                _ = task.Exception;
 
                 schedulingException = caughtException;
             }
@@ -491,7 +491,7 @@ namespace System.Threading.Tasks.Dataflow.Internal
         /// <remarks>No locks should be held at this time. Unfortunately we cannot assert that.</remarks>
         internal static void ReleaseAllPostponedMessages<T>(ITargetBlock<T> target,
                                     QueuedMap<ISourceBlock<T>, DataflowMessageHeader> postponedMessages,
-                                    ref List<Exception> exceptions)
+                                    ref List<Exception>? exceptions)
         {
             Debug.Assert(target != null, "There must be a subject target.");
             Debug.Assert(postponedMessages != null, "The stacked map of postponed messages must exist.");
@@ -538,13 +538,13 @@ namespace System.Threading.Tasks.Dataflow.Internal
         /// <param name="sourceCompletionTask">The task whose completion is to be propagated. It must be completed.</param>
         /// <param name="target">The block where completion is propagated.</param>
         /// <param name="exceptionHandler">Handler for exceptions from the target. May be null which would propagate the exception to the caller.</param>
-        internal static void PropagateCompletion(Task sourceCompletionTask, IDataflowBlock target, Action<Exception> exceptionHandler)
+        internal static void PropagateCompletion(Task sourceCompletionTask, IDataflowBlock target, Action<Exception>? exceptionHandler)
         {
             Debug.Assert(sourceCompletionTask != null, "sourceCompletionTask may not be null.");
             Debug.Assert(target != null, "The target where completion is to be propagated may not be null.");
             Debug.Assert(sourceCompletionTask.IsCompleted, "sourceCompletionTask must be completed in order to propagate its completion.");
 
-            AggregateException exception = sourceCompletionTask.IsFaulted ? sourceCompletionTask.Exception : null;
+            AggregateException? exception = sourceCompletionTask.IsFaulted ? sourceCompletionTask.Exception : null;
 
             try
             {
@@ -565,7 +565,7 @@ namespace System.Threading.Tasks.Dataflow.Internal
         {
             Debug.Assert(sourceCompletionTask != null, "sourceCompletionTask may not be null.");
             Debug.Assert(target != null, "The target where completion is to be propagated may not be null.");
-            sourceCompletionTask.ContinueWith((task, state) => Common.PropagateCompletion(task, (IDataflowBlock)state, AsyncExceptionHandler),
+            sourceCompletionTask.ContinueWith((task, state) => Common.PropagateCompletion(task, (IDataflowBlock)state!, AsyncExceptionHandler),
                 target, CancellationToken.None, Common.GetContinuationOptions(), TaskScheduler.Default);
         }
 
@@ -588,7 +588,7 @@ namespace System.Threading.Tasks.Dataflow.Internal
         private static class CachedGenericDelegates<T>
         {
             /// <summary>A function that returns the default value of T.</summary>
-            internal static readonly Func<T> DefaultTResultFunc = () => default(T);
+            internal static readonly Func<T> DefaultTResultFunc = () => default(T)!;
             /// <summary>
             /// A function to use as the body of ActionOnDispose in CreateUnlinkerShim.
             /// Passed a tuple of the sync obj, the target registry, and the target block as the state parameter.
@@ -667,7 +667,7 @@ namespace System.Threading.Tasks.Dataflow.Internal
     internal class BoundingStateWithPostponedAndTask<TInput> : BoundingStateWithPostponed<TInput>
     {
         /// <summary>The task used to process messages.</summary>
-        internal Task TaskForInputProcessing;
+        internal Task? TaskForInputProcessing;
 
         /// <summary>Initializes the BoundingState.</summary>
         /// <param name="boundedCapacity">The positive bounded capacity.</param>
index b4058ec..db5af01 100644 (file)
@@ -11,6 +11,7 @@
 //
 // =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
 
+#nullable disable // old copy used only for netstandard1.0 build
 using System;
 using System.Collections;
 using System.Collections.Generic;
index 171f141..1177af8 100644 (file)
@@ -11,6 +11,7 @@
 //
 // =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
 
+#nullable disable // copy used only for netstandard1.0 build
 using System.Collections;
 using System.Collections.Generic;
 using System.Diagnostics;
index 3897cc3..70c72e4 100644 (file)
@@ -31,6 +31,7 @@ using System.Collections.Concurrent;
 #endif
 using System.Collections.Generic;
 using System.Diagnostics;
+using System.Diagnostics.CodeAnalysis;
 using System.Runtime.InteropServices;
 using Internal;
 
@@ -49,7 +50,7 @@ namespace System.Threading.Tasks
         /// <param name="result">The dequeued item.</param>
         /// <returns>true if an item could be dequeued; otherwise, false.</returns>
         /// <remarks>This method is meant to be thread-safe subject to the particular nature of the implementation.</remarks>
-        bool TryDequeue(out T result);
+        bool TryDequeue([MaybeNullWhen(false)] out T result);
 
         /// <summary>Gets whether the collection is currently empty.</summary>
         /// <remarks>This method may or may not be thread-safe.</remarks>
@@ -210,7 +211,7 @@ namespace System.Threading.Tasks
         /// <summary>Attempts to dequeue an item from the queue.</summary>
         /// <param name="result">The dequeued item.</param>
         /// <returns>true if an item could be dequeued; otherwise, false.</returns>
-        public bool TryDequeue(out T result)
+        public bool TryDequeue([MaybeNullWhen(false)] out T result)
         {
             Segment segment = _head;
             T[] array = segment._array;
@@ -220,7 +221,7 @@ namespace System.Threading.Tasks
             if (first != segment._state._lastCopy)
             {
                 result = array[first];
-                array[first] = default(T); // Clear the slot to release the element
+                array[first] = default(T)!; // Clear the slot to release the element
                 segment._state._first = (first + 1) & (array.Length - 1);
                 return true;
             }
@@ -233,7 +234,7 @@ namespace System.Threading.Tasks
         /// <param name="segment">The segment from which the item was dequeued.</param>
         /// <param name="result">The dequeued item.</param>
         /// <returns>true if an item could be dequeued; otherwise, false.</returns>
-        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.");
@@ -260,7 +261,7 @@ namespace System.Threading.Tasks
             }
 
             result = array[first];
-            array[first] = default(T); // Clear the slot to release the element
+            array[first] = default(T)!; // Clear the slot to release the element
             segment._state._first = (first + 1) & (segment._array.Length - 1);
             segment._state._lastCopy = segment._state._last; // Refresh _lastCopy to ensure that _first has not passed _lastCopy
 
@@ -291,7 +292,7 @@ namespace System.Threading.Tasks
         /// <param name="segment">The segment from which the item is peeked.</param>
         /// <param name="result">The peeked item.</param>
         /// <returns>true if an item could be peeked; otherwise, false.</returns>
-        private bool TryPeekSlow(ref Segment segment, ref T[] array, out T result)
+        private bool TryPeekSlow(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.");
@@ -325,7 +326,7 @@ namespace System.Threading.Tasks
         /// <param name="predicate">The predicate that must return true for the item to be dequeued.  If null, all items implicitly return true.</param>
         /// <param name="result">The dequeued item.</param>
         /// <returns>true if an item could be dequeued; otherwise, false.</returns>
-        public bool TryDequeueIf(Predicate<T> predicate, out T result)
+        public bool TryDequeueIf(Predicate<T>? predicate, [MaybeNullWhen(false)] out T result)
         {
             Segment segment = _head;
             T[] array = segment._array;
@@ -337,7 +338,7 @@ namespace System.Threading.Tasks
                 result = array[first];
                 if (predicate == null || predicate(result))
                 {
-                    array[first] = default(T); // Clear the slot to release the element
+                    array[first] = default(T)!; // Clear the slot to release the element
                     segment._state._first = (first + 1) & (array.Length - 1);
                     return true;
                 }
@@ -357,7 +358,7 @@ namespace System.Threading.Tasks
         /// <param name="segment">The segment from which the item was dequeued.</param>
         /// <param name="result">The dequeued item.</param>
         /// <returns>true if an item could be dequeued; otherwise, false.</returns>
-        private bool TryDequeueIfSlow(Predicate<T> predicate, ref Segment segment, ref T[] array, out T result)
+        private bool TryDequeueIfSlow(Predicate<T>? predicate, 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.");
@@ -386,7 +387,7 @@ namespace System.Threading.Tasks
             result = array[first];
             if (predicate == null || predicate(result))
             {
-                array[first] = default(T); // Clear the slot to release the element
+                array[first] = default(T)!; // Clear the slot to release the element
                 segment._state._first = (first + 1) & (segment._array.Length - 1);
                 segment._state._lastCopy = segment._state._last; // Refresh _lastCopy to ensure that _first has not passed _lastCopy
                 return true;
@@ -422,7 +423,7 @@ namespace System.Threading.Tasks
         /// <remarks>WARNING: This should only be used for debugging purposes.  It is not safe to be used concurrently.</remarks>
         public IEnumerator<T> GetEnumerator()
         {
-            for (Segment segment = _head; segment != null; segment = segment._next)
+            for (Segment? segment = _head; segment != null; segment = segment._next)
             {
                 for (int pt = segment._state._first;
                     pt != segment._state._last;
@@ -443,7 +444,7 @@ namespace System.Threading.Tasks
             get
             {
                 int count = 0;
-                for (Segment segment = _head; segment != null; segment = segment._next)
+                for (Segment? segment = _head; segment != null; segment = segment._next)
                 {
                     int arraySize = segment._array.Length;
                     int first, last;
@@ -475,7 +476,7 @@ namespace System.Threading.Tasks
         private sealed class Segment
         {
             /// <summary>The next segment in the linked list of segments.</summary>
-            internal Segment _next;
+            internal Segment? _next;
             /// <summary>The data stored in this segment.</summary>
             internal readonly T[] _array;
             /// <summary>Details about the segment.</summary>
index ed4ef24..bcd745f 100644 (file)
@@ -15,6 +15,7 @@
 using System.Collections;
 using System.Collections.Generic;
 using System.Diagnostics;
+using System.Diagnostics.CodeAnalysis;
 
 namespace System.Threading.Tasks.Dataflow.Internal
 {
@@ -28,7 +29,7 @@ namespace System.Threading.Tasks.Dataflow.Internal
     /// <remarks>This type is not thread-safe.</remarks>
     [DebuggerDisplay("Count = {Count}")]
     [DebuggerTypeProxy(typeof(EnumerableDebugView<,>))]
-    internal sealed class QueuedMap<TKey, TValue>
+    internal sealed class QueuedMap<TKey, TValue> where TKey: notnull
     {
         /// <summary>
         /// A queue structure that uses an array-based list to store its items
@@ -108,7 +109,7 @@ namespace System.Threading.Tasks.Dataflow.Internal
 
             /// <summary>Tries to dequeue an item.</summary>
             /// <param name="item">The item that is dequeued.</param>
-            internal bool TryDequeue(out T item)
+            internal bool TryDequeue([MaybeNullWhen(false)] out T item)
             {
                 // If the queue is empty, just initialize the output item and return false
                 if (_headIndex == TERMINATOR_INDEX)
@@ -124,7 +125,7 @@ namespace System.Threading.Tasks.Dataflow.Internal
 
                 // Move the popped slot to the head of the free list
                 int newHeadIndex = _storage[_headIndex].Key;
-                _storage[_headIndex] = new KeyValuePair<int, T>(_freeIndex, default(T));
+                _storage[_headIndex] = new KeyValuePair<int, T>(_freeIndex, default(T)!);
                 _freeIndex = _headIndex;
                 _headIndex = newHeadIndex;
                 if (_headIndex == TERMINATOR_INDEX) _tailIndex = TERMINATOR_INDEX;
index 15fc700..7181bf8 100644 (file)
@@ -15,6 +15,7 @@
 
 using System.Collections.Generic;
 using System.Diagnostics;
+using System.Diagnostics.CodeAnalysis;
 using System.Linq;
 
 namespace System.Threading.Tasks.Dataflow.Internal
@@ -66,7 +67,7 @@ namespace System.Threading.Tasks.Dataflow.Internal
         /// <param name="id">The ID of the item.</param>
         /// <param name="item">The completed item.</param>
         /// <param name="itemIsValid">Specifies whether the item is valid (true) or just a placeholder (false).</param>
-        internal void AddItem(long id, TOutput item, bool itemIsValid)
+        internal void AddItem(long id, [AllowNull] TOutput item, bool itemIsValid)
         {
             Debug.Assert(id != Common.INVALID_REORDERING_ID, "This ID should never have been handed out.");
             Common.ContractAssertMonitorStatus(ValueLock, held: false);
@@ -84,7 +85,7 @@ namespace System.Threading.Tasks.Dataflow.Internal
                 else
                 {
                     Debug.Assert((ulong)id > (ulong)_nextReorderedIdToOutput, "Duplicate id.");
-                    _reorderingBuffer.Add(id, new KeyValuePair<bool, TOutput>(itemIsValid, item));
+                    _reorderingBuffer.Add(id, new KeyValuePair<bool, TOutput>(itemIsValid, item!));
                 }
             }
         }
@@ -104,7 +105,7 @@ namespace System.Threading.Tasks.Dataflow.Internal
         /// true if the item was not added but is next in line.
         /// false if the item was not added and is not next in line.
         /// </returns>
-        internal bool? AddItemIfNextAndTrusted(long id, TOutput item, bool isTrusted)
+        internal bool? AddItemIfNextAndTrusted(long id, [AllowNull] TOutput item, bool isTrusted)
         {
             Debug.Assert(id != Common.INVALID_REORDERING_ID, "This ID should never have been handed out.");
             Common.ContractAssertMonitorStatus(ValueLock, held: false);
@@ -132,20 +133,20 @@ namespace System.Threading.Tasks.Dataflow.Internal
         /// <param name="id">The id of the message to be ignored.</param>
         public void IgnoreItem(long id)
         {
-            AddItem(id, default(TOutput), itemIsValid: false);
+            AddItem(id, default(TOutput)!, itemIsValid: false);
         }
 
         /// <summary>Outputs the item.  The item must have already been confirmed to have the next ID.</summary>
         /// <param name="theNextItem">The item to output.</param>
         /// <param name="itemIsValid">Whether the item is valid.</param>
-        private void OutputNextItem(TOutput theNextItem, bool itemIsValid)
+        private void OutputNextItem([AllowNull] TOutput theNextItem, bool itemIsValid)
         {
             Common.ContractAssertMonitorStatus(ValueLock, held: true);
 
             // Note that we're now looking for a different item, and pass this one through.
             // Then release any items which may be pending.
             _nextReorderedIdToOutput++;
-            if (itemIsValid) _outputAction(_owningSource, theNextItem);
+            if (itemIsValid) _outputAction(_owningSource, theNextItem!);
 
             // Try to get the next available item from the buffer and output it.  Continue to do so
             // until we run out of items in the reordering buffer or don't yet have the next ID buffered.
index 57f701a..0b5899a 100644 (file)
@@ -70,18 +70,18 @@ namespace System.Threading.Tasks.Dataflow.Internal
         /// An action to be invoked on the owner block when an item is removed.
         /// This may be null if the owner block doesn't need to be notified.
         /// </summary>
-        private readonly Action<ISourceBlock<TOutput>, int> _itemsRemovedAction;
+        private readonly Action<ISourceBlock<TOutput>, int>? _itemsRemovedAction;
         /// <summary>Item counting function</summary>
-        private readonly Func<ISourceBlock<TOutput>, TOutput, IList<TOutput>, int> _itemCountingFunc;
+        private readonly Func<ISourceBlock<TOutput>, TOutput, IList<TOutput>?, int>? _itemCountingFunc;
 
         // *** These fields are mutated during execution.
 
         /// <summary>The task used to process the output and offer it to targets.</summary>
-        private Task _taskForOutputProcessing; // protected by ValueLock
+        private Task? _taskForOutputProcessing; // protected by ValueLock
         /// <summary>Counter for message IDs unique within this source block.</summary>
         private PaddedInt64 _nextMessageId = new PaddedInt64 { Value = 1 }; // We are going to use this value before incrementing.  Protected by ValueLock.
         /// <summary>The target that the next message is reserved for, or null if nothing is reserved.</summary>
-        private ITargetBlock<TOutput> _nextMessageReservedFor; // protected by OutgoingLock
+        private ITargetBlock<TOutput>? _nextMessageReservedFor; // protected by OutgoingLock
         /// <summary>Whether all future messages should be declined.</summary>
         private bool _decliningPermanently; // Protected by ValueLock
         /// <summary>Whether this block should again attempt to offer messages to targets.</summary>
@@ -89,7 +89,7 @@ namespace System.Threading.Tasks.Dataflow.Internal
         /// <summary>Whether someone has reserved the right to call CompleteBlockOncePossible.</summary>
         private bool _completionReserved; // Protected by OutgoingLock
         /// <summary>Exceptions that may have occurred and gone unhandled during processing.</summary>
-        private List<Exception> _exceptions; // Protected by ValueLock, sometimes read with volatile reads
+        private List<Exception>? _exceptions; // Protected by ValueLock, sometimes read with volatile reads
 
         /// <summary>Initializes the source core.</summary>
         /// <param name="owningSource">The source utilizing this core.</param>
@@ -103,8 +103,8 @@ namespace System.Threading.Tasks.Dataflow.Internal
         internal SourceCore(
             ISourceBlock<TOutput> owningSource, DataflowBlockOptions dataflowBlockOptions,
             Action<ISourceBlock<TOutput>> completeAction,
-            Action<ISourceBlock<TOutput>, int> itemsRemovedAction = null,
-            Func<ISourceBlock<TOutput>, TOutput, IList<TOutput>, int> itemCountingFunc = null)
+            Action<ISourceBlock<TOutput>, int>? itemsRemovedAction = null,
+            Func<ISourceBlock<TOutput>, TOutput, IList<TOutput>?, int>? itemCountingFunc = null)
         {
             Debug.Assert(owningSource != null, "Core must be associated with a source.");
             Debug.Assert(dataflowBlockOptions != null, "Options must be provided to configure the core.");
@@ -156,6 +156,7 @@ namespace System.Threading.Tasks.Dataflow.Internal
         }
 
         /// <include file='XmlDocs/CommonXmlDocComments.xml' path='CommonXmlDocComments/Sources/Member[@name="ConsumeMessage"]/*' />
+        [return: MaybeNull]
         internal TOutput ConsumeMessage(DataflowMessageHeader messageHeader, ITargetBlock<TOutput> target, out bool messageConsumed)
         {
             // Validate arguments
@@ -274,7 +275,7 @@ namespace System.Threading.Tasks.Dataflow.Internal
         internal Task Completion { get { return _completionTask.Task; } }
 
         /// <include file='XmlDocs/CommonXmlDocComments.xml' path='CommonXmlDocComments/Sources/Member[@name="TryReceive"]/*' />
-        internal bool TryReceive(Predicate<TOutput> filter, out TOutput item)
+        internal bool TryReceive(Predicate<TOutput>? filter, [MaybeNullWhen(false)] out TOutput item)
         {
             item = default(TOutput);
             bool itemReceived = false;
@@ -313,7 +314,7 @@ namespace System.Threading.Tasks.Dataflow.Internal
                 // Notify the owner block that our count has decreased
                 if (_itemsRemovedAction != null)
                 {
-                    int count = _itemCountingFunc != null ? _itemCountingFunc(_owningSource, item, null) : 1;
+                    int count = _itemCountingFunc != null ? _itemCountingFunc(_owningSource, item!, null) : 1;
                     _itemsRemovedAction(_owningSource, count);
                 }
             }
@@ -321,7 +322,7 @@ namespace System.Threading.Tasks.Dataflow.Internal
         }
 
         /// <include file='XmlDocs/CommonXmlDocComments.xml' path='CommonXmlDocComments/Sources/Member[@name="TryReceiveAll"]/*' />
-        internal bool TryReceiveAll(out IList<TOutput> items)
+        internal bool TryReceiveAll([NotNullWhen(true)] out IList<TOutput>? items)
         {
             items = null;
             int countReceived = 0;
@@ -360,10 +361,12 @@ namespace System.Threading.Tasks.Dataflow.Internal
                 // Notify the owner block that our count has decreased
                 if (_itemsRemovedAction != null)
                 {
-                    int count = _itemCountingFunc != null ? _itemCountingFunc(_owningSource, default(TOutput), items) : countReceived;
+                    int count = _itemCountingFunc != null ? _itemCountingFunc(_owningSource, default(TOutput)!, items) : countReceived;
                     _itemsRemovedAction(_owningSource, count);
                 }
+#pragma warning disable CS8762 // Parameter may not have a null value when exiting in some condition.
                 return true;
+#pragma warning restore CS8762
             }
             else return false;
         }
@@ -423,7 +426,7 @@ namespace System.Threading.Tasks.Dataflow.Internal
             }
             else
             {
-                TOutput[] itemsAsArray = items as TOutput[];
+                TOutput[]? itemsAsArray = items as TOutput[];
                 if (itemsAsArray != null)
                 {
                     for (int i = 0; i < itemsAsArray.Length; i++)
@@ -511,7 +514,7 @@ namespace System.Threading.Tasks.Dataflow.Internal
                 // and take the necessary locks in a situation where we're sure it won't cause a problem.
                 Task.Factory.StartNew(state =>
                 {
-                    var thisSourceCore = (SourceCore<TOutput>)state;
+                    var thisSourceCore = (SourceCore<TOutput>)state!;
                     lock (thisSourceCore.OutgoingLock)
                     {
                         lock (thisSourceCore.ValueLock)
@@ -531,7 +534,7 @@ namespace System.Threading.Tasks.Dataflow.Internal
         /// The newly linked target, if OfferToTargets is being called to synchronously
         /// propagate to a target during a LinkTo operation.
         /// </param>
-        private bool OfferToTargets(ITargetBlock<TOutput> linkToTarget = null)
+        private bool OfferToTargets(ITargetBlock<TOutput>? linkToTarget = null)
         {
             Common.ContractAssertMonitorStatus(OutgoingLock, held: true);
             Common.ContractAssertMonitorStatus(ValueLock, held: false);
@@ -585,10 +588,10 @@ namespace System.Threading.Tasks.Dataflow.Internal
                     // separately from cur.Next, in case cur.Next changes by cur being removed from the list.
                     // No other node in the list should change, as we're protected by OutgoingLock.
 
-                    TargetRegistry<TOutput>.LinkedTargetInfo cur = _targetRegistry.FirstTargetNode;
+                    TargetRegistry<TOutput>.LinkedTargetInfo? cur = _targetRegistry.FirstTargetNode;
                     while (cur != null)
                     {
-                        TargetRegistry<TOutput>.LinkedTargetInfo next = cur.Next;
+                        TargetRegistry<TOutput>.LinkedTargetInfo? next = cur.Next;
                         if (OfferMessageToTarget(header, message, cur.Target, out messageWasAccepted)) break;
                         cur = next;
                     }
@@ -749,7 +752,7 @@ namespace System.Threading.Tasks.Dataflow.Internal
             {
                 // Create task and store into _taskForOutputProcessing prior to scheduling the task
                 // so that _taskForOutputProcessing will be visibly set in the task loop.
-                _taskForOutputProcessing = new Task(thisSourceCore => ((SourceCore<TOutput>)thisSourceCore).OfferMessagesLoopCore(), this,
+                _taskForOutputProcessing = new Task(thisSourceCore => ((SourceCore<TOutput>)thisSourceCore!).OfferMessagesLoopCore(), this,
                                                      Common.GetCreationOptionsForTask(isReplacementReplica));
 
 #if FEATURE_TRACING
@@ -762,7 +765,7 @@ namespace System.Threading.Tasks.Dataflow.Internal
 #endif
 
                 // Start the task handling scheduling exceptions
-                Exception exception = Common.StartTaskSafe(_taskForOutputProcessing, _dataflowBlockOptions.TaskScheduler);
+                Exception? exception = Common.StartTaskSafe(_taskForOutputProcessing, _dataflowBlockOptions.TaskScheduler);
                 if (exception != null)
                 {
                     // First, log the exception while the processing state is dirty which is preventing the block from completing.
@@ -776,7 +779,7 @@ namespace System.Threading.Tasks.Dataflow.Internal
                     // Re-take the locks on a separate thread.
                     Task.Factory.StartNew(state =>
                     {
-                        var thisSourceCore = (SourceCore<TOutput>)state;
+                        var thisSourceCore = (SourceCore<TOutput>)state!;
                         lock (thisSourceCore.OutgoingLock)
                         {
                             lock (thisSourceCore.ValueLock)
@@ -917,7 +920,7 @@ namespace System.Threading.Tasks.Dataflow.Internal
                 // Get out from under currently held locks.  This is to avoid
                 // invoking synchronous continuations off of _completionTask.Task
                 // while holding a lock.
-                Task.Factory.StartNew(state => ((SourceCore<TOutput>)state).CompleteBlockOncePossible(),
+                Task.Factory.StartNew(state => ((SourceCore<TOutput>)state!).CompleteBlockOncePossible(),
                     this, CancellationToken.None, Common.GetCreationOptionsForTask(), TaskScheduler.Default);
             }
         }
@@ -928,8 +931,8 @@ namespace System.Threading.Tasks.Dataflow.Internal
         /// </summary>
         private void CompleteBlockOncePossible()
         {
-            TargetRegistry<TOutput>.LinkedTargetInfo linkedTargets;
-            List<Exception> exceptions;
+            TargetRegistry<TOutput>.LinkedTargetInfo? linkedTargets;
+            List<Exception>? exceptions;
 
             // Avoid completing while the code that caused this completion to occur is still holding a lock.
             // Clear out the target registry and buffers to help avoid memory leaks.
@@ -1006,7 +1009,7 @@ namespace System.Threading.Tasks.Dataflow.Internal
             /// <summary>Gets the messages available for receiving.</summary>
             internal IEnumerable<TOutput> OutputQueue { get { return _source._messages.ToList(); } }
             /// <summary>Gets the task being used for output processing.</summary>
-            internal Task TaskForOutputProcessing { get { return _source._taskForOutputProcessing; } }
+            internal Task? TaskForOutputProcessing { get { return _source._taskForOutputProcessing; } }
 
             /// <summary>Gets the DataflowBlockOptions used to configure this block.</summary>
             internal DataflowBlockOptions DataflowBlockOptions { get { return _source._dataflowBlockOptions; } }
@@ -1017,7 +1020,7 @@ namespace System.Threading.Tasks.Dataflow.Internal
             /// <summary>Gets the set of all targets linked from this block.</summary>
             internal TargetRegistry<TOutput> LinkedTargets { get { return _source._targetRegistry; } }
             /// <summary>Gets the target that holds a reservation on the next message, if any.</summary>
-            internal ITargetBlock<TOutput> NextMessageReservedFor { get { return _source._nextMessageReservedFor; } }
+            internal ITargetBlock<TOutput>? NextMessageReservedFor { get { return _source._nextMessageReservedFor; } }
         }
     }
 }
index f742443..07187ac 100644 (file)
@@ -53,7 +53,7 @@ namespace System.Threading.Tasks.Dataflow.Internal
         private readonly Action<TInput> _action;
 
         /// <summary>Exceptions that may have occurred and gone unhandled during processing.  This field is lazily initialized.</summary>
-        private volatile List<Exception> _exceptions;
+        private volatile List<Exception>? _exceptions;
         /// <summary>Whether to stop accepting new messages.</summary>
         private volatile bool _decliningPermanently;
         /// <summary>A task has reserved the right to run the completion routine.</summary>
@@ -63,9 +63,9 @@ namespace System.Threading.Tasks.Dataflow.Internal
         /// and it should not be set to null once the block completes, as doing so would allow for races where the producer
         /// gets another consumer task queued even though the block has completed.
         /// </summary>
-        private volatile Task _activeConsumer;
+        private volatile Task? _activeConsumer;
         /// <summary>A task representing the completion of the block.  This field is lazily initialized.</summary>
-        private TaskCompletionSource<VoidResult> _completionTask;
+        private TaskCompletionSource<VoidResult>? _completionTask;
 
         /// <summary>Initialize the SPSC target core.</summary>
         /// <param name="owningTarget">The owning target block.</param>
@@ -108,7 +108,7 @@ namespace System.Threading.Tasks.Dataflow.Internal
         }
 
         /// <include file='XmlDocs/CommonXmlDocComments.xml' path='CommonXmlDocComments/Targets/Member[@name="OfferMessage"]/*' />
-        internal DataflowMessageStatus OfferMessage(DataflowMessageHeader messageHeader, TInput messageValue, ISourceBlock<TInput> source, bool consumeToAccept)
+        internal DataflowMessageStatus OfferMessage(DataflowMessageHeader messageHeader, TInput messageValue, ISourceBlock<TInput>? source, bool consumeToAccept)
         {
             // If we're not required to go back to the source to consume the offered message, try fast path.
             return !consumeToAccept && Post(messageValue) ?
@@ -122,7 +122,7 @@ namespace System.Threading.Tasks.Dataflow.Internal
         /// <param name="source">The source offering the message. This may be null.</param>
         /// <param name="consumeToAccept">true if we need to call back to the source to consume the message; otherwise, false if we can simply accept it directly.</param>
         /// <returns>The status of the message.</returns>
-        private DataflowMessageStatus OfferMessage_Slow(DataflowMessageHeader messageHeader, TInput messageValue, ISourceBlock<TInput> source, bool consumeToAccept)
+        private DataflowMessageStatus OfferMessage_Slow(DataflowMessageHeader messageHeader, TInput messageValue, ISourceBlock<TInput>? source, bool consumeToAccept)
         {
             // If we're declining permanently, let the caller know.
             if (_decliningPermanently)
@@ -146,7 +146,7 @@ namespace System.Threading.Tasks.Dataflow.Internal
             }
 
             // See the "fast path" comments in Post
-            _messages.Enqueue(messageValue);
+            _messages.Enqueue(messageValue!);
             Interlocked.MemoryBarrier(); // ensure the read of _activeConsumer doesn't move up before the writes in Enqueue
             if (_activeConsumer == null)
             {
@@ -164,7 +164,7 @@ namespace System.Threading.Tasks.Dataflow.Internal
             {
                 // Create a new consumption task and try to set it as current as long as there's still no other task
                 var newConsumer = new Task(
-                    state => ((SpscTargetCore<TInput>)state).ProcessMessagesLoopCore(),
+                    state => ((SpscTargetCore<TInput>)state!).ProcessMessagesLoopCore(),
                     this, CancellationToken.None, Common.GetCreationOptionsForTask(isReplica));
                 if (Interlocked.CompareExchange(ref _activeConsumer, newConsumer, null) == null)
                 {
@@ -225,7 +225,7 @@ namespace System.Threading.Tasks.Dataflow.Internal
                     if (!Common.IsCooperativeCancellation(exc))
                     {
                         _decliningPermanently = true; // stop accepting from producers
-                        Common.StoreDataflowMessageValueIntoExceptionData<TInput>(exc, nextMessage, false);
+                        Common.StoreDataflowMessageValueIntoExceptionData<TInput>(exc, nextMessage!, false);
                         StoreException(exc);
                     }
                 }
@@ -254,7 +254,7 @@ namespace System.Threading.Tasks.Dataflow.Internal
                         else
                         {
                             // Mark that we're exiting.
-                            Task previousConsumer = Interlocked.Exchange(ref _activeConsumer, null);
+                            Task? previousConsumer = Interlocked.Exchange(ref _activeConsumer, null);
                             Debug.Assert(previousConsumer != null && previousConsumer.Id == Task.CurrentId,
                                 "The running task should have been denoted as the active task.");
 
@@ -285,7 +285,7 @@ namespace System.Threading.Tasks.Dataflow.Internal
         /// completing, all invocations after the first are ignored.
         /// </summary>
         /// <param name="exception">The exception to be stored.</param>
-        internal void Complete(Exception exception)
+        internal void Complete(Exception? exception)
         {
             // If we're not yet declining permanently...
             if (!_decliningPermanently)
index f3aa761..58a8ada 100644 (file)
@@ -71,9 +71,9 @@ namespace System.Threading.Tasks.Dataflow.Internal
         /// <summary>Whether the block relies on the delegate to signal when an async operation has completed.</summary>
         private readonly TargetCoreOptions _targetCoreOptions;
         /// <summary>Bounding state for when the block is executing in bounded mode.</summary>
-        private readonly BoundingStateWithPostponed<TInput> _boundingState;
+        private readonly BoundingStateWithPostponed<TInput>? _boundingState;
         /// <summary>The reordering buffer used by the owner.  May be null.</summary>
-        private readonly IReorderingBuffer _reorderingBuffer;
+        private readonly IReorderingBuffer? _reorderingBuffer;
 
         /// <summary>Gets the object used as the incoming lock.</summary>
         private object IncomingLock { get { return _messages; } }
@@ -81,7 +81,7 @@ namespace System.Threading.Tasks.Dataflow.Internal
         // *** These fields are mutated during execution.
 
         /// <summary>Exceptions that may have occurred and gone unhandled during processing.</summary>
-        private List<Exception> _exceptions;
+        private List<Exception>? _exceptions;
         /// <summary>Whether to stop accepting new messages.</summary>
         private bool _decliningPermanently;
         /// <summary>The number of operations (including service tasks) currently running asynchronously.</summary>
@@ -106,7 +106,7 @@ namespace System.Threading.Tasks.Dataflow.Internal
         internal TargetCore(
             ITargetBlock<TInput> owningTarget,
             Action<KeyValuePair<TInput, long>> callAction,
-            IReorderingBuffer reorderingBuffer,
+            IReorderingBuffer? reorderingBuffer,
             ExecutionDataflowBlockOptions dataflowBlockOptions,
             TargetCoreOptions targetCoreOptions)
         {
@@ -137,7 +137,7 @@ namespace System.Threading.Tasks.Dataflow.Internal
         /// <param name="storeExceptionEvenIfAlreadyCompleting">If true, an exception will be stored after _decliningPermanently has been set to true.</param>
         /// <param name="unwrapInnerExceptions">If true, exception will be treated as an AggregateException.</param>
         /// <param name="revertProcessingState">Indicates whether the processing state is dirty and has to be reverted.</param>
-        internal void Complete(Exception exception, bool dropPendingMessages, bool storeExceptionEvenIfAlreadyCompleting = false,
+        internal void Complete(Exception? exception, bool dropPendingMessages, bool storeExceptionEvenIfAlreadyCompleting = false,
             bool unwrapInnerExceptions = false, bool revertProcessingState = false)
         {
             Debug.Assert(storeExceptionEvenIfAlreadyCompleting || !revertProcessingState,
@@ -178,7 +178,7 @@ namespace System.Threading.Tasks.Dataflow.Internal
         }
 
         /// <include file='XmlDocs/CommonXmlDocComments.xml' path='CommonXmlDocComments/Targets/Member[@name="OfferMessage"]/*' />
-        internal DataflowMessageStatus OfferMessage(DataflowMessageHeader messageHeader, TInput messageValue, ISourceBlock<TInput> source, bool consumeToAccept)
+        internal DataflowMessageStatus OfferMessage(DataflowMessageHeader messageHeader, TInput messageValue, ISourceBlock<TInput>? source, bool consumeToAccept)
         {
             // Validate arguments
             if (!messageHeader.IsValid) throw new ArgumentException(SR.Argument_InvalidMessageHeader, nameof(messageHeader));
@@ -217,7 +217,7 @@ namespace System.Threading.Tasks.Dataflow.Internal
                     long messageId = _nextAvailableInputMessageId.Value++;
                     Debug.Assert(messageId != Common.INVALID_REORDERING_ID, "The assigned message ID is invalid.");
                     if (_boundingState != null) _boundingState.CurrentCount += 1; // track this new item against our bound
-                    _messages.Enqueue(new KeyValuePair<TInput, long>(messageValue, messageId));
+                    _messages.Enqueue(new KeyValuePair<TInput, long>(messageValue!, messageId));
                     ProcessAsyncIfNecessary();
                     return DataflowMessageStatus.Accepted;
                 }
@@ -369,7 +369,7 @@ namespace System.Threading.Tasks.Dataflow.Internal
                 _numberOfOutstandingOperations++;
                 if (UsesAsyncCompletion) _numberOfOutstandingServiceTasks++;
 
-                var taskForInputProcessing = new Task(thisTargetCore => ((TargetCore<TInput>)thisTargetCore).ProcessMessagesLoopCore(), this,
+                var taskForInputProcessing = new Task(thisTargetCore => ((TargetCore<TInput>)thisTargetCore!).ProcessMessagesLoopCore(), this,
                                                       Common.GetCreationOptionsForTask(repeat));
 
 #if FEATURE_TRACING
@@ -383,11 +383,11 @@ namespace System.Threading.Tasks.Dataflow.Internal
 #endif
 
                 // Start the task handling scheduling exceptions
-                Exception exception = Common.StartTaskSafe(taskForInputProcessing, _dataflowBlockOptions.TaskScheduler);
+                Exception? exception = Common.StartTaskSafe(taskForInputProcessing, _dataflowBlockOptions.TaskScheduler);
                 if (exception != null)
                 {
                     // Get out from under currently held locks. Complete re-acquires the locks it needs.
-                    Task.Factory.StartNew(exc => Complete(exception: (Exception)exc, dropPendingMessages: true, storeExceptionEvenIfAlreadyCompleting: true,
+                    Task.Factory.StartNew(exc => Complete(exception: (Exception)exc!, dropPendingMessages: true, storeExceptionEvenIfAlreadyCompleting: true,
                                                         unwrapInnerExceptions: false, revertProcessingState: true),
                                         exception, CancellationToken.None, Common.GetCreationOptionsForTask(), TaskScheduler.Default);
                 }
@@ -424,7 +424,7 @@ namespace System.Threading.Tasks.Dataflow.Internal
                         lock (IncomingLock)
                         {
                             Debug.Assert(
-                                _boundingState.OutstandingTransfers > 0
+                                _boundingState!.OutstandingTransfers > 0
                                 && _boundingState.OutstandingTransfers <= _dataflowBlockOptions.ActualMaxDegreeOfParallelism,
                                 "Expected TryConsumePostponedMessage to have incremented the count and for the count to not exceed the DOP.");
                             _boundingState.OutstandingTransfers--; // was incremented in TryConsumePostponedMessage
@@ -638,7 +638,7 @@ namespace System.Threading.Tasks.Dataflow.Internal
 
                     // We can consume a message to process if there's one to process and also if
                     // if we have logical room within our bound for the message.
-                    if (!_boundingState.CountIsLessThanBound || !_boundingState.PostponedMessages.TryPop(out element))
+                    if (!_boundingState!.CountIsLessThanBound || !_boundingState.PostponedMessages.TryPop(out element))
                     {
                         if (countIncrementedExpectingToGetItem)
                         {
@@ -665,7 +665,7 @@ namespace System.Threading.Tasks.Dataflow.Internal
                 TInput consumedValue = element.Key.ConsumeMessage(element.Value, _owningTarget, out consumed);
                 if (consumed)
                 {
-                    result = new KeyValuePair<TInput, long>(consumedValue, messageId);
+                    result = new KeyValuePair<TInput, long>(consumedValue!, messageId);
                     return true;
                 }
                 else
@@ -734,7 +734,7 @@ namespace System.Threading.Tasks.Dataflow.Internal
                 // Get out from under currently held locks.  This is to avoid
                 // invoking synchronous continuations off of _completionSource.Task
                 // while holding a lock.
-                Task.Factory.StartNew(state => ((TargetCore<TInput>)state).CompleteBlockOncePossible(),
+                Task.Factory.StartNew(state => ((TargetCore<TInput>)state!).CompleteBlockOncePossible(),
                     this, CancellationToken.None, Common.GetCreationOptionsForTask(), TaskScheduler.Default);
             }
         }
@@ -770,7 +770,7 @@ namespace System.Threading.Tasks.Dataflow.Internal
                 // It's ok to read _exceptions' content here, because
                 // at this point no more exceptions can be generated and thus no one will
                 // be writing to it.
-                _completionSource.TrySetException(Volatile.Read(ref _exceptions));
+                _completionSource.TrySetException(Volatile.Read(ref _exceptions!));
             }
             // If we completed with cancellation, finish in a canceled state
             else if (_dataflowBlockOptions.CancellationToken.IsCancellationRequested)
@@ -851,7 +851,7 @@ namespace System.Threading.Tasks.Dataflow.Internal
             internal IEnumerable<TInput> InputQueue { get { return _target._messages.Select(kvp => kvp.Key).ToList(); } }
 
             /// <summary>Gets any postponed messages.</summary>
-            internal QueuedMap<ISourceBlock<TInput>, DataflowMessageHeader> PostponedMessages
+            internal QueuedMap<ISourceBlock<TInput>, DataflowMessageHeader>? PostponedMessages
             {
                 get { return _target._boundingState != null ? _target._boundingState.PostponedMessages : null; }
             }
index c75a644..954d183 100644 (file)
@@ -52,9 +52,9 @@ namespace System.Threading.Tasks.Dataflow.Internal
             /// gets decremented after each successful propagation.</summary>
             internal int RemainingMessages;
             /// <summary>The previous node in the list.</summary>
-            internal LinkedTargetInfo Previous;
+            internal LinkedTargetInfo? Previous;
             /// <summary>The next node in the list.</summary>
-            internal LinkedTargetInfo Next;
+            internal LinkedTargetInfo? Next;
         }
 
         /// <summary>A reference to the owning source block.</summary>
@@ -62,9 +62,9 @@ namespace System.Threading.Tasks.Dataflow.Internal
         /// <summary>A mapping of targets to information about them.</summary>
         private readonly Dictionary<ITargetBlock<T>, LinkedTargetInfo> _targetInformation;
         /// <summary>The first node of an ordered list of targets. Messages should be offered to targets starting from First and following Next.</summary>
-        private LinkedTargetInfo _firstTarget;
+        private LinkedTargetInfo? _firstTarget;
         /// <summary>The last node of the ordered list of targets. This field is used purely as a perf optimization to avoid traversing the list for each Add.</summary>
-        private LinkedTargetInfo _lastTarget;
+        private LinkedTargetInfo? _lastTarget;
         /// <summary>Number of links with positive RemainingMessages counters.
         /// This is an optimization that allows us to skip dictionary lookup when this counter is 0.</summary>
         private int _linksWithRemainingMessages;
@@ -86,7 +86,7 @@ namespace System.Threading.Tasks.Dataflow.Internal
             Debug.Assert(target != null, "The target that is supposed to be linked must not be null.");
             Debug.Assert(linkOptions != null, "The link options must not be null.");
 
-            LinkedTargetInfo targetInfo;
+            LinkedTargetInfo? targetInfo;
 
             // If the target already exists in the registry, replace it with a new NopLinkPropagator to maintain uniqueness
             if (_targetInformation.TryGetValue(target, out targetInfo)) target = new NopLinkPropagator(_owningSource, target);
@@ -147,7 +147,7 @@ namespace System.Threading.Tasks.Dataflow.Internal
             Debug.Assert(!onlyIfReachedMaxMessages || _linksWithRemainingMessages > 0, "We shouldn't have ended on the slow path.");
 
             // If the target is registered...
-            LinkedTargetInfo node;
+            LinkedTargetInfo? node;
             if (_targetInformation.TryGetValue(target, out node))
             {
                 Debug.Assert(node != null, "The LinkedTargetInfo node referenced in the Dictionary must be non-null.");
@@ -180,10 +180,10 @@ namespace System.Threading.Tasks.Dataflow.Internal
         }
 
         /// <summary>Clears the target registry entry points while allowing subsequent traversals of the linked list.</summary>
-        internal LinkedTargetInfo ClearEntryPoints()
+        internal LinkedTargetInfo? ClearEntryPoints()
         {
             // Save _firstTarget so we can return it
-            LinkedTargetInfo firstTarget = _firstTarget;
+            LinkedTargetInfo? firstTarget = _firstTarget;
 
             // Clear out the entry points
             _firstTarget = _lastTarget = null;
@@ -196,7 +196,7 @@ namespace System.Threading.Tasks.Dataflow.Internal
 
         /// <summary>Propagated completion to the targets of the given linked list.</summary>
         /// <param name="firstTarget">The head of a saved linked list.</param>
-        internal void PropagateCompletion(LinkedTargetInfo firstTarget)
+        internal void PropagateCompletion(LinkedTargetInfo? firstTarget)
         {
             Debug.Assert(_owningSource.Completion.IsCompleted, "The owning source must have completed before propagating completion.");
 
@@ -204,14 +204,14 @@ namespace System.Threading.Tasks.Dataflow.Internal
             Task owningSourceCompletion = _owningSource.Completion;
 
             // Propagate completion to those targets that have requested it
-            for (LinkedTargetInfo node = firstTarget; node != null; node = node.Next)
+            for (LinkedTargetInfo? node = firstTarget; node != null; node = node.Next)
             {
                 if (node.PropagateCompletion) Common.PropagateCompletion(owningSourceCompletion, node.Target, Common.AsyncExceptionHandler);
             }
         }
 
         /// <summary>Gets the first node of the ordered target list.</summary>
-        internal LinkedTargetInfo FirstTargetNode { get { return _firstTarget; } }
+        internal LinkedTargetInfo? FirstTargetNode { get { return _firstTarget; } }
 
         /// <summary>Adds a LinkedTargetInfo node to the doubly-linked list.</summary>
         /// <param name="node">The node to be added.</param>
@@ -257,8 +257,8 @@ namespace System.Threading.Tasks.Dataflow.Internal
             Debug.Assert(node != null, "Node to remove is required.");
             Debug.Assert(_firstTarget != null && _lastTarget != null, "Both first and last node must be non-null before RemoveFromList.");
 
-            LinkedTargetInfo previous = node.Previous;
-            LinkedTargetInfo next = node.Next;
+            LinkedTargetInfo? previous = node.Previous;
+            LinkedTargetInfo? next = node.Next;
 
             // Remove the node by linking the adjacent nodes
             if (node.Previous != null)
@@ -290,7 +290,7 @@ namespace System.Threading.Tasks.Dataflow.Internal
             {
                 var targets = new ITargetBlock<T>[Count];
                 int i = 0;
-                for (LinkedTargetInfo node = _firstTarget; node != null; node = node.Next)
+                for (LinkedTargetInfo? node = _firstTarget; node != null; node = node.Next)
                 {
                     targets[i++] = node.Target;
                 }
@@ -325,13 +325,14 @@ namespace System.Threading.Tasks.Dataflow.Internal
             }
 
             /// <include file='XmlDocs/CommonXmlDocComments.xml' path='CommonXmlDocComments/Targets/Member[@name="OfferMessage"]/*' />
-            DataflowMessageStatus ITargetBlock<T>.OfferMessage(DataflowMessageHeader messageHeader, T messageValue, ISourceBlock<T> source, bool consumeToAccept)
+            DataflowMessageStatus ITargetBlock<T>.OfferMessage(DataflowMessageHeader messageHeader, T messageValue, ISourceBlock<T>? source, bool consumeToAccept)
             {
                 Debug.Assert(source == _owningSource, "Only valid to be used with the source for which it was created.");
                 return _target.OfferMessage(messageHeader, messageValue, this, consumeToAccept);
             }
 
             /// <include file='XmlDocs/CommonXmlDocComments.xml' path='CommonXmlDocComments/Sources/Member[@name="ConsumeMessage"]/*' />
+            [return: MaybeNull]
             T ISourceBlock<T>.ConsumeMessage(DataflowMessageHeader messageHeader, ITargetBlock<T> target, out bool messageConsumed)
             {
                 return _owningSource.ConsumeMessage(messageHeader, this, out messageConsumed);
index 2d2a99f..b34c41a 100644 (file)
@@ -2,6 +2,7 @@
 // The .NET Foundation licenses this file to you under the MIT license.
 // See the LICENSE file in the project root for more information.
 
+#nullable disable // used only for netstandard1.0 build
 using System;
 using System.Collections.Generic;
 using System.Diagnostics;
index c4319ee..9e20116 100644 (file)
@@ -1,10 +1,11 @@
-<Project Sdk="Microsoft.NET.Sdk">
+<Project Sdk="Microsoft.NET.Sdk">
   <PropertyGroup>
     <DefineConstants Condition="'$(TargetFramework)' == 'netstandard1.1' or '$(TargetFramework)' == 'netstandard2.0'">$(DefineConstants);FEATURE_TRACING</DefineConstants>
     <DefineConstants Condition="'$(TargetFramework)' == 'netstandard1.0'">$(DefineConstants);USE_INTERNAL_CONCURRENT_COLLECTIONS</DefineConstants>
     <DefineConstants Condition="'$(TargetFramework)' == 'netstandard1.0' or '$(TargetFramework)' == 'netstandard1.1'">$(DefineConstants);USE_INTERNAL_THREADING</DefineConstants>
     <PackageTargetFramework Condition="'$(TargetFramework)' == 'netstandard1.1'">netstandard1.1;portable-net45+win8+wpa81</PackageTargetFramework>
     <TargetFrameworks>netstandard2.0;netstandard1.0;netstandard1.1</TargetFrameworks>
+    <Nullable>enable</Nullable>
   </PropertyGroup>
   <ItemGroup>
     <Compile Include="Base\DataflowBlock.cs" />
index 2db6048..d022a31 100644 (file)
@@ -306,10 +306,10 @@ namespace System.Threading.Tasks.Dataflow.Tests
             }
 
             // Validate sane behavior with a bad LinkTo
-            Assert.Null(
-                new DelegatePropagator<int, int> {
-                    LinkToDelegate = (_,__) => null
-                }.AsObservable().Subscribe(DataflowBlock.NullTarget<int>().AsObserver()));
+            new DelegatePropagator<int, int>
+            {
+                LinkToDelegate = (_, __) => null
+            }.AsObservable().Subscribe(DataflowBlock.NullTarget<int>().AsObserver()).Dispose();
         }
 
         [Fact]