From b9b80640f5158bd9152e354f4918cc42cd69fe1a Mon Sep 17 00:00:00 2001 From: Stephen Toub Date: Wed, 3 Apr 2019 21:00:16 -0400 Subject: Nullable: System.Threading.Tasks (#23691) * Nullable: System.Threading.Tasks * Address PR feedback --- .../System/Globalization/CompareInfo.Unix.cs | 2 +- .../shared/System/Globalization/CultureData.cs | 2 +- .../System/Globalization/DateTimeFormatInfo.cs | 2 +- .../shared/System/Globalization/RegionInfo.cs | 10 +- .../shared/System/Globalization/StringInfo.cs | 2 +- .../shared/System/IAsyncResult.cs | 4 +- .../System/Threading/CancellationTokenSource.cs | 5 +- .../Threading/Tasks/AsyncCausalityTracer.Noop.cs | 1 + .../Tasks/AsyncCausalityTracerConstants.cs | 1 + .../Tasks/ConcurrentExclusiveSchedulerPair.cs | 35 +- .../shared/System/Threading/Tasks/Future.cs | 85 ++--- .../shared/System/Threading/Tasks/FutureFactory.cs | 226 +++++++------ .../Threading/Tasks/ProducerConsumerQueues.cs | 13 +- .../Threading/Tasks/Sources/IValueTaskSource.cs | 5 +- .../Sources/ManualResetValueTaskSourceCore.cs | 29 +- .../shared/System/Threading/Tasks/Task.cs | 365 +++++++++++---------- .../Threading/Tasks/TaskCanceledException.cs | 15 +- .../System/Threading/Tasks/TaskCompletionSource.cs | 13 +- .../System/Threading/Tasks/TaskContinuation.cs | 88 ++--- .../System/Threading/Tasks/TaskExceptionHolder.cs | 11 +- .../System/Threading/Tasks/TaskExtensions.cs | 1 + .../shared/System/Threading/Tasks/TaskFactory.cs | 126 +++---- .../shared/System/Threading/Tasks/TaskScheduler.cs | 53 ++- .../Threading/Tasks/TaskSchedulerException.cs | 9 +- .../shared/System/Threading/Tasks/TaskToApm.cs | 13 +- .../Threading/Tasks/ThreadPoolTaskScheduler.cs | 12 +- .../System/Threading/Tasks/TplEventSource.cs | 1 + .../shared/System/Threading/Tasks/ValueTask.cs | 59 ++-- .../shared/System/Threading/Timer.cs | 2 +- src/System.Private.CoreLib/src/System/Delegate.cs | 2 +- .../src/System/MulticastDelegate.cs | 2 +- .../System/Threading/Tasks/AsyncCausalityTracer.cs | 8 +- .../Tasks/IAsyncCausalityTracerStatics.cs | 4 +- 33 files changed, 616 insertions(+), 590 deletions(-) (limited to 'src') diff --git a/src/System.Private.CoreLib/shared/System/Globalization/CompareInfo.Unix.cs b/src/System.Private.CoreLib/shared/System/Globalization/CompareInfo.Unix.cs index 6a6764a727..bbb07a7535 100644 --- a/src/System.Private.CoreLib/shared/System/Globalization/CompareInfo.Unix.cs +++ b/src/System.Private.CoreLib/shared/System/Globalization/CompareInfo.Unix.cs @@ -16,7 +16,7 @@ namespace System.Globalization public partial class CompareInfo { [NonSerialized] - private Interop.Globalization.SafeSortHandle _sortHandle = null!; + private Interop.Globalization.SafeSortHandle _sortHandle = null!; // initialized in helper called by ctors [NonSerialized] private bool _isAsciiEqualityOrdinal; diff --git a/src/System.Private.CoreLib/shared/System/Globalization/CultureData.cs b/src/System.Private.CoreLib/shared/System/Globalization/CultureData.cs index 12f8ce2bc7..7e1e66857f 100644 --- a/src/System.Private.CoreLib/shared/System/Globalization/CultureData.cs +++ b/src/System.Private.CoreLib/shared/System/Globalization/CultureData.cs @@ -56,7 +56,7 @@ namespace System.Globalization private const int undef = -1; // Override flag - private string _sRealName = null!; // Name you passed in (ie: en-US, en, or de-DE_phoneb) + private string _sRealName = null!; // Name you passed in (ie: en-US, en, or de-DE_phoneb). Initialized by helper called during initialization. private string? _sWindowsName; // Name OS thinks the object is (ie: de-DE_phoneb, or en-US (even if en was passed in)) // Identity diff --git a/src/System.Private.CoreLib/shared/System/Globalization/DateTimeFormatInfo.cs b/src/System.Private.CoreLib/shared/System/Globalization/DateTimeFormatInfo.cs index 4ff055442e..78c97903ce 100644 --- a/src/System.Private.CoreLib/shared/System/Globalization/DateTimeFormatInfo.cs +++ b/src/System.Private.CoreLib/shared/System/Globalization/DateTimeFormatInfo.cs @@ -88,7 +88,7 @@ namespace System.Globalization private const string sortableDateTimePattern = "yyyy'-'MM'-'dd'T'HH':'mm':'ss"; private const string universalSortableDateTimePattern = "yyyy'-'MM'-'dd HH':'mm':'ss'Z'"; - private Calendar calendar = null!; + private Calendar calendar = null!; // initialized in helper called by ctors private int firstDayOfWeek = -1; private int calendarWeekRule = -1; diff --git a/src/System.Private.CoreLib/shared/System/Globalization/RegionInfo.cs b/src/System.Private.CoreLib/shared/System/Globalization/RegionInfo.cs index b638b2a00a..30471095f0 100644 --- a/src/System.Private.CoreLib/shared/System/Globalization/RegionInfo.cs +++ b/src/System.Private.CoreLib/shared/System/Globalization/RegionInfo.cs @@ -16,7 +16,7 @@ namespace System.Globalization public class RegionInfo { // Name of this region (ie: es-US): serialized, the field used for deserialization - private string _name = null!; + private string _name; // The CultureData instance that we are going to read data from. private readonly CultureData _cultureData; @@ -47,7 +47,7 @@ namespace System.Globalization throw new ArgumentException(SR.Format(SR.Argument_InvalidNeutralRegionName, name), nameof(name)); } - SetName(name); + _name = _cultureData.RegionName; } public RegionInfo(int culture) @@ -86,12 +86,6 @@ namespace System.Globalization _name = _cultureData.RegionName; } - private void SetName(string name) - { - // Use the name of the region we found - _name = _cultureData.RegionName; - } - /// /// This instance provides methods based on the current user settings. /// These settings are volatile and may change over the lifetime of the diff --git a/src/System.Private.CoreLib/shared/System/Globalization/StringInfo.cs b/src/System.Private.CoreLib/shared/System/Globalization/StringInfo.cs index ef2efb9c98..fe5db920ef 100644 --- a/src/System.Private.CoreLib/shared/System/Globalization/StringInfo.cs +++ b/src/System.Private.CoreLib/shared/System/Globalization/StringInfo.cs @@ -14,7 +14,7 @@ namespace System.Globalization /// public class StringInfo { - private string _str = null!; + private string _str = null!; // initialized in helper called by ctors private int[]? _indexes; diff --git a/src/System.Private.CoreLib/shared/System/IAsyncResult.cs b/src/System.Private.CoreLib/shared/System/IAsyncResult.cs index 56ebcdb2f5..8d7b32327e 100644 --- a/src/System.Private.CoreLib/shared/System/IAsyncResult.cs +++ b/src/System.Private.CoreLib/shared/System/IAsyncResult.cs @@ -11,7 +11,7 @@ ** ===========================================================*/ -using System; +#nullable enable using System.Threading; namespace System @@ -23,7 +23,7 @@ namespace System WaitHandle AsyncWaitHandle { get; } - object AsyncState { get; } + object? AsyncState { get; } bool CompletedSynchronously { get; } } diff --git a/src/System.Private.CoreLib/shared/System/Threading/CancellationTokenSource.cs b/src/System.Private.CoreLib/shared/System/Threading/CancellationTokenSource.cs index 9bbd5a74ec..4d01cd09ff 100644 --- a/src/System.Private.CoreLib/shared/System/Threading/CancellationTokenSource.cs +++ b/src/System.Private.CoreLib/shared/System/Threading/CancellationTokenSource.cs @@ -133,10 +133,10 @@ namespace System.Threading // 2. if IsCancellationRequested = false, then NotifyCancellation will see that the event exists, and will call Set(). if (IsCancellationRequested) { - _kernelEvent!.Set(); // TODO-NULLABLE: The ! shouldn't be necessary due to CompareExchange initialization above. + _kernelEvent!.Set(); // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 } - return _kernelEvent!; // TODO-NULLABLE: The ! shouldn't be necessary due to CompareExchange initialization above. + return _kernelEvent!; // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 } } @@ -823,6 +823,7 @@ namespace System.Threading // this work with a callback mechanism will add additional cost to other more common cases. return new ValueTask(Task.Factory.StartNew(s => { + Debug.Assert(s is Tuple); var state = (Tuple)s; state.Item1.WaitForCallbackToComplete(state.Item2); }, Tuple.Create(this, id), CancellationToken.None, TaskCreationOptions.None, TaskScheduler.Default)); diff --git a/src/System.Private.CoreLib/shared/System/Threading/Tasks/AsyncCausalityTracer.Noop.cs b/src/System.Private.CoreLib/shared/System/Threading/Tasks/AsyncCausalityTracer.Noop.cs index b00d5d6756..927b8fa1e4 100644 --- a/src/System.Private.CoreLib/shared/System/Threading/Tasks/AsyncCausalityTracer.Noop.cs +++ b/src/System.Private.CoreLib/shared/System/Threading/Tasks/AsyncCausalityTracer.Noop.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +#nullable enable using System.Diagnostics; namespace System.Threading.Tasks diff --git a/src/System.Private.CoreLib/shared/System/Threading/Tasks/AsyncCausalityTracerConstants.cs b/src/System.Private.CoreLib/shared/System/Threading/Tasks/AsyncCausalityTracerConstants.cs index 3677051f05..7e710677ce 100644 --- a/src/System.Private.CoreLib/shared/System/Threading/Tasks/AsyncCausalityTracerConstants.cs +++ b/src/System.Private.CoreLib/shared/System/Threading/Tasks/AsyncCausalityTracerConstants.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +#nullable enable namespace System.Threading.Tasks { internal enum AsyncCausalityStatus diff --git a/src/System.Private.CoreLib/shared/System/Threading/Tasks/ConcurrentExclusiveSchedulerPair.cs b/src/System.Private.CoreLib/shared/System/Threading/Tasks/ConcurrentExclusiveSchedulerPair.cs index df7c9342f3..155b00a2f4 100644 --- a/src/System.Private.CoreLib/shared/System/Threading/Tasks/ConcurrentExclusiveSchedulerPair.cs +++ b/src/System.Private.CoreLib/shared/System/Threading/Tasks/ConcurrentExclusiveSchedulerPair.cs @@ -14,6 +14,7 @@ // // =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +#nullable enable using System.Collections.Generic; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; @@ -51,9 +52,9 @@ namespace System.Threading.Tasks private int m_processingCount; /// Completion state for a task representing the completion of this pair. /// Lazily-initialized only if the scheduler pair is shutting down or if the Completion is requested. - private CompletionState m_completionState; + private CompletionState? m_completionState; /// Lazily-initialized work item for processing when targeting the default scheduler. - private SchedulerWorkItem m_threadPoolWorkItem; + private SchedulerWorkItem? m_threadPoolWorkItem; /// A constant value used to signal unlimited processing. private const int UNLIMITED_PROCESSING = -1; @@ -152,7 +153,7 @@ namespace System.Threading.Tasks private CompletionState EnsureCompletionStateInitialized() { // ValueLock not needed, but it's ok if it's held - return LazyInitializer.EnsureInitialized(ref m_completionState, () => new CompletionState()); + return LazyInitializer.EnsureInitialized(ref m_completionState!, () => new CompletionState()); // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 } /// Gets whether completion has been requested. @@ -211,10 +212,11 @@ namespace System.Threading.Tasks cs.m_completionQueued = true; ThreadPool.QueueUserWorkItem(state => { + Debug.Assert(state is ConcurrentExclusiveSchedulerPair); var localThis = (ConcurrentExclusiveSchedulerPair)state; - Debug.Assert(!localThis.m_completionState.IsCompleted, "Completion should only happen once."); + Debug.Assert(!localThis.m_completionState!.IsCompleted, "Completion should only happen once."); - List exceptions = localThis.m_completionState.m_exceptions; + List? exceptions = localThis.m_completionState.m_exceptions; bool success = (exceptions != null && exceptions.Count > 0) ? localThis.m_completionState.TrySetException(exceptions) : localThis.m_completionState.TrySetResult(); @@ -229,7 +231,7 @@ namespace System.Threading.Tasks /// The faulted worker task that's initiating the shutdown. private void FaultWithTask(Task faultedTask) { - Debug.Assert(faultedTask != null && faultedTask.IsFaulted && faultedTask.Exception.InnerExceptions.Count > 0, + Debug.Assert(faultedTask != null && faultedTask.IsFaulted && faultedTask.Exception!.InnerExceptions.Count > 0, "Needs a task in the faulted state and thus with exceptions."); ContractAssertMonitorStatus(ValueLock, held: true); @@ -287,7 +289,7 @@ namespace System.Threading.Tasks // If there's no processing currently happening but there are waiting exclusive tasks, // let's start processing those exclusive tasks. - Task processingTask = null; + Task? processingTask = null; if (m_processingCount == 0 && exclusiveTasksAreWaiting) { // Launch exclusive task processing @@ -296,17 +298,17 @@ namespace System.Threading.Tasks { try { - processingTask = new Task(thisPair => ((ConcurrentExclusiveSchedulerPair)thisPair).ProcessExclusiveTasks(), this, + processingTask = new Task(thisPair => ((ConcurrentExclusiveSchedulerPair)thisPair!).ProcessExclusiveTasks(), this, // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 default, GetCreationOptionsForTask(fairly)); processingTask.Start(m_underlyingTaskScheduler); // When we call Start, if the underlying scheduler throws in QueueTask, TPL will fault the task and rethrow // the exception. To deal with that, we need a reference to the task object, so that we can observe its exception. // Hence, we separate creation and starting, so that we can store a reference to the task before we attempt QueueTask. } - catch + catch (Exception e) { m_processingCount = 0; - FaultWithTask(processingTask); + FaultWithTask(processingTask ?? Task.FromException(e)); } } } @@ -326,14 +328,14 @@ namespace System.Threading.Tasks { try { - processingTask = new Task(thisPair => ((ConcurrentExclusiveSchedulerPair)thisPair).ProcessConcurrentTasks(), this, + processingTask = new Task(thisPair => ((ConcurrentExclusiveSchedulerPair)thisPair!).ProcessConcurrentTasks(), this, // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 default, GetCreationOptionsForTask(fairly)); processingTask.Start(m_underlyingTaskScheduler); // See above logic for why we use new + Start rather than StartNew } - catch + catch (Exception e) { --m_processingCount; - FaultWithTask(processingTask); + FaultWithTask(processingTask ?? Task.FromException(e)); } } } @@ -485,7 +487,7 @@ namespace System.Threading.Tasks /// Whether completion processing has been queued. internal bool m_completionQueued; /// Unrecoverable exceptions incurred while processing. - internal List m_exceptions; + internal List? m_exceptions; } /// Reusable immutable work item that can be scheduled to the thread pool to run processing. @@ -516,7 +518,7 @@ namespace System.Threading.Tasks private sealed class ConcurrentExclusiveTaskScheduler : TaskScheduler { /// Cached delegate for invoking TryExecuteTaskShim. - private static readonly Func s_tryExecuteTaskShim = new Func(TryExecuteTaskShim); + private static readonly Func s_tryExecuteTaskShim = new Func(TryExecuteTaskShim); /// The parent pair. private readonly ConcurrentExclusiveSchedulerPair m_pair; /// The maximum concurrency level for the scheduler. @@ -666,8 +668,9 @@ namespace System.Threading.Tasks /// This method is separated out not because of performance reasons but so that /// the SecuritySafeCritical attribute may be employed. /// - private static bool TryExecuteTaskShim(object state) + private static bool TryExecuteTaskShim(object? state) { + Debug.Assert(state is Tuple); var tuple = (Tuple)state; return tuple.Item1.TryExecuteTask(tuple.Item2); } diff --git a/src/System.Private.CoreLib/shared/System/Threading/Tasks/Future.cs b/src/System.Private.CoreLib/shared/System/Threading/Tasks/Future.cs index 0b93ee85df..9e562e3c46 100644 --- a/src/System.Private.CoreLib/shared/System/Threading/Tasks/Future.cs +++ b/src/System.Private.CoreLib/shared/System/Threading/Tasks/Future.cs @@ -10,6 +10,7 @@ // // =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +#nullable enable using System.Collections.Generic; using System.Diagnostics; using System.Runtime.CompilerServices; @@ -60,7 +61,7 @@ namespace System.Threading.Tasks [DebuggerDisplay("Id = {Id}, Status = {Status}, Method = {DebuggerDisplayMethodDescription}, Result = {DebuggerDisplayResultDescription}")] public class Task : Task { - internal TResult m_result; // The value itself, if set. + internal TResult m_result = default!; // The value itself, if set. // TODO-NULLABLE-GENERIC private static readonly TaskFactory s_Factory = new TaskFactory(); @@ -75,14 +76,14 @@ namespace System.Threading.Tasks internal static readonly Func, Task> Value = completed => (Task)completed.Result; } - // Construct a promise-style task without any options. + // Construct a promise-style task without any options. internal Task() : base() { } // Construct a promise-style task with state and options. - internal Task(object state, TaskCreationOptions options) : + internal Task(object? state, TaskCreationOptions options) : base(state, options, promiseStyle: true) { } @@ -209,7 +210,7 @@ namespace System.Threading.Tasks /// /// The argument is null. /// - public Task(Func function, object state) + public Task(Func function, object? state) // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 : this(function, state, null, default, TaskCreationOptions.None, InternalTaskOptions.None, null) { @@ -230,7 +231,7 @@ namespace System.Threading.Tasks /// The provided CancellationToken /// has already been disposed. /// - public Task(Func function, object state, CancellationToken cancellationToken) + public Task(Func function, object? state, CancellationToken cancellationToken) // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 : this(function, state, null, cancellationToken, TaskCreationOptions.None, InternalTaskOptions.None, null) { @@ -255,7 +256,7 @@ namespace System.Threading.Tasks /// The argument specifies an invalid value for . /// - public Task(Func function, object state, TaskCreationOptions creationOptions) + public Task(Func function, object? state, TaskCreationOptions creationOptions) // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 : this(function, state, Task.InternalCurrentIfAttached(creationOptions), default, creationOptions, InternalTaskOptions.None, null) { @@ -285,7 +286,7 @@ namespace System.Threading.Tasks /// The provided CancellationToken /// has already been disposed. /// - public Task(Func function, object state, CancellationToken cancellationToken, TaskCreationOptions creationOptions) + public Task(Func function, object? state, CancellationToken cancellationToken, TaskCreationOptions creationOptions) // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 : this(function, state, Task.InternalCurrentIfAttached(creationOptions), cancellationToken, creationOptions, InternalTaskOptions.None, null) { @@ -300,8 +301,8 @@ namespace System.Threading.Tasks /// The CancellationToken for the task. /// Options to control the future's behavior. /// Internal options to control the future's behavior. - internal Task(Func valueSelector, Task parent, CancellationToken cancellationToken, - TaskCreationOptions creationOptions, InternalTaskOptions internalOptions, TaskScheduler scheduler) : + internal Task(Func valueSelector, Task? parent, CancellationToken cancellationToken, + TaskCreationOptions creationOptions, InternalTaskOptions internalOptions, TaskScheduler? scheduler) : base(valueSelector, null, parent, cancellationToken, creationOptions, internalOptions, scheduler) { } @@ -316,15 +317,15 @@ namespace System.Threading.Tasks /// The task scheduler which will be used to execute the future. /// Options to control the future's behavior. /// Internal options to control the future's behavior. - internal Task(Delegate valueSelector, object state, Task parent, CancellationToken cancellationToken, - TaskCreationOptions creationOptions, InternalTaskOptions internalOptions, TaskScheduler scheduler) : + internal Task(Delegate valueSelector, object? state, Task? parent, CancellationToken cancellationToken, + TaskCreationOptions creationOptions, InternalTaskOptions internalOptions, TaskScheduler? scheduler) : base(valueSelector, state, parent, cancellationToken, creationOptions, internalOptions, scheduler) { } // Internal method used by TaskFactory.StartNew() methods - internal static Task StartNew(Task parent, Func function, CancellationToken cancellationToken, + internal static Task StartNew(Task? parent, Func function, CancellationToken cancellationToken, TaskCreationOptions creationOptions, InternalTaskOptions internalOptions, TaskScheduler scheduler) { if (function == null) @@ -337,14 +338,14 @@ namespace System.Threading.Tasks } // Create and schedule the future. - Task f = new Task(function, parent, cancellationToken, creationOptions, internalOptions | InternalTaskOptions.QueuedByRuntime, scheduler); + Task f = new Task(function!, parent, cancellationToken, creationOptions, internalOptions | InternalTaskOptions.QueuedByRuntime, scheduler); // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 f.ScheduleAndStart(false); return f; } // Internal method used by TaskFactory.StartNew() methods - internal static Task StartNew(Task parent, Func function, object state, CancellationToken cancellationToken, + internal static Task StartNew(Task? parent, Func function, object? state, CancellationToken cancellationToken, TaskCreationOptions creationOptions, InternalTaskOptions internalOptions, TaskScheduler scheduler) { if (function == null) @@ -357,7 +358,7 @@ namespace System.Threading.Tasks } // Create and schedule the future. - Task f = new Task(function, state, parent, cancellationToken, creationOptions, internalOptions | InternalTaskOptions.QueuedByRuntime, scheduler); + Task f = new Task(function!, state, parent, cancellationToken, creationOptions, internalOptions | InternalTaskOptions.QueuedByRuntime, scheduler); // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 f.ScheduleAndStart(false); return f; @@ -377,8 +378,7 @@ namespace System.Threading.Tasks { get { - Delegate d = m_action; - return d != null ? d.Method.ToString() : "{null}"; + return m_action?.Method.ToString() ?? "{null}"; } } @@ -408,7 +408,7 @@ namespace System.Threading.Tasks // and which can be summarized more concisely with the following snippet from // FinishStageTwo, omitting everything that doesn't pertain to TrySetResult. Interlocked.Exchange(ref m_stateFlags, m_stateFlags | TASK_STATE_RAN_TO_COMPLETION); - ContingentProperties props = m_contingentProperties; + ContingentProperties? props = m_contingentProperties; if (props != null) { NotifyParentIfPotentiallyAttachedTask(); @@ -518,7 +518,7 @@ namespace System.Threading.Tasks return; } - if (m_action is Func funcWithState) + if (m_action is Func funcWithState) { m_result = funcWithState(m_stateObject); return; @@ -726,13 +726,13 @@ namespace System.Threading.Tasks out internalOptions); Task continuationTask = new ContinuationTaskFromResultTask( - this, continuationAction, null, + this, continuationAction!, null, // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 creationOptions, internalOptions ); // Register the continuation. If synchronous execution is requested, this may // actually invoke the continuation before returning. - ContinueWithCore(continuationTask, scheduler, cancellationToken, continuationOptions); + ContinueWithCore(continuationTask, scheduler!, cancellationToken, continuationOptions); // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 return continuationTask; } @@ -757,7 +757,7 @@ namespace System.Threading.Tasks /// /// The argument is null. /// - public Task ContinueWith(Action, object> continuationAction, object state) + public Task ContinueWith(Action, object?> continuationAction, object? state) // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 { return ContinueWith(continuationAction, state, TaskScheduler.Current, default, TaskContinuationOptions.None); } @@ -784,7 +784,7 @@ namespace System.Threading.Tasks /// The provided CancellationToken /// has already been disposed. /// - public Task ContinueWith(Action, object> continuationAction, object state, CancellationToken cancellationToken) + public Task ContinueWith(Action, object?> continuationAction, object? state, CancellationToken cancellationToken) // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 { return ContinueWith(continuationAction, state, TaskScheduler.Current, cancellationToken, TaskContinuationOptions.None); } @@ -813,7 +813,7 @@ namespace System.Threading.Tasks /// /// The argument is null. /// - public Task ContinueWith(Action, object> continuationAction, object state, TaskScheduler scheduler) + public Task ContinueWith(Action, object?> continuationAction, object? state, TaskScheduler scheduler) // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 { return ContinueWith(continuationAction, state, scheduler, default, TaskContinuationOptions.None); } @@ -847,7 +847,7 @@ namespace System.Threading.Tasks /// The argument specifies an invalid value for TaskContinuationOptions. /// - public Task ContinueWith(Action, object> continuationAction, object state, TaskContinuationOptions continuationOptions) + public Task ContinueWith(Action, object?> continuationAction, object? state, TaskContinuationOptions continuationOptions) // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 { return ContinueWith(continuationAction, state, TaskScheduler.Current, default, continuationOptions); } @@ -891,14 +891,14 @@ namespace System.Threading.Tasks /// The provided CancellationToken /// has already been disposed. /// - public Task ContinueWith(Action, object> continuationAction, object state, CancellationToken cancellationToken, + public Task ContinueWith(Action, object?> continuationAction, object? state, CancellationToken cancellationToken, // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 TaskContinuationOptions continuationOptions, TaskScheduler scheduler) { return ContinueWith(continuationAction, state, scheduler, cancellationToken, continuationOptions); } // Same as the above overload, only with a stack mark. - internal Task ContinueWith(Action, object> continuationAction, object state, TaskScheduler scheduler, CancellationToken cancellationToken, + internal Task ContinueWith(Action, object?> continuationAction, object? state, TaskScheduler scheduler, CancellationToken cancellationToken, // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 TaskContinuationOptions continuationOptions) { if (continuationAction == null) @@ -919,13 +919,13 @@ namespace System.Threading.Tasks out internalOptions); Task continuationTask = new ContinuationTaskFromResultTask( - this, continuationAction, state, + this, continuationAction!, state, // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 creationOptions, internalOptions ); // Register the continuation. If synchronous execution is requested, this may // actually invoke the continuation before returning. - ContinueWithCore(continuationTask, scheduler, cancellationToken, continuationOptions); + ContinueWithCore(continuationTask, scheduler!, cancellationToken, continuationOptions); // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 return continuationTask; } @@ -1135,13 +1135,13 @@ namespace System.Threading.Tasks out internalOptions); Task continuationFuture = new ContinuationResultTaskFromResultTask( - this, continuationFunction, null, + this, continuationFunction!, null, // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 creationOptions, internalOptions ); // Register the continuation. If synchronous execution is requested, this may // actually invoke the continuation before returning. - ContinueWithCore(continuationFuture, scheduler, cancellationToken, continuationOptions); + ContinueWithCore(continuationFuture, scheduler!, cancellationToken, continuationOptions); // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 return continuationFuture; } @@ -1169,7 +1169,7 @@ namespace System.Threading.Tasks /// /// The argument is null. /// - public Task ContinueWith(Func, object, TNewResult> continuationFunction, object state) + public Task ContinueWith(Func, object?, TNewResult> continuationFunction, object? state) { return ContinueWith(continuationFunction, state, TaskScheduler.Current, default, TaskContinuationOptions.None); } @@ -1199,7 +1199,7 @@ namespace System.Threading.Tasks /// The provided CancellationToken /// has already been disposed. /// - public Task ContinueWith(Func, object, TNewResult> continuationFunction, object state, + public Task ContinueWith(Func, object?, TNewResult> continuationFunction, object? state, CancellationToken cancellationToken) { return ContinueWith(continuationFunction, state, TaskScheduler.Current, cancellationToken, TaskContinuationOptions.None); @@ -1231,7 +1231,7 @@ namespace System.Threading.Tasks /// /// The argument is null. /// - public Task ContinueWith(Func, object, TNewResult> continuationFunction, object state, + public Task ContinueWith(Func, object?, TNewResult> continuationFunction, object? state, TaskScheduler scheduler) { return ContinueWith(continuationFunction, state, scheduler, default, TaskContinuationOptions.None); @@ -1275,7 +1275,7 @@ namespace System.Threading.Tasks /// The argument specifies an invalid value for TaskContinuationOptions. /// - public Task ContinueWith(Func, object, TNewResult> continuationFunction, object state, + public Task ContinueWith(Func, object?, TNewResult> continuationFunction, object? state, TaskContinuationOptions continuationOptions) { return ContinueWith(continuationFunction, state, TaskScheduler.Current, default, continuationOptions); @@ -1330,14 +1330,14 @@ namespace System.Threading.Tasks /// The provided CancellationToken /// has already been disposed. /// - public Task ContinueWith(Func, object, TNewResult> continuationFunction, object state, + public Task ContinueWith(Func, object?, TNewResult> continuationFunction, object? state, CancellationToken cancellationToken, TaskContinuationOptions continuationOptions, TaskScheduler scheduler) { return ContinueWith(continuationFunction, state, scheduler, cancellationToken, continuationOptions); } // Same as the above overload, just with a stack mark. - internal Task ContinueWith(Func, object, TNewResult> continuationFunction, object state, + internal Task ContinueWith(Func, object?, TNewResult> continuationFunction, object? state, TaskScheduler scheduler, CancellationToken cancellationToken, TaskContinuationOptions continuationOptions) { if (continuationFunction == null) @@ -1358,13 +1358,13 @@ namespace System.Threading.Tasks out internalOptions); Task continuationFuture = new ContinuationResultTaskFromResultTask( - this, continuationFunction, state, + this, continuationFunction!, state, // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 creationOptions, internalOptions ); // Register the continuation. If synchronous execution is requested, this may // actually invoke the continuation before returning. - ContinueWithCore(continuationFuture, scheduler, cancellationToken, continuationOptions); + ContinueWithCore(continuationFuture, scheduler!, cancellationToken, continuationOptions); // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 return continuationFuture; } @@ -1381,13 +1381,14 @@ namespace System.Threading.Tasks public SystemThreadingTasks_FutureDebugView(Task task) { + Debug.Assert(task != null); m_task = task; } - public TResult Result { get { return m_task.Status == TaskStatus.RanToCompletion ? m_task.Result : default; } } - public object AsyncState { get { return m_task.AsyncState; } } + public TResult Result { get { return m_task.Status == TaskStatus.RanToCompletion ? m_task.Result : default!; } } // TODO-NULLABLE-GENERIC + public object? AsyncState { get { return m_task.AsyncState; } } public TaskCreationOptions CreationOptions { get { return m_task.CreationOptions; } } - public Exception Exception { get { return m_task.Exception; } } + public Exception? Exception { get { return m_task.Exception; } } public int Id { get { return m_task.Id; } } public bool CancellationPending { get { return (m_task.Status == TaskStatus.WaitingToRun) && m_task.CancellationToken.IsCancellationRequested; } } public TaskStatus Status { get { return m_task.Status; } } diff --git a/src/System.Private.CoreLib/shared/System/Threading/Tasks/FutureFactory.cs b/src/System.Private.CoreLib/shared/System/Threading/Tasks/FutureFactory.cs index 55fab9a5de..cc4c938f51 100644 --- a/src/System.Private.CoreLib/shared/System/Threading/Tasks/FutureFactory.cs +++ b/src/System.Private.CoreLib/shared/System/Threading/Tasks/FutureFactory.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +#nullable enable using System.Diagnostics; namespace System.Threading.Tasks @@ -32,27 +33,20 @@ namespace System.Threading.Tasks // member variables private CancellationToken m_defaultCancellationToken; - private TaskScheduler m_defaultScheduler; + private TaskScheduler? m_defaultScheduler; private TaskCreationOptions m_defaultCreationOptions; private TaskContinuationOptions m_defaultContinuationOptions; - private TaskScheduler DefaultScheduler - { - get - { - if (m_defaultScheduler == null) return TaskScheduler.Current; - else return m_defaultScheduler; - } - } + private TaskScheduler DefaultScheduler => m_defaultScheduler ?? TaskScheduler.Current; // sister method to above property -- avoids a TLS lookup - private TaskScheduler GetDefaultScheduler(Task currTask) + private TaskScheduler GetDefaultScheduler(Task? currTask) { if (m_defaultScheduler != null) return m_defaultScheduler; else if ((currTask != null) && ((currTask.CreationOptions & TaskCreationOptions.HideScheduler) == 0) ) - return currTask.ExecutingTaskScheduler; + return currTask.ExecutingTaskScheduler!; // a "current" task must be executing, which means it must have a scheduler else return TaskScheduler.Default; } @@ -116,7 +110,7 @@ namespace System.Threading.Tasks /// initialized to the current scheduler (see TaskScheduler.Current). /// - public TaskFactory(TaskScheduler scheduler) // null means to use TaskScheduler.Current + public TaskFactory(TaskScheduler? scheduler) // null means to use TaskScheduler.Current : this(default, TaskCreationOptions.None, TaskContinuationOptions.None, scheduler) { } @@ -187,7 +181,7 @@ namespace System.Threading.Tasks /// current scheduler (see TaskScheduler.Current). /// - public TaskFactory(CancellationToken cancellationToken, TaskCreationOptions creationOptions, TaskContinuationOptions continuationOptions, TaskScheduler scheduler) + public TaskFactory(CancellationToken cancellationToken, TaskCreationOptions creationOptions, TaskContinuationOptions continuationOptions, TaskScheduler? scheduler) { TaskFactory.CheckMultiTaskContinuationOptions(continuationOptions); TaskFactory.CheckCreationOptions(creationOptions); @@ -221,7 +215,7 @@ namespace System.Threading.Tasks /// If null, TaskScheduler.Current /// will be used. /// - public TaskScheduler Scheduler { get { return m_defaultScheduler; } } + public TaskScheduler? Scheduler { get { return m_defaultScheduler; } } /// /// Gets the TaskCreationOptions @@ -264,7 +258,7 @@ namespace System.Threading.Tasks /// public Task StartNew(Func function) { - Task currTask = Task.InternalCurrent; + Task? currTask = Task.InternalCurrent; return Task.StartNew(currTask, function, m_defaultCancellationToken, m_defaultCreationOptions, InternalTaskOptions.None, GetDefaultScheduler(currTask)); } @@ -291,7 +285,7 @@ namespace System.Threading.Tasks /// public Task StartNew(Func function, CancellationToken cancellationToken) { - Task currTask = Task.InternalCurrent; + Task? currTask = Task.InternalCurrent; return Task.StartNew(currTask, function, cancellationToken, m_defaultCreationOptions, InternalTaskOptions.None, GetDefaultScheduler(currTask)); } @@ -320,7 +314,7 @@ namespace System.Threading.Tasks /// public Task StartNew(Func function, TaskCreationOptions creationOptions) { - Task currTask = Task.InternalCurrent; + Task? currTask = Task.InternalCurrent; return Task.StartNew(currTask, function, m_defaultCancellationToken, creationOptions, InternalTaskOptions.None, GetDefaultScheduler(currTask)); } @@ -383,9 +377,9 @@ namespace System.Threading.Tasks /// However, unless creation and scheduling must be separated, StartNew is the recommended approach /// for both simplicity and performance. /// - public Task StartNew(Func function, object state) + public Task StartNew(Func function, object? state) // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 { - Task currTask = Task.InternalCurrent; + Task? currTask = Task.InternalCurrent; return Task.StartNew(currTask, function, state, m_defaultCancellationToken, m_defaultCreationOptions, InternalTaskOptions.None, GetDefaultScheduler(currTask)); } @@ -412,9 +406,9 @@ namespace System.Threading.Tasks /// However, unless creation and scheduling must be separated, StartNew is the recommended approach /// for both simplicity and performance. /// - public Task StartNew(Func function, object state, CancellationToken cancellationToken) + public Task StartNew(Func function, object? state, CancellationToken cancellationToken) // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 { - Task currTask = Task.InternalCurrent; + Task? currTask = Task.InternalCurrent; return Task.StartNew(currTask, function, state, cancellationToken, m_defaultCreationOptions, InternalTaskOptions.None, GetDefaultScheduler(currTask)); } @@ -443,9 +437,9 @@ namespace System.Threading.Tasks /// However, unless creation and scheduling must be separated, StartNew is the recommended approach /// for both simplicity and performance. /// - public Task StartNew(Func function, object state, TaskCreationOptions creationOptions) + public Task StartNew(Func function, object? state, TaskCreationOptions creationOptions) // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 { - Task currTask = Task.InternalCurrent; + Task? currTask = Task.InternalCurrent; return Task.StartNew(currTask, function, state, m_defaultCancellationToken, creationOptions, InternalTaskOptions.None, GetDefaultScheduler(currTask)); } @@ -485,7 +479,7 @@ namespace System.Threading.Tasks /// However, unless creation and scheduling must be separated, StartNew is the recommended approach /// for both simplicity and performance. /// - public Task StartNew(Func function, object state, CancellationToken cancellationToken, TaskCreationOptions creationOptions, TaskScheduler scheduler) + public Task StartNew(Func function, object? state, CancellationToken cancellationToken, TaskCreationOptions creationOptions, TaskScheduler scheduler) // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 { return Task.StartNew(Task.InternalCurrentIfAttached(creationOptions), function, state, cancellationToken, creationOptions, InternalTaskOptions.None, scheduler); @@ -498,16 +492,16 @@ namespace System.Threading.Tasks // Common core logic for FromAsync calls. This minimizes the chance of "drift" between overload implementations. private static void FromAsyncCoreLogic( IAsyncResult iar, - Func endFunction, - Action endAction, + Func? endFunction, + Action? endAction, Task promise, bool requiresSynchronization) { Debug.Assert((endFunction != null) != (endAction != null), "Expected exactly one of endFunction/endAction to be non-null"); - Exception ex = null; - OperationCanceledException oce = null; - TResult result = default; + Exception? ex = null; + OperationCanceledException? oce = null; + TResult result = default!; // TODO-NULLABLE-GENERIC try { @@ -517,7 +511,7 @@ namespace System.Threading.Tasks } else { - endAction(iar); + endAction!(iar); } } catch (OperationCanceledException _oce) { oce = _oce; } @@ -636,8 +630,8 @@ namespace System.Threading.Tasks // method can access the logic w/o declaring a TaskFactory instance. internal static Task FromAsyncImpl( IAsyncResult asyncResult, - Func endFunction, - Action endAction, + Func? endFunction, + Action? endAction, TaskCreationOptions creationOptions, TaskScheduler scheduler) { @@ -654,7 +648,7 @@ namespace System.Threading.Tasks TaskFactory.CheckFromAsyncOptions(creationOptions, false); - Task promise = new Task((object)null, creationOptions); + Task promise = new Task((object?)null, creationOptions); if (AsyncCausalityTracer.LoggingOn) AsyncCausalityTracer.TraceOperationCreation(promise, "TaskFactory.FromAsync"); @@ -669,7 +663,7 @@ namespace System.Threading.Tasks { FromAsyncCoreLogic(asyncResult, endFunction, endAction, promise, requiresSynchronization: true); }), - (object)null, null, + (object?)null, null, default, TaskCreationOptions.None, InternalTaskOptions.None, null); if (AsyncCausalityTracer.LoggingOn) @@ -678,9 +672,9 @@ namespace System.Threading.Tasks if (Task.s_asyncDebuggingEnabled) Task.AddToActiveTasks(t); - if (asyncResult.IsCompleted) + if (asyncResult!.IsCompleted) // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 { - try { t.InternalRunSynchronously(scheduler, waitForCompletion: false); } + try { t.InternalRunSynchronously(scheduler!, waitForCompletion: false); } // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 catch (Exception e) { promise.TrySetException(e); } // catch and log any scheduler exceptions } else @@ -718,8 +712,8 @@ namespace System.Threading.Tasks /// This method throws any exceptions thrown by the . /// public Task FromAsync( - Func beginMethod, - Func endMethod, object state) + Func beginMethod, + Func endMethod, object? state) // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 { return FromAsyncImpl(beginMethod, endMethod, null, state, m_defaultCreationOptions); } @@ -747,17 +741,17 @@ namespace System.Threading.Tasks /// This method throws any exceptions thrown by the . /// public Task FromAsync( - Func beginMethod, - Func endMethod, object state, TaskCreationOptions creationOptions) + Func beginMethod, + Func endMethod, object? state, TaskCreationOptions creationOptions) // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 { return FromAsyncImpl(beginMethod, endMethod, null, state, creationOptions); } // We need this logic broken out into a static method so that the similar TaskFactory.FromAsync() // method can access the logic w/o declaring a TaskFactory instance. - internal static Task FromAsyncImpl(Func beginMethod, - Func endFunction, Action endAction, - object state, TaskCreationOptions creationOptions) + internal static Task FromAsyncImpl(Func beginMethod, + Func? endFunction, Action? endAction, + object? state, TaskCreationOptions creationOptions) { if (beginMethod == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.beginMethod); @@ -772,7 +766,7 @@ namespace System.Threading.Tasks Task promise = new Task(state, creationOptions); if (AsyncCausalityTracer.LoggingOn) - AsyncCausalityTracer.TraceOperationCreation(promise, "TaskFactory.FromAsync: " + beginMethod.Method.Name); + AsyncCausalityTracer.TraceOperationCreation(promise, "TaskFactory.FromAsync: " + beginMethod!.Method.Name); // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 if (Task.s_asyncDebuggingEnabled) Task.AddToActiveTasks(promise); @@ -780,7 +774,7 @@ namespace System.Threading.Tasks try { //if we don't require synchronization, a faster set result path is taken - var asyncResult = beginMethod(iar => + var asyncResult = beginMethod!(iar => // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 { if (!iar.CompletedSynchronously) FromAsyncCoreLogic(iar, endFunction, endAction, promise, requiresSynchronization: true); @@ -829,9 +823,9 @@ namespace System.Threading.Tasks /// This method throws any exceptions thrown by the . /// public Task FromAsync( - Func beginMethod, + Func beginMethod, Func endMethod, - TArg1 arg1, object state) + TArg1 arg1, object? state) // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 { return FromAsyncImpl(beginMethod, endMethod, null, arg1, state, m_defaultCreationOptions); } @@ -863,18 +857,18 @@ namespace System.Threading.Tasks /// This method throws any exceptions thrown by the . /// public Task FromAsync( - Func beginMethod, + Func beginMethod, Func endMethod, - TArg1 arg1, object state, TaskCreationOptions creationOptions) + TArg1 arg1, object? state, TaskCreationOptions creationOptions) // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 { return FromAsyncImpl(beginMethod, endMethod, null, arg1, state, creationOptions); } // We need this logic broken out into a static method so that the similar TaskFactory.FromAsync() // method can access the logic w/o declaring a TaskFactory instance. - internal static Task FromAsyncImpl(Func beginMethod, - Func endFunction, Action endAction, - TArg1 arg1, object state, TaskCreationOptions creationOptions) + internal static Task FromAsyncImpl(Func beginMethod, + Func? endFunction, Action? endAction, + TArg1 arg1, object? state, TaskCreationOptions creationOptions) { if (beginMethod == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.beginMethod); @@ -889,7 +883,7 @@ namespace System.Threading.Tasks Task promise = new Task(state, creationOptions); if (AsyncCausalityTracer.LoggingOn) - AsyncCausalityTracer.TraceOperationCreation(promise, "TaskFactory.FromAsync: " + beginMethod.Method.Name); + AsyncCausalityTracer.TraceOperationCreation(promise, "TaskFactory.FromAsync: " + beginMethod!.Method.Name); // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 if (Task.s_asyncDebuggingEnabled) Task.AddToActiveTasks(promise); @@ -897,7 +891,7 @@ namespace System.Threading.Tasks try { //if we don't require synchronization, a faster set result path is taken - var asyncResult = beginMethod(arg1, iar => + var asyncResult = beginMethod!(arg1, iar => // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 { if (!iar.CompletedSynchronously) FromAsyncCoreLogic(iar, endFunction, endAction, promise, requiresSynchronization: true); @@ -950,9 +944,9 @@ namespace System.Threading.Tasks /// This method throws any exceptions thrown by the . /// public Task FromAsync( - Func beginMethod, + Func beginMethod, Func endMethod, - TArg1 arg1, TArg2 arg2, object state) + TArg1 arg1, TArg2 arg2, object? state) // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 { return FromAsyncImpl(beginMethod, endMethod, null, arg1, arg2, state, m_defaultCreationOptions); } @@ -988,18 +982,18 @@ namespace System.Threading.Tasks /// This method throws any exceptions thrown by the . /// public Task FromAsync( - Func beginMethod, + Func beginMethod, Func endMethod, - TArg1 arg1, TArg2 arg2, object state, TaskCreationOptions creationOptions) + TArg1 arg1, TArg2 arg2, object? state, TaskCreationOptions creationOptions) // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 { return FromAsyncImpl(beginMethod, endMethod, null, arg1, arg2, state, creationOptions); } // We need this logic broken out into a static method so that the similar TaskFactory.FromAsync() // method can access the logic w/o declaring a TaskFactory instance. - internal static Task FromAsyncImpl(Func beginMethod, - Func endFunction, Action endAction, - TArg1 arg1, TArg2 arg2, object state, TaskCreationOptions creationOptions) + internal static Task FromAsyncImpl(Func beginMethod, + Func? endFunction, Action? endAction, + TArg1 arg1, TArg2 arg2, object? state, TaskCreationOptions creationOptions) // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 { if (beginMethod == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.beginMethod); @@ -1014,7 +1008,7 @@ namespace System.Threading.Tasks Task promise = new Task(state, creationOptions); if (AsyncCausalityTracer.LoggingOn) - AsyncCausalityTracer.TraceOperationCreation(promise, "TaskFactory.FromAsync: " + beginMethod.Method.Name); + AsyncCausalityTracer.TraceOperationCreation(promise, "TaskFactory.FromAsync: " + beginMethod!.Method.Name); // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 if (Task.s_asyncDebuggingEnabled) Task.AddToActiveTasks(promise); @@ -1022,7 +1016,7 @@ namespace System.Threading.Tasks try { //if we don't require synchronization, a faster set result path is taken - var asyncResult = beginMethod(arg1, arg2, iar => + var asyncResult = beginMethod!(arg1, arg2, iar => // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 { if (!iar.CompletedSynchronously) FromAsyncCoreLogic(iar, endFunction, endAction, promise, requiresSynchronization: true); @@ -1079,9 +1073,9 @@ namespace System.Threading.Tasks /// This method throws any exceptions thrown by the . /// public Task FromAsync( - Func beginMethod, + Func beginMethod, Func endMethod, - TArg1 arg1, TArg2 arg2, TArg3 arg3, object state) + TArg1 arg1, TArg2 arg2, TArg3 arg3, object? state) { return FromAsyncImpl(beginMethod, endMethod, null, arg1, arg2, arg3, state, m_defaultCreationOptions); } @@ -1121,18 +1115,18 @@ namespace System.Threading.Tasks /// This method throws any exceptions thrown by the . /// public Task FromAsync( - Func beginMethod, + Func beginMethod, Func endMethod, - TArg1 arg1, TArg2 arg2, TArg3 arg3, object state, TaskCreationOptions creationOptions) + TArg1 arg1, TArg2 arg2, TArg3 arg3, object? state, TaskCreationOptions creationOptions) { return FromAsyncImpl(beginMethod, endMethod, null, arg1, arg2, arg3, state, creationOptions); } // We need this logic broken out into a static method so that the similar TaskFactory.FromAsync() // method can access the logic w/o declaring a TaskFactory instance. - internal static Task FromAsyncImpl(Func beginMethod, - Func endFunction, Action endAction, - TArg1 arg1, TArg2 arg2, TArg3 arg3, object state, TaskCreationOptions creationOptions) + internal static Task FromAsyncImpl(Func beginMethod, + Func? endFunction, Action? endAction, + TArg1 arg1, TArg2 arg2, TArg3 arg3, object? state, TaskCreationOptions creationOptions) { if (beginMethod == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.beginMethod); @@ -1147,7 +1141,7 @@ namespace System.Threading.Tasks Task promise = new Task(state, creationOptions); if (AsyncCausalityTracer.LoggingOn) - AsyncCausalityTracer.TraceOperationCreation(promise, "TaskFactory.FromAsync: " + beginMethod.Method.Name); + AsyncCausalityTracer.TraceOperationCreation(promise, "TaskFactory.FromAsync: " + beginMethod!.Method.Name); // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 if (Task.s_asyncDebuggingEnabled) Task.AddToActiveTasks(promise); @@ -1155,7 +1149,7 @@ namespace System.Threading.Tasks try { //if we don't require synchronization, a faster set result path is taken - var asyncResult = beginMethod(arg1, arg2, arg3, iar => + var asyncResult = beginMethod!(arg1, arg2, arg3, iar => // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 { if (!iar.CompletedSynchronously) FromAsyncCoreLogic(iar, endFunction, endAction, promise, requiresSynchronization: true); @@ -1237,7 +1231,7 @@ namespace System.Threading.Tasks /// A reference to the object on which the begin/end methods are invoked. private TInstance m_thisRef; /// The end method. - private Func m_endMethod; + private Func? m_endMethod; /// Initializes the promise. /// A reference to the object on which the begin/end methods are invoked. @@ -1260,13 +1254,13 @@ namespace System.Threading.Tasks // Validate argument if (asyncResult == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.asyncResult); - var promise = asyncResult.AsyncState as FromAsyncTrimPromise; + var promise = asyncResult!.AsyncState as FromAsyncTrimPromise; // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 if (promise == null) ThrowHelper.ThrowArgumentException(ExceptionResource.InvalidOperation_WrongAsyncResultOrEndCalledMultiple, ExceptionArgument.asyncResult); // Grab the relevant state and then null it out so that the task doesn't hold onto the state unnecessarily - var thisRef = promise.m_thisRef; + var thisRef = promise!.m_thisRef; // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 var endMethod = promise.m_endMethod; - promise.m_thisRef = default; + promise.m_thisRef = default!; // TODO-NULLABLE-GENERIC promise.m_endMethod = null; if (endMethod == null) ThrowHelper.ThrowArgumentException(ExceptionResource.InvalidOperation_WrongAsyncResultOrEndCalledMultiple, ExceptionArgument.asyncResult); @@ -1274,7 +1268,7 @@ namespace System.Threading.Tasks // we'll instead complete the promise at the call site. if (!asyncResult.CompletedSynchronously) { - promise.Complete(thisRef, endMethod, asyncResult, requiresSynchronization: true); + promise.Complete(thisRef, endMethod!, asyncResult, requiresSynchronization: true); // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 } } @@ -1328,9 +1322,8 @@ namespace System.Threading.Tasks private static Task CreateCanceledTask(TaskContinuationOptions continuationOptions, CancellationToken ct) { TaskCreationOptions tco; - InternalTaskOptions dontcare; - Task.CreationOptionsFromContinuationOptions(continuationOptions, out tco, out dontcare); - return new Task(true, default, tco, ct); + Task.CreationOptionsFromContinuationOptions(continuationOptions, out tco, out _); + return new Task(true, default!, tco, ct); // TODO-NULLABLE-GENERIC } // @@ -1607,7 +1600,7 @@ namespace System.Threading.Tasks // Core implementation of ContinueWhenAll -- the generic version // Note: if you make any changes to this method, please do the same to the non-generic version too. internal static Task ContinueWhenAllImpl(Task[] tasks, - Func[], TResult> continuationFunction, Action[]> continuationAction, + Func[], TResult>? continuationFunction, Action[]>? continuationAction, TaskContinuationOptions continuationOptions, CancellationToken cancellationToken, TaskScheduler scheduler) { // check arguments @@ -1618,7 +1611,7 @@ namespace System.Threading.Tasks if (scheduler == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.scheduler); // Check tasks array and make defensive copy - Task[] tasksCopy = TaskFactory.CheckMultiContinuationTasksAndCopy(tasks); + Task[] tasksCopy = TaskFactory.CheckMultiContinuationTasksAndCopy(tasks!); // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 // Bail early if cancellation has been requested. if (cancellationToken.IsCancellationRequested @@ -1637,7 +1630,7 @@ namespace System.Threading.Tasks return starter.ContinueWith( // use a cached delegate GenericDelegateCache.CWAllFuncDelegate, - continuationFunction, scheduler, cancellationToken, continuationOptions); + continuationFunction, scheduler!, cancellationToken, continuationOptions); // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 } else { @@ -1646,14 +1639,14 @@ namespace System.Threading.Tasks return starter.ContinueWith( // use a cached delegate GenericDelegateCache.CWAllActionDelegate, - continuationAction, scheduler, cancellationToken, continuationOptions); + continuationAction, scheduler!, cancellationToken, continuationOptions); // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 } } // Core implementation of ContinueWhenAll -- the non-generic version // Note: if you make any changes to this method, please do the same to the generic version too. internal static Task ContinueWhenAllImpl(Task[] tasks, - Func continuationFunction, Action continuationAction, + Func? continuationFunction, Action? continuationAction, TaskContinuationOptions continuationOptions, CancellationToken cancellationToken, TaskScheduler scheduler) { // check arguments @@ -1664,7 +1657,7 @@ namespace System.Threading.Tasks if (scheduler == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.scheduler); // Check tasks array and make defensive copy - Task[] tasksCopy = TaskFactory.CheckMultiContinuationTasksAndCopy(tasks); + Task[] tasksCopy = TaskFactory.CheckMultiContinuationTasksAndCopy(tasks!); // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 // Bail early if cancellation has been requested. if (cancellationToken.IsCancellationRequested @@ -1687,9 +1680,10 @@ namespace System.Threading.Tasks (completedTasks, state) => { completedTasks.NotifyDebuggerOfWaitCompletionIfNecessary(); + Debug.Assert(state is Func); return ((Func)state)(completedTasks.Result); }, - continuationFunction, scheduler, cancellationToken, continuationOptions); + continuationFunction, scheduler!, cancellationToken, continuationOptions); // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 } else { @@ -1701,9 +1695,10 @@ namespace System.Threading.Tasks (completedTasks, state) => { completedTasks.NotifyDebuggerOfWaitCompletionIfNecessary(); - ((Action)state)(completedTasks.Result); return default; + Debug.Assert(state is Action); + ((Action)state)(completedTasks.Result); return default!; // TODO-NULLABLE-GENERIC }, - continuationAction, scheduler, cancellationToken, continuationOptions); + continuationAction, scheduler!, cancellationToken, continuationOptions); // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 } } @@ -1980,13 +1975,13 @@ namespace System.Threading.Tasks // Core implementation of ContinueWhenAny, non-generic version // Note: if you make any changes to this method, be sure to do the same to the generic version internal static Task ContinueWhenAnyImpl(Task[] tasks, - Func continuationFunction, Action continuationAction, + Func? continuationFunction, Action? continuationAction, TaskContinuationOptions continuationOptions, CancellationToken cancellationToken, TaskScheduler scheduler) { // check arguments TaskFactory.CheckMultiTaskContinuationOptions(continuationOptions); if (tasks == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.tasks); - if (tasks.Length == 0) ThrowHelper.ThrowArgumentException(ExceptionResource.Task_MultiTaskContinuation_EmptyTaskList, ExceptionArgument.tasks); + if (tasks!.Length == 0) ThrowHelper.ThrowArgumentException(ExceptionResource.Task_MultiTaskContinuation_EmptyTaskList, ExceptionArgument.tasks); // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 //ArgumentNullException of continuationFunction or continuationAction is checked by the caller Debug.Assert((continuationFunction != null) != (continuationAction != null), "Expected exactly one of endFunction/endAction to be non-null"); @@ -2009,8 +2004,12 @@ namespace System.Threading.Tasks return starter.ContinueWith( //the following delegate avoids closure capture as much as possible //completedTask.Result is the winning task; state == continuationAction - (completedTask, state) => { return ((Func)state)(completedTask.Result); }, - continuationFunction, scheduler, cancellationToken, continuationOptions); + (completedTask, state) => + { + Debug.Assert(state is Func); + return ((Func)state)(completedTask.Result); + }, + continuationFunction, scheduler!, cancellationToken, continuationOptions); // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 } else { @@ -2018,8 +2017,13 @@ namespace System.Threading.Tasks return starter.ContinueWith( //the following delegate avoids closure capture as much as possible //completedTask.Result is the winning task; state == continuationAction - (completedTask, state) => { ((Action)state)(completedTask.Result); return default; }, - continuationAction, scheduler, cancellationToken, continuationOptions); + (completedTask, state) => + { + Debug.Assert(state is Action); + ((Action)state)(completedTask.Result); + return default!; // TODO-NULLABLE-GENERIC + }, + continuationAction, scheduler!, cancellationToken, continuationOptions); // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 } } @@ -2027,13 +2031,13 @@ namespace System.Threading.Tasks // Core implementation of ContinueWhenAny, generic version // Note: if you make any changes to this method, be sure to do the same to the non-generic version internal static Task ContinueWhenAnyImpl(Task[] tasks, - Func, TResult> continuationFunction, Action> continuationAction, + Func, TResult>? continuationFunction, Action>? continuationAction, TaskContinuationOptions continuationOptions, CancellationToken cancellationToken, TaskScheduler scheduler) { // check arguments TaskFactory.CheckMultiTaskContinuationOptions(continuationOptions); if (tasks == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.tasks); - if (tasks.Length == 0) ThrowHelper.ThrowArgumentException(ExceptionResource.Task_MultiTaskContinuation_EmptyTaskList, ExceptionArgument.tasks); + if (tasks!.Length == 0) ThrowHelper.ThrowArgumentException(ExceptionResource.Task_MultiTaskContinuation_EmptyTaskList, ExceptionArgument.tasks); // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 //ArgumentNullException of continuationFunction or continuationAction is checked by the caller Debug.Assert((continuationFunction != null) != (continuationAction != null), "Expected exactly one of endFunction/endAction to be non-null"); if (scheduler == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.scheduler); @@ -2055,7 +2059,7 @@ namespace System.Threading.Tasks return starter.ContinueWith( // Use a cached delegate GenericDelegateCache.CWAnyFuncDelegate, - continuationFunction, scheduler, cancellationToken, continuationOptions); + continuationFunction, scheduler!, cancellationToken, continuationOptions); // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 } else { @@ -2063,7 +2067,7 @@ namespace System.Threading.Tasks return starter.ContinueWith( // Use a cached delegate GenericDelegateCache.CWAnyActionDelegate, - continuationAction, scheduler, cancellationToken, continuationOptions); + continuationAction, scheduler!, cancellationToken, continuationOptions); // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 } } } @@ -2074,41 +2078,45 @@ namespace System.Threading.Tasks internal static class GenericDelegateCache { // ContinueWith delegate for TaskFactory.ContinueWhenAnyImpl(non-null continuationFunction) - internal static Func, object, TResult> CWAnyFuncDelegate = - (Task wrappedWinner, object state) => + internal static Func, object?, TResult> CWAnyFuncDelegate = + (Task wrappedWinner, object? state) => { + Debug.Assert(state is Func, TResult>); var func = (Func, TResult>)state; var arg = (Task)wrappedWinner.Result; return func(arg); }; // ContinueWith delegate for TaskFactory.ContinueWhenAnyImpl(non-null continuationAction) - internal static Func, object, TResult> CWAnyActionDelegate = - (Task wrappedWinner, object state) => + internal static Func, object?, TResult> CWAnyActionDelegate = + (Task wrappedWinner, object? state) => { + Debug.Assert(state is Action>); var action = (Action>)state; var arg = (Task)wrappedWinner.Result; action(arg); - return default; + return default!; // TODO-NULLABLE-GENERIC }; // ContinueWith delegate for TaskFactory.ContinueWhenAllImpl(non-null continuationFunction) - internal static Func[]>, object, TResult> CWAllFuncDelegate = - (Task[]> wrappedAntecedents, object state) => + internal static Func[]>, object?, TResult> CWAllFuncDelegate = + (Task[]> wrappedAntecedents, object? state) => { wrappedAntecedents.NotifyDebuggerOfWaitCompletionIfNecessary(); + Debug.Assert(state is Func>); var func = (Func[], TResult>)state; return func(wrappedAntecedents.Result); }; // ContinueWith delegate for TaskFactory.ContinueWhenAllImpl(non-null continuationAction) - internal static Func[]>, object, TResult> CWAllActionDelegate = - (Task[]> wrappedAntecedents, object state) => + internal static Func[]>, object?, TResult> CWAllActionDelegate = + (Task[]> wrappedAntecedents, object? state) => { wrappedAntecedents.NotifyDebuggerOfWaitCompletionIfNecessary(); + Debug.Assert(state is Action[]>); var action = (Action[]>)state; action(wrappedAntecedents.Result); - return default; + return default!; // TODO-NULLABLE-GENERIC }; } } diff --git a/src/System.Private.CoreLib/shared/System/Threading/Tasks/ProducerConsumerQueues.cs b/src/System.Private.CoreLib/shared/System/Threading/Tasks/ProducerConsumerQueues.cs index 1880288c51..21214e85a8 100644 --- a/src/System.Private.CoreLib/shared/System/Threading/Tasks/ProducerConsumerQueues.cs +++ b/src/System.Private.CoreLib/shared/System/Threading/Tasks/ProducerConsumerQueues.cs @@ -21,6 +21,7 @@ // ************************* // =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +#nullable enable using System.Collections; using System.Collections.Concurrent; using System.Collections.Generic; @@ -204,7 +205,7 @@ namespace System.Threading.Tasks if (first != segment.m_state.m_lastCopy) { result = array[first]; - array[first] = default; // Clear the slot to release the element + array[first] = default!; // Clear the slot to release the element // TODO-NULLABLE-GENERIC segment.m_state.m_first = (first + 1) & (array.Length - 1); return true; } @@ -239,12 +240,12 @@ namespace System.Threading.Tasks if (first == segment.m_state.m_last) { - result = default; + result = default!; // TODO-NULLABLE-GENERIC return false; } result = array[first]; - array[first] = default; // Clear the slot to release the element + array[first] = default!; // Clear the slot to release the element // TODO-NULLABLE-GENERIC segment.m_state.m_first = (first + 1) & (segment.m_array.Length - 1); segment.m_state.m_lastCopy = segment.m_state.m_last; // Refresh m_lastCopy to ensure that m_first has not passed m_lastCopy @@ -269,7 +270,7 @@ namespace System.Threading.Tasks /// WARNING: This should only be used for debugging purposes. It is not safe to be used concurrently. public IEnumerator GetEnumerator() { - for (Segment segment = m_head; segment != null; segment = segment.m_next) + for (Segment? segment = m_head; segment != null; segment = segment.m_next) { for (int pt = segment.m_state.m_first; pt != segment.m_state.m_last; @@ -290,7 +291,7 @@ namespace System.Threading.Tasks get { int count = 0; - for (Segment segment = m_head; segment != null; segment = segment.m_next) + for (Segment? segment = m_head; segment != null; segment = segment.m_next) { int arraySize = segment.m_array.Length; int first, last; @@ -311,7 +312,7 @@ namespace System.Threading.Tasks private sealed class Segment { /// The next segment in the linked list of segments. - internal Segment m_next; + internal Segment? m_next; /// The data stored in this segment. internal readonly T[] m_array; /// Details about the segment. diff --git a/src/System.Private.CoreLib/shared/System/Threading/Tasks/Sources/IValueTaskSource.cs b/src/System.Private.CoreLib/shared/System/Threading/Tasks/Sources/IValueTaskSource.cs index e411146a1d..6181ab2bf0 100644 --- a/src/System.Private.CoreLib/shared/System/Threading/Tasks/Sources/IValueTaskSource.cs +++ b/src/System.Private.CoreLib/shared/System/Threading/Tasks/Sources/IValueTaskSource.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +#nullable enable namespace System.Threading.Tasks.Sources { /// @@ -53,7 +54,7 @@ namespace System.Threading.Tasks.Sources /// The state object to pass to when it's invoked. /// Opaque value that was provided to the 's constructor. /// The flags describing the behavior of the continuation. - void OnCompleted(Action continuation, object state, short token, ValueTaskSourceOnCompletedFlags flags); + void OnCompleted(Action continuation, object? state, short token, ValueTaskSourceOnCompletedFlags flags); // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 /// Gets the result of the . /// Opaque value that was provided to the 's constructor. @@ -73,7 +74,7 @@ namespace System.Threading.Tasks.Sources /// The state object to pass to when it's invoked. /// Opaque value that was provided to the 's constructor. /// The flags describing the behavior of the continuation. - void OnCompleted(Action continuation, object state, short token, ValueTaskSourceOnCompletedFlags flags); + void OnCompleted(Action continuation, object? state, short token, ValueTaskSourceOnCompletedFlags flags); // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 /// Gets the result of the . /// Opaque value that was provided to the 's constructor. diff --git a/src/System.Private.CoreLib/shared/System/Threading/Tasks/Sources/ManualResetValueTaskSourceCore.cs b/src/System.Private.CoreLib/shared/System/Threading/Tasks/Sources/ManualResetValueTaskSourceCore.cs index 797ed6ed8a..967cbbeadf 100644 --- a/src/System.Private.CoreLib/shared/System/Threading/Tasks/Sources/ManualResetValueTaskSourceCore.cs +++ b/src/System.Private.CoreLib/shared/System/Threading/Tasks/Sources/ManualResetValueTaskSourceCore.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +#nullable enable using System.Diagnostics; using System.Runtime.ExceptionServices; using System.Runtime.InteropServices; @@ -18,22 +19,22 @@ namespace System.Threading.Tasks.Sources /// or if the operation completed before a callback was supplied, /// or null if a callback hasn't yet been provided and the operation hasn't yet completed. /// - private Action _continuation; + private Action? _continuation; /// State to pass to . - private object _continuationState; + private object? _continuationState; /// to flow to the callback, or null if no flowing is required. - private ExecutionContext _executionContext; + private ExecutionContext? _executionContext; /// /// A "captured" or with which to invoke the callback, /// or null if no special context is required. /// - private object _capturedContext; + private object? _capturedContext; /// Whether the current operation has completed. private bool _completed; /// The result with which the operation succeeded, or the default value if it hasn't yet completed or failed. private TResult _result; /// The exception with which the operation failed, or null if it hasn't yet completed or completed successfully. - private ExceptionDispatchInfo _error; + private ExceptionDispatchInfo? _error; /// The current version of this value, used to help prevent misuse. private short _version; @@ -47,7 +48,7 @@ namespace System.Threading.Tasks.Sources // Reset/update state for the next use/await of this instance. _version++; _completed = false; - _result = default; + _result = default!; // TODO-NULLABLE-GENERIC _error = null; _executionContext = null; _capturedContext = null; @@ -106,7 +107,7 @@ namespace System.Threading.Tasks.Sources /// The state object to pass to when it's invoked. /// Opaque value that was provided to the 's constructor. /// The flags describing the behavior of the continuation. - public void OnCompleted(Action continuation, object state, short token, ValueTaskSourceOnCompletedFlags flags) + public void OnCompleted(Action continuation, object? state, short token, ValueTaskSourceOnCompletedFlags flags) // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 { if (continuation == null) { @@ -121,7 +122,7 @@ namespace System.Threading.Tasks.Sources if ((flags & ValueTaskSourceOnCompletedFlags.UseSchedulingContext) != 0) { - SynchronizationContext sc = SynchronizationContext.Current; + SynchronizationContext? sc = SynchronizationContext.Current; if (sc != null && sc.GetType() != typeof(SynchronizationContext)) { _capturedContext = sc; @@ -144,7 +145,7 @@ namespace System.Threading.Tasks.Sources // To minimize the chances of that, we check preemptively whether _continuation // is already set to something other than the completion sentinel. - object oldContinuation = _continuation; + object? oldContinuation = _continuation; if (oldContinuation == null) { _continuationState = state; @@ -175,7 +176,7 @@ namespace System.Threading.Tasks.Sources case SynchronizationContext sc: sc.Post(s => { - var tuple = (Tuple, object>)s; + var tuple = (Tuple, object?>)s!; // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 tuple.Item1(tuple.Item2); }, Tuple.Create(continuation, state)); break; @@ -229,6 +230,8 @@ namespace System.Threading.Tasks.Sources /// private void InvokeContinuation() { + Debug.Assert(_continuation != null); + switch (_capturedContext) { case null: @@ -252,7 +255,7 @@ namespace System.Threading.Tasks.Sources case SynchronizationContext sc: sc.Post(s => { - var state = (Tuple, object>)s; + var state = (Tuple, object?>)s!; // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 state.Item1(state.Item2); }, Tuple.Create(_continuation, _continuationState)); break; @@ -266,8 +269,8 @@ namespace System.Threading.Tasks.Sources internal static class ManualResetValueTaskSourceCoreShared // separated out of generic to avoid unnecessary duplication { - internal static readonly Action s_sentinel = CompletionSentinel; - private static void CompletionSentinel(object _) // named method to aid debugging + internal static readonly Action s_sentinel = CompletionSentinel; + private static void CompletionSentinel(object? _) // named method to aid debugging { Debug.Fail("The sentinel delegate should never be invoked."); ThrowHelper.ThrowInvalidOperationException(); diff --git a/src/System.Private.CoreLib/shared/System/Threading/Tasks/Task.cs b/src/System.Private.CoreLib/shared/System/Threading/Tasks/Task.cs index 5d893c5cee..a8aac04936 100644 --- a/src/System.Private.CoreLib/shared/System/Threading/Tasks/Task.cs +++ b/src/System.Private.CoreLib/shared/System/Threading/Tasks/Task.cs @@ -10,6 +10,7 @@ // // =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +#nullable enable using System.Collections.Generic; using System.Collections.ObjectModel; using System.Diagnostics; @@ -130,13 +131,13 @@ namespace System.Threading.Tasks public class Task : IAsyncResult, IDisposable { [ThreadStatic] - internal static Task t_currentTask; // The currently executing task. + internal static Task? t_currentTask; // The currently executing task. internal static int s_taskIdCounter; //static counter used to generate unique task IDs private volatile int m_taskId; // this task's unique ID. initialized only if it is ever requested - internal Delegate m_action; // The body of the task. Might be Action, Action or Action. Or possibly a Func. + internal Delegate? m_action; // The body of the task. Might be Action, Action or Action. Or possibly a Func. // If m_action is set to null it will indicate that we operate in the // "externally triggered completion" mode, which is exclusively meant // for the signalling Task (aka. promise). In this mode, @@ -145,12 +146,12 @@ namespace System.Threading.Tasks // But the event would now be signalled if Cancel() is called - internal object m_stateObject; // A state object that can be optionally supplied, passed to action. - internal TaskScheduler m_taskScheduler; // The task scheduler this task runs under. + internal object? m_stateObject; // A state object that can be optionally supplied, passed to action. + internal TaskScheduler? m_taskScheduler; // The task scheduler this task runs under. internal volatile int m_stateFlags; // SOS DumpAsync command depends on this name - private Task ParentForDebugger => m_contingentProperties?.m_parent; // Private property used by a debugger to access this Task's parent + private Task? ParentForDebugger => m_contingentProperties?.m_parent; // Private property used by a debugger to access this Task's parent private int StateFlagsForDebugger => m_stateFlags; // Private property used by a debugger to access this Task's state flags // State constants for m_stateFlags; @@ -188,7 +189,7 @@ namespace System.Threading.Tasks // Can be null, a single continuation, a list of continuations, or s_taskCompletionSentinel, // in that order. The logic arround this object assumes it will never regress to a previous state. - private volatile object m_continuationObject = null; // SOS DumpAsync command depends on this name + private volatile object? m_continuationObject = null; // SOS DumpAsync command depends on this name // m_continuationObject is set to this when the task completes. private static readonly object s_taskCompletionSentinel = new object(); @@ -199,7 +200,7 @@ namespace System.Threading.Tasks // This dictonary relates the task id, from an operation id located in the Async Causality log to the actual // task. This is to be used by the debugger ONLY. Task in this dictionary represent current active tasks. - private static Dictionary s_currentActiveTasks; + private static Dictionary? s_currentActiveTasks; // These methods are a way to access the dictionary both from this class and for other classes that also // activate dummy tasks. Specifically the AsyncTaskMethodBuilder and AsyncTaskMethodBuilder<> @@ -210,9 +211,9 @@ namespace System.Threading.Tasks LazyInitializer.EnsureInitialized(ref s_currentActiveTasks, () => new Dictionary()); int taskId = task.Id; - lock (s_currentActiveTasks) + lock (s_currentActiveTasks!) // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 { - s_currentActiveTasks[taskId] = task; + s_currentActiveTasks![taskId] = task; // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 } //always return true to keep signature as bool for backwards compatibility return true; @@ -238,17 +239,17 @@ namespace System.Threading.Tasks { // Additional context - internal ExecutionContext m_capturedContext; // The execution context to run the task within, if any. Only set from non-concurrent contexts. + internal ExecutionContext? m_capturedContext; // The execution context to run the task within, if any. Only set from non-concurrent contexts. // Completion fields (exceptions and event) - internal volatile ManualResetEventSlim m_completionEvent; // Lazily created if waiting is required. - internal volatile TaskExceptionHolder m_exceptionsHolder; // Tracks exceptions, if any have occurred + internal volatile ManualResetEventSlim? m_completionEvent; // Lazily created if waiting is required. + internal volatile TaskExceptionHolder? m_exceptionsHolder; // Tracks exceptions, if any have occurred // Cancellation fields (token, registration, and internally requested) internal CancellationToken m_cancellationToken; // Task's cancellation token, if it has one - internal Shared m_cancellationRegistration; // Task's registration with the cancellation token + internal Shared? m_cancellationRegistration; // Task's registration with the cancellation token internal volatile int m_internalCancellationRequested; // Its own field because multiple threads legally try to set it. // Parenting fields @@ -260,9 +261,9 @@ namespace System.Threading.Tasks internal volatile int m_completionCountdown = 1; // A list of child tasks that threw an exception (TCEs don't count), // but haven't yet been waited on by the parent, lazily initialized. - internal volatile List m_exceptionalChildren; + internal volatile List? m_exceptionalChildren; // A task's parent, or null if parent-less. Only set during Task construction. - internal Task m_parent; + internal Task? m_parent; /// /// Sets the internal completion event. @@ -295,7 +296,7 @@ namespace System.Threading.Tasks // This field will only be instantiated to some non-null value if any ContingentProperties need to be set. // This will be a ContingentProperties instance or a type derived from it - internal ContingentProperties m_contingentProperties; + internal ContingentProperties? m_contingentProperties; // Special internal constructor to create an already-completed task. // if canceled==true, create a Canceled task, or else create a RanToCompletion task. @@ -325,7 +326,7 @@ namespace System.Threading.Tasks // Special constructor for use with promise-style tasks. // Added promiseStyle parameter as an aid to the compiler to distinguish between (state,TCO) and // (action,TCO). It should always be true. - internal Task(object state, TaskCreationOptions creationOptions, bool promiseStyle) + internal Task(object? state, TaskCreationOptions creationOptions, bool promiseStyle) { Debug.Assert(promiseStyle, "Promise CTOR: promiseStyle was false"); @@ -339,7 +340,7 @@ namespace System.Threading.Tasks // Only set a parent if AttachedToParent is specified. if ((creationOptions & TaskCreationOptions.AttachedToParent) != 0) { - Task parent = Task.InternalCurrent; + Task? parent = Task.InternalCurrent; if (parent != null) { EnsureContingentPropertiesInitializedUnsafe().m_parent = parent; @@ -427,7 +428,7 @@ namespace System.Threading.Tasks /// /// The argument is null. /// - public Task(Action action, object state) + public Task(Action action, object? state) // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 : this(action, state, null, default, TaskCreationOptions.None, InternalTaskOptions.None, null) { } @@ -444,7 +445,7 @@ namespace System.Threading.Tasks /// The provided CancellationToken /// has already been disposed. /// - public Task(Action action, object state, CancellationToken cancellationToken) + public Task(Action action, object? state, CancellationToken cancellationToken) // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 : this(action, state, null, cancellationToken, TaskCreationOptions.None, InternalTaskOptions.None, null) { } @@ -465,7 +466,7 @@ namespace System.Threading.Tasks /// The argument specifies an invalid value for . /// - public Task(Action action, object state, TaskCreationOptions creationOptions) + public Task(Action action, object? state, TaskCreationOptions creationOptions) // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 : this(action, state, Task.InternalCurrentIfAttached(creationOptions), default, creationOptions, InternalTaskOptions.None, null) { } @@ -490,7 +491,7 @@ namespace System.Threading.Tasks /// The provided CancellationToken /// has already been disposed. /// - public Task(Action action, object state, CancellationToken cancellationToken, TaskCreationOptions creationOptions) + public Task(Action action, object? state, CancellationToken cancellationToken, TaskCreationOptions creationOptions) // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 : this(action, state, Task.InternalCurrentIfAttached(creationOptions), cancellationToken, creationOptions, InternalTaskOptions.None, null) { } @@ -505,8 +506,8 @@ namespace System.Threading.Tasks /// A task scheduler under which the task will run. /// Options to control its execution. /// Internal options to control its execution - internal Task(Delegate action, object state, Task parent, CancellationToken cancellationToken, - TaskCreationOptions creationOptions, InternalTaskOptions internalOptions, TaskScheduler scheduler) + internal Task(Delegate action, object? state, Task? parent, CancellationToken cancellationToken, + TaskCreationOptions creationOptions, InternalTaskOptions internalOptions, TaskScheduler? scheduler) { if (action == null) { @@ -537,8 +538,8 @@ namespace System.Threading.Tasks /// A CancellationToken for the Task. /// Options to customize behavior of Task. /// Internal options to customize behavior of Task. - internal void TaskConstructorCore(Delegate action, object state, CancellationToken cancellationToken, - TaskCreationOptions creationOptions, InternalTaskOptions internalOptions, TaskScheduler scheduler) + internal void TaskConstructorCore(Delegate? action, object? state, CancellationToken cancellationToken, + TaskCreationOptions creationOptions, InternalTaskOptions internalOptions, TaskScheduler? scheduler) { m_action = action; m_stateObject = state; @@ -580,10 +581,10 @@ namespace System.Threading.Tasks // We can safely call the creator task's AddNewChild() method to register it, // because at this point we are already on its thread of execution. - ContingentProperties props = m_contingentProperties; + ContingentProperties? props = m_contingentProperties; if (props != null) { - Task parent = props.m_parent; + Task? parent = props.m_parent; if (parent != null && ((creationOptions & TaskCreationOptions.AttachedToParent) != 0) && ((parent.CreationOptions & TaskCreationOptions.DenyChildAttach) == 0)) @@ -606,7 +607,7 @@ namespace System.Threading.Tasks /// Handles everything needed for associating a CancellationToken with a task which is being constructed. /// This method is meant to be called either from the TaskConstructorCore or from ContinueWithCore. /// - private void AssignCancellationToken(CancellationToken cancellationToken, Task antecedent, TaskContinuation continuation) + private void AssignCancellationToken(CancellationToken cancellationToken, Task? antecedent, TaskContinuation? continuation) { // There is no need to worry about concurrency issues here because we are in the constructor path of the task -- // there should not be any race conditions to set m_contingentProperties at this point. @@ -634,16 +635,18 @@ namespace System.Threading.Tasks if (antecedent == null) { // if no antecedent was specified, use this task's reference as the cancellation state object - ctr = cancellationToken.UnsafeRegister(t => ((Task)t).InternalCancel(false), this); + ctr = cancellationToken.UnsafeRegister(t => ((Task)t!).InternalCancel(false), this); // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 } else { + Debug.Assert(continuation != null); + // If an antecedent was specified, pack this task, its antecedent and the TaskContinuation together as a tuple // and use it as the cancellation state object. This will be unpacked in the cancellation callback so that // antecedent.RemoveCancellation(continuation) can be invoked. ctr = cancellationToken.UnsafeRegister(t => { - var tuple = (Tuple)t; + var tuple = (Tuple)t!; Task targetTask = tuple.Item1; Task antecedentTask = tuple.Item2; @@ -662,7 +665,7 @@ namespace System.Threading.Tasks { // If we have an exception related to our CancellationToken, then we need to subtract ourselves // from our parent before throwing it. - Task parent = m_contingentProperties?.m_parent; + Task? parent = m_contingentProperties?.m_parent; if ((parent != null) && ((Options & TaskCreationOptions.AttachedToParent) != 0) && ((parent.Options & TaskCreationOptions.DenyChildAttach) == 0)) @@ -678,8 +681,7 @@ namespace System.Threading.Tasks { get { - Delegate d = m_action; - return d != null ? d.Method.ToString() : "{null}"; + return m_action?.Method.ToString() ?? "{null}"; } } @@ -787,7 +789,7 @@ namespace System.Threading.Tasks /// Returns true if any of the supplied tasks require wait notification. /// The tasks to check. /// true if any of the tasks require notification; otherwise, false. - internal static bool AnyTaskRequiresNotifyDebuggerOfWaitCompletion(Task[] tasks) + internal static bool AnyTaskRequiresNotifyDebuggerOfWaitCompletion(Task?[] tasks) { Debug.Assert(tasks != null, "Expected non-null array of tasks"); foreach (var task in tasks) @@ -871,8 +873,8 @@ namespace System.Threading.Tasks { m_stateFlags |= Task.TASK_STATE_TASKSCHEDULED_WAS_FIRED; - Task currentTask = Task.InternalCurrent; - Task parentTask = m_contingentProperties?.m_parent; + Task? currentTask = Task.InternalCurrent; + Task? parentTask = m_contingentProperties?.m_parent; TplEventSource.Log.TaskScheduled(ts.Id, currentTask == null ? 0 : currentTask.Id, this.Id, parentTask == null ? 0 : parentTask.Id, (int)this.Options); } @@ -1049,7 +1051,7 @@ namespace System.Threading.Tasks ThrowHelper.ThrowArgumentNullException(ExceptionArgument.scheduler); } - InternalRunSynchronously(scheduler, waitForCompletion: true); + InternalRunSynchronously(scheduler!, waitForCompletion: true); // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 } // @@ -1158,7 +1160,7 @@ namespace System.Threading.Tasks // Implicitly converts action to object and handles the meat of the StartNew() logic. internal static Task InternalStartNew( - Task creatingTask, Delegate action, object state, CancellationToken cancellationToken, TaskScheduler scheduler, + Task? creatingTask, Delegate action, object? state, CancellationToken cancellationToken, TaskScheduler scheduler, TaskCreationOptions options, InternalTaskOptions internalOptions) { // Validate arguments. @@ -1227,7 +1229,7 @@ namespace System.Threading.Tasks { get { - Task currentTask = InternalCurrent; + Task? currentTask = InternalCurrent; if (currentTask != null) return currentTask.Id; else @@ -1239,7 +1241,7 @@ namespace System.Threading.Tasks /// Gets the Task instance currently executing, or /// null if none exists. /// - internal static Task InternalCurrent + internal static Task? InternalCurrent { get { return t_currentTask; } } @@ -1250,7 +1252,7 @@ namespace System.Threading.Tasks /// /// The options to check. /// The current task if there is one and if AttachToParent is in the options; otherwise, null. - internal static Task InternalCurrentIfAttached(TaskCreationOptions creationOptions) + internal static Task? InternalCurrentIfAttached(TaskCreationOptions creationOptions) { return (creationOptions & TaskCreationOptions.AttachedToParent) != 0 ? InternalCurrent : null; } @@ -1267,11 +1269,11 @@ namespace System.Threading.Tasks /// or in accesses to the property. Any exceptions not observed by the time /// the Task instance is garbage collected will be propagated on the finalizer thread. /// - public AggregateException Exception + public AggregateException? Exception { get { - AggregateException e = null; + AggregateException? e = null; // If you're faulted, retrieve the exception(s) if (IsFaulted) e = GetExceptions(false); @@ -1355,7 +1357,7 @@ namespace System.Threading.Tasks /// The initialized contingent properties object. internal ContingentProperties EnsureContingentPropertiesInitialized() { - return LazyInitializer.EnsureInitialized(ref m_contingentProperties, () => new ContingentProperties()); + return LazyInitializer.EnsureInitialized(ref m_contingentProperties, () => new ContingentProperties())!; // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 } /// @@ -1460,7 +1462,7 @@ namespace System.Threading.Tasks /// Gets the state object supplied when the Task was created, /// or null if none was supplied. /// - public object AsyncState + public object? AsyncState { get { return m_stateObject; } } @@ -1480,7 +1482,7 @@ namespace System.Threading.Tasks /// /// Provides access to the TaskScheduler responsible for executing this Task. /// - internal TaskScheduler ExecutingTaskScheduler + internal TaskScheduler? ExecutingTaskScheduler { get { return m_taskScheduler; } } @@ -1524,13 +1526,13 @@ namespace System.Threading.Tasks } } - return contingentProps.m_completionEvent; + return contingentProps.m_completionEvent!; // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 } } /// - /// The property formerly known as IsFaulted. + /// Whether an exception has been stored into the task. /// internal bool ExceptionRecorded { @@ -1563,7 +1565,7 @@ namespace System.Threading.Tasks /// If the TASK_STATE_EXECUTIONCONTEXT_IS_NULL flag is set, this means ExecutionContext.Capture returned null, otherwise /// If the captured context is the default, nothing is saved, otherwise the m_contingentProperties inflates to save the context /// - internal ExecutionContext CapturedContext + internal ExecutionContext? CapturedContext { get { @@ -1716,6 +1718,7 @@ namespace System.Threading.Tasks if (AsyncCausalityTracer.LoggingOn && (Options & (TaskCreationOptions)InternalTaskOptions.ContinuationTask) == 0) { //For all other task than TaskContinuations we want to log. TaskContinuations log in their constructor + Debug.Assert(m_action != null, "Must have a delegate to be in ScheduleAndStart"); AsyncCausalityTracer.TraceOperationCreation(this, "Task: " + m_action.Method.Name); } @@ -1813,7 +1816,7 @@ namespace System.Threading.Tasks lock (props) { - props.m_exceptionsHolder.Add(exceptionObject, representsCancellation); + props.m_exceptionsHolder!.Add(exceptionObject, representsCancellation); // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 } } @@ -1823,7 +1826,7 @@ namespace System.Threading.Tasks /// /// Whether to include a TCE if cancelled. /// An aggregate exception, or null if no exceptions have been caught. - private AggregateException GetExceptions(bool includeTaskCanceledExceptions) + private AggregateException? GetExceptions(bool includeTaskCanceledExceptions) { // // WARNING: The Task/Task/TaskCompletionSource classes @@ -1861,7 +1864,7 @@ namespace System.Threading.Tasks // // We'll lazily create a TCE if the task has been canceled. - Exception canceledException = null; + Exception? canceledException = null; if (includeTaskCanceledExceptions && IsCanceled) { // Backcompat: @@ -1877,7 +1880,7 @@ namespace System.Threading.Tasks { // There are exceptions; get the aggregate and optionally add the canceled // exception to the aggregate (if applicable). - Debug.Assert(m_contingentProperties != null); // ExceptionRecorded ==> m_contingentProperties != null + Debug.Assert(m_contingentProperties != null && m_contingentProperties.m_exceptionsHolder != null, "ExceptionRecorded should imply this"); // No need to lock around this, as other logic prevents the consumption of exceptions // before they have been completely processed. @@ -1898,13 +1901,13 @@ namespace System.Threading.Tasks bool exceptionsAvailable = IsFaulted && ExceptionRecorded; Debug.Assert(exceptionsAvailable, "Must only be used when the task has faulted with exceptions."); return exceptionsAvailable ? - m_contingentProperties.m_exceptionsHolder.GetExceptionDispatchInfos() : + m_contingentProperties!.m_exceptionsHolder!.GetExceptionDispatchInfos() : new ReadOnlyCollection(new ExceptionDispatchInfo[0]); } /// Gets the ExceptionDispatchInfo containing the OperationCanceledException for this task. /// The ExceptionDispatchInfo. May be null if no OCE was stored for the task. - internal ExceptionDispatchInfo GetCancellationExceptionDispatchInfo() + internal ExceptionDispatchInfo? GetCancellationExceptionDispatchInfo() { Debug.Assert(IsCanceled, "Must only be used when the task has canceled."); return Volatile.Read(ref m_contingentProperties)?.m_exceptionsHolder?.GetCancellationExceptionDispatchInfo(); // may be null @@ -1917,7 +1920,7 @@ namespace System.Threading.Tasks { Debug.Assert(IsCompleted, "ThrowIfExceptional(): Expected IsCompleted == true"); - Exception exception = GetExceptions(includeTaskCanceledExceptions); + Exception? exception = GetExceptions(includeTaskCanceledExceptions); if (exception != null) { UpdateExceptionObservedStatus(); @@ -1928,7 +1931,7 @@ namespace System.Threading.Tasks /// Throws the exception on the ThreadPool. /// The exception to propagate. /// The target context on which to propagate the exception. Null to use the ThreadPool. - internal static void ThrowAsync(Exception exception, SynchronizationContext targetContext) + internal static void ThrowAsync(Exception exception, SynchronizationContext? targetContext) { // Capture the exception into an ExceptionDispatchInfo so that its // stack trace and Watson bucket info will be preserved @@ -1940,7 +1943,7 @@ namespace System.Threading.Tasks try { // Post the throwing of the exception to that context, and return. - targetContext.Post(state => ((ExceptionDispatchInfo)state).Throw(), edi); + targetContext.Post(state => ((ExceptionDispatchInfo)state!).Throw(), edi); return; } catch (Exception postException) @@ -1962,7 +1965,7 @@ namespace System.Threading.Tasks #endif // Propagate the exception(s) on the ThreadPool - ThreadPool.QueueUserWorkItem(state => ((ExceptionDispatchInfo)state).Throw(), edi); + ThreadPool.QueueUserWorkItem(state => ((ExceptionDispatchInfo)state!).Throw(), edi); #endif // CORERT } @@ -1980,7 +1983,7 @@ namespace System.Threading.Tasks /// internal void UpdateExceptionObservedStatus() { - Task parent = m_contingentProperties?.m_parent; + Task? parent = m_contingentProperties?.m_parent; if ((parent != null) && ((Options & TaskCreationOptions.AttachedToParent) != 0) && ((parent.CreationOptions & TaskCreationOptions.DenyChildAttach) == 0) @@ -2048,7 +2051,7 @@ namespace System.Threading.Tasks } else { - ContingentProperties props = m_contingentProperties; + ContingentProperties props = m_contingentProperties!; // Count of 1 => either all children finished, or there were none. Safe to complete ourselves // without paying the price of an Interlocked.Decrement. @@ -2075,7 +2078,7 @@ namespace System.Threading.Tasks // Now is the time to prune exceptional children. We'll walk the list and removes the ones whose exceptions we might have observed after they threw. // we use a local variable for exceptional children here because some other thread may be nulling out m_contingentProperties.m_exceptionalChildren - List exceptionalChildren = props.m_exceptionalChildren; + List? exceptionalChildren = props.m_exceptionalChildren; if (exceptionalChildren != null) { lock (exceptionalChildren) @@ -2096,7 +2099,7 @@ namespace System.Threading.Tasks // At this point, the task is done executing and waiting for its children, // we can transition our task to a completion state. - ContingentProperties cp = Volatile.Read(ref m_contingentProperties); + ContingentProperties? cp = Volatile.Read(ref m_contingentProperties); if (cp != null) { AddExceptionsFromChildren(cp); @@ -2170,7 +2173,7 @@ namespace System.Threading.Tasks // continuations hold onto the task, and therefore are keeping it alive. m_action = null; - ContingentProperties cp = m_contingentProperties; + ContingentProperties? cp = m_contingentProperties; if (cp != null) { // Similarly, null out any ExecutionContext we may have captured, @@ -2188,7 +2191,7 @@ namespace System.Threading.Tasks internal void NotifyParentIfPotentiallyAttachedTask() { - Task parent = m_contingentProperties?.m_parent; + Task? parent = m_contingentProperties?.m_parent; if (parent != null && ((parent.CreationOptions & TaskCreationOptions.DenyChildAttach) == 0) && (((TaskCreationOptions)(m_stateFlags & OptionsMask)) & TaskCreationOptions.AttachedToParent) != 0) @@ -2213,7 +2216,7 @@ namespace System.Threading.Tasks if (childTask.IsFaulted && !childTask.IsExceptionObservedByParent) { // Lazily initialize the child exception list - if (props.m_exceptionalChildren == null) + if (props!.m_exceptionalChildren == null) { Interlocked.CompareExchange(ref props.m_exceptionalChildren, new List(), null); } @@ -2222,7 +2225,7 @@ namespace System.Threading.Tasks // multiple times for the same task. In that case, AddExceptionsFromChildren() could be nulling m_exceptionalChildren // out at the same time that we're processing it, resulting in a NullReferenceException here. We'll protect // ourselves by caching m_exceptionChildren in a local variable. - List tmp = props.m_exceptionalChildren; + List? tmp = props.m_exceptionalChildren; if (tmp != null) { lock (tmp) @@ -2232,7 +2235,7 @@ namespace System.Threading.Tasks } } - if (Interlocked.Decrement(ref props.m_completionCountdown) == 0) + if (Interlocked.Decrement(ref props!.m_completionCountdown) == 0) { // This call came from the final child to complete, and apparently we have previously given up this task's right to complete itself. // So we need to invoke the final finish stage. @@ -2253,7 +2256,7 @@ namespace System.Threading.Tasks // simultaneously on the same task from two different contexts. This can result in m_exceptionalChildren // being nulled out while it is being processed, which could lead to a NullReferenceException. To // protect ourselves, we'll cache m_exceptionalChildren in a local variable. - List exceptionalChildren = props.m_exceptionalChildren; + List? exceptionalChildren = props.m_exceptionalChildren; if (exceptionalChildren != null) { @@ -2268,7 +2271,7 @@ namespace System.Threading.Tasks Debug.Assert(task.IsCompleted, "Expected all tasks in list to be completed"); if (task.IsFaulted && !task.IsExceptionObservedByParent) { - TaskExceptionHolder exceptionHolder = Volatile.Read(ref task.m_contingentProperties).m_exceptionsHolder; + TaskExceptionHolder? exceptionHolder = Volatile.Read(ref task.m_contingentProperties)!.m_exceptionsHolder; Debug.Assert(exceptionHolder != null); // No locking necessary since child task is finished adding exceptions @@ -2322,7 +2325,7 @@ namespace System.Threading.Tasks /// internal virtual void ExecuteFromThreadPool(Thread threadPoolThread) => ExecuteEntryUnsafe(threadPoolThread); - internal void ExecuteEntryUnsafe(Thread threadPoolThread) // used instead of ExecuteEntry() when we don't have to worry about double-execution prevent + internal void ExecuteEntryUnsafe(Thread? threadPoolThread) // used instead of ExecuteEntry() when we don't have to worry about double-execution prevent { // Remember that we started running the task delegate. m_stateFlags |= TASK_STATE_DELEGATE_INVOKED; @@ -2350,10 +2353,10 @@ namespace System.Threading.Tasks } // A trick so we can refer to the TLS slot with a byref. - private void ExecuteWithThreadLocal(ref Task currentTaskSlot, Thread threadPoolThread = null) + private void ExecuteWithThreadLocal(ref Task? currentTaskSlot, Thread? threadPoolThread = null) { // Remember the current task so we can restore it after running, and then - Task previousTask = currentTaskSlot; + Task? previousTask = currentTaskSlot; // ETW event for Task Started var log = TplEventSource.Log; @@ -2365,7 +2368,7 @@ namespace System.Threading.Tasks EventSource.SetCurrentThreadActivityId(TplEventSource.CreateGuidForTaskID(this.Id), out savedActivityID); // previousTask holds the actual "current task" we want to report in the event if (previousTask != null) - log.TaskStarted(previousTask.m_taskScheduler.Id, previousTask.Id, this.Id); + log.TaskStarted(previousTask.m_taskScheduler!.Id, previousTask.Id, this.Id); else log.TaskStarted(TaskScheduler.Current.Id, 0, this.Id); } @@ -2382,7 +2385,7 @@ namespace System.Threading.Tasks // Execute the task body try { - ExecutionContext ec = CapturedContext; + ExecutionContext? ec = CapturedContext; if (ec == null) { // No context, just run the task directly. @@ -2421,7 +2424,7 @@ namespace System.Threading.Tasks { // previousTask holds the actual "current task" we want to report in the event if (previousTask != null) - log.TaskCompleted(previousTask.m_taskScheduler.Id, previousTask.Id, this.Id, IsFaulted); + log.TaskCompleted(previousTask.m_taskScheduler!.Id, previousTask.Id, this.Id, IsFaulted); else log.TaskCompleted(TaskScheduler.Current.Id, 0, this.Id, IsFaulted); @@ -2451,7 +2454,7 @@ namespace System.Threading.Tasks return; } - if (m_action is Action actionWithState) + if (m_action is Action actionWithState) { actionWithState(m_stateObject); return; @@ -2469,7 +2472,7 @@ namespace System.Threading.Tasks Debug.Assert(unhandledException != null); if (unhandledException is OperationCanceledException exceptionAsOce && IsCancellationRequested && - m_contingentProperties.m_cancellationToken == exceptionAsOce.CancellationToken) + m_contingentProperties!.m_cancellationToken == exceptionAsOce.CancellationToken) { // All conditions are satisfied for us to go into canceled state in Finish(). // Mark the acknowledgement. The exception is also stored to enable it to be @@ -2526,7 +2529,7 @@ namespace System.Threading.Tasks // Create the best AwaitTaskContinuation object given the request. // If this remains null by the end of the function, we can use the // continuationAction directly without wrapping it. - TaskContinuation tc = null; + TaskContinuation? tc = null; // If the user wants the continuation to run on the current "context" if there is one... if (continueOnCapturedContext) @@ -2605,7 +2608,7 @@ namespace System.Threading.Tasks // fall back to using the state machine's delegate. if (continueOnCapturedContext) { - SynchronizationContext syncCtx = SynchronizationContext.Current; + SynchronizationContext? syncCtx = SynchronizationContext.Current; if (syncCtx != null && syncCtx.GetType() != typeof(SynchronizationContext)) { var tc = new SynchronizationContextAwaitTaskContinuation(syncCtx, stateMachineBox.MoveNextAction, flowExecutionContext: false); @@ -2617,7 +2620,7 @@ namespace System.Threading.Tasks } else { - TaskScheduler scheduler = TaskScheduler.InternalCurrent; + TaskScheduler? scheduler = TaskScheduler.InternalCurrent; if (scheduler != null && scheduler != TaskScheduler.Default) { var tc = new TaskSchedulerAwaitTaskContinuation(scheduler, stateMachineBox.MoveNextAction, flowExecutionContext: false); @@ -2846,9 +2849,9 @@ namespace System.Threading.Tasks bool etwIsEnabled = log.IsEnabled(); if (etwIsEnabled) { - Task currentTask = Task.InternalCurrent; + Task? currentTask = Task.InternalCurrent; log.TaskWaitBegin( - (currentTask != null ? currentTask.m_taskScheduler.Id : TaskScheduler.Default.Id), (currentTask != null ? currentTask.Id : 0), + (currentTask != null ? currentTask.m_taskScheduler!.Id : TaskScheduler.Default.Id), (currentTask != null ? currentTask.Id : 0), this.Id, TplEventSource.TaskWaitBehavior.Synchronous, 0); } @@ -2877,10 +2880,10 @@ namespace System.Threading.Tasks // ETW event for Task Wait End if (etwIsEnabled) { - Task currentTask = Task.InternalCurrent; + Task? currentTask = Task.InternalCurrent; if (currentTask != null) { - log.TaskWaitEnd(currentTask.m_taskScheduler.Id, currentTask.Id, this.Id); + log.TaskWaitEnd(currentTask.m_taskScheduler!.Id, currentTask.Id, this.Id); } else { @@ -2999,12 +3002,12 @@ namespace System.Threading.Tasks bool bPopSucceeded = false; bool mustCleanup = false; - TaskSchedulerException tse = null; + TaskSchedulerException? tse = null; // If started, and running in a task context, we can try to pop the chore. if ((m_stateFlags & TASK_STATE_STARTED) != 0) { - TaskScheduler ts = m_taskScheduler; + TaskScheduler? ts = m_taskScheduler; try { @@ -3095,7 +3098,7 @@ namespace System.Threading.Tasks RecordInternalCancellationRequest(); Debug.Assert((Options & (TaskCreationOptions)InternalTaskOptions.PromiseTask) != 0, "Task.RecordInternalCancellationRequest(CancellationToken) only valid for promise-style task"); - Debug.Assert(m_contingentProperties.m_cancellationToken == default); + Debug.Assert(m_contingentProperties!.m_cancellationToken == default); // Store the supplied cancellation token as this task's token. // Waiting on this task will then result in an OperationCanceledException containing this token. @@ -3108,7 +3111,7 @@ namespace System.Threading.Tasks // Breaks out logic for recording a cancellation request // This overload should only be used for promise tasks where no cancellation token // was supplied when the task was created. - internal void RecordInternalCancellationRequest(CancellationToken tokenToRecord, object cancellationException) + internal void RecordInternalCancellationRequest(CancellationToken tokenToRecord, object? cancellationException) { RecordInternalCancellationRequest(tokenToRecord); @@ -3184,7 +3187,7 @@ namespace System.Threading.Tasks TASK_STATE_COMPLETION_RESERVED | TASK_STATE_RAN_TO_COMPLETION, TASK_STATE_COMPLETION_RESERVED | TASK_STATE_RAN_TO_COMPLETION | TASK_STATE_FAULTED | TASK_STATE_CANCELED)) { - ContingentProperties props = m_contingentProperties; + ContingentProperties? props = m_contingentProperties; if (props != null) { NotifyParentIfPotentiallyAttachedTask(); @@ -3252,7 +3255,7 @@ namespace System.Threading.Tasks // If the tokenToRecord is not None, it will be stored onto the task. // If the OperationCanceledException is not null, it will be stored into the task's exception holder. // This method is only valid for promise tasks. - internal bool TrySetCanceled(CancellationToken tokenToRecord, object cancellationException) + internal bool TrySetCanceled(CancellationToken tokenToRecord, object? cancellationException) { Debug.Assert(m_action == null, "Task.TrySetCanceled(): non-null m_action"); Debug.Assert( @@ -3296,7 +3299,7 @@ namespace System.Threading.Tasks // Atomically store the fact that this task is completing. From this point on, the adding of continuations will // result in the continuations being run/launched directly rather than being added to the continuation list. // Then if we grabbed any continuations, run them. - object continuationObject = Interlocked.Exchange(ref m_continuationObject, s_taskCompletionSentinel); + object? continuationObject = Interlocked.Exchange(ref m_continuationObject, s_taskCompletionSentinel); if (continuationObject != null) { RunContinuations(continuationObject); @@ -3352,7 +3355,7 @@ namespace System.Threading.Tasks } // Not a single; it must be a list. - List continuations = (List)continuationObject; + List continuations = (List)continuationObject; // // Begin processing of continuation list @@ -3384,7 +3387,7 @@ namespace System.Threading.Tasks // and Action delegates, which are all by default implicitly synchronous. for (int i = 0; i < continuationCount; i++) { - object currentContinuation = continuations[i]; + object? currentContinuation = continuations[i]; if (currentContinuation == null) { continue; @@ -3611,13 +3614,13 @@ namespace System.Threading.Tasks CreationOptionsFromContinuationOptions(continuationOptions, out creationOptions, out internalOptions); Task continuationTask = new ContinuationTaskFromTask( - this, continuationAction, null, + this, continuationAction!, null, // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 creationOptions, internalOptions ); // Register the continuation. If synchronous execution is requested, this may // actually invoke the continuation before returning. - ContinueWithCore(continuationTask, scheduler, cancellationToken, continuationOptions); + ContinueWithCore(continuationTask, scheduler!, cancellationToken, continuationOptions); // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 return continuationTask; } @@ -3642,7 +3645,7 @@ namespace System.Threading.Tasks /// /// The argument is null. /// - public Task ContinueWith(Action continuationAction, object state) + public Task ContinueWith(Action continuationAction, object? state) { return ContinueWith(continuationAction, state, TaskScheduler.Current, default, TaskContinuationOptions.None); } @@ -3668,7 +3671,7 @@ namespace System.Threading.Tasks /// The provided CancellationToken /// has already been disposed. /// - public Task ContinueWith(Action continuationAction, object state, CancellationToken cancellationToken) + public Task ContinueWith(Action continuationAction, object? state, CancellationToken cancellationToken) { return ContinueWith(continuationAction, state, TaskScheduler.Current, cancellationToken, TaskContinuationOptions.None); } @@ -3696,7 +3699,7 @@ namespace System.Threading.Tasks /// /// The argument is null. /// - public Task ContinueWith(Action continuationAction, object state, TaskScheduler scheduler) + public Task ContinueWith(Action continuationAction, object? state, TaskScheduler scheduler) { return ContinueWith(continuationAction, state, scheduler, default, TaskContinuationOptions.None); } @@ -3730,7 +3733,7 @@ namespace System.Threading.Tasks /// The argument specifies an invalid value for TaskContinuationOptions. /// - public Task ContinueWith(Action continuationAction, object state, TaskContinuationOptions continuationOptions) + public Task ContinueWith(Action continuationAction, object? state, TaskContinuationOptions continuationOptions) { return ContinueWith(continuationAction, state, TaskScheduler.Current, default, continuationOptions); } @@ -3774,14 +3777,14 @@ namespace System.Threading.Tasks /// The provided CancellationToken /// has already been disposed. /// - public Task ContinueWith(Action continuationAction, object state, CancellationToken cancellationToken, + public Task ContinueWith(Action continuationAction, object? state, CancellationToken cancellationToken, TaskContinuationOptions continuationOptions, TaskScheduler scheduler) { return ContinueWith(continuationAction, state, scheduler, cancellationToken, continuationOptions); } // Same as the above overload, just with a stack mark parameter. - private Task ContinueWith(Action continuationAction, object state, TaskScheduler scheduler, + private Task ContinueWith(Action continuationAction, object? state, TaskScheduler scheduler, CancellationToken cancellationToken, TaskContinuationOptions continuationOptions) { // Throw on continuation with null action @@ -3801,13 +3804,13 @@ namespace System.Threading.Tasks CreationOptionsFromContinuationOptions(continuationOptions, out creationOptions, out internalOptions); Task continuationTask = new ContinuationTaskFromTask( - this, continuationAction, state, + this, continuationAction!, state, // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 creationOptions, internalOptions ); // Register the continuation. If synchronous execution is requested, this may // actually invoke the continuation before returning. - ContinueWithCore(continuationTask, scheduler, cancellationToken, continuationOptions); + ContinueWithCore(continuationTask, scheduler!, cancellationToken, continuationOptions); // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 return continuationTask; } @@ -4004,13 +4007,13 @@ namespace System.Threading.Tasks CreationOptionsFromContinuationOptions(continuationOptions, out creationOptions, out internalOptions); Task continuationTask = new ContinuationResultTaskFromTask( - this, continuationFunction, null, + this, continuationFunction!, null, // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 creationOptions, internalOptions ); // Register the continuation. If synchronous execution is requested, this may // actually invoke the continuation before returning. - ContinueWithCore(continuationTask, scheduler, cancellationToken, continuationOptions); + ContinueWithCore(continuationTask, scheduler!, cancellationToken, continuationOptions); // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 return continuationTask; } @@ -4038,7 +4041,7 @@ namespace System.Threading.Tasks /// /// The argument is null. /// - public Task ContinueWith(Func continuationFunction, object state) + public Task ContinueWith(Func continuationFunction, object? state) { return ContinueWith(continuationFunction, state, TaskScheduler.Current, default, TaskContinuationOptions.None); @@ -4069,7 +4072,7 @@ namespace System.Threading.Tasks /// The provided CancellationToken /// has already been disposed. /// - public Task ContinueWith(Func continuationFunction, object state, CancellationToken cancellationToken) + public Task ContinueWith(Func continuationFunction, object? state, CancellationToken cancellationToken) { return ContinueWith(continuationFunction, state, TaskScheduler.Current, cancellationToken, TaskContinuationOptions.None); } @@ -4100,7 +4103,7 @@ namespace System.Threading.Tasks /// /// The argument is null. /// - public Task ContinueWith(Func continuationFunction, object state, TaskScheduler scheduler) + public Task ContinueWith(Func continuationFunction, object? state, TaskScheduler scheduler) { return ContinueWith(continuationFunction, state, scheduler, default, TaskContinuationOptions.None); } @@ -4137,7 +4140,7 @@ namespace System.Threading.Tasks /// The argument specifies an invalid value for TaskContinuationOptions. /// - public Task ContinueWith(Func continuationFunction, object state, TaskContinuationOptions continuationOptions) + public Task ContinueWith(Func continuationFunction, object? state, TaskContinuationOptions continuationOptions) { return ContinueWith(continuationFunction, state, TaskScheduler.Current, default, continuationOptions); } @@ -4184,14 +4187,14 @@ namespace System.Threading.Tasks /// The provided CancellationToken /// has already been disposed. /// - public Task ContinueWith(Func continuationFunction, object state, CancellationToken cancellationToken, + public Task ContinueWith(Func continuationFunction, object? state, CancellationToken cancellationToken, TaskContinuationOptions continuationOptions, TaskScheduler scheduler) { return ContinueWith(continuationFunction, state, scheduler, cancellationToken, continuationOptions); } // Same as the above overload, just with a stack mark parameter. - private Task ContinueWith(Func continuationFunction, object state, TaskScheduler scheduler, + private Task ContinueWith(Func continuationFunction, object? state, TaskScheduler scheduler, CancellationToken cancellationToken, TaskContinuationOptions continuationOptions) { // Throw on continuation with null function @@ -4211,13 +4214,13 @@ namespace System.Threading.Tasks CreationOptionsFromContinuationOptions(continuationOptions, out creationOptions, out internalOptions); Task continuationTask = new ContinuationResultTaskFromTask( - this, continuationFunction, state, + this, continuationFunction!, state, // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 creationOptions, internalOptions ); // Register the continuation. If synchronous execution is requested, this may // actually invoke the continuation before returning. - ContinueWithCore(continuationTask, scheduler, cancellationToken, continuationOptions); + ContinueWithCore(continuationTask, scheduler!, cancellationToken, continuationOptions); // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 return continuationTask; } @@ -4386,13 +4389,13 @@ namespace System.Threading.Tasks { Debug.Assert(tc != null, "Expected non-null tc object in AddTaskContinuationComplex"); - object oldValue = m_continuationObject; + object? oldValue = m_continuationObject; // Logic for the case where we were previously storing a single continuation - if ((oldValue != s_taskCompletionSentinel) && (!(oldValue is List))) + if ((oldValue != s_taskCompletionSentinel) && (!(oldValue is List))) { // Construct a new TaskContinuation list - List newList = new List(); + List newList = new List(); // Add in the old single value newList.Add(oldValue); @@ -4407,7 +4410,7 @@ namespace System.Threading.Tasks // m_continuationObject is guaranteed at this point to be either a List or // s_taskCompletionSentinel. - List list = m_continuationObject as List; + List? list = m_continuationObject as List; Debug.Assert((list != null) || (m_continuationObject == s_taskCompletionSentinel), "Expected m_continuationObject to be list or sentinel"); @@ -4469,21 +4472,21 @@ namespace System.Threading.Tasks { // We need to snap a local reference to m_continuations since reading a volatile object is more costly. // Also to prevent the value to be changed as result of a race condition with another method. - object continuationsLocalRef = m_continuationObject; + object? continuationsLocalRef = m_continuationObject; // Task is completed. Nothing to do here. if (continuationsLocalRef == s_taskCompletionSentinel) return; - if (!(continuationsLocalRef is List continuationsLocalListRef)) + if (!(continuationsLocalRef is List continuationsLocalListRef)) { // This is not a list. If we have a single object (the one we want to remove) we try to replace it with an empty list. // Note we cannot go back to a null state, since it will mess up the AddTaskContinuation logic. - if (Interlocked.CompareExchange(ref m_continuationObject, new List(), continuationObject) != continuationObject) + if (Interlocked.CompareExchange(ref m_continuationObject, new List(), continuationObject) != continuationObject) { // If we fail it means that either AddContinuationComplex won the race condition and m_continuationObject is now a List // that contains the element we want to remove. Or FinishContinuations set the s_taskCompletionSentinel. // So we should try to get a list one more time - continuationsLocalListRef = m_continuationObject as List; + continuationsLocalListRef = m_continuationObject as List; } else { @@ -4711,9 +4714,9 @@ namespace System.Threading.Tasks // We make sure that the exception behavior of Task.Wait() is replicated the same for tasks handled in either of these codepaths // - List exceptions = null; - List waitedOnTaskList = null; - List notificationTasks = null; + List? exceptions = null; + List? waitedOnTaskList = null; + List? notificationTasks = null; // If any of the waited-upon tasks end as Faulted or Canceled, set these to true. bool exceptionSeen = false, cancellationSeen = false; @@ -4721,7 +4724,7 @@ namespace System.Threading.Tasks bool returnValue = true; // Collects incomplete tasks in "waitedOnTaskList" - for (int i = tasks.Length - 1; i >= 0; i--) + for (int i = tasks!.Length - 1; i >= 0; i--) // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 { Task task = tasks[i]; @@ -4730,7 +4733,7 @@ namespace System.Threading.Tasks ThrowHelper.ThrowArgumentException(ExceptionResource.Task_WaitMulti_NullTask, ExceptionArgument.tasks); } - bool taskIsCompleted = task.IsCompleted; + bool taskIsCompleted = task!.IsCompleted; // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 if (!taskIsCompleted) { // try inlining the task only if we have an infinite timeout and an empty cancellation token @@ -4819,7 +4822,7 @@ namespace System.Threading.Tasks /// The item to add. /// The list. /// The size to which to initialize the list if the list is null. - private static void AddToList(T item, ref List list, int initSize) + private static void AddToList(T item, ref List? list, int initSize) { if (list == null) list = new List(initSize); list.Add(item); @@ -4897,9 +4900,9 @@ namespace System.Threading.Tasks /// If the completed task is canceled or it has other exceptions, here we will add those /// into the passed in exception list (which will be lazily initialized here). /// - internal static void AddExceptionsForCompletedTask(ref List exceptions, Task t) + internal static void AddExceptionsForCompletedTask(ref List? exceptions, Task t) { - AggregateException ex = t.GetExceptions(true); + AggregateException? ex = t.GetExceptions(true); if (ex != null) { // make sure the task's exception observed status is set appropriately @@ -5086,7 +5089,7 @@ namespace System.Threading.Tasks // Make a pass through the loop to check for any tasks that may have // already been completed, and to verify that no tasks are null. - for (int taskIndex = 0; taskIndex < tasks.Length; taskIndex++) + for (int taskIndex = 0; taskIndex < tasks!.Length; taskIndex++) // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 { Task task = tasks[taskIndex]; @@ -5095,7 +5098,7 @@ namespace System.Threading.Tasks ThrowHelper.ThrowArgumentException(ExceptionResource.Task_WaitMulti_NullTask, ExceptionArgument.tasks); } - if (signaledTaskIndex == -1 && task.IsCompleted) + if (signaledTaskIndex == -1 && task!.IsCompleted) // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 { // We found our first completed task. Store it, but we can't just return here, // as we still need to validate the whole array for nulls. @@ -5147,7 +5150,7 @@ namespace System.Threading.Tasks if (exception == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.exception); var task = new Task(); - bool succeeded = task.TrySetException(exception); + bool succeeded = task.TrySetException(exception!); // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 Debug.Assert(succeeded, "This should always succeed on a new task."); return task; } @@ -5161,7 +5164,7 @@ namespace System.Threading.Tasks if (exception == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.exception); var task = new Task(); - bool succeeded = task.TrySetException(exception); + bool succeeded = task.TrySetException(exception!); // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 Debug.Assert(succeeded, "This should always succeed on a new task."); return task; } @@ -5184,7 +5187,7 @@ namespace System.Threading.Tasks { if (!cancellationToken.IsCancellationRequested) ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.cancellationToken); - return new Task(true, default, TaskCreationOptions.None, cancellationToken); + return new Task(true, default!, TaskCreationOptions.None, cancellationToken); // TODO-NULLABLE-GENERIC } /// Creates a that's completed due to cancellation with the specified exception. @@ -5292,7 +5295,7 @@ namespace System.Threading.Tasks /// /// The parameter was null. /// - public static Task Run(Func function) + public static Task Run(Func function) { return Run(function, default); } @@ -5311,7 +5314,7 @@ namespace System.Threading.Tasks /// /// The associated with was disposed. /// - public static Task Run(Func function, CancellationToken cancellationToken) + public static Task Run(Func function, CancellationToken cancellationToken) { // Check arguments if (function == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.function); @@ -5321,7 +5324,7 @@ namespace System.Threading.Tasks return Task.FromCanceled(cancellationToken); // Kick off initial Task, which will call the user-supplied function and yield a Task. - Task task1 = Task.Factory.StartNew(function, cancellationToken, TaskCreationOptions.DenyChildAttach, TaskScheduler.Default); + Task task1 = Task.Factory.StartNew(function!, cancellationToken, TaskCreationOptions.DenyChildAttach, TaskScheduler.Default); // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 // Create a promise-style Task to be used as a proxy for the operation // Set lookForOce == true so that unwrap logic can be on the lookout for OCEs thrown as faults from task1, to support in-delegate cancellation. @@ -5340,7 +5343,7 @@ namespace System.Threading.Tasks /// /// The parameter was null. /// - public static Task Run(Func> function) + public static Task Run(Func?> function) { return Run(function, default); } @@ -5356,7 +5359,7 @@ namespace System.Threading.Tasks /// /// The parameter was null. /// - public static Task Run(Func> function, CancellationToken cancellationToken) + public static Task Run(Func?> function, CancellationToken cancellationToken) { // Check arguments if (function == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.function); @@ -5366,7 +5369,7 @@ namespace System.Threading.Tasks return Task.FromCanceled(cancellationToken); // Kick off initial Task, which will call the user-supplied function and yield a Task. - Task> task1 = Task>.Factory.StartNew(function, cancellationToken, TaskCreationOptions.DenyChildAttach, TaskScheduler.Default); + Task?> task1 = Task?>.Factory.StartNew(function!, cancellationToken, TaskCreationOptions.DenyChildAttach, TaskScheduler.Default); // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 // Create a promise-style Task to be used as a proxy for the operation // Set lookForOce == true so that unwrap logic can be on the lookout for OCEs thrown as faults from task1, to support in-delegate cancellation. @@ -5475,7 +5478,7 @@ namespace System.Threading.Tasks /// Task that also stores the completion closure and logic for Task.Delay implementation. private class DelayPromise : Task { - private readonly TimerQueueTimer _timer; + private readonly TimerQueueTimer? _timer; internal DelayPromise(int millisecondsDelay) { @@ -5489,7 +5492,7 @@ namespace System.Threading.Tasks if (millisecondsDelay != Timeout.Infinite) // no need to create the timer if it's an infinite timeout { - _timer = new TimerQueueTimer(state => ((DelayPromise)state).CompleteTimedOut(), this, (uint)millisecondsDelay, Timeout.UnsignedInfinite, flowExecutionContext: false); + _timer = new TimerQueueTimer(state => ((DelayPromise)state!).CompleteTimedOut(), this, (uint)millisecondsDelay, Timeout.UnsignedInfinite, flowExecutionContext: false); // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 if (IsCanceled) { // Handle rare race condition where cancellation occurs prior to our having created and stored the timer, in which case @@ -5528,7 +5531,7 @@ namespace System.Threading.Tasks Debug.Assert(token.CanBeCanceled); _token = token; - _registration = token.UnsafeRegister(state => ((DelayPromiseWithCancellation)state).CompleteCanceled(), this); + _registration = token.UnsafeRegister(state => ((DelayPromiseWithCancellation)state!).CompleteCanceled(), this); // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 } private void CompleteCanceled() @@ -5593,7 +5596,7 @@ namespace System.Threading.Tasks foreach (var task in tasks) { if (task == null) ThrowHelper.ThrowArgumentException(ExceptionResource.Task_MultiTaskContinuation_NullTask, ExceptionArgument.tasks); - taskArray[index++] = task; + taskArray[index++] = task!; // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 } return InternalWhenAll(taskArray); } @@ -5601,10 +5604,10 @@ namespace System.Threading.Tasks // Do some argument checking and convert tasks to a List (and later an array). if (tasks == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.tasks); List taskList = new List(); - foreach (Task task in tasks) + foreach (Task task in tasks!) // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 { if (task == null) ThrowHelper.ThrowArgumentException(ExceptionResource.Task_MultiTaskContinuation_NullTask, ExceptionArgument.tasks); - taskList.Add(task); + taskList.Add(task!); // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 } // Delegate the rest to InternalWhenAll() @@ -5643,7 +5646,7 @@ namespace System.Threading.Tasks // Do some argument checking and make a defensive copy of the tasks array if (tasks == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.tasks); - int taskCount = tasks.Length; + int taskCount = tasks!.Length; // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 if (taskCount == 0) return InternalWhenAll(tasks); // Small optimization in the case of an empty array. Task[] tasksCopy = new Task[taskCount]; @@ -5651,7 +5654,7 @@ namespace System.Threading.Tasks { Task task = tasks[i]; if (task == null) ThrowHelper.ThrowArgumentException(ExceptionResource.Task_MultiTaskContinuation_NullTask, ExceptionArgument.tasks); - tasksCopy[i] = task; + tasksCopy[i] = task!; // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 } // The rest can be delegated to InternalWhenAll() @@ -5686,7 +5689,7 @@ namespace System.Threading.Tasks /// Stores all of the constituent tasks. Tasks clear themselves out of this /// array as they complete, but only if they don't have their wait notification bit set. /// - private readonly Task[] m_tasks; + private readonly Task?[] m_tasks; /// The number of tasks remaining to complete. private int m_count; @@ -5720,8 +5723,8 @@ namespace System.Threading.Tasks if (Interlocked.Decrement(ref m_count) == 0) { // Set up some accounting variables - List observedExceptions = null; - Task canceledTask = null; + List? observedExceptions = null; + Task? canceledTask = null; // Loop through antecedents: // If any one of them faults, the result will be faulted @@ -5837,7 +5840,7 @@ namespace System.Threading.Tasks foreach (var task in tasks) { if (task == null) ThrowHelper.ThrowArgumentException(ExceptionResource.Task_MultiTaskContinuation_NullTask, ExceptionArgument.tasks); - taskArray[index++] = task; + taskArray[index++] = task!; // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 } return InternalWhenAll(taskArray); } @@ -5845,10 +5848,10 @@ namespace System.Threading.Tasks // Do some argument checking and convert tasks into a List (later an array) if (tasks == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.tasks); List> taskList = new List>(); - foreach (Task task in tasks) + foreach (Task task in tasks!) // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 { if (task == null) ThrowHelper.ThrowArgumentException(ExceptionResource.Task_MultiTaskContinuation_NullTask, ExceptionArgument.tasks); - taskList.Add(task); + taskList.Add(task!); // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 } // Delegate the rest to InternalWhenAll(). @@ -5890,7 +5893,7 @@ namespace System.Threading.Tasks // Do some argument checking and make a defensive copy of the tasks array if (tasks == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.tasks); - int taskCount = tasks.Length; + int taskCount = tasks!.Length; // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 if (taskCount == 0) return InternalWhenAll(tasks); // small optimization in the case of an empty task array Task[] tasksCopy = new Task[taskCount]; @@ -5898,7 +5901,7 @@ namespace System.Threading.Tasks { Task task = tasks[i]; if (task == null) ThrowHelper.ThrowArgumentException(ExceptionResource.Task_MultiTaskContinuation_NullTask, ExceptionArgument.tasks); - tasksCopy[i] = task; + tasksCopy[i] = task!; // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 } // Delegate the rest to InternalWhenAll() @@ -5925,7 +5928,7 @@ namespace System.Threading.Tasks /// Stores all of the constituent tasks. Tasks clear themselves out of this /// array as they complete, but only if they don't have their wait notification bit set. /// - private readonly Task[] m_tasks; + private readonly Task?[] m_tasks; /// The number of tasks remaining to complete. private int m_count; @@ -5961,8 +5964,8 @@ namespace System.Threading.Tasks { // Set up some accounting variables T[] results = new T[m_tasks.Length]; - List observedExceptions = null; - Task canceledTask = null; + List? observedExceptions = null; + Task? canceledTask = null; // Loop through antecedents: // If any one of them faults, the result will be faulted @@ -5970,7 +5973,7 @@ namespace System.Threading.Tasks // If none fault or are canceled, then result will be RanToCompletion for (int i = 0; i < m_tasks.Length; i++) { - Task task = m_tasks[i]; + Task? task = m_tasks[i]; Debug.Assert(task != null, "Constituent task in WhenAll should never be null"); if (task.IsFaulted) @@ -6057,7 +6060,7 @@ namespace System.Threading.Tasks public static Task WhenAny(params Task[] tasks) { if (tasks == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.tasks); - if (tasks.Length == 0) + if (tasks!.Length == 0) // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 { ThrowHelper.ThrowArgumentException(ExceptionResource.Task_MultiTaskContinuation_EmptyTaskList, ExceptionArgument.tasks); } @@ -6070,7 +6073,7 @@ namespace System.Threading.Tasks { Task task = tasks[i]; if (task == null) ThrowHelper.ThrowArgumentException(ExceptionResource.Task_MultiTaskContinuation_NullTask, ExceptionArgument.tasks); - tasksCopy[i] = task; + tasksCopy[i] = task!; // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 } // Previously implemented CommonCWAnyLogic() can handle the rest @@ -6099,10 +6102,10 @@ namespace System.Threading.Tasks // Make a defensive copy, as the user may manipulate the tasks collection // after we return but before the WhenAny asynchronously completes. List taskList = new List(); - foreach (Task task in tasks) + foreach (Task task in tasks!) // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 { if (task == null) ThrowHelper.ThrowArgumentException(ExceptionResource.Task_MultiTaskContinuation_NullTask, ExceptionArgument.tasks); - taskList.Add(task); + taskList.Add(task!); // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 } if (taskList.Count == 0) @@ -6183,7 +6186,7 @@ namespace System.Threading.Tasks #if PROJECTN [DependencyReductionRoot] #endif - internal virtual Delegate[] GetDelegateContinuationsForDebugger() + internal virtual Delegate[]? GetDelegateContinuationsForDebugger() { //Avoid an infinite loop by making sure the continuation object is not a reference to istelf. if (m_continuationObject != this) @@ -6192,7 +6195,7 @@ namespace System.Threading.Tasks return null; } - private static Delegate[] GetDelegatesFromContinuationObject(object continuationObject) + private static Delegate[]? GetDelegatesFromContinuationObject(object? continuationObject) { if (continuationObject != null) { @@ -6209,7 +6212,7 @@ namespace System.Threading.Tasks if (continuationObject is Task continuationTask) { Debug.Assert(continuationTask.m_action == null); - Delegate[] delegates = continuationTask.GetDelegateContinuationsForDebugger(); + Delegate[]? delegates = continuationTask.GetDelegateContinuationsForDebugger(); if (delegates != null) return delegates; } @@ -6221,10 +6224,10 @@ namespace System.Threading.Tasks return new Delegate[] { new Action(singleCompletionAction.Invoke) }; } - if (continuationObject is List continuationList) + if (continuationObject is List continuationList) { List result = new List(); - foreach (object obj in continuationList) + foreach (object? obj in continuationList) { var innerDelegates = GetDelegatesFromContinuationObject(obj); if (innerDelegates != null) @@ -6248,10 +6251,10 @@ namespace System.Threading.Tasks [DependencyReductionRoot] #endif //Do not remove: VS debugger calls this API directly using func-eval to populate data in the tasks window - private static Task GetActiveTaskFromId(int taskId) + private static Task? GetActiveTaskFromId(int taskId) { - Task task = null; - s_currentActiveTasks.TryGetValue(taskId, out task); + Task? task = null; + s_currentActiveTasks?.TryGetValue(taskId, out task); return task; } } @@ -6283,9 +6286,9 @@ namespace System.Threading.Tasks m_task = task; } - public object AsyncState { get { return m_task.AsyncState; } } + public object? AsyncState { get { return m_task.AsyncState; } } public TaskCreationOptions CreationOptions { get { return m_task.CreationOptions; } } - public Exception Exception { get { return m_task.Exception; } } + public Exception? Exception { get { return m_task.Exception; } } public int Id { get { return m_task.Id; } } public bool CancellationPending { get { return (m_task.Status == TaskStatus.WaitingToRun) && m_task.CancellationToken.IsCancellationRequested; } } public TaskStatus Status { get { return m_task.Status; } } @@ -6519,7 +6522,7 @@ namespace System.Threading.Tasks private readonly bool _lookForOce; public UnwrapPromise(Task outerTask, bool lookForOce) - : base((object)null, outerTask.CreationOptions & TaskCreationOptions.AttachedToParent) + : base((object?)null, outerTask.CreationOptions & TaskCreationOptions.AttachedToParent) { Debug.Assert(outerTask != null, "Expected non-null outerTask"); _lookForOce = lookForOce; @@ -6594,7 +6597,7 @@ namespace System.Threading.Tasks ThreadPool.UnsafeQueueUserWorkItem(state => { // InvokeCore(completingTask); - var tuple = (Tuple, Task>)state; + var tuple = (Tuple, Task>)state!; // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 tuple.Item1.InvokeCore(tuple.Item2); }, Tuple.Create, Task>(this, completingTask)); } @@ -6648,7 +6651,7 @@ namespace System.Threading.Tasks case TaskStatus.Faulted: var edis = task.GetExceptionDispatchInfos(); ExceptionDispatchInfo oceEdi; - OperationCanceledException oce; + OperationCanceledException? oce; if (lookForOce && edis.Count > 0 && (oceEdi = edis[0]) != null && (oce = oceEdi.SourceException as OperationCanceledException) != null) @@ -6670,7 +6673,7 @@ namespace System.Threading.Tasks if (Task.s_asyncDebuggingEnabled) RemoveFromActiveTasks(this); - result = TrySetResult(taskTResult != null ? taskTResult.Result : default); + result = TrySetResult(taskTResult != null ? taskTResult.Result : default!); // TODO-NULLABLE-GENERIC break; } return result; @@ -6681,7 +6684,7 @@ namespace System.Threading.Tasks /// transferring the appropriate results to ourself. /// /// The inner task returned by the task provided by the user. - private void ProcessInnerTask(Task task) + private void ProcessInnerTask(Task? task) { // If the inner task is null, the proxy should be canceled. if (task == null) diff --git a/src/System.Private.CoreLib/shared/System/Threading/Tasks/TaskCanceledException.cs b/src/System.Private.CoreLib/shared/System/Threading/Tasks/TaskCanceledException.cs index c3ee31a53c..5147f116eb 100644 --- a/src/System.Private.CoreLib/shared/System/Threading/Tasks/TaskCanceledException.cs +++ b/src/System.Private.CoreLib/shared/System/Threading/Tasks/TaskCanceledException.cs @@ -10,8 +10,7 @@ // // =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -using System; -using System.Runtime.InteropServices; +#nullable enable using System.Runtime.Serialization; namespace System.Threading.Tasks @@ -24,7 +23,7 @@ namespace System.Threading.Tasks public class TaskCanceledException : OperationCanceledException { [NonSerialized] - private readonly Task _canceledTask; // The task which has been canceled. + private readonly Task? _canceledTask; // The task which has been canceled. /// /// Initializes a new instance of the class. @@ -38,7 +37,7 @@ namespace System.Threading.Tasks /// class with a specified error message. /// /// The error message that explains the reason for the exception. - public TaskCanceledException(string message) : base(message) + public TaskCanceledException(string? message) : base(message) { } @@ -49,7 +48,7 @@ namespace System.Threading.Tasks /// /// The error message that explains the reason for the exception. /// The exception that is the cause of the current exception. - public TaskCanceledException(string message, Exception innerException) : base(message, innerException) + public TaskCanceledException(string? message, Exception? innerException) : base(message, innerException) { } @@ -61,7 +60,7 @@ namespace System.Threading.Tasks /// The error message that explains the reason for the exception. /// The exception that is the cause of the current exception. /// The that triggered the cancellation. - public TaskCanceledException(string message, Exception innerException, CancellationToken token) : base(message, innerException, token) + public TaskCanceledException(string? message, Exception? innerException, CancellationToken token) : base(message, innerException, token) { } @@ -70,7 +69,7 @@ namespace System.Threading.Tasks /// with a reference to the that has been canceled. /// /// A task that has been canceled. - public TaskCanceledException(Task task) : + public TaskCanceledException(Task? task) : base(SR.TaskCanceledException_ctor_DefaultMessage, task != null ? task.CancellationToken : new CancellationToken()) { _canceledTask = task; @@ -94,6 +93,6 @@ namespace System.Threading.Tasks /// , in which case /// this property will return null. /// - public Task Task => _canceledTask; + public Task? Task => _canceledTask; } } diff --git a/src/System.Private.CoreLib/shared/System/Threading/Tasks/TaskCompletionSource.cs b/src/System.Private.CoreLib/shared/System/Threading/Tasks/TaskCompletionSource.cs index c85a44f974..045486a6a1 100644 --- a/src/System.Private.CoreLib/shared/System/Threading/Tasks/TaskCompletionSource.cs +++ b/src/System.Private.CoreLib/shared/System/Threading/Tasks/TaskCompletionSource.cs @@ -11,6 +11,7 @@ // // =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +#nullable enable using System; using System.Diagnostics; using System.Collections.Generic; @@ -81,7 +82,7 @@ namespace System.Threading.Tasks /// /// The state to use as the underlying /// 's AsyncState. - public TaskCompletionSource(object state) + public TaskCompletionSource(object? state) : this(state, TaskCreationOptions.None) { } @@ -98,7 +99,7 @@ namespace System.Threading.Tasks /// The represent options invalid for use /// with a . /// - public TaskCompletionSource(object state, TaskCreationOptions creationOptions) + public TaskCompletionSource(object? state, TaskCreationOptions creationOptions) { _task = new Task(state, creationOptions); } @@ -150,7 +151,7 @@ namespace System.Threading.Tasks { if (exception == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.exception); - bool rval = _task.TrySetException(exception); + bool rval = _task.TrySetException(exception!); // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 if (!rval && !_task.IsCompleted) SpinUntilCompleted(); return rval; } @@ -180,11 +181,11 @@ namespace System.Threading.Tasks if (exceptions == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.exceptions); List defensiveCopy = new List(); - foreach (Exception e in exceptions) + foreach (Exception e in exceptions!) // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 { if (e == null) ThrowHelper.ThrowArgumentException(ExceptionResource.TaskCompletionSourceT_TrySetException_NullException, ExceptionArgument.exceptions); - defensiveCopy.Add(e); + defensiveCopy.Add(e!); // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 } if (defensiveCopy.Count == 0) @@ -216,7 +217,7 @@ namespace System.Threading.Tasks { if (exception == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.exception); - if (!TrySetException(exception)) + if (!TrySetException(exception!)) // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 { ThrowHelper.ThrowInvalidOperationException(ExceptionResource.TaskT_TransitionToFinal_AlreadyCompleted); } diff --git a/src/System.Private.CoreLib/shared/System/Threading/Tasks/TaskContinuation.cs b/src/System.Private.CoreLib/shared/System/Threading/Tasks/TaskContinuation.cs index 63ae2bd815..0968a747b1 100644 --- a/src/System.Private.CoreLib/shared/System/Threading/Tasks/TaskContinuation.cs +++ b/src/System.Private.CoreLib/shared/System/Threading/Tasks/TaskContinuation.cs @@ -2,9 +2,8 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using System.Security; +#nullable enable using System.Diagnostics; -using System.Runtime.ExceptionServices; using System.Runtime.CompilerServices; namespace System.Threading.Tasks @@ -12,13 +11,13 @@ namespace System.Threading.Tasks // Task type used to implement: Task ContinueWith(Action) internal sealed class ContinuationTaskFromTask : Task { - private Task m_antecedent; + private Task? m_antecedent; public ContinuationTaskFromTask( - Task antecedent, Delegate action, object state, TaskCreationOptions creationOptions, InternalTaskOptions internalOptions) : + Task antecedent, Delegate action, object? state, TaskCreationOptions creationOptions, InternalTaskOptions internalOptions) : base(action, state, Task.InternalCurrentIfAttached(creationOptions), default, creationOptions, internalOptions, null) { - Debug.Assert(action is Action || action is Action, + Debug.Assert(action is Action || action is Action, "Invalid delegate type in ContinuationTaskFromTask"); m_antecedent = antecedent; } @@ -30,7 +29,7 @@ namespace System.Threading.Tasks { // Get and null out the antecedent. This is crucial to avoid a memory // leak with long chains of continuations. - var antecedent = m_antecedent; + Task? antecedent = m_antecedent; Debug.Assert(antecedent != null, "No antecedent was set for the ContinuationTaskFromTask."); m_antecedent = null; @@ -46,7 +45,7 @@ namespace System.Threading.Tasks return; } - if (m_action is Action actionWithState) + if (m_action is Action actionWithState) { actionWithState(antecedent, m_stateObject); return; @@ -58,13 +57,13 @@ namespace System.Threading.Tasks // Task type used to implement: Task ContinueWith(Func) internal sealed class ContinuationResultTaskFromTask : Task { - private Task m_antecedent; + private Task? m_antecedent; public ContinuationResultTaskFromTask( - Task antecedent, Delegate function, object state, TaskCreationOptions creationOptions, InternalTaskOptions internalOptions) : + Task antecedent, Delegate function, object? state, TaskCreationOptions creationOptions, InternalTaskOptions internalOptions) : base(function, state, Task.InternalCurrentIfAttached(creationOptions), default, creationOptions, internalOptions, null) { - Debug.Assert(function is Func || function is Func, + Debug.Assert(function is Func || function is Func, "Invalid delegate type in ContinuationResultTaskFromTask"); m_antecedent = antecedent; } @@ -76,7 +75,7 @@ namespace System.Threading.Tasks { // Get and null out the antecedent. This is crucial to avoid a memory // leak with long chains of continuations. - var antecedent = m_antecedent; + Task? antecedent = m_antecedent; Debug.Assert(antecedent != null, "No antecedent was set for the ContinuationResultTaskFromTask."); m_antecedent = null; @@ -92,7 +91,7 @@ namespace System.Threading.Tasks return; } - if (m_action is Func funcWithState) + if (m_action is Func funcWithState) { m_result = funcWithState(antecedent, m_stateObject); return; @@ -104,13 +103,13 @@ namespace System.Threading.Tasks // Task type used to implement: Task ContinueWith(Action,...>) internal sealed class ContinuationTaskFromResultTask : Task { - private Task m_antecedent; + private Task? m_antecedent; public ContinuationTaskFromResultTask( - Task antecedent, Delegate action, object state, TaskCreationOptions creationOptions, InternalTaskOptions internalOptions) : + Task antecedent, Delegate action, object? state, TaskCreationOptions creationOptions, InternalTaskOptions internalOptions) : base(action, state, Task.InternalCurrentIfAttached(creationOptions), default, creationOptions, internalOptions, null) { - Debug.Assert(action is Action> || action is Action, object>, + Debug.Assert(action is Action> || action is Action, object?>, "Invalid delegate type in ContinuationTaskFromResultTask"); m_antecedent = antecedent; } @@ -122,7 +121,7 @@ namespace System.Threading.Tasks { // Get and null out the antecedent. This is crucial to avoid a memory // leak with long chains of continuations. - var antecedent = m_antecedent; + Task? antecedent = m_antecedent; Debug.Assert(antecedent != null, "No antecedent was set for the ContinuationTaskFromResultTask."); m_antecedent = null; @@ -138,7 +137,7 @@ namespace System.Threading.Tasks return; } - if (m_action is Action, object> actionWithState) + if (m_action is Action, object?> actionWithState) { actionWithState(antecedent, m_stateObject); return; @@ -150,13 +149,13 @@ namespace System.Threading.Tasks // Task type used to implement: Task ContinueWith(Func,...>) internal sealed class ContinuationResultTaskFromResultTask : Task { - private Task m_antecedent; + private Task? m_antecedent; public ContinuationResultTaskFromResultTask( - Task antecedent, Delegate function, object state, TaskCreationOptions creationOptions, InternalTaskOptions internalOptions) : + Task antecedent, Delegate function, object? state, TaskCreationOptions creationOptions, InternalTaskOptions internalOptions) : base(function, state, Task.InternalCurrentIfAttached(creationOptions), default, creationOptions, internalOptions, null) { - Debug.Assert(function is Func, TResult> || function is Func, object, TResult>, + Debug.Assert(function is Func, TResult> || function is Func, object?, TResult>, "Invalid delegate type in ContinuationResultTaskFromResultTask"); m_antecedent = antecedent; } @@ -168,7 +167,7 @@ namespace System.Threading.Tasks { // Get and null out the antecedent. This is crucial to avoid a memory // leak with long chains of continuations. - var antecedent = m_antecedent; + Task? antecedent = m_antecedent; Debug.Assert(antecedent != null, "No antecedent was set for the ContinuationResultTaskFromResultTask."); m_antecedent = null; @@ -184,7 +183,7 @@ namespace System.Threading.Tasks return; } - if (m_action is Func, object, TResult> funcWithState) + if (m_action is Func, object?, TResult> funcWithState) { m_result = funcWithState(antecedent, m_stateObject); return; @@ -283,7 +282,7 @@ namespace System.Threading.Tasks m_options = options; m_taskScheduler = scheduler; if (AsyncCausalityTracer.LoggingOn) - AsyncCausalityTracer.TraceOperationCreation(m_task, "Task.ContinueWith: " + task.m_action.Method.Name); + AsyncCausalityTracer.TraceOperationCreation(m_task, "Task.ContinueWith: " + task.m_action!.Method.Name); if (Task.s_asyncDebuggingEnabled) Task.AddToActiveTasks(m_task); @@ -343,7 +342,7 @@ namespace System.Threading.Tasks else continuationTask.InternalCancel(false); } - internal override Delegate[] GetDelegateContinuationsForDebugger() + internal override Delegate[]? GetDelegateContinuationsForDebugger() { if (m_task.m_action == null) { @@ -358,9 +357,13 @@ namespace System.Threading.Tasks internal sealed class SynchronizationContextAwaitTaskContinuation : AwaitTaskContinuation { /// SendOrPostCallback delegate to invoke the action. - private static readonly SendOrPostCallback s_postCallback = state => ((Action)state)(); // can't use InvokeAction as it's SecurityCritical + private static readonly SendOrPostCallback s_postCallback = state => + { + Debug.Assert(state is Action); + ((Action)state)(); + }; /// Cached delegate for PostAction - private static ContextCallback s_postActionCallback; + private static ContextCallback? s_postActionCallback; /// The context with which to run the action. private readonly SynchronizationContext m_syncContext; @@ -403,8 +406,9 @@ namespace System.Threading.Tasks /// Calls InvokeOrPostAction(false) on the supplied SynchronizationContextAwaitTaskContinuation. /// The SynchronizationContextAwaitTaskContinuation. - private static void PostAction(object state) + private static void PostAction(object? state) { + Debug.Assert(state is SynchronizationContextAwaitTaskContinuation); var c = (SynchronizationContextAwaitTaskContinuation)state; TplEventSource log = TplEventSource.Log; @@ -438,7 +442,7 @@ namespace System.Threading.Tasks [MethodImpl(MethodImplOptions.AggressiveInlining)] private static ContextCallback GetPostActionCallback() { - ContextCallback callback = s_postActionCallback; + ContextCallback? callback = s_postActionCallback; if (callback == null) { s_postActionCallback = callback = PostAction; } // lazily initialize SecurityCritical delegate return callback; } @@ -489,7 +493,7 @@ namespace System.Threading.Tasks { try { - ((Action)state)(); + ((Action)state!)(); // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 } catch (Exception exception) { @@ -515,7 +519,7 @@ namespace System.Threading.Tasks internal class AwaitTaskContinuation : TaskContinuation, IThreadPoolWorkItem { /// The ExecutionContext with which to run the continuation. - private readonly ExecutionContext m_capturedContext; + private readonly ExecutionContext? m_capturedContext; /// The action to invoke. protected readonly Action m_action; @@ -539,7 +543,7 @@ namespace System.Threading.Tasks /// The state to pass to the action. Must not be null. /// The scheduler to target. /// The created task. - protected Task CreateTask(Action action, object state, TaskScheduler scheduler) + protected Task CreateTask(Action action, object? state, TaskScheduler scheduler) { Debug.Assert(action != null); Debug.Assert(scheduler != null); @@ -615,7 +619,7 @@ namespace System.Threading.Tasks void IThreadPoolWorkItem.Execute() { var log = TplEventSource.Log; - ExecutionContext context = m_capturedContext; + ExecutionContext? context = m_capturedContext; if (!log.IsEnabled() && context == null) { @@ -659,7 +663,11 @@ namespace System.Threading.Tasks } /// Cached delegate that invokes an Action passed as an object parameter. - private readonly static ContextCallback s_invokeContextCallback = (state) => ((Action)state)(); + private readonly static ContextCallback s_invokeContextCallback = (state) => + { + Debug.Assert(state is Action); + ((Action)state)(); + }; private readonly static Action s_invokeAction = (action) => action(); [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -669,7 +677,7 @@ namespace System.Threading.Tasks /// The callback to run. /// The state to pass to the callback. /// A reference to Task.t_currentTask. - protected void RunCallback(ContextCallback callback, object state, ref Task currentTask) + protected void RunCallback(ContextCallback callback, object? state, ref Task? currentTask) { Debug.Assert(callback != null); Debug.Assert(currentTask == Task.t_currentTask); @@ -681,7 +689,7 @@ namespace System.Threading.Tasks { if (prevCurrentTask != null) currentTask = null; - ExecutionContext context = m_capturedContext; + ExecutionContext? context = m_capturedContext; if (context == null) { // If there's no captured context, just run the callback directly. @@ -717,8 +725,8 @@ namespace System.Threading.Tasks /// internal static void RunOrScheduleAction(Action action, bool allowInlining) { - ref Task currentTask = ref Task.t_currentTask; - Task prevCurrentTask = currentTask; + ref Task? currentTask = ref Task.t_currentTask; + Task? prevCurrentTask = currentTask; // If we're not allowed to run here, schedule the action if (!allowInlining || !IsValidLocationForInlining) @@ -753,8 +761,8 @@ namespace System.Threading.Tasks // Same logic as in the RunOrScheduleAction(Action, ...) overload, except invoking // box.Invoke instead of action(). - ref Task currentTask = ref Task.t_currentTask; - Task prevCurrentTask = currentTask; + ref Task? currentTask = ref Task.t_currentTask; + Task? prevCurrentTask = currentTask; // If we're not allowed to run here, schedule the action if (!allowInlining || !IsValidLocationForInlining) @@ -798,7 +806,7 @@ namespace System.Threading.Tasks /// Schedules the action to be executed. No ExecutionContext work is performed used. /// The action to invoke or queue. /// The task scheduling the action. - internal static void UnsafeScheduleAction(Action action, Task task) + internal static void UnsafeScheduleAction(Action action, Task? task) { AwaitTaskContinuation atc = new AwaitTaskContinuation(action, flowExecutionContext: false); diff --git a/src/System.Private.CoreLib/shared/System/Threading/Tasks/TaskExceptionHolder.cs b/src/System.Private.CoreLib/shared/System/Threading/Tasks/TaskExceptionHolder.cs index 67b4220b8d..d35e6a2e67 100644 --- a/src/System.Private.CoreLib/shared/System/Threading/Tasks/TaskExceptionHolder.cs +++ b/src/System.Private.CoreLib/shared/System/Threading/Tasks/TaskExceptionHolder.cs @@ -10,6 +10,7 @@ // // =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +#nullable enable using System.Collections.Generic; using System.Collections.ObjectModel; using System.Diagnostics; @@ -33,9 +34,9 @@ namespace System.Threading.Tasks /// The lazily-initialized list of faulting exceptions. Volatile /// so that it may be read to determine whether any exceptions were stored. /// - private volatile List m_faultExceptions; + private volatile List? m_faultExceptions; /// An exception that triggered the task to cancel. - private ExceptionDispatchInfo m_cancellationException; + private ExceptionDispatchInfo? m_cancellationException; /// Whether the holder was "observed" and thus doesn't cause finalization behavior. private volatile bool m_isHandled; @@ -252,7 +253,7 @@ namespace System.Threading.Tasks /// Whether this is being called from a finalizer. /// An extra exception to be included (optionally). /// The aggregate exception to throw. - internal AggregateException CreateExceptionObject(bool calledFromFinalizer, Exception includeThisException) + internal AggregateException CreateExceptionObject(bool calledFromFinalizer, Exception? includeThisException) { var exceptions = m_faultExceptions; Debug.Assert(exceptions != null, "Expected an initialized list."); @@ -284,7 +285,7 @@ namespace System.Threading.Tasks /// internal ReadOnlyCollection GetExceptionDispatchInfos() { - var exceptions = m_faultExceptions; + List? exceptions = m_faultExceptions; Debug.Assert(exceptions != null, "Expected an initialized list."); Debug.Assert(exceptions.Count > 0, "Expected at least one exception."); MarkAsHandled(false); @@ -298,7 +299,7 @@ namespace System.Threading.Tasks /// /// The ExceptionDispatchInfo for the cancellation exception. May be null. /// - internal ExceptionDispatchInfo GetCancellationExceptionDispatchInfo() + internal ExceptionDispatchInfo? GetCancellationExceptionDispatchInfo() { var edi = m_cancellationException; Debug.Assert(edi == null || edi.SourceException is OperationCanceledException, diff --git a/src/System.Private.CoreLib/shared/System/Threading/Tasks/TaskExtensions.cs b/src/System.Private.CoreLib/shared/System/Threading/Tasks/TaskExtensions.cs index 75b4b0a378..4b45f75c98 100644 --- a/src/System.Private.CoreLib/shared/System/Threading/Tasks/TaskExtensions.cs +++ b/src/System.Private.CoreLib/shared/System/Threading/Tasks/TaskExtensions.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +#nullable enable using System.Collections.Generic; using System.Runtime.CompilerServices; diff --git a/src/System.Private.CoreLib/shared/System/Threading/Tasks/TaskFactory.cs b/src/System.Private.CoreLib/shared/System/Threading/Tasks/TaskFactory.cs index f7816d6206..cc5a5a1aa1 100644 --- a/src/System.Private.CoreLib/shared/System/Threading/Tasks/TaskFactory.cs +++ b/src/System.Private.CoreLib/shared/System/Threading/Tasks/TaskFactory.cs @@ -12,6 +12,7 @@ // // =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +#nullable enable using System; using System.Collections.Generic; using System.Security; @@ -40,18 +41,18 @@ namespace System.Threading.Tasks { // member variables private readonly CancellationToken m_defaultCancellationToken; - private readonly TaskScheduler m_defaultScheduler; + private readonly TaskScheduler? m_defaultScheduler; private readonly TaskCreationOptions m_defaultCreationOptions; private readonly TaskContinuationOptions m_defaultContinuationOptions; private TaskScheduler DefaultScheduler => m_defaultScheduler ?? TaskScheduler.Current; // sister method to above property -- avoids a TLS lookup - private TaskScheduler GetDefaultScheduler(Task currTask) + private TaskScheduler GetDefaultScheduler(Task? currTask) { return m_defaultScheduler ?? - (currTask != null && (currTask.CreationOptions & TaskCreationOptions.HideScheduler) == 0 ? currTask.ExecutingTaskScheduler : + (currTask != null && (currTask.CreationOptions & TaskCreationOptions.HideScheduler) == 0 ? currTask.ExecutingTaskScheduler! : // a "current" task must be executing, which means it must have a scheduler TaskScheduler.Default); } @@ -119,7 +120,7 @@ namespace System.Threading.Tasks /// initialized to the current scheduler (see TaskScheduler.Current). /// - public TaskFactory(TaskScheduler scheduler) // null means to use TaskScheduler.Current + public TaskFactory(TaskScheduler? scheduler) // null means to use TaskScheduler.Current : this(default, TaskCreationOptions.None, TaskContinuationOptions.None, scheduler) { } @@ -190,7 +191,7 @@ namespace System.Threading.Tasks /// current scheduler (see TaskScheduler.Current). /// - public TaskFactory(CancellationToken cancellationToken, TaskCreationOptions creationOptions, TaskContinuationOptions continuationOptions, TaskScheduler scheduler) + public TaskFactory(CancellationToken cancellationToken, TaskCreationOptions creationOptions, TaskContinuationOptions continuationOptions, TaskScheduler? scheduler) { CheckMultiTaskContinuationOptions(continuationOptions); CheckCreationOptions(creationOptions); @@ -239,7 +240,7 @@ namespace System.Threading.Tasks /// If null, TaskScheduler.Current /// will be used. /// - public TaskScheduler Scheduler { get { return m_defaultScheduler; } } + public TaskScheduler? Scheduler { get { return m_defaultScheduler; } } /// /// Gets the TaskCreationOptions @@ -281,7 +282,7 @@ namespace System.Threading.Tasks /// public Task StartNew(Action action) { - Task currTask = Task.InternalCurrent; + Task? currTask = Task.InternalCurrent; return Task.InternalStartNew(currTask, action, null, m_defaultCancellationToken, GetDefaultScheduler(currTask), m_defaultCreationOptions, InternalTaskOptions.None); } @@ -306,7 +307,7 @@ namespace System.Threading.Tasks /// public Task StartNew(Action action, CancellationToken cancellationToken) { - Task currTask = Task.InternalCurrent; + Task? currTask = Task.InternalCurrent; return Task.InternalStartNew(currTask, action, null, cancellationToken, GetDefaultScheduler(currTask), m_defaultCreationOptions, InternalTaskOptions.None); } @@ -334,7 +335,7 @@ namespace System.Threading.Tasks /// public Task StartNew(Action action, TaskCreationOptions creationOptions) { - Task currTask = Task.InternalCurrent; + Task? currTask = Task.InternalCurrent; return Task.InternalStartNew(currTask, action, null, m_defaultCancellationToken, GetDefaultScheduler(currTask), creationOptions, InternalTaskOptions.None); } @@ -396,9 +397,9 @@ namespace System.Threading.Tasks /// However, unless creation and scheduling must be separated, StartNew is the recommended approach /// for both simplicity and performance. /// - public Task StartNew(Action action, object state) + public Task StartNew(Action action, object? state) // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 { - Task currTask = Task.InternalCurrent; + Task? currTask = Task.InternalCurrent; return Task.InternalStartNew(currTask, action, state, m_defaultCancellationToken, GetDefaultScheduler(currTask), m_defaultCreationOptions, InternalTaskOptions.None); } @@ -425,9 +426,9 @@ namespace System.Threading.Tasks /// However, unless creation and scheduling must be separated, StartNew is the recommended approach /// for both simplicity and performance. /// - public Task StartNew(Action action, object state, CancellationToken cancellationToken) + public Task StartNew(Action action, object? state, CancellationToken cancellationToken) // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 { - Task currTask = Task.InternalCurrent; + Task? currTask = Task.InternalCurrent; return Task.InternalStartNew(currTask, action, state, cancellationToken, GetDefaultScheduler(currTask), m_defaultCreationOptions, InternalTaskOptions.None); } @@ -455,9 +456,9 @@ namespace System.Threading.Tasks /// However, unless creation and scheduling must be separated, StartNew is the recommended approach /// for both simplicity and performance. /// - public Task StartNew(Action action, object state, TaskCreationOptions creationOptions) + public Task StartNew(Action action, object? state, TaskCreationOptions creationOptions) // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 { - Task currTask = Task.InternalCurrent; + Task? currTask = Task.InternalCurrent; return Task.InternalStartNew(currTask, action, state, m_defaultCancellationToken, GetDefaultScheduler(currTask), creationOptions, InternalTaskOptions.None); } @@ -496,7 +497,7 @@ namespace System.Threading.Tasks /// However, unless creation and scheduling must be separated, StartNew is the recommended approach /// for both simplicity and performance. /// - public Task StartNew(Action action, object state, CancellationToken cancellationToken, + public Task StartNew(Action action, object? state, CancellationToken cancellationToken, // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 TaskCreationOptions creationOptions, TaskScheduler scheduler) { return Task.InternalStartNew( @@ -525,7 +526,7 @@ namespace System.Threading.Tasks /// public Task StartNew(Func function) { - Task currTask = Task.InternalCurrent; + Task? currTask = Task.InternalCurrent; return Task.StartNew(currTask, function, m_defaultCancellationToken, m_defaultCreationOptions, InternalTaskOptions.None, GetDefaultScheduler(currTask)); } @@ -556,7 +557,7 @@ namespace System.Threading.Tasks /// public Task StartNew(Func function, CancellationToken cancellationToken) { - Task currTask = Task.InternalCurrent; + Task? currTask = Task.InternalCurrent; return Task.StartNew(currTask, function, cancellationToken, m_defaultCreationOptions, InternalTaskOptions.None, GetDefaultScheduler(currTask)); } @@ -588,7 +589,7 @@ namespace System.Threading.Tasks /// public Task StartNew(Func function, TaskCreationOptions creationOptions) { - Task currTask = Task.InternalCurrent; + Task? currTask = Task.InternalCurrent; return Task.StartNew(currTask, function, m_defaultCancellationToken, creationOptions, InternalTaskOptions.None, GetDefaultScheduler(currTask)); } @@ -657,9 +658,9 @@ namespace System.Threading.Tasks /// However, unless creation and scheduling must be separated, StartNew is the recommended approach /// for both simplicity and performance. /// - public Task StartNew(Func function, object state) + public Task StartNew(Func function, object? state) // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 { - Task currTask = Task.InternalCurrent; + Task? currTask = Task.InternalCurrent; return Task.StartNew(currTask, function, state, m_defaultCancellationToken, m_defaultCreationOptions, InternalTaskOptions.None, GetDefaultScheduler(currTask)); } @@ -690,9 +691,9 @@ namespace System.Threading.Tasks /// However, unless creation and scheduling must be separated, StartNew is the recommended approach /// for both simplicity and performance. /// - public Task StartNew(Func function, object state, CancellationToken cancellationToken) + public Task StartNew(Func function, object? state, CancellationToken cancellationToken) // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 { - Task currTask = Task.InternalCurrent; + Task? currTask = Task.InternalCurrent; return Task.StartNew(currTask, function, state, cancellationToken, m_defaultCreationOptions, InternalTaskOptions.None, GetDefaultScheduler(currTask)); } @@ -724,9 +725,9 @@ namespace System.Threading.Tasks /// However, unless creation and scheduling must be separated, StartNew is the recommended approach /// for both simplicity and performance. /// - public Task StartNew(Func function, object state, TaskCreationOptions creationOptions) + public Task StartNew(Func function, object? state, TaskCreationOptions creationOptions) // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 { - Task currTask = Task.InternalCurrent; + Task? currTask = Task.InternalCurrent; return Task.StartNew(currTask, function, state, m_defaultCancellationToken, creationOptions, InternalTaskOptions.None, GetDefaultScheduler(currTask)); } @@ -769,7 +770,7 @@ namespace System.Threading.Tasks /// However, unless creation and scheduling must be separated, StartNew is the recommended approach /// for both simplicity and performance. /// - public Task StartNew(Func function, object state, CancellationToken cancellationToken, + public Task StartNew(Func function, object? state, CancellationToken cancellationToken, // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 TaskCreationOptions creationOptions, TaskScheduler scheduler) { return Task.StartNew( @@ -879,9 +880,9 @@ namespace System.Threading.Tasks /// This method throws any exceptions thrown by the . /// public Task FromAsync( - Func beginMethod, + Func beginMethod, Action endMethod, - object state) + object? state) { return FromAsync(beginMethod, endMethod, state, m_defaultCreationOptions); } @@ -909,8 +910,8 @@ namespace System.Threading.Tasks /// This method throws any exceptions thrown by the . /// public Task FromAsync( - Func beginMethod, - Action endMethod, object state, TaskCreationOptions creationOptions) + Func beginMethod, + Action endMethod, object? state, TaskCreationOptions creationOptions) { return TaskFactory.FromAsyncImpl(beginMethod, null, endMethod, state, creationOptions); } @@ -938,10 +939,10 @@ namespace System.Threading.Tasks /// This method throws any exceptions thrown by the . /// public Task FromAsync( - Func beginMethod, + Func beginMethod, Action endMethod, TArg1 arg1, - object state) + object? state) { return FromAsync(beginMethod, endMethod, arg1, state, m_defaultCreationOptions); } @@ -974,9 +975,9 @@ namespace System.Threading.Tasks /// This method throws any exceptions thrown by the . /// public Task FromAsync( - Func beginMethod, + Func beginMethod, Action endMethod, - TArg1 arg1, object state, TaskCreationOptions creationOptions) + TArg1 arg1, object? state, TaskCreationOptions creationOptions) { return TaskFactory.FromAsyncImpl(beginMethod, null, endMethod, arg1, state, creationOptions); } @@ -1008,9 +1009,9 @@ namespace System.Threading.Tasks /// This method throws any exceptions thrown by the . /// public Task FromAsync( - Func beginMethod, + Func beginMethod, Action endMethod, - TArg1 arg1, TArg2 arg2, object state) + TArg1 arg1, TArg2 arg2, object? state) { return FromAsync(beginMethod, endMethod, arg1, arg2, state, m_defaultCreationOptions); } @@ -1047,9 +1048,9 @@ namespace System.Threading.Tasks /// This method throws any exceptions thrown by the . /// public Task FromAsync( - Func beginMethod, + Func beginMethod, Action endMethod, - TArg1 arg1, TArg2 arg2, object state, TaskCreationOptions creationOptions) + TArg1 arg1, TArg2 arg2, object? state, TaskCreationOptions creationOptions) { return TaskFactory.FromAsyncImpl(beginMethod, null, endMethod, arg1, arg2, state, creationOptions); } @@ -1085,9 +1086,9 @@ namespace System.Threading.Tasks /// This method throws any exceptions thrown by the . /// public Task FromAsync( - Func beginMethod, + Func beginMethod, Action endMethod, - TArg1 arg1, TArg2 arg2, TArg3 arg3, object state) + TArg1 arg1, TArg2 arg2, TArg3 arg3, object? state) { return FromAsync(beginMethod, endMethod, arg1, arg2, arg3, state, m_defaultCreationOptions); } @@ -1128,9 +1129,9 @@ namespace System.Threading.Tasks /// This method throws any exceptions thrown by the . /// public Task FromAsync( - Func beginMethod, + Func beginMethod, Action endMethod, - TArg1 arg1, TArg2 arg2, TArg3 arg3, object state, TaskCreationOptions creationOptions) + TArg1 arg1, TArg2 arg2, TArg3 arg3, object? state, TaskCreationOptions creationOptions) { return TaskFactory.FromAsyncImpl(beginMethod, null, endMethod, arg1, arg2, arg3, state, creationOptions); } @@ -1243,8 +1244,8 @@ namespace System.Threading.Tasks /// This method throws any exceptions thrown by the . /// public Task FromAsync( - Func beginMethod, - Func endMethod, object state) + Func beginMethod, + Func endMethod, object? state) { return TaskFactory.FromAsyncImpl(beginMethod, endMethod, null, state, m_defaultCreationOptions); } @@ -1275,8 +1276,8 @@ namespace System.Threading.Tasks /// This method throws any exceptions thrown by the . /// public Task FromAsync( - Func beginMethod, - Func endMethod, object state, TaskCreationOptions creationOptions) + Func beginMethod, + Func endMethod, object? state, TaskCreationOptions creationOptions) { return TaskFactory.FromAsyncImpl(beginMethod, endMethod, null, state, creationOptions); } @@ -1306,8 +1307,8 @@ namespace System.Threading.Tasks /// This method throws any exceptions thrown by the . /// public Task FromAsync( - Func beginMethod, - Func endMethod, TArg1 arg1, object state) + Func beginMethod, + Func endMethod, TArg1 arg1, object? state) { return TaskFactory.FromAsyncImpl(beginMethod, endMethod, null, arg1, state, m_defaultCreationOptions); } @@ -1341,8 +1342,8 @@ namespace System.Threading.Tasks /// /// This method throws any exceptions thrown by the . /// - public Task FromAsync(Func beginMethod, - Func endMethod, TArg1 arg1, object state, TaskCreationOptions creationOptions) + public Task FromAsync(Func beginMethod, + Func endMethod, TArg1 arg1, object? state, TaskCreationOptions creationOptions) { return TaskFactory.FromAsyncImpl(beginMethod, endMethod, null, arg1, state, creationOptions); } @@ -1375,8 +1376,8 @@ namespace System.Threading.Tasks /// /// This method throws any exceptions thrown by the . /// - public Task FromAsync(Func beginMethod, - Func endMethod, TArg1 arg1, TArg2 arg2, object state) + public Task FromAsync(Func beginMethod, + Func endMethod, TArg1 arg1, TArg2 arg2, object? state) { return TaskFactory.FromAsyncImpl(beginMethod, endMethod, null, arg1, arg2, state, m_defaultCreationOptions); } @@ -1415,8 +1416,8 @@ namespace System.Threading.Tasks /// This method throws any exceptions thrown by the . /// public Task FromAsync( - Func beginMethod, - Func endMethod, TArg1 arg1, TArg2 arg2, object state, TaskCreationOptions creationOptions) + Func beginMethod, + Func endMethod, TArg1 arg1, TArg2 arg2, object? state, TaskCreationOptions creationOptions) { return TaskFactory.FromAsyncImpl(beginMethod, endMethod, null, arg1, arg2, state, creationOptions); } @@ -1454,8 +1455,8 @@ namespace System.Threading.Tasks /// This method throws any exceptions thrown by the . /// public Task FromAsync( - Func beginMethod, - Func endMethod, TArg1 arg1, TArg2 arg2, TArg3 arg3, object state) + Func beginMethod, + Func endMethod, TArg1 arg1, TArg2 arg2, TArg3 arg3, object? state) { return TaskFactory.FromAsyncImpl(beginMethod, endMethod, null, arg1, arg2, arg3, state, m_defaultCreationOptions); } @@ -1498,8 +1499,8 @@ namespace System.Threading.Tasks /// This method throws any exceptions thrown by the . /// public Task FromAsync( - Func beginMethod, - Func endMethod, TArg1 arg1, TArg2 arg2, TArg3 arg3, object state, TaskCreationOptions creationOptions) + Func beginMethod, + Func endMethod, TArg1 arg1, TArg2 arg2, TArg3 arg3, object? state, TaskCreationOptions creationOptions) { return TaskFactory.FromAsyncImpl(beginMethod, endMethod, null, arg1, arg2, arg3, state, creationOptions); } @@ -2284,7 +2285,7 @@ namespace System.Threading.Tasks private const int CompletedFlag = 0b_01; private const int SyncBlockingFlag = 0b_10; - private IList _tasks; // must track this for cleanup + private IList? _tasks; // must track this for cleanup private int _stateFlags; public CompleteOnInvokePromise(IList tasks, bool isSyncBlocking) : base() @@ -2331,7 +2332,8 @@ namespace System.Threading.Tasks // This may also help to avoided unnecessary invocations of this whenComplete delegate. // Note that we may be attempting to remove a continuation from a task that hasn't had it // added yet; while there's overhead there, the operation won't hurt anything. - var tasks = _tasks; + IList? tasks = _tasks; + Debug.Assert(tasks != null, "Should not have been nulled out yet."); int numTasks = tasks.Count; for (int i = 0; i < numTasks; i++) { @@ -2411,8 +2413,8 @@ namespace System.Threading.Tasks internal static void CommonCWAnyLogicCleanup(Task continuation) { // Force cleanup of the promise (e.g. removing continuations from each - // constituent task), by completing the promise with any value. - ((CompleteOnInvokePromise)continuation).Invoke(null); + // constituent task), by completing the promise with any value (it's not observable). + ((CompleteOnInvokePromise)continuation).Invoke(null!); } /// diff --git a/src/System.Private.CoreLib/shared/System/Threading/Tasks/TaskScheduler.cs b/src/System.Private.CoreLib/shared/System/Threading/Tasks/TaskScheduler.cs index 1d1a581b0b..d8940044da 100644 --- a/src/System.Private.CoreLib/shared/System/Threading/Tasks/TaskScheduler.cs +++ b/src/System.Private.CoreLib/shared/System/Threading/Tasks/TaskScheduler.cs @@ -10,6 +10,7 @@ // // =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +#nullable enable using System.Collections.Generic; using System.Diagnostics; using System.Runtime.CompilerServices; @@ -142,7 +143,7 @@ namespace System.Threading.Tasks /// /// This scheduler is unable to generate a list of queued tasks at this time. /// - protected abstract IEnumerable GetScheduledTasks(); + protected abstract IEnumerable? GetScheduledTasks(); /// /// Indicates the maximum concurrency level this @@ -174,7 +175,7 @@ namespace System.Threading.Tasks // Do not inline unstarted tasks (i.e., task.ExecutingTaskScheduler == null). // Do not inline TaskCompletionSource-style (a.k.a. "promise") tasks. // No need to attempt inlining if the task body was already run (i.e. either TASK_STATE_DELEGATE_INVOKED or TASK_STATE_CANCELED bits set) - TaskScheduler ets = task.ExecutingTaskScheduler; + TaskScheduler? ets = task.ExecutingTaskScheduler; // Delegate cross-scheduler inlining requests to target scheduler if (ets != this && ets != null) return ets.TryRunInline(task, taskWasPreviouslyQueued); @@ -254,7 +255,7 @@ namespace System.Threading.Tasks // // The global container that keeps track of TaskScheduler instances for debugging purposes. - private static ConditionalWeakTable s_activeTaskSchedulers; + private static ConditionalWeakTable? s_activeTaskSchedulers; // An AppDomain-wide default manager. private static readonly TaskScheduler s_defaultTaskScheduler = new ThreadPoolTaskScheduler(); @@ -292,13 +293,13 @@ namespace System.Threading.Tasks /// Adds this scheduler ot the active schedulers tracking collection for debugging purposes. private void AddToActiveTaskSchedulers() { - ConditionalWeakTable activeTaskSchedulers = s_activeTaskSchedulers; + ConditionalWeakTable? activeTaskSchedulers = s_activeTaskSchedulers; if (activeTaskSchedulers == null) { - Interlocked.CompareExchange(ref s_activeTaskSchedulers, new ConditionalWeakTable(), null); + Interlocked.CompareExchange(ref s_activeTaskSchedulers, new ConditionalWeakTable(), null); activeTaskSchedulers = s_activeTaskSchedulers; } - activeTaskSchedulers.Add(this, null); + activeTaskSchedulers!.Add(this, null); // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 } /// @@ -323,8 +324,7 @@ namespace System.Threading.Tasks { get { - TaskScheduler current = InternalCurrent; - return current ?? TaskScheduler.Default; + return InternalCurrent ?? Default; } } @@ -335,11 +335,11 @@ namespace System.Threading.Tasks /// /// When not called from within a task, will return null. /// - internal static TaskScheduler InternalCurrent + internal static TaskScheduler? InternalCurrent { get { - Task currentTask = Task.InternalCurrent; + Task? currentTask = Task.InternalCurrent; return ((currentTask != null) && ((currentTask.CreationOptions & TaskCreationOptions.HideScheduler) == 0) ) ? currentTask.ExecutingTaskScheduler : null; @@ -472,11 +472,11 @@ namespace System.Threading.Tasks /// /// This scheduler is unable to generate a list of queued tasks at this time. /// - internal Task[] GetScheduledTasksForDebugger() + internal Task[]? GetScheduledTasksForDebugger() { // this can throw InvalidOperationException indicating that they are unable to provide the info // at the moment. We should let the debugger receive that exception so that it can indicate it in the UI - IEnumerable activeTasksSource = GetScheduledTasks(); + IEnumerable? activeTasksSource = GetScheduledTasks(); if (activeTasksSource == null) return null; @@ -553,7 +553,7 @@ namespace System.Threading.Tasks } // returns the scheduler's GetScheduledTasks - public IEnumerable ScheduledTasks + public IEnumerable? ScheduledTasks { get { return m_taskScheduler.GetScheduledTasks(); } } @@ -578,15 +578,9 @@ namespace System.Threading.Tasks /// This constructor expects to be set. internal SynchronizationContextTaskScheduler() { - SynchronizationContext synContext = SynchronizationContext.Current; - - // make sure we have a synccontext to work with - if (synContext == null) - { + m_synchronizationContext = SynchronizationContext.Current ?? + // make sure we have a synccontext to work with throw new InvalidOperationException(SR.TaskScheduler_FromCurrentSynchronizationContext_NoCurrent); - } - - m_synchronizationContext = synContext; } /// @@ -615,11 +609,12 @@ namespace System.Threading.Tasks return TryExecuteTask(task); } else + { return false; + } } - // not implemented - protected override IEnumerable GetScheduledTasks() + protected override IEnumerable? GetScheduledTasks() { return null; } @@ -640,7 +635,11 @@ namespace System.Threading.Tasks } // preallocated SendOrPostCallback delegate - private static readonly SendOrPostCallback s_postCallback = s => ((Task)s).ExecuteEntry(); // with double-execute check because SC could be buggy + private static readonly SendOrPostCallback s_postCallback = s => + { + Debug.Assert(s is Task); + ((Task)s).ExecuteEntry(); // with double-execute check because SC could be buggy + }; } /// @@ -655,7 +654,7 @@ namespace System.Threading.Tasks /// public class UnobservedTaskExceptionEventArgs : EventArgs { - private AggregateException m_exception; + private AggregateException? m_exception; internal bool m_observed = false; /// @@ -663,7 +662,7 @@ namespace System.Threading.Tasks /// with the unobserved exception. /// /// The Exception that has gone unobserved. - public UnobservedTaskExceptionEventArgs(AggregateException exception) { m_exception = exception; } + public UnobservedTaskExceptionEventArgs(AggregateException? exception) { m_exception = exception; } /// /// Marks the as "observed," thus preventing it @@ -679,6 +678,6 @@ namespace System.Threading.Tasks /// /// The Exception that went unobserved. /// - public AggregateException Exception { get { return m_exception; } } + public AggregateException? Exception { get { return m_exception; } } } } diff --git a/src/System.Private.CoreLib/shared/System/Threading/Tasks/TaskSchedulerException.cs b/src/System.Private.CoreLib/shared/System/Threading/Tasks/TaskSchedulerException.cs index 85ec497219..c68469c5cd 100644 --- a/src/System.Private.CoreLib/shared/System/Threading/Tasks/TaskSchedulerException.cs +++ b/src/System.Private.CoreLib/shared/System/Threading/Tasks/TaskSchedulerException.cs @@ -10,8 +10,7 @@ // // =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -using System; -using System.Runtime.InteropServices; +#nullable enable using System.Runtime.Serialization; namespace System.Threading.Tasks @@ -36,7 +35,7 @@ namespace System.Threading.Tasks /// class with a specified error message. /// /// The error message that explains the reason for the exception. - public TaskSchedulerException(string message) : base(message) + public TaskSchedulerException(string? message) : base(message) { } @@ -46,7 +45,7 @@ namespace System.Threading.Tasks /// this exception. /// /// The exception that is the cause of the current exception. - public TaskSchedulerException(Exception innerException) + public TaskSchedulerException(Exception? innerException) : base(SR.TaskSchedulerException_ctor_DefaultMessage, innerException) { } @@ -58,7 +57,7 @@ namespace System.Threading.Tasks /// /// The error message that explains the reason for the exception. /// The exception that is the cause of the current exception. - public TaskSchedulerException(string message, Exception innerException) : base(message, innerException) + public TaskSchedulerException(string? message, Exception? innerException) : base(message, innerException) { } diff --git a/src/System.Private.CoreLib/shared/System/Threading/Tasks/TaskToApm.cs b/src/System.Private.CoreLib/shared/System/Threading/Tasks/TaskToApm.cs index add41f588e..110520a32b 100644 --- a/src/System.Private.CoreLib/shared/System/Threading/Tasks/TaskToApm.cs +++ b/src/System.Private.CoreLib/shared/System/Threading/Tasks/TaskToApm.cs @@ -16,6 +16,7 @@ // return TaskToApm.End(asyncResult); // } +#nullable enable using System.Diagnostics; namespace System.Threading.Tasks @@ -33,7 +34,7 @@ namespace System.Threading.Tasks /// The callback to be invoked upon completion. /// The state to be stored in the IAsyncResult. /// An IAsyncResult to represent the task's asynchronous operation. - public static IAsyncResult Begin(Task task, AsyncCallback callback, object state) + public static IAsyncResult Begin(Task task, AsyncCallback callback, object? state) { Debug.Assert(task != null); @@ -63,7 +64,7 @@ namespace System.Threading.Tasks /// The IAsyncResult to unwrap. public static void End(IAsyncResult asyncResult) { - Task task; + Task? task; // If the IAsyncResult is our task-wrapping IAsyncResult, extract the Task. var twar = asyncResult as TaskWrapperAsyncResult; @@ -91,7 +92,7 @@ namespace System.Threading.Tasks /// The IAsyncResult to unwrap. public static TResult End(IAsyncResult asyncResult) { - Task task; + Task? task; // If the IAsyncResult is our task-wrapping IAsyncResult, extract the Task. var twar = asyncResult as TaskWrapperAsyncResult; @@ -158,7 +159,7 @@ namespace System.Threading.Tasks /// The wrapped Task. internal readonly Task Task; /// The new AsyncState value. - private readonly object _state; + private readonly object? _state; /// The new CompletedSynchronously value. private readonly bool _completedSynchronously; @@ -166,7 +167,7 @@ namespace System.Threading.Tasks /// The Task to wrap. /// The new AsyncState value /// The new CompletedSynchronously value. - internal TaskWrapperAsyncResult(Task task, object state, bool completedSynchronously) + internal TaskWrapperAsyncResult(Task task, object? state, bool completedSynchronously) { Debug.Assert(task != null); Debug.Assert(!completedSynchronously || task.IsCompleted, "If completedSynchronously is true, the task must be completed."); @@ -180,7 +181,7 @@ namespace System.Threading.Tasks // - IsCompleted and AsyncWaitHandle just pass through to the Task. // - AsyncState and CompletedSynchronously return the corresponding values stored in this object. - object IAsyncResult.AsyncState { get { return _state; } } + object? IAsyncResult.AsyncState { get { return _state; } } bool IAsyncResult.CompletedSynchronously { get { return _completedSynchronously; } } bool IAsyncResult.IsCompleted { get { return this.Task.IsCompleted; } } WaitHandle IAsyncResult.AsyncWaitHandle { get { return ((IAsyncResult)this.Task).AsyncWaitHandle; } } diff --git a/src/System.Private.CoreLib/shared/System/Threading/Tasks/ThreadPoolTaskScheduler.cs b/src/System.Private.CoreLib/shared/System/Threading/Tasks/ThreadPoolTaskScheduler.cs index 9ab28ef34a..05cb75bcbc 100644 --- a/src/System.Private.CoreLib/shared/System/Threading/Tasks/ThreadPoolTaskScheduler.cs +++ b/src/System.Private.CoreLib/shared/System/Threading/Tasks/ThreadPoolTaskScheduler.cs @@ -11,11 +11,9 @@ // // =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -using System; -using System.Security; -using System.Diagnostics; +#nullable enable using System.Collections.Generic; -using System.Text; +using System.Diagnostics; namespace System.Threading.Tasks { @@ -33,7 +31,11 @@ namespace System.Threading.Tasks } // static delegate for threads allocated to handle LongRunning tasks. - private static readonly ParameterizedThreadStart s_longRunningThreadWork = s => ((Task)s).ExecuteEntryUnsafe(threadPoolThread: null); + private static readonly ParameterizedThreadStart s_longRunningThreadWork = s => + { + Debug.Assert(s is Task); + ((Task)s).ExecuteEntryUnsafe(threadPoolThread: null); + }; /// /// Schedules a task to the ThreadPool. diff --git a/src/System.Private.CoreLib/shared/System/Threading/Tasks/TplEventSource.cs b/src/System.Private.CoreLib/shared/System/Threading/Tasks/TplEventSource.cs index 94f0ec37e8..184cc32890 100644 --- a/src/System.Private.CoreLib/shared/System/Threading/Tasks/TplEventSource.cs +++ b/src/System.Private.CoreLib/shared/System/Threading/Tasks/TplEventSource.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +#nullable enable using System.Runtime.CompilerServices; using System.Diagnostics.Tracing; using Internal.Runtime.CompilerServices; diff --git a/src/System.Private.CoreLib/shared/System/Threading/Tasks/ValueTask.cs b/src/System.Private.CoreLib/shared/System/Threading/Tasks/ValueTask.cs index e9285ce45f..1b175614e2 100644 --- a/src/System.Private.CoreLib/shared/System/Threading/Tasks/ValueTask.cs +++ b/src/System.Private.CoreLib/shared/System/Threading/Tasks/ValueTask.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +#nullable enable using System.Collections.Generic; using System.Diagnostics; using System.Runtime.CompilerServices; @@ -63,7 +64,7 @@ namespace System.Threading.Tasks internal static Task CompletedTask => Task.CompletedTask; /// null if representing a successful synchronous completion, otherwise a or a . - internal readonly object _obj; + internal readonly object? _obj; /// Opaque value passed through to the . internal readonly short _token; /// true to continue on the capture context; otherwise, true. @@ -106,7 +107,7 @@ namespace System.Threading.Tasks } [MethodImpl(MethodImplOptions.AggressiveInlining)] - private ValueTask(object obj, short token, bool continueOnCapturedContext) + private ValueTask(object? obj, short token, bool continueOnCapturedContext) { _obj = obj; _token = token; @@ -117,7 +118,7 @@ namespace System.Threading.Tasks public override int GetHashCode() => _obj?.GetHashCode() ?? 0; /// Returns a value indicating whether this value is equal to a specified . - public override bool Equals(object obj) => + public override bool Equals(object? obj) => obj is ValueTask && Equals((ValueTask)obj); @@ -141,7 +142,7 @@ namespace System.Threading.Tasks /// public Task AsTask() { - object obj = _obj; + object? obj = _obj; Debug.Assert(obj == null || obj is Task || obj is IValueTaskSource); return obj == null ? CompletedTask : @@ -200,7 +201,7 @@ namespace System.Threading.Tasks /// Type used to create a to represent a . private sealed class ValueTaskSourceAsTask : Task { - private static readonly Action s_completionAction = state => + private static readonly Action s_completionAction = state => { if (!(state is ValueTaskSourceAsTask vtst) || !(vtst._source is IValueTaskSource source)) @@ -240,11 +241,11 @@ namespace System.Threading.Tasks }; /// The associated . - private IValueTaskSource _source; + private IValueTaskSource? _source; /// The token to pass through to operations on private readonly short _token; - public ValueTaskSourceAsTask(IValueTaskSource source, short token) + internal ValueTaskSourceAsTask(IValueTaskSource source, short token) { _token = token; _source = source; @@ -258,7 +259,7 @@ namespace System.Threading.Tasks [MethodImpl(MethodImplOptions.AggressiveInlining)] get { - object obj = _obj; + object? obj = _obj; Debug.Assert(obj == null || obj is Task || obj is IValueTaskSource); if (obj == null) @@ -281,7 +282,7 @@ namespace System.Threading.Tasks [MethodImpl(MethodImplOptions.AggressiveInlining)] get { - object obj = _obj; + object? obj = _obj; Debug.Assert(obj == null || obj is Task || obj is IValueTaskSource); if (obj == null) @@ -303,7 +304,7 @@ namespace System.Threading.Tasks { get { - object obj = _obj; + object? obj = _obj; Debug.Assert(obj == null || obj is Task || obj is IValueTaskSource); if (obj == null) @@ -330,7 +331,7 @@ namespace System.Threading.Tasks { get { - object obj = _obj; + object? obj = _obj; Debug.Assert(obj == null || obj is Task || obj is IValueTaskSource); if (obj == null) @@ -352,7 +353,7 @@ namespace System.Threading.Tasks [StackTraceHidden] internal void ThrowIfCompletedUnsuccessfully() { - object obj = _obj; + object? obj = _obj; Debug.Assert(obj == null || obj is Task || obj is IValueTaskSource); if (obj != null) @@ -411,9 +412,9 @@ namespace System.Threading.Tasks public readonly struct ValueTask : IEquatable> { /// A task canceled using `new CancellationToken(true)`. Lazily created only when first needed. - private static Task s_canceledTask; + private static Task? s_canceledTask; /// null if has the result, otherwise a or a . - internal readonly object _obj; + internal readonly object? _obj; /// The result to be used if the operation completed successfully synchronously. internal readonly TResult _result; /// Opaque value passed through to the . @@ -449,7 +450,7 @@ namespace System.Threading.Tasks _obj = task; - _result = default; + _result = default!; // TODO-NULLABLE-GENERIC _continueOnCapturedContext = true; _token = 0; } @@ -468,7 +469,7 @@ namespace System.Threading.Tasks _obj = source; _token = token; - _result = default; + _result = default!; // TODO-NULLABLE-GENERIC _continueOnCapturedContext = true; } @@ -478,7 +479,7 @@ namespace System.Threading.Tasks /// The token. /// true to continue on captured context; otherwise, false. [MethodImpl(MethodImplOptions.AggressiveInlining)] - private ValueTask(object obj, TResult result, short token, bool continueOnCapturedContext) + private ValueTask(object? obj, TResult result, short token, bool continueOnCapturedContext) { _obj = obj; _result = result; @@ -494,7 +495,7 @@ namespace System.Threading.Tasks 0; /// Returns a value indicating whether this value is equal to a specified . - public override bool Equals(object obj) => + public override bool Equals(object? obj) => obj is ValueTask && Equals((ValueTask)obj); @@ -521,7 +522,7 @@ namespace System.Threading.Tasks /// public Task AsTask() { - object obj = _obj; + object? obj = _obj; Debug.Assert(obj == null || obj is Task || obj is IValueTaskSource); if (obj == null) @@ -572,11 +573,11 @@ namespace System.Threading.Tasks return task; } - Task canceledTask = s_canceledTask; + Task? canceledTask = s_canceledTask; if (canceledTask == null) { // Benign race condition to initialize cached task, as identity doesn't matter. - s_canceledTask = Task.FromCanceled(new CancellationToken(true)); + s_canceledTask = canceledTask = Task.FromCanceled(new CancellationToken(true)); } return canceledTask; } @@ -593,7 +594,7 @@ namespace System.Threading.Tasks /// Type used to create a to represent a . private sealed class ValueTaskSourceAsTask : Task { - private static readonly Action s_completionAction = state => + private static readonly Action s_completionAction = state => { if (!(state is ValueTaskSourceAsTask vtst) || !(vtst._source is IValueTaskSource source)) @@ -632,7 +633,7 @@ namespace System.Threading.Tasks }; /// The associated . - private IValueTaskSource _source; + private IValueTaskSource? _source; /// The token to pass through to operations on private readonly short _token; @@ -650,7 +651,7 @@ namespace System.Threading.Tasks [MethodImpl(MethodImplOptions.AggressiveInlining)] get { - object obj = _obj; + object? obj = _obj; Debug.Assert(obj == null || obj is Task || obj is IValueTaskSource); if (obj == null) @@ -673,7 +674,7 @@ namespace System.Threading.Tasks [MethodImpl(MethodImplOptions.AggressiveInlining)] get { - object obj = _obj; + object? obj = _obj; Debug.Assert(obj == null || obj is Task || obj is IValueTaskSource); if (obj == null) @@ -695,7 +696,7 @@ namespace System.Threading.Tasks { get { - object obj = _obj; + object? obj = _obj; Debug.Assert(obj == null || obj is Task || obj is IValueTaskSource); if (obj == null) @@ -722,7 +723,7 @@ namespace System.Threading.Tasks { get { - object obj = _obj; + object? obj = _obj; Debug.Assert(obj == null || obj is Task || obj is IValueTaskSource); if (obj == null) @@ -745,7 +746,7 @@ namespace System.Threading.Tasks [MethodImpl(MethodImplOptions.AggressiveInlining)] get { - object obj = _obj; + object? obj = _obj; Debug.Assert(obj == null || obj is Task || obj is IValueTaskSource); if (obj == null) @@ -776,7 +777,7 @@ namespace System.Threading.Tasks new ConfiguredValueTaskAwaitable(new ValueTask(_obj, _result, _token, continueOnCapturedContext)); /// Gets a string-representation of this . - public override string ToString() + public override string? ToString() { if (IsCompletedSuccessfully) { diff --git a/src/System.Private.CoreLib/shared/System/Threading/Timer.cs b/src/System.Private.CoreLib/shared/System/Threading/Timer.cs index a21203070f..66d01ac81a 100644 --- a/src/System.Private.CoreLib/shared/System/Threading/Timer.cs +++ b/src/System.Private.CoreLib/shared/System/Threading/Timer.cs @@ -718,7 +718,7 @@ namespace System.Threading { private const uint MAX_SUPPORTED_TIMEOUT = (uint)0xfffffffe; - private TimerHolder _timer = null!; // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 + private TimerHolder _timer = null!; // initialized in helper called by ctors public Timer(TimerCallback callback, object? state, diff --git a/src/System.Private.CoreLib/src/System/Delegate.cs b/src/System.Private.CoreLib/src/System/Delegate.cs index 77dcea5a76..b281c9244e 100644 --- a/src/System.Private.CoreLib/src/System/Delegate.cs +++ b/src/System.Private.CoreLib/src/System/Delegate.cs @@ -20,7 +20,7 @@ namespace System // MethodBase, either cached after first request or assigned from a DynamicMethod // For open delegates to collectible types, this may be a LoaderAllocator object - internal object _methodBase = null!; // Initialized by VM as needed + internal object? _methodBase; // Initialized by VM as needed // _methodPtr is a pointer to the method we will invoke // It could be a small thunk if this is a static or UM call diff --git a/src/System.Private.CoreLib/src/System/MulticastDelegate.cs b/src/System.Private.CoreLib/src/System/MulticastDelegate.cs index dfb8ceaaeb..e128c7597b 100644 --- a/src/System.Private.CoreLib/src/System/MulticastDelegate.cs +++ b/src/System.Private.CoreLib/src/System/MulticastDelegate.cs @@ -578,7 +578,7 @@ namespace System { if (target == null) ThrowNullThisInDelegateToInstance(); - this._target = target!; // TODO-NULLABLE: Compiler can't see throw helper above + this._target = target!; // TODO-NULLABLE: https://github.com/dotnet/csharplang/issues/538 this._methodPtr = methodPtr; } diff --git a/src/System.Private.CoreLib/src/System/Threading/Tasks/AsyncCausalityTracer.cs b/src/System.Private.CoreLib/src/System/Threading/Tasks/AsyncCausalityTracer.cs index d72ca12b70..491916699f 100644 --- a/src/System.Private.CoreLib/src/System/Threading/Tasks/AsyncCausalityTracer.cs +++ b/src/System.Private.CoreLib/src/System/Threading/Tasks/AsyncCausalityTracer.cs @@ -2,16 +2,12 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using System.Security; +#nullable enable using System.Diagnostics; using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - using System.Runtime.InteropServices.WindowsRuntime; - using WFD = Windows.Foundation.Diagnostics; - namespace System.Threading.Tasks { internal static class AsyncCausalityTracer @@ -64,7 +60,7 @@ namespace System.Threading.Tasks //COM Interface GUID {50850B26-267E-451B-A890-AB6A370245EE} Guid guid = new Guid(0x50850B26, 0x267E, 0x451B, 0xA8, 0x90, 0XAB, 0x6A, 0x37, 0x02, 0x45, 0xEE); - object factory = null; + object? factory = null; try { diff --git a/src/System.Private.CoreLib/src/System/Threading/Tasks/IAsyncCausalityTracerStatics.cs b/src/System.Private.CoreLib/src/System/Threading/Tasks/IAsyncCausalityTracerStatics.cs index a09279c06c..131fffc348 100644 --- a/src/System.Private.CoreLib/src/System/Threading/Tasks/IAsyncCausalityTracerStatics.cs +++ b/src/System.Private.CoreLib/src/System/Threading/Tasks/IAsyncCausalityTracerStatics.cs @@ -2,9 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -// -// - +#nullable enable using System; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; -- cgit v1.2.3